UNPKG

@mui/material

Version:

Material UI is an open-source React component library that implements Google's Material Design. It's comprehensive and can be used in production out of the box.

207 lines (200 loc) 6.55 kB
"use strict"; 'use client'; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var React = _interopRequireWildcard(require("react")); var _utils = require("@mui/utils"); var _extractEventHandlers = _interopRequireDefault(require("@mui/utils/extractEventHandlers")); var _ModalManager = require("./ModalManager"); function getContainer(container) { return typeof container === 'function' ? container() : container; } function getHasTransition(children) { return children ? children.props.hasOwnProperty('in') : false; } const noop = () => {}; // A modal manager used to track and manage the state of open Modals. // Modals don't open on the server so this won't conflict with concurrent requests. const manager = new _ModalManager.ModalManager(); /** * * Demos: * * - [Modal](https://mui.com/base-ui/react-modal/#hook) * * API: * * - [useModal API](https://mui.com/base-ui/react-modal/hooks-api/#use-modal) */ function useModal(parameters) { const { container, disableEscapeKeyDown = false, disableScrollLock = false, closeAfterTransition = false, onTransitionEnter, onTransitionExited, children, onClose, open, rootRef } = parameters; // @ts-ignore internal logic const modal = React.useRef({}); const mountNodeRef = React.useRef(null); const modalRef = React.useRef(null); const handleRef = (0, _utils.unstable_useForkRef)(modalRef, rootRef); const [exited, setExited] = React.useState(!open); const hasTransition = getHasTransition(children); let ariaHiddenProp = true; if (parameters['aria-hidden'] === 'false' || parameters['aria-hidden'] === false) { ariaHiddenProp = false; } const getDoc = () => (0, _utils.unstable_ownerDocument)(mountNodeRef.current); const getModal = () => { modal.current.modalRef = modalRef.current; modal.current.mount = mountNodeRef.current; return modal.current; }; const handleMounted = () => { manager.mount(getModal(), { disableScrollLock }); // Fix a bug on Chrome where the scroll isn't initially 0. if (modalRef.current) { modalRef.current.scrollTop = 0; } }; const handleOpen = (0, _utils.unstable_useEventCallback)(() => { const resolvedContainer = getContainer(container) || getDoc().body; manager.add(getModal(), resolvedContainer); // The element was already mounted. if (modalRef.current) { handleMounted(); } }); const isTopModal = () => manager.isTopModal(getModal()); const handlePortalRef = (0, _utils.unstable_useEventCallback)(node => { mountNodeRef.current = node; if (!node) { return; } if (open && isTopModal()) { handleMounted(); } else if (modalRef.current) { (0, _ModalManager.ariaHidden)(modalRef.current, ariaHiddenProp); } }); const handleClose = React.useCallback(() => { manager.remove(getModal(), ariaHiddenProp); }, [ariaHiddenProp]); React.useEffect(() => { return () => { handleClose(); }; }, [handleClose]); React.useEffect(() => { if (open) { handleOpen(); } else if (!hasTransition || !closeAfterTransition) { handleClose(); } }, [open, handleClose, hasTransition, closeAfterTransition, handleOpen]); const createHandleKeyDown = otherHandlers => event => { otherHandlers.onKeyDown?.(event); // The handler doesn't take event.defaultPrevented into account: // // event.preventDefault() is meant to stop default behaviors like // clicking a checkbox to check it, hitting a button to submit a form, // and hitting left arrow to move the cursor in a text input etc. // Only special HTML elements have these default behaviors. if (event.key !== 'Escape' || event.which === 229 || // Wait until IME is settled. !isTopModal()) { return; } if (!disableEscapeKeyDown) { // Swallow the event, in case someone is listening for the escape key on the body. event.stopPropagation(); if (onClose) { onClose(event, 'escapeKeyDown'); } } }; const createHandleBackdropClick = otherHandlers => event => { otherHandlers.onClick?.(event); if (event.target !== event.currentTarget) { return; } if (onClose) { onClose(event, 'backdropClick'); } }; const getRootProps = (otherHandlers = {}) => { const propsEventHandlers = (0, _extractEventHandlers.default)(parameters); // The custom event handlers shouldn't be spread on the root element delete propsEventHandlers.onTransitionEnter; delete propsEventHandlers.onTransitionExited; const externalEventHandlers = { ...propsEventHandlers, ...otherHandlers }; return { /* * Marking an element with the role presentation indicates to assistive technology * that this element should be ignored; it exists to support the web application and * is not meant for humans to interact with directly. * https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-static-element-interactions.md */ role: 'presentation', ...externalEventHandlers, onKeyDown: createHandleKeyDown(externalEventHandlers), ref: handleRef }; }; const getBackdropProps = (otherHandlers = {}) => { const externalEventHandlers = otherHandlers; return { 'aria-hidden': true, ...externalEventHandlers, onClick: createHandleBackdropClick(externalEventHandlers), open }; }; const getTransitionProps = () => { const handleEnter = () => { setExited(false); if (onTransitionEnter) { onTransitionEnter(); } }; const handleExited = () => { setExited(true); if (onTransitionExited) { onTransitionExited(); } if (closeAfterTransition) { handleClose(); } }; return { onEnter: (0, _utils.unstable_createChainedFunction)(handleEnter, children?.props.onEnter ?? noop), onExited: (0, _utils.unstable_createChainedFunction)(handleExited, children?.props.onExited ?? noop) }; }; return { getRootProps, getBackdropProps, getTransitionProps, rootRef: handleRef, portalRef: handlePortalRef, isTopModal, exited, hasTransition }; } var _default = exports.default = useModal;