UNPKG

13.3 kBJavaScriptView Raw
1'use client';
2
3import * as React from 'react';
4import PropTypes from 'prop-types';
5import clsx from 'clsx';
6import composeClasses from '@mui/utils/composeClasses';
7import useId from '@mui/utils/useId';
8import capitalize from "../utils/capitalize.js";
9import Modal from "../Modal/index.js";
10import Fade from "../Fade/index.js";
11import Paper from "../Paper/index.js";
12import dialogClasses, { getDialogUtilityClass } from "./dialogClasses.js";
13import DialogContext from "./DialogContext.js";
14import Backdrop from "../Backdrop/index.js";
15import { styled, useTheme } from "../zero-styled/index.js";
16import memoTheme from "../utils/memoTheme.js";
17import { useDefaultProps } from "../DefaultPropsProvider/index.js";
18import { jsx as _jsx } from "react/jsx-runtime";
19const DialogBackdrop = styled(Backdrop, {
20 name: 'MuiDialog',
21 slot: 'Backdrop',
22 overrides: (props, styles) => styles.backdrop
23})({
24 // Improve scrollable dialog support.
25 zIndex: -1
26});
27const useUtilityClasses = ownerState => {
28 const {
29 classes,
30 scroll,
31 maxWidth,
32 fullWidth,
33 fullScreen
34 } = ownerState;
35 const slots = {
36 root: ['root'],
37 container: ['container', `scroll${capitalize(scroll)}`],
38 paper: ['paper', `paperScroll${capitalize(scroll)}`, `paperWidth${capitalize(String(maxWidth))}`, fullWidth && 'paperFullWidth', fullScreen && 'paperFullScreen']
39 };
40 return composeClasses(slots, getDialogUtilityClass, classes);
41};
42const DialogRoot = styled(Modal, {
43 name: 'MuiDialog',
44 slot: 'Root',
45 overridesResolver: (props, styles) => styles.root
46})({
47 '@media print': {
48 // Use !important to override the Modal inline-style.
49 position: 'absolute !important'
50 }
51});
52const DialogContainer = styled('div', {
53 name: 'MuiDialog',
54 slot: 'Container',
55 overridesResolver: (props, styles) => {
56 const {
57 ownerState
58 } = props;
59 return [styles.container, styles[`scroll${capitalize(ownerState.scroll)}`]];
60 }
61})({
62 height: '100%',
63 '@media print': {
64 height: 'auto'
65 },
66 // We disable the focus ring for mouse, touch and keyboard users.
67 outline: 0,
68 variants: [{
69 props: {
70 scroll: 'paper'
71 },
72 style: {
73 display: 'flex',
74 justifyContent: 'center',
75 alignItems: 'center'
76 }
77 }, {
78 props: {
79 scroll: 'body'
80 },
81 style: {
82 overflowY: 'auto',
83 overflowX: 'hidden',
84 textAlign: 'center',
85 '&::after': {
86 content: '""',
87 display: 'inline-block',
88 verticalAlign: 'middle',
89 height: '100%',
90 width: '0'
91 }
92 }
93 }]
94});
95const DialogPaper = styled(Paper, {
96 name: 'MuiDialog',
97 slot: 'Paper',
98 overridesResolver: (props, styles) => {
99 const {
100 ownerState
101 } = props;
102 return [styles.paper, styles[`scrollPaper${capitalize(ownerState.scroll)}`], styles[`paperWidth${capitalize(String(ownerState.maxWidth))}`], ownerState.fullWidth && styles.paperFullWidth, ownerState.fullScreen && styles.paperFullScreen];
103 }
104})(memoTheme(({
105 theme
106}) => ({
107 margin: 32,
108 position: 'relative',
109 overflowY: 'auto',
110 '@media print': {
111 overflowY: 'visible',
112 boxShadow: 'none'
113 },
114 variants: [{
115 props: {
116 scroll: 'paper'
117 },
118 style: {
119 display: 'flex',
120 flexDirection: 'column',
121 maxHeight: 'calc(100% - 64px)'
122 }
123 }, {
124 props: {
125 scroll: 'body'
126 },
127 style: {
128 display: 'inline-block',
129 verticalAlign: 'middle',
130 textAlign: 'initial'
131 }
132 }, {
133 props: ({
134 ownerState
135 }) => !ownerState.maxWidth,
136 style: {
137 maxWidth: 'calc(100% - 64px)'
138 }
139 }, {
140 props: {
141 maxWidth: 'xs'
142 },
143 style: {
144 maxWidth: theme.breakpoints.unit === 'px' ? Math.max(theme.breakpoints.values.xs, 444) : `max(${theme.breakpoints.values.xs}${theme.breakpoints.unit}, 444px)`,
145 [`&.${dialogClasses.paperScrollBody}`]: {
146 [theme.breakpoints.down(Math.max(theme.breakpoints.values.xs, 444) + 32 * 2)]: {
147 maxWidth: 'calc(100% - 64px)'
148 }
149 }
150 }
151 }, ...Object.keys(theme.breakpoints.values).filter(maxWidth => maxWidth !== 'xs').map(maxWidth => ({
152 props: {
153 maxWidth
154 },
155 style: {
156 maxWidth: `${theme.breakpoints.values[maxWidth]}${theme.breakpoints.unit}`,
157 [`&.${dialogClasses.paperScrollBody}`]: {
158 [theme.breakpoints.down(theme.breakpoints.values[maxWidth] + 32 * 2)]: {
159 maxWidth: 'calc(100% - 64px)'
160 }
161 }
162 }
163 })), {
164 props: ({
165 ownerState
166 }) => ownerState.fullWidth,
167 style: {
168 width: 'calc(100% - 64px)'
169 }
170 }, {
171 props: ({
172 ownerState
173 }) => ownerState.fullScreen,
174 style: {
175 margin: 0,
176 width: '100%',
177 maxWidth: '100%',
178 height: '100%',
179 maxHeight: 'none',
180 borderRadius: 0,
181 [`&.${dialogClasses.paperScrollBody}`]: {
182 margin: 0,
183 maxWidth: '100%'
184 }
185 }
186 }]
187})));
188
189/**
190 * Dialogs are overlaid modal paper based components with a backdrop.
191 */
192const Dialog = /*#__PURE__*/React.forwardRef(function Dialog(inProps, ref) {
193 const props = useDefaultProps({
194 props: inProps,
195 name: 'MuiDialog'
196 });
197 const theme = useTheme();
198 const defaultTransitionDuration = {
199 enter: theme.transitions.duration.enteringScreen,
200 exit: theme.transitions.duration.leavingScreen
201 };
202 const {
203 'aria-describedby': ariaDescribedby,
204 'aria-labelledby': ariaLabelledbyProp,
205 'aria-modal': ariaModal = true,
206 BackdropComponent,
207 BackdropProps,
208 children,
209 className,
210 disableEscapeKeyDown = false,
211 fullScreen = false,
212 fullWidth = false,
213 maxWidth = 'sm',
214 onBackdropClick,
215 onClick,
216 onClose,
217 open,
218 PaperComponent = Paper,
219 PaperProps = {},
220 scroll = 'paper',
221 TransitionComponent = Fade,
222 transitionDuration = defaultTransitionDuration,
223 TransitionProps,
224 ...other
225 } = props;
226 const ownerState = {
227 ...props,
228 disableEscapeKeyDown,
229 fullScreen,
230 fullWidth,
231 maxWidth,
232 scroll
233 };
234 const classes = useUtilityClasses(ownerState);
235 const backdropClick = React.useRef();
236 const handleMouseDown = event => {
237 // We don't want to close the dialog when clicking the dialog content.
238 // Make sure the event starts and ends on the same DOM element.
239 backdropClick.current = event.target === event.currentTarget;
240 };
241 const handleBackdropClick = event => {
242 if (onClick) {
243 onClick(event);
244 }
245
246 // Ignore the events not coming from the "backdrop".
247 if (!backdropClick.current) {
248 return;
249 }
250 backdropClick.current = null;
251 if (onBackdropClick) {
252 onBackdropClick(event);
253 }
254 if (onClose) {
255 onClose(event, 'backdropClick');
256 }
257 };
258 const ariaLabelledby = useId(ariaLabelledbyProp);
259 const dialogContextValue = React.useMemo(() => {
260 return {
261 titleId: ariaLabelledby
262 };
263 }, [ariaLabelledby]);
264 return /*#__PURE__*/_jsx(DialogRoot, {
265 className: clsx(classes.root, className),
266 closeAfterTransition: true,
267 components: {
268 Backdrop: DialogBackdrop
269 },
270 componentsProps: {
271 backdrop: {
272 transitionDuration,
273 as: BackdropComponent,
274 ...BackdropProps
275 }
276 },
277 disableEscapeKeyDown: disableEscapeKeyDown,
278 onClose: onClose,
279 open: open,
280 ref: ref,
281 onClick: handleBackdropClick,
282 ownerState: ownerState,
283 ...other,
284 children: /*#__PURE__*/_jsx(TransitionComponent, {
285 appear: true,
286 in: open,
287 timeout: transitionDuration,
288 role: "presentation",
289 ...TransitionProps,
290 children: /*#__PURE__*/_jsx(DialogContainer, {
291 className: clsx(classes.container),
292 onMouseDown: handleMouseDown,
293 ownerState: ownerState,
294 children: /*#__PURE__*/_jsx(DialogPaper, {
295 as: PaperComponent,
296 elevation: 24,
297 role: "dialog",
298 "aria-describedby": ariaDescribedby,
299 "aria-labelledby": ariaLabelledby,
300 "aria-modal": ariaModal,
301 ...PaperProps,
302 className: clsx(classes.paper, PaperProps.className),
303 ownerState: ownerState,
304 children: /*#__PURE__*/_jsx(DialogContext.Provider, {
305 value: dialogContextValue,
306 children: children
307 })
308 })
309 })
310 })
311 });
312});
313process.env.NODE_ENV !== "production" ? Dialog.propTypes /* remove-proptypes */ = {
314 // ┌────────────────────────────── Warning ──────────────────────────────┐
315 // │ These PropTypes are generated from the TypeScript type definitions. │
316 // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
317 // └─────────────────────────────────────────────────────────────────────┘
318 /**
319 * The id(s) of the element(s) that describe the dialog.
320 */
321 'aria-describedby': PropTypes.string,
322 /**
323 * The id(s) of the element(s) that label the dialog.
324 */
325 'aria-labelledby': PropTypes.string,
326 /**
327 * Informs assistive technologies that the element is modal.
328 * It's added on the element with role="dialog".
329 * @default true
330 */
331 'aria-modal': PropTypes.oneOfType([PropTypes.oneOf(['false', 'true']), PropTypes.bool]),
332 /**
333 * A backdrop component. This prop enables custom backdrop rendering.
334 * @deprecated Use `slots.backdrop` instead. While this prop currently works, it will be removed in the next major version.
335 * Use the `slots.backdrop` prop to make your application ready for the next version of Material UI.
336 * @default styled(Backdrop, {
337 * name: 'MuiModal',
338 * slot: 'Backdrop',
339 * overridesResolver: (props, styles) => {
340 * return styles.backdrop;
341 * },
342 * })({
343 * zIndex: -1,
344 * })
345 */
346 BackdropComponent: PropTypes.elementType,
347 /**
348 * @ignore
349 */
350 BackdropProps: PropTypes.object,
351 /**
352 * Dialog children, usually the included sub-components.
353 */
354 children: PropTypes.node,
355 /**
356 * Override or extend the styles applied to the component.
357 */
358 classes: PropTypes.object,
359 /**
360 * @ignore
361 */
362 className: PropTypes.string,
363 /**
364 * If `true`, hitting escape will not fire the `onClose` callback.
365 * @default false
366 */
367 disableEscapeKeyDown: PropTypes.bool,
368 /**
369 * If `true`, the dialog is full-screen.
370 * @default false
371 */
372 fullScreen: PropTypes.bool,
373 /**
374 * If `true`, the dialog stretches to `maxWidth`.
375 *
376 * Notice that the dialog width grow is limited by the default margin.
377 * @default false
378 */
379 fullWidth: PropTypes.bool,
380 /**
381 * Determine the max-width of the dialog.
382 * The dialog width grows with the size of the screen.
383 * Set to `false` to disable `maxWidth`.
384 * @default 'sm'
385 */
386 maxWidth: PropTypes /* @typescript-to-proptypes-ignore */.oneOfType([PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl', false]), PropTypes.string]),
387 /**
388 * Callback fired when the backdrop is clicked.
389 * @deprecated Use the `onClose` prop with the `reason` argument to handle the `backdropClick` events.
390 */
391 onBackdropClick: PropTypes.func,
392 /**
393 * @ignore
394 */
395 onClick: PropTypes.func,
396 /**
397 * Callback fired when the component requests to be closed.
398 *
399 * @param {object} event The event source of the callback.
400 * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`.
401 */
402 onClose: PropTypes.func,
403 /**
404 * If `true`, the component is shown.
405 */
406 open: PropTypes.bool.isRequired,
407 /**
408 * The component used to render the body of the dialog.
409 * @default Paper
410 */
411 PaperComponent: PropTypes.elementType,
412 /**
413 * Props applied to the [`Paper`](https://mui.com/material-ui/api/paper/) element.
414 * @default {}
415 */
416 PaperProps: PropTypes.object,
417 /**
418 * Determine the container for scrolling the dialog.
419 * @default 'paper'
420 */
421 scroll: PropTypes.oneOf(['body', 'paper']),
422 /**
423 * The system prop that allows defining system overrides as well as additional CSS styles.
424 */
425 sx: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])), PropTypes.func, PropTypes.object]),
426 /**
427 * The component used for the transition.
428 * [Follow this guide](https://mui.com/material-ui/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.
429 * @default Fade
430 */
431 TransitionComponent: PropTypes.elementType,
432 /**
433 * The duration for the transition, in milliseconds.
434 * You may specify a single timeout for all transitions, or individually with an object.
435 * @default {
436 * enter: theme.transitions.duration.enteringScreen,
437 * exit: theme.transitions.duration.leavingScreen,
438 * }
439 */
440 transitionDuration: PropTypes.oneOfType([PropTypes.number, PropTypes.shape({
441 appear: PropTypes.number,
442 enter: PropTypes.number,
443 exit: PropTypes.number
444 })]),
445 /**
446 * Props applied to the transition element.
447 * By default, the element is based on this [`Transition`](https://reactcommunity.org/react-transition-group/transition/) component.
448 */
449 TransitionProps: PropTypes.object
450} : void 0;
451export default Dialog;
\No newline at end of file