UNPKG

react-aria

Version:
1 lines 7.71 kB
{"mappings":";;;;;;AAAA;;;;;;;;;;CAUC;;;;;AAiDD,MAAM,wCAA+C,EAAE;AAOhD,SAAS,0CAAW,KAAuB,EAAE,GAA8B;IAChF,IAAI,WACF,OAAO,qBACP,iBAAiB,UACjB,MAAM,iBACN,gBAAgB,kCAChB,4BAA4B,qCAC5B,4BAA4B,EAC7B,GAAG;IAEJ,IAAI,qBAAqB,CAAA,GAAA,aAAK,EAA6B;IAE3D,wFAAwF;IACxF,CAAA,GAAA,gBAAQ,EAAE;QACR,IAAI,UAAU,CAAC,sCAAgB,QAAQ,CAAC,MAAM;YAC5C,sCAAgB,IAAI,CAAC;YACrB,OAAO;gBACL,IAAI,QAAQ,sCAAgB,OAAO,CAAC;gBACpC,IAAI,SAAS,GACX,sCAAgB,MAAM,CAAC,OAAO;YAElC;QACF;IACF,GAAG;QAAC;QAAQ;KAAI;IAEhB,4EAA4E;IAC5E,IAAI,SAAS;QACX,IAAI,qCAAe,CAAC,sCAAgB,MAAM,GAAG,EAAE,KAAK,OAAO,SACzD;IAEJ;IAEA,IAAI,yBAAyB,CAAC;QAC5B,MAAM,iBAAiB,qCAAe,CAAC,sCAAgB,MAAM,GAAG,EAAE;QAClE,mBAAmB,OAAO,GAAG;QAC7B,IACE,CAAC,gCACD,6BAA6B,CAAA,GAAA,yCAAa,EAAE,KAE5C;YAAA,IAAI,mBAAmB,KACrB,EAAE,eAAe;QACnB;IAEJ;IAEA,IAAI,oBAAoB,CAAC;QACvB,IACE,CAAC,gCACD,6BAA6B,CAAA,GAAA,yCAAa,EAAE,KAC5C;YACA,IAAI,qCAAe,CAAC,sCAAgB,MAAM,GAAG,EAAE,KAAK,KAClD,EAAE,eAAe;YAEnB,IAAI,mBAAmB,OAAO,KAAK,KACjC;QAEJ;QACA,mBAAmB,OAAO,GAAG;IAC/B;IAEA,wBAAwB;IACxB,IAAI,YAAY,CAAA;QACd,IAAI,EAAE,GAAG,KAAK,YAAY,CAAC,6BAA6B,CAAC,EAAE,WAAW,CAAC,WAAW,EAAE;YAClF,EAAE,eAAe;YACjB,EAAE,cAAc;YAChB;QACF;IACF;IAEA,kDAAkD;IAClD,CAAA,GAAA,yCAAiB,EAAE;aACjB;QACA,mBAAmB,iBAAiB,SAAS,oBAAoB;gCACjE;IACF;IAEA,IAAI,oBAAC,gBAAgB,EAAC,GAAG,CAAA,GAAA,yCAAa,EAAE;QACtC,YAAY,CAAC;QACb,cAAc,CAAA;YACZ,gFAAgF;YAChF,8GAA8G;YAC9G,6FAA6F;YAC7F,sDAAsD;YACtD,sDAAsD;YACtD,EAAE;YACF,2EAA2E;YAC3E,yEAAyE;YACzE,kEAAkE;YAClE,IAAI,CAAC,EAAE,aAAa,IAAI,CAAA,GAAA,yCAA4B,EAAE,EAAE,aAAa,GACnE;YAGF,IACE,CAAC,gCACD,6BAA6B,EAAE,aAAa,GAE5C;QAEJ;IACF;IAEA,OAAO;QACL,cAAc;uBACZ;YACA,GAAG,gBAAgB;QACrB;QACA,eAAe,CAAC;IAClB;AACF","sources":["packages/react-aria/src/overlays/useOverlay.ts"],"sourcesContent":["/*\n * Copyright 2020 Adobe. All rights reserved.\n * This file is licensed to you under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License. You may obtain a copy\n * of the License at http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software distributed under\n * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS\n * OF ANY KIND, either express or implied. See the License for the specific language\n * governing permissions and limitations under the License.\n */\n\nimport {DOMAttributes, RefObject} from '@react-types/shared';\nimport {getEventTarget} from '../utils/shadowdom/DOMFunctions';\nimport {isElementInChildOfActiveScope} from '../focus/FocusScope';\nimport {useEffect, useRef} from 'react';\nimport {useFocusWithin} from '../interactions/useFocusWithin';\nimport {useInteractOutside} from '../interactions/useInteractOutside';\n\nexport interface AriaOverlayProps {\n /** Whether the overlay is currently open. */\n isOpen?: boolean;\n\n /** Handler that is called when the overlay should close. */\n onClose?: () => void;\n\n /**\n * Whether to close the overlay when the user interacts outside it.\n *\n * @default false\n */\n isDismissable?: boolean;\n\n /** Whether the overlay should close when focus is lost or moves outside it. */\n shouldCloseOnBlur?: boolean;\n\n /**\n * Whether pressing the escape key to close the overlay should be disabled.\n *\n * @default false\n */\n isKeyboardDismissDisabled?: boolean;\n\n /**\n * When user interacts with the argument element outside of the overlay ref,\n * return true if onClose should be called. This gives you a chance to filter\n * out interaction with elements that should not dismiss the overlay.\n * By default, onClose will always be called on interaction outside the overlay ref.\n */\n shouldCloseOnInteractOutside?: (element: Element) => boolean;\n}\n\nexport interface OverlayAria {\n /** Props to apply to the overlay container element. */\n overlayProps: DOMAttributes;\n /** Props to apply to the underlay element, if any. */\n underlayProps: DOMAttributes;\n}\n\nconst visibleOverlays: RefObject<Element | null>[] = [];\n\n/**\n * Provides the behavior for overlays such as dialogs, popovers, and menus.\n * Hides the overlay when the user interacts outside it, when the Escape key is pressed,\n * or optionally, on blur. Only the top-most overlay will close at once.\n */\nexport function useOverlay(props: AriaOverlayProps, ref: RefObject<Element | null>): OverlayAria {\n let {\n onClose,\n shouldCloseOnBlur,\n isOpen,\n isDismissable = false,\n isKeyboardDismissDisabled = false,\n shouldCloseOnInteractOutside\n } = props;\n\n let lastVisibleOverlay = useRef<RefObject<Element | null>>(undefined);\n\n // Add the overlay ref to the stack of visible overlays on mount, and remove on unmount.\n useEffect(() => {\n if (isOpen && !visibleOverlays.includes(ref)) {\n visibleOverlays.push(ref);\n return () => {\n let index = visibleOverlays.indexOf(ref);\n if (index >= 0) {\n visibleOverlays.splice(index, 1);\n }\n };\n }\n }, [isOpen, ref]);\n\n // Only hide the overlay when it is the topmost visible overlay in the stack\n let onHide = () => {\n if (visibleOverlays[visibleOverlays.length - 1] === ref && onClose) {\n onClose();\n }\n };\n\n let onInteractOutsideStart = (e: PointerEvent) => {\n const topMostOverlay = visibleOverlays[visibleOverlays.length - 1];\n lastVisibleOverlay.current = topMostOverlay;\n if (\n !shouldCloseOnInteractOutside ||\n shouldCloseOnInteractOutside(getEventTarget(e) as Element)\n ) {\n if (topMostOverlay === ref) {\n e.stopPropagation();\n }\n }\n };\n\n let onInteractOutside = (e: PointerEvent) => {\n if (\n !shouldCloseOnInteractOutside ||\n shouldCloseOnInteractOutside(getEventTarget(e) as Element)\n ) {\n if (visibleOverlays[visibleOverlays.length - 1] === ref) {\n e.stopPropagation();\n }\n if (lastVisibleOverlay.current === ref) {\n onHide();\n }\n }\n lastVisibleOverlay.current = undefined;\n };\n\n // Handle the escape key\n let onKeyDown = e => {\n if (e.key === 'Escape' && !isKeyboardDismissDisabled && !e.nativeEvent.isComposing) {\n e.stopPropagation();\n e.preventDefault();\n onHide();\n }\n };\n\n // Handle clicking outside the overlay to close it\n useInteractOutside({\n ref,\n onInteractOutside: isDismissable && isOpen ? onInteractOutside : undefined,\n onInteractOutsideStart\n });\n\n let {focusWithinProps} = useFocusWithin({\n isDisabled: !shouldCloseOnBlur,\n onBlurWithin: e => {\n // Do not close if relatedTarget is null, which means focus is lost to the body.\n // That can happen when switching tabs, or due to a VoiceOver/Chrome bug with Control+Option+Arrow navigation.\n // Clicking on the body to close the overlay should already be handled by useInteractOutside.\n // https://github.com/adobe/react-spectrum/issues/4130\n // https://github.com/adobe/react-spectrum/issues/4922\n //\n // If focus is moving into a child focus scope (e.g. menu inside a dialog),\n // do not close the outer overlay. At this point, the active scope should\n // still be the outer overlay, since blur events run before focus.\n if (!e.relatedTarget || isElementInChildOfActiveScope(e.relatedTarget)) {\n return;\n }\n\n if (\n !shouldCloseOnInteractOutside ||\n shouldCloseOnInteractOutside(e.relatedTarget as Element)\n ) {\n onClose?.();\n }\n }\n });\n\n return {\n overlayProps: {\n onKeyDown,\n ...focusWithinProps\n },\n underlayProps: {}\n };\n}\n"],"names":[],"version":3,"file":"useOverlay.mjs.map"}