UNPKG

terra-abstract-modal

Version:

The abstract modal is a structural component that provides the ability to display portal'd content in a layer above the app.

185 lines (184 loc) 7.82 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); require("promise-polyfill/dist/polyfill.min"); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _reactPortal = require("react-portal"); var _keycodeJs = require("keycode-js"); require("mutationobserver-shim"); require("./_contains-polyfill"); require("./_matches-polyfill"); var _ModalContent = _interopRequireDefault(require("./_ModalContent")); var _excluded = ["ariaLabel", "ariaLabelledBy", "ariaDescribedBy", "children", "classNameModal", "classNameOverlay", "closeOnEsc", "closeOnOutsideClick", "isFullscreen", "isOpen", "role", "rootSelector", "onRequestClose", "zIndex", "isCalledFromNotificationDialog", "shouldTrapFocus"]; // React-focus-on uses native promises which isn't available in IE11 function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } var zIndexes = ['6000', '7000', '8000', '9000']; var propTypes = { /** * String that labels the modal for screen readers. */ ariaLabel: _propTypes.default.string, /** * String that labels the modal for screen readers. */ ariaLabelledBy: _propTypes.default.string, /** * String that labels the modal for screen readers. */ ariaDescribedBy: _propTypes.default.string, /** * Content inside the modal dialog. */ children: _propTypes.default.node.isRequired, /** * CSS classnames that are appended to the modal. */ classNameModal: _propTypes.default.string, /** * CSS classnames that are appended to the overlay. */ classNameOverlay: _propTypes.default.string, /** * If set to true, the modal will close when the esc key is pressed. */ closeOnEsc: _propTypes.default.bool, /** * If set to true, the modal will close when a mouse click is triggered outside the modal. */ closeOnOutsideClick: _propTypes.default.bool, /** * If set to true, the modal will be fullscreen on all breakpoint sizes. */ isFullscreen: _propTypes.default.bool, /** * If set to true, the modal will rendered as opened. */ isOpen: _propTypes.default.bool.isRequired, /** * Callback function indicating a close condition was met, should be combined with isOpen for state management. */ onRequestClose: _propTypes.default.func.isRequired, /** * Role attribute on the modal dialog. */ role: _propTypes.default.string, /** * Allows assigning of root element custom data attribute for easy selecting of document base component. */ rootSelector: _propTypes.default.string, /** * Z-Index layer to apply to the ModalContent and ModalOverlay. Valid values are the standard modal layer: '6000', and the max layer: '8000'. */ zIndex: _propTypes.default.oneOf(zIndexes), /** * @private * Callback function to set the reference of the element that will receive focus when the Slide content is visible. */ setModalFocusElementRef: _propTypes.default.func, /** * @private * If set to true, the AbstractModal is rendered inside a NotificationDialog. */ isCalledFromNotificationDialog: _propTypes.default.bool, /** * If set to true, then the focus lock will get enabled. */ shouldTrapFocus: _propTypes.default.bool }; var defaultProps = { classNameModal: null, classNameOverlay: null, closeOnEsc: true, closeOnOutsideClick: true, isFullscreen: false, role: 'dialog', rootSelector: '#root', zIndex: '6000', isCalledFromNotificationDialog: false, shouldTrapFocus: false }; var AbstractModal = function AbstractModal(props) { var ariaLabel = props.ariaLabel, ariaLabelledBy = props.ariaLabelledBy, ariaDescribedBy = props.ariaDescribedBy, children = props.children, classNameModal = props.classNameModal, classNameOverlay = props.classNameOverlay, closeOnEsc = props.closeOnEsc, closeOnOutsideClick = props.closeOnOutsideClick, isFullscreen = props.isFullscreen, isOpen = props.isOpen, role = props.role, rootSelector = props.rootSelector, onRequestClose = props.onRequestClose, zIndex = props.zIndex, isCalledFromNotificationDialog = props.isCalledFromNotificationDialog, shouldTrapFocus = props.shouldTrapFocus, customProps = (0, _objectWithoutProperties2.default)(props, _excluded); var modalElementRef = (0, _react.useRef)(); (0, _react.useLayoutEffect)(function () { // eslint-disable-next-line no-prototype-builtins if (!Element.prototype.hasOwnProperty('inert')) { // IE10 throws an error if wicg-inert is imported too early, as wicg-inert tries to set an observer on document.body which may not exist on import // eslint-disable-next-line global-require require('wicg-inert/dist/inert'); } }, []); (0, _react.useEffect)(function () { function handleDocumentKeydown(e) { if (e.keyCode === _keycodeJs.KEY_ESCAPE && closeOnEsc && isOpen) { var body = document.querySelector('body'); if (e.target === body) { onRequestClose(); } } } document.addEventListener('keydown', handleDocumentKeydown); return function () { document.removeEventListener('keydown', handleDocumentKeydown); }; }, [closeOnEsc, isOpen, onRequestClose]); var handleKeydown = (0, _react.useCallback)(function (e) { if (e.keyCode === _keycodeJs.KEY_ESCAPE && closeOnEsc && isOpen) { var currentModalNode = modalElementRef.current; if (currentModalNode && (e.target === currentModalNode || currentModalNode.contains(e.target))) { if (e.target === modalElementRef.current || modalElementRef.current.contains(e.target)) { onRequestClose(); } } } }, [closeOnEsc, isOpen, onRequestClose, modalElementRef]); if (!isOpen) { return null; } return /*#__PURE__*/_react.default.createElement(_reactPortal.Portal, { isOpened: isOpen }, /*#__PURE__*/_react.default.createElement(_ModalContent.default, (0, _extends2.default)({}, customProps, { closeOnOutsideClick: closeOnOutsideClick, ariaLabel: ariaLabel, ariaLabelledBy: ariaLabelledBy, ariaDescribedBy: ariaDescribedBy, classNameModal: classNameModal, classNameOverlay: classNameOverlay, role: role, isFullscreen: isFullscreen, onRequestClose: onRequestClose, rootSelector: rootSelector, zIndex: zIndex, "aria-modal": "true", ref: modalElementRef, onKeyDown: handleKeydown, isCalledFromNotificationDialog: isCalledFromNotificationDialog, shouldTrapFocus: shouldTrapFocus }), children)); }; AbstractModal.propTypes = propTypes; AbstractModal.defaultProps = defaultProps; var _default = exports.default = AbstractModal;