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.

198 lines (196 loc) 8.95 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")); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _reactIntl = require("react-intl"); var _classnames = _interopRequireDefault(require("classnames")); var _bind = _interopRequireDefault(require("classnames/bind")); var _terraThemeContext = _interopRequireDefault(require("terra-theme-context")); var _terraVisuallyHiddenText = _interopRequireDefault(require("terra-visually-hidden-text")); var _reactFocusOn = require("react-focus-on"); var _ModalOverlay = _interopRequireDefault(require("./_ModalOverlay")); var _inertHelpers = require("./inertHelpers"); var _ModalContentModule = _interopRequireDefault(require("./ModalContent.module.scss")); var _excluded = ["ariaLabel", "ariaLabelledBy", "ariaDescribedBy", "children", "classNameModal", "classNameOverlay", "closeOnOutsideClick", "onRequestClose", "role", "isFullscreen", "isScrollable", "rootSelector", "zIndex", "setModalFocusElementRef", "isCalledFromNotificationDialog", "shouldTrapFocus"]; 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 cx = _bind.default.bind(_ModalContentModule.default); 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 a mouseclick is triggered outside the modal. */ closeOnOutsideClick: _propTypes.default.bool, /** * Callback function indicating a close condition was met, should be combined with isOpen for state management. */ onRequestClose: _propTypes.default.func.isRequired, /** * If set to true, the modal will be fullscreen on all breakpoint sizes. */ isFullscreen: _propTypes.default.bool, /** * If set to true, the modal dialog with have overflow-y set to scroll. */ isScrollable: _propTypes.default.bool, /** * 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. */ 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, closeOnOutsideClick: true, isFullscreen: false, isScrollable: false, role: 'dialog', rootSelector: '#root', zIndex: '6000', isCalledFromNotificationDialog: false }; var ModalContent = /*#__PURE__*/(0, _react.forwardRef)(function (props, ref) { var ariaLabel = props.ariaLabel, ariaLabelledBy = props.ariaLabelledBy, ariaDescribedBy = props.ariaDescribedBy, children = props.children, classNameModal = props.classNameModal, classNameOverlay = props.classNameOverlay, closeOnOutsideClick = props.closeOnOutsideClick, onRequestClose = props.onRequestClose, role = props.role, isFullscreen = props.isFullscreen, isScrollable = props.isScrollable, rootSelector = props.rootSelector, zIndex = props.zIndex, setModalFocusElementRef = props.setModalFocusElementRef, isCalledFromNotificationDialog = props.isCalledFromNotificationDialog, shouldTrapFocus = props.shouldTrapFocus, customProps = (0, _objectWithoutProperties2.default)(props, _excluded); (0, _react.useEffect)(function () { // Store element that was last focused prior to modal opening var modalTrigger = document.activeElement; (0, _inertHelpers.showModalDomUpdates)(ref.current, rootSelector); return function () { (0, _inertHelpers.hideModalDomUpdates)(modalTrigger, rootSelector); }; }, [ref, rootSelector]); var zIndexLayer = '6000'; if (zIndexes.indexOf(zIndex) >= 0) { zIndexLayer = zIndex; } var theme = _react.default.useContext(_terraThemeContext.default); var modalClassName = (0, _classnames.default)(cx('abstract-modal', { 'is-fullscreen': isFullscreen }, "layer-".concat(zIndexLayer), theme.className), classNameModal); var modalContainerClassName = (0, _classnames.default)(cx('abstract-modal-container')); // Delete the closePortal prop that comes from react-portal. delete customProps.closePortal; delete customProps.fallbackFocus; var beginLabelId = ariaLabel === 'Modal' ? 'Terra.AbstractModal.BeginModalDialog' : 'Terra.AbstractModal.BeginModalDialogTitle'; var endLabelId = ariaLabel === 'Modal' ? 'Terra.AbstractModal.EndModalDialog' : 'Terra.AbstractModal.EndModalDialogTitle'; var modalContent = /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({}, customProps, { "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, className: modalClassName, role: role, ref: ref }), /*#__PURE__*/_react.default.createElement("div", { className: modalContainerClassName, ref: setModalFocusElementRef, "data-terra-abstract-modal-begin": true, tabIndex: "-1" }, !isCalledFromNotificationDialog && /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, { id: beginLabelId, values: { title: ariaLabel } }, function (text) { // In the latest version of react-intl this param is an array, when previous versions it was a string. var useText = text; if (Array.isArray(text)) { useText = text.join(''); } return /*#__PURE__*/_react.default.createElement(_terraVisuallyHiddenText.default, { text: useText }); }), children, !isCalledFromNotificationDialog && /*#__PURE__*/_react.default.createElement(_reactIntl.FormattedMessage, { id: endLabelId, values: { title: ariaLabel } }, function (text) { // In the latest version of react-intl this param is an array, when previous versions it was a string. var useText = text; if (Array.isArray(text)) { useText = text.join(''); } return /*#__PURE__*/_react.default.createElement(_terraVisuallyHiddenText.default, { text: useText }); }))); return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_ModalOverlay.default, { onClick: closeOnOutsideClick ? onRequestClose : null, className: classNameOverlay, zIndex: zIndexLayer }), shouldTrapFocus ? /*#__PURE__*/_react.default.createElement(_reactFocusOn.FocusOn, { onClickOutside: closeOnOutsideClick ? onRequestClose : null }, modalContent) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, modalContent)); }); ModalContent.propTypes = propTypes; ModalContent.defaultProps = defaultProps; var _default = exports.default = ModalContent;