1 | 'use client';
|
2 |
|
3 | import _extends from "@babel/runtime/helpers/esm/extends";
|
4 | import * as React from 'react';
|
5 | import { unstable_ownerDocument as ownerDocument, unstable_useForkRef as useForkRef, unstable_useEventCallback as useEventCallback, unstable_createChainedFunction as createChainedFunction } from '@mui/utils';
|
6 | import { extractEventHandlers } from '../utils';
|
7 | import { ModalManager, ariaHidden } from './ModalManager';
|
8 | function getContainer(container) {
|
9 | return typeof container === 'function' ? container() : container;
|
10 | }
|
11 | function getHasTransition(children) {
|
12 | return children ? children.props.hasOwnProperty('in') : false;
|
13 | }
|
14 |
|
15 |
|
16 |
|
17 | const defaultManager = new ModalManager();
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 |
|
27 |
|
28 | export function useModal(parameters) {
|
29 | const {
|
30 | container,
|
31 | disableEscapeKeyDown = false,
|
32 | disableScrollLock = false,
|
33 |
|
34 | manager = defaultManager,
|
35 | closeAfterTransition = false,
|
36 | onTransitionEnter,
|
37 | onTransitionExited,
|
38 | children,
|
39 | onClose,
|
40 | open,
|
41 | rootRef
|
42 | } = parameters;
|
43 |
|
44 |
|
45 | const modal = React.useRef({});
|
46 | const mountNodeRef = React.useRef(null);
|
47 | const modalRef = React.useRef(null);
|
48 | const handleRef = useForkRef(modalRef, rootRef);
|
49 | const [exited, setExited] = React.useState(!open);
|
50 | const hasTransition = getHasTransition(children);
|
51 | let ariaHiddenProp = true;
|
52 | if (parameters['aria-hidden'] === 'false' || parameters['aria-hidden'] === false) {
|
53 | ariaHiddenProp = false;
|
54 | }
|
55 | const getDoc = () => ownerDocument(mountNodeRef.current);
|
56 | const getModal = () => {
|
57 | modal.current.modalRef = modalRef.current;
|
58 | modal.current.mount = mountNodeRef.current;
|
59 | return modal.current;
|
60 | };
|
61 | const handleMounted = () => {
|
62 | manager.mount(getModal(), {
|
63 | disableScrollLock
|
64 | });
|
65 |
|
66 |
|
67 | if (modalRef.current) {
|
68 | modalRef.current.scrollTop = 0;
|
69 | }
|
70 | };
|
71 | const handleOpen = useEventCallback(() => {
|
72 | const resolvedContainer = getContainer(container) || getDoc().body;
|
73 | manager.add(getModal(), resolvedContainer);
|
74 |
|
75 |
|
76 | if (modalRef.current) {
|
77 | handleMounted();
|
78 | }
|
79 | });
|
80 | const isTopModal = React.useCallback(() => manager.isTopModal(getModal()), [manager]);
|
81 | const handlePortalRef = useEventCallback(node => {
|
82 | mountNodeRef.current = node;
|
83 | if (!node) {
|
84 | return;
|
85 | }
|
86 | if (open && isTopModal()) {
|
87 | handleMounted();
|
88 | } else if (modalRef.current) {
|
89 | ariaHidden(modalRef.current, ariaHiddenProp);
|
90 | }
|
91 | });
|
92 | const handleClose = React.useCallback(() => {
|
93 | manager.remove(getModal(), ariaHiddenProp);
|
94 | }, [ariaHiddenProp, manager]);
|
95 | React.useEffect(() => {
|
96 | return () => {
|
97 | handleClose();
|
98 | };
|
99 | }, [handleClose]);
|
100 | React.useEffect(() => {
|
101 | if (open) {
|
102 | handleOpen();
|
103 | } else if (!hasTransition || !closeAfterTransition) {
|
104 | handleClose();
|
105 | }
|
106 | }, [open, handleClose, hasTransition, closeAfterTransition, handleOpen]);
|
107 | const createHandleKeyDown = otherHandlers => event => {
|
108 | var _otherHandlers$onKeyD;
|
109 | (_otherHandlers$onKeyD = otherHandlers.onKeyDown) == null || _otherHandlers$onKeyD.call(otherHandlers, event);
|
110 |
|
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | if (event.key !== 'Escape' || event.which === 229 ||
|
118 |
|
119 | !isTopModal()) {
|
120 | return;
|
121 | }
|
122 | if (!disableEscapeKeyDown) {
|
123 |
|
124 | event.stopPropagation();
|
125 | if (onClose) {
|
126 | onClose(event, 'escapeKeyDown');
|
127 | }
|
128 | }
|
129 | };
|
130 | const createHandleBackdropClick = otherHandlers => event => {
|
131 | var _otherHandlers$onClic;
|
132 | (_otherHandlers$onClic = otherHandlers.onClick) == null || _otherHandlers$onClic.call(otherHandlers, event);
|
133 | if (event.target !== event.currentTarget) {
|
134 | return;
|
135 | }
|
136 | if (onClose) {
|
137 | onClose(event, 'backdropClick');
|
138 | }
|
139 | };
|
140 | const getRootProps = (otherHandlers = {}) => {
|
141 | const propsEventHandlers = extractEventHandlers(parameters);
|
142 |
|
143 |
|
144 | delete propsEventHandlers.onTransitionEnter;
|
145 | delete propsEventHandlers.onTransitionExited;
|
146 | const externalEventHandlers = _extends({}, propsEventHandlers, otherHandlers);
|
147 | return _extends({
|
148 | role: 'presentation'
|
149 | }, externalEventHandlers, {
|
150 | onKeyDown: createHandleKeyDown(externalEventHandlers),
|
151 | ref: handleRef
|
152 | });
|
153 | };
|
154 | const getBackdropProps = (otherHandlers = {}) => {
|
155 | const externalEventHandlers = otherHandlers;
|
156 | return _extends({
|
157 | 'aria-hidden': true
|
158 | }, externalEventHandlers, {
|
159 | onClick: createHandleBackdropClick(externalEventHandlers),
|
160 | open
|
161 | });
|
162 | };
|
163 | const getTransitionProps = () => {
|
164 | const handleEnter = () => {
|
165 | setExited(false);
|
166 | if (onTransitionEnter) {
|
167 | onTransitionEnter();
|
168 | }
|
169 | };
|
170 | const handleExited = () => {
|
171 | setExited(true);
|
172 | if (onTransitionExited) {
|
173 | onTransitionExited();
|
174 | }
|
175 | if (closeAfterTransition) {
|
176 | handleClose();
|
177 | }
|
178 | };
|
179 | return {
|
180 | onEnter: createChainedFunction(handleEnter, children == null ? void 0 : children.props.onEnter),
|
181 | onExited: createChainedFunction(handleExited, children == null ? void 0 : children.props.onExited)
|
182 | };
|
183 | };
|
184 | return {
|
185 | getRootProps,
|
186 | getBackdropProps,
|
187 | getTransitionProps,
|
188 | rootRef: handleRef,
|
189 | portalRef: handlePortalRef,
|
190 | isTopModal,
|
191 | exited,
|
192 | hasTransition
|
193 | };
|
194 | } |
\ | No newline at end of file |