UNPKG

14.1 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
5var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
6
7Object.defineProperty(exports, "__esModule", {
8 value: true
9});
10exports.default = exports.styles = void 0;
11
12var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
13
14var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
15
16var React = _interopRequireWildcard(require("react"));
17
18var ReactDOM = _interopRequireWildcard(require("react-dom"));
19
20var _propTypes = _interopRequireDefault(require("prop-types"));
21
22var _styles = require("@material-ui/styles");
23
24var _utils = require("@material-ui/utils");
25
26var _ownerDocument = _interopRequireDefault(require("../utils/ownerDocument"));
27
28var _Portal = _interopRequireDefault(require("../Portal"));
29
30var _createChainedFunction = _interopRequireDefault(require("../utils/createChainedFunction"));
31
32var _useForkRef = _interopRequireDefault(require("../utils/useForkRef"));
33
34var _useEventCallback = _interopRequireDefault(require("../utils/useEventCallback"));
35
36var _zIndex = _interopRequireDefault(require("../styles/zIndex"));
37
38var _ModalManager = _interopRequireWildcard(require("./ModalManager"));
39
40var _Unstable_TrapFocus = _interopRequireDefault(require("../Unstable_TrapFocus"));
41
42var _SimpleBackdrop = _interopRequireDefault(require("./SimpleBackdrop"));
43
44function getContainer(container) {
45 container = typeof container === 'function' ? container() : container;
46 return ReactDOM.findDOMNode(container);
47}
48
49function getHasTransition(props) {
50 return props.children ? props.children.props.hasOwnProperty('in') : false;
51} // A modal manager used to track and manage the state of open Modals.
52// Modals don't open on the server so this won't conflict with concurrent requests.
53
54
55var defaultManager = new _ModalManager.default();
56
57var styles = function styles(theme) {
58 return {
59 /* Styles applied to the root element. */
60 root: {
61 position: 'fixed',
62 zIndex: theme.zIndex.modal,
63 right: 0,
64 bottom: 0,
65 top: 0,
66 left: 0
67 },
68
69 /* Styles applied to the root element if the `Modal` has exited. */
70 hidden: {
71 visibility: 'hidden'
72 }
73 };
74};
75/**
76 * Modal is a lower-level construct that is leveraged by the following components:
77 *
78 * - [Dialog](/api/dialog/)
79 * - [Drawer](/api/drawer/)
80 * - [Menu](/api/menu/)
81 * - [Popover](/api/popover/)
82 *
83 * If you are creating a modal dialog, you probably want to use the [Dialog](/api/dialog/) component
84 * rather than directly using Modal.
85 *
86 * This component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).
87 */
88
89
90exports.styles = styles;
91var Modal = /*#__PURE__*/React.forwardRef(function Modal(inProps, ref) {
92 var theme = (0, _styles.useTheme)();
93 var props = (0, _styles.getThemeProps)({
94 name: 'MuiModal',
95 props: (0, _extends2.default)({}, inProps),
96 theme: theme
97 });
98 var _props$BackdropCompon = props.BackdropComponent,
99 BackdropComponent = _props$BackdropCompon === void 0 ? _SimpleBackdrop.default : _props$BackdropCompon,
100 BackdropProps = props.BackdropProps,
101 children = props.children,
102 _props$closeAfterTran = props.closeAfterTransition,
103 closeAfterTransition = _props$closeAfterTran === void 0 ? false : _props$closeAfterTran,
104 container = props.container,
105 _props$disableAutoFoc = props.disableAutoFocus,
106 disableAutoFocus = _props$disableAutoFoc === void 0 ? false : _props$disableAutoFoc,
107 _props$disableBackdro = props.disableBackdropClick,
108 disableBackdropClick = _props$disableBackdro === void 0 ? false : _props$disableBackdro,
109 _props$disableEnforce = props.disableEnforceFocus,
110 disableEnforceFocus = _props$disableEnforce === void 0 ? false : _props$disableEnforce,
111 _props$disableEscapeK = props.disableEscapeKeyDown,
112 disableEscapeKeyDown = _props$disableEscapeK === void 0 ? false : _props$disableEscapeK,
113 _props$disablePortal = props.disablePortal,
114 disablePortal = _props$disablePortal === void 0 ? false : _props$disablePortal,
115 _props$disableRestore = props.disableRestoreFocus,
116 disableRestoreFocus = _props$disableRestore === void 0 ? false : _props$disableRestore,
117 _props$disableScrollL = props.disableScrollLock,
118 disableScrollLock = _props$disableScrollL === void 0 ? false : _props$disableScrollL,
119 _props$hideBackdrop = props.hideBackdrop,
120 hideBackdrop = _props$hideBackdrop === void 0 ? false : _props$hideBackdrop,
121 _props$keepMounted = props.keepMounted,
122 keepMounted = _props$keepMounted === void 0 ? false : _props$keepMounted,
123 _props$manager = props.manager,
124 manager = _props$manager === void 0 ? defaultManager : _props$manager,
125 onBackdropClick = props.onBackdropClick,
126 onClose = props.onClose,
127 onEscapeKeyDown = props.onEscapeKeyDown,
128 onRendered = props.onRendered,
129 open = props.open,
130 other = (0, _objectWithoutProperties2.default)(props, ["BackdropComponent", "BackdropProps", "children", "closeAfterTransition", "container", "disableAutoFocus", "disableBackdropClick", "disableEnforceFocus", "disableEscapeKeyDown", "disablePortal", "disableRestoreFocus", "disableScrollLock", "hideBackdrop", "keepMounted", "manager", "onBackdropClick", "onClose", "onEscapeKeyDown", "onRendered", "open"]);
131
132 var _React$useState = React.useState(true),
133 exited = _React$useState[0],
134 setExited = _React$useState[1];
135
136 var modal = React.useRef({});
137 var mountNodeRef = React.useRef(null);
138 var modalRef = React.useRef(null);
139 var handleRef = (0, _useForkRef.default)(modalRef, ref);
140 var hasTransition = getHasTransition(props);
141
142 var getDoc = function getDoc() {
143 return (0, _ownerDocument.default)(mountNodeRef.current);
144 };
145
146 var getModal = function getModal() {
147 modal.current.modalRef = modalRef.current;
148 modal.current.mountNode = mountNodeRef.current;
149 return modal.current;
150 };
151
152 var handleMounted = function handleMounted() {
153 manager.mount(getModal(), {
154 disableScrollLock: disableScrollLock
155 }); // Fix a bug on Chrome where the scroll isn't initially 0.
156
157 modalRef.current.scrollTop = 0;
158 };
159
160 var handleOpen = (0, _useEventCallback.default)(function () {
161 var resolvedContainer = getContainer(container) || getDoc().body;
162 manager.add(getModal(), resolvedContainer); // The element was already mounted.
163
164 if (modalRef.current) {
165 handleMounted();
166 }
167 });
168 var isTopModal = React.useCallback(function () {
169 return manager.isTopModal(getModal());
170 }, [manager]);
171 var handlePortalRef = (0, _useEventCallback.default)(function (node) {
172 mountNodeRef.current = node;
173
174 if (!node) {
175 return;
176 }
177
178 if (onRendered) {
179 onRendered();
180 }
181
182 if (open && isTopModal()) {
183 handleMounted();
184 } else {
185 (0, _ModalManager.ariaHidden)(modalRef.current, true);
186 }
187 });
188 var handleClose = React.useCallback(function () {
189 manager.remove(getModal());
190 }, [manager]);
191 React.useEffect(function () {
192 return function () {
193 handleClose();
194 };
195 }, [handleClose]);
196 React.useEffect(function () {
197 if (open) {
198 handleOpen();
199 } else if (!hasTransition || !closeAfterTransition) {
200 handleClose();
201 }
202 }, [open, handleClose, hasTransition, closeAfterTransition, handleOpen]);
203
204 if (!keepMounted && !open && (!hasTransition || exited)) {
205 return null;
206 }
207
208 var handleEnter = function handleEnter() {
209 setExited(false);
210 };
211
212 var handleExited = function handleExited() {
213 setExited(true);
214
215 if (closeAfterTransition) {
216 handleClose();
217 }
218 };
219
220 var handleBackdropClick = function handleBackdropClick(event) {
221 if (event.target !== event.currentTarget) {
222 return;
223 }
224
225 if (onBackdropClick) {
226 onBackdropClick(event);
227 }
228
229 if (!disableBackdropClick && onClose) {
230 onClose(event, 'backdropClick');
231 }
232 };
233
234 var handleKeyDown = function handleKeyDown(event) {
235 // The handler doesn't take event.defaultPrevented into account:
236 //
237 // event.preventDefault() is meant to stop default behaviours like
238 // clicking a checkbox to check it, hitting a button to submit a form,
239 // and hitting left arrow to move the cursor in a text input etc.
240 // Only special HTML elements have these default behaviors.
241 if (event.key !== 'Escape' || !isTopModal()) {
242 return;
243 }
244
245 if (onEscapeKeyDown) {
246 onEscapeKeyDown(event);
247 }
248
249 if (!disableEscapeKeyDown) {
250 // Swallow the event, in case someone is listening for the escape key on the body.
251 event.stopPropagation();
252
253 if (onClose) {
254 onClose(event, 'escapeKeyDown');
255 }
256 }
257 };
258
259 var inlineStyle = styles(theme || {
260 zIndex: _zIndex.default
261 });
262 var childProps = {};
263
264 if (children.props.tabIndex === undefined) {
265 childProps.tabIndex = children.props.tabIndex || '-1';
266 } // It's a Transition like component
267
268
269 if (hasTransition) {
270 childProps.onEnter = (0, _createChainedFunction.default)(handleEnter, children.props.onEnter);
271 childProps.onExited = (0, _createChainedFunction.default)(handleExited, children.props.onExited);
272 }
273
274 return /*#__PURE__*/React.createElement(_Portal.default, {
275 ref: handlePortalRef,
276 container: container,
277 disablePortal: disablePortal
278 }, /*#__PURE__*/React.createElement("div", (0, _extends2.default)({
279 ref: handleRef,
280 onKeyDown: handleKeyDown,
281 role: "presentation"
282 }, other, {
283 style: (0, _extends2.default)({}, inlineStyle.root, !open && exited ? inlineStyle.hidden : {}, other.style)
284 }), hideBackdrop ? null : /*#__PURE__*/React.createElement(BackdropComponent, (0, _extends2.default)({
285 open: open,
286 onClick: handleBackdropClick
287 }, BackdropProps)), /*#__PURE__*/React.createElement(_Unstable_TrapFocus.default, {
288 disableEnforceFocus: disableEnforceFocus,
289 disableAutoFocus: disableAutoFocus,
290 disableRestoreFocus: disableRestoreFocus,
291 getDoc: getDoc,
292 isEnabled: isTopModal,
293 open: open
294 }, /*#__PURE__*/React.cloneElement(children, childProps))));
295});
296process.env.NODE_ENV !== "production" ? Modal.propTypes = {
297 /**
298 * A backdrop component. This prop enables custom backdrop rendering.
299 */
300 BackdropComponent: _propTypes.default.elementType,
301
302 /**
303 * Props applied to the [`Backdrop`](/api/backdrop/) element.
304 */
305 BackdropProps: _propTypes.default.object,
306
307 /**
308 * A single child content element.
309 */
310 children: _utils.elementAcceptingRef.isRequired,
311
312 /**
313 * When set to true the Modal waits until a nested Transition is completed before closing.
314 */
315 closeAfterTransition: _propTypes.default.bool,
316
317 /**
318 * A HTML element, component instance, or function that returns either.
319 * The `container` will have the portal children appended to it.
320 *
321 * By default, it uses the body of the top-level document object,
322 * so it's simply `document.body` most of the time.
323 */
324 container: _propTypes.default
325 /* @typescript-to-proptypes-ignore */
326 .oneOfType([_utils.HTMLElementType, _propTypes.default.instanceOf(React.Component), _propTypes.default.func]),
327
328 /**
329 * If `true`, the modal will not automatically shift focus to itself when it opens, and
330 * replace it to the last focused element when it closes.
331 * This also works correctly with any modal children that have the `disableAutoFocus` prop.
332 *
333 * Generally this should never be set to `true` as it makes the modal less
334 * accessible to assistive technologies, like screen readers.
335 */
336 disableAutoFocus: _propTypes.default.bool,
337
338 /**
339 * If `true`, clicking the backdrop will not fire `onClose`.
340 */
341 disableBackdropClick: _propTypes.default.bool,
342
343 /**
344 * If `true`, the modal will not prevent focus from leaving the modal while open.
345 *
346 * Generally this should never be set to `true` as it makes the modal less
347 * accessible to assistive technologies, like screen readers.
348 */
349 disableEnforceFocus: _propTypes.default.bool,
350
351 /**
352 * If `true`, hitting escape will not fire `onClose`.
353 */
354 disableEscapeKeyDown: _propTypes.default.bool,
355
356 /**
357 * Disable the portal behavior.
358 * The children stay within it's parent DOM hierarchy.
359 */
360 disablePortal: _propTypes.default.bool,
361
362 /**
363 * If `true`, the modal will not restore focus to previously focused element once
364 * modal is hidden.
365 */
366 disableRestoreFocus: _propTypes.default.bool,
367
368 /**
369 * Disable the scroll lock behavior.
370 */
371 disableScrollLock: _propTypes.default.bool,
372
373 /**
374 * If `true`, the backdrop is not rendered.
375 */
376 hideBackdrop: _propTypes.default.bool,
377
378 /**
379 * Always keep the children in the DOM.
380 * This prop can be useful in SEO situation or
381 * when you want to maximize the responsiveness of the Modal.
382 */
383 keepMounted: _propTypes.default.bool,
384
385 /**
386 * @ignore
387 */
388 manager: _propTypes.default.object,
389
390 /**
391 * Callback fired when the backdrop is clicked.
392 */
393 onBackdropClick: _propTypes.default.func,
394
395 /**
396 * Callback fired when the component requests to be closed.
397 * The `reason` parameter can optionally be used to control the response to `onClose`.
398 *
399 * @param {object} event The event source of the callback.
400 * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`.
401 */
402 onClose: _propTypes.default.func,
403
404 /**
405 * Callback fired when the escape key is pressed,
406 * `disableEscapeKeyDown` is false and the modal is in focus.
407 */
408 onEscapeKeyDown: _propTypes.default.func,
409
410 /**
411 * Callback fired once the children has been mounted into the `container`.
412 * It signals that the `open={true}` prop took effect.
413 *
414 * This prop will be deprecated and removed in v5, the ref can be used instead.
415 */
416 onRendered: _propTypes.default.func,
417
418 /**
419 * If `true`, the modal is open.
420 */
421 open: _propTypes.default.bool.isRequired
422} : void 0;
423var _default = Modal;
424exports.default = _default;
\No newline at end of file