UNPKG

@atlaskit/modal-dialog

Version:

A modal dialog displays content that requires user interaction, in a layer above the page.

159 lines (156 loc) 7.03 kB
/* modal-wrapper.tsx generated by @compiled/babel-plugin v0.39.1 */ import _extends from "@babel/runtime/helpers/extends"; import "./modal-wrapper.compiled.css"; import * as React from 'react'; import { ax, ix } from "@compiled/react/runtime"; import { useCallback } from 'react'; import FocusLock from 'react-focus-lock'; import ScrollLock, { TouchScrollable } from 'react-scrolllock'; import { usePlatformLeafEventHandler } from '@atlaskit/analytics-next'; import Blanket from '@atlaskit/blanket'; import noop from '@atlaskit/ds-lib/noop'; import { Layering } from '@atlaskit/layering'; import { useNotifyOpenLayerObserver } from '@atlaskit/layering/experimental/open-layer-observer'; import { Motion } from '@atlaskit/motion'; import FadeIn from '@atlaskit/motion/fade-in'; import { fg } from '@atlaskit/platform-feature-flags'; import Portal from '@atlaskit/portal'; import { layers } from '@atlaskit/theme/constants'; import useModalStack from '../hooks/use-modal-stack'; import usePreventProgrammaticScroll from '../hooks/use-prevent-programmatic-scroll'; import ModalDialog from './modal-dialog'; const fillScreenStyles = null; const allowlistElements = (element, callback) => { // Allow focus to reach elements outside the modal: // if AUI dialog is allowListed and visible if (!!document.querySelector('.aui-blanket:not([hidden])')) { return false; } // allows to pass a callback function to allow elements be ignored by focus lock if (typeof callback === 'function') { return callback(element); } return true; }; /** * __Modal wrapper__ * * A modal wrapper displays content that requires user interaction, in a layer above the page. * This component is primary container for other modal components. * * - [Examples](https://atlassian.design/components/modal-dialog/examples) * - [Code](https://atlassian.design/components/modal-dialog/code) * - [Usage](https://atlassian.design/components/modal-dialog/usage) */ const InternalModalWrapper = props => { const { autoFocus = true, focusLockAllowlist, shouldCloseOnEscapePress = true, shouldCloseOnOverlayClick = true, shouldScrollInViewport = false, shouldReturnFocus = true, stackIndex: stackIndexOverride, onClose: providedOnClose, onStackChange = noop, isBlanketHidden, children, height, width, onCloseComplete, onOpenComplete, label, testId, isFullScreen } = props; const calculatedStackIndex = useModalStack({ onStackChange }); const stackIndex = stackIndexOverride || calculatedStackIndex; const isForeground = stackIndex === 0; // When a user supplies a ref to focus we skip auto focus via react-focus-lock // When flag is true and a ref is not supplied, autofocus is true. See https://product-fabric.atlassian.net/browse/DSP-24307 // When we remove boolean `autoFocus`, we won't have to worry about this const autoFocusLock = fg('platform_dst_autofocus-never-false-2') ? typeof autoFocus === 'boolean' : typeof autoFocus === 'boolean' ? autoFocus : false; const onCloseHandler = usePlatformLeafEventHandler({ fn: providedOnClose || noop, action: 'closed', componentName: 'modalDialog', packageName: "@atlaskit/modal-dialog", packageVersion: "14.14.2" }); const onBlanketClicked = useCallback(e => { if (shouldCloseOnOverlayClick) { onCloseHandler(e); } }, [shouldCloseOnOverlayClick, onCloseHandler]); // This ensures to prevent additional re-renders while nothing is passed to focusLockAllowlist explicitly. const allowListCallback = useCallback(element => allowlistElements(element, focusLockAllowlist), [focusLockAllowlist]); usePreventProgrammaticScroll(); useNotifyOpenLayerObserver({ type: 'modal', // Modal dialog is conditionally rendered when visible, so when this runs it is always open. isOpen: true, // Passing a no-op for now, as there isn't a real use case for closing the modal dialog programmatically // by the OpenLayerObserver. The only current use case is closing layers when resizing the nav layout, // which cannot happen while a modal dialog is open. onClose: noop }); const modalDialogWithBlanket = /*#__PURE__*/React.createElement(Blanket, { isTinted: !isBlanketHidden, onBlanketClicked: onBlanketClicked, testId: testId && `${testId}--blanket` }, /*#__PURE__*/React.createElement(ModalDialog, { testId: testId, label: label, autoFocus: autoFocus, stackIndex: stackIndex, onClose: onCloseHandler, shouldCloseOnEscapePress: shouldCloseOnEscapePress && isForeground, shouldScrollInViewport: shouldScrollInViewport, height: height, width: width, onCloseComplete: onCloseComplete, onOpenComplete: onOpenComplete, hasProvidedOnClose: Boolean(providedOnClose), isFullScreen: isFullScreen }, children)); let returnFocus = true; let onDeactivation = noop; if ('boolean' === typeof shouldReturnFocus) { returnFocus = shouldReturnFocus; } else { onDeactivation = () => { window.setTimeout(() => { var _shouldReturnFocus$cu; (_shouldReturnFocus$cu = shouldReturnFocus.current) === null || _shouldReturnFocus$cu === void 0 ? void 0 : _shouldReturnFocus$cu.focus(); }, 0); }; } return /*#__PURE__*/React.createElement(Layering, { isDisabled: false }, /*#__PURE__*/React.createElement(Portal, { zIndex: layers.modal() }, fg('platform-dst-motion-uplift') ? /*#__PURE__*/React.createElement(Motion, { enteringAnimation: "var(--ds-content-enter-medium, 200ms cubic-bezier(0.4, 0, 0, 1) FadeIn)", exitingAnimation: "var(--ds-content-exit-long, 200ms cubic-bezier(0.4, 0, 0, 1) FadeOut)" }, /*#__PURE__*/React.createElement("div", { "aria-hidden": !isForeground, className: ax(["_1bsbauwl _4t3i1kxc _kqsw1n9t _152tze3t _1e02ze3t _18m91wug _8am5i4x0"]) }, /*#__PURE__*/React.createElement(FocusLock, { autoFocus: autoFocusLock, returnFocus: returnFocus, onDeactivation: onDeactivation, whiteList: allowListCallback }, /*#__PURE__*/React.createElement(ScrollLock, null), shouldScrollInViewport ? /*#__PURE__*/React.createElement(TouchScrollable, null, modalDialogWithBlanket) : modalDialogWithBlanket))) : /*#__PURE__*/React.createElement(FadeIn, null, fadeInProps => /*#__PURE__*/React.createElement("div", _extends({}, fadeInProps, { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop className: ax(["_1bsbauwl _4t3i1kxc _kqsw1n9t _152tze3t _1e02ze3t _18m91wug _8am5i4x0", fadeInProps.className]), "aria-hidden": !isForeground }), /*#__PURE__*/React.createElement(FocusLock, { autoFocus: autoFocusLock, returnFocus: returnFocus, onDeactivation: onDeactivation, whiteList: allowListCallback }, /*#__PURE__*/React.createElement(ScrollLock, null), shouldScrollInViewport ? /*#__PURE__*/React.createElement(TouchScrollable, null, modalDialogWithBlanket) : modalDialogWithBlanket))))); }; export default InternalModalWrapper;