22import * as React from 'react' ;
33import {
44 createPopper as defaultCreatePopper ,
5- type Options as PopperOptions ,
65 type VirtualElement ,
6+ type Modifier ,
7+ type OptionsGeneric ,
8+ type StrictModifiers ,
79} from '@popperjs/core' ;
810import isEqual from 'react-fast-compare' ;
911import { fromEntries , useIsomorphicLayoutEffect } from './utils' ;
1012
11- type Options = $Shape < {
12- ...PopperOptions ,
13+ type Options < TModifiers > = $Shape < {
14+ ...OptionsGeneric < TModifiers > ,
1315 createPopper : typeof defaultCreatePopper ,
1416} > ;
1517
@@ -22,14 +24,20 @@ type State = {
2224 } ,
2325} ;
2426
27+ type UpdateStateModifier = Modifier < 'updateState' , { || } > ;
28+
2529const EMPTY_MODIFIERS = [ ] ;
2630
27- export const usePopper = (
31+ export const usePopper = <
32+ TModifiers : StrictModifiers | $Shape < Modifier < string , { } > >
33+ > (
2834 referenceElement : ?( Element | VirtualElement ) ,
2935 popperElement : ?HTMLElement ,
30- options : Options = { }
36+ options : Options < TModifiers > = { }
3137) => {
32- const prevOptions = React . useRef < ?PopperOptions > ( null ) ;
38+ type TExtendedModifier = TModifiers | $Shape < UpdateStateModifier > ;
39+
40+ const prevOptions = React . useRef < ?OptionsGeneric < TExtendedModifier >> ( null ) ;
3341
3442 const optionsWithDefaults = {
3543 onFirstUpdate : options . onFirstUpdate ,
@@ -49,7 +57,7 @@ export const usePopper = (
4957 attributes : { } ,
5058 } ) ;
5159
52- const updateStateModifier = React . useMemo (
60+ const updateStateModifier = React . useMemo < UpdateStateModifier > (
5361 ( ) => ( {
5462 name : 'updateState' ,
5563 enabled : true ,
@@ -71,7 +79,7 @@ export const usePopper = (
7179 [ setState ]
7280 ) ;
7381
74- const popperOptions = React . useMemo ( ( ) => {
82+ const popperOptions = React . useMemo < OptionsGeneric < TExtendedModifier >> ( ( ) => {
7583 const newOptions = {
7684 onFirstUpdate : optionsWithDefaults . onFirstUpdate ,
7785 placement : optionsWithDefaults . placement || 'bottom' ,
@@ -83,8 +91,11 @@ export const usePopper = (
8391 ] ,
8492 } ;
8593
86- if ( isEqual ( prevOptions . current , newOptions ) ) {
87- return prevOptions . current || newOptions ;
94+ if (
95+ prevOptions . current != null &&
96+ isEqual ( prevOptions . current , newOptions )
97+ ) {
98+ return prevOptions . current ;
8899 } else {
89100 prevOptions . current = newOptions ;
90101 return newOptions ;
@@ -98,15 +109,17 @@ export const usePopper = (
98109 ] ) ;
99110
100111 const popperInstanceRef = React . useRef ( ) ;
101- const createPopper = React . useMemo (
102- ( ) => options . createPopper || defaultCreatePopper ,
112+
113+ const createPopper = React . useMemo < typeof defaultCreatePopper > (
114+ // For some reason the two identical types don't like to be cast to one of them
115+ ( ) => ( options . createPopper : any ) || defaultCreatePopper ,
103116 [ options . createPopper ]
104117 ) ;
105118
106119 useIsomorphicLayoutEffect ( ( ) => {
107120 let popperInstance = null ;
108121 if ( referenceElement != null && popperElement != null ) {
109- popperInstance = createPopper (
122+ popperInstance = createPopper < TExtendedModifier > (
110123 referenceElement ,
111124 popperElement ,
112125 popperOptions
0 commit comments