UNPKG

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