UNPKG

react-aria

Version:
1 lines 8.54 kB
{"mappings":";;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;CAUC;;;;AA2BD,MAAM,8CAAU,CAAA,GAAA,sCAAI,EAAE,aAAa,CAAsB;AAUlD,SAAS,yCAAc,KAAyB;IACrD,IAAI,YAAC,QAAQ,EAAC,GAAG;IACjB,IAAI,SAAS,CAAA,GAAA,uBAAS,EAAE;IACxB,IAAI,CAAC,YAAY,cAAc,GAAG,CAAA,GAAA,qBAAO,EAAE;IAC3C,IAAI,UAAU,CAAA,GAAA,oBAAM,EAClB,IAAO,CAAA;oBACL;wBACA;YACA;gBACE,cAAc,CAAA,QAAS,QAAQ;gBAC/B,IAAI,QACF,OAAO,QAAQ;YAEnB;YACA;gBACE,cAAc,CAAA,QAAS,QAAQ;gBAC/B,IAAI,QACF,OAAO,WAAW;YAEtB;QACF,CAAA,GACA;QAAC;QAAQ;KAAW;IAGtB,qBAAO,0DAAC,8BAAQ,QAAQ;QAAC,OAAO;OAAU;AAC5C;AAaO,SAAS;IACd,IAAI,UAAU,CAAA,GAAA,uBAAS,EAAE;IACzB,OAAO;QACL,oBAAoB;YAClB,eAAe,WAAW,QAAQ,UAAU,GAAG,IAAI,OAAO;QAC5D;IACF;AACF;AAEA;;CAEC,GACD,SAAS,0CAAoB,KAAyB;IACpD,IAAI,sBAAC,kBAAkB,EAAC,GAAG;IAC3B,qBAAO,0DAAC;QAAI,0BAAA;QAAwB,GAAG,KAAK;QAAG,GAAG,kBAAkB;;AACtE;AAUO,SAAS,0CAAgB,KAAyB;IACvD,qBACE,0DAAC,8DACC,0DAAC,2CAAwB;AAG/B;AAmBO,SAAS,0CAAiB,KAA4B;IAC3D,IAAI,QAAQ,CAAA,GAAA,kCAAO;IACnB,IAAI,mBAAC,kBAAkB,QAAQ,OAAO,SAAS,IAAI,EAAE,GAAG,MAAK,GAAG;IAChE,IAAI,gBAAC,YAAY,EAAC,GAAG,CAAA,GAAA,iDAAsB;IAC3C,IAAI,CAAC,MAAM,eAAe,IAAI,cAC5B,kBAAkB;IAGpB,CAAA,GAAA,sCAAI,EAAE,SAAS,CAAC;QACd,IAAI,iBAAiB,QAAQ,6BAC3B,MAAM,IAAI,MACR;IAGN,GAAG;QAAC;KAAgB;IAEpB,IAAI,CAAC,iBACH,OAAO;IAGT,IAAI,yBAAW,0DAAC,2CAAoB;IACpC,qBAAO,CAAA,GAAA,yCAAO,EAAE,YAAY,CAAC,UAAU;AACzC;AAsBO,SAAS,0CAAS,OAA0B;IACjD,4EAA4E;IAC5E,IAAI,UAAU,CAAA,GAAA,uBAAS,EAAE;IACzB,IAAI,CAAC,SACH,MAAM,IAAI,MAAM;IAGlB,CAAA,GAAA,sBAAQ,EAAE;QACR,IAAI,SAAS,cAAc,CAAC,WAAW,CAAC,QAAQ,MAAM,EACpD;QAGF,+EAA+E;QAC/E,+EAA+E;QAC/E,QAAQ,MAAM,CAAC,QAAQ;QACvB,OAAO;YACL,IAAI,WAAW,QAAQ,MAAM,EAC3B,QAAQ,MAAM,CAAC,WAAW;QAE9B;IACF,GAAG;QAAC;QAAS,QAAQ,MAAM;QAAE,SAAS;KAAW;IAEjD,OAAO;QACL,YAAY;YACV,gBAAgB,CAAC,SAAS;QAC5B;IACF;AACF","sources":["packages/react-aria/src/overlays/useModal.tsx"],"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} from '@react-types/shared';\nimport React, {\n AriaAttributes,\n JSX,\n ReactNode,\n useContext,\n useEffect,\n useMemo,\n useState\n} from 'react';\nimport ReactDOM from 'react-dom';\nimport {useIsSSR} from '../ssr/SSRProvider';\nimport {useUNSAFE_PortalContext} from './PortalProvider';\n\nexport interface ModalProviderProps extends DOMAttributes {\n children: ReactNode;\n}\n\ninterface ModalContext {\n parent: ModalContext | null;\n modalCount: number;\n addModal: () => void;\n removeModal: () => void;\n}\n\nconst Context = React.createContext<ModalContext | null>(null);\n\n/**\n * Each ModalProvider tracks how many modals are open in its subtree. On mount, the modals trigger\n * `addModal` to increment the count, and trigger `removeModal` on unmount to decrement it. This is\n * done recursively so that all parent providers are incremented and decremented. If the modal count\n * is greater than zero, we add `aria-hidden` to this provider to hide its subtree from screen\n * readers. This is done using React context in order to account for things like portals, which can\n * cause the React tree and the DOM tree to differ significantly in structure.\n */\nexport function ModalProvider(props: ModalProviderProps): JSX.Element {\n let {children} = props;\n let parent = useContext(Context);\n let [modalCount, setModalCount] = useState(0);\n let context = useMemo(\n () => ({\n parent,\n modalCount,\n addModal() {\n setModalCount(count => count + 1);\n if (parent) {\n parent.addModal();\n }\n },\n removeModal() {\n setModalCount(count => count - 1);\n if (parent) {\n parent.removeModal();\n }\n }\n }),\n [parent, modalCount]\n );\n\n return <Context.Provider value={context}>{children}</Context.Provider>;\n}\n\nexport interface ModalProviderAria {\n /**\n * Props to be spread on the container element.\n */\n modalProviderProps: AriaAttributes;\n}\n\n/**\n * Used to determine if the tree should be aria-hidden based on how many\n * modals are open.\n */\nexport function useModalProvider(): ModalProviderAria {\n let context = useContext(Context);\n return {\n modalProviderProps: {\n 'aria-hidden': context && context.modalCount > 0 ? true : undefined\n }\n };\n}\n\n/**\n * Creates a root node that will be aria-hidden if there are other modals open.\n */\nfunction OverlayContainerDOM(props: ModalProviderProps) {\n let {modalProviderProps} = useModalProvider();\n return <div data-overlay-container {...props} {...modalProviderProps} />;\n}\n\n/**\n * An OverlayProvider acts as a container for the top-level application.\n * Any application that uses modal dialogs or other overlays should\n * be wrapped in a `<OverlayProvider>`. This is used to ensure that\n * the main content of the application is hidden from screen readers\n * if a modal or other overlay is opened. Only the top-most modal or\n * overlay should be accessible at once.\n */\nexport function OverlayProvider(props: ModalProviderProps): JSX.Element {\n return (\n <ModalProvider>\n <OverlayContainerDOM {...props} />\n </ModalProvider>\n );\n}\n\nexport interface OverlayContainerProps extends ModalProviderProps {\n /**\n * The container element in which the overlay portal will be placed.\n *\n * @deprecated - Use a parent UNSAFE_PortalProvider to set your portal container instead.\n * @default document.body\n */\n portalContainer?: Element;\n}\n\n/**\n * A container for overlays like modals and popovers. Renders the overlay\n * into a Portal which is placed at the end of the document body.\n * Also ensures that the overlay is hidden from screen readers if a\n * nested modal is opened. Only the top-most modal or overlay should\n * be accessible at once.\n */\nexport function OverlayContainer(props: OverlayContainerProps): React.ReactPortal | null {\n let isSSR = useIsSSR();\n let {portalContainer = isSSR ? null : document.body, ...rest} = props;\n let {getContainer} = useUNSAFE_PortalContext();\n if (!props.portalContainer && getContainer) {\n portalContainer = getContainer();\n }\n\n React.useEffect(() => {\n if (portalContainer?.closest('[data-overlay-container]')) {\n throw new Error(\n 'An OverlayContainer must not be inside another container. Please change the portalContainer prop.'\n );\n }\n }, [portalContainer]);\n\n if (!portalContainer) {\n return null;\n }\n\n let contents = <OverlayProvider {...rest} />;\n return ReactDOM.createPortal(contents, portalContainer);\n}\n\ninterface ModalAriaProps extends DOMAttributes {\n /** Data attribute marks the dom node as a modal for the aria-modal-polyfill. */\n 'data-ismodal': boolean;\n}\n\nexport interface AriaModalOptions {\n isDisabled?: boolean;\n}\n\nexport interface ModalAria {\n /** Props for the modal content element. */\n modalProps: ModalAriaProps;\n}\n\n/**\n * Hides content outside the current `<OverlayContainer>` from screen readers\n * on mount and restores it on unmount. Typically used by modal dialogs and\n * other types of overlays to ensure that only the top-most modal is\n * accessible at once.\n */\nexport function useModal(options?: AriaModalOptions): ModalAria {\n // Add aria-hidden to all parent providers on mount, and restore on unmount.\n let context = useContext(Context);\n if (!context) {\n throw new Error('Modal is not contained within a provider');\n }\n\n useEffect(() => {\n if (options?.isDisabled || !context || !context.parent) {\n return;\n }\n\n // The immediate context is from the provider containing this modal, so we only\n // want to trigger aria-hidden on its parents not on the modal provider itself.\n context.parent.addModal();\n return () => {\n if (context && context.parent) {\n context.parent.removeModal();\n }\n };\n }, [context, context.parent, options?.isDisabled]);\n\n return {\n modalProps: {\n 'data-ismodal': !options?.isDisabled\n }\n };\n}\n"],"names":[],"version":3,"file":"useModal.cjs.map"}