UNPKG

9.75 kBJavaScriptView Raw
1'use client';
2
3import _extends from "@babel/runtime/helpers/esm/extends";
4import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
5const _excluded = ["children", "closeAfterTransition", "container", "disableAutoFocus", "disableEnforceFocus", "disableEscapeKeyDown", "disablePortal", "disableRestoreFocus", "disableScrollLock", "hideBackdrop", "keepMounted", "onBackdropClick", "onClose", "onKeyDown", "open", "onTransitionEnter", "onTransitionExited", "slotProps", "slots"];
6import * as React from 'react';
7import PropTypes from 'prop-types';
8import { elementAcceptingRef, HTMLElementType } from '@mui/utils';
9import { useSlotProps } from '../utils';
10import { useClassNamesOverride } from '../utils/ClassNameConfigurator';
11import { unstable_composeClasses as composeClasses } from '../composeClasses';
12import { Portal } from '../Portal';
13import { unstable_useModal as useModal } from '../unstable_useModal';
14import { FocusTrap } from '../FocusTrap';
15import { getModalUtilityClass } from './modalClasses';
16import { jsx as _jsx } from "react/jsx-runtime";
17import { jsxs as _jsxs } from "react/jsx-runtime";
18const useUtilityClasses = ownerState => {
19 const {
20 open,
21 exited
22 } = ownerState;
23 const slots = {
24 root: ['root', !open && exited && 'hidden'],
25 backdrop: ['backdrop']
26 };
27 return composeClasses(slots, useClassNamesOverride(getModalUtilityClass));
28};
29
30/**
31 * Modal is a lower-level construct that is leveraged by the following components:
32 *
33 * * [Dialog](https://mui.com/material-ui/api/dialog/)
34 * * [Drawer](https://mui.com/material-ui/api/drawer/)
35 * * [Menu](https://mui.com/material-ui/api/menu/)
36 * * [Popover](https://mui.com/material-ui/api/popover/)
37 *
38 * If you are creating a modal dialog, you probably want to use the [Dialog](https://mui.com/material-ui/api/dialog/) component
39 * rather than directly using Modal.
40 *
41 * This component shares many concepts with [react-overlays](https://react-bootstrap.github.io/react-overlays/#modals).
42 *
43 * Demos:
44 *
45 * - [Modal](https://mui.com/base-ui/react-modal/)
46 *
47 * API:
48 *
49 * - [Modal API](https://mui.com/base-ui/react-modal/components-api/#modal)
50 */
51const Modal = /*#__PURE__*/React.forwardRef(function Modal(props, forwardedRef) {
52 var _slots$root;
53 const {
54 children,
55 closeAfterTransition = false,
56 container,
57 disableAutoFocus = false,
58 disableEnforceFocus = false,
59 disableEscapeKeyDown = false,
60 disablePortal = false,
61 disableRestoreFocus = false,
62 disableScrollLock = false,
63 hideBackdrop = false,
64 keepMounted = false,
65 onBackdropClick,
66 open,
67 slotProps = {},
68 slots = {}
69 } = props,
70 other = _objectWithoutPropertiesLoose(props, _excluded);
71 const propsWithDefaults = _extends({}, props, {
72 closeAfterTransition,
73 disableAutoFocus,
74 disableEnforceFocus,
75 disableEscapeKeyDown,
76 disablePortal,
77 disableRestoreFocus,
78 disableScrollLock,
79 hideBackdrop,
80 keepMounted
81 });
82 const {
83 getRootProps,
84 getBackdropProps,
85 getTransitionProps,
86 portalRef,
87 isTopModal,
88 exited,
89 hasTransition
90 } = useModal(_extends({}, propsWithDefaults, {
91 rootRef: forwardedRef
92 }));
93 const ownerState = _extends({}, propsWithDefaults, {
94 exited,
95 hasTransition
96 });
97 const classes = useUtilityClasses(ownerState);
98 const childProps = {};
99 if (children.props.tabIndex === undefined) {
100 childProps.tabIndex = '-1';
101 }
102
103 // It's a Transition like component
104 if (hasTransition) {
105 const {
106 onEnter,
107 onExited
108 } = getTransitionProps();
109 childProps.onEnter = onEnter;
110 childProps.onExited = onExited;
111 }
112 const Root = (_slots$root = slots.root) != null ? _slots$root : 'div';
113 const rootProps = useSlotProps({
114 elementType: Root,
115 externalSlotProps: slotProps.root,
116 externalForwardedProps: other,
117 getSlotProps: getRootProps,
118 className: classes.root,
119 ownerState
120 });
121 const BackdropComponent = slots.backdrop;
122 const backdropProps = useSlotProps({
123 elementType: BackdropComponent,
124 externalSlotProps: slotProps.backdrop,
125 getSlotProps: otherHandlers => {
126 return getBackdropProps(_extends({}, otherHandlers, {
127 onClick: e => {
128 if (onBackdropClick) {
129 onBackdropClick(e);
130 }
131 if (otherHandlers != null && otherHandlers.onClick) {
132 otherHandlers.onClick(e);
133 }
134 }
135 }));
136 },
137 className: classes.backdrop,
138 ownerState
139 });
140 if (!keepMounted && !open && (!hasTransition || exited)) {
141 return null;
142 }
143 return /*#__PURE__*/_jsx(Portal, {
144 ref: portalRef,
145 container: container,
146 disablePortal: disablePortal,
147 children: /*#__PURE__*/_jsxs(Root, _extends({}, rootProps, {
148 children: [!hideBackdrop && BackdropComponent ? /*#__PURE__*/_jsx(BackdropComponent, _extends({}, backdropProps)) : null, /*#__PURE__*/_jsx(FocusTrap, {
149 disableEnforceFocus: disableEnforceFocus,
150 disableAutoFocus: disableAutoFocus,
151 disableRestoreFocus: disableRestoreFocus,
152 isEnabled: isTopModal,
153 open: open,
154 children: /*#__PURE__*/React.cloneElement(children, childProps)
155 })]
156 }))
157 });
158});
159process.env.NODE_ENV !== "production" ? Modal.propTypes /* remove-proptypes */ = {
160 // ┌────────────────────────────── Warning ──────────────────────────────┐
161 // │ These PropTypes are generated from the TypeScript type definitions. │
162 // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
163 // └─────────────────────────────────────────────────────────────────────┘
164 /**
165 * A single child content element.
166 */
167 children: elementAcceptingRef.isRequired,
168 /**
169 * When set to true the Modal waits until a nested Transition is completed before closing.
170 * @default false
171 */
172 closeAfterTransition: PropTypes.bool,
173 /**
174 * An HTML element or function that returns one.
175 * The `container` will have the portal children appended to it.
176 *
177 * You can also provide a callback, which is called in a React layout effect.
178 * This lets you set the container from a ref, and also makes server-side rendering possible.
179 *
180 * By default, it uses the body of the top-level document object,
181 * so it's simply `document.body` most of the time.
182 */
183 container: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([HTMLElementType, PropTypes.func]),
184 /**
185 * If `true`, the modal will not automatically shift focus to itself when it opens, and
186 * replace it to the last focused element when it closes.
187 * This also works correctly with any modal children that have the `disableAutoFocus` prop.
188 *
189 * Generally this should never be set to `true` as it makes the modal less
190 * accessible to assistive technologies, like screen readers.
191 * @default false
192 */
193 disableAutoFocus: PropTypes.bool,
194 /**
195 * If `true`, the modal will not prevent focus from leaving the modal while open.
196 *
197 * Generally this should never be set to `true` as it makes the modal less
198 * accessible to assistive technologies, like screen readers.
199 * @default false
200 */
201 disableEnforceFocus: PropTypes.bool,
202 /**
203 * If `true`, hitting escape will not fire the `onClose` callback.
204 * @default false
205 */
206 disableEscapeKeyDown: PropTypes.bool,
207 /**
208 * The `children` will be under the DOM hierarchy of the parent component.
209 * @default false
210 */
211 disablePortal: PropTypes.bool,
212 /**
213 * If `true`, the modal will not restore focus to previously focused element once
214 * modal is hidden or unmounted.
215 * @default false
216 */
217 disableRestoreFocus: PropTypes.bool,
218 /**
219 * Disable the scroll lock behavior.
220 * @default false
221 */
222 disableScrollLock: PropTypes.bool,
223 /**
224 * If `true`, the backdrop is not rendered.
225 * @default false
226 */
227 hideBackdrop: PropTypes.bool,
228 /**
229 * Always keep the children in the DOM.
230 * This prop can be useful in SEO situation or
231 * when you want to maximize the responsiveness of the Modal.
232 * @default false
233 */
234 keepMounted: PropTypes.bool,
235 /**
236 * Callback fired when the backdrop is clicked.
237 * @deprecated Use the `onClose` prop with the `reason` argument to handle the `backdropClick` events.
238 */
239 onBackdropClick: PropTypes.func,
240 /**
241 * Callback fired when the component requests to be closed.
242 * The `reason` parameter can optionally be used to control the response to `onClose`.
243 *
244 * @param {object} event The event source of the callback.
245 * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`.
246 */
247 onClose: PropTypes.func,
248 /**
249 * A function called when a transition enters.
250 */
251 onTransitionEnter: PropTypes.func,
252 /**
253 * A function called when a transition has exited.
254 */
255 onTransitionExited: PropTypes.func,
256 /**
257 * If `true`, the component is shown.
258 */
259 open: PropTypes.bool.isRequired,
260 /**
261 * The props used for each slot inside the Modal.
262 * @default {}
263 */
264 slotProps: PropTypes.shape({
265 backdrop: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
266 root: PropTypes.oneOfType([PropTypes.func, PropTypes.object])
267 }),
268 /**
269 * The components used for each slot inside the Modal.
270 * Either a string to use a HTML element or a component.
271 * @default {}
272 */
273 slots: PropTypes.shape({
274 backdrop: PropTypes.elementType,
275 root: PropTypes.elementType
276 })
277} : void 0;
278export { Modal };
\No newline at end of file