@12-apps/ui 6.0.0 → 6.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-U3J55YPN.js → chunk-GSEAUMCS.js} +18 -6
- package/dist/chunk-GSEAUMCS.js.map +1 -0
- package/dist/chunk-MQLM43E4.js +15 -0
- package/dist/chunk-MQLM43E4.js.map +1 -0
- package/dist/{chunk-XDP4HLQ3.js → chunk-QZZVHY6U.js} +7 -3
- package/dist/chunk-QZZVHY6U.js.map +1 -0
- package/dist/{chunk-LBYA4ZPT.js → chunk-R4TYXKDD.js} +7 -1
- package/dist/{chunk-LBYA4ZPT.js.map → chunk-R4TYXKDD.js.map} +1 -1
- package/dist/data-display/DataViews.js +16 -15
- package/dist/data-display/DataViews.js.map +1 -1
- package/dist/feedback/Dialog.js +1 -1
- package/dist/feedback/StackedModal.js +2 -1
- package/dist/form/CategorySelect.js +2 -1
- package/dist/form/CreatableSelect.js +4 -1
- package/dist/form/CreatableSelect.js.map +1 -1
- package/dist/form/total-form.js +2 -1
- package/dist/form/total-form.js.map +1 -1
- package/dist/navigation/AppHeader.js +1 -1
- package/dist/tokens/layers.js +16 -0
- package/dist/tokens/layers.js.map +1 -0
- package/dist/types/components/feedback/Dialog/Dialog.d.ts.map +1 -1
- package/dist/types/components/feedback/StackedModal/modal-stack.d.ts.map +1 -1
- package/dist/types/components/form/CategorySelect/CategoryPanelSurface.d.ts.map +1 -1
- package/dist/types/components/form/CreatableSelect/CreatableSelect.d.ts.map +1 -1
- package/dist/types/tokens/layers.d.ts +63 -0
- package/dist/types/tokens/layers.d.ts.map +1 -0
- package/package.json +6 -2
- package/src/components/feedback/Dialog/Dialog.md +40 -1
- package/src/components/feedback/Dialog/Dialog.tsx +50 -7
- package/src/components/feedback/StackedModal/StackedModal.md +26 -0
- package/src/components/feedback/StackedModal/modal-stack.tsx +10 -3
- package/src/components/form/CategorySelect/CategoryPanelSurface.tsx +15 -0
- package/src/components/form/CreatableSelect/CreatableSelect.tsx +5 -2
- package/src/tokens/layers.ts +70 -0
- package/dist/chunk-U3J55YPN.js.map +0 -1
- package/dist/chunk-XDP4HLQ3.js.map +0 -1
|
@@ -2,9 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
import { Drawer, Popover } from '@mui/material';
|
|
4
4
|
|
|
5
|
+
import { stackedOverlayZIndex } from '../../../tokens/layers';
|
|
6
|
+
|
|
5
7
|
/** Chrome-free surface props: the panel draws its own border and shadow. */
|
|
6
8
|
const BARE_PAPER = { background: 'transparent', boxShadow: 'none' } as const;
|
|
7
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Both surfaces clear the sheet ladder rather than taking MUI's default.
|
|
12
|
+
*
|
|
13
|
+
* A `Popover` defaults to `zIndex.modal` and a temporary `Drawer` to
|
|
14
|
+
* `zIndex.drawer`, one step lower still — and `StackedModal` gives its second
|
|
15
|
+
* panel 1310. So this panel opened UNDER the sheet that opened it, and, being a
|
|
16
|
+
* live modal with an unreachable backdrop, took the focus of every field around
|
|
17
|
+
* it with no way to dismiss it (12-57). See `tokens/layers`.
|
|
18
|
+
*/
|
|
19
|
+
const ABOVE_SHEETS = { zIndex: stackedOverlayZIndex } as const;
|
|
20
|
+
|
|
8
21
|
interface SurfaceProps {
|
|
9
22
|
open: boolean;
|
|
10
23
|
/** True below the sheet breakpoint — anchor to the bottom edge instead. */
|
|
@@ -34,6 +47,7 @@ export function CategoryPanelSurface({
|
|
|
34
47
|
anchor="bottom"
|
|
35
48
|
open={open}
|
|
36
49
|
onClose={onClose}
|
|
50
|
+
sx={ABOVE_SHEETS}
|
|
37
51
|
slotProps={{ paper: { sx: BARE_PAPER } }}
|
|
38
52
|
>
|
|
39
53
|
{children}
|
|
@@ -48,6 +62,7 @@ export function CategoryPanelSurface({
|
|
|
48
62
|
anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}
|
|
49
63
|
transformOrigin={{ vertical: 'top', horizontal: 'left' }}
|
|
50
64
|
marginThreshold={8}
|
|
65
|
+
sx={ABOVE_SHEETS}
|
|
51
66
|
slotProps={{ paper: { sx: { ...BARE_PAPER, marginTop: '6px', overflow: 'visible' } } }}
|
|
52
67
|
>
|
|
53
68
|
{children}
|
|
@@ -7,6 +7,7 @@ import { CircularProgress } from '@mui/material';
|
|
|
7
7
|
import { TextField } from '@mui/material';
|
|
8
8
|
import { useId, useMemo } from 'react';
|
|
9
9
|
|
|
10
|
+
import { stackedOverlayZIndex } from '../../../tokens/layers';
|
|
10
11
|
import { FormControl, FormLabel, FormMessage } from '../Form';
|
|
11
12
|
import type { CreatableSelectOption, CreatableSelectProps } from './CreatableSelect.types';
|
|
12
13
|
import type { SizeValue } from '../../../tokens/scales';
|
|
@@ -216,8 +217,10 @@ export function CreatableSelect({
|
|
|
216
217
|
noOptionsText={noOptionsText}
|
|
217
218
|
// Lift the dropdown above stacked modals: the default popup z-index is
|
|
218
219
|
// `modal` (1300), but a stacked sheet at depth ≥2 sits at 1300 + depth*10,
|
|
219
|
-
// which would otherwise cover the options.
|
|
220
|
-
|
|
220
|
+
// which would otherwise cover the options. The height is the token's
|
|
221
|
+
// now — this component used to be the only place the rule was written
|
|
222
|
+
// down, which is how `CategorySelect` came to be missing it (12-57).
|
|
223
|
+
slotProps={{ popper: { sx: { zIndex: stackedOverlayZIndex } } }}
|
|
221
224
|
getOptionLabel={(option) => (typeof option === 'string' ? option : option.label)}
|
|
222
225
|
isOptionEqualToValue={(option, current) => option.value === current.value}
|
|
223
226
|
renderOption={renderIndentedOption}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { Theme } from '@mui/material';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* WHERE A PORTALLED OVERLAY SITS RELATIVE TO A STACK OF SHEETS.
|
|
5
|
+
*
|
|
6
|
+
* `StackedModal` does not put its panels on one layer. Each panel takes its own
|
|
7
|
+
* z-index as it joins the stack — {@link MODAL_STACK_BASE_Z_INDEX} for the
|
|
8
|
+
* first, another {@link MODAL_STACK_Z_INDEX_STEP} for every panel above it — so
|
|
9
|
+
* the top of a two-deep stack sits at 1310, not at `zIndex.modal`.
|
|
10
|
+
*
|
|
11
|
+
* Anything that portals out of a panel has to clear that. MUI's own defaults do
|
|
12
|
+
* not: a `Popover` (and therefore a `Menu`, and therefore a `Select`) renders at
|
|
13
|
+
* `zIndex.modal`, and a temporary `Drawer` a step lower still at
|
|
14
|
+
* `zIndex.drawer`. With exactly one sheet open the numbers tie and portal order
|
|
15
|
+
* settles it in the overlay's favour, which is why this looks fine right up
|
|
16
|
+
* until a second sheet opens over the first.
|
|
17
|
+
*
|
|
18
|
+
* ## What the failure looks like, because it is not "the panel is invisible"
|
|
19
|
+
*
|
|
20
|
+
* A `Popover` under a sheet is still a live modal. It takes focus into itself
|
|
21
|
+
* and holds it, and its backdrop is under the sheet too — so no click can reach
|
|
22
|
+
* the backdrop to dismiss it. The trigger flips its chevron, no panel appears,
|
|
23
|
+
* and from that point every keystroke aimed at the rest of the form is swallowed
|
|
24
|
+
* by an input nobody can see. One click on a field that looks inert leaves the
|
|
25
|
+
* whole form inert. Reported downstream as three unrelated blocks being
|
|
26
|
+
* "disabled" (12-57).
|
|
27
|
+
*
|
|
28
|
+
* ## Why this is a token and not a prop on each component
|
|
29
|
+
*
|
|
30
|
+
* The invariant belongs to the ladder, and the ladder is `StackedModal`'s. Left
|
|
31
|
+
* to individual components it is a rule each one has to remember, and the ones
|
|
32
|
+
* that did not remember are indistinguishable from the ones that did until a
|
|
33
|
+
* consumer stacks a sheet. `CategorySelect` never had it and `Autocomplete`
|
|
34
|
+
* answered the same question with `zIndex.tooltip` — three different heights for
|
|
35
|
+
* one question, in one package.
|
|
36
|
+
*/
|
|
37
|
+
|
|
38
|
+
/** The z-index `StackedModal` gives the FIRST panel in a stack. */
|
|
39
|
+
export const MODAL_STACK_BASE_Z_INDEX = 1300;
|
|
40
|
+
|
|
41
|
+
/** How much higher each panel stacked on top of another one sits. */
|
|
42
|
+
export const MODAL_STACK_Z_INDEX_STEP = 10;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* How many stacked panels a portalled overlay is guaranteed to clear.
|
|
46
|
+
*
|
|
47
|
+
* Ten rather than a number derived from the deepest stack anyone has built,
|
|
48
|
+
* because there is nothing to derive it from: a theme is resolved once, at paint
|
|
49
|
+
* time, and knows nothing about how many sheets happen to be open. So the
|
|
50
|
+
* headroom is a constant, and this is the depth it buys.
|
|
51
|
+
*/
|
|
52
|
+
export const STACKED_OVERLAY_CLEARED_LEVELS = 10;
|
|
53
|
+
|
|
54
|
+
/** The constant added to `zIndex.modal` to clear that many panels — 100. */
|
|
55
|
+
export const STACKED_OVERLAY_HEADROOM =
|
|
56
|
+
MODAL_STACK_Z_INDEX_STEP * STACKED_OVERLAY_CLEARED_LEVELS;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The z-index for a surface that portals out of a sheet and must stay on top of
|
|
60
|
+
* it — a dropdown, a picker panel, a menu.
|
|
61
|
+
*
|
|
62
|
+
* Read from the theme rather than hardcoded so a host that has moved
|
|
63
|
+
* `zIndex.modal` keeps the same relationship instead of a stale absolute.
|
|
64
|
+
*
|
|
65
|
+
* ```tsx
|
|
66
|
+
* <Popover sx={{ zIndex: stackedOverlayZIndex }} … />
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export const stackedOverlayZIndex = (theme: Theme): number =>
|
|
70
|
+
theme.zIndex.modal + STACKED_OVERLAY_HEADROOM;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/feedback/Dialog/Dialog.tsx","../src/components/feedback/Dialog/Dialog.styles.ts"],"sourcesContent":["import CloseIcon from '@mui/icons-material/Close';\nimport {\n Backdrop,\n Box,\n Dialog as MuiDialog,\n DialogActions as MuiDialogActions,\n DialogContent as MuiDialogContent,\n DialogTitle as MuiDialogTitle,\n Drawer,\n IconButton,\n Typography,\n useTheme,\n} from '@mui/material';\nimport React from 'react';\n\nimport { backdropSxOf, variantStylesOf } from './Dialog.styles';\nimport type {\n DialogActionsProps,\n DialogContentProps,\n DialogHeaderProps,\n DialogProps,\n} from './Dialog.types';\n\n/**\n * The dialog body. Consumers that pass raw children (no <DialogContent>) used\n * to render them flush against the paper edges — give them comfortable default\n * padding; <DialogContent>/<DialogActions> users keep managing their own\n * spacing.\n */\nfunction bodyOf(children: React.ReactNode, hasTitle: boolean): React.ReactNode {\n const managesOwnSpacing = React.Children.toArray(children).some(\n (child) =>\n React.isValidElement(child) &&\n (child.type === DialogContent || child.type === DialogActions),\n );\n if (managesOwnSpacing) return children;\n return <Box sx={{ px: 3, pb: 2.5, pt: hasTitle ? 0.5 : 2.5 }}>{children}</Box>;\n}\n\nconst DIALOG_DEFAULTS = {\n variant: 'default',\n size: 'md',\n showCloseButton: true,\n backdrop: true,\n persistent: false,\n glass: false,\n gradient: false,\n glow: false,\n pulse: false,\n borderRadius: 'lg',\n} as const satisfies Partial<DialogProps>;\n\n/** DialogProps with every defaulted field guaranteed present (wide types). */\ntype DialogPropsWithDefaults = DialogProps &\n Required<Pick<DialogProps, keyof typeof DIALOG_DEFAULTS>>;\n\n/**\n * Apply {@link DIALOG_DEFAULTS} exactly like parameter defaults would: only a\n * missing/`undefined` prop falls back (a loop, so the component's cyclomatic\n * complexity doesn't pay one branch per defaulted prop).\n */\nfunction withDialogDefaults(props: DialogProps): DialogPropsWithDefaults {\n const merged: Record<string, unknown> = { ...props };\n for (const [key, value] of Object.entries(DIALOG_DEFAULTS)) {\n if (merged[key] === undefined) merged[key] = value;\n }\n return merged as unknown as DialogPropsWithDefaults;\n}\n\nexport const Dialog: React.FC<DialogProps> = (rawProps) => {\n const {\n children,\n variant,\n size,\n title,\n description,\n showCloseButton,\n backdrop,\n persistent,\n glass,\n gradient,\n glow,\n pulse,\n borderRadius,\n onClose,\n open,\n dataTestId,\n ...props\n } = withDialogDefaults(rawProps);\n const theme = useTheme();\n const testId = dataTestId || 'dialog';\n const paperSx = variantStylesOf(theme, {\n variant, size, borderRadius, glass, gradient, glow, pulse,\n });\n\n const handleClose = (event: object, reason: 'backdropClick' | 'escapeKeyDown') => {\n if (persistent && (reason === 'backdropClick' || reason === 'escapeKeyDown')) {\n return;\n }\n onClose?.();\n };\n\n const header = title ? (\n <DialogHeader\n title={title}\n subtitle={description}\n showCloseButton={showCloseButton}\n onClose={onClose}\n dataTestId={dataTestId}\n />\n ) : null;\n const body = bodyOf(children, Boolean(title));\n\n if (variant === 'drawer') {\n return (\n <Drawer\n anchor=\"right\"\n open={open}\n onClose={onClose}\n data-testid={testId}\n {...props}\n >\n <Box sx={{ ...paperSx, display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>\n {header}\n {body}\n </Box>\n </Drawer>\n );\n }\n\n return (\n <MuiDialog\n open={open}\n onClose={handleClose}\n fullScreen={variant === 'fullscreen'}\n BackdropComponent={backdrop ? Backdrop : undefined}\n BackdropProps={{ sx: backdropSxOf(theme, glass) }}\n PaperProps={{ sx: paperSx, 'data-testid': testId }}\n {...props}\n >\n {header}\n {body}\n </MuiDialog>\n );\n};\n\nexport const DialogHeader: React.FC<DialogHeaderProps> = ({\n children,\n title,\n subtitle,\n showCloseButton = true,\n onClose,\n dataTestId,\n}) => {\n if (children) {\n return (\n <Box sx={{ p: 2, borderBottom: '1px solid', borderColor: 'divider' }}>\n {children}\n </Box>\n );\n }\n\n return (\n <MuiDialogTitle\n data-testid={dataTestId ? `${dataTestId}-title` : 'dialog-title'}\n sx={{\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n pb: subtitle ? 1 : 2,\n }}\n >\n <Box>\n <Typography variant=\"h6\" component=\"div\">\n {title}\n </Typography>\n {subtitle && (\n <Typography variant=\"body2\" color=\"text.secondary\" sx={{ mt: 0.5 }}>\n {subtitle}\n </Typography>\n )}\n </Box>\n {showCloseButton && onClose && (\n <IconButton\n aria-label=\"close\"\n onClick={onClose}\n data-testid={dataTestId ? `${dataTestId}-close` : 'dialog-close'}\n sx={{\n color: 'text.secondary',\n '&:hover': {\n backgroundColor: 'action.hover',\n },\n }}\n >\n <CloseIcon />\n </IconButton>\n )}\n </MuiDialogTitle>\n );\n};\n\n/**\n * Top padding for a body that sits directly under the title.\n *\n * MUI zeroes it there (`.MuiDialogTitle-root + &` on a non-`dividers` content),\n * assuming the title's own bottom padding is the whole gap. That assumption\n * breaks for a body opening with an outlined field: a filled field floats its\n * label ABOVE the input's border box, and `DialogContent` is `overflow-y: auto`\n * — a clipping box — so the label gets sliced in half (FUT-544: \"Tipo\" in the\n * \"Novo insumo\" dialog).\n *\n * Reserve the overhang rather than restore the full 24px: the title already\n * contributes its bottom padding, so a shrunk label's `translate(…, -9px)` is\n * all that is missing. 12px clears it and leaves the gap visually tight.\n */\nconst TITLED_BODY_PADDING_TOP = 1.5;\n\n/**\n * `.MuiDialogTitle-root + &` is `(0,2,0)`-specific and a plain `sx` entry is\n * `(0,1,0)`, so the padding above only survives the cascade by naming the class\n * again — `(0,3,0)`. Scoped to the title-following case so an untitled dialog\n * keeps MUI's roomier default.\n */\nconst TITLED_BODY_SELECTOR = '.MuiDialogTitle-root + &.MuiDialogContent-root';\n\nexport const DialogContent: React.FC<DialogContentProps> = ({\n children,\n dividers = false,\n dense = false,\n dataTestId,\n ...props\n}) => (\n <MuiDialogContent\n data-testid={dataTestId ? `${dataTestId}-content` : 'dialog-content'}\n dividers={dividers}\n sx={{\n padding: dense ? 1.5 : 3,\n [TITLED_BODY_SELECTOR]: { paddingTop: TITLED_BODY_PADDING_TOP },\n '&.MuiDialogContent-dividers': {\n borderTop: dividers ? '1px solid' : 'none',\n borderBottom: dividers ? '1px solid' : 'none',\n borderColor: 'divider',\n },\n }}\n {...props}\n >\n {children}\n </MuiDialogContent>\n );\n\nexport const DialogActions: React.FC<DialogActionsProps> = ({\n children,\n alignment = 'right',\n spacing = 1,\n dataTestId,\n ...props\n}) => {\n const getJustifyContent = () => {\n switch (alignment) {\n case 'left': return 'flex-start';\n case 'center': return 'center';\n case 'right': return 'flex-end';\n case 'space-between': return 'space-between';\n default: return 'flex-end';\n }\n };\n\n return (\n <MuiDialogActions\n data-testid={dataTestId ? `${dataTestId}-actions` : 'dialog-actions'}\n sx={{\n justifyContent: getJustifyContent(),\n gap: spacing,\n p: 2,\n }}\n {...props}\n >\n {children}\n </MuiDialogActions>\n );\n};","import type { SxProps, Theme } from '@mui/material';\nimport { alpha, keyframes } from '@mui/material';\n\nimport { dynamicViewportHeight } from '../../../utils/viewport';\nimport type { DialogProps } from './Dialog.types';\n\n/**\n * Paper/backdrop styling for the Dialog component (FUT-181 gate cleanup):\n * pure helpers so `Dialog.tsx` stays within the size/complexity budget.\n */\n\n// Define pulse animation\nconst pulseAnimation = keyframes`\n 0% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 1;\n }\n 70% {\n box-shadow: 0 0 0 20px currentColor;\n opacity: 0;\n }\n 100% {\n box-shadow: 0 0 0 0 currentColor;\n opacity: 0;\n }\n`;\n\n/** Style toggles that shape the dialog paper (extracted so each fn stays small). */\ninterface VariantStyleOptions {\n variant: NonNullable<DialogProps['variant']>;\n size: NonNullable<DialogProps['size']>;\n borderRadius: NonNullable<DialogProps['borderRadius']>;\n glass: boolean;\n gradient: boolean;\n glow: boolean;\n pulse: boolean;\n}\n\nfunction borderRadiusOf(theme: Theme, borderRadius: VariantStyleOptions['borderRadius']) {\n switch (borderRadius) {\n case 'none': return 0;\n case 'sm': return theme.spacing(0.5);\n case 'md': return theme.spacing(1);\n case 'xl': return theme.spacing(3);\n case 'lg':\n default: return theme.spacing(2);\n }\n}\n\nfunction maxWidthOf(size: VariantStyleOptions['size']): number {\n switch (size) {\n case 'xs': return 400;\n case 'sm': return 600;\n case 'lg': return 1000;\n case 'xl': return 1200;\n case 'md':\n default: return 800;\n }\n}\n\nfunction baseStylesOf(theme: Theme, opts: VariantStyleOptions) {\n return {\n borderRadius: borderRadiusOf(theme, opts.borderRadius),\n maxWidth: maxWidthOf(opts.size),\n width: '90vw',\n margin: theme.spacing(2),\n transition: theme.transitions.create(\n ['box-shadow', 'background-color', 'backdrop-filter'],\n { duration: theme.transitions.duration.standard },\n ),\n };\n}\n\nfunction glowStylesOf(theme: Theme, glow: boolean) {\n return glow ? { boxShadow: `0 0 40px ${alpha(theme.palette.primary.main, 0.3)}` } : {};\n}\n\nfunction pulseStylesOf(theme: Theme, pulse: boolean) {\n if (!pulse) return {};\n return {\n position: 'relative' as const,\n '&::after': {\n content: '\"\"',\n position: 'absolute' as const,\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n borderRadius: 'inherit',\n backgroundColor: theme.palette.primary.main,\n opacity: 0.3,\n animation: `${pulseAnimation} 2s infinite`,\n pointerEvents: 'none' as const,\n zIndex: -1,\n },\n };\n}\n\n/** The default variant's paper: optional gradient/glass over the base styles. */\nfunction defaultVariantStyles(theme: Theme, opts: VariantStyleOptions) {\n const gradientStyles = opts.gradient\n ? {\n background: `linear-gradient(135deg, ${alpha(theme.palette.primary.main, 0.1)}, ${alpha(theme.palette.secondary.main, 0.1)})`,\n backdropFilter: 'blur(10px)',\n }\n : {};\n return {\n ...gradientStyles,\n backgroundColor: opts.glass\n ? alpha(theme.palette.background.paper, 0.1)\n : theme.palette.background.paper,\n backdropFilter: opts.glass ? 'blur(20px)' : 'none',\n border: opts.glass ? `1px solid ${alpha(theme.palette.primary.main, 0.2)}` : 'none',\n };\n}\n\nexport function variantStylesOf(theme: Theme, opts: VariantStyleOptions): SxProps<Theme> {\n const decorations = {\n ...glowStylesOf(theme, opts.glow),\n ...pulseStylesOf(theme, opts.pulse),\n };\n switch (opts.variant) {\n case 'glass':\n return {\n ...baseStylesOf(theme, opts),\n ...decorations,\n backgroundColor: alpha(theme.palette.background.paper, 0.1),\n backdropFilter: 'blur(20px)',\n border: `1px solid ${alpha(theme.palette.primary.main, 0.2)}`,\n boxShadow: `0 8px 32px ${alpha(theme.palette.common.black, 0.1)}`,\n };\n case 'fullscreen':\n return {\n borderRadius: 0,\n margin: 0,\n width: '100vw',\n // `100dvh`, not `100vh` — see `dynamicViewportHeight`.\n ...dynamicViewportHeight('height'),\n maxWidth: 'none',\n maxHeight: 'none',\n ...decorations,\n };\n case 'drawer': {\n const radius = borderRadiusOf(theme, opts.borderRadius);\n return {\n borderRadius: `${radius}px 0 0 ${radius}px`,\n margin: 0,\n width: maxWidthOf(opts.size),\n ...dynamicViewportHeight('height'),\n maxHeight: 'none',\n position: 'absolute' as const,\n right: 0,\n ...decorations,\n };\n }\n default:\n return {\n ...baseStylesOf(theme, opts),\n ...decorations,\n ...defaultVariantStyles(theme, opts),\n };\n }\n}\n\nexport function backdropSxOf(theme: Theme, glass: boolean) {\n return {\n backgroundColor: glass\n ? alpha(theme.palette.common.black, 0.2)\n : alpha(theme.palette.common.black, 0.5),\n backdropFilter: glass ? 'blur(8px)' : 'none',\n };\n}\n\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.tsx","../src/components/feedback/StackedModal/StackedModal.hooks.ts","../src/components/feedback/StackedModal/modal-stack.tsx","../src/components/feedback/StackedModal/StackedModal.parts.tsx","../src/components/feedback/StackedModal/StackedModal.styles.ts"],"sourcesContent":["import { Dialog, Slide, styled } from '@mui/material';\nimport type { TransitionProps } from '@mui/material/transitions';\nimport type { FC } from 'react';\nimport React, { forwardRef, useId } from 'react';\nimport { usePanelChrome } from './StackedModal.hooks';\nimport { modalAriaIds, ModalPanelContents, resolveModalContent } from './StackedModal.parts';\nimport type { PanelStyleProps } from './StackedModal.styles';\nimport { dialogRootStyles, STYLE_ONLY_PROPS } from './StackedModal.styles';\nimport type { StackedModalProps } from './StackedModal.types';\n\nconst StyledDialog = styled(Dialog, {\n shouldForwardProp: (prop) => !STYLE_ONLY_PROPS.includes(prop as string),\n})<PanelStyleProps>(({ theme, ...props }) => dialogRootStyles(theme, props));\n\n/** Panels slide in from the right on every device. */\nconst SlideTransition = forwardRef<HTMLDivElement, TransitionProps>(\n function SlideTransition(props, ref) {\n return (\n <Slide direction=\"left\" ref={ref} {...props}>\n {props.children as React.ReactElement}\n </Slide>\n );\n },\n);\n\nconst DEFAULTS: Partial<StackedModalProps> = {\n open: false,\n glass: false,\n navigationTitle: '',\n closeOnClickOutside: true,\n closeOnEsc: true,\n loading: false,\n loadingText: 'Loading...',\n maxWidth: false,\n disableBackdrop: false,\n disableFocusTrap: false,\n keepMounted: false,\n rtl: false,\n};\n\n/**\n * Fills in the defaults for props the caller left `undefined`. A table plus one\n * loop, rather than a default per destructured prop — each of those is a branch,\n * and fifteen of them put the component over the complexity bar on their own.\n */\nconst withDefaults = (props: StackedModalProps): StackedModalProps => {\n const resolved = { ...props };\n for (const [key, value] of Object.entries(DEFAULTS)) {\n const prop = key as keyof StackedModalProps;\n if (resolved[prop] === undefined) {\n Object.assign(resolved, { [prop]: value });\n }\n }\n return resolved;\n};\n\n/** The modal's props once defaults are applied and its stack identity is settled. */\ntype ResolvedProps = StackedModalProps & { modalId: string };\n\nconst StackedModalPanel: FC<ResolvedProps> = (props) => {\n const {\n open, onClose, glass, navigationTitle, hideClose, children, actions, modalId,\n closeOnClickOutside, closeOnEsc, loading, loadingText, fullScreen, maxWidth, disableBackdrop,\n disableFocusTrap, keepMounted, rtl, dataTestId,\n 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, ...otherProps\n } = props;\n\n const {\n dialogRef, modalRole, isAnimating, showSkeleton, zIndex, isMobile, canGoBack,\n handleBack, handleClose,\n } = usePanelChrome({\n open, modalId, loading, closeOnEsc, closeOnClickOutside, disableFocusTrap, onClose,\n });\n\n // Don't render if in background (performance optimization)\n if (modalRole === 'background' && !keepMounted) return null;\n\n const { content, modalActions, headerActions, hasMobileActions } = resolveModalContent(\n children,\n actions,\n isMobile,\n );\n const { titleId, descId } = modalAriaIds(modalId, ariaLabelledBy, ariaDescribedBy);\n\n return (\n <StyledDialog\n ref={dialogRef}\n open={Boolean(open)}\n onClose={handleClose}\n fullScreen={fullScreen ?? isMobile}\n modalRole={modalRole}\n isAnimating={isAnimating}\n glass={glass}\n rtl={rtl}\n customMaxWidth={maxWidth}\n TransitionComponent={SlideTransition}\n maxWidth={maxWidth}\n disableEscapeKeyDown={!closeOnEsc}\n hideBackdrop={disableBackdrop}\n keepMounted={keepMounted}\n aria-labelledby={titleId}\n aria-describedby={descId}\n data-testid={dataTestId}\n sx={{ zIndex }}\n {...otherProps}\n >\n <ModalPanelContents\n showSkeleton={showSkeleton}\n loadingText={loadingText}\n titleId={titleId}\n descId={descId}\n navigationTitle={navigationTitle}\n hideClose={hideClose}\n canGoBack={canGoBack}\n onBack={handleBack}\n onClose={onClose}\n headerActions={headerActions}\n content={content}\n modalActions={modalActions}\n hasMobileActions={hasMobileActions}\n rtl={rtl}\n dataTestId={dataTestId}\n />\n </StyledDialog>\n );\n};\n\nexport const StackedModal: FC<StackedModalProps> = (props) => {\n // A modal with no caller-supplied id still needs a STABLE one — it keys this\n // panel's entry in the stack, so a value that changed per render (as a\n // `Math.random()` default does) would re-register it on every pass.\n const fallbackId = useId();\n const resolved = withDefaults(props);\n return <StackedModalPanel {...resolved} modalId={resolved.modalId ?? fallbackId} />;\n};\n\n// Re-exported so `./StackedModal` stays the single public entry point for the\n// component and its stack primitives, as the barrel and existing imports expect.\nexport {\n ModalStackProvider,\n ModalStackProvider as StackedModalProvider,\n useModalStack,\n useModalStack as useStackedModal,\n} from './modal-stack';\nexport { StackedModalActions, StackedModalContent } from './StackedModal.parts';\n","import { useMediaQuery, useTheme } from '@mui/material';\nimport type { RefObject } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { useModalStack } from './modal-stack';\nimport type { ModalPanelRole } from './StackedModal.types';\n\nconst FOCUSABLE = 'a[href], button, textarea, input, select, [tabindex]:not([tabindex=\"-1\"])';\n/** MUI Dialog's own default, used when the modal isn't registered in the stack yet. */\nconst FALLBACK_Z_INDEX = 1300;\n/** Matches the panel's slide duration, so role swaps animate rather than jump. */\nconst ROLE_TRANSITION_MS = 300;\n\n/** Keeps Tab cycling inside the open panel instead of escaping to the page behind. */\nconst useFocusTrap = (\n ref: RefObject<HTMLElement | null>,\n isActive: boolean,\n disabled?: boolean,\n): void => {\n useEffect(() => {\n if (!isActive || disabled || !ref.current) return;\n\n const element = ref.current;\n const focusable = element.querySelectorAll(FOCUSABLE);\n const first = focusable[0] as HTMLElement | undefined;\n const last = focusable[focusable.length - 1] as HTMLElement | undefined;\n\n window.setTimeout(() => first?.focus(), 100);\n\n const handleTabKey = (e: globalThis.KeyboardEvent): void => {\n if (e.key !== 'Tab') return;\n const atEdge = e.shiftKey ? first : last;\n if (document.activeElement !== atEdge) return;\n e.preventDefault();\n (e.shiftKey ? last : first)?.focus();\n };\n\n element.addEventListener('keydown', handleTabKey);\n return () => element.removeEventListener('keydown', handleTabKey);\n }, [ref, isActive, disabled]);\n};\n\n/** Closes the panel on Escape — only while it is the top one. */\nconst useEscapeToClose = (active: boolean, onClose: () => void): void => {\n useEffect(() => {\n if (!active) return;\n\n const handleEsc = (e: globalThis.KeyboardEvent): void => {\n if (e.key !== 'Escape') return;\n e.preventDefault();\n onClose();\n };\n\n window.addEventListener('keydown', handleEsc);\n return () => window.removeEventListener('keydown', handleEsc);\n }, [active, onClose]);\n};\n\n/** Holds the skeleton a beat past `loading` so the swap to content isn't a flash. */\nconst useSkeleton = (loading: boolean): boolean => {\n const [showSkeleton, setShowSkeleton] = useState(loading);\n\n useEffect(() => {\n if (loading) {\n setShowSkeleton(true);\n return;\n }\n const timer = window.setTimeout(() => setShowSkeleton(false), 200);\n return () => window.clearTimeout(timer);\n }, [loading]);\n\n return showSkeleton;\n};\n\n/** Registers the modal in the stack while open, and unregisters it after it slides out. */\nconst useStackRegistration = (open: boolean, modalId: string): void => {\n const { pushModal, popModal, isModalInStack } = useModalStack();\n const hasRegisteredRef = useRef(false);\n\n useEffect(() => {\n if (open && !hasRegisteredRef.current) {\n pushModal(modalId);\n hasRegisteredRef.current = true;\n } else if (!open) {\n hasRegisteredRef.current = false;\n }\n }, [open, modalId, pushModal]);\n\n useEffect(() => {\n if (open || !isModalInStack(modalId)) return;\n const timer = window.setTimeout(() => popModal(modalId), ROLE_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [open, modalId, popModal, isModalInStack]);\n};\n\ninterface PanelChromeOptions {\n open?: boolean;\n modalId: string;\n loading?: boolean;\n closeOnEsc?: boolean;\n closeOnClickOutside?: boolean;\n disableFocusTrap?: boolean;\n onClose: () => void;\n}\n\ninterface PanelChrome {\n dialogRef: RefObject<HTMLDivElement | null>;\n modalRole: ModalPanelRole;\n isAnimating: boolean;\n showSkeleton: boolean;\n zIndex: number;\n isMobile: boolean;\n canGoBack: boolean;\n handleBack: () => void;\n handleClose: (event: object, reason: 'backdropClick' | 'escapeKeyDown') => void;\n}\n\n/**\n * Everything the panel needs to render itself: its place in the stack, the\n * viewport it is on, and the handlers that dismiss it. Bundled into one hook so\n * the component stays a description of the markup.\n */\nexport const usePanelChrome = (options: PanelChromeOptions): PanelChrome => {\n const { open, modalId, loading, closeOnEsc, closeOnClickOutside, disableFocusTrap, onClose } =\n options;\n\n const dialogRef = useRef<HTMLDivElement>(null);\n const { currentDepth } = useModalStack();\n const { modalRole, isAnimating } = useModalRole(Boolean(open), modalId);\n const showSkeleton = useSkeleton(Boolean(loading));\n const zIndex = usePanelZIndex(modalId, FALLBACK_Z_INDEX);\n\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('sm'));\n const isPrimary = modalRole === 'primary';\n const canGoBack = currentDepth > 1;\n\n useFocusTrap(dialogRef, Boolean(open) && isPrimary, disableFocusTrap);\n useEscapeToClose(Boolean(open && closeOnEsc) && isPrimary, onClose);\n\n const { handleBack, handleClose } = useCloseHandlers({\n isPrimary,\n closeOnClickOutside,\n closeOnEsc,\n canGoBack,\n onClose,\n });\n\n return {\n dialogRef,\n modalRole,\n isAnimating,\n showSkeleton,\n zIndex,\n isMobile,\n canGoBack,\n handleBack,\n handleClose,\n };\n};\n\ninterface CloseHandlerOptions {\n /** Only the top panel responds to a backdrop click or Escape. */\n isPrimary: boolean;\n closeOnClickOutside?: boolean;\n closeOnEsc?: boolean;\n /** Deeper than one panel, so the leading control goes back rather than closing. */\n canGoBack: boolean;\n onClose: () => void;\n}\n\n/** The panel's dismissal handlers, honouring which gestures the caller allows. */\nconst useCloseHandlers = ({\n isPrimary,\n closeOnClickOutside,\n closeOnEsc,\n canGoBack,\n onClose,\n}: CloseHandlerOptions): {\n handleBack: () => void;\n handleClose: (event: object, reason: 'backdropClick' | 'escapeKeyDown') => void;\n} => ({\n handleBack: () => {\n if (canGoBack) onClose();\n },\n handleClose: (_event, reason) => {\n if (!isPrimary) return;\n if (reason === 'backdropClick' && !closeOnClickOutside) return;\n if (reason === 'escapeKeyDown' && !closeOnEsc) return;\n onClose();\n },\n});\n\n/** The z-index this panel was assigned when it joined the stack. */\nconst usePanelZIndex = (modalId: string, fallback: number): number => {\n const { stack } = useModalStack();\n return stack.find((m) => m.id === modalId)?.zIndex ?? fallback;\n};\n\n/**\n * This modal's role in the stack, plus whether it is mid-transition between two\n * roles (which drives the expand/contract animation).\n */\nconst useModalRole = (\n open: boolean,\n modalId: string,\n): { modalRole: ModalPanelRole; isAnimating: boolean } => {\n const { stack } = useModalStack();\n const [modalRole, setModalRole] = useState<ModalPanelRole>('primary');\n const [isAnimating, setIsAnimating] = useState(false);\n\n useStackRegistration(open, modalId);\n\n useEffect(() => {\n if (!open) return;\n\n const newRole = stack.find((m) => m.id === modalId)?.role;\n if (!newRole || newRole === modalRole) return;\n\n setIsAnimating(true);\n setModalRole(newRole);\n const timer = window.setTimeout(() => setIsAnimating(false), ROLE_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [stack, modalId, open, modalRole]);\n\n return { modalRole, isAnimating };\n};\n","import type { FC, ReactNode } from 'react';\nimport { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ModalInfo, ModalPanelRole, ModalStackContextValue } from './StackedModal.types';\n\n/** MUI Dialog default z-index; each panel in the stack sits 10 above the last. */\nconst BASE_Z_INDEX = 1300;\nconst Z_INDEX_STEP = 10;\n\nconst noop = (): void => {\n /** do nothing */\n};\n\nconst ModalStackContext = createContext<ModalStackContextValue>({\n stack: [],\n pushModal: noop,\n popModal: noop,\n clearStack: noop,\n currentDepth: 0,\n isModalInStack: () => false,\n getModalRole: () => null,\n});\n\nexport const useModalStack = (): ModalStackContextValue => {\n const context = useContext(ModalStackContext);\n if (!context) {\n throw new Error('useModalStack must be used within a ModalStackProvider');\n }\n return context;\n};\n\n/** Top of the stack drives the view; the one behind it recedes; the rest are hidden. */\nconst roleAt = (index: number, depth: number): ModalPanelRole => {\n if (index === depth - 1) return 'primary';\n if (index === depth - 2) return 'secondary';\n return 'background';\n};\n\n/** Re-derive every role from stack position — the one place roles are assigned. */\nconst withRoles = (stack: ModalInfo[]): ModalInfo[] =>\n stack.map((modal, index) => ({ ...modal, role: roleAt(index, stack.length) }));\n\n/**\n * Locks body scroll while any modal is open, restoring whatever the page had\n * before. Owned by the provider rather than each modal, so nested panels can't\n * fight over the same style.\n */\nconst useBodyScrollLock = (locked: boolean): void => {\n const originalOverflow = useRef<string>('');\n\n useEffect(() => {\n const restore = (): void => {\n if (!originalOverflow.current) return;\n document.body.style.overflow = originalOverflow.current;\n originalOverflow.current = '';\n };\n\n if (locked) {\n if (!originalOverflow.current) {\n originalOverflow.current = document.body.style.overflow || '';\n }\n document.body.style.overflow = 'hidden';\n } else {\n restore();\n }\n\n return restore;\n }, [locked]);\n};\n\nexport const ModalStackProvider: FC<{ children: ReactNode }> = ({ children }) => {\n const [stack, setStack] = useState<ModalInfo[]>([]);\n\n useBodyScrollLock(stack.length > 0);\n\n const pushModal = useCallback((modalId: string) => {\n setStack((prev) => {\n if (prev.some((m) => m.id === modalId)) return prev;\n const entry: ModalInfo = {\n id: modalId,\n zIndex: BASE_Z_INDEX + prev.length * Z_INDEX_STEP,\n role: 'primary',\n };\n return withRoles([...prev, entry]);\n });\n }, []);\n\n const popModal = useCallback((modalId?: string) => {\n setStack((prev) =>\n withRoles(modalId ? prev.filter((m) => m.id !== modalId) : prev.slice(0, -1)),\n );\n }, []);\n\n const clearStack = useCallback(() => setStack([]), []);\n\n const isModalInStack = useCallback(\n (modalId: string) => stack.some((m) => m.id === modalId),\n [stack],\n );\n\n const getModalRole = useCallback(\n (modalId: string) => stack.find((m) => m.id === modalId)?.role ?? null,\n [stack],\n );\n\n const value = useMemo(\n () => ({\n stack,\n pushModal,\n popModal,\n clearStack,\n currentDepth: stack.length,\n isModalInStack,\n getModalRole,\n }),\n [stack, pushModal, popModal, clearStack, isModalInStack, getModalRole],\n );\n\n return <ModalStackContext.Provider value={value}>{children}</ModalStackContext.Provider>;\n};\n","import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport CloseIcon from '@mui/icons-material/Close';\nimport {\n Box,\n CircularProgress,\n DialogActions,\n DialogContent,\n DialogTitle,\n IconButton,\n Skeleton,\n styled,\n Typography,\n} from '@mui/material';\nimport type { FC, ReactNode } from 'react';\nimport React from 'react';\nimport { safeAreaBottom } from '../../../utils/viewport';\nimport {\n loadingOverlayStyles,\n modalContentStyles,\n titleLeftStyles,\n titleRightStyles,\n titleStyles,\n} from './StackedModal.styles';\n\nconst StyledDialogTitle = styled(DialogTitle, {\n shouldForwardProp: (prop) => prop !== 'rtl',\n})<{ rtl?: boolean }>(({ theme, rtl }) => titleStyles(theme, rtl));\n\nconst DialogTitleLeft = styled(Box)(({ theme }) => titleLeftStyles(theme));\nconst DialogTitleRight = styled(Box)(({ theme }) => titleRightStyles(theme));\nconst LoadingOverlay = styled(Box)(({ theme }) => loadingOverlayStyles(theme));\n\n/**\n * The padded content wrapper callers put inside a StackedModal. The explicit\n * `typeof DialogContent` annotation keeps its type nameable across package\n * boundaries (TS2742) now that it is re-exported from the barrel.\n */\nexport const StackedModalContent: typeof DialogContent = styled(DialogContent)(({ theme }) =>\n modalContentStyles(theme),\n) as typeof DialogContent;\n\n/** Sub-element test IDs derive from the modal's own, or stay off when it has none. */\nexport const testId = (base: string | undefined, suffix: string): string | undefined =>\n base ? `${base}-${suffix}` : undefined;\n\n/**\n * A wrapper marking the subtree that should render as modal actions — the\n * StackedModal pulls it out of `children` and places it by device.\n */\nexport const StackedModalActions: FC<{ children?: ReactNode }> = ({ children }) => <>{children}</>;\n\n/** Separates the `StackedModalActions` subtree from the rest of the content. */\nconst splitModalChildren = (children: ReactNode): { content: ReactNode; actions: ReactNode } => {\n let actions: ReactNode = null;\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement<{ children?: ReactNode }>(child) && child.type === StackedModalActions) {\n actions = child.props.children;\n }\n });\n\n const content = React.Children.toArray(children).filter(\n (child) => !(React.isValidElement(child) && child.type === StackedModalActions),\n );\n\n return { content, actions };\n};\n\n/**\n * Works out what renders where: a `StackedModalActions` child wins over the\n * `actions` prop, and on phones those actions move out of the header into a\n * pinned bottom bar.\n */\nexport const resolveModalContent = (\n children: ReactNode,\n actions: ReactNode,\n isMobile: boolean,\n): {\n content: ReactNode;\n modalActions: ReactNode;\n headerActions: ReactNode;\n hasMobileActions: boolean;\n} => {\n const { content, actions: childActions } = splitModalChildren(children);\n const modalActions = childActions ?? actions;\n return {\n content,\n modalActions,\n headerActions: isMobile ? null : modalActions,\n hasMobileActions: Boolean(isMobile && modalActions),\n };\n};\n\n/** The panel's own ARIA ids, unless the caller wired it to its own labels. */\nexport const modalAriaIds = (\n modalId: string,\n ariaLabelledBy?: string,\n ariaDescribedBy?: string,\n): { titleId: string; descId: string } => ({\n titleId: ariaLabelledBy || `modal-title-${modalId}`,\n descId: ariaDescribedBy || `modal-desc-${modalId}`,\n});\n\nexport const ModalLoadingOverlay: FC<{ loadingText?: string; dataTestId?: string }> = ({\n loadingText,\n dataTestId,\n}) => (\n <LoadingOverlay data-testid={testId(dataTestId, 'loading-overlay')}>\n <CircularProgress size={40} data-testid={testId(dataTestId, 'loading-spinner')} />\n {loadingText && (\n <Typography variant=\"body2\" sx={{ mt: 2 }} data-testid={testId(dataTestId, 'loading-text')}>\n {loadingText}\n </Typography>\n )}\n </LoadingOverlay>\n);\n\ninterface ModalHeaderProps {\n titleId: string;\n navigationTitle?: ReactNode;\n /** Deeper than the first panel, so the leading button goes back instead of closing. */\n canGoBack: boolean;\n onBack: () => void;\n onClose: () => void;\n /** Renders the bar without its ✕ — the panel's content owns the dismiss. */\n hideClose?: boolean;\n /** Header actions — desktop only; on phones they move to the footer. */\n headerActions?: ReactNode;\n rtl?: boolean;\n dataTestId?: string;\n}\n\n/**\n * The bar's leading control: back at depth ≥2, otherwise close — and nothing at\n * all when the panel's content carries its own ✕ (`hideClose`).\n */\nconst HeaderLeadingButton: FC<\n Pick<ModalHeaderProps, 'canGoBack' | 'onBack' | 'onClose' | 'hideClose' | 'rtl' | 'dataTestId'>\n> = ({ canGoBack, onBack, onClose, hideClose, rtl, dataTestId }) => {\n if (canGoBack) {\n return (\n <IconButton\n edge=\"start\"\n color=\"inherit\"\n onClick={onBack}\n aria-label=\"go back\"\n size=\"small\"\n sx={{ transform: rtl ? 'rotate(180deg)' : 'none' }}\n data-testid={testId(dataTestId, 'back-button')}\n >\n <ChevronLeftIcon />\n </IconButton>\n );\n }\n if (hideClose) return null;\n return (\n <IconButton\n edge=\"start\"\n color=\"inherit\"\n onClick={onClose}\n aria-label=\"close\"\n size=\"small\"\n data-testid={testId(dataTestId, 'close-button')}\n >\n <CloseIcon />\n </IconButton>\n );\n};\n\nexport const ModalHeader: FC<ModalHeaderProps> = ({\n titleId,\n navigationTitle,\n canGoBack,\n onBack,\n onClose,\n hideClose,\n headerActions,\n rtl,\n dataTestId,\n}) => (\n <StyledDialogTitle id={titleId} rtl={rtl} data-testid={testId(dataTestId, 'header')}>\n <DialogTitleLeft>\n <HeaderLeadingButton\n canGoBack={canGoBack}\n onBack={onBack}\n onClose={onClose}\n hideClose={hideClose}\n rtl={rtl}\n dataTestId={dataTestId}\n />\n {navigationTitle && (\n <Typography\n variant=\"h6\"\n component=\"h2\"\n noWrap\n sx={{ ml: canGoBack || !hideClose ? 1 : 0 }}\n data-testid={testId(dataTestId, 'title')}\n >\n {navigationTitle}\n </Typography>\n )}\n </DialogTitleLeft>\n <DialogTitleRight data-testid={testId(dataTestId, 'header-actions')}>\n {headerActions}\n </DialogTitleRight>\n </StyledDialogTitle>\n);\n\nconst ContentSkeleton: FC = () => (\n <Box sx={{ p: 3 }}>\n <Skeleton variant=\"text\" width=\"60%\" height={32} />\n <Skeleton variant=\"text\" width=\"100%\" />\n <Skeleton variant=\"text\" width=\"100%\" />\n <Skeleton variant=\"rectangular\" height={200} sx={{ mt: 2 }} />\n </Box>\n);\n\ninterface ModalBodyProps {\n descId: string;\n showSkeleton: boolean;\n /** When there is no action bar, the body is what reaches the bottom of the panel. */\n endsPanel: boolean;\n dataTestId?: string;\n children?: ReactNode;\n}\n\nexport const ModalBody: FC<ModalBodyProps> = ({\n descId,\n showSkeleton,\n endsPanel,\n dataTestId,\n children,\n}) => (\n <Box\n id={descId}\n sx={{\n position: 'relative',\n flex: 1,\n overflow: 'auto',\n // iOS momentum scrolling, and no scroll-chaining to the page behind —\n // without `contain`, an overscroll at the end of the list rubber-bands the\n // whole panel and springs back before the last row can be tapped.\n WebkitOverflowScrolling: 'touch',\n overscrollBehavior: 'contain',\n // The content itself ends the panel when there is no action bar, so it has\n // to clear the home indicator on its own.\n ...(endsPanel ? safeAreaBottom(0) : {}),\n }}\n data-testid={testId(dataTestId, 'content')}\n >\n {showSkeleton ? <ContentSkeleton /> : children}\n </Box>\n);\n\n/** The phone-only pinned action bar; on desktop the actions live in the header. */\nexport const ModalFooter: FC<{ dataTestId?: string; children?: ReactNode }> = ({\n dataTestId,\n children,\n}) => (\n <DialogActions\n sx={{\n borderTop: (theme) => `1px solid ${theme.palette.divider}`,\n padding: 2,\n // Never let the action row sit under the iOS home indicator.\n flexShrink: 0,\n ...safeAreaBottom(16),\n }}\n data-testid={testId(dataTestId, 'footer')}\n >\n {children}\n </DialogActions>\n);\n\ninterface PanelContentsProps extends ModalHeaderProps {\n showSkeleton: boolean;\n loadingText?: string;\n descId: string;\n content: ReactNode;\n /** The resolved actions, already placed in the header or destined for the footer. */\n modalActions: ReactNode;\n hasMobileActions: boolean;\n}\n\n/** Everything inside the sliding panel: the loading veil, header, body and action bar. */\nexport const ModalPanelContents: FC<PanelContentsProps> = ({\n showSkeleton,\n loadingText,\n descId,\n content,\n modalActions,\n hasMobileActions,\n ...header\n}) => (\n <>\n {showSkeleton && (\n <ModalLoadingOverlay loadingText={loadingText} dataTestId={header.dataTestId} />\n )}\n <ModalHeader {...header} />\n <ModalBody\n descId={descId}\n showSkeleton={showSkeleton}\n endsPanel={!hasMobileActions}\n dataTestId={header.dataTestId}\n >\n {content}\n </ModalBody>\n {hasMobileActions && (\n <ModalFooter dataTestId={header.dataTestId}>{modalActions}</ModalFooter>\n )}\n </>\n);\n","import { alpha } from '@mui/material';\nimport type { CSSObject, Theme } from '@mui/material';\nimport { dynamicViewportHeight } from '../../../utils/viewport';\nimport type { ModalPanelRole, PanelMaxWidth } from './StackedModal.types';\n\n/** Props that drive the panel's look but must not reach the DOM. */\nexport interface PanelStyleProps {\n modalRole?: ModalPanelRole;\n isAnimating?: boolean;\n glass?: boolean;\n rtl?: boolean;\n customMaxWidth?: PanelMaxWidth;\n}\n\n/** Style-only props, filtered out before they can land on a DOM node. */\nexport const STYLE_ONLY_PROPS = ['modalRole', 'isAnimating', 'glass', 'rtl', 'customMaxWidth'];\n\n/** MUI breakpoint names mapped to the pixel width they cap the panel at. */\nconst MAX_WIDTH_PX: Record<Exclude<PanelMaxWidth, false>, number> = {\n xs: 444,\n sm: 600,\n md: 960,\n lg: 1280,\n xl: 1920,\n};\n\nconst BACKDROP_BY_ROLE: Partial<Record<ModalPanelRole, string>> = {\n secondary: 'rgba(0, 0, 0, 0.3)',\n background: 'rgba(0, 0, 0, 0.1)',\n};\n\nconst ANIMATION_BY_ROLE: Partial<Record<ModalPanelRole, string>> = {\n secondary: 'expandModal 300ms ease-in-out forwards',\n primary: 'contractModal 300ms ease-in-out forwards',\n};\n\n// Animation endpoints use the common lg width (60vw); the role styles set the\n// exact per-breakpoint width once the animation settles.\nconst KEYFRAMES: CSSObject = {\n '@keyframes expandModal': {\n from: { width: '60vw', transform: 'translateX(0)' },\n to: { width: '100vw', transform: 'translateX(0)' },\n },\n '@keyframes contractModal': {\n from: { width: '100vw', transform: 'translateX(0)' },\n to: { width: '60vw', transform: 'translateX(0)' },\n },\n};\n\nconst cap = (customMaxWidth?: PanelMaxWidth): number | null =>\n customMaxWidth ? MAX_WIDTH_PX[customMaxWidth] : null;\n\n/** One breakpoint's width: the viewport share, held under the optional px cap. */\nconst panelWidth = (share: string, capPx: number | null): CSSObject =>\n capPx\n ? { width: `min(${share}, ${capPx}px)`, maxWidth: `${capPx}px` }\n : { width: share, maxWidth: share };\n\nconst backdropStyles = (modalRole?: ModalPanelRole): CSSObject => ({\n backgroundColor: (modalRole && BACKDROP_BY_ROLE[modalRole]) ?? 'rgba(0, 0, 0, 0.5)',\n backdropFilter: modalRole === 'primary' ? 'blur(4px)' : 'none',\n});\n\n/**\n * The top panel is viewport-aware and narrows as the screen grows: full width on\n * mobile, 80vw on tablet/small desktop, 60vw on regular desktops (lg up —\n * including ~1080p/1440p/1080-wide), and 40vw only on ultra-wide screens\n * (≥2200px) so the receding panel stays visible on huge monitors. A `maxWidth`\n * prop, when given, caps it further.\n */\nconst primaryPanelStyles = (theme: Theme, capPx: number | null): CSSObject => ({\n [theme.breakpoints.down('sm')]: panelWidth('100%', capPx),\n [theme.breakpoints.between('sm', 'lg')]: panelWidth('80vw', capPx),\n [theme.breakpoints.up('lg')]: panelWidth('60vw', capPx),\n '@media (min-width:2200px)': panelWidth('40vw', capPx),\n});\n\n/** Panels below the top one expand to full width, producing the GTM stacking effect. */\nconst secondaryPanelStyles = (): CSSObject => ({\n width: '100vw !important',\n maxWidth: '100vw !important',\n right: '0 !important',\n top: '0 !important',\n ...dynamicViewportHeight('height', 'maxHeight'),\n borderRadius: '0 !important',\n opacity: 0.95,\n transform: 'scale(1)',\n});\n\nconst rolePanelStyles = (theme: Theme, role: ModalPanelRole | undefined, capPx: number | null): CSSObject => {\n if (role === 'primary') return primaryPanelStyles(theme, capPx);\n if (role === 'secondary') return secondaryPanelStyles();\n // Background modals stay mounted but hidden, for performance.\n if (role === 'background') return { display: 'none' };\n return {};\n};\n\nconst glassStyles = (theme: Theme, glass?: boolean, role?: ModalPanelRole): CSSObject =>\n glass && role === 'primary'\n ? {\n backgroundColor: alpha(theme.palette.background.paper, 0.85),\n backdropFilter: 'blur(10px)',\n WebkitBackdropFilter: 'blur(10px)',\n border: `1px solid ${alpha(theme.palette.divider, 0.18)}`,\n }\n : {};\n\nconst animationStyles = (isAnimating?: boolean, role?: ModalPanelRole): CSSObject =>\n isAnimating ? { animation: (role && ANIMATION_BY_ROLE[role]) ?? 'none' } : {};\n\nconst panelBaseStyles = (theme: Theme): CSSObject => ({\n margin: 0,\n position: 'fixed',\n right: 0,\n top: 0,\n // Pinned to the DYNAMIC viewport: on iOS a `100vh` panel runs underneath the\n // browser toolbar, which parks the tail of the scroll area (the submit row)\n // out of reach. See `dynamicViewportHeight`.\n ...dynamicViewportHeight('height', 'maxHeight'),\n borderRadius: 0,\n willChange: 'transform, width, border-radius',\n transition: theme.transitions.create(\n ['width', 'max-width', 'border-radius', 'transform', 'opacity'],\n { duration: 300, easing: theme.transitions.easing.easeInOut },\n ),\n});\n\nconst panelStyles = (theme: Theme, props: PanelStyleProps): CSSObject => {\n const capPx = cap(props.customMaxWidth);\n return {\n ...panelBaseStyles(theme),\n ...rolePanelStyles(theme, props.modalRole, capPx),\n ...glassStyles(theme, props.glass, props.modalRole),\n ...animationStyles(props.isAnimating, props.modalRole),\n };\n};\n\n/** The full rule set for the sliding panel's Dialog root. */\nexport const dialogRootStyles = (theme: Theme, props: PanelStyleProps): CSSObject => ({\n direction: props.rtl ? 'rtl' : 'ltr',\n '& .MuiBackdrop-root': backdropStyles(props.modalRole),\n '& .MuiDialog-container': { alignItems: 'flex-start', justifyContent: 'flex-end' },\n '& .MuiDialog-paper': panelStyles(theme, props),\n ...KEYFRAMES,\n});\n\nexport const titleStyles = (theme: Theme, rtl?: boolean): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: theme.spacing(2, 2.5),\n borderBottom: `1px solid ${theme.palette.divider}`,\n direction: rtl ? 'rtl' : 'ltr',\n});\n\nexport const titleLeftStyles = (theme: Theme): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1.5),\n flex: 1,\n});\n\nexport const titleRightStyles = (theme: Theme): CSSObject => ({\n display: 'flex',\n alignItems: 'center',\n gap: theme.spacing(1),\n});\n\nexport const loadingOverlayStyles = (theme: Theme): CSSObject => ({\n position: 'absolute',\n top: 0,\n left: 0,\n right: 0,\n bottom: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: alpha(theme.palette.background.paper, 0.8),\n zIndex: 9999,\n});\n\nexport const modalContentStyles = (theme: Theme): CSSObject => ({\n padding: theme.spacing(3),\n // MUI's DialogContent defaults to `overflow-y: auto`, but inside a panel it is\n // NOT the element that scrolls — ModalBody above it is, and this box always\n // ends up exactly as tall as its own content. A scroll container that never\n // scrolls is still the containing block for every `position: sticky`\n // descendant, so a sticky header anchored here gets zero travel and rides the\n // content out of view: sticky, and pinned to nothing. Handing the overflow\n // back to ModalBody makes the panel's own scroller the anchor.\n overflowY: 'visible',\n});\n"],"mappings":"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","names":["styled","useEffect","useRef","useState","useEffect","useState","useRef","jsx","jsx","styled","SlideTransition"]}
|