diff --git a/packages/@headlessui-react/src/components/dialog/dialog.tsx b/packages/@headlessui-react/src/components/dialog/dialog.tsx index 8d4b42cec8..859fda748f 100644 --- a/packages/@headlessui-react/src/components/dialog/dialog.tsx +++ b/packages/@headlessui-react/src/components/dialog/dialog.tsx @@ -32,7 +32,7 @@ import { Description, useDescriptions } from '../description/description' import { useOpenClosed, State } from '../../internal/open-closed' import { useServerHandoffComplete } from '../../hooks/use-server-handoff-complete' import { StackProvider, StackMessage } from '../../internal/stack-context' -import { useOutsideClick, Features as OutsideClickFeatures } from '../../hooks/use-outside-click' +import { useOutsideClick } from '../../hooks/use-outside-click' import { getOwnerDocument } from '../../utils/owner' import { useOwnerDocument } from '../../hooks/use-owner' import { useEventListener } from '../../hooks/use-event-listener' @@ -100,13 +100,7 @@ let DEFAULT_DIALOG_TAG = 'div' as const interface DialogRenderPropArg { open: boolean } -type DialogPropsWeControl = - | 'id' - | 'role' - | 'aria-modal' - | 'aria-describedby' - | 'aria-labelledby' - | 'onClick' +type DialogPropsWeControl = 'id' | 'role' | 'aria-modal' | 'aria-describedby' | 'aria-labelledby' let DialogRenderFeatures = Features.RenderStrategy | Features.Static @@ -224,7 +218,7 @@ let DialogRoot = forwardRefWithAs(function Dialog< close() }, - OutsideClickFeatures.IgnoreScrollbars + enabled ) // Handle `Escape` to close @@ -311,9 +305,6 @@ let DialogRoot = forwardRefWithAs(function Dialog< 'aria-modal': dialogState === DialogStates.Open ? true : undefined, 'aria-labelledby': state.titleId, 'aria-describedby': describedby, - onClick(event: ReactMouseEvent) { - event.stopPropagation() - }, } return ( @@ -492,10 +483,17 @@ let Panel = forwardRefWithAs(function Panel elements even if we portalled the Dialog. + let handleClick = useEvent((event: ReactMouseEvent) => { + event.stopPropagation() + }) + let theirProps = props let ourProps = { ref: panelRef, id, + onClick: handleClick, } return render({ diff --git a/packages/@headlessui-react/src/components/focus-trap/focus-trap.tsx b/packages/@headlessui-react/src/components/focus-trap/focus-trap.tsx index 0cdf662b65..bbab04b213 100644 --- a/packages/@headlessui-react/src/components/focus-trap/focus-trap.tsx +++ b/packages/@headlessui-react/src/components/focus-trap/focus-trap.tsx @@ -147,7 +147,10 @@ function useRestoreFocus({ ownerDocument }: { ownerDocument: Document | null }, useWatch(() => { if (enabled) return - focusElement(restoreElement.current) + if (ownerDocument?.activeElement === ownerDocument?.body) { + focusElement(restoreElement.current) + } + restoreElement.current = null }, [enabled]) diff --git a/packages/@headlessui-react/src/components/menu/menu.tsx b/packages/@headlessui-react/src/components/menu/menu.tsx index 1dae520d4a..a46609b2eb 100644 --- a/packages/@headlessui-react/src/components/menu/menu.tsx +++ b/packages/@headlessui-react/src/components/menu/menu.tsx @@ -344,7 +344,6 @@ let Button = forwardRefWithAs(function Button state.buttonRef.current?.focus({ preventScroll: true })) } else { event.preventDefault() - event.stopPropagation() dispatch({ type: ActionTypes.OpenMenu }) } }) diff --git a/packages/@headlessui-vue/src/components/dialog/dialog.ts b/packages/@headlessui-vue/src/components/dialog/dialog.ts index 0845d073f8..0cf90f18de 100644 --- a/packages/@headlessui-vue/src/components/dialog/dialog.ts +++ b/packages/@headlessui-vue/src/components/dialog/dialog.ts @@ -29,7 +29,7 @@ import { ForcePortalRoot } from '../../internal/portal-force-root' import { Description, useDescriptions } from '../description/description' import { dom } from '../../utils/dom' import { useOpenClosed, State } from '../../internal/open-closed' -import { useOutsideClick, Features as OutsideClickFeatures } from '../../hooks/use-outside-click' +import { useOutsideClick } from '../../hooks/use-outside-click' import { getOwnerDocument } from '../../utils/owner' import { useEventListener } from '../../hooks/use-event-listener' import { Hidden, Features as HiddenFeatures } from '../../internal/hidden' @@ -196,8 +196,7 @@ export let Dialog = defineComponent({ api.close() nextTick(() => target?.focus()) - }, - OutsideClickFeatures.IgnoreScrollbars + } ) // Handle `Escape` to close @@ -264,10 +263,6 @@ export let Dialog = defineComponent({ onInvalidate(() => observer.disconnect()) }) - function handleClick(event: MouseEvent) { - event.stopPropagation() - } - return () => { let ourProps = { // Manually passthrough the attributes, because Vue can't automatically pass @@ -279,7 +274,6 @@ export let Dialog = defineComponent({ 'aria-modal': dialogState.value === DialogStates.Open ? true : undefined, 'aria-labelledby': titleId.value, 'aria-describedby': describedby.value, - onClick: handleClick, } let { open: _, initialFocus, ...incomingProps } = props @@ -417,10 +411,15 @@ export let DialogPanel = defineComponent({ expose({ el: api.panelRef, $el: api.panelRef }) + function handleClick(event: MouseEvent) { + event.stopPropagation() + } + return () => { let ourProps = { id, ref: api.panelRef, + onClick: handleClick, } let incomingProps = props diff --git a/packages/@headlessui-vue/src/components/menu/menu.ts b/packages/@headlessui-vue/src/components/menu/menu.ts index e34a831462..5e29c4c18d 100644 --- a/packages/@headlessui-vue/src/components/menu/menu.ts +++ b/packages/@headlessui-vue/src/components/menu/menu.ts @@ -289,7 +289,6 @@ export let MenuButton = defineComponent({ nextTick(() => dom(api.buttonRef)?.focus({ preventScroll: true })) } else { event.preventDefault() - event.stopPropagation() api.openMenu() nextFrame(() => dom(api.itemsRef)?.focus({ preventScroll: true })) }