import { Component } from 'react'; import Dialog from '@mui/material/Dialog'; import { DIALOG_FOG } from '../colors'; /** * Shared dialog shell — drop-in replacement for MUI `Dialog`. * * Guarantees across the whole app: * - instant open/close (no Fade/scale animation): `transitionDuration={0}` * - darker, bluish fog: backdrop `backgroundColor` = `DIALOG_FOG` * - scrollbar-gutter matches the fog: toggles `df-dialog-open` on * `` while any `AppDialog` is open (see `src/index.css`). * * Class component on purpose (PureComponent-free: open state is driven * by props, state lives in the wrapped content). * * Usage: * import AppDialog from '../AppDialog'; * */ class AppDialog extends Component { static openCount = 0; static updateFogClass() { if (typeof document === 'undefined') return; const html = document.documentElement; if (!html) return; if (AppDialog.openCount > 0) { html.classList.add('df-dialog-open'); } else { html.classList.remove('df-dialog-open'); } } static enter() { AppDialog.openCount += 1; AppDialog.updateFogClass(); } static exit() { AppDialog.openCount = Math.max(0, AppDialog.openCount - 1); AppDialog.updateFogClass(); } componentDidMount() { if (this.props.open) AppDialog.enter(); } componentDidUpdate(prevProps) { if (this.props.open && !prevProps.open) AppDialog.enter(); else if (!this.props.open && prevProps.open) AppDialog.exit(); } componentWillUnmount() { if (this.props.open) AppDialog.exit(); } render() { const { transitionDuration: _transitionDuration, TransitionProps: _transitionProps, transitionProps: _lowerTransitionProps, TransitionComponent: _transitionComponent, // Legacy MUI prop (removed in v9) — merge into slotProps.paper instead // of spreading onto Dialog/DOM where it triggers // "React does not recognize the `PaperProps` prop" warnings. PaperProps: legacyPaperProps, disableScrollLock = true, slotProps: userSlotProps, slots: userSlots, ...rest } = this.props; void _transitionDuration; void _transitionProps; void _lowerTransitionProps; void _transitionComponent; const userPaper = userSlotProps?.paper ?? {}; const { sx: userPaperSx, ...restPaper } = userPaper; const { sx: legacyPaperSx, ...restLegacyPaper } = legacyPaperProps ?? {}; const toSxArray = (sx) => // eslint-disable-next-line no-nested-ternary Array.isArray(sx) ? sx : sx ? [sx] : []; const mergedPaperSx = [...toSxArray(legacyPaperSx), ...toSxArray(userPaperSx)]; const mergedPaper = mergedPaperSx.length > 0 ? { ...restLegacyPaper, ...restPaper, sx: mergedPaperSx } : { ...restLegacyPaper, ...restPaper }; const userBackdrop = userSlotProps?.backdrop ?? {}; const { sx: userBackdropSx, ...restBackdrop } = userBackdrop; const userTransition = userSlotProps?.transition ?? {}; const { transition: _userTransitionSlot, ...restSlots } = userSlots ?? {}; void _userTransitionSlot; const slotProps = { ...userSlotProps, paper: mergedPaper, backdrop: { ...restBackdrop, sx: [ { backgroundColor: DIALOG_FOG }, ...(Array.isArray(userBackdropSx) ? userBackdropSx : userBackdropSx ? [userBackdropSx] : []), ], }, transition: { ...userTransition, timeout: 0, }, }; return ( { e.stopPropagation(); rest.onWheel?.(e); }} slots={restSlots} slotProps={slotProps} transitionDuration={0} /> ); } } export default AppDialog;