@12-apps/ui 6.47.0 → 6.48.1

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.
Files changed (47) hide show
  1. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +6 -6
  2. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +7 -7
  3. package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +4 -4
  4. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +5 -5
  5. package/dist/_internal/components/data-display/LazyImage/LazyImage.js +1 -1
  6. package/dist/_internal/components/data-display/index.js +1 -1
  7. package/dist/_internal/components/feedback/StackedModal/StackedModal.js +3 -3
  8. package/dist/_internal/components/feedback/StackedModal/StackedModal.parts.js +2 -2
  9. package/dist/_internal/components/feedback/StackedModal/StackedModal.styles.js +1 -1
  10. package/dist/_internal/components/feedback/index.js +3 -3
  11. package/dist/_internal/components/index.js +4 -4
  12. package/dist/{chunk-442FSG7G.js → chunk-3QGMAVUF.js} +5 -3
  13. package/dist/chunk-3QGMAVUF.js.map +1 -0
  14. package/dist/{chunk-77JL5XVD.js → chunk-6TZE77YJ.js} +30 -7
  15. package/dist/chunk-6TZE77YJ.js.map +1 -0
  16. package/dist/{chunk-A5ODDTGU.js → chunk-H7DVH6KD.js} +2 -2
  17. package/dist/{chunk-AS2PWQIU.js → chunk-KESGVMHW.js} +2 -2
  18. package/dist/{chunk-IX3U3XPP.js → chunk-KN7C6R6L.js} +2 -2
  19. package/dist/{chunk-XXNLBO4Q.js → chunk-QJK7BNH3.js} +3 -3
  20. package/dist/{chunk-6J32H2RN.js → chunk-QMSCRKR6.js} +3 -2
  21. package/dist/{chunk-6J32H2RN.js.map → chunk-QMSCRKR6.js.map} +1 -1
  22. package/dist/{chunk-L4G5BZFF.js → chunk-RJVUECN7.js} +2 -2
  23. package/dist/data-display/DataViews.js +7 -7
  24. package/dist/data-display/LazyImage.js +1 -1
  25. package/dist/feedback/StackedModal.js +3 -3
  26. package/dist/types/components/feedback/StackedModal/StackedModal.d.ts.map +1 -1
  27. package/dist/types/components/feedback/StackedModal/StackedModal.styles.d.ts +2 -1
  28. package/dist/types/components/feedback/StackedModal/StackedModal.styles.d.ts.map +1 -1
  29. package/dist/types/components/feedback/StackedModal/StackedModal.types.d.ts +8 -0
  30. package/dist/types/components/feedback/StackedModal/StackedModal.types.d.ts.map +1 -1
  31. package/dist/types/components/feedback/StackedModal/index.d.ts +1 -1
  32. package/dist/types/components/feedback/StackedModal/index.d.ts.map +1 -1
  33. package/package.json +1 -1
  34. package/src/components/data-display/LazyImage/LazyImage.md +38 -9
  35. package/src/components/data-display/LazyImage/LazyImage.tsx +6 -6
  36. package/src/components/feedback/StackedModal/StackedModal.md +1 -0
  37. package/src/components/feedback/StackedModal/StackedModal.styles.ts +44 -8
  38. package/src/components/feedback/StackedModal/StackedModal.tsx +2 -1
  39. package/src/components/feedback/StackedModal/StackedModal.types.ts +9 -0
  40. package/src/components/feedback/StackedModal/index.ts +1 -1
  41. package/dist/chunk-442FSG7G.js.map +0 -1
  42. package/dist/chunk-77JL5XVD.js.map +0 -1
  43. /package/dist/{chunk-A5ODDTGU.js.map → chunk-H7DVH6KD.js.map} +0 -0
  44. /package/dist/{chunk-AS2PWQIU.js.map → chunk-KESGVMHW.js.map} +0 -0
  45. /package/dist/{chunk-IX3U3XPP.js.map → chunk-KN7C6R6L.js.map} +0 -0
  46. /package/dist/{chunk-XXNLBO4Q.js.map → chunk-QJK7BNH3.js.map} +0 -0
  47. /package/dist/{chunk-L4G5BZFF.js.map → chunk-RJVUECN7.js.map} +0 -0
@@ -1,11 +1,11 @@
1
1
  "use client";
2
2
  import {
3
3
  DataViewsGrid
4
- } from "../../../../chunk-AS2PWQIU.js";
5
- import "../../../../chunk-IX3U3XPP.js";
4
+ } from "../../../../chunk-KESGVMHW.js";
5
+ import "../../../../chunk-KN7C6R6L.js";
6
6
  import "../../../../chunk-BPOVRMVS.js";
7
7
  import "../../../../chunk-J2SFOLGZ.js";
8
- import "../../../../chunk-XXNLBO4Q.js";
8
+ import "../../../../chunk-QJK7BNH3.js";
9
9
  import "../../../../chunk-OCQ6GDCF.js";
10
10
  import "../../../../chunk-6QYKZMEE.js";
11
11
  import "../../../../chunk-DNT5PZLF.js";
@@ -93,9 +93,9 @@ import "../../../../chunk-Z6T5SXST.js";
93
93
  import "../../../../chunk-C3UKR3NT.js";
94
94
  import "../../../../chunk-D6KL74KI.js";
95
95
  import "../../../../chunk-CN46HGXE.js";
96
- import "../../../../chunk-442FSG7G.js";
97
- import "../../../../chunk-L4G5BZFF.js";
98
- import "../../../../chunk-77JL5XVD.js";
96
+ import "../../../../chunk-3QGMAVUF.js";
97
+ import "../../../../chunk-RJVUECN7.js";
98
+ import "../../../../chunk-6TZE77YJ.js";
99
99
  import "../../../../chunk-G3QKH23Y.js";
100
100
  import "../../../../chunk-JZRSHDNY.js";
101
101
  import "../../../../chunk-L5CPOEDP.js";
@@ -1,14 +1,14 @@
1
1
  "use client";
2
2
  import {
3
3
  DataViewsTableBase
4
- } from "../../../../chunk-A5ODDTGU.js";
4
+ } from "../../../../chunk-H7DVH6KD.js";
5
5
  import "../../../../chunk-NRI2TZDS.js";
6
- import "../../../../chunk-AS2PWQIU.js";
6
+ import "../../../../chunk-KESGVMHW.js";
7
7
  import "../../../../chunk-ZOLAYP2D.js";
8
- import "../../../../chunk-IX3U3XPP.js";
8
+ import "../../../../chunk-KN7C6R6L.js";
9
9
  import "../../../../chunk-BPOVRMVS.js";
10
10
  import "../../../../chunk-J2SFOLGZ.js";
11
- import "../../../../chunk-XXNLBO4Q.js";
11
+ import "../../../../chunk-QJK7BNH3.js";
12
12
  import "../../../../chunk-OCQ6GDCF.js";
13
13
  import "../../../../chunk-6QYKZMEE.js";
14
14
  import "../../../../chunk-DNT5PZLF.js";
@@ -128,9 +128,9 @@ import "../../../../chunk-GVGJMH77.js";
128
128
  import "../../../../chunk-GYXUCS37.js";
129
129
  import "../../../../chunk-LV7LSPBF.js";
130
130
  import "../../../../chunk-CN46HGXE.js";
131
- import "../../../../chunk-442FSG7G.js";
132
- import "../../../../chunk-L4G5BZFF.js";
133
- import "../../../../chunk-77JL5XVD.js";
131
+ import "../../../../chunk-3QGMAVUF.js";
132
+ import "../../../../chunk-RJVUECN7.js";
133
+ import "../../../../chunk-6TZE77YJ.js";
134
134
  import "../../../../chunk-G3QKH23Y.js";
135
135
  import "../../../../chunk-JZRSHDNY.js";
136
136
  import "../../../../chunk-L5CPOEDP.js";
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  FilterDialog,
4
4
  GridFilterPanel
5
- } from "../../../../chunk-XXNLBO4Q.js";
5
+ } from "../../../../chunk-QJK7BNH3.js";
6
6
  import "../../../../chunk-2LSJTQIL.js";
7
7
  import "../../../../chunk-G6II7SVX.js";
8
8
  import "../../../../chunk-YRUX7XMQ.js";
@@ -43,9 +43,9 @@ import "../../../../chunk-Z6T5SXST.js";
43
43
  import "../../../../chunk-C3UKR3NT.js";
44
44
  import "../../../../chunk-D6KL74KI.js";
45
45
  import "../../../../chunk-CN46HGXE.js";
46
- import "../../../../chunk-442FSG7G.js";
47
- import "../../../../chunk-L4G5BZFF.js";
48
- import "../../../../chunk-77JL5XVD.js";
46
+ import "../../../../chunk-3QGMAVUF.js";
47
+ import "../../../../chunk-RJVUECN7.js";
48
+ import "../../../../chunk-6TZE77YJ.js";
49
49
  import "../../../../chunk-G3QKH23Y.js";
50
50
  import "../../../../chunk-JZRSHDNY.js";
51
51
  import "../../../../chunk-AKZWDZCZ.js";
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
  import {
3
3
  GridShell
4
- } from "../../../../chunk-IX3U3XPP.js";
4
+ } from "../../../../chunk-KN7C6R6L.js";
5
5
  import "../../../../chunk-BPOVRMVS.js";
6
6
  import "../../../../chunk-J2SFOLGZ.js";
7
- import "../../../../chunk-XXNLBO4Q.js";
7
+ import "../../../../chunk-QJK7BNH3.js";
8
8
  import "../../../../chunk-OCQ6GDCF.js";
9
9
  import "../../../../chunk-6QYKZMEE.js";
10
10
  import "../../../../chunk-DNT5PZLF.js";
@@ -86,9 +86,9 @@ import "../../../../chunk-Z6T5SXST.js";
86
86
  import "../../../../chunk-C3UKR3NT.js";
87
87
  import "../../../../chunk-D6KL74KI.js";
88
88
  import "../../../../chunk-CN46HGXE.js";
89
- import "../../../../chunk-442FSG7G.js";
90
- import "../../../../chunk-L4G5BZFF.js";
91
- import "../../../../chunk-77JL5XVD.js";
89
+ import "../../../../chunk-3QGMAVUF.js";
90
+ import "../../../../chunk-RJVUECN7.js";
91
+ import "../../../../chunk-6TZE77YJ.js";
92
92
  import "../../../../chunk-G3QKH23Y.js";
93
93
  import "../../../../chunk-JZRSHDNY.js";
94
94
  import "../../../../chunk-L5CPOEDP.js";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  LazyImage
3
- } from "../../../../chunk-6J32H2RN.js";
3
+ } from "../../../../chunk-QMSCRKR6.js";
4
4
  import "../../../../chunk-2TSGRQ2J.js";
5
5
  import "../../../../chunk-724ZONOL.js";
6
6
  import "../../../../chunk-2K2B5QM2.js";
@@ -91,7 +91,7 @@ import "../../../chunk-S5UY5U73.js";
91
91
  import "../../../chunk-5ZFO7ROE.js";
92
92
  import {
93
93
  LazyImage
94
- } from "../../../chunk-6J32H2RN.js";
94
+ } from "../../../chunk-QMSCRKR6.js";
95
95
  import "../../../chunk-2TSGRQ2J.js";
96
96
  import "../../../chunk-724ZONOL.js";
97
97
  import "../../../chunk-UM35GGCS.js";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  StackedModal
3
- } from "../../../../chunk-442FSG7G.js";
3
+ } from "../../../../chunk-3QGMAVUF.js";
4
4
  import {
5
5
  StackedModalActions,
6
6
  StackedModalContent
7
- } from "../../../../chunk-L4G5BZFF.js";
8
- import "../../../../chunk-77JL5XVD.js";
7
+ } from "../../../../chunk-RJVUECN7.js";
8
+ import "../../../../chunk-6TZE77YJ.js";
9
9
  import "../../../../chunk-G3QKH23Y.js";
10
10
  import {
11
11
  ModalStackProvider,
@@ -9,8 +9,8 @@ import {
9
9
  modalAriaIds,
10
10
  resolveModalContent,
11
11
  testId
12
- } from "../../../../chunk-L4G5BZFF.js";
13
- import "../../../../chunk-77JL5XVD.js";
12
+ } from "../../../../chunk-RJVUECN7.js";
13
+ import "../../../../chunk-6TZE77YJ.js";
14
14
  import "../../../../chunk-AKZWDZCZ.js";
