diff --git a/packages/@headlessui-react/CHANGELOG.md b/packages/@headlessui-react/CHANGELOG.md index 562f9ebe8a..0d55afda70 100644 --- a/packages/@headlessui-react/CHANGELOG.md +++ b/packages/@headlessui-react/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix crash in `Combobox` component when in `virtual` mode when options are empty ([#3356](https://github.com/tailwindlabs/headlessui/pull/3356)) - Fix hanging tests when using `anchor` prop ([#3357](https://github.com/tailwindlabs/headlessui/pull/3357)) - Fix `transition` and `focus` prop combination for `PopoverPanel` component ([#3361](https://github.com/tailwindlabs/headlessui/pull/3361)) +- Fix outside click in nested portalled `Popover` components ([#3362](https://github.com/tailwindlabs/headlessui/pull/3362)) ## [2.1.1] - 2024-06-26 diff --git a/packages/@headlessui-react/src/components/dialog/dialog.tsx b/packages/@headlessui-react/src/components/dialog/dialog.tsx index 49fd061f4d..ff7fceb3c5 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.tsx @@ -25,12 +25,15 @@ import { useIsTouchDevice } from '../../hooks/use-is-touch-device' import { useOnDisappear } from '../../hooks/use-on-disappear' import { useOutsideClick } from '../../hooks/use-outside-click' import { useOwnerDocument } from '../../hooks/use-owner' -import { useRootContainers } from '../../hooks/use-root-containers' +import { + MainTreeProvider, + useMainTreeNode, + useRootContainers, +} from '../../hooks/use-root-containers' import { useScrollLock } from '../../hooks/use-scroll-lock' import { useServerHandoffComplete } from '../../hooks/use-server-handoff-complete' import { useSyncRefs } from '../../hooks/use-sync-refs' import { CloseProvider } from '../../internal/close-provider' -import { HoistFormFields } from '../../internal/form-fields' import { ResetOpenClosedProvider, State, useOpenClosed } from '../../internal/open-closed' import { ForcePortalRoot } from '../../internal/portal-force-root' import type { Props } from '../../types' @@ -180,11 +183,9 @@ let InternalDialog = forwardRefWithAs(function InternalDialog< }, } - let { - resolveContainers: resolveRootContainers, - mainTreeNodeRef, - MainTreeNode, - } = useRootContainers({ + let mainTreeNode = useMainTreeNode() + let { resolveContainers: resolveRootContainers } = useRootContainers({ + mainTreeNode, portals, defaultContainers: [defaultContainer], }) @@ -207,8 +208,7 @@ let InternalDialog = forwardRefWithAs(function InternalDialog< ]), disallowed: useEvent(() => [ // Disallow the "main" tree root node - mainTreeNodeRef.current?.closest('body > *:not(#headlessui-portal-root)') ?? - null, + mainTreeNode?.closest('body > *:not(#headlessui-portal-root)') ?? null, ]), }) @@ -320,9 +320,6 @@ let InternalDialog = forwardRefWithAs(function InternalDialog< - - - ) }) @@ -395,13 +392,19 @@ function DialogFn( if ((open !== undefined || transition) && !rest.static) { return ( - - - + + + + + ) } - return + return ( + + + + ) } // --- diff --git a/packages/@headlessui-react/src/components/popover/popover.tsx b/packages/@headlessui-react/src/components/popover/popover.tsx index 082f4a82b6..3f0642f4c5 100644 --- a/packages/@headlessui-react/src/components/popover/popover.tsx +++ b/packages/@headlessui-react/src/components/popover/popover.tsx @@ -32,7 +32,11 @@ import { useOnDisappear } from '../../hooks/use-on-disappear' import { useOutsideClick } from '../../hooks/use-outside-click' import { useOwnerDocument } from '../../hooks/use-owner' import { useResolveButtonType } from '../../hooks/use-resolve-button-type' -import { useMainTreeNode, useRootContainers } from '../../hooks/use-root-containers' +import { + MainTreeProvider, + useMainTreeNode, + useRootContainers, +} from '../../hooks/use-root-containers' import { useScrollLock } from '../../hooks/use-scroll-lock' import { optionalRef, useSyncRefs } from '../../hooks/use-sync-refs' import { Direction as TabDirection, useTabDirection } from '../../hooks/use-tab-direction' @@ -195,7 +199,6 @@ let PopoverGroupContext = createContext<{ unregisterPopover(registerBag: PopoverRegisterBag): void isFocusWithinPopoverGroup(): boolean closeOthers(buttonId: string): void - mainTreeNodeRef: MutableRefObject } | null>(null) PopoverGroupContext.displayName = 'PopoverGroupContext' @@ -343,8 +346,9 @@ function PopoverFn( useEffect(() => registerPopover?.(registerBag), [registerPopover, registerBag]) let [portals, PortalWrapper] = useNestedPortals() + let mainTreeNode = useMainTreeNode(button) let root = useRootContainers({ - mainTreeNodeRef: groupContext?.mainTreeNodeRef, + mainTreeNode, portals, defaultContainers: [button, panel], }) @@ -416,33 +420,34 @@ function PopoverFn( let ourProps = { ref: popoverRef } return ( - - - - - - - - {render({ - ourProps, - theirProps, - slot, - defaultTag: DEFAULT_POPOVER_TAG, - name: 'Popover', + + + + + + + - - - - - - - + > + + {render({ + ourProps, + theirProps, + slot, + defaultTag: DEFAULT_POPOVER_TAG, + name: 'Popover', + })} + + + + + + + + ) } @@ -1110,7 +1115,6 @@ function GroupFn( let internalGroupRef = useRef(null) let groupRef = useSyncRefs(internalGroupRef, ref) let [popovers, setPopovers] = useState([]) - let root = useMainTreeNode() let unregisterPopover = useEvent((registerBag: PopoverRegisterBag) => { setPopovers((existing) => { @@ -1157,15 +1161,8 @@ function GroupFn( unregisterPopover: unregisterPopover, isFocusWithinPopoverGroup, closeOthers, - mainTreeNodeRef: root.mainTreeNodeRef, }), - [ - registerPopover, - unregisterPopover, - isFocusWithinPopoverGroup, - closeOthers, - root.mainTreeNodeRef, - ] + [registerPopover, unregisterPopover, isFocusWithinPopoverGroup, closeOthers] ) let slot = useMemo(() => ({}) satisfies GroupRenderPropArg, []) @@ -1174,16 +1171,17 @@ function GroupFn( let ourProps = { ref: groupRef } return ( - - {render({ - ourProps, - theirProps, - slot, - defaultTag: DEFAULT_GROUP_TAG, - name: 'Popover.Group', - })} - - + + + {render({ + ourProps, + theirProps, + slot, + defaultTag: DEFAULT_GROUP_TAG, + name: 'Popover.Group', + })} + + ) } diff --git a/packages/@headlessui-react/src/components/tabs/tabs.tsx b/packages/@headlessui-react/src/components/tabs/tabs.tsx index eb7d9b36d0..e33f309b17 100644 --- a/packages/@headlessui-react/src/components/tabs/tabs.tsx +++ b/packages/@headlessui-react/src/components/tabs/tabs.tsx @@ -649,7 +649,7 @@ function PanelFn( ) if (!selected && (theirProps.unmount ?? true) && !(theirProps.static ?? false)) { - return