1 | import _extends from "@babel/runtime/helpers/esm/extends";
|
2 | import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
3 | const _excluded = ["children", "closeAfterTransition", "container", "disableAutoFocus", "disableEnforceFocus", "disableEscapeKeyDown", "disablePortal", "disableRestoreFocus", "disableScrollLock", "hideBackdrop", "keepMounted", "manager", "onBackdropClick", "onClose", "onKeyDown", "open", "onTransitionEnter", "onTransitionExited", "slotProps", "slots"];
|
4 | import * as React from 'react';
|
5 | import PropTypes from 'prop-types';
|
6 | import { elementAcceptingRef, HTMLElementType, unstable_ownerDocument as ownerDocument, unstable_useForkRef as useForkRef, unstable_createChainedFunction as createChainedFunction, unstable_useEventCallback as useEventCallback } from '@mui/utils';
|
7 | import composeClasses from '../composeClasses';
|
8 | import Portal from '../Portal';
|
9 | import ModalManager, { ariaHidden } from './ModalManager';
|
10 | import FocusTrap from '../FocusTrap';
|
11 | import { getModalUtilityClass } from './modalClasses';
|
12 | import { useSlotProps } from '../utils';
|
13 | import { useClassNamesOverride } from '../utils/ClassNameConfigurator';
|
14 | import { jsx as _jsx } from "react/jsx-runtime";
|
15 | import { jsxs as _jsxs } from "react/jsx-runtime";
|
16 | const useUtilityClasses = ownerState => {
|
17 | const {
|
18 | open,
|
19 | exited
|
20 | } = ownerState;
|
21 | const slots = {
|
22 | root: ['root', !open && exited && 'hidden'],
|
23 | backdrop: ['backdrop']
|
24 | };
|
25 | return composeClasses(slots, useClassNamesOverride(getModalUtilityClass));
|
26 | };
|
27 | function getContainer(container) {
|
28 | return typeof container === 'function' ? container() : container;
|
29 | }
|
30 | function getHasTransition(children) {
|
31 | return children ? children.props.hasOwnProperty('in') : false;
|
32 | }
|
33 |
|
34 |
|
35 |
|
36 | const defaultManager = new ModalManager();
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | const Modal = React.forwardRef(function Modal(props, forwardedRef) {
|
60 | var _props$ariaHidden, _slots$root;
|
61 | const {
|
62 | children,
|
63 | closeAfterTransition = false,
|
64 | container,
|
65 | disableAutoFocus = false,
|
66 | disableEnforceFocus = false,
|
67 | disableEscapeKeyDown = false,
|
68 | disablePortal = false,
|
69 | disableRestoreFocus = false,
|
70 | disableScrollLock = false,
|
71 | hideBackdrop = false,
|
72 | keepMounted = false,
|
73 |
|
74 | manager: managerProp = defaultManager,
|
75 | onBackdropClick,
|
76 | onClose,
|
77 | onKeyDown,
|
78 | open,
|
79 | onTransitionEnter,
|
80 | onTransitionExited,
|
81 | slotProps = {},
|
82 | slots = {}
|
83 | } = props,
|
84 | other = _objectWithoutPropertiesLoose(props, _excluded);
|
85 |
|
86 |
|
87 | const manager = managerProp;
|
88 | const [exited, setExited] = React.useState(!open);
|
89 | const modal = React.useRef({});
|
90 | const mountNodeRef = React.useRef(null);
|
91 | const modalRef = React.useRef(null);
|
92 | const handleRef = useForkRef(modalRef, forwardedRef);
|
93 | const hasTransition = getHasTransition(children);
|
94 | const ariaHiddenProp = (_props$ariaHidden = props['aria-hidden']) != null ? _props$ariaHidden : true;
|
95 | const getDoc = () => ownerDocument(mountNodeRef.current);
|
96 | const getModal = () => {
|
97 | modal.current.modalRef = modalRef.current;
|
98 | modal.current.mountNode = mountNodeRef.current;
|
99 | return modal.current;
|
100 | };
|
101 | const handleMounted = () => {
|
102 | manager.mount(getModal(), {
|
103 | disableScrollLock
|
104 | });
|
105 |
|
106 |
|
107 | if (modalRef.current) {
|
108 | modalRef.current.scrollTop = 0;
|
109 | }
|
110 | };
|
111 | const handleOpen = useEventCallback(() => {
|
112 | const resolvedContainer = getContainer(container) || getDoc().body;
|
113 | manager.add(getModal(), resolvedContainer);
|
114 |
|
115 |
|
116 | if (modalRef.current) {
|
117 | handleMounted();
|
118 | }
|
119 | });
|
120 | const isTopModal = React.useCallback(() => manager.isTopModal(getModal()), [manager]);
|
121 | const handlePortalRef = useEventCallback(node => {
|
122 | mountNodeRef.current = node;
|
123 | if (!node || !modalRef.current) {
|
124 | return;
|
125 | }
|
126 | if (open && isTopModal()) {
|
127 | handleMounted();
|
128 | } else {
|
129 | ariaHidden(modalRef.current, ariaHiddenProp);
|
130 | }
|
131 | });
|
132 | const handleClose = React.useCallback(() => {
|
133 | manager.remove(getModal(), ariaHiddenProp);
|
134 | }, [manager, ariaHiddenProp]);
|
135 | React.useEffect(() => {
|
136 | return () => {
|
137 | handleClose();
|
138 | };
|
139 | }, [handleClose]);
|
140 | React.useEffect(() => {
|
141 | if (open) {
|
142 | handleOpen();
|
143 | } else if (!hasTransition || !closeAfterTransition) {
|
144 | handleClose();
|
145 | }
|
146 | }, [open, handleClose, hasTransition, closeAfterTransition, handleOpen]);
|
147 | const ownerState = _extends({}, props, {
|
148 | closeAfterTransition,
|
149 | disableAutoFocus,
|
150 | disableEnforceFocus,
|
151 | disableEscapeKeyDown,
|
152 | disablePortal,
|
153 | disableRestoreFocus,
|
154 | disableScrollLock,
|
155 | exited,
|
156 | hideBackdrop,
|
157 | keepMounted
|
158 | });
|
159 | const classes = useUtilityClasses(ownerState);
|
160 | const handleEnter = () => {
|
161 | setExited(false);
|
162 | if (onTransitionEnter) {
|
163 | onTransitionEnter();
|
164 | }
|
165 | };
|
166 | const handleExited = () => {
|
167 | setExited(true);
|
168 | if (onTransitionExited) {
|
169 | onTransitionExited();
|
170 | }
|
171 | if (closeAfterTransition) {
|
172 | handleClose();
|
173 | }
|
174 | };
|
175 | const handleBackdropClick = event => {
|
176 | if (event.target !== event.currentTarget) {
|
177 | return;
|
178 | }
|
179 | if (onBackdropClick) {
|
180 | onBackdropClick(event);
|
181 | }
|
182 | if (onClose) {
|
183 | onClose(event, 'backdropClick');
|
184 | }
|
185 | };
|
186 | const handleKeyDown = event => {
|
187 | if (onKeyDown) {
|
188 | onKeyDown(event);
|
189 | }
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | if (event.key !== 'Escape' || !isTopModal()) {
|
198 | return;
|
199 | }
|
200 | if (!disableEscapeKeyDown) {
|
201 |
|
202 | event.stopPropagation();
|
203 | if (onClose) {
|
204 | onClose(event, 'escapeKeyDown');
|
205 | }
|
206 | }
|
207 | };
|
208 | const childProps = {};
|
209 | if (children.props.tabIndex === undefined) {
|
210 | childProps.tabIndex = '-1';
|
211 | }
|
212 |
|
213 |
|
214 | if (hasTransition) {
|
215 | childProps.onEnter = createChainedFunction(handleEnter, children.props.onEnter);
|
216 | childProps.onExited = createChainedFunction(handleExited, children.props.onExited);
|
217 | }
|
218 | const Root = (_slots$root = slots.root) != null ? _slots$root : 'div';
|
219 | const rootProps = useSlotProps({
|
220 | elementType: Root,
|
221 | externalSlotProps: slotProps.root,
|
222 | externalForwardedProps: other,
|
223 | additionalProps: {
|
224 | ref: handleRef,
|
225 | role: 'presentation',
|
226 | onKeyDown: handleKeyDown
|
227 | },
|
228 | className: classes.root,
|
229 | ownerState
|
230 | });
|
231 | const BackdropComponent = slots.backdrop;
|
232 | const backdropProps = useSlotProps({
|
233 | elementType: BackdropComponent,
|
234 | externalSlotProps: slotProps.backdrop,
|
235 | additionalProps: {
|
236 | 'aria-hidden': true,
|
237 | onClick: handleBackdropClick,
|
238 | open
|
239 | },
|
240 | className: classes.backdrop,
|
241 | ownerState
|
242 | });
|
243 | if (!keepMounted && !open && (!hasTransition || exited)) {
|
244 | return null;
|
245 | }
|
246 | return _jsx(Portal
|
247 |
|
248 | , {
|
249 | ref: handlePortalRef,
|
250 | container: container,
|
251 | disablePortal: disablePortal,
|
252 | children: _jsxs(Root, _extends({}, rootProps, {
|
253 | children: [!hideBackdrop && BackdropComponent ? _jsx(BackdropComponent, _extends({}, backdropProps)) : null, _jsx(FocusTrap, {
|
254 | disableEnforceFocus: disableEnforceFocus,
|
255 | disableAutoFocus: disableAutoFocus,
|
256 | disableRestoreFocus: disableRestoreFocus,
|
257 | isEnabled: isTopModal,
|
258 | open: open,
|
259 | children: React.cloneElement(children, childProps)
|
260 | })]
|
261 | }))
|
262 | });
|
263 | });
|
264 | process.env.NODE_ENV !== "production" ? Modal.propTypes = {
|
265 |
|
266 |
|
267 |
|
268 |
|
269 | |
270 |
|
271 |
|
272 | children: elementAcceptingRef.isRequired,
|
273 | |
274 |
|
275 |
|
276 |
|
277 | closeAfterTransition: PropTypes.bool,
|
278 | |
279 |
|
280 |
|
281 |
|
282 |
|
283 |
|
284 |
|
285 | container: PropTypes .oneOfType([HTMLElementType, PropTypes.func]),
|
286 | |
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 |
|
294 |
|
295 | disableAutoFocus: PropTypes.bool,
|
296 | |
297 |
|
298 |
|
299 |
|
300 |
|
301 |
|
302 |
|
303 | disableEnforceFocus: PropTypes.bool,
|
304 | |
305 |
|
306 |
|
307 |
|
308 | disableEscapeKeyDown: PropTypes.bool,
|
309 | |
310 |
|
311 |
|
312 |
|
313 | disablePortal: PropTypes.bool,
|
314 | |
315 |
|
316 |
|
317 |
|
318 |
|
319 | disableRestoreFocus: PropTypes.bool,
|
320 | |
321 |
|
322 |
|
323 |
|
324 | disableScrollLock: PropTypes.bool,
|
325 | |
326 |
|
327 |
|
328 |
|
329 | hideBackdrop: PropTypes.bool,
|
330 | |
331 |
|
332 |
|
333 |
|
334 |
|
335 |
|
336 | keepMounted: PropTypes.bool,
|
337 | |
338 |
|
339 |
|
340 |
|
341 | onBackdropClick: PropTypes.func,
|
342 | |
343 |
|
344 |
|
345 |
|
346 |
|
347 |
|
348 |
|
349 | onClose: PropTypes.func,
|
350 | |
351 |
|
352 |
|
353 | open: PropTypes.bool.isRequired,
|
354 | |
355 |
|
356 |
|
357 |
|
358 | slotProps: PropTypes.shape({
|
359 | backdrop: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
360 | root: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
|
361 | }),
|
362 | |
363 |
|
364 |
|
365 |
|
366 |
|
367 | slots: PropTypes.shape({
|
368 | backdrop: PropTypes.elementType,
|
369 | root: PropTypes.elementType
|
370 | })
|
371 | } : void 0;
|
372 | export default Modal; |
\ | No newline at end of file |