15
15
  import "../../../../chunk-FQ6UW7IY.js";
16
16
  import "../../../../chunk-6JAIFIPW.js";
@@ -6,7 +6,7 @@ import {
6
6
  titleLeftStyles,
7
7
  titleRightStyles,
8
8
  titleStyles
9
- } from "../../../../chunk-77JL5XVD.js";
9
+ } from "../../../../chunk-6TZE77YJ.js";
10
10
  import "../../../../chunk-AKZWDZCZ.js";
11
11
  import "../../../../chunk-FQ6UW7IY.js";
12
12
  import "../../../../chunk-6JAIFIPW.js";
@@ -68,12 +68,12 @@ import "../../../chunk-LV7LSPBF.js";
68
68
  import "../../../chunk-CN46HGXE.js";
69
69
  import {
70
70
  StackedModal
71
- } from "../../../chunk-442FSG7G.js";
71
+ } from "../../../chunk-3QGMAVUF.js";
72
72
  import {
73
73
  StackedModalActions,
74
74
  StackedModalContent
75
- } from "../../../chunk-L4G5BZFF.js";
76
- import "../../../chunk-77JL5XVD.js";
75
+ } from "../../../chunk-RJVUECN7.js";
76
+ import "../../../chunk-6TZE77YJ.js";
77
77
  import "../../../chunk-G3QKH23Y.js";
78
78
  import {
79
79
  ModalStackProvider,
@@ -521,7 +521,7 @@ import "../../chunk-S5UY5U73.js";
521
521
  import "../../chunk-5ZFO7ROE.js";
522
522
  import {
523
523
  LazyImage
524
- } from "../../chunk-6J32H2RN.js";
524
+ } from "../../chunk-QMSCRKR6.js";
525
525
  import "../../chunk-2TSGRQ2J.js";
526
526
  import "../../chunk-724ZONOL.js";
527
527
  import "../../chunk-UM35GGCS.js";
@@ -679,12 +679,12 @@ import "../../chunk-LV7LSPBF.js";
679
679
  import "../../chunk-CN46HGXE.js";
680
680
  import {
681
681
  StackedModal
682
- } from "../../chunk-442FSG7G.js";
682
+ } from "../../chunk-3QGMAVUF.js";
683
683
  import {
684
684
  StackedModalActions,
685
685
  StackedModalContent
686
- } from "../../chunk-L4G5BZFF.js";
687
- import "../../chunk-77JL5XVD.js";
686
+ } from "../../chunk-RJVUECN7.js";
687
+ import "../../chunk-6TZE77YJ.js";
688
688
  import "../../chunk-G3QKH23Y.js";
689
689
  import {
690
690
  ModalStackProvider,
@@ -2,11 +2,11 @@ import {
2
2
  ModalPanelContents,
3
3
  modalAriaIds,
4
4
  resolveModalContent
5
- } from "./chunk-L4G5BZFF.js";
5
+ } from "./chunk-RJVUECN7.js";
6
6
  import {
7
7
  STYLE_ONLY_PROPS,
8
8
  dialogRootStyles
9
- } from "./chunk-77JL5XVD.js";
9
+ } from "./chunk-6TZE77YJ.js";
10
10
  import {
11
11
  usePanelChrome
12
12
  } from "./chunk-G3QKH23Y.js";
