@@ -35,6 +35,47 @@ it('should should return a position', async () => {
3535 } )
3636} )
3737
38+ it ( 'should defer initial updatePosition to useEffect when overlay is closed on mount' , async ( ) => {
39+ // When no floating element is present (overlay closed), the initial
40+ // updatePosition call should be deferred from useLayoutEffect to useEffect.
41+ // We verify this by checking that onPositionChange has NOT been called by
42+ // the time the component's own useLayoutEffect runs (which fires after the
43+ // hook's useLayoutEffect in declaration order).
44+ const onPositionChange = vi . fn ( )
45+ const layoutPhaseCheck = vi . fn ( )
46+
47+ const ClosedOverlayComponent = ( {
48+ onPositionChangeProp,
49+ onLayoutEffect,
50+ } : {
51+ onPositionChangeProp : typeof onPositionChange
52+ onLayoutEffect : ( calledDuringLayout : boolean ) => void
53+ } ) => {
54+ const floatingElementRef = React . useRef < HTMLDivElement > ( null )
55+ const anchorElementRef = React . useRef < HTMLDivElement > ( null )
56+ useAnchoredPosition ( { floatingElementRef, anchorElementRef, onPositionChange : onPositionChangeProp } )
57+
58+ // This layout effect runs after the hook's layout effects (declaration order).
59+ // With the fix, onPositionChange should NOT have been called yet because
60+ // the initial updatePosition is deferred to useEffect.
61+ React . useLayoutEffect ( ( ) => {
62+ onLayoutEffect ( onPositionChangeProp . mock . calls . length > 0 )
63+ } , [ onPositionChangeProp , onLayoutEffect ] )
64+
65+ return < div />
66+ }
67+
68+ render ( < ClosedOverlayComponent onPositionChangeProp = { onPositionChange } onLayoutEffect = { layoutPhaseCheck } /> )
69+
70+ // onPositionChange should not have fired during the layout phase
71+ expect ( layoutPhaseCheck ) . toHaveBeenCalledWith ( false )
72+
73+ // After effects run, onPositionChange should have been called with undefined
74+ await waitFor ( ( ) => {
75+ expect ( onPositionChange ) . toHaveBeenCalledWith ( undefined )
76+ } )
77+ } )
78+
3879describe ( 'scroll recalculation' , ( ) => {
3980 it ( 'should recalculate position when window scrolls' , async ( ) => {
4081 const cb = vi . fn ( )
0 commit comments