diff --git a/packages/@headlessui-react/src/components/combobox/combobox.tsx b/packages/@headlessui-react/src/components/combobox/combobox.tsx index 131284aa31..a76f893867 100644 --- a/packages/@headlessui-react/src/components/combobox/combobox.tsx +++ b/packages/@headlessui-react/src/components/combobox/combobox.tsx @@ -1672,14 +1672,20 @@ function OptionsFn( } let [floatingRef, style] = useFloatingPanel(anchor) + let [localOptionsElement, setLocalOptionsElement] = useState(null) let getFloatingPanelProps = useFloatingPanelProps() - let optionsRef = useSyncRefs(ref, anchor ? floatingRef : null, actions.setOptionsElement) + let optionsRef = useSyncRefs( + ref, + anchor ? floatingRef : null, + actions.setOptionsElement, + setLocalOptionsElement + ) let ownerDocument = useOwnerDocument(data.optionsElement) let usesOpenClosedState = useOpenClosed() let [visible, transitionData] = useTransition( transition, - data.optionsElement, + localOptionsElement, usesOpenClosedState !== null ? (usesOpenClosedState & State.Open) === State.Open : data.comboboxState === ComboboxState.Open diff --git a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx index 4a20bb2e5e..743deefb63 100644 --- a/packages/@headlessui-react/src/components/disclosure/disclosure.tsx +++ b/packages/@headlessui-react/src/components/disclosure/disclosure.tsx @@ -11,6 +11,7 @@ import React, { useMemo, useReducer, useRef, + useState, type ContextType, type Dispatch, type ElementType, @@ -450,12 +451,14 @@ function PanelFn( let [state, dispatch] = useDisclosureContext('Disclosure.Panel') let { close } = useDisclosureAPIContext('Disclosure.Panel') let mergeRefs = useMergeRefsFn() + let [localPanelElement, setLocalPanelElement] = useState(null) let panelRef = useSyncRefs( ref, useEvent((element) => { startTransition(() => dispatch({ type: ActionTypes.SetPanelElement, element })) - }) + }), + setLocalPanelElement ) useEffect(() => { @@ -468,7 +471,7 @@ function PanelFn( let usesOpenClosedState = useOpenClosed() let [visible, transitionData] = useTransition( transition, - state.panelElement, + localPanelElement, usesOpenClosedState !== null ? (usesOpenClosedState & State.Open) === State.Open : state.disclosureState === DisclosureStates.Open diff --git a/packages/@headlessui-react/src/components/listbox/listbox.tsx b/packages/@headlessui-react/src/components/listbox/listbox.tsx index e8c40e4365..78d8c15694 100644 --- a/packages/@headlessui-react/src/components/listbox/listbox.tsx +++ b/packages/@headlessui-react/src/components/listbox/listbox.tsx @@ -12,6 +12,7 @@ import React, { useMemo, useReducer, useRef, + useState, type CSSProperties, type ElementType, type MutableRefObject, @@ -931,6 +932,7 @@ function OptionsFn( ...theirProps } = props let anchor = useResolvedAnchor(rawAnchor) + let [localOptionsElement, setLocalOptionsElement] = useState(null) // Always enable `portal` functionality, when `anchor` is enabled if (anchor) { @@ -945,7 +947,7 @@ function OptionsFn( let usesOpenClosedState = useOpenClosed() let [visible, transitionData] = useTransition( transition, - data.optionsElement, + localOptionsElement, usesOpenClosedState !== null ? (usesOpenClosedState & State.Open) === State.Open : data.listboxState === ListboxStates.Open @@ -1023,7 +1025,12 @@ function OptionsFn( let [floatingRef, style] = useFloatingPanel(anchorOptions) let getFloatingPanelProps = useFloatingPanelProps() - let optionsRef = useSyncRefs(ref, anchor ? floatingRef : null, actions.setOptionsElement) + let optionsRef = useSyncRefs( + ref, + anchor ? floatingRef : null, + actions.setOptionsElement, + setLocalOptionsElement + ) let searchDisposables = useDisposables() diff --git a/packages/@headlessui-react/src/components/menu/menu.tsx b/packages/@headlessui-react/src/components/menu/menu.tsx index 8da007529a..655f7cdf8a 100644 --- a/packages/@headlessui-react/src/components/menu/menu.tsx +++ b/packages/@headlessui-react/src/components/menu/menu.tsx @@ -12,6 +12,7 @@ import React, { useMemo, useReducer, useRef, + useState, type CSSProperties, type Dispatch, type ElementType, @@ -620,10 +621,13 @@ function ItemsFn( let [state, dispatch] = useMenuContext('Menu.Items') let [floatingRef, style] = useFloatingPanel(anchor) let getFloatingPanelProps = useFloatingPanelProps() + let [localItemsElement, setLocalItemsElement] = useState(null) + let itemsRef = useSyncRefs( ref, anchor ? floatingRef : null, - useEvent((element) => dispatch({ type: ActionTypes.SetItemsElement, element })) + useEvent((element) => dispatch({ type: ActionTypes.SetItemsElement, element })), + setLocalItemsElement ) let ownerDocument = useOwnerDocument(state.itemsElement) @@ -635,7 +639,7 @@ function ItemsFn( let usesOpenClosedState = useOpenClosed() let [visible, transitionData] = useTransition( transition, - state.itemsElement, + localItemsElement, usesOpenClosedState !== null ? (usesOpenClosedState & State.Open) === State.Open : state.menuState === MenuStates.Open diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx index 018368d167..2c130b4519 100644 --- a/packages/@headlessui-react/src/components/popover/popover.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.tsx @@ -763,13 +763,13 @@ function BackdropFn( ...theirProps } = props let [{ popoverState }, dispatch] = usePopoverContext('Popover.Backdrop') - let [backdropElement, setBackdropElement] = useState(null) - let backdropRef = useSyncRefs(ref, setBackdropElement) + let [localBackdropElement, setLocalBackdropElement] = useState(null) + let backdropRef = useSyncRefs(ref, setLocalBackdropElement) let usesOpenClosedState = useOpenClosed() let [visible, transitionData] = useTransition( transition, - backdropElement, + localBackdropElement, usesOpenClosedState !== null ? (usesOpenClosedState & State.Open) === State.Open : popoverState === PopoverStates.Open @@ -865,11 +865,13 @@ function PanelFn( portal = true } + let [localPanelElement, setLocalPanelElement] = useState(null) let panelRef = useSyncRefs( internalPanelRef, ref, anchor ? floatingRef : null, - useEvent((panel) => dispatch({ type: ActionTypes.SetPanel, panel })) + useEvent((panel) => dispatch({ type: ActionTypes.SetPanel, panel })), + setLocalPanelElement ) let ownerDocument = useOwnerDocument(internalPanelRef) let mergeRefs = useMergeRefsFn() @@ -884,7 +886,7 @@ function PanelFn( let usesOpenClosedState = useOpenClosed() let [visible, transitionData] = useTransition( transition, - state.panel, + localPanelElement, usesOpenClosedState !== null ? (usesOpenClosedState & State.Open) === State.Open : state.popoverState === PopoverStates.Open @@ -1028,7 +1030,10 @@ function PanelFn( // Ignore sentinel buttons and items inside the panel for (let element of combined.slice()) { - if (element.dataset.headlessuiFocusGuard === 'true' || state.panel?.contains(element)) { + if ( + element.dataset.headlessuiFocusGuard === 'true' || + localPanelElement?.contains(element) + ) { let idx = combined.indexOf(element) if (idx !== -1) combined.splice(idx, 1) } diff --git a/packages/@headlessui-react/src/components/transition/transition.tsx b/packages/@headlessui-react/src/components/transition/transition.tsx index 31aaf07a4c..9f0922f0a3 100644 --- a/packages/@headlessui-react/src/components/transition/transition.tsx +++ b/packages/@headlessui-react/src/components/transition/transition.tsx @@ -319,12 +319,12 @@ function TransitionChildFn(null) + let [localContainerElement, setLocalContainerElement] = useState(null) let container = useRef(null) let requiresRef = shouldForwardRef(props) let transitionRef = useSyncRefs( - ...(requiresRef ? [container, ref, setContainerElement] : ref === null ? [] : [ref]) + ...(requiresRef ? [container, ref, setLocalContainerElement] : ref === null ? [] : [ref]) ) let strategy = theirProps.unmount ?? true ? RenderStrategy.Unmount : RenderStrategy.Hidden @@ -438,7 +438,7 @@ function TransitionChildFn` is done, but there is still a // child `` busy, then `visible` would be `false`, while // `state` would still be `TreeStates.Visible`. - let [, transitionData] = useTransition(enabled, containerElement, show, { start, end }) + let [, transitionData] = useTransition(enabled, localContainerElement, show, { start, end }) let ourProps = compact({ ref: transitionRef,