@atlaskit/modal-dialog
Version:
A modal dialog displays content that requires user interaction, in a layer above the page.
165 lines (163 loc) • 7.73 kB
JavaScript
/* modal-dialog.tsx generated by @compiled/babel-plugin v0.39.1 */
import _extends from "@babel/runtime/helpers/extends";
import "./modal-dialog.compiled.css";
import * as React from 'react';
import { ax, ix } from "@compiled/react/runtime";
import { useEffect, useMemo } from 'react';
import { cx } from '@atlaskit/css';
import mergeRefs from '@atlaskit/ds-lib/merge-refs';
import useAutoFocus from '@atlaskit/ds-lib/use-auto-focus';
import { useId } from '@atlaskit/ds-lib/use-id';
import { useCloseOnEscapePress, useLayering } from '@atlaskit/layering';
import { Motion } from '@atlaskit/motion';
import FadeIn from '@atlaskit/motion/fade-in';
import { fg } from '@atlaskit/platform-feature-flags';
import { combine } from '@atlaskit/pragmatic-drag-and-drop/combine';
import { ModalContext, ScrollContext } from '../context';
import useOnMotionFinish from '../hooks/use-on-motion-finish';
import { disableDraggingToCrossOriginIFramesForElement } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/element';
import { disableDraggingToCrossOriginIFramesForExternal } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/external';
import { disableDraggingToCrossOriginIFramesForTextSelection } from '../pragmatic-drag-and-drop/disable-dragging-to-cross-origin-iframes/text-selection';
import { width } from '../width';
import Positioner from './positioner';
const dialogWidth = input => {
if (!input) {
return 'auto';
}
const isWidthName = width.values.indexOf(input.toString()) !== -1;
const widthName = isWidthName && input;
if (widthName) {
return `${width.widths[widthName]}px`;
}
return typeof input === 'number' ? `${input}px` : input;
};
const dialogHeight = input => {
if (!input) {
return 'auto';
}
return typeof input === 'number' ? `${input}px` : input;
};
const LOCAL_CURRENT_SURFACE_CSS_VAR = '--ds-elevation-surface-current';
const dialogStyles = {
root: "_16jlidpf _1o9zkb7n _i0dl1wug _1e0c1txw _1bsb1osq _p12fauwl _4t3i1osq _1tkeidpf _c71l1kxc _2lx21bp4 _bfhk1bhr _syazi7uo _1q1l1bhr _lcxv1wug _1mq81kw7 _m01u1kw7 _1dg11kw7 _mizu1v1w _1ah3dkaa _ra3xnqa1 _128mdkaa _1cvmnqa1 _4davt94y _we1i1kw7 _zg7p130s _yakv1kw7 _4lht1kw7 _1xlt6m9r",
borderRadius: "_epkxfajl",
borderRadiusT26Shape: "_epkxpb1k",
motion: "_4t3i1osq _c71l1kw7 _p12f1kw7 _1jyk1wug _yakv1kw7 _4lht1kw7",
fullscreen: "_1jyk1osq"
};
const viewportScrollStyles = null;
const bodyScrollStyles = null;
const ModalDialog = props => {
const {
width = 'medium',
shouldScrollInViewport = false,
shouldCloseOnEscapePress,
autoFocus: providedAutoFocus,
stackIndex,
onClose,
onCloseComplete,
onOpenComplete,
height,
hasProvidedOnClose,
children,
label,
testId,
isFullScreen = false
} = props;
const id = useId();
const titleId = `modal-dialog-title-${id}`;
const defaultTestId = testId || 'modal-dialog';
// https://product-fabric.atlassian.net/browse/DSP-24307
// If flag and falsy, use true instead.
// When we remove boolean `autoFocus`, we won't have to worry about this
const autoFocus = !providedAutoFocus ? true : providedAutoFocus;
useEffect(() => {
// Modal dialogs can appear on top of iframe elements that are on another domain.
// There is a Chrome bug where drag and drop in an element on top of a cross domain
// iframe is not working. We are applying the workaround for this bug in modal so
// that consumers of our modal don't have to worry about this bug and are free to
// create whatever drag and drop experience they like inside a modal
//
// Chrome bug: https://issues.chromium.org/issues/362301053
return combine(disableDraggingToCrossOriginIFramesForElement(), disableDraggingToCrossOriginIFramesForTextSelection(), disableDraggingToCrossOriginIFramesForExternal());
}, []);
useAutoFocus(typeof autoFocus === 'object' ? autoFocus : undefined,
// When a user supplies a ref to focus we enable this hook
typeof autoFocus === 'object');
const [motionRef, onMotionFinish] = useOnMotionFinish({
onOpenComplete,
onCloseComplete
});
const modalDialogContext = useMemo(() => ({
testId: defaultTestId,
titleId,
onClose,
hasProvidedOnClose,
isFullScreen
}), [defaultTestId, titleId, onClose, hasProvidedOnClose, isFullScreen]);
useCloseOnEscapePress({
onClose,
isDisabled: !shouldCloseOnEscapePress
});
const {
currentLevel
} = useLayering();
return /*#__PURE__*/React.createElement(Positioner, {
stackIndex: stackIndex,
shouldScrollInViewport: shouldScrollInViewport,
testId: defaultTestId,
isFullScreen: isFullScreen
}, /*#__PURE__*/React.createElement(ModalContext.Provider, {
value: modalDialogContext
}, /*#__PURE__*/React.createElement(ScrollContext.Provider, {
value: shouldScrollInViewport
}, fg('platform-dst-motion-uplift') ? /*#__PURE__*/React.createElement(Motion, {
enteringAnimation: "var(--ds-modal-enter, 200ms cubic-bezier(0.4, 0, 0, 1) ScaleIn95, 200ms cubic-bezier(0.4, 0, 0, 1) FadeIn)",
exitingAnimation: "var(--ds-modal-exit, 200ms cubic-bezier(0.4, 1, 0.6, 1) ScaleOut95, 200ms cubic-bezier(0.4, 1, 0.6, 1) FadeOut)",
onFinish: onMotionFinish,
xcss: cx(dialogStyles.motion, isFullScreen && dialogStyles.fullscreen)
}, /*#__PURE__*/React.createElement("section", {
"aria-label": label,
ref: motionRef,
style: {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
'--modal-dialog-width': dialogWidth(width),
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
'--modal-dialog-height': dialogHeight(height)
},
role: "dialog",
"aria-labelledby": label ? undefined : titleId,
"data-testid": defaultTestId,
"data-modal-stack": stackIndex,
tabIndex: -1,
"aria-modal": true,
"data-ds--level": currentLevel,
className: ax([dialogStyles.root, !isFullScreen && dialogStyles.borderRadius, !isFullScreen && fg('platform-dst-shape-theme-default') && dialogStyles.borderRadiusT26Shape, shouldScrollInViewport ? "_1tke1kxc _c71lglyw _8kn617ks" : "_cbiz17ks _bolh1kw7"])
}, children)) : /*#__PURE__*/React.createElement(FadeIn
/**
* We don't want a 'slide in' for the full screen modals.
*/, {
entranceDirection: isFullScreen ? undefined : 'bottom',
onFinish: onMotionFinish
}, bottomFadeInProps => /*#__PURE__*/React.createElement("section", _extends({}, bottomFadeInProps, {
"aria-label": label,
ref: mergeRefs([bottomFadeInProps.ref, motionRef]),
style: {
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
'--modal-dialog-width': dialogWidth(width),
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values -- Ignored via go/DSP-18766
'--modal-dialog-height': dialogHeight(height)
},
// eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop
className: ax([dialogStyles.root, !isFullScreen && dialogStyles.borderRadius, !isFullScreen && fg('platform-dst-shape-theme-default') && dialogStyles.borderRadiusT26Shape, shouldScrollInViewport ? "_1tke1kxc _c71lglyw _8kn617ks" : "_cbiz17ks _bolh1kw7", bottomFadeInProps.className]),
role: "dialog",
"aria-labelledby": label ? undefined : titleId,
"data-testid": defaultTestId,
"data-modal-stack": stackIndex,
tabIndex: -1,
"aria-modal": true,
"data-ds--level": currentLevel
}), children)))));
};
// eslint-disable-next-line @repo/internal/react/require-jsdoc
export default ModalDialog;