@@ -66,6 +66,7 @@ var StackedModalPanel = (props) => {
66
66
  loadingText,
67
67
  fullScreen,
68
68
  maxWidth,
69
+ size,
69
70
  disableBackdrop,
70
71
  disableFocusTrap,
71
72
  keepMounted,
@@ -113,6 +114,7 @@ var StackedModalPanel = (props) => {
113
114
  glass,
114
115
  rtl,
115
116
  customMaxWidth: maxWidth,
117
+ panelSize: size,
116
118
  TransitionComponent: SlideTransition,
117
119
  maxWidth,
118
120
  disableEscapeKeyDown: !closeOnEsc,
@@ -156,4 +158,4 @@ var StackedModal = (props) => {
156
158
  export {
157
159
  StackedModal
158
160
  };
159
- //# sourceMappingURL=chunk-442FSG7G.js.map
161
+ //# sourceMappingURL=chunk-3QGMAVUF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.tsx"],"sourcesContent":["import Dialog from '@mui/material/Dialog/index.js';\nimport Slide from '@mui/material/Slide/index.js';\nimport { styled } from '@mui/material/styles/index.js';\nimport type { TransitionProps } from '@mui/material/transitions/index.js';\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, backLabel, hideClose, children, actions, modalId,\n closeOnClickOutside, closeOnEsc, loading, loadingText, fullScreen, maxWidth, size, 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 panelSize={size}\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 backLabel={backLabel}\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"],"mappings":"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","names":["SlideTransition"]}
@@ -10,7 +10,7 @@ import {
10
10
 
11
11
  // src/components/feedback/StackedModal/StackedModal.styles.ts
12
12
  import { alpha } from "@mui/material/styles/index.js";
13
- var STYLE_ONLY_PROPS = ["modalRole", "isAnimating", "glass", "rtl", "customMaxWidth"];
13
+ var STYLE_ONLY_PROPS = ["modalRole", "isAnimating", "glass", "rtl", "customMaxWidth", "panelSize"];
14
14
  var MAX_WIDTH_PX = {
15
15
  xs: 444,
16
16
  sm: 600,
@@ -26,6 +26,10 @@ var ANIMATION_BY_ROLE = {
26
26
  secondary: "expandModal 300ms ease-in-out forwards",
27
27
  primary: "contractModal 300ms ease-in-out forwards"
28
28
  };
29
+ var WIDE_ANIMATION_BY_ROLE = {
30
+ secondary: "expandModalWide 300ms ease-in-out forwards",
31
+ primary: "contractModalWide 300ms ease-in-out forwards"
32
+ };
29
33
  var KEYFRAMES = {
30
34
  "@keyframes expandModal": {
31
35
  from: { width: "60vw", transform: "translateX(0)" },
@@ -34,6 +38,14 @@ var KEYFRAMES = {
34
38
  "@keyframes contractModal": {
35
39
  from: { width: "100vw", transform: "translateX(0)" },
36
40
  to: { width: "60vw", transform: "translateX(0)" }
41
+ },
42
+ "@keyframes expandModalWide": {
43
+ from: { width: "90vw", transform: "translateX(0)" },
44
+ to: { width: "100vw", transform: "translateX(0)" }
45
+ },
46
+ "@keyframes contractModalWide": {
47
+ from: { width: "100vw", transform: "translateX(0)" },
48
+ to: { width: "90vw", transform: "translateX(0)" }
37
49
  }
38
50
  };
39
51
  var cap = (customMaxWidth) => customMaxWidth ? MAX_WIDTH_PX[customMaxWidth] : null;
@@ -49,6 +61,12 @@ var primaryPanelStyles = (theme, capPx) => ({
49
61
  // A viewport width, in the theme's breakpoint unit like the three above.
50
62
  [theme.breakpoints.up(2200)]: panelWidth(theme, "40vw", capPx)
51
63
  });
64
+ var widePrimaryPanelStyles = (theme, capPx) => ({
65
+ [theme.breakpoints.down("sm")]: panelWidth(theme, "100%", capPx),
66
+ [theme.breakpoints.between("sm", "xl")]: panelWidth(theme, "90vw", capPx),
67
+ [theme.breakpoints.up("xl")]: panelWidth(theme, "75vw", capPx),
68
+ [theme.breakpoints.up(2200)]: panelWidth(theme, "60vw", capPx)
69
+ });
52
70
  var secondaryPanelStyles = () => ({
53
71
  width: "100vw !important",
54
72
  maxWidth: "100vw !important",
@@ -59,8 +77,10 @@ var secondaryPanelStyles = () => ({
59
77
  opacity: 0.95,
60
78
  transform: "scale(1)"
61
79
  });
62
- var rolePanelStyles = (theme, role, capPx) => {
63
- if (role === "primary") return primaryPanelStyles(theme, capPx);
80
+ var rolePanelStyles = (theme, role, capPx, size) => {
81
+ if (role === "primary") {
82
+ return size === "wide" ? widePrimaryPanelStyles(theme, capPx) : primaryPanelStyles(theme, capPx);
83
+ }
64
84
  if (role === "secondary") return secondaryPanelStyles();
65
85
  if (role === "background") return { display: "none" };
66
86
  return {};
@@ -71,7 +91,10 @@ var glassStyles = (theme, glass, role) => glass && role === "primary" ? {
71
91
  WebkitBackdropFilter: `blur(${rem(theme, 10)})`,
72
92
  border: `1px solid ${alpha(theme.palette.divider, 0.18)}`
73
93
  } : {};
74
- var animationStyles = (isAnimating, role) => isAnimating ? { animation: (role && ANIMATION_BY_ROLE[role]) ?? "none" } : {};
94
+ var animationStyles = (isAnimating, role, size) => {
95
+ const byRole = size === "wide" ? WIDE_ANIMATION_BY_ROLE : ANIMATION_BY_ROLE;
96
+ return isAnimating ? { animation: (role && byRole[role]) ?? "none" } : {};
97
+ };
75
98
  var panelBaseStyles = (theme) => ({
76
99
  margin: 0,
77
100
  position: "fixed",
@@ -92,9 +115,9 @@ var panelStyles = (theme, props) => {
92
115
  const capPx = cap(props.customMaxWidth);
93
116
  return {
94
117
  ...panelBaseStyles(theme),
95
- ...rolePanelStyles(theme, props.modalRole, capPx),
118
+ ...rolePanelStyles(theme, props.modalRole, capPx, props.panelSize),
96
119
  ...glassStyles(theme, props.glass, props.modalRole),
97
- ...animationStyles(props.isAnimating, props.modalRole)
120
+ ...animationStyles(props.isAnimating, props.modalRole, props.panelSize)
98
121
  };
99
122
  };
100
123
  var dialogRootStyles = (theme, props) => ({
@@ -157,4 +180,4 @@ export {
157
180
  loadingOverlayStyles,
158
181
  modalContentStyles
159
182
  };
160
- //# sourceMappingURL=chunk-77JL5XVD.js.map
183
+ //# sourceMappingURL=chunk-6TZE77YJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.styles.ts"],"sourcesContent":["import { alpha } from '@mui/material/styles/index.js';\nimport type { CSSObject, Theme } from '@mui/material/styles/index.js';\nimport { scrim } from '../../../tokens/ink';\nimport { rem } from '../../../tokens/relative';\nimport { dynamicViewportHeight } from '../../../utils/viewport';\nimport type { ModalPanelRole, PanelMaxWidth, PanelSize } 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 panelSize?: PanelSize;\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', 'panelSize'];\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\n/** The scrim's opacity behind each receding panel role. */\nconst BACKDROP_ALPHA_BY_ROLE: Partial<Record<ModalPanelRole, number>> = {\n secondary: 0.3,\n background: 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/** A wide panel settles at 90vw, so its keyframes must end there too, or it snaps. */\nconst WIDE_ANIMATION_BY_ROLE: Partial<Record<ModalPanelRole, string>> = {\n secondary: 'expandModalWide 300ms ease-in-out forwards',\n primary: 'contractModalWide 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 '@keyframes expandModalWide': {\n from: { width: '90vw', transform: 'translateX(0)' },\n to: { width: '100vw', transform: 'translateX(0)' },\n },\n '@keyframes contractModalWide': {\n from: { width: '100vw', transform: 'translateX(0)' },\n to: { width: '90vw', 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 = (theme: Theme, share: string, capPx: number | null): CSSObject =>\n capPx\n ? { width: `min(${share}, ${rem(theme, capPx)})`, maxWidth: rem(theme, capPx) }\n : { width: share, maxWidth: share };\n\nconst backdropStyles = (theme: Theme, modalRole?: ModalPanelRole): CSSObject => ({\n backgroundColor: scrim(theme, (modalRole && BACKDROP_ALPHA_BY_ROLE[modalRole]) ?? 0.5),\n backdropFilter: modalRole === 'primary' ? `blur(${rem(theme, 4)})` : '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(theme, '100%', capPx),\n [theme.breakpoints.between('sm', 'lg')]: panelWidth(theme, '80vw', capPx),\n [theme.breakpoints.up('lg')]: panelWidth(theme, '60vw', capPx),\n // A viewport width, in the theme's breakpoint unit like the three above.\n [theme.breakpoints.up(2200)]: panelWidth(theme, '40vw', capPx),\n});\n\n/**\n * `size=\"wide\"`: 90vw up to `xl`, 75vw above it, 60vw on ultra-wide screens.\n * At 1280 that is ~1150px instead of 768px — room for a form column beside a\n * fixed ~350px sidebar — while a sliver of the page behind stays visible.\n */\nconst widePrimaryPanelStyles = (theme: Theme, capPx: number | null): CSSObject => ({\n [theme.breakpoints.down('sm')]: panelWidth(theme, '100%', capPx),\n [theme.breakpoints.between('sm', 'xl')]: panelWidth(theme, '90vw', capPx),\n [theme.breakpoints.up('xl')]: panelWidth(theme, '75vw', capPx),\n [theme.breakpoints.up(2200)]: panelWidth(theme, '60vw', 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 = (\n theme: Theme,\n role: ModalPanelRole | undefined,\n capPx: number | null,\n size?: PanelSize,\n): CSSObject => {\n if (role === 'primary') {\n return size === 'wide' ? widePrimaryPanelStyles(theme, capPx) : primaryPanelStyles(theme, capPx);\n }\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(${rem(theme, 10)})`,\n WebkitBackdropFilter: `blur(${rem(theme, 10)})`,\n border: `1px solid ${alpha(theme.palette.divider, 0.18)}`,\n }\n : {};\n\nconst animationStyles = (isAnimating?: boolean, role?: ModalPanelRole, size?: PanelSize): CSSObject => {\n const byRole = size === 'wide' ? WIDE_ANIMATION_BY_ROLE : ANIMATION_BY_ROLE;\n return isAnimating ? { animation: (role && byRole[role]) ?? 'none' } : {};\n};\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, props.panelSize),\n ...glassStyles(theme, props.glass, props.modalRole),\n ...animationStyles(props.isAnimating, props.modalRole, props.panelSize),\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(theme, 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":[]}
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-NRI2TZDS.js";
4
4
  import {
5
5
  DataViewsGrid
6
- } from "./chunk-AS2PWQIU.js";
6
+ } from "./chunk-KESGVMHW.js";
7
7
  import {
8
8
  viewStateKey
9
9
  } from "./chunk-ZOLAYP2D.js";
@@ -178,4 +178,4 @@ function renderViewDialogs(ctl, fields, columns, views, testIdPrefix, onSaved) {
178
178
  export {
179
179
  DataViewsTableBase
180
180
  };
181
- //# sourceMappingURL=chunk-A5ODDTGU.js.map
181
+ //# sourceMappingURL=chunk-H7DVH6KD.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  GridShell
3
- } from "./chunk-IX3U3XPP.js";
3
+ } from "./chunk-KN7C6R6L.js";
4
4
  import {
5
5
  useDataViewsState
6
6
  } from "./chunk-YXU45AVO.js";
@@ -27,4 +27,4 @@ function DataViewsGrid(props) {
27
27
  export {
28
28
  DataViewsGrid
29
29
  };
30
- //# sourceMappingURL=chunk-AS2PWQIU.js.map
30
+ //# sourceMappingURL=chunk-KESGVMHW.js.map
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  FilterDialog,
6
6
  GridFilterPanel
7
- } from "./chunk-XXNLBO4Q.js";
7
+ } from "./chunk-QJK7BNH3.js";
8
8
  import {
9
9
  DataViewsEmpty
10
10
  } from "./chunk-OCQ6GDCF.js";
@@ -238,4 +238,4 @@ function GridShell(props) {
238
238
  export {
239
239
  GridShell
240
240
  };
241
- //# sourceMappingURL=chunk-IX3U3XPP.js.map
241
+ //# sourceMappingURL=chunk-KN7C6R6L.js.map
@@ -12,10 +12,10 @@ import {
12
12
  } from "./chunk-FXWXBEOZ.js";
13
13
  import {
14
14
  StackedModal
15
- } from "./chunk-442FSG7G.js";
15
+ } from "./chunk-3QGMAVUF.js";
16
16
  import {
17
17
  StackedModalContent
18
- } from "./chunk-L4G5BZFF.js";
18
+ } from "./chunk-RJVUECN7.js";
19
19
  import {
20
20
  sxRem
21
21
  } from "./chunk-YKCAJ2TN.js";
@@ -157,4 +157,4 @@ export {
157
157
  GridFilterPanel,
158
158
  FilterDialog
159
159
  };
160
- //# sourceMappingURL=chunk-XXNLBO4Q.js.map
160
+ //# sourceMappingURL=chunk-QJK7BNH3.js.map
@@ -64,7 +64,8 @@ var sxLength = (theme, value) => isFraction(value) ? `${value * 100}%` : styleLe
64
64
  var innerLength = (theme, value) => isFraction(value) ? "100%" : styleLength(theme, value);
65
65
  var orDefault = (value, fallback) => value === void 0 || value === "" ? fallback : value;
66
66
  var emptyToUnset = (value) => value === "" ? void 0 : value;
67
- var isRelativeLength = (value) => isFraction(value) || typeof value === "string" && value.trim().endsWith("%");
67
+ var RELATIVE_LENGTH_UNIT = /[\d.]+(?:%|[dsl]?v(?:w|h|i|b|min|max)|cq(?:w|h|i|b|min|max))(?![a-zA-Z])/;
68
+ var isRelativeLength = (value) => isFraction(value) || typeof value === "string" && RELATIVE_LENGTH_UNIT.test(value);
68
69
  var placeholderAxis = (theme, width, height, resolve) => {
69
70
  const w = emptyToUnset(width);
70
71
  const h = height === "auto" ? void 0 : emptyToUnset(height);
@@ -274,4 +275,4 @@ LazyImage.displayName = "LazyImage";
274
275
  export {
275
276
  LazyImage
276
277
  };
277
- //# sourceMappingURL=chunk-6J32H2RN.js.map
278
+ //# sourceMappingURL=chunk-QMSCRKR6.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/data-display/LazyImage/LazyImage.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport CircularProgress from '@mui/material/CircularProgress/index.js';\nimport { styled, useTheme, type Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\nimport { Skeleton } from '../../layout/Skeleton';\nimport type { ResolvedLazyImageProps } from './LazyImage.hooks';\nimport { imgPassThrough, resolveLazyImageProps, useLazyImage } from './LazyImage.hooks';\nimport type { LazyImageProps } from './LazyImage.types';\nimport { sheen } from '../../../tokens/ink';\nimport { rem } from '../../../tokens/relative';\nimport { fieldHeight } from '../../../tokens/field-height';\n\nconst ImageContainer = styled(Box)(() => ({\n position: 'relative',\n display: 'inline-block',\n overflow: 'hidden',\n}));\n\nconst StyledImage = styled('img')<{\n fadeIn?: boolean;\n fadeInDuration?: number;\n isLoaded?: boolean;\n}>(({ fadeIn, fadeInDuration = 300, isLoaded }) => ({\n display: 'block',\n maxWidth: '100%',\n height: 'auto',\n opacity: fadeIn ? (isLoaded ? 1 : 0) : 1,\n transition: fadeIn ? `opacity ${fadeInDuration}ms ease-in-out` : 'none',\n}));\n\nconst SpinnerOverlay = styled(Box)(({ theme }) => ({\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: sheen(theme, 0.8),\n borderRadius: '50%',\n padding: theme.spacing(1),\n}));\n\nconst FallbackContainer = styled(Box)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: theme.palette.action.disabledBackground,\n color: theme.palette.text.secondary,\n width: '100%',\n height: '100%',\n position: 'absolute',\n top: 0,\n left: 0,\n}));\n\ntype Length = number | string | undefined;\n\n/** A length prop as React `style` and MUI's `Skeleton` read it: a number is design px. */\nconst styleLength = (theme: Theme, value: Length): string | undefined =>\n typeof value === 'number' ? rem(theme, value) : value;\n\n/**\n * A width or height above 0 and up to 1 is a fraction of the container's parent, as in `sx`.\n * A negative number is no fraction: it stays a (negative, so invalid) length.\n */\nconst isFraction = (value: Length): value is number =>\n typeof value === 'number' && value > 0 && value <= 1;\n\n/**\n * A length prop as `sx` reads it on a width or height: a number of 1 or less is\n * a fraction of the parent, and that stays so; any other number is design px.\n */\nconst sxLength = (theme: Theme, value: Length): string | undefined =>\n isFraction(value) ? `${value * 100}%` : styleLength(theme, value);\n\n/**\n * A width or height for what is drawn inside the container. The container alone\n * takes a fraction, so everything in it fills it: a percentage here is measured\n * against the container and would stack (FUT-2666). Otherwise the same as `styleLength`.\n */\nconst innerLength = (theme: Theme, value: Length): string | undefined =>\n isFraction(value) ? '100%' : styleLength(theme, value);\n\n/**\n * A width or height with its default. Only an unset or empty size takes it: `0`\n * is a size, which `||` read as unset (FUT-2669), and `sx` reads `''` as `0%`.\n */\nconst orDefault = (value: Length, fallback: number | string): number | string =>\n value === undefined || value === '' ? fallback : value;\n\n/**\n * A width/height as `metrics` and the `ReactNode` `ErrorFallback` read it\n * (FUT-2774 #4): an explicit empty string is normalized to \"as if unset\"\n * rather than mapped to a component-wide default. Unlike `SkeletonIndicator`\n * (a content-less box with nothing else to size by, hence its own deliberate\n * `'100%'`/`'auto'` fallback), these draw the real image or a `ReactNode`\n * fallback — both have their own intrinsic size, so leaving an unset width\n * unset lets it size naturally (`brand-link.tsx`'s logo relies on exactly\n * this: an unset width capped by its own `sx.maxWidth`).\n */\nconst emptyToUnset = (value: Length): Length => (value === '' ? undefined : value);\n\n/** A length, already resolved to CSS — {@link innerLength} or {@link sxLength}. */\ntype LengthResolver = (theme: Theme, value: Length) => string | undefined;\n\n/**\n * Whether a length is a PERCENTAGE (a numeric {@link isFraction} or a `%`\n * string) — copying it onto the OTHER axis re-creates this ticket's own\n * collapse either way (width%/height% measure different boxes; Chromium-confirmed).\n */\nconst isRelativeLength = (value: Length): boolean =>\n isFraction(value) || (typeof value === 'string' && value.trim().endsWith('%'));\n\n/** A resolved axis pair; `aspectRatio` is set when the OTHER axis comes from CSS, not a length. */\ntype AxisPair = { width: string | undefined; height: string | undefined; aspectRatio?: string };\n\n/**\n * The unset-axis DEFAULT for a PLACEHOLDER only (skeleton, `ReactNode`\n * fallback) — never the real image/`metrics` (an unset width sizes it\n * naturally; `brand-link.tsx`'s logo relies on that). Decision (FUT-2805): an\n * unset axis borrows the set one (a square); neither set, both take the\n * theme's field height; both set stays unchanged. `resolve` is `innerLength`\n * (skeleton) or `sxLength` (the container). A RELATIVE single axis\n * ({@link isRelativeLength}) cannot borrow the same way: it keeps its value\n * and squares up via `aspectRatio: '1 / 1'`, the other axis explicitly\n * `'auto'` (never `undefined` — `Skeleton`'s own default, a fixed `40`,\n * would silently win otherwise).\n */\nconst placeholderAxis = (theme: Theme, width: Length, height: Length, resolve: LengthResolver): AxisPair => {\n const w = emptyToUnset(width);\n // `height` always arrives defaulted to the literal `'auto'` when unset\n // (`LAZY_IMAGE_DEFAULTS`) — indistinguishable from an explicit `\"auto\"`,\n // and no distinction is needed: both mean \"no fixed height requested\".\n const h = height === 'auto' ? undefined : emptyToUnset(height);\n\n if (w === undefined && h === undefined) {\n const field = fieldHeight(theme);\n return { width: field, height: field };\n }\n if (h === undefined) {\n if (isRelativeLength(w)) return { width: resolve(theme, w), height: 'auto', aspectRatio: '1 / 1' };\n const resolved = resolve(theme, w);\n return { width: resolved, height: resolved };\n }\n if (w === undefined) {\n if (isRelativeLength(h)) return { width: 'auto', height: resolve(theme, h), aspectRatio: '1 / 1' };\n const resolved = resolve(theme, h);\n return { width: resolved, height: resolved };\n }\n return { width: resolve(theme, w), height: resolve(theme, h) };\n};\n\n/**\n * `ImageContainer`'s own axis: the ordinary `orDefault(...,'auto')` in every\n * state, except a ReactNode `fallback` while showing — the one case where\n * the container is the only thing that CAN fix its own collapse\n * (`FallbackContainer` is `position: absolute`, never feeding shrink-to-fit).\n */\nconst containerAxisFor = (theme: Theme, props: ResolvedLazyImageProps, hasError: boolean): AxisPair => {\n const { width, height, fallback } = props;\n const needsPlaceholderSize = hasError && Boolean(fallback) && typeof fallback !== 'string';\n return needsPlaceholderSize\n ? placeholderAxis(theme, width, height, sxLength)\n : { width: sxLength(theme, orDefault(width, 'auto')), height: sxLength(theme, orDefault(height, 'auto')) };\n};\n\n/** The box the image occupies, as CSS, shared by the real image and every stand-in for it. */\ninterface BoxMetrics {\n width?: string;\n height?: string;\n objectFit: NonNullable<LazyImageProps['objectFit']>;\n objectPosition: string;\n borderRadius?: string;\n}\n\ninterface IndicatorProps {\n props: ResolvedLazyImageProps;\n metrics: BoxMetrics;\n}\n\nconst SkeletonIndicator: React.FC<IndicatorProps> = ({ props }) => {\n const theme = useTheme();\n // FUT-2805: replaces the old literal `'100%'`/`'auto'` fallbacks, which\n // collapsed to 0 in a shrink-to-fit `ImageContainer` with nothing to\n // resolve against.\n const { width, height, aspectRatio } = placeholderAxis(theme, props.width, props.height, innerLength);\n return (\n <Skeleton\n // FUT-2774 #5: `skeletonProps.variant` was typed but never read — the\n // variant was hard-coded regardless of what a caller passed.\n variant={props.skeletonProps.variant ?? 'rectangular'}\n width={width}\n height={height}\n style={aspectRatio ? { aspectRatio } : undefined}\n // FUT-2774 #5: `||` reads a caller's `false` the same as \"unset\", so\n // `skeletonProps.animation={false}` could never turn the animation off.\n animation={props.skeletonProps.animation ?? 'pulse'}\n intensity={props.skeletonProps.intensity}\n borderRadius={styleLength(theme, props.borderRadius)}\n data-testid={`${props['data-testid']}-skeleton`}\n />\n );\n};\n\nconst SpinnerIndicator: React.FC<IndicatorProps> = ({ props }) => {\n const theme = useTheme();\n const { spinnerProps } = props;\n\n return (\n <SpinnerOverlay>\n <CircularProgress\n // FUT-2774 #5: `||` read `spinnerProps.size`/`thickness` of `0` the\n // same as unset — the same class of bug FUT-2669 fixed for\n // `width`/`height`, missed here.\n size={styleLength(theme, spinnerProps.size ?? 40)}\n thickness={spinnerProps.thickness ?? 4}\n sx={{ color: spinnerProps.color || theme.palette.primary.main }}\n data-testid={`${props['data-testid']}-spinner`}\n />\n </SpinnerOverlay>\n );\n};\n\n/**\n * The placeholder sits in the box's flow and gives the box its size: the box's\n * own when one is set, the placeholder's when not. The real image is drawn over\n * it (`OVER_PLACEHOLDER`) until it has faded in. Its load and error are not the\n * image's, so neither reaches the caller; a failing one just retires.\n */\nconst PlaceholderIndicator: React.FC<IndicatorProps & { onError: () => void }> = ({\n props,\n metrics,\n onError,\n}) => {\n if (!props.placeholder) return null;\n\n return (\n <StyledImage\n src={props.placeholder}\n alt={`${props.alt} (loading)`}\n style={metrics}\n decoding={props.decoding}\n loading={props.lazy ? 'lazy' : props.loading}\n onError={onError}\n data-testid={`${props['data-testid']}-placeholder`}\n />\n );\n};\n\nconst LoadingIndicator: React.FC<\n IndicatorProps & { kind: NonNullable<LazyImageProps['loadingState']>; onPlaceholderError: () => void }\n> = ({ kind, onPlaceholderError, ...rest }) => {\n switch (kind) {\n case 'skeleton':\n return <SkeletonIndicator {...rest} />;\n case 'spinner':\n return <SpinnerIndicator {...rest} />;\n case 'placeholder':\n return <PlaceholderIndicator {...rest} onError={onPlaceholderError} />;\n default:\n return null;\n }\n};\n\n/**\n * The real image while the placeholder is up: laid over it and cropped by\n * `objectFit`, so the box never grows to hold both. It takes the flow back\n * when the placeholder goes.\n */\nconst OVER_PLACEHOLDER: React.CSSProperties = {\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n};\n\nconst ErrorFallback: React.FC<IndicatorProps> = ({ props, metrics }) => {\n const theme = useTheme();\n const { alt, fallback, width, height, borderRadius } = props;\n const testId = props['data-testid'];\n\n if (!fallback) return null;\n\n if (typeof fallback === 'string') {\n return (\n <StyledImage\n src={fallback}\n alt={`${alt} (fallback)`}\n style={metrics}\n fadeIn={false}\n isLoaded={true}\n data-testid={`${testId}-fallback`}\n />\n );\n }\n\n return (\n <FallbackContainer\n sx={{\n // FUT-2774 #4 (see `emptyToUnset`); the collapse is fixed by\n // `LazyImage` giving `ImageContainer` ITSELF a size now\n // (`containerAxisFor`) — this `position: absolute` box just fills it.\n width: innerLength(theme, emptyToUnset(width)),\n height: innerLength(theme, orDefault(height, 'auto')),\n borderRadius: styleLength(theme, borderRadius),\n }}\n data-testid={`${testId}-fallback`}\n >\n {fallback}\n </FallbackContainer>\n );\n};\n\n/**\n * LazyImage component with enhanced features for optimized image loading\n * Supports lazy loading, placeholders, error handling, and various loading states\n */\nexport const LazyImage = React.memo<LazyImageProps>(function LazyImage(rawProps) {\n const props = resolveLazyImageProps(rawProps);\n const theme = useTheme();\n const {\n state,\n containerRef,\n effectiveLoadingState,\n handleImageLoad,\n handleImageError,\n handlePlaceholderError,\n showImage,\n showLoading,\n showPlaceholder,\n } = useLazyImage(props);\n\n const { width, height, borderRadius, alt } = props;\n const testId = props['data-testid'];\n const metrics: BoxMetrics = {\n // FUT-2774 #4 (see `emptyToUnset`): `metrics` also sizes the REAL `<img>`,\n // where an unset width means \"the image's own intrinsic size\" —\n // `brand-link.tsx`'s logo relies on exactly that. `height`'s `'auto'`\n // fallback has no such live case to protect: a percentage height against\n // an auto-height containing block computes to `auto` regardless, so\n // sharing `SkeletonIndicator`'s fallback changes nothing observable.\n width: innerLength(theme, emptyToUnset(width)),\n height: innerLength(theme, orDefault(height, 'auto')),\n objectFit: props.objectFit,\n objectPosition: props.objectPosition,\n borderRadius: styleLength(theme, borderRadius),\n };\n\n const containerAxis = containerAxisFor(theme, props, state.hasError);\n\n return (\n <ImageContainer\n ref={containerRef}\n className={props.className}\n sx={{\n width: containerAxis.width,\n height: containerAxis.height,\n aspectRatio: containerAxis.aspectRatio,\n // The same px length the image gets (`metrics`): in `sx` a bare number\n // would be a multiple of `shape.borderRadius`, and this box clips (FUT-2656).\n borderRadius: metrics.borderRadius,\n }}\n data-testid={testId}\n >\n {showLoading && (\n <LoadingIndicator\n kind={effectiveLoadingState}\n props={props}\n metrics={metrics}\n onPlaceholderError={handlePlaceholderError}\n />\n )}\n\n {showImage && (\n <StyledImage\n src={state.currentSrc || undefined}\n alt={alt}\n onLoad={handleImageLoad}\n onError={handleImageError}\n fadeIn={props.fadeIn}\n fadeInDuration={props.fadeInDuration}\n isLoaded={!state.isLoading}\n decoding={props.decoding}\n loading={props.lazy ? 'lazy' : props.loading}\n style={{ ...metrics, ...props.sx, ...(showPlaceholder && OVER_PLACEHOLDER) }}\n aria-label={props['aria-label'] || alt}\n aria-describedby={props['aria-describedby']}\n role={props.role}\n data-testid={`${testId}-img`}\n {...imgPassThrough(props)}\n />\n )}\n\n {state.hasError && <ErrorFallback props={props} metrics={metrics} />}\n </ImageContainer>\n );\n});\n\nLazyImage.displayName = 'LazyImage';\n"],"mappings":"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","names":["LazyImage"]}
1
+ {"version":3,"sources":["../src/components/data-display/LazyImage/LazyImage.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport CircularProgress from '@mui/material/CircularProgress/index.js';\nimport { styled, useTheme, type Theme } from '@mui/material/styles/index.js';\nimport React from 'react';\nimport { Skeleton } from '../../layout/Skeleton';\nimport type { ResolvedLazyImageProps } from './LazyImage.hooks';\nimport { imgPassThrough, resolveLazyImageProps, useLazyImage } from './LazyImage.hooks';\nimport type { LazyImageProps } from './LazyImage.types';\nimport { sheen } from '../../../tokens/ink';\nimport { rem } from '../../../tokens/relative';\nimport { fieldHeight } from '../../../tokens/field-height';\n\nconst ImageContainer = styled(Box)(() => ({\n position: 'relative',\n display: 'inline-block',\n overflow: 'hidden',\n}));\n\nconst StyledImage = styled('img')<{\n fadeIn?: boolean;\n fadeInDuration?: number;\n isLoaded?: boolean;\n}>(({ fadeIn, fadeInDuration = 300, isLoaded }) => ({\n display: 'block',\n maxWidth: '100%',\n height: 'auto',\n opacity: fadeIn ? (isLoaded ? 1 : 0) : 1,\n transition: fadeIn ? `opacity ${fadeInDuration}ms ease-in-out` : 'none',\n}));\n\nconst SpinnerOverlay = styled(Box)(({ theme }) => ({\n position: 'absolute',\n top: '50%',\n left: '50%',\n transform: 'translate(-50%, -50%)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: sheen(theme, 0.8),\n borderRadius: '50%',\n padding: theme.spacing(1),\n}));\n\nconst FallbackContainer = styled(Box)(({ theme }) => ({\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: theme.palette.action.disabledBackground,\n color: theme.palette.text.secondary,\n width: '100%',\n height: '100%',\n position: 'absolute',\n top: 0,\n left: 0,\n}));\n\ntype Length = number | string | undefined;\n\n/** A length prop as React `style` and MUI's `Skeleton` read it: a number is design px. */\nconst styleLength = (theme: Theme, value: Length): string | undefined =>\n typeof value === 'number' ? rem(theme, value) : value;\n\n/**\n * A width or height above 0 and up to 1 is a fraction of the container's parent, as in `sx`.\n * A negative number is no fraction: it stays a (negative, so invalid) length.\n */\nconst isFraction = (value: Length): value is number =>\n typeof value === 'number' && value > 0 && value <= 1;\n\n/**\n * A length prop as `sx` reads it on a width or height: a number of 1 or less is\n * a fraction of the parent, and that stays so; any other number is design px.\n */\nconst sxLength = (theme: Theme, value: Length): string | undefined =>\n isFraction(value) ? `${value * 100}%` : styleLength(theme, value);\n\n/**\n * A width or height for what is drawn inside the container. The container alone\n * takes a fraction, so everything in it fills it: a percentage here is measured\n * against the container and would stack (FUT-2666). Otherwise the same as `styleLength`.\n */\nconst innerLength = (theme: Theme, value: Length): string | undefined =>\n isFraction(value) ? '100%' : styleLength(theme, value);\n\n/**\n * A width or height with its default. Only an unset or empty size takes it: `0`\n * is a size, which `||` read as unset (FUT-2669), and `sx` reads `''` as `0%`.\n */\nconst orDefault = (value: Length, fallback: number | string): number | string =>\n value === undefined || value === '' ? fallback : value;\n\n/**\n * A width/height as `metrics` and the `ReactNode` `ErrorFallback` read it\n * (FUT-2774 #4): an explicit empty string is normalized to \"as if unset\"\n * rather than mapped to a component-wide default. Unlike `SkeletonIndicator`\n * (a content-less box with nothing else to size by, hence its own deliberate\n * `'100%'`/`'auto'` fallback), these draw the real image or a `ReactNode`\n * fallback — both have their own intrinsic size, so leaving an unset width\n * unset lets it size naturally (`brand-link.tsx`'s logo relies on exactly\n * this: an unset width capped by its own `sx.maxWidth`).\n */\nconst emptyToUnset = (value: Length): Length => (value === '' ? undefined : value);\n\n/** A length, already resolved to CSS — {@link innerLength} or {@link sxLength}. */\ntype LengthResolver = (theme: Theme, value: Length) => string | undefined;\n\n// A number + `%`, a (small/large/dynamic) viewport unit, or a container-query\n// unit, anywhere in a string, even nested in `calc()`/`min()`/`max()`/`clamp()`.\nconst RELATIVE_LENGTH_UNIT = /[\\d.]+(?:%|[dsl]?v(?:w|h|i|b|min|max)|cq(?:w|h|i|b|min|max))(?![a-zA-Z])/;\n// RELATIVE: {@link isFraction}, or that unit anywhere — borrowing it onto the\n// OTHER axis re-creates this collapse (all these units square, `LazyImage.md`).\nconst isRelativeLength = (value: Length): boolean =>\n isFraction(value) || (typeof value === 'string' && RELATIVE_LENGTH_UNIT.test(value));\n\n/** A resolved axis pair; `aspectRatio` is set when the OTHER axis comes from CSS, not a length. */\ntype AxisPair = { width: string | undefined; height: string | undefined; aspectRatio?: string };\n\n/**\n * The unset-axis DEFAULT for a PLACEHOLDER only (skeleton, `ReactNode`\n * fallback) — never the real image/`metrics` (an unset width sizes it\n * naturally; `brand-link.tsx`'s logo relies on that). Decision (FUT-2805): an\n * unset axis borrows the set one (a square); neither set, both take the\n * theme's field height; both set stays unchanged. `resolve` is `innerLength`\n * (skeleton) or `sxLength` (the container). A RELATIVE single axis\n * ({@link isRelativeLength}) cannot borrow the same way: it keeps its value\n * and squares up via `aspectRatio: '1 / 1'`, the other axis explicitly\n * `'auto'` (never `undefined` — `Skeleton`'s own default, a fixed `40`,\n * would silently win otherwise).\n */\nconst placeholderAxis = (theme: Theme, width: Length, height: Length, resolve: LengthResolver): AxisPair => {\n const w = emptyToUnset(width);\n // `height` always arrives defaulted to the literal `'auto'` when unset\n // (`LAZY_IMAGE_DEFAULTS`) — indistinguishable from an explicit `\"auto\"`,\n // and no distinction is needed: both mean \"no fixed height requested\".\n const h = height === 'auto' ? undefined : emptyToUnset(height);\n\n if (w === undefined && h === undefined) {\n const field = fieldHeight(theme);\n return { width: field, height: field };\n }\n if (h === undefined) {\n if (isRelativeLength(w)) return { width: resolve(theme, w), height: 'auto', aspectRatio: '1 / 1' };\n const resolved = resolve(theme, w);\n return { width: resolved, height: resolved };\n }\n if (w === undefined) {\n if (isRelativeLength(h)) return { width: 'auto', height: resolve(theme, h), aspectRatio: '1 / 1' };\n const resolved = resolve(theme, h);\n return { width: resolved, height: resolved };\n }\n return { width: resolve(theme, w), height: resolve(theme, h) };\n};\n\n/**\n * `ImageContainer`'s own axis: the ordinary `orDefault(...,'auto')` in every\n * state, except a ReactNode `fallback` while showing — the one case where\n * the container is the only thing that CAN fix its own collapse\n * (`FallbackContainer` is `position: absolute`, never feeding shrink-to-fit).\n */\nconst containerAxisFor = (theme: Theme, props: ResolvedLazyImageProps, hasError: boolean): AxisPair => {\n const { width, height, fallback } = props;\n const needsPlaceholderSize = hasError && Boolean(fallback) && typeof fallback !== 'string';\n return needsPlaceholderSize\n ? placeholderAxis(theme, width, height, sxLength)\n : { width: sxLength(theme, orDefault(width, 'auto')), height: sxLength(theme, orDefault(height, 'auto')) };\n};\n\n/** The box the image occupies, as CSS, shared by the real image and every stand-in for it. */\ninterface BoxMetrics {\n width?: string;\n height?: string;\n objectFit: NonNullable<LazyImageProps['objectFit']>;\n objectPosition: string;\n borderRadius?: string;\n}\n\ninterface IndicatorProps {\n props: ResolvedLazyImageProps;\n metrics: BoxMetrics;\n}\n\nconst SkeletonIndicator: React.FC<IndicatorProps> = ({ props }) => {\n const theme = useTheme();\n // FUT-2805: replaces the old literal `'100%'`/`'auto'` fallbacks, which\n // collapsed to 0 in a shrink-to-fit `ImageContainer` with nothing to\n // resolve against.\n const { width, height, aspectRatio } = placeholderAxis(theme, props.width, props.height, innerLength);\n return (\n <Skeleton\n // FUT-2774 #5: `skeletonProps.variant` was typed but never read — the\n // variant was hard-coded regardless of what a caller passed.\n variant={props.skeletonProps.variant ?? 'rectangular'}\n width={width}\n height={height}\n style={aspectRatio ? { aspectRatio } : undefined}\n // FUT-2774 #5: `||` reads a caller's `false` the same as \"unset\", so\n // `skeletonProps.animation={false}` could never turn the animation off.\n animation={props.skeletonProps.animation ?? 'pulse'}\n intensity={props.skeletonProps.intensity}\n borderRadius={styleLength(theme, props.borderRadius)}\n data-testid={`${props['data-testid']}-skeleton`}\n />\n );\n};\n\nconst SpinnerIndicator: React.FC<IndicatorProps> = ({ props }) => {\n const theme = useTheme();\n const { spinnerProps } = props;\n\n return (\n <SpinnerOverlay>\n <CircularProgress\n // FUT-2774 #5: `||` read `spinnerProps.size`/`thickness` of `0` the\n // same as unset — the same class of bug FUT-2669 fixed for\n // `width`/`height`, missed here.\n size={styleLength(theme, spinnerProps.size ?? 40)}\n thickness={spinnerProps.thickness ?? 4}\n sx={{ color: spinnerProps.color || theme.palette.primary.main }}\n data-testid={`${props['data-testid']}-spinner`}\n />\n </SpinnerOverlay>\n );\n};\n\n/**\n * The placeholder sits in the box's flow and gives the box its size: the box's\n * own when one is set, the placeholder's when not. The real image is drawn over\n * it (`OVER_PLACEHOLDER`) until it has faded in. Its load and error are not the\n * image's, so neither reaches the caller; a failing one just retires.\n */\nconst PlaceholderIndicator: React.FC<IndicatorProps & { onError: () => void }> = ({\n props,\n metrics,\n onError,\n}) => {\n if (!props.placeholder) return null;\n\n return (\n <StyledImage\n src={props.placeholder}\n alt={`${props.alt} (loading)`}\n style={metrics}\n decoding={props.decoding}\n loading={props.lazy ? 'lazy' : props.loading}\n onError={onError}\n data-testid={`${props['data-testid']}-placeholder`}\n />\n );\n};\n\nconst LoadingIndicator: React.FC<\n IndicatorProps & { kind: NonNullable<LazyImageProps['loadingState']>; onPlaceholderError: () => void }\n> = ({ kind, onPlaceholderError, ...rest }) => {\n switch (kind) {\n case 'skeleton':\n return <SkeletonIndicator {...rest} />;\n case 'spinner':\n return <SpinnerIndicator {...rest} />;\n case 'placeholder':\n return <PlaceholderIndicator {...rest} onError={onPlaceholderError} />;\n default:\n return null;\n }\n};\n\n/**\n * The real image while the placeholder is up: laid over it and cropped by\n * `objectFit`, so the box never grows to hold both. It takes the flow back\n * when the placeholder goes.\n */\nconst OVER_PLACEHOLDER: React.CSSProperties = {\n position: 'absolute',\n inset: 0,\n width: '100%',\n height: '100%',\n};\n\nconst ErrorFallback: React.FC<IndicatorProps> = ({ props, metrics }) => {\n const theme = useTheme();\n const { alt, fallback, width, height, borderRadius } = props;\n const testId = props['data-testid'];\n\n if (!fallback) return null;\n\n if (typeof fallback === 'string') {\n return (\n <StyledImage\n src={fallback}\n alt={`${alt} (fallback)`}\n style={metrics}\n fadeIn={false}\n isLoaded={true}\n data-testid={`${testId}-fallback`}\n />\n );\n }\n\n return (\n <FallbackContainer\n sx={{\n // FUT-2774 #4 (see `emptyToUnset`); the collapse is fixed by\n // `LazyImage` giving `ImageContainer` ITSELF a size now\n // (`containerAxisFor`) — this `position: absolute` box just fills it.\n width: innerLength(theme, emptyToUnset(width)),\n height: innerLength(theme, orDefault(height, 'auto')),\n borderRadius: styleLength(theme, borderRadius),\n }}\n data-testid={`${testId}-fallback`}\n >\n {fallback}\n </FallbackContainer>\n );\n};\n\n/**\n * LazyImage component with enhanced features for optimized image loading\n * Supports lazy loading, placeholders, error handling, and various loading states\n */\nexport const LazyImage = React.memo<LazyImageProps>(function LazyImage(rawProps) {\n const props = resolveLazyImageProps(rawProps);\n const theme = useTheme();\n const {\n state,\n containerRef,\n effectiveLoadingState,\n handleImageLoad,\n handleImageError,\n handlePlaceholderError,\n showImage,\n showLoading,\n showPlaceholder,\n } = useLazyImage(props);\n\n const { width, height, borderRadius, alt } = props;\n const testId = props['data-testid'];\n const metrics: BoxMetrics = {\n // FUT-2774 #4 (see `emptyToUnset`): `metrics` also sizes the REAL `<img>`,\n // where an unset width means \"the image's own intrinsic size\" —\n // `brand-link.tsx`'s logo relies on exactly that. `height`'s `'auto'`\n // fallback has no such live case to protect: a percentage height against\n // an auto-height containing block computes to `auto` regardless, so\n // sharing `SkeletonIndicator`'s fallback changes nothing observable.\n width: innerLength(theme, emptyToUnset(width)),\n height: innerLength(theme, orDefault(height, 'auto')),\n objectFit: props.objectFit,\n objectPosition: props.objectPosition,\n borderRadius: styleLength(theme, borderRadius),\n };\n\n const containerAxis = containerAxisFor(theme, props, state.hasError);\n\n return (\n <ImageContainer\n ref={containerRef}\n className={props.className}\n sx={{\n width: containerAxis.width,\n height: containerAxis.height,\n aspectRatio: containerAxis.aspectRatio,\n // The same px length the image gets (`metrics`): in `sx` a bare number\n // would be a multiple of `shape.borderRadius`, and this box clips (FUT-2656).\n borderRadius: metrics.borderRadius,\n }}\n data-testid={testId}\n >\n {showLoading && (\n <LoadingIndicator\n kind={effectiveLoadingState}\n props={props}\n metrics={metrics}\n onPlaceholderError={handlePlaceholderError}\n />\n )}\n\n {showImage && (\n <StyledImage\n src={state.currentSrc || undefined}\n alt={alt}\n onLoad={handleImageLoad}\n onError={handleImageError}\n fadeIn={props.fadeIn}\n fadeInDuration={props.fadeInDuration}\n isLoaded={!state.isLoading}\n decoding={props.decoding}\n loading={props.lazy ? 'lazy' : props.loading}\n style={{ ...metrics, ...props.sx, ...(showPlaceholder && OVER_PLACEHOLDER) }}\n aria-label={props['aria-label'] || alt}\n aria-describedby={props['aria-describedby']}\n role={props.role}\n data-testid={`${testId}-img`}\n {...imgPassThrough(props)}\n />\n )}\n\n {state.hasError && <ErrorFallback props={props} metrics={metrics} />}\n </ImageContainer>\n );\n});\n\nLazyImage.displayName = 'LazyImage';\n"],"mappings":"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","names":["LazyImage"]}
@@ -4,7 +4,7 @@ import {
4
4
  titleLeftStyles,
5
5
  titleRightStyles,
6
6
  titleStyles
7
- } from "./chunk-77JL5XVD.js";
7
+ } from "./chunk-6TZE77YJ.js";
8
8
  import {
9
9
  safeAreaBottom
10
10
  } from "./chunk-AKZWDZCZ.js";
@@ -231,4 +231,4 @@ export {
231
231
  ModalFooter,
232
232
  ModalPanelContents
233
233
  };
234
- //# sourceMappingURL=chunk-L4G5BZFF.js.map
234
+ //# sourceMappingURL=chunk-RJVUECN7.js.map
@@ -3,11 +3,11 @@ import {
3
3
  } from "../chunk-AJ4MRDKM.js";
4
4
  import {
5
5
  DataViewsTableBase
6
- } from "../chunk-A5ODDTGU.js";
6
+ } from "../chunk-H7DVH6KD.js";
7
7
  import "../chunk-NRI2TZDS.js";
8
8
  import {
9
9
  DataViewsGrid
10
- } from "../chunk-AS2PWQIU.js";
10
+ } from "../chunk-KESGVMHW.js";
11
11
  import {
12
12
  BaseListCard
13
13
  } from "../chunk-3WAAL3KN.js";
@@ -22,12 +22,12 @@ import {
22
22
  useDragItem
23
23
  } from "../chunk-K4EKTMTC.js";
24
24
  import "../chunk-ZOLAYP2D.js";
25
- import "../chunk-IX3U3XPP.js";
25
+ import "../chunk-KN7C6R6L.js";
26
26
  import "../chunk-BPOVRMVS.js";
27
27
  import {
28
28
  DataViewsBoard
29
29
  } from "../chunk-J2SFOLGZ.js";
30
- import "../chunk-XXNLBO4Q.js";
30
+ import "../chunk-QJK7BNH3.js";
31
31
  import "../chunk-OCQ6GDCF.js";
32
32
  import "../chunk-6QYKZMEE.js";
33
33
  import "../chunk-DNT5PZLF.js";
@@ -171,9 +171,9 @@ import "../chunk-GVGJMH77.js";
171
171
  import "../chunk-GYXUCS37.js";
172
172
  import "../chunk-LV7LSPBF.js";
173
173
  import "../chunk-CN46HGXE.js";
174
- import "../chunk-442FSG7G.js";
175
- import "../chunk-L4G5BZFF.js";
176
- import "../chunk-77JL5XVD.js";
174
+ import "../chunk-3QGMAVUF.js";
175
+ import "../chunk-RJVUECN7.js";
176
+ import "../chunk-6TZE77YJ.js";
177
177
  import "../chunk-G3QKH23Y.js";
178
178
  import "../chunk-JZRSHDNY.js";
179
179
  import "../chunk-L5CPOEDP.js";
@@ -1,7 +1,7 @@
1
1
  import "../chunk-5ZFO7ROE.js";
2
2
  import {
3
3
  LazyImage
4
- } from "../chunk-6J32H2RN.js";
4
+ } from "../chunk-QMSCRKR6.js";
5
5
  import "../chunk-2TSGRQ2J.js";
6
6
  import "../chunk-724ZONOL.js";
7
7
  import "../chunk-2K2B5QM2.js";
@@ -1,12 +1,12 @@
1
1
  import "../chunk-CN46HGXE.js";
2
2
  import {
3
3
  StackedModal
4
- } from "../chunk-442FSG7G.js";
4
+ } from "../chunk-3QGMAVUF.js";
5
5
  import {
6
6
  StackedModalActions,
7
7
  StackedModalContent
8
- } from "../chunk-L4G5BZFF.js";
9
- import "../chunk-77JL5XVD.js";
8
+ } from "../chunk-RJVUECN7.js";
9
+ import "../chunk-6TZE77YJ.js";
10
10
  import "../chunk-G3QKH23Y.js";
11
11
  import {
12
12
  ModalStackProvider,
@@ -1 +1 @@
1
- {"version":3,"file":"StackedModal.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAMhC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAwH9D,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAO9C,CAAC;AAIF,OAAO,EACL,kBAAkB,EAClB,kBAAkB,IAAI,oBAAoB,EAC1C,aAAa,EACb,aAAa,IAAI,eAAe,GACjC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"StackedModal.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC;AAMhC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAyH9D,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAO9C,CAAC;AAIF,OAAO,EACL,kBAAkB,EAClB,kBAAkB,IAAI,oBAAoB,EAC1C,aAAa,EACb,aAAa,IAAI,eAAe,GACjC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { CSSObject, Theme } from '@mui/material/styles/index.js';
2
- import type { ModalPanelRole, PanelMaxWidth } from './StackedModal.types';
2
+ import type { ModalPanelRole, PanelMaxWidth, PanelSize } from './StackedModal.types';
3
3
  /** Props that drive the panel's look but must not reach the DOM. */
4
4
  export interface PanelStyleProps {
5
5
  modalRole?: ModalPanelRole;
@@ -7,6 +7,7 @@ export interface PanelStyleProps {
7
7
  glass?: boolean;
8
8
  rtl?: boolean;
9
9
  customMaxWidth?: PanelMaxWidth;
10
+ panelSize?: PanelSize;
10
11
  }
11
12
  /** Style-only props, filtered out before they can land on a DOM node. */
12
13
  export declare const STYLE_ONLY_PROPS: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"StackedModal.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.styles.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAItE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAE1E,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,cAAc,CAAC,EAAE,aAAa,CAAC;CAChC;AAED,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,UAAiE,CAAC;AA4H/F,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,EAAE,OAAO,eAAe,KAAG,SAMtE,CAAC;AAEH,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,EAAE,MAAM,OAAO,KAAG,SAOxD,CAAC;AAEH,eAAO,MAAM,eAAe,GAAI,OAAO,KAAK,KAAG,SAK7C,CAAC;AAEH,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,KAAG,SAI9C,CAAC;AAEH,eAAO,MAAM,oBAAoB,GAAI,OAAO,KAAK,KAAG,SAYlD,CAAC;AAEH,eAAO,MAAM,kBAAkB,GAAI,OAAO,KAAK,KAAG,SAUhD,CAAC"}
1
+ {"version":3,"file":"StackedModal.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.styles.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAItE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAErF,oEAAoE;AACpE,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,cAAc,CAAC,EAAE,aAAa,CAAC;IAC/B,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,yEAAyE;AACzE,eAAO,MAAM,gBAAgB,UAA8E,CAAC;AA+J5G,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,EAAE,OAAO,eAAe,KAAG,SAMtE,CAAC;AAEH,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,EAAE,MAAM,OAAO,KAAG,SAOxD,CAAC;AAEH,eAAO,MAAM,eAAe,GAAI,OAAO,KAAK,KAAG,SAK7C,CAAC;AAEH,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,KAAG,SAI9C,CAAC;AAEH,eAAO,MAAM,oBAAoB,GAAI,OAAO,KAAK,KAAG,SAYlD,CAAC;AAEH,eAAO,MAAM,kBAAkB,GAAI,OAAO,KAAK,KAAG,SAUhD,CAAC"}
@@ -3,6 +3,12 @@ import type { ReactNode } from 'react';
3
3
  export type ModalPanelRole = 'primary' | 'secondary' | 'background';
4
4
  /** The breakpoint the panel's width is capped at, or `false` for uncapped. */
5
5
  export type PanelMaxWidth = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | false;
6
+ /**
7
+ * How much of the viewport the top panel takes from `sm` up. `wide` is for a
8
+ * dense editor that lays out two columns inside the panel, which the default
9
+ * 60vw starves on a laptop.
10
+ */
11
+ export type PanelSize = 'default' | 'wide';
6
12
  export interface StackedModalProps {
7
13
  /** The back arrow's accessible name — it carries a glyph only. REQUIRED. */
8
14
  backLabel: string;
@@ -40,6 +46,8 @@ export interface StackedModalProps {
40
46
  fullScreen?: boolean;
41
47
  /** Maximum width of the modal */
42
48
  maxWidth?: PanelMaxWidth;
49
+ /** Viewport share of the top panel — `wide` gives a dense editor more room */
50
+ size?: PanelSize;
43
51
  /** Disable the backdrop click behavior */
44
52
  disableBackdrop?: boolean;
45
53
  /** Disable focus trap functionality */
@@ -1 +1 @@
1
- {"version":3,"file":"StackedModal.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,oFAAoF;AACpF,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,CAAC;AAEpE,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,IAAI,EAAE,OAAO,CAAC;IACd,8DAA8D;IAC9D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,mCAAmC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,0CAA0C;IAC1C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yCAAyC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gCAAgC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iCAAiC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,IAAI,EAAE,cAAc,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,0BAA0B;IAC1B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,oCAAoC;IACpC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,sCAAsC;IACtC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,2CAA2C;IAC3C,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,cAAc,GAAG,IAAI,CAAC;CAC1D"}
1
+ {"version":3,"file":"StackedModal.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,oFAAoF;AACpF,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,CAAC;AAEpE,8EAA8E;AAC9E,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;AAErE;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAE3C,MAAM,WAAW,iBAAiB;IAChC,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,IAAI,EAAE,OAAO,CAAC;IACd,8DAA8D;IAC9D,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,mCAAmC;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,kDAAkD;IAClD,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,mDAAmD;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6BAA6B;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,aAAa,CAAC;IACzB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,0CAA0C;IAC1C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uCAAuC;IACvC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,yCAAyC;IACzC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gCAAgC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iCAAiC;IACjC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,4CAA4C;IAC5C,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,SAAS;IACxB,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,IAAI,EAAE,cAAc,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,0BAA0B;IAC1B,KAAK,EAAE,SAAS,EAAE,CAAC;IACnB,+BAA+B;IAC/B,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,oCAAoC;IACpC,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,sCAAsC;IACtC,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,uCAAuC;IACvC,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC;IAC7C,2CAA2C;IAC3C,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,cAAc,GAAG,IAAI,CAAC;CAC1D"}
@@ -1,3 +1,3 @@
1
1
  export { ModalStackProvider, StackedModal, StackedModalActions as StackedModalActions, StackedModalContent as StackedModalContent, ModalStackProvider as StackedModalProvider, useModalStack, useModalStack as useStackedModal, } from './StackedModal';
2
- export type { StackedModalProps } from './StackedModal.types';
2
+ export type { PanelSize, StackedModalProps } from './StackedModal.types';
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,IAAI,mBAAmB,EAC1C,mBAAmB,IAAI,mBAAmB,EAC1C,kBAAkB,IAAI,oBAAoB,EAC1C,aAAa,EACb,aAAa,IAAI,eAAe,GACjC,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,YAAY,EACZ,mBAAmB,IAAI,mBAAmB,EAC1C,mBAAmB,IAAI,mBAAmB,EAC1C,kBAAkB,IAAI,oBAAoB,EAC1C,aAAa,EACb,aAAa,IAAI,eAAe,GACjC,MAAM,gBAAgB,CAAC;AAExB,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/ui",
3
- "version": "6.47.0",
3
+ "version": "6.48.1",
4
4
  "license": "MIT",
5
5
  "packageManager": "pnpm@10.34.5",
6
6
  "type": "module",
@@ -191,15 +191,44 @@ wrapping element, rounded to match the image:
191
191
  > - A **DEFINITE** set axis (a plain design-px number, or an absolute CSS
192
192
  > length string) borrows straight onto the unset one: a square in real
193
193
  > px/rem — e.g. `width={120}` alone gives the skeleton `120×120`.
194
- > - A **RELATIVE** set axis (a fraction in `(0, 1]`, or a `%` string) cannot
195
- > be copied onto the other one the same way — a width-percentage and a
196
- > height-percentage measure against two different boxes, so copying the
197
- > value would re-create the exact 0-height/0-width collapse this default
198
- > exists to fix. Instead, the set axis keeps its own value and the box
199
- > squares up through CSS `aspectRatio: '1 / 1'`, with the other axis left
200
- > `auto` — e.g. `width="100%"` alone gives the skeleton `width: 100%;
201
- > height: auto; aspect-ratio: 1 / 1`, a square exactly as wide as its
202
- > (now non-collapsing) container.
194
+ > - A **RELATIVE** set axis cannot be copied onto the other one the same way —
195
+ > a width-percentage and a height-percentage measure against two different
196
+ > boxes, so copying the value would re-create the exact 0-height/0-width
197
+ > collapse this default exists to fix. Instead, the set axis keeps its own
198
+ > value and the box squares up through CSS `aspectRatio: '1 / 1'`, with the
199
+ > other axis left `auto` — e.g. `width="100%"` alone gives the skeleton
200
+ > `width: 100%; height: auto; aspect-ratio: 1 / 1`, a square exactly as wide
201
+ > as its (now non-collapsing) container. A length is RELATIVE when:
202
+ > - it is a fraction in `(0, 1]`, or
203
+ > - it has a `%` **anywhere** in the string — not only a bare trailing `%`,
204
+ > but a `%` nested inside `calc()`/`min()`/`max()`/`clamp()` too (FUT-2869:
205
+ > `width="calc(100% - 8px)"` alone squares, exactly like `width="100%"`
206
+ > alone — a `%` still measures against the containing block no matter what
207
+ > it is wrapped in, and borrowing it onto the other axis still collapses
208
+ > to 0 against an auto-height parent), or
209
+ > - it has a viewport unit — `vw`/`vh`/`vmin`/`vmax`, or the small/large/
210
+ > dynamic variants `svw`/`svh`/`svmin`/`svmax`, `lvw`/`lvh`/`lvmin`/
211
+ > `lvmax`, `dvw`/`dvh`/`dvmin`/`dvmax`, or the logical `vi`/`vb` — anywhere
212
+ > in the string (FUT-2869: `width="50vw"` alone squares too — see below for
213
+ > why), or
214
+ > - it has a container-query unit — `cqw`/`cqh`/`cqi`/`cqb`/`cqmin`/`cqmax` —
215
+ > anywhere in the string: it depends on the nearest queried container, not
216
+ > the length itself, exactly the reasoning below.
217
+ >
218
+ > **Why viewport and container-query units square instead of borrow
219
+ > (FUT-2869's Decision).** Neither collapses to 0 the way a borrowed `%`
220
+ > does — a viewport unit resolves against the viewport, a container-query
221
+ > unit against its queried container, so a literally-borrowed `height: 50vw`
222
+ > is merely some non-zero length. But it is still wrong: the component's own
223
+ > promise for a single set axis is a SQUARE placeholder, and a length
224
+ > borrowed onto the other axis is a square only when the thing it measures
225
+ > against (the viewport, or the queried container) happens to be exactly the
226
+ > SAME size as `LazyImage`'s own container — the moment it isn't (any
227
+ > padding, sidebar, or max-width layout — the ordinary case), `width: 50vw`
228
+ > next to a borrowed `height: 50vw` is visibly not square. Squaring costs
229
+ > nothing extra (the same `aspectRatio` mechanism `%` already uses) and keeps
230
+ > one rule — "does this length depend on anything outside itself" — for
231
+ > every relative unit, instead of a different rule per unit family.
203
232
  > - With **neither** axis set, both take the theme's field height
204
233
  > (`theme.fieldHeight`, through `fieldHeight()`/`rem()` — never a raw px).
205
234
  > - With **both** set, nothing above applies: the placeholder renders exactly
@@ -104,13 +104,13 @@ const emptyToUnset = (value: Length): Length => (value === '' ? undefined : valu
104
104
  /** A length, already resolved to CSS — {@link innerLength} or {@link sxLength}. */
105
105
  type LengthResolver = (theme: Theme, value: Length) => string | undefined;
106
106
 
107
- /**
108
- * Whether a length is a PERCENTAGE (a numeric {@link isFraction} or a `%`
109
- * string) — copying it onto the OTHER axis re-creates this ticket's own
110
- * collapse either way (width%/height% measure different boxes; Chromium-confirmed).
111
- */
107
+ // A number + `%`, a (small/large/dynamic) viewport unit, or a container-query
108
+ // unit, anywhere in a string, even nested in `calc()`/`min()`/`max()`/`clamp()`.
109
+ const RELATIVE_LENGTH_UNIT = /[\d.]+(?:%|[dsl]?v(?:w|h|i|b|min|max)|cq(?:w|h|i|b|min|max))(?![a-zA-Z])/;
110
+ // RELATIVE: {@link isFraction}, or that unit anywhere — borrowing it onto the
111
+ // OTHER axis re-creates this collapse (all these units square, `LazyImage.md`).
112
112
  const isRelativeLength = (value: Length): boolean =>
113
- isFraction(value) || (typeof value === 'string' && value.trim().endsWith('%'));
113
+ isFraction(value) || (typeof value === 'string' && RELATIVE_LENGTH_UNIT.test(value));
114
114
 
115
115
  /** A resolved axis pair; `aspectRatio` is set when the OTHER axis comes from CSS, not a length. */
116
116
  type AxisPair = { width: string | undefined; height: string | undefined; aspectRatio?: string };
@@ -135,6 +135,7 @@ new component that portals should too.
135
135
  | `loadingText` | `string` | `'Loading...'` | Text shown during loading state |
136
136
  | `fullScreen` | `boolean` | `false` | Full screen mode |
137
137
  | `maxWidth` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'xl' \| false` | `'md'` | Maximum modal width |
138
+ | `size` | `'default' \| 'wide'` | `'default'` | Viewport share of the top panel: default is 80vw (`sm`–`lg`), 60vw (`lg`+), 40vw (≥2200px); `wide` is 90vw up to `xl`, 75vw above, 60vw ≥2200px — for a dense two-column editor |
138
139
  | `disableBackdrop` | `boolean` | `false` | Hide backdrop |
139
140
  | `disableFocusTrap` | `boolean` | `false` | Disable focus trapping |
140
141
  | `keepMounted` | `boolean` | `false` | Keep modal mounted when closed |
@@ -3,7 +3,7 @@ import type { CSSObject, Theme } from '@mui/material/styles/index.js';
3
3
  import { scrim } from '../../../tokens/ink';
4
4
  import { rem } from '../../../tokens/relative';
5
5
  import { dynamicViewportHeight } from '../../../utils/viewport';
6
- import type { ModalPanelRole, PanelMaxWidth } from './StackedModal.types';
6
+ import type { ModalPanelRole, PanelMaxWidth, PanelSize } from './StackedModal.types';
7
7
 
8
8
  /** Props that drive the panel's look but must not reach the DOM. */
9
9
  export interface PanelStyleProps {
@@ -12,10 +12,11 @@ export interface PanelStyleProps {
12
12
  glass?: boolean;
13
13
  rtl?: boolean;
14
14
  customMaxWidth?: PanelMaxWidth;
15
+ panelSize?: PanelSize;
15
16
  }
16
17
 
17
18
  /** Style-only props, filtered out before they can land on a DOM node. */
18
- export const STYLE_ONLY_PROPS = ['modalRole', 'isAnimating', 'glass', 'rtl', 'customMaxWidth'];
19
+ export const STYLE_ONLY_PROPS = ['modalRole', 'isAnimating', 'glass', 'rtl', 'customMaxWidth', 'panelSize'];
19
20
 
20
21
  /** MUI breakpoint names mapped to the pixel width they cap the panel at. */
21
22
  const MAX_WIDTH_PX: Record<Exclude<PanelMaxWidth, false>, number> = {
@@ -37,6 +38,12 @@ const ANIMATION_BY_ROLE: Partial<Record<ModalPanelRole, string>> = {
37
38
  primary: 'contractModal 300ms ease-in-out forwards',
38
39
  };
39
40
 
41
+ /** A wide panel settles at 90vw, so its keyframes must end there too, or it snaps. */
42
+ const WIDE_ANIMATION_BY_ROLE: Partial<Record<ModalPanelRole, string>> = {
43
+ secondary: 'expandModalWide 300ms ease-in-out forwards',
44
+ primary: 'contractModalWide 300ms ease-in-out forwards',
45
+ };
46
+
40
47
  // Animation endpoints use the common lg width (60vw); the role styles set the
41
48
  // exact per-breakpoint width once the animation settles.
42
49
  const KEYFRAMES: CSSObject = {
@@ -48,6 +55,14 @@ const KEYFRAMES: CSSObject = {
48
55
  from: { width: '100vw', transform: 'translateX(0)' },
49
56
  to: { width: '60vw', transform: 'translateX(0)' },
50
57
  },
58
+ '@keyframes expandModalWide': {
59
+ from: { width: '90vw', transform: 'translateX(0)' },
60
+ to: { width: '100vw', transform: 'translateX(0)' },
61
+ },
62
+ '@keyframes contractModalWide': {
63
+ from: { width: '100vw', transform: 'translateX(0)' },
64
+ to: { width: '90vw', transform: 'translateX(0)' },
65
+ },
51
66
  };
52
67
 
53
68
  const cap = (customMaxWidth?: PanelMaxWidth): number | null =>
@@ -79,6 +94,18 @@ const primaryPanelStyles = (theme: Theme, capPx: number | null): CSSObject => ({
79
94
  [theme.breakpoints.up(2200)]: panelWidth(theme, '40vw', capPx),
80
95
  });
81
96
 
97
+ /**
98
+ * `size="wide"`: 90vw up to `xl`, 75vw above it, 60vw on ultra-wide screens.
99
+ * At 1280 that is ~1150px instead of 768px — room for a form column beside a
100
+ * fixed ~350px sidebar — while a sliver of the page behind stays visible.
101
+ */
102
+ const widePrimaryPanelStyles = (theme: Theme, capPx: number | null): CSSObject => ({
103
+ [theme.breakpoints.down('sm')]: panelWidth(theme, '100%', capPx),
104
+ [theme.breakpoints.between('sm', 'xl')]: panelWidth(theme, '90vw', capPx),
105
+ [theme.breakpoints.up('xl')]: panelWidth(theme, '75vw', capPx),
106
+ [theme.breakpoints.up(2200)]: panelWidth(theme, '60vw', capPx),
107
+ });
108
+
82
109
  /** Panels below the top one expand to full width, producing the GTM stacking effect. */
83
110
  const secondaryPanelStyles = (): CSSObject => ({
84
111
  width: '100vw !important',
@@ -91,8 +118,15 @@ const secondaryPanelStyles = (): CSSObject => ({
91
118
  transform: 'scale(1)',
92
119
  });
93
120
 
94
- const rolePanelStyles = (theme: Theme, role: ModalPanelRole | undefined, capPx: number | null): CSSObject => {
95
- if (role === 'primary') return primaryPanelStyles(theme, capPx);
121
+ const rolePanelStyles = (
122
+ theme: Theme,
123
+ role: ModalPanelRole | undefined,
124
+ capPx: number | null,
125
+ size?: PanelSize,
126
+ ): CSSObject => {
127
+ if (role === 'primary') {
128
+ return size === 'wide' ? widePrimaryPanelStyles(theme, capPx) : primaryPanelStyles(theme, capPx);
129
+ }
96
130
  if (role === 'secondary') return secondaryPanelStyles();
97
131
  // Background modals stay mounted but hidden, for performance.
98
132
  if (role === 'background') return { display: 'none' };
@@ -109,8 +143,10 @@ const glassStyles = (theme: Theme, glass?: boolean, role?: ModalPanelRole): CSSO
109
143
  }
110
144
  : {};
111
145
 
112
- const animationStyles = (isAnimating?: boolean, role?: ModalPanelRole): CSSObject =>
113
- isAnimating ? { animation: (role && ANIMATION_BY_ROLE[role]) ?? 'none' } : {};
146
+ const animationStyles = (isAnimating?: boolean, role?: ModalPanelRole, size?: PanelSize): CSSObject => {
147
+ const byRole = size === 'wide' ? WIDE_ANIMATION_BY_ROLE : ANIMATION_BY_ROLE;
148
+ return isAnimating ? { animation: (role && byRole[role]) ?? 'none' } : {};
149
+ };
114
150
 
115
151
  const panelBaseStyles = (theme: Theme): CSSObject => ({
116
152
  margin: 0,
@@ -133,9 +169,9 @@ const panelStyles = (theme: Theme, props: PanelStyleProps): CSSObject => {
133
169
  const capPx = cap(props.customMaxWidth);
134
170
  return {
135
171
  ...panelBaseStyles(theme),
136
- ...rolePanelStyles(theme, props.modalRole, capPx),
172
+ ...rolePanelStyles(theme, props.modalRole, capPx, props.panelSize),
137
173
  ...glassStyles(theme, props.glass, props.modalRole),
138
- ...animationStyles(props.isAnimating, props.modalRole),
174
+ ...animationStyles(props.isAnimating, props.modalRole, props.panelSize),
139
175
  };
140
176
  };
141
177
 
@@ -62,7 +62,7 @@ type ResolvedProps = StackedModalProps & { modalId: string };
62
62
  const StackedModalPanel: FC<ResolvedProps> = (props) => {
63
63
  const {
64
64
  open, onClose, glass, navigationTitle, backLabel, hideClose, children, actions, modalId,
65
- closeOnClickOutside, closeOnEsc, loading, loadingText, fullScreen, maxWidth, disableBackdrop,
65
+ closeOnClickOutside, closeOnEsc, loading, loadingText, fullScreen, maxWidth, size, disableBackdrop,
66
66
  disableFocusTrap, keepMounted, rtl, dataTestId,
67
67
  'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, ...otherProps
68
68
  } = props;
@@ -95,6 +95,7 @@ const StackedModalPanel: FC<ResolvedProps> = (props) => {
95
95
  glass={glass}
96
96
  rtl={rtl}
97
97
  customMaxWidth={maxWidth}
98
+ panelSize={size}
98
99
  TransitionComponent={SlideTransition}
99
100
  maxWidth={maxWidth}
100
101
  disableEscapeKeyDown={!closeOnEsc}
@@ -6,6 +6,13 @@ export type ModalPanelRole = 'primary' | 'secondary' | 'background';
6
6
  /** The breakpoint the panel's width is capped at, or `false` for uncapped. */
7
7
  export type PanelMaxWidth = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | false;
8
8
 
9
+ /**
10
+ * How much of the viewport the top panel takes from `sm` up. `wide` is for a
11
+ * dense editor that lays out two columns inside the panel, which the default
12
+ * 60vw starves on a laptop.
13
+ */
14
+ export type PanelSize = 'default' | 'wide';
15
+
9
16
  export interface StackedModalProps {
10
17
  /** The back arrow's accessible name — it carries a glyph only. REQUIRED. */
11
18
  backLabel: string;
@@ -43,6 +50,8 @@ export interface StackedModalProps {
43
50
  fullScreen?: boolean;
44
51
  /** Maximum width of the modal */
45
52
  maxWidth?: PanelMaxWidth;
53
+ /** Viewport share of the top panel — `wide` gives a dense editor more room */
54
+ size?: PanelSize;
46
55
  /** Disable the backdrop click behavior */
47
56
  disableBackdrop?: boolean;
48
57
  /** Disable focus trap functionality */
@@ -8,4 +8,4 @@ export {
8
8
  useModalStack as useStackedModal,
9
9
  } from './StackedModal';
10
10
 
11
- export type { StackedModalProps } from './StackedModal.types';
11
+ export type { PanelSize, StackedModalProps } from './StackedModal.types';
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.tsx"],"sourcesContent":["import Dialog from '@mui/material/Dialog/index.js';\nimport Slide from '@mui/material/Slide/index.js';\nimport { styled } from '@mui/material/styles/index.js';\nimport type { TransitionProps } from '@mui/material/transitions/index.js';\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, backLabel, 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 backLabel={backLabel}\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"],"mappings":"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","names":["SlideTransition"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.styles.ts"],"sourcesContent":["import { alpha } from '@mui/material/styles/index.js';\nimport type { CSSObject, Theme } from '@mui/material/styles/index.js';\nimport { scrim } from '../../../tokens/ink';\nimport { rem } from '../../../tokens/relative';\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\n/** The scrim's opacity behind each receding panel role. */\nconst BACKDROP_ALPHA_BY_ROLE: Partial<Record<ModalPanelRole, number>> = {\n secondary: 0.3,\n background: 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 = (theme: Theme, share: string, capPx: number | null): CSSObject =>\n capPx\n ? { width: `min(${share}, ${rem(theme, capPx)})`, maxWidth: rem(theme, capPx) }\n : { width: share, maxWidth: share };\n\nconst backdropStyles = (theme: Theme, modalRole?: ModalPanelRole): CSSObject => ({\n backgroundColor: scrim(theme, (modalRole && BACKDROP_ALPHA_BY_ROLE[modalRole]) ?? 0.5),\n backdropFilter: modalRole === 'primary' ? `blur(${rem(theme, 4)})` : '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(theme, '100%', capPx),\n [theme.breakpoints.between('sm', 'lg')]: panelWidth(theme, '80vw', capPx),\n [theme.breakpoints.up('lg')]: panelWidth(theme, '60vw', capPx),\n // A viewport width, in the theme's breakpoint unit like the three above.\n [theme.breakpoints.up(2200)]: panelWidth(theme, '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(${rem(theme, 10)})`,\n WebkitBackdropFilter: `blur(${rem(theme, 10)})`,\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(theme, 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":";;;;;;;;;;;AAAA,SAAS,aAAa;AAiBf,IAAM,mBAAmB,CAAC,aAAa,eAAe,SAAS,OAAO,gBAAgB;AAG7F,IAAM,eAA8D;AAAA,EAClE,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAGA,IAAM,yBAAkE;AAAA,EACtE,WAAW;AAAA,EACX,YAAY;AACd;AAEA,IAAM,oBAA6D;AAAA,EACjE,WAAW;AAAA,EACX,SAAS;AACX;AAIA,IAAM,YAAuB;AAAA,EAC3B,0BAA0B;AAAA,IACxB,MAAM,EAAE,OAAO,QAAQ,WAAW,gBAAgB;AAAA,IAClD,IAAI,EAAE,OAAO,SAAS,WAAW,gBAAgB;AAAA,EACnD;AAAA,EACA,4BAA4B;AAAA,IAC1B,MAAM,EAAE,OAAO,SAAS,WAAW,gBAAgB;AAAA,IACnD,IAAI,EAAE,OAAO,QAAQ,WAAW,gBAAgB;AAAA,EAClD;AACF;AAEA,IAAM,MAAM,CAAC,mBACX,iBAAiB,aAAa,cAAc,IAAI;AAGlD,IAAM,aAAa,CAAC,OAAc,OAAe,UAC/C,QACI,EAAE,OAAO,OAAO,KAAK,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,UAAU,IAAI,OAAO,KAAK,EAAE,IAC5E,EAAE,OAAO,OAAO,UAAU,MAAM;AAEtC,IAAM,iBAAiB,CAAC,OAAc,eAA2C;AAAA,EAC/E,iBAAiB,MAAM,QAAQ,aAAa,uBAAuB,SAAS,MAAM,GAAG;AAAA,EACrF,gBAAgB,cAAc,YAAY,QAAQ,IAAI,OAAO,CAAC,CAAC,MAAM;AACvE;AASA,IAAM,qBAAqB,CAAC,OAAc,WAAqC;AAAA,EAC7E,CAAC,MAAM,YAAY,KAAK,IAAI,CAAC,GAAG,WAAW,OAAO,QAAQ,KAAK;AAAA,EAC/D,CAAC,MAAM,YAAY,QAAQ,MAAM,IAAI,CAAC,GAAG,WAAW,OAAO,QAAQ,KAAK;AAAA,EACxE,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,WAAW,OAAO,QAAQ,KAAK;AAAA;AAAA,EAE7D,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,WAAW,OAAO,QAAQ,KAAK;AAC/D;AAGA,IAAM,uBAAuB,OAAkB;AAAA,EAC7C,OAAO;AAAA,EACP,UAAU;AAAA,EACV,OAAO;AAAA,EACP,KAAK;AAAA,EACL,GAAG,sBAAsB,UAAU,WAAW;AAAA,EAC9C,cAAc;AAAA,EACd,SAAS;AAAA,EACT,WAAW;AACb;AAEA,IAAM,kBAAkB,CAAC,OAAc,MAAkC,UAAoC;AAC3G,MAAI,SAAS,UAAW,QAAO,mBAAmB,OAAO,KAAK;AAC9D,MAAI,SAAS,YAAa,QAAO,qBAAqB;AAEtD,MAAI,SAAS,aAAc,QAAO,EAAE,SAAS,OAAO;AACpD,SAAO,CAAC;AACV;AAEA,IAAM,cAAc,CAAC,OAAc,OAAiB,SAClD,SAAS,SAAS,YACd;AAAA,EACE,iBAAiB,MAAM,MAAM,QAAQ,WAAW,OAAO,IAAI;AAAA,EAC3D,gBAAgB,QAAQ,IAAI,OAAO,EAAE,CAAC;AAAA,EACtC,sBAAsB,QAAQ,IAAI,OAAO,EAAE,CAAC;AAAA,EAC5C,QAAQ,aAAa,MAAM,MAAM,QAAQ,SAAS,IAAI,CAAC;AACzD,IACA,CAAC;AAEP,IAAM,kBAAkB,CAAC,aAAuB,SAC9C,cAAc,EAAE,YAAY,QAAQ,kBAAkB,IAAI,MAAM,OAAO,IAAI,CAAC;AAE9E,IAAM,kBAAkB,CAAC,WAA6B;AAAA,EACpD,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,OAAO;AAAA,EACP,KAAK;AAAA;AAAA;AAAA;AAAA,EAIL,GAAG,sBAAsB,UAAU,WAAW;AAAA,EAC9C,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,YAAY,MAAM,YAAY;AAAA,IAC5B,CAAC,SAAS,aAAa,iBAAiB,aAAa,SAAS;AAAA,IAC9D,EAAE,UAAU,KAAK,QAAQ,MAAM,YAAY,OAAO,UAAU;AAAA,EAC9D;AACF;AAEA,IAAM,cAAc,CAAC,OAAc,UAAsC;AACvE,QAAM,QAAQ,IAAI,MAAM,cAAc;AACtC,SAAO;AAAA,IACL,GAAG,gBAAgB,KAAK;AAAA,IACxB,GAAG,gBAAgB,OAAO,MAAM,WAAW,KAAK;AAAA,IAChD,GAAG,YAAY,OAAO,MAAM,OAAO,MAAM,SAAS;AAAA,IAClD,GAAG,gBAAgB,MAAM,aAAa,MAAM,SAAS;AAAA,EACvD;AACF;AAGO,IAAM,mBAAmB,CAAC,OAAc,WAAuC;AAAA,EACpF,WAAW,MAAM,MAAM,QAAQ;AAAA,EAC/B,uBAAuB,eAAe,OAAO,MAAM,SAAS;AAAA,EAC5D,0BAA0B,EAAE,YAAY,cAAc,gBAAgB,WAAW;AAAA,EACjF,sBAAsB,YAAY,OAAO,KAAK;AAAA,EAC9C,GAAG;AACL;AAEO,IAAM,cAAc,CAAC,OAAc,SAA8B;AAAA,EACtE,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,SAAS,MAAM,QAAQ,GAAG,GAAG;AAAA,EAC7B,cAAc,aAAa,MAAM,QAAQ,OAAO;AAAA,EAChD,WAAW,MAAM,QAAQ;AAC3B;AAEO,IAAM,kBAAkB,CAAC,WAA6B;AAAA,EAC3D,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,KAAK,MAAM,QAAQ,GAAG;AAAA,EACtB,MAAM;AACR;AAEO,IAAM,mBAAmB,CAAC,WAA6B;AAAA,EAC5D,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,KAAK,MAAM,QAAQ,CAAC;AACtB;AAEO,IAAM,uBAAuB,CAAC,WAA6B;AAAA,EAChE,UAAU;AAAA,EACV,KAAK;AAAA,EACL,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,iBAAiB,MAAM,MAAM,QAAQ,WAAW,OAAO,GAAG;AAAA,EAC1D,QAAQ;AACV;AAEO,IAAM,qBAAqB,CAAC,WAA6B;AAAA,EAC9D,SAAS,MAAM,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQxB,WAAW;AACb;","names":[]}