@12-apps/ui 6.62.1 → 6.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +7 -7
- package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +8 -8
- package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +5 -5
- package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +6 -6
- package/dist/_internal/components/feedback/StackedModal/StackedModal.hooks.js +1 -1
- package/dist/_internal/components/feedback/StackedModal/StackedModal.js +4 -4
- package/dist/_internal/components/feedback/StackedModal/StackedModal.parts.js +2 -2
- package/dist/_internal/components/feedback/StackedModal/StackedModal.styles.js +1 -1
- package/dist/_internal/components/feedback/index.js +4 -4
- package/dist/_internal/components/index.js +4 -4
- package/dist/{chunk-6KQWNPER.js → chunk-64BEEFLJ.js} +2 -2
- package/dist/{chunk-SKOAJPOS.js → chunk-EP674QTM.js} +3 -3
- package/dist/{chunk-6DJQKK6Q.js → chunk-F5LDJ52M.js} +2 -2
- package/dist/{chunk-2KGYTJCN.js → chunk-GLKUN3DL.js} +4 -3
- package/dist/{chunk-2KGYTJCN.js.map → chunk-GLKUN3DL.js.map} +1 -1
- package/dist/{chunk-UDC5M3P2.js → chunk-RG3GJTSK.js} +2 -2
- package/dist/{chunk-OGBLNORM.js → chunk-RQ2NKSIA.js} +19 -5
- package/dist/chunk-RQ2NKSIA.js.map +1 -0
- package/dist/{chunk-G3QKH23Y.js → chunk-TSMF7K37.js} +4 -2
- package/dist/chunk-TSMF7K37.js.map +1 -0
- package/dist/{chunk-NEHCU3EZ.js → chunk-XSIVM4VO.js} +5 -2
- package/dist/{chunk-NEHCU3EZ.js.map → chunk-XSIVM4VO.js.map} +1 -1
- package/dist/data-display/DataViews.js +8 -8
- package/dist/feedback/StackedModal.js +4 -4
- package/dist/types/components/feedback/StackedModal/StackedModal.d.ts.map +1 -1
- package/dist/types/components/feedback/StackedModal/StackedModal.hooks.d.ts +6 -0
- package/dist/types/components/feedback/StackedModal/StackedModal.hooks.d.ts.map +1 -1
- package/dist/types/components/feedback/StackedModal/StackedModal.parts.d.ts +2 -0
- package/dist/types/components/feedback/StackedModal/StackedModal.parts.d.ts.map +1 -1
- package/dist/types/components/feedback/StackedModal/StackedModal.styles.d.ts.map +1 -1
- package/dist/types/components/feedback/StackedModal/StackedModal.types.d.ts +12 -0
- package/dist/types/components/feedback/StackedModal/StackedModal.types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/feedback/StackedModal/StackedModal.hooks.ts +11 -1
- package/src/components/feedback/StackedModal/StackedModal.md +28 -1
- package/src/components/feedback/StackedModal/StackedModal.parts.tsx +4 -1
- package/src/components/feedback/StackedModal/StackedModal.styles.ts +4 -1
- package/src/components/feedback/StackedModal/StackedModal.tsx +22 -3
- package/src/components/feedback/StackedModal/StackedModal.types.ts +12 -0
- package/dist/chunk-G3QKH23Y.js.map +0 -1
- package/dist/chunk-OGBLNORM.js.map +0 -1
- /package/dist/{chunk-6KQWNPER.js.map → chunk-64BEEFLJ.js.map} +0 -0
- /package/dist/{chunk-SKOAJPOS.js.map → chunk-EP674QTM.js.map} +0 -0
- /package/dist/{chunk-6DJQKK6Q.js.map → chunk-F5LDJ52M.js.map} +0 -0
- /package/dist/{chunk-UDC5M3P2.js.map → chunk-RG3GJTSK.js.map} +0 -0
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
DataViewsGrid
|
|
4
|
-
} from "../../../../chunk-
|
|
5
|
-
import "../../../../chunk-
|
|
4
|
+
} from "../../../../chunk-F5LDJ52M.js";
|
|
5
|
+
import "../../../../chunk-64BEEFLJ.js";
|
|
6
6
|
import "../../../../chunk-HM6T6EQR.js";
|
|
7
7
|
import "../../../../chunk-NHHWNA5W.js";
|
|
8
|
-
import "../../../../chunk-
|
|
8
|
+
import "../../../../chunk-EP674QTM.js";
|
|
9
9
|
import "../../../../chunk-GOIFPE2E.js";
|
|
10
10
|
import "../../../../chunk-X6WC5QBY.js";
|
|
11
11
|
import "../../../../chunk-QLJU7UUI.js";
|
|
@@ -95,11 +95,11 @@ import "../../../../chunk-PN4HVM43.js";
|
|
|
95
95
|
import "../../../../chunk-C3UKR3NT.js";
|
|
96
96
|
import "../../../../chunk-D6KL74KI.js";
|
|
97
97
|
import "../../../../chunk-CN46HGXE.js";
|
|
98
|
-
import "../../../../chunk-
|
|
99
|
-
import "../../../../chunk-
|
|
98
|
+
import "../../../../chunk-RQ2NKSIA.js";
|
|
99
|
+
import "../../../../chunk-TSMF7K37.js";
|
|
100
100
|
import "../../../../chunk-JZRSHDNY.js";
|
|
101
|
-
import "../../../../chunk-
|
|
102
|
-
import "../../../../chunk-
|
|
101
|
+
import "../../../../chunk-GLKUN3DL.js";
|
|
102
|
+
import "../../../../chunk-XSIVM4VO.js";
|
|
103
103
|
import "../../../../chunk-L5CPOEDP.js";
|
|
104
104
|
import "../../../../chunk-FXZUVZON.js";
|
|
105
105
|
import "../../../../chunk-EARWC6PD.js";
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
DataViewsTableBase
|
|
4
|
-
} from "../../../../chunk-
|
|
4
|
+
} from "../../../../chunk-RG3GJTSK.js";
|
|
5
5
|
import "../../../../chunk-YWIVVKCJ.js";
|
|
6
|
-
import "../../../../chunk-
|
|
6
|
+
import "../../../../chunk-F5LDJ52M.js";
|
|
7
7
|
import "../../../../chunk-ZOLAYP2D.js";
|
|
8
|
-
import "../../../../chunk-
|
|
8
|
+
import "../../../../chunk-64BEEFLJ.js";
|
|
9
9
|
import "../../../../chunk-HM6T6EQR.js";
|
|
10
10
|
import "../../../../chunk-NHHWNA5W.js";
|
|
11
|
-
import "../../../../chunk-
|
|
11
|
+
import "../../../../chunk-EP674QTM.js";
|
|
12
12
|
import "../../../../chunk-GOIFPE2E.js";
|
|
13
13
|
import "../../../../chunk-X6WC5QBY.js";
|
|
14
14
|
import "../../../../chunk-QLJU7UUI.js";
|
|
@@ -131,11 +131,11 @@ import "../../../../chunk-AL5E624U.js";
|
|
|
131
131
|
import "../../../../chunk-Z2JH5KW5.js";
|
|
132
132
|
import "../../../../chunk-LV7LSPBF.js";
|
|
133
133
|
import "../../../../chunk-CN46HGXE.js";
|
|
134
|
-
import "../../../../chunk-
|
|
135
|
-
import "../../../../chunk-
|
|
134
|
+
import "../../../../chunk-RQ2NKSIA.js";
|
|
135
|
+
import "../../../../chunk-TSMF7K37.js";
|
|
136
136
|
import "../../../../chunk-JZRSHDNY.js";
|
|
137
|
-
import "../../../../chunk-
|
|
138
|
-
import "../../../../chunk-
|
|
137
|
+
import "../../../../chunk-GLKUN3DL.js";
|
|
138
|
+
import "../../../../chunk-XSIVM4VO.js";
|
|
139
139
|
import "../../../../chunk-L5CPOEDP.js";
|
|
140
140
|
import "../../../../chunk-FXZUVZON.js";
|
|
141
141
|
import "../../../../chunk-EARWC6PD.js";
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
FilterDialog,
|
|
4
4
|
GridFilterPanel
|
|
5
|
-
} from "../../../../chunk-
|
|
5
|
+
} from "../../../../chunk-EP674QTM.js";
|
|
6
6
|
import "../../../../chunk-GWUJIO6Z.js";
|
|
7
7
|
import "../../../../chunk-5WJFCQFN.js";
|
|
8
8
|
import "../../../../chunk-FJ3UZ4RC.js";
|
|
@@ -43,11 +43,11 @@ import "../../../../chunk-PN4HVM43.js";
|
|
|
43
43
|
import "../../../../chunk-C3UKR3NT.js";
|
|
44
44
|
import "../../../../chunk-D6KL74KI.js";
|
|
45
45
|
import "../../../../chunk-CN46HGXE.js";
|
|
46
|
-
import "../../../../chunk-
|
|
47
|
-
import "../../../../chunk-
|
|
46
|
+
import "../../../../chunk-RQ2NKSIA.js";
|
|
47
|
+
import "../../../../chunk-TSMF7K37.js";
|
|
48
48
|
import "../../../../chunk-JZRSHDNY.js";
|
|
49
|
-
import "../../../../chunk-
|
|
50
|
-
import "../../../../chunk-
|
|
49
|
+
import "../../../../chunk-GLKUN3DL.js";
|
|
50
|
+
import "../../../../chunk-XSIVM4VO.js";
|
|
51
51
|
import "../../../../chunk-AKZWDZCZ.js";
|
|
52
52
|
import "../../../../chunk-RGVNXES5.js";
|
|
53
53
|
import "../../../../chunk-GDN2LUTZ.js";
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import {
|
|
3
3
|
GridShell
|
|
4
|
-
} from "../../../../chunk-
|
|
4
|
+
} from "../../../../chunk-64BEEFLJ.js";
|
|
5
5
|
import "../../../../chunk-HM6T6EQR.js";
|
|
6
6
|
import "../../../../chunk-NHHWNA5W.js";
|
|
7
|
-
import "../../../../chunk-
|
|
7
|
+
import "../../../../chunk-EP674QTM.js";
|
|
8
8
|
import "../../../../chunk-GOIFPE2E.js";
|
|
9
9
|
import "../../../../chunk-X6WC5QBY.js";
|
|
10
10
|
import "../../../../chunk-QLJU7UUI.js";
|
|
@@ -88,11 +88,11 @@ import "../../../../chunk-PN4HVM43.js";
|
|
|
88
88
|
import "../../../../chunk-C3UKR3NT.js";
|
|
89
89
|
import "../../../../chunk-D6KL74KI.js";
|
|
90
90
|
import "../../../../chunk-CN46HGXE.js";
|
|
91
|
-
import "../../../../chunk-
|
|
92
|
-
import "../../../../chunk-
|
|
91
|
+
import "../../../../chunk-RQ2NKSIA.js";
|
|
92
|
+
import "../../../../chunk-TSMF7K37.js";
|
|
93
93
|
import "../../../../chunk-JZRSHDNY.js";
|
|
94
|
-
import "../../../../chunk-
|
|
95
|
-
import "../../../../chunk-
|
|
94
|
+
import "../../../../chunk-GLKUN3DL.js";
|
|
95
|
+
import "../../../../chunk-XSIVM4VO.js";
|
|
96
96
|
import "../../../../chunk-L5CPOEDP.js";
|
|
97
97
|
import "../../../../chunk-FXZUVZON.js";
|
|
98
98
|
import "../../../../chunk-EARWC6PD.js";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
StackedModal
|
|
3
|
-
} from "../../../../chunk-
|
|
4
|
-
import "../../../../chunk-
|
|
3
|
+
} from "../../../../chunk-RQ2NKSIA.js";
|
|
4
|
+
import "../../../../chunk-TSMF7K37.js";
|
|
5
5
|
import {
|
|
6
6
|
ModalStackProvider,
|
|
7
7
|
useModalStack
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
StackedModalActions,
|
|
11
11
|
StackedModalContent
|
|
12
|
-
} from "../../../../chunk-
|
|
13
|
-
import "../../../../chunk-
|
|
12
|
+
} from "../../../../chunk-GLKUN3DL.js";
|
|
13
|
+
import "../../../../chunk-XSIVM4VO.js";
|
|
14
14
|
import "../../../../chunk-AKZWDZCZ.js";
|
|
15
15
|
import "../../../../chunk-SSX5ITPM.js";
|
|
16
16
|
import "../../../../chunk-F5H2ZXST.js";
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
modalAriaIds,
|
|
10
10
|
resolveModalContent,
|
|
11
11
|
testId
|
|
12
|
-
} from "../../../../chunk-
|
|
13
|
-
import "../../../../chunk-
|
|
12
|
+
} from "../../../../chunk-GLKUN3DL.js";
|
|
13
|
+
import "../../../../chunk-XSIVM4VO.js";
|
|
14
14
|
import "../../../../chunk-AKZWDZCZ.js";
|
|
15
15
|
import "../../../../chunk-SSX5ITPM.js";
|
|
16
16
|
import "../../../../chunk-F5H2ZXST.js";
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
titleLeftStyles,
|
|
7
7
|
titleRightStyles,
|
|
8
8
|
titleStyles
|
|
9
|
-
} from "../../../../chunk-
|
|
9
|
+
} from "../../../../chunk-XSIVM4VO.js";
|
|
10
10
|
import "../../../../chunk-AKZWDZCZ.js";
|
|
11
11
|
import "../../../../chunk-SSX5ITPM.js";
|
|
12
12
|
import "../../../../chunk-F5H2ZXST.js";
|
|
@@ -68,8 +68,8 @@ import "../../../chunk-LV7LSPBF.js";
|
|
|
68
68
|
import "../../../chunk-CN46HGXE.js";
|
|
69
69
|
import {
|
|
70
70
|
StackedModal
|
|
71
|
-
} from "../../../chunk-
|
|
72
|
-
import "../../../chunk-
|
|
71
|
+
} from "../../../chunk-RQ2NKSIA.js";
|
|
72
|
+
import "../../../chunk-TSMF7K37.js";
|
|
73
73
|
import {
|
|
74
74
|
ModalStackProvider,
|
|
75
75
|
useModalStack
|
|
@@ -77,8 +77,8 @@ import {
|
|
|
77
77
|
import {
|
|
78
78
|
StackedModalActions,
|
|
79
79
|
StackedModalContent
|
|
80
|
-
} from "../../../chunk-
|
|
81
|
-
import "../../../chunk-
|
|
80
|
+
} from "../../../chunk-GLKUN3DL.js";
|
|
81
|
+
import "../../../chunk-XSIVM4VO.js";
|
|
82
82
|
import "../../../chunk-TP3XKS72.js";
|
|
83
83
|
import "../../../chunk-PAO2IWU5.js";
|
|
84
84
|
import "../../../chunk-L7VH6IMR.js";
|
|
@@ -684,8 +684,8 @@ import "../../chunk-LV7LSPBF.js";
|
|
|
684
684
|
import "../../chunk-CN46HGXE.js";
|
|
685
685
|
import {
|
|
686
686
|
StackedModal
|
|
687
|
-
} from "../../chunk-
|
|
688
|
-
import "../../chunk-
|
|
687
|
+
} from "../../chunk-RQ2NKSIA.js";
|
|
688
|
+
import "../../chunk-TSMF7K37.js";
|
|
689
689
|
import {
|
|
690
690
|
ModalStackProvider,
|
|
691
691
|
useModalStack
|
|
@@ -693,8 +693,8 @@ import {
|
|
|
693
693
|
import {
|
|
694
694
|
StackedModalActions,
|
|
695
695
|
StackedModalContent
|
|
696
|
-
} from "../../chunk-
|
|
697
|
-
import "../../chunk-
|
|
696
|
+
} from "../../chunk-GLKUN3DL.js";
|
|
697
|
+
import "../../chunk-XSIVM4VO.js";
|
|
698
698
|
import "../../chunk-L5CPOEDP.js";
|
|
699
699
|
import {
|
|
700
700
|
DataGrid
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
FilterDialog,
|
|
6
6
|
GridFilterPanel
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-EP674QTM.js";
|
|
8
8
|
import {
|
|
9
9
|
DataViewsEmpty
|
|
10
10
|
} from "./chunk-GOIFPE2E.js";
|
|
@@ -240,4 +240,4 @@ function GridShell(props) {
|
|
|
240
240
|
export {
|
|
241
241
|
GridShell
|
|
242
242
|
};
|
|
243
|
-
//# sourceMappingURL=chunk-
|
|
243
|
+
//# sourceMappingURL=chunk-64BEEFLJ.js.map
|
|
@@ -12,10 +12,10 @@ import {
|
|
|
12
12
|
} from "./chunk-7LOCLC24.js";
|
|
13
13
|
import {
|
|
14
14
|
StackedModal
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-RQ2NKSIA.js";
|
|
16
16
|
import {
|
|
17
17
|
StackedModalContent
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-GLKUN3DL.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-
|
|
160
|
+
//# sourceMappingURL=chunk-EP674QTM.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
GridShell
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-64BEEFLJ.js";
|
|
4
4
|
import {
|
|
5
5
|
useDataViewsState
|
|
6
6
|
} from "./chunk-5COIBRIP.js";
|
|
@@ -27,4 +27,4 @@ function DataViewsGrid(props) {
|
|
|
27
27
|
export {
|
|
28
28
|
DataViewsGrid
|
|
29
29
|
};
|
|
30
|
-
//# sourceMappingURL=chunk-
|
|
30
|
+
//# sourceMappingURL=chunk-F5LDJ52M.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
titleLeftStyles,
|
|
5
5
|
titleRightStyles,
|
|
6
6
|
titleStyles
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-XSIVM4VO.js";
|
|
8
8
|
import {
|
|
9
9
|
safeAreaBottom
|
|
10
10
|
} from "./chunk-AKZWDZCZ.js";
|
|
@@ -223,10 +223,11 @@ var ModalPanelContents = ({
|
|
|
223
223
|
content,
|
|
224
224
|
modalActions,
|
|
225
225
|
hasMobileActions,
|
|
226
|
+
hideHeader,
|
|
226
227
|
...header
|
|
227
228
|
}) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
228
229
|
showSkeleton && /* @__PURE__ */ jsx(ModalLoadingOverlay, { loadingText, dataTestId: header.dataTestId }),
|
|
229
|
-
/* @__PURE__ */ jsx(ModalHeader, { ...header }),
|
|
230
|
+
!hideHeader && /* @__PURE__ */ jsx(ModalHeader, { ...header }),
|
|
230
231
|
/* @__PURE__ */ jsx(
|
|
231
232
|
ModalBody,
|
|
232
233
|
{
|
|
@@ -252,4 +253,4 @@ export {
|
|
|
252
253
|
ModalFooter,
|
|
253
254
|
ModalPanelContents
|
|
254
255
|
};
|
|
255
|
-
//# sourceMappingURL=chunk-
|
|
256
|
+
//# sourceMappingURL=chunk-GLKUN3DL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.parts.tsx"],"sourcesContent":["import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport CloseIcon from '@mui/icons-material/Close';\nimport Box from '@mui/material/Box/index.js';\nimport CircularProgress from '@mui/material/CircularProgress/index.js';\nimport DialogActions from '@mui/material/DialogActions/index.js';\nimport DialogContent from '@mui/material/DialogContent/index.js';\nimport DialogTitle from '@mui/material/DialogTitle/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport Skeleton from '@mui/material/Skeleton/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { styled, useTheme } from '@mui/material/styles/index.js';\nimport type { ElementType, FC, ReactNode } from 'react';\nimport React from 'react';\nimport { rem } from '../../../tokens/relative';\nimport { safeAreaBottom } from '../../../utils/viewport';\nimport {\n loadingOverlayStyles,\n modalContentStyles,\n titleLeftStyles,\n titleRightStyles,\n titleStyles,\n} from './StackedModal.styles';\n\n// `component` typed through: the bar is a `div` when it holds a title (`ModalHeader`).\nconst StyledDialogTitle = styled(DialogTitle, {\n shouldForwardProp: (prop) => prop !== 'rtl',\n})<{ rtl?: boolean; component?: ElementType }>(({ theme, rtl }) => titleStyles(theme, rtl));\n\nconst DialogTitleLeft = styled(Box)(({ theme }) => titleLeftStyles(theme));\nconst DialogTitleRight = styled(Box)(({ theme }) => titleRightStyles(theme));\nconst LoadingOverlay = styled(Box)(({ theme }) => loadingOverlayStyles(theme));\n\n/**\n * The padded content wrapper callers put inside a StackedModal. The explicit\n * `typeof DialogContent` annotation keeps its type nameable across package\n * boundaries (TS2742) now that it is re-exported from the barrel.\n */\nexport const StackedModalContent: typeof DialogContent = styled(DialogContent)(({ theme }) =>\n modalContentStyles(theme),\n) as typeof DialogContent;\n\n/** Sub-element test IDs derive from the modal's own, or stay off when it has none. */\nexport const testId = (base: string | undefined, suffix: string): string | undefined =>\n base ? `${base}-${suffix}` : undefined;\n\n/**\n * A wrapper marking the subtree that should render as modal actions — the\n * StackedModal pulls it out of `children` and places it by device.\n */\nexport const StackedModalActions: FC<{ children?: ReactNode }> = ({ children }) => <>{children}</>;\n\n/** Separates the `StackedModalActions` subtree from the rest of the content. */\nconst splitModalChildren = (children: ReactNode): { content: ReactNode; actions: ReactNode } => {\n let actions: ReactNode = null;\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement<{ children?: ReactNode }>(child) && child.type === StackedModalActions) {\n actions = child.props.children;\n }\n });\n\n const content = React.Children.toArray(children).filter(\n (child) => !(React.isValidElement(child) && child.type === StackedModalActions),\n );\n\n return { content, actions };\n};\n\n/**\n * Works out what renders where: a `StackedModalActions` child wins over the\n * `actions` prop, and on phones those actions move out of the header into a\n * pinned bottom bar.\n */\nexport const resolveModalContent = (\n children: ReactNode,\n actions: ReactNode,\n isMobile: boolean,\n): {\n content: ReactNode;\n modalActions: ReactNode;\n headerActions: ReactNode;\n hasMobileActions: boolean;\n} => {\n const { content, actions: childActions } = splitModalChildren(children);\n const modalActions = childActions ?? actions;\n return {\n content,\n modalActions,\n headerActions: isMobile ? null : modalActions,\n hasMobileActions: Boolean(isMobile && modalActions),\n };\n};\n\n/** The panel's own ARIA ids, unless the caller wired it to its own labels. */\nexport const modalAriaIds = (\n modalId: string,\n ariaLabelledBy?: string,\n ariaDescribedBy?: string,\n): { titleId: string; descId: string } => ({\n titleId: ariaLabelledBy || `modal-title-${modalId}`,\n descId: ariaDescribedBy || `modal-desc-${modalId}`,\n});\n\nexport const ModalLoadingOverlay: FC<{ loadingText?: string; dataTestId?: string }> = ({\n loadingText,\n dataTestId,\n}) => {\n const theme = useTheme();\n return (\n <LoadingOverlay data-testid={testId(dataTestId, 'loading-overlay')}>\n <CircularProgress size={rem(theme, 40)} data-testid={testId(dataTestId, 'loading-spinner')} />\n {loadingText && (\n <Typography variant=\"body2\" sx={{ mt: 2 }} data-testid={testId(dataTestId, 'loading-text')}>\n {loadingText}\n </Typography>\n )}\n </LoadingOverlay>\n );\n};\n\ninterface ModalHeaderProps {\n titleId: string;\n navigationTitle?: ReactNode;\n /** Deeper than the first panel, so the leading button goes back instead of closing. */\n canGoBack: boolean;\n onBack: () => void;\n /** The back arrow's accessible name — it carries a glyph only. REQUIRED. */\n backLabel: string;\n onClose: () => void;\n /** Renders the bar without its ✕ — the panel's content owns the dismiss. */\n hideClose?: boolean;\n /** Header actions — desktop only; on phones they move to the footer. */\n headerActions?: ReactNode;\n rtl?: boolean;\n dataTestId?: string;\n}\n\n/**\n * The bar's leading control: back at depth ≥2, otherwise close — and nothing at\n * all when the panel's content carries its own ✕ (`hideClose`).\n */\nconst HeaderLeadingButton: FC<\n Pick<\n ModalHeaderProps,\n 'canGoBack' | 'onBack' | 'backLabel' | 'onClose' | 'hideClose' | 'rtl' | 'dataTestId'\n >\n> = ({ canGoBack, onBack, backLabel, onClose, hideClose, rtl, dataTestId }) => {\n if (canGoBack) {\n return (\n <IconButton\n edge=\"start\"\n color=\"inherit\"\n onClick={onBack}\n aria-label={backLabel}\n size=\"small\"\n sx={{ transform: rtl ? 'rotate(180deg)' : 'none' }}\n data-testid={testId(dataTestId, 'back-button')}\n >\n <ChevronLeftIcon />\n </IconButton>\n );\n }\n if (hideClose) return null;\n return (\n <IconButton\n edge=\"start\"\n color=\"inherit\"\n onClick={onClose}\n aria-label=\"close\"\n size=\"small\"\n data-testid={testId(dataTestId, 'close-button')}\n >\n <CloseIcon />\n </IconButton>\n );\n};\n\nexport const ModalHeader: FC<ModalHeaderProps> = ({\n titleId,\n navigationTitle,\n canGoBack,\n onBack,\n onClose,\n hideClose,\n backLabel,\n headerActions,\n rtl,\n dataTestId,\n}) => (\n // The BAR is not a heading: it holds the ✕ or back button and the header\n // actions. The title inside it is the panel's one heading and carries the id\n // the dialog's `aria-labelledby` names, so the dialog is named by the title\n // alone — not \"close Title Save\" — and a screen reader hears it once.\n //\n // The bar's id is stated, never left to MUI: `DialogTitle` falls back to the\n // Dialog's `aria-labelledby` and would claim the title's id a second time.\n // With NO title the bar is drawn exactly as it always was — MUI's own `h2`,\n // holding the id — so an untitled panel keeps its markup and its name.\n <StyledDialogTitle\n component={navigationTitle ? 'div' : 'h2'}\n id={navigationTitle ? `${titleId}-bar` : titleId}\n rtl={rtl}\n data-testid={testId(dataTestId, 'header')}\n >\n <DialogTitleLeft>\n <HeaderLeadingButton\n canGoBack={canGoBack}\n onBack={onBack}\n backLabel={backLabel}\n onClose={onClose}\n hideClose={hideClose}\n rtl={rtl}\n dataTestId={dataTestId}\n />\n {navigationTitle && (\n <Typography\n id={titleId}\n variant=\"h6\"\n component=\"h2\"\n noWrap\n sx={{ ml: canGoBack || !hideClose ? 1 : 0 }}\n data-testid={testId(dataTestId, 'title')}\n >\n {navigationTitle}\n </Typography>\n )}\n </DialogTitleLeft>\n <DialogTitleRight data-testid={testId(dataTestId, 'header-actions')}>\n {headerActions}\n </DialogTitleRight>\n </StyledDialogTitle>\n);\n\nconst ContentSkeleton: FC = () => {\n const theme = useTheme();\n return (\n <Box sx={{ p: 3 }}>\n <Skeleton variant=\"text\" width=\"60%\" height={rem(theme, 32)} />\n <Skeleton variant=\"text\" width=\"100%\" />\n <Skeleton variant=\"text\" width=\"100%\" />\n <Skeleton variant=\"rectangular\" height={rem(theme, 200)} sx={{ mt: 2 }} />\n </Box>\n );\n};\n\ninterface ModalBodyProps {\n descId: string;\n showSkeleton: boolean;\n /** When there is no action bar, the body is what reaches the bottom of the panel. */\n endsPanel: boolean;\n dataTestId?: string;\n children?: ReactNode;\n}\n\nexport const ModalBody: FC<ModalBodyProps> = ({\n descId,\n showSkeleton,\n endsPanel,\n dataTestId,\n children,\n}) => (\n <Box\n id={descId}\n sx={{\n position: 'relative',\n flex: 1,\n overflow: 'auto',\n // iOS momentum scrolling, and no scroll-chaining to the page behind —\n // without `contain`, an overscroll at the end of the list rubber-bands the\n // whole panel and springs back before the last row can be tapped.\n WebkitOverflowScrolling: 'touch',\n overscrollBehavior: 'contain',\n // The content itself ends the panel when there is no action bar, so it has\n // to clear the home indicator on its own.\n ...(endsPanel ? safeAreaBottom(0) : {}),\n }}\n data-testid={testId(dataTestId, 'content')}\n >\n {showSkeleton ? <ContentSkeleton /> : children}\n </Box>\n);\n\n/** The phone-only pinned action bar; on desktop the actions live in the header. */\nexport const ModalFooter: FC<{ dataTestId?: string; children?: ReactNode }> = ({\n dataTestId,\n children,\n}) => (\n <DialogActions\n sx={{\n borderTop: (theme) => `1px solid ${theme.palette.divider}`,\n padding: 2,\n // Never let the action row sit under the iOS home indicator.\n flexShrink: 0,\n ...safeAreaBottom(16),\n }}\n data-testid={testId(dataTestId, 'footer')}\n >\n {children}\n </DialogActions>\n);\n\ninterface PanelContentsProps extends ModalHeaderProps {\n showSkeleton: boolean;\n loadingText?: string;\n descId: string;\n content: ReactNode;\n /** The resolved actions, already placed in the header or destined for the footer. */\n modalActions: ReactNode;\n hasMobileActions: boolean;\n}\n\n/** Everything inside the sliding panel: the loading veil, header, body and action bar. */\nexport const ModalPanelContents: FC<PanelContentsProps> = ({\n showSkeleton,\n loadingText,\n descId,\n content,\n modalActions,\n hasMobileActions,\n ...header\n}) => (\n <>\n {showSkeleton && (\n <ModalLoadingOverlay loadingText={loadingText} dataTestId={header.dataTestId} />\n )}\n <ModalHeader {...header} />\n <ModalBody\n descId={descId}\n showSkeleton={showSkeleton}\n endsPanel={!hasMobileActions}\n dataTestId={header.dataTestId}\n >\n {content}\n </ModalBody>\n {hasMobileActions && (\n <ModalFooter dataTestId={header.dataTestId}>{modalActions}</ModalFooter>\n )}\n </>\n);\n"],"mappings":";;;;;;;;;;;;;;;AAAA,OAAO,qBAAqB;AAC5B,OAAO,eAAe;AACtB,OAAO,SAAS;AAChB,OAAO,sBAAsB;AAC7B,OAAO,mBAAmB;AAC1B,OAAO,mBAAmB;AAC1B,OAAO,iBAAiB;AACxB,OAAO,gBAAgB;AACvB,OAAO,cAAc;AACrB,OAAO,gBAAgB;AACvB,SAAS,QAAQ,gBAAgB;AAEjC,OAAO,WAAW;AAqCiE,wBA4D/E,YA5D+E;AAzBnF,IAAM,oBAAoB,OAAO,aAAa;AAAA,EAC5C,mBAAmB,CAAC,SAAS,SAAS;AACxC,CAAC,EAA8C,CAAC,EAAE,OAAO,IAAI,MAAM,YAAY,OAAO,GAAG,CAAC;AAE1F,IAAM,kBAAkB,OAAO,GAAG,EAAE,CAAC,EAAE,MAAM,MAAM,gBAAgB,KAAK,CAAC;AACzE,IAAM,mBAAmB,OAAO,GAAG,EAAE,CAAC,EAAE,MAAM,MAAM,iBAAiB,KAAK,CAAC;AAC3E,IAAM,iBAAiB,OAAO,GAAG,EAAE,CAAC,EAAE,MAAM,MAAM,qBAAqB,KAAK,CAAC;AAOtE,IAAM,sBAA4C,OAAO,aAAa;AAAA,EAAE,CAAC,EAAE,MAAM,MACtF,mBAAmB,KAAK;AAC1B;AAGO,IAAM,SAAS,CAAC,MAA0B,WAC/C,OAAO,GAAG,IAAI,IAAI,MAAM,KAAK;AAMxB,IAAM,sBAAoD,CAAC,EAAE,SAAS,MAAM,gCAAG,UAAS;AAG/F,IAAM,qBAAqB,CAAC,aAAoE;AAC9F,MAAI,UAAqB;AAEzB,QAAM,SAAS,QAAQ,UAAU,CAAC,UAAU;AAC1C,QAAI,MAAM,eAAyC,KAAK,KAAK,MAAM,SAAS,qBAAqB;AAC/F,gBAAU,MAAM,MAAM;AAAA,IACxB;AAAA,EACF,CAAC;AAED,QAAM,UAAU,MAAM,SAAS,QAAQ,QAAQ,EAAE;AAAA,IAC/C,CAAC,UAAU,EAAE,MAAM,eAAe,KAAK,KAAK,MAAM,SAAS;AAAA,EAC7D;AAEA,SAAO,EAAE,SAAS,QAAQ;AAC5B;AAOO,IAAM,sBAAsB,CACjC,UACA,SACA,aAMG;AACH,QAAM,EAAE,SAAS,SAAS,aAAa,IAAI,mBAAmB,QAAQ;AACtE,QAAM,eAAe,gBAAgB;AACrC,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,eAAe,WAAW,OAAO;AAAA,IACjC,kBAAkB,QAAQ,YAAY,YAAY;AAAA,EACpD;AACF;AAGO,IAAM,eAAe,CAC1B,SACA,gBACA,qBACyC;AAAA,EACzC,SAAS,kBAAkB,eAAe,OAAO;AAAA,EACjD,QAAQ,mBAAmB,cAAc,OAAO;AAClD;AAEO,IAAM,sBAAyE,CAAC;AAAA,EACrF;AAAA,EACA;AACF,MAAM;AACJ,QAAM,QAAQ,SAAS;AACvB,SACE,qBAAC,kBAAe,eAAa,OAAO,YAAY,iBAAiB,GAC/D;AAAA,wBAAC,oBAAiB,MAAM,IAAI,OAAO,EAAE,GAAG,eAAa,OAAO,YAAY,iBAAiB,GAAG;AAAA,IAC3F,eACC,oBAAC,cAAW,SAAQ,SAAQ,IAAI,EAAE,IAAI,EAAE,GAAG,eAAa,OAAO,YAAY,cAAc,GACtF,uBACH;AAAA,KAEJ;AAEJ;AAuBA,IAAM,sBAKF,CAAC,EAAE,WAAW,QAAQ,WAAW,SAAS,WAAW,KAAK,WAAW,MAAM;AAC7E,MAAI,WAAW;AACb,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,OAAM;AAAA,QACN,SAAS;AAAA,QACT,cAAY;AAAA,QACZ,MAAK;AAAA,QACL,IAAI,EAAE,WAAW,MAAM,mBAAmB,OAAO;AAAA,QACjD,eAAa,OAAO,YAAY,aAAa;AAAA,QAE7C,8BAAC,mBAAgB;AAAA;AAAA,IACnB;AAAA,EAEJ;AACA,MAAI,UAAW,QAAO;AACtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,OAAM;AAAA,MACN,SAAS;AAAA,MACT,cAAW;AAAA,MACX,MAAK;AAAA,MACL,eAAa,OAAO,YAAY,cAAc;AAAA,MAE9C,8BAAC,aAAU;AAAA;AAAA,EACb;AAEJ;AAEO,IAAM,cAAoC,CAAC;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,kBAAkB,QAAQ;AAAA,MACrC,IAAI,kBAAkB,GAAG,OAAO,SAAS;AAAA,MACzC;AAAA,MACA,eAAa,OAAO,YAAY,QAAQ;AAAA,MAExC;AAAA,6BAAC,mBACC;AAAA;AAAA,YAAC;AAAA;AAAA,cACC;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA,cACA;AAAA;AAAA,UACF;AAAA,UACC,mBACC;AAAA,YAAC;AAAA;AAAA,cACC,IAAI;AAAA,cACJ,SAAQ;AAAA,cACR,WAAU;AAAA,cACV,QAAM;AAAA,cACN,IAAI,EAAE,IAAI,aAAa,CAAC,YAAY,IAAI,EAAE;AAAA,cAC1C,eAAa,OAAO,YAAY,OAAO;AAAA,cAEtC;AAAA;AAAA,UACH;AAAA,WAEJ;AAAA,QACA,oBAAC,oBAAiB,eAAa,OAAO,YAAY,gBAAgB,GAC/D,yBACH;AAAA;AAAA;AAAA,EACF;AAAA;AAGF,IAAM,kBAAsB,MAAM;AAChC,QAAM,QAAQ,SAAS;AACvB,SACE,qBAAC,OAAI,IAAI,EAAE,GAAG,EAAE,GACd;AAAA,wBAAC,YAAS,SAAQ,QAAO,OAAM,OAAM,QAAQ,IAAI,OAAO,EAAE,GAAG;AAAA,IAC7D,oBAAC,YAAS,SAAQ,QAAO,OAAM,QAAO;AAAA,IACtC,oBAAC,YAAS,SAAQ,QAAO,OAAM,QAAO;AAAA,IACtC,oBAAC,YAAS,SAAQ,eAAc,QAAQ,IAAI,OAAO,GAAG,GAAG,IAAI,EAAE,IAAI,EAAE,GAAG;AAAA,KAC1E;AAEJ;AAWO,IAAM,YAAgC,CAAC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA;AAAA,IACC,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,UAAU;AAAA,MACV,MAAM;AAAA,MACN,UAAU;AAAA;AAAA;AAAA;AAAA,MAIV,yBAAyB;AAAA,MACzB,oBAAoB;AAAA;AAAA;AAAA,MAGpB,GAAI,YAAY,eAAe,CAAC,IAAI,CAAC;AAAA,IACvC;AAAA,IACA,eAAa,OAAO,YAAY,SAAS;AAAA,IAExC,yBAAe,oBAAC,mBAAgB,IAAK;AAAA;AACxC;AAIK,IAAM,cAAiE,CAAC;AAAA,EAC7E;AAAA,EACA;AACF,MACE;AAAA,EAAC;AAAA;AAAA,IACC,IAAI;AAAA,MACF,WAAW,CAAC,UAAU,aAAa,MAAM,QAAQ,OAAO;AAAA,MACxD,SAAS;AAAA;AAAA,MAET,YAAY;AAAA,MACZ,GAAG,eAAe,EAAE;AAAA,IACtB;AAAA,IACA,eAAa,OAAO,YAAY,QAAQ;AAAA,IAEvC;AAAA;AACH;AAcK,IAAM,qBAA6C,CAAC;AAAA,EACzD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MACE,iCACG;AAAA,kBACC,oBAAC,uBAAoB,aAA0B,YAAY,OAAO,YAAY;AAAA,EAEhF,oBAAC,eAAa,GAAG,QAAQ;AAAA,EACzB;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA,WAAW,CAAC;AAAA,MACZ,YAAY,OAAO;AAAA,MAElB;AAAA;AAAA,EACH;AAAA,EACC,oBACC,oBAAC,eAAY,YAAY,OAAO,YAAa,wBAAa;AAAA,GAE9D;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.parts.tsx"],"sourcesContent":["import ChevronLeftIcon from '@mui/icons-material/ChevronLeft';\nimport CloseIcon from '@mui/icons-material/Close';\nimport Box from '@mui/material/Box/index.js';\nimport CircularProgress from '@mui/material/CircularProgress/index.js';\nimport DialogActions from '@mui/material/DialogActions/index.js';\nimport DialogContent from '@mui/material/DialogContent/index.js';\nimport DialogTitle from '@mui/material/DialogTitle/index.js';\nimport IconButton from '@mui/material/IconButton/index.js';\nimport Skeleton from '@mui/material/Skeleton/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport { styled, useTheme } from '@mui/material/styles/index.js';\nimport type { ElementType, FC, ReactNode } from 'react';\nimport React from 'react';\nimport { rem } from '../../../tokens/relative';\nimport { safeAreaBottom } from '../../../utils/viewport';\nimport {\n loadingOverlayStyles,\n modalContentStyles,\n titleLeftStyles,\n titleRightStyles,\n titleStyles,\n} from './StackedModal.styles';\n\n// `component` typed through: the bar is a `div` when it holds a title (`ModalHeader`).\nconst StyledDialogTitle = styled(DialogTitle, {\n shouldForwardProp: (prop) => prop !== 'rtl',\n})<{ rtl?: boolean; component?: ElementType }>(({ theme, rtl }) => titleStyles(theme, rtl));\n\nconst DialogTitleLeft = styled(Box)(({ theme }) => titleLeftStyles(theme));\nconst DialogTitleRight = styled(Box)(({ theme }) => titleRightStyles(theme));\nconst LoadingOverlay = styled(Box)(({ theme }) => loadingOverlayStyles(theme));\n\n/**\n * The padded content wrapper callers put inside a StackedModal. The explicit\n * `typeof DialogContent` annotation keeps its type nameable across package\n * boundaries (TS2742) now that it is re-exported from the barrel.\n */\nexport const StackedModalContent: typeof DialogContent = styled(DialogContent)(({ theme }) =>\n modalContentStyles(theme),\n) as typeof DialogContent;\n\n/** Sub-element test IDs derive from the modal's own, or stay off when it has none. */\nexport const testId = (base: string | undefined, suffix: string): string | undefined =>\n base ? `${base}-${suffix}` : undefined;\n\n/**\n * A wrapper marking the subtree that should render as modal actions — the\n * StackedModal pulls it out of `children` and places it by device.\n */\nexport const StackedModalActions: FC<{ children?: ReactNode }> = ({ children }) => <>{children}</>;\n\n/** Separates the `StackedModalActions` subtree from the rest of the content. */\nconst splitModalChildren = (children: ReactNode): { content: ReactNode; actions: ReactNode } => {\n let actions: ReactNode = null;\n\n React.Children.forEach(children, (child) => {\n if (React.isValidElement<{ children?: ReactNode }>(child) && child.type === StackedModalActions) {\n actions = child.props.children;\n }\n });\n\n const content = React.Children.toArray(children).filter(\n (child) => !(React.isValidElement(child) && child.type === StackedModalActions),\n );\n\n return { content, actions };\n};\n\n/**\n * Works out what renders where: a `StackedModalActions` child wins over the\n * `actions` prop, and on phones those actions move out of the header into a\n * pinned bottom bar.\n */\nexport const resolveModalContent = (\n children: ReactNode,\n actions: ReactNode,\n isMobile: boolean,\n): {\n content: ReactNode;\n modalActions: ReactNode;\n headerActions: ReactNode;\n hasMobileActions: boolean;\n} => {\n const { content, actions: childActions } = splitModalChildren(children);\n const modalActions = childActions ?? actions;\n return {\n content,\n modalActions,\n headerActions: isMobile ? null : modalActions,\n hasMobileActions: Boolean(isMobile && modalActions),\n };\n};\n\n/** The panel's own ARIA ids, unless the caller wired it to its own labels. */\nexport const modalAriaIds = (\n modalId: string,\n ariaLabelledBy?: string,\n ariaDescribedBy?: string,\n): { titleId: string; descId: string } => ({\n titleId: ariaLabelledBy || `modal-title-${modalId}`,\n descId: ariaDescribedBy || `modal-desc-${modalId}`,\n});\n\nexport const ModalLoadingOverlay: FC<{ loadingText?: string; dataTestId?: string }> = ({\n loadingText,\n dataTestId,\n}) => {\n const theme = useTheme();\n return (\n <LoadingOverlay data-testid={testId(dataTestId, 'loading-overlay')}>\n <CircularProgress size={rem(theme, 40)} data-testid={testId(dataTestId, 'loading-spinner')} />\n {loadingText && (\n <Typography variant=\"body2\" sx={{ mt: 2 }} data-testid={testId(dataTestId, 'loading-text')}>\n {loadingText}\n </Typography>\n )}\n </LoadingOverlay>\n );\n};\n\ninterface ModalHeaderProps {\n titleId: string;\n navigationTitle?: ReactNode;\n /** Deeper than the first panel, so the leading button goes back instead of closing. */\n canGoBack: boolean;\n onBack: () => void;\n /** The back arrow's accessible name — it carries a glyph only. REQUIRED. */\n backLabel: string;\n onClose: () => void;\n /** Renders the bar without its ✕ — the panel's content owns the dismiss. */\n hideClose?: boolean;\n /** Header actions — desktop only; on phones they move to the footer. */\n headerActions?: ReactNode;\n rtl?: boolean;\n dataTestId?: string;\n}\n\n/**\n * The bar's leading control: back at depth ≥2, otherwise close — and nothing at\n * all when the panel's content carries its own ✕ (`hideClose`).\n */\nconst HeaderLeadingButton: FC<\n Pick<\n ModalHeaderProps,\n 'canGoBack' | 'onBack' | 'backLabel' | 'onClose' | 'hideClose' | 'rtl' | 'dataTestId'\n >\n> = ({ canGoBack, onBack, backLabel, onClose, hideClose, rtl, dataTestId }) => {\n if (canGoBack) {\n return (\n <IconButton\n edge=\"start\"\n color=\"inherit\"\n onClick={onBack}\n aria-label={backLabel}\n size=\"small\"\n sx={{ transform: rtl ? 'rotate(180deg)' : 'none' }}\n data-testid={testId(dataTestId, 'back-button')}\n >\n <ChevronLeftIcon />\n </IconButton>\n );\n }\n if (hideClose) return null;\n return (\n <IconButton\n edge=\"start\"\n color=\"inherit\"\n onClick={onClose}\n aria-label=\"close\"\n size=\"small\"\n data-testid={testId(dataTestId, 'close-button')}\n >\n <CloseIcon />\n </IconButton>\n );\n};\n\nexport const ModalHeader: FC<ModalHeaderProps> = ({\n titleId,\n navigationTitle,\n canGoBack,\n onBack,\n onClose,\n hideClose,\n backLabel,\n headerActions,\n rtl,\n dataTestId,\n}) => (\n // The BAR is not a heading: it holds the ✕ or back button and the header\n // actions. The title inside it is the panel's one heading and carries the id\n // the dialog's `aria-labelledby` names, so the dialog is named by the title\n // alone — not \"close Title Save\" — and a screen reader hears it once.\n //\n // The bar's id is stated, never left to MUI: `DialogTitle` falls back to the\n // Dialog's `aria-labelledby` and would claim the title's id a second time.\n // With NO title the bar is drawn exactly as it always was — MUI's own `h2`,\n // holding the id — so an untitled panel keeps its markup and its name.\n <StyledDialogTitle\n component={navigationTitle ? 'div' : 'h2'}\n id={navigationTitle ? `${titleId}-bar` : titleId}\n rtl={rtl}\n data-testid={testId(dataTestId, 'header')}\n >\n <DialogTitleLeft>\n <HeaderLeadingButton\n canGoBack={canGoBack}\n onBack={onBack}\n backLabel={backLabel}\n onClose={onClose}\n hideClose={hideClose}\n rtl={rtl}\n dataTestId={dataTestId}\n />\n {navigationTitle && (\n <Typography\n id={titleId}\n variant=\"h6\"\n component=\"h2\"\n noWrap\n sx={{ ml: canGoBack || !hideClose ? 1 : 0 }}\n data-testid={testId(dataTestId, 'title')}\n >\n {navigationTitle}\n </Typography>\n )}\n </DialogTitleLeft>\n <DialogTitleRight data-testid={testId(dataTestId, 'header-actions')}>\n {headerActions}\n </DialogTitleRight>\n </StyledDialogTitle>\n);\n\nconst ContentSkeleton: FC = () => {\n const theme = useTheme();\n return (\n <Box sx={{ p: 3 }}>\n <Skeleton variant=\"text\" width=\"60%\" height={rem(theme, 32)} />\n <Skeleton variant=\"text\" width=\"100%\" />\n <Skeleton variant=\"text\" width=\"100%\" />\n <Skeleton variant=\"rectangular\" height={rem(theme, 200)} sx={{ mt: 2 }} />\n </Box>\n );\n};\n\ninterface ModalBodyProps {\n descId: string;\n showSkeleton: boolean;\n /** When there is no action bar, the body is what reaches the bottom of the panel. */\n endsPanel: boolean;\n dataTestId?: string;\n children?: ReactNode;\n}\n\nexport const ModalBody: FC<ModalBodyProps> = ({\n descId,\n showSkeleton,\n endsPanel,\n dataTestId,\n children,\n}) => (\n <Box\n id={descId}\n sx={{\n position: 'relative',\n flex: 1,\n overflow: 'auto',\n // iOS momentum scrolling, and no scroll-chaining to the page behind —\n // without `contain`, an overscroll at the end of the list rubber-bands the\n // whole panel and springs back before the last row can be tapped.\n WebkitOverflowScrolling: 'touch',\n overscrollBehavior: 'contain',\n // The content itself ends the panel when there is no action bar, so it has\n // to clear the home indicator on its own.\n ...(endsPanel ? safeAreaBottom(0) : {}),\n }}\n data-testid={testId(dataTestId, 'content')}\n >\n {showSkeleton ? <ContentSkeleton /> : children}\n </Box>\n);\n\n/** The phone-only pinned action bar; on desktop the actions live in the header. */\nexport const ModalFooter: FC<{ dataTestId?: string; children?: ReactNode }> = ({\n dataTestId,\n children,\n}) => (\n <DialogActions\n sx={{\n borderTop: (theme) => `1px solid ${theme.palette.divider}`,\n padding: 2,\n // Never let the action row sit under the iOS home indicator.\n flexShrink: 0,\n ...safeAreaBottom(16),\n }}\n data-testid={testId(dataTestId, 'footer')}\n >\n {children}\n </DialogActions>\n);\n\ninterface PanelContentsProps extends ModalHeaderProps {\n /** Draw no bar — already resolved: `hideHeader` on the ROOT panel only. */\n hideHeader?: boolean;\n showSkeleton: boolean;\n loadingText?: string;\n descId: string;\n content: ReactNode;\n /** The resolved actions, already placed in the header or destined for the footer. */\n modalActions: ReactNode;\n hasMobileActions: boolean;\n}\n\n/** Everything inside the sliding panel: the loading veil, header, body and action bar. */\nexport const ModalPanelContents: FC<PanelContentsProps> = ({\n showSkeleton,\n loadingText,\n descId,\n content,\n modalActions,\n hasMobileActions,\n hideHeader,\n ...header\n}) => (\n <>\n {showSkeleton && (\n <ModalLoadingOverlay loadingText={loadingText} dataTestId={header.dataTestId} />\n )}\n {!hideHeader && <ModalHeader {...header} />}\n <ModalBody\n descId={descId}\n showSkeleton={showSkeleton}\n endsPanel={!hasMobileActions}\n dataTestId={header.dataTestId}\n >\n {content}\n </ModalBody>\n {hasMobileActions && (\n <ModalFooter dataTestId={header.dataTestId}>{modalActions}</ModalFooter>\n )}\n </>\n);\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-YWIVVKCJ.js";
|
|
4
4
|
import {
|
|
5
5
|
DataViewsGrid
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-F5LDJ52M.js";
|
|
7
7
|
import {
|
|
8
8
|
viewStateKey
|
|
9
9
|
} from "./chunk-ZOLAYP2D.js";
|
|
@@ -166,4 +166,4 @@ function renderViewDialogs(ctl, fields, columns, views, testIdPrefix, onSaved) {
|
|
|
166
166
|
export {
|
|
167
167
|
DataViewsTableBase
|
|
168
168
|
};
|
|
169
|
-
//# sourceMappingURL=chunk-
|
|
169
|
+
//# sourceMappingURL=chunk-RG3GJTSK.js.map
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import {
|
|
2
2
|
usePanelChrome
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TSMF7K37.js";
|
|
4
4
|
import {
|
|
5
5
|
ModalPanelContents,
|
|
6
6
|
modalAriaIds,
|
|
7
7
|
resolveModalContent
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-GLKUN3DL.js";
|
|
9
9
|
import {
|
|
10
10
|
STYLE_ONLY_PROPS,
|
|
11
11
|
dialogRootStyles
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-XSIVM4VO.js";
|
|
13
13
|
|
|
14
14
|
// src/components/feedback/StackedModal/StackedModal.tsx
|
|
15
15
|
import Dialog from "@mui/material/Dialog/index.js";
|
|
16
16
|
import Slide from "@mui/material/Slide/index.js";
|
|
17
17
|
import { styled } from "@mui/material/styles/index.js";
|
|
18
|
-
import { forwardRef, useId } from "react";
|
|
18
|
+
import { forwardRef, useEffect, useId } from "react";
|
|
19
19
|
import { jsx } from "react/jsx-runtime";
|
|
20
20
|
var StyledDialog = styled(Dialog, {
|
|
21
21
|
shouldForwardProp: (prop) => !STYLE_ONLY_PROPS.includes(prop)
|
|
@@ -49,6 +49,16 @@ var withDefaults = (props) => {
|
|
|
49
49
|
}
|
|
50
50
|
return resolved;
|
|
51
51
|
};
|
|
52
|
+
var useUnnamedDialogWarning = (unnamed) => {
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
const development = typeof process !== "undefined" && process.env?.NODE_ENV !== "production";
|
|
55
|
+
if (unnamed && development) {
|
|
56
|
+
console.warn(
|
|
57
|
+
"StackedModal: `hideHeader` without `aria-labelledby` leaves the dialog unnamed. Point `aria-labelledby` at your content header's title."
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}, [unnamed]);
|
|
61
|
+
};
|
|
52
62
|
var StackedModalPanel = (props) => {
|
|
53
63
|
const {
|
|
54
64
|
open,
|
|
@@ -57,6 +67,7 @@ var StackedModalPanel = (props) => {
|
|
|
57
67
|
navigationTitle,
|
|
58
68
|
backLabel,
|
|
59
69
|
hideClose,
|
|
70
|
+
hideHeader,
|
|
60
71
|
children,
|
|
61
72
|
actions,
|
|
62
73
|
modalId,
|
|
@@ -84,6 +95,7 @@ var StackedModalPanel = (props) => {
|
|
|
84
95
|
zIndex,
|
|
85
96
|
isMobile,
|
|
86
97
|
canGoBack,
|
|
98
|
+
isRoot,
|
|
87
99
|
handleBack,
|
|
88
100
|
handleClose
|
|
89
101
|
} = usePanelChrome({
|
|
@@ -102,6 +114,7 @@ var StackedModalPanel = (props) => {
|
|
|
102
114
|
isMobile
|
|
103
115
|
);
|
|
104
116
|
const { titleId, descId } = modalAriaIds(modalId, ariaLabelledBy, ariaDescribedBy);
|
|
117
|
+
useUnnamedDialogWarning(Boolean(hideHeader) && !ariaLabelledBy);
|
|
105
118
|
return /* @__PURE__ */ jsx(
|
|
106
119
|
StyledDialog,
|
|
107
120
|
{
|
|
@@ -135,6 +148,7 @@ var StackedModalPanel = (props) => {
|
|
|
135
148
|
descId,
|
|
136
149
|
navigationTitle,
|
|
137
150
|
hideClose,
|
|
151
|
+
hideHeader: Boolean(hideHeader) && isRoot,
|
|
138
152
|
canGoBack,
|
|
139
153
|
onBack: handleBack,
|
|
140
154
|
onClose,
|
|
@@ -158,4 +172,4 @@ var StackedModal = (props) => {
|
|
|
158
172
|
export {
|
|
159
173
|
StackedModal
|
|
160
174
|
};
|
|
161
|
-
//# sourceMappingURL=chunk-
|
|
175
|
+
//# sourceMappingURL=chunk-RQ2NKSIA.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, useEffect, 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\n/**\n * `hideHeader` removes the bar that names the dialog; without an\n * `aria-labelledby` of the caller's own, the dialog has no accessible name.\n */\nconst useUnnamedDialogWarning = (unnamed: boolean): void => {\n useEffect(() => {\n const development = typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';\n if (unnamed && development) {\n // eslint-disable-next-line no-console -- a config warning has no other channel.\n console.warn(\n 'StackedModal: `hideHeader` without `aria-labelledby` leaves the dialog unnamed. ' +\n \"Point `aria-labelledby` at your content header's title.\",\n );\n }\n }, [unnamed]);\n};\n\nconst StackedModalPanel: FC<ResolvedProps> = (props) => {\n const {\n open, onClose, glass, navigationTitle, backLabel, hideClose, hideHeader, 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, isRoot,\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 useUnnamedDialogWarning(Boolean(hideHeader) && !ariaLabelledBy);\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 hideHeader={Boolean(hideHeader) && isRoot}\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"]}
|
|
@@ -72,7 +72,7 @@ var useStackRegistration = (open, modalId) => {
|
|
|
72
72
|
var usePanelChrome = (options) => {
|
|
73
73
|
const { open, modalId, loading, closeOnEsc, closeOnClickOutside, disableFocusTrap, onClose } = options;
|
|
74
74
|
const dialogRef = useRef(null);
|
|
75
|
-
const { currentDepth } = useModalStack();
|
|
75
|
+
const { currentDepth, stack } = useModalStack();
|
|
76
76
|
const { modalRole, isAnimating } = useModalRole(Boolean(open), modalId);
|
|
77
77
|
const showSkeleton = useSkeleton(Boolean(loading));
|
|
78
78
|
const zIndex = usePanelZIndex(modalId, FALLBACK_Z_INDEX);
|
|
@@ -80,6 +80,7 @@ var usePanelChrome = (options) => {
|
|
|
80
80
|
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
|
|
81
81
|
const isPrimary = modalRole === "primary";
|
|
82
82
|
const canGoBack = currentDepth > 1;
|
|
83
|
+
const isRoot = (stack[0]?.id ?? modalId) === modalId;
|
|
83
84
|
useFocusTrap(dialogRef, Boolean(open) && isPrimary, disableFocusTrap);
|
|
84
85
|
useEscapeToClose(Boolean(open && closeOnEsc) && isPrimary, onClose);
|
|
85
86
|
const { handleBack, handleClose } = useCloseHandlers({
|
|
@@ -97,6 +98,7 @@ var usePanelChrome = (options) => {
|
|
|
97
98
|
zIndex,
|
|
98
99
|
isMobile,
|
|
99
100
|
canGoBack,
|
|
101
|
+
isRoot,
|
|
100
102
|
handleBack,
|
|
101
103
|
handleClose
|
|
102
104
|
};
|
|
@@ -142,4 +144,4 @@ var useModalRole = (open, modalId) => {
|
|
|
142
144
|
export {
|
|
143
145
|
usePanelChrome
|
|
144
146
|
};
|
|
145
|
-
//# sourceMappingURL=chunk-
|
|
147
|
+
//# sourceMappingURL=chunk-TSMF7K37.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.hooks.ts"],"sourcesContent":["import { useTheme } from '@mui/material/styles/index.js';\nimport useMediaQuery from '@mui/material/useMediaQuery/index.js';\nimport type { RefObject } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { useModalStack } from './modal-stack';\nimport type { ModalPanelRole } from './StackedModal.types';\n\nconst FOCUSABLE = 'a[href], button, textarea, input, select, [tabindex]:not([tabindex=\"-1\"])';\n/** MUI Dialog's own default, used when the modal isn't registered in the stack yet. */\nconst FALLBACK_Z_INDEX = 1300;\n/** Matches the panel's slide duration, so role swaps animate rather than jump. */\nconst ROLE_TRANSITION_MS = 300;\n\n/** Keeps Tab cycling inside the open panel instead of escaping to the page behind. */\nconst useFocusTrap = (\n ref: RefObject<HTMLElement | null>,\n isActive: boolean,\n disabled?: boolean,\n): void => {\n useEffect(() => {\n if (!isActive || disabled || !ref.current) return;\n\n const element = ref.current;\n const focusable = element.querySelectorAll(FOCUSABLE);\n const first = focusable[0] as HTMLElement | undefined;\n const last = focusable[focusable.length - 1] as HTMLElement | undefined;\n\n window.setTimeout(() => first?.focus(), 100);\n\n const handleTabKey = (e: globalThis.KeyboardEvent): void => {\n if (e.key !== 'Tab') return;\n const atEdge = e.shiftKey ? first : last;\n if (document.activeElement !== atEdge) return;\n e.preventDefault();\n (e.shiftKey ? last : first)?.focus();\n };\n\n element.addEventListener('keydown', handleTabKey);\n return () => element.removeEventListener('keydown', handleTabKey);\n }, [ref, isActive, disabled]);\n};\n\n/** Closes the panel on Escape — only while it is the top one. */\nconst useEscapeToClose = (active: boolean, onClose: () => void): void => {\n useEffect(() => {\n if (!active) return;\n\n const handleEsc = (e: globalThis.KeyboardEvent): void => {\n if (e.key !== 'Escape') return;\n e.preventDefault();\n onClose();\n };\n\n window.addEventListener('keydown', handleEsc);\n return () => window.removeEventListener('keydown', handleEsc);\n }, [active, onClose]);\n};\n\n/** Holds the skeleton a beat past `loading` so the swap to content isn't a flash. */\nconst useSkeleton = (loading: boolean): boolean => {\n const [showSkeleton, setShowSkeleton] = useState(loading);\n\n useEffect(() => {\n if (loading) {\n setShowSkeleton(true);\n return;\n }\n const timer = window.setTimeout(() => setShowSkeleton(false), 200);\n return () => window.clearTimeout(timer);\n }, [loading]);\n\n return showSkeleton;\n};\n\n/** Registers the modal in the stack while open, and unregisters it after it slides out. */\nconst useStackRegistration = (open: boolean, modalId: string): void => {\n const { pushModal, popModal, isModalInStack } = useModalStack();\n const hasRegisteredRef = useRef(false);\n\n useEffect(() => {\n if (open && !hasRegisteredRef.current) {\n pushModal(modalId);\n hasRegisteredRef.current = true;\n } else if (!open) {\n hasRegisteredRef.current = false;\n }\n }, [open, modalId, pushModal]);\n\n useEffect(() => {\n if (open || !isModalInStack(modalId)) return;\n const timer = window.setTimeout(() => popModal(modalId), ROLE_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [open, modalId, popModal, isModalInStack]);\n};\n\ninterface PanelChromeOptions {\n open?: boolean;\n modalId: string;\n loading?: boolean;\n closeOnEsc?: boolean;\n closeOnClickOutside?: boolean;\n disableFocusTrap?: boolean;\n onClose: () => void;\n}\n\ninterface PanelChrome {\n dialogRef: RefObject<HTMLDivElement | null>;\n modalRole: ModalPanelRole;\n isAnimating: boolean;\n showSkeleton: boolean;\n zIndex: number;\n isMobile: boolean;\n canGoBack: boolean;\n /**\n * This panel is the bottom of the stack. Read from ITS position, not from the\n * depth: once a child opens, the depth says \"can go back\" for every panel,\n * the receding root included.\n */\n isRoot: boolean;\n handleBack: () => void;\n handleClose: (event: object, reason: 'backdropClick' | 'escapeKeyDown') => void;\n}\n\n/**\n * Everything the panel needs to render itself: its place in the stack, the\n * viewport it is on, and the handlers that dismiss it. Bundled into one hook so\n * the component stays a description of the markup.\n */\nexport const usePanelChrome = (options: PanelChromeOptions): PanelChrome => {\n const { open, modalId, loading, closeOnEsc, closeOnClickOutside, disableFocusTrap, onClose } =\n options;\n\n const dialogRef = useRef<HTMLDivElement>(null);\n const { currentDepth, stack } = useModalStack();\n const { modalRole, isAnimating } = useModalRole(Boolean(open), modalId);\n const showSkeleton = useSkeleton(Boolean(loading));\n const zIndex = usePanelZIndex(modalId, FALLBACK_Z_INDEX);\n\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('sm'));\n const isPrimary = modalRole === 'primary';\n const canGoBack = currentDepth > 1;\n // Not yet pushed (its first render) and something already below it: NOT the\n // root — so a child never renders a frame without its back arrow.\n const isRoot = (stack[0]?.id ?? modalId) === modalId;\n\n useFocusTrap(dialogRef, Boolean(open) && isPrimary, disableFocusTrap);\n useEscapeToClose(Boolean(open && closeOnEsc) && isPrimary, onClose);\n\n const { handleBack, handleClose } = useCloseHandlers({\n isPrimary,\n closeOnClickOutside,\n closeOnEsc,\n canGoBack,\n onClose,\n });\n\n return {\n dialogRef,\n modalRole,\n isAnimating,\n showSkeleton,\n zIndex,\n isMobile,\n canGoBack,\n isRoot,\n handleBack,\n handleClose,\n };\n};\n\ninterface CloseHandlerOptions {\n /** Only the top panel responds to a backdrop click or Escape. */\n isPrimary: boolean;\n closeOnClickOutside?: boolean;\n closeOnEsc?: boolean;\n /** Deeper than one panel, so the leading control goes back rather than closing. */\n canGoBack: boolean;\n onClose: () => void;\n}\n\n/** The panel's dismissal handlers, honouring which gestures the caller allows. */\nconst useCloseHandlers = ({\n isPrimary,\n closeOnClickOutside,\n closeOnEsc,\n canGoBack,\n onClose,\n}: CloseHandlerOptions): {\n handleBack: () => void;\n handleClose: (event: object, reason: 'backdropClick' | 'escapeKeyDown') => void;\n} => ({\n handleBack: () => {\n if (canGoBack) onClose();\n },\n handleClose: (_event, reason) => {\n if (!isPrimary) return;\n if (reason === 'backdropClick' && !closeOnClickOutside) return;\n if (reason === 'escapeKeyDown' && !closeOnEsc) return;\n onClose();\n },\n});\n\n/** The z-index this panel was assigned when it joined the stack. */\nconst usePanelZIndex = (modalId: string, fallback: number): number => {\n const { stack } = useModalStack();\n return stack.find((m) => m.id === modalId)?.zIndex ?? fallback;\n};\n\n/**\n * This modal's role in the stack, plus whether it is mid-transition between two\n * roles (which drives the expand/contract animation).\n */\nconst useModalRole = (\n open: boolean,\n modalId: string,\n): { modalRole: ModalPanelRole; isAnimating: boolean } => {\n const { stack } = useModalStack();\n const [modalRole, setModalRole] = useState<ModalPanelRole>('primary');\n const [isAnimating, setIsAnimating] = useState(false);\n\n useStackRegistration(open, modalId);\n\n useEffect(() => {\n if (!open) return;\n\n const newRole = stack.find((m) => m.id === modalId)?.role;\n if (!newRole || newRole === modalRole) return;\n\n setIsAnimating(true);\n setModalRole(newRole);\n const timer = window.setTimeout(() => setIsAnimating(false), ROLE_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [stack, modalId, open, modalRole]);\n\n return { modalRole, isAnimating };\n};\n"],"mappings":";;;;;AAAA,SAAS,gBAAgB;AACzB,OAAO,mBAAmB;AAE1B,SAAS,WAAW,QAAQ,gBAAgB;AAI5C,IAAM,YAAY;AAElB,IAAM,mBAAmB;AAEzB,IAAM,qBAAqB;AAG3B,IAAM,eAAe,CACnB,KACA,UACA,aACS;AACT,YAAU,MAAM;AACd,QAAI,CAAC,YAAY,YAAY,CAAC,IAAI,QAAS;AAE3C,UAAM,UAAU,IAAI;AACpB,UAAM,YAAY,QAAQ,iBAAiB,SAAS;AACpD,UAAM,QAAQ,UAAU,CAAC;AACzB,UAAM,OAAO,UAAU,UAAU,SAAS,CAAC;AAE3C,WAAO,WAAW,MAAM,OAAO,MAAM,GAAG,GAAG;AAE3C,UAAM,eAAe,CAAC,MAAsC;AAC1D,UAAI,EAAE,QAAQ,MAAO;AACrB,YAAM,SAAS,EAAE,WAAW,QAAQ;AACpC,UAAI,SAAS,kBAAkB,OAAQ;AACvC,QAAE,eAAe;AACjB,OAAC,EAAE,WAAW,OAAO,QAAQ,MAAM;AAAA,IACrC;AAEA,YAAQ,iBAAiB,WAAW,YAAY;AAChD,WAAO,MAAM,QAAQ,oBAAoB,WAAW,YAAY;AAAA,EAClE,GAAG,CAAC,KAAK,UAAU,QAAQ,CAAC;AAC9B;AAGA,IAAM,mBAAmB,CAAC,QAAiB,YAA8B;AACvE,YAAU,MAAM;AACd,QAAI,CAAC,OAAQ;AAEb,UAAM,YAAY,CAAC,MAAsC;AACvD,UAAI,EAAE,QAAQ,SAAU;AACxB,QAAE,eAAe;AACjB,cAAQ;AAAA,IACV;AAEA,WAAO,iBAAiB,WAAW,SAAS;AAC5C,WAAO,MAAM,OAAO,oBAAoB,WAAW,SAAS;AAAA,EAC9D,GAAG,CAAC,QAAQ,OAAO,CAAC;AACtB;AAGA,IAAM,cAAc,CAAC,YAA8B;AACjD,QAAM,CAAC,cAAc,eAAe,IAAI,SAAS,OAAO;AAExD,YAAU,MAAM;AACd,QAAI,SAAS;AACX,sBAAgB,IAAI;AACpB;AAAA,IACF;AACA,UAAM,QAAQ,OAAO,WAAW,MAAM,gBAAgB,KAAK,GAAG,GAAG;AACjE,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,OAAO,CAAC;AAEZ,SAAO;AACT;AAGA,IAAM,uBAAuB,CAAC,MAAe,YAA0B;AACrE,QAAM,EAAE,WAAW,UAAU,eAAe,IAAI,cAAc;AAC9D,QAAM,mBAAmB,OAAO,KAAK;AAErC,YAAU,MAAM;AACd,QAAI,QAAQ,CAAC,iBAAiB,SAAS;AACrC,gBAAU,OAAO;AACjB,uBAAiB,UAAU;AAAA,IAC7B,WAAW,CAAC,MAAM;AAChB,uBAAiB,UAAU;AAAA,IAC7B;AAAA,EACF,GAAG,CAAC,MAAM,SAAS,SAAS,CAAC;AAE7B,YAAU,MAAM;AACd,QAAI,QAAQ,CAAC,eAAe,OAAO,EAAG;AACtC,UAAM,QAAQ,OAAO,WAAW,MAAM,SAAS,OAAO,GAAG,kBAAkB;AAC3E,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,MAAM,SAAS,UAAU,cAAc,CAAC;AAC9C;AAmCO,IAAM,iBAAiB,CAAC,YAA6C;AAC1E,QAAM,EAAE,MAAM,SAAS,SAAS,YAAY,qBAAqB,kBAAkB,QAAQ,IACzF;AAEF,QAAM,YAAY,OAAuB,IAAI;AAC7C,QAAM,EAAE,cAAc,MAAM,IAAI,cAAc;AAC9C,QAAM,EAAE,WAAW,YAAY,IAAI,aAAa,QAAQ,IAAI,GAAG,OAAO;AACtE,QAAM,eAAe,YAAY,QAAQ,OAAO,CAAC;AACjD,QAAM,SAAS,eAAe,SAAS,gBAAgB;AAEvD,QAAM,QAAQ,SAAS;AACvB,QAAM,WAAW,cAAc,MAAM,YAAY,KAAK,IAAI,CAAC;AAC3D,QAAM,YAAY,cAAc;AAChC,QAAM,YAAY,eAAe;AAGjC,QAAM,UAAU,MAAM,CAAC,GAAG,MAAM,aAAa;AAE7C,eAAa,WAAW,QAAQ,IAAI,KAAK,WAAW,gBAAgB;AACpE,mBAAiB,QAAQ,QAAQ,UAAU,KAAK,WAAW,OAAO;AAElE,QAAM,EAAE,YAAY,YAAY,IAAI,iBAAiB;AAAA,IACnD;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAaA,IAAM,mBAAmB,CAAC;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,OAGM;AAAA,EACJ,YAAY,MAAM;AAChB,QAAI,UAAW,SAAQ;AAAA,EACzB;AAAA,EACA,aAAa,CAAC,QAAQ,WAAW;AAC/B,QAAI,CAAC,UAAW;AAChB,QAAI,WAAW,mBAAmB,CAAC,oBAAqB;AACxD,QAAI,WAAW,mBAAmB,CAAC,WAAY;AAC/C,YAAQ;AAAA,EACV;AACF;AAGA,IAAM,iBAAiB,CAAC,SAAiB,aAA6B;AACpE,QAAM,EAAE,MAAM,IAAI,cAAc;AAChC,SAAO,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,GAAG,UAAU;AACxD;AAMA,IAAM,eAAe,CACnB,MACA,YACwD;AACxD,QAAM,EAAE,MAAM,IAAI,cAAc;AAChC,QAAM,CAAC,WAAW,YAAY,IAAI,SAAyB,SAAS;AACpE,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AAEpD,uBAAqB,MAAM,OAAO;AAElC,YAAU,MAAM;AACd,QAAI,CAAC,KAAM;AAEX,UAAM,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,GAAG;AACrD,QAAI,CAAC,WAAW,YAAY,UAAW;AAEvC,mBAAe,IAAI;AACnB,iBAAa,OAAO;AACpB,UAAM,QAAQ,OAAO,WAAW,MAAM,eAAe,KAAK,GAAG,kBAAkB;AAC/E,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,OAAO,SAAS,MAAM,SAAS,CAAC;AAEpC,SAAO,EAAE,WAAW,YAAY;AAClC;","names":[]}
|
|
@@ -122,7 +122,10 @@ var panelStyles = (theme, props) => {
|
|
|
122
122
|
};
|
|
123
123
|
var dialogRootStyles = (theme, props) => ({
|
|
124
124
|
direction: props.rtl ? "rtl" : "ltr",
|
|
125
|
-
|
|
125
|
+
// The dialog's OWN backdrop only: a descendant selector also reached the
|
|
126
|
+
// backdrop of any sheet or drawer rendered inside the panel, and blurred the
|
|
127
|
+
// very panel that sheet sits on.
|
|
128
|
+
"& > .MuiBackdrop-root": backdropStyles(theme, props.modalRole),
|
|
126
129
|
"& .MuiDialog-container": { alignItems: "flex-start", justifyContent: "flex-end" },
|
|
127
130
|
"& .MuiDialog-paper": panelStyles(theme, props),
|
|
128
131
|
...KEYFRAMES
|
|
@@ -180,4 +183,4 @@ export {
|
|
|
180
183
|
loadingOverlayStyles,
|
|
181
184
|
modalContentStyles
|
|
182
185
|
};
|
|
183
|
-
//# sourceMappingURL=chunk-
|
|
186
|
+
//# sourceMappingURL=chunk-XSIVM4VO.js.map
|
|
@@ -1 +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":";;;;;;;;;;;AAAA,SAAS,aAAa;AAkBf,IAAM,mBAAmB,CAAC,aAAa,eAAe,SAAS,OAAO,kBAAkB,WAAW;AAG1G,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;AAGA,IAAM,yBAAkE;AAAA,EACtE,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;AAAA,EACA,8BAA8B;AAAA,IAC5B,MAAM,EAAE,OAAO,QAAQ,WAAW,gBAAgB;AAAA,IAClD,IAAI,EAAE,OAAO,SAAS,WAAW,gBAAgB;AAAA,EACnD;AAAA,EACA,gCAAgC;AAAA,IAC9B,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;AAOA,IAAM,yBAAyB,CAAC,OAAc,WAAqC;AAAA,EACjF,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,EAC7D,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,CACtB,OACA,MACA,OACA,SACc;AACd,MAAI,SAAS,WAAW;AACtB,WAAO,SAAS,SAAS,uBAAuB,OAAO,KAAK,IAAI,mBAAmB,OAAO,KAAK;AAAA,EACjG;AACA,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,MAAuB,SAAgC;AACrG,QAAM,SAAS,SAAS,SAAS,yBAAyB;AAC1D,SAAO,cAAc,EAAE,YAAY,QAAQ,OAAO,IAAI,MAAM,OAAO,IAAI,CAAC;AAC1E;AAEA,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,OAAO,MAAM,SAAS;AAAA,IACjE,GAAG,YAAY,OAAO,MAAM,OAAO,MAAM,SAAS;AAAA,IAClD,GAAG,gBAAgB,MAAM,aAAa,MAAM,WAAW,MAAM,SAAS;AAAA,EACxE;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":[]}
|
|
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 // The dialog's OWN backdrop only: a descendant selector also reached the\n // backdrop of any sheet or drawer rendered inside the panel, and blurred the\n // very panel that sheet sits on.\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,11 +3,11 @@ import {
|
|
|
3
3
|
} from "../chunk-35IEACIJ.js";
|
|
4
4
|
import {
|
|
5
5
|
DataViewsTableBase
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-RG3GJTSK.js";
|
|
7
7
|
import "../chunk-YWIVVKCJ.js";
|
|
8
8
|
import {
|
|
9
9
|
DataViewsGrid
|
|
10
|
-
} from "../chunk-
|
|
10
|
+
} from "../chunk-F5LDJ52M.js";
|
|
11
11
|
import {
|
|
12
12
|
BaseListCard
|
|
13
13
|
} from "../chunk-PJ5HXNBG.js";
|
|
@@ -23,12 +23,12 @@ import {
|
|
|
23
23
|
DropIndicator,
|
|
24
24
|
useDragItem
|
|
25
25
|
} from "../chunk-K4EKTMTC.js";
|
|
26
|
-
import "../chunk-
|
|
26
|
+
import "../chunk-64BEEFLJ.js";
|
|
27
27
|
import "../chunk-HM6T6EQR.js";
|
|
28
28
|
import {
|
|
29
29
|
DataViewsBoard
|
|
30
30
|
} from "../chunk-NHHWNA5W.js";
|
|
31
|
-
import "../chunk-
|
|
31
|
+
import "../chunk-EP674QTM.js";
|
|
32
32
|
import "../chunk-GOIFPE2E.js";
|
|
33
33
|
import "../chunk-X6WC5QBY.js";
|
|
34
34
|
import "../chunk-QLJU7UUI.js";
|
|
@@ -175,11 +175,11 @@ import "../chunk-AL5E624U.js";
|
|
|
175
175
|
import "../chunk-Z2JH5KW5.js";
|
|
176
176
|
import "../chunk-LV7LSPBF.js";
|
|
177
177
|
import "../chunk-CN46HGXE.js";
|
|
178
|
-
import "../chunk-
|
|
179
|
-
import "../chunk-
|
|
178
|
+
import "../chunk-RQ2NKSIA.js";
|
|
179
|
+
import "../chunk-TSMF7K37.js";
|
|
180
180
|
import "../chunk-JZRSHDNY.js";
|
|
181
|
-
import "../chunk-
|
|
182
|
-
import "../chunk-
|
|
181
|
+
import "../chunk-GLKUN3DL.js";
|
|
182
|
+
import "../chunk-XSIVM4VO.js";
|
|
183
183
|
import "../chunk-L5CPOEDP.js";
|
|
184
184
|
import "../chunk-FXZUVZON.js";
|
|
185
185
|
import "../chunk-EARWC6PD.js";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "../chunk-CN46HGXE.js";
|
|
2
2
|
import {
|
|
3
3
|
StackedModal
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import "../chunk-
|
|
4
|
+
} from "../chunk-RQ2NKSIA.js";
|
|
5
|
+
import "../chunk-TSMF7K37.js";
|
|
6
6
|
import {
|
|
7
7
|
ModalStackProvider,
|
|
8
8
|
useModalStack
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
StackedModalActions,
|
|
12
12
|
StackedModalContent
|
|
13
|
-
} from "../chunk-
|
|
14
|
-
import "../chunk-
|
|
13
|
+
} from "../chunk-GLKUN3DL.js";
|
|
14
|
+
import "../chunk-XSIVM4VO.js";
|
|
15
15
|
import "../chunk-AKZWDZCZ.js";
|
|
16
16
|
import "../chunk-SSX5ITPM.js";
|
|
17
17
|
import "../chunk-F5H2ZXST.js";
|
|
@@ -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;
|
|
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;AA4I9D,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"}
|
|
@@ -17,6 +17,12 @@ interface PanelChrome {
|
|
|
17
17
|
zIndex: number;
|
|
18
18
|
isMobile: boolean;
|
|
19
19
|
canGoBack: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* This panel is the bottom of the stack. Read from ITS position, not from the
|
|
22
|
+
* depth: once a child opens, the depth says "can go back" for every panel,
|
|
23
|
+
* the receding root included.
|
|
24
|
+
*/
|
|
25
|
+
isRoot: boolean;
|
|
20
26
|
handleBack: () => void;
|
|
21
27
|
handleClose: (event: object, reason: 'backdropClick' | 'escapeKeyDown') => void;
|
|
22
28
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StackedModal.hooks.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA0F3D,UAAU,kBAAkB;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,UAAU,WAAW;IACnB,SAAS,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC5C,SAAS,EAAE,cAAc,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,eAAe,KAAK,IAAI,CAAC;CACjF;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,kBAAkB,KAAG,
|
|
1
|
+
{"version":3,"file":"StackedModal.hooks.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.hooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AA0F3D,UAAU,kBAAkB;IAC1B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,UAAU,WAAW;IACnB,SAAS,EAAE,SAAS,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC5C,SAAS,EAAE,cAAc,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB;;;;OAIG;IACH,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,eAAe,KAAK,IAAI,CAAC;CACjF;AAED;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAI,SAAS,kBAAkB,KAAG,WAyC5D,CAAC"}
|
|
@@ -67,6 +67,8 @@ export declare const ModalFooter: FC<{
|
|
|
67
67
|
children?: ReactNode;
|
|
68
68
|
}>;
|
|
69
69
|
interface PanelContentsProps extends ModalHeaderProps {
|
|
70
|
+
/** Draw no bar — already resolved: `hideHeader` on the ROOT panel only. */
|
|
71
|
+
hideHeader?: boolean;
|
|
70
72
|
showSkeleton: boolean;
|
|
71
73
|
loadingText?: string;
|
|
72
74
|
descId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StackedModal.parts.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.parts.tsx"],"names":[],"mappings":"AAKA,OAAO,aAAa,MAAM,sCAAsC,CAAC;AAMjE,OAAO,KAAK,EAAe,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAqBxD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,OAAO,aAEhB,CAAC;AAE1B,sFAAsF;AACtF,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,GAAG,SAAS,EAAE,QAAQ,MAAM,KAAG,MAAM,GAAG,SACnC,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAqC,CAAC;AAmBnG;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,SAAS,EACnB,SAAS,SAAS,EAClB,UAAU,OAAO,KAChB;IACD,OAAO,EAAE,SAAS,CAAC;IACnB,YAAY,EAAE,SAAS,CAAC;IACxB,aAAa,EAAE,SAAS,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;CAU3B,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,YAAY,GACvB,SAAS,MAAM,EACf,iBAAiB,MAAM,EACvB,kBAAkB,MAAM,KACvB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAGlC,CAAC;AAEH,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAejF,CAAC;AAEF,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,uFAAuF;IACvF,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA0CD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAsD5C,CAAC;AAcF,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,qFAAqF;IACrF,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CA0BxC,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAgBzE,CAAC;AAEF,UAAU,kBAAmB,SAAQ,gBAAgB;IACnD,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,SAAS,CAAC;IACnB,qFAAqF;IACrF,YAAY,EAAE,SAAS,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,0FAA0F;AAC1F,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,kBAAkB,
|
|
1
|
+
{"version":3,"file":"StackedModal.parts.d.ts","sourceRoot":"","sources":["../../../../../src/components/feedback/StackedModal/StackedModal.parts.tsx"],"names":[],"mappings":"AAKA,OAAO,aAAa,MAAM,sCAAsC,CAAC;AAMjE,OAAO,KAAK,EAAe,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAqBxD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,OAAO,aAEhB,CAAC;AAE1B,sFAAsF;AACtF,eAAO,MAAM,MAAM,GAAI,MAAM,MAAM,GAAG,SAAS,EAAE,QAAQ,MAAM,KAAG,MAAM,GAAG,SACnC,CAAC;AAEzC;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAAqC,CAAC;AAmBnG;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAC9B,UAAU,SAAS,EACnB,SAAS,SAAS,EAClB,UAAU,OAAO,KAChB;IACD,OAAO,EAAE,SAAS,CAAC;IACnB,YAAY,EAAE,SAAS,CAAC;IACxB,aAAa,EAAE,SAAS,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;CAU3B,CAAC;AAEF,8EAA8E;AAC9E,eAAO,MAAM,YAAY,GACvB,SAAS,MAAM,EACf,iBAAiB,MAAM,EACvB,kBAAkB,MAAM,KACvB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAGlC,CAAC;AAEH,eAAO,MAAM,mBAAmB,EAAE,EAAE,CAAC;IAAE,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAejF,CAAC;AAEF,UAAU,gBAAgB;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,SAAS,CAAC;IAC5B,uFAAuF;IACvF,SAAS,EAAE,OAAO,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,4EAA4E;IAC5E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AA0CD,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC,gBAAgB,CAsD5C,CAAC;AAcF,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,qFAAqF;IACrF,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,EAAE,EAAE,CAAC,cAAc,CA0BxC,CAAC;AAEF,mFAAmF;AACnF,eAAO,MAAM,WAAW,EAAE,EAAE,CAAC;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,CAgBzE,CAAC;AAEF,UAAU,kBAAmB,SAAQ,gBAAgB;IACnD,2EAA2E;IAC3E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,SAAS,CAAC;IACnB,qFAAqF;IACrF,YAAY,EAAE,SAAS,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,0FAA0F;AAC1F,eAAO,MAAM,kBAAkB,EAAE,EAAE,CAAC,kBAAkB,CA2BrD,CAAC"}
|
|
@@ -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,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,
|
|
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,SAStE,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"}
|
|
@@ -28,6 +28,18 @@ export interface StackedModalProps {
|
|
|
28
28
|
* different action, and it is the only way out of depth ≥2.
|
|
29
29
|
*/
|
|
30
30
|
hideClose?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Draws no navigation bar at all, for a ROOT panel whose content carries its
|
|
33
|
+
* own header — the ✕ and the panel's name in one sticky bar. A bar above it
|
|
34
|
+
* holding only a breadcrumb is a second header on a screen that already has
|
|
35
|
+
* one, and on a phone it costs the first 64px of the viewport.
|
|
36
|
+
*
|
|
37
|
+
* Pass `aria-labelledby` with it, naming the content header's title: the bar
|
|
38
|
+
* is what names the dialog otherwise (a dev warning says so). Applies to the
|
|
39
|
+
* ROOT panel only — a stacked panel's back arrow lives in the bar and is the
|
|
40
|
+
* only way out — and the root stays bar-less while a child is open over it.
|
|
41
|
+
*/
|
|
42
|
+
hideHeader?: boolean;
|
|
31
43
|
/** Modal content */
|
|
32
44
|
children?: ReactNode;
|
|
33
45
|
/** Actions to display in the modal header (desktop) or footer (mobile) */
|
|
@@ -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;;;;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
|
+
{"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;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,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"}
|
package/package.json
CHANGED
|
@@ -111,6 +111,12 @@ interface PanelChrome {
|
|
|
111
111
|
zIndex: number;
|
|
112
112
|
isMobile: boolean;
|
|
113
113
|
canGoBack: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* This panel is the bottom of the stack. Read from ITS position, not from the
|
|
116
|
+
* depth: once a child opens, the depth says "can go back" for every panel,
|
|
117
|
+
* the receding root included.
|
|
118
|
+
*/
|
|
119
|
+
isRoot: boolean;
|
|
114
120
|
handleBack: () => void;
|
|
115
121
|
handleClose: (event: object, reason: 'backdropClick' | 'escapeKeyDown') => void;
|
|
116
122
|
}
|
|
@@ -125,7 +131,7 @@ export const usePanelChrome = (options: PanelChromeOptions): PanelChrome => {
|
|
|
125
131
|
options;
|
|
126
132
|
|
|
127
133
|
const dialogRef = useRef<HTMLDivElement>(null);
|
|
128
|
-
const { currentDepth } = useModalStack();
|
|
134
|
+
const { currentDepth, stack } = useModalStack();
|
|
129
135
|
const { modalRole, isAnimating } = useModalRole(Boolean(open), modalId);
|
|
130
136
|
const showSkeleton = useSkeleton(Boolean(loading));
|
|
131
137
|
const zIndex = usePanelZIndex(modalId, FALLBACK_Z_INDEX);
|
|
@@ -134,6 +140,9 @@ export const usePanelChrome = (options: PanelChromeOptions): PanelChrome => {
|
|
|
134
140
|
const isMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
|
135
141
|
const isPrimary = modalRole === 'primary';
|
|
136
142
|
const canGoBack = currentDepth > 1;
|
|
143
|
+
// Not yet pushed (its first render) and something already below it: NOT the
|
|
144
|
+
// root — so a child never renders a frame without its back arrow.
|
|
145
|
+
const isRoot = (stack[0]?.id ?? modalId) === modalId;
|
|
137
146
|
|
|
138
147
|
useFocusTrap(dialogRef, Boolean(open) && isPrimary, disableFocusTrap);
|
|
139
148
|
useEscapeToClose(Boolean(open && closeOnEsc) && isPrimary, onClose);
|
|
@@ -154,6 +163,7 @@ export const usePanelChrome = (options: PanelChromeOptions): PanelChrome => {
|
|
|
154
163
|
zIndex,
|
|
155
164
|
isMobile,
|
|
156
165
|
canGoBack,
|
|
166
|
+
isRoot,
|
|
157
167
|
handleBack,
|
|
158
168
|
handleClose,
|
|
159
169
|
};
|
|
@@ -125,6 +125,8 @@ new component that portals should too.
|
|
|
125
125
|
| `open` | `boolean` | `false` | Controls modal visibility |
|
|
126
126
|
| `onClose` | `() => void` | - | Callback when modal is closed |
|
|
127
127
|
| `navigationTitle` | `string` | - | Title displayed in modal header |
|
|
128
|
+
| `hideClose` | `boolean` | `false` | Drop the header's ✕ — the content owns the dismiss |
|
|
129
|
+
| `hideHeader` | `boolean` | `false` | Draw no header bar at all, for a root panel whose content brings its own header (✕ and name). Pass `aria-labelledby` naming that header's title (a dev warning fires without it). Root panel only |
|
|
128
130
|
| `children` | `ReactNode` | - | Modal content |
|
|
129
131
|
| `glass` | `boolean` | `false` | Enable glass morphism effect |
|
|
130
132
|
| `actions` | `ReactNode` | - | Custom action buttons for header/footer |
|
|
@@ -179,6 +181,31 @@ and a dialog named by everything in the bar ("close Title Save").
|
|
|
179
181
|
Without a `navigationTitle` the bar is still MUI's `h2` and holds the id, as
|
|
180
182
|
before. Give such a panel its own `aria-labelledby` if it needs a name.
|
|
181
183
|
|
|
184
|
+
### A panel that brings its own header
|
|
185
|
+
|
|
186
|
+
A root panel whose content already has a sticky header — the name and the ✕ in
|
|
187
|
+
one bar — would otherwise show TWO bars, the first holding only a breadcrumb.
|
|
188
|
+
`hideHeader` drops the panel's bar; the dialog is then named by the content's
|
|
189
|
+
own title through `aria-labelledby`:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
<StackedModal
|
|
193
|
+
backLabel="Voltar"
|
|
194
|
+
open={open}
|
|
195
|
+
onClose={close}
|
|
196
|
+
hideHeader
|
|
197
|
+
aria-labelledby="product-edit-title"
|
|
198
|
+
>
|
|
199
|
+
<ProductEditHeader titleId="product-edit-title" … />
|
|
200
|
+
</StackedModal>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Only the ROOT panel drops its bar, and it stays bar-less while a child panel is
|
|
204
|
+
open over it. A stacked panel keeps its bar whatever this says: the back arrow
|
|
205
|
+
lives there and is the only way out of depth ≥2.
|
|
206
|
+
|
|
207
|
+
With no bar, initial focus lands on the first focusable element of your content.
|
|
208
|
+
|
|
182
209
|
## Testing
|
|
183
210
|
|
|
184
211
|
The StackedModal component provides comprehensive test IDs for all interactive elements through the `dataTestId` prop. When provided, it generates consistent test IDs for all child elements.
|
|
@@ -190,7 +217,7 @@ When you provide `dataTestId="my-modal"`, the following test IDs are automatical
|
|
|
190
217
|
| Element | Test ID | Description |
|
|
191
218
|
|---------|---------|-------------|
|
|
192
219
|
| Modal Container | `my-modal` | The root dialog element |
|
|
193
|
-
| Header | `my-modal-header` | The modal header bar (a `div` when there is a title) |
|
|
220
|
+
| Header | `my-modal-header` | The modal header bar (a `div` when there is a title; absent with `hideHeader` on a root panel) |
|
|
194
221
|
| Title | `my-modal-title` | The navigation title — the panel's one `h2` |
|
|
195
222
|
| Close Button | `my-modal-close-button` | The close button (when no modals stacked) |
|
|
196
223
|
| Back Button | `my-modal-back-button` | The back button (when modals are stacked) |
|
|
@@ -300,6 +300,8 @@ export const ModalFooter: FC<{ dataTestId?: string; children?: ReactNode }> = ({
|
|
|
300
300
|
);
|
|
301
301
|
|
|
302
302
|
interface PanelContentsProps extends ModalHeaderProps {
|
|
303
|
+
/** Draw no bar — already resolved: `hideHeader` on the ROOT panel only. */
|
|
304
|
+
hideHeader?: boolean;
|
|
303
305
|
showSkeleton: boolean;
|
|
304
306
|
loadingText?: string;
|
|
305
307
|
descId: string;
|
|
@@ -317,13 +319,14 @@ export const ModalPanelContents: FC<PanelContentsProps> = ({
|
|
|
317
319
|
content,
|
|
318
320
|
modalActions,
|
|
319
321
|
hasMobileActions,
|
|
322
|
+
hideHeader,
|
|
320
323
|
...header
|
|
321
324
|
}) => (
|
|
322
325
|
<>
|
|
323
326
|
{showSkeleton && (
|
|
324
327
|
<ModalLoadingOverlay loadingText={loadingText} dataTestId={header.dataTestId} />
|
|
325
328
|
)}
|
|
326
|
-
<ModalHeader {...header} />
|
|
329
|
+
{!hideHeader && <ModalHeader {...header} />}
|
|
327
330
|
<ModalBody
|
|
328
331
|
descId={descId}
|
|
329
332
|
showSkeleton={showSkeleton}
|
|
@@ -178,7 +178,10 @@ const panelStyles = (theme: Theme, props: PanelStyleProps): CSSObject => {
|
|
|
178
178
|
/** The full rule set for the sliding panel's Dialog root. */
|
|
179
179
|
export const dialogRootStyles = (theme: Theme, props: PanelStyleProps): CSSObject => ({
|
|
180
180
|
direction: props.rtl ? 'rtl' : 'ltr',
|
|
181
|
-
'
|
|
181
|
+
// The dialog's OWN backdrop only: a descendant selector also reached the
|
|
182
|
+
// backdrop of any sheet or drawer rendered inside the panel, and blurred the
|
|
183
|
+
// very panel that sheet sits on.
|
|
184
|
+
'& > .MuiBackdrop-root': backdropStyles(theme, props.modalRole),
|
|
182
185
|
'& .MuiDialog-container': { alignItems: 'flex-start', justifyContent: 'flex-end' },
|
|
183
186
|
'& .MuiDialog-paper': panelStyles(theme, props),
|
|
184
187
|
...KEYFRAMES,
|
|
@@ -3,7 +3,7 @@ import Slide from '@mui/material/Slide/index.js';
|
|
|
3
3
|
import { styled } from '@mui/material/styles/index.js';
|
|
4
4
|
import type { TransitionProps } from '@mui/material/transitions/index.js';
|
|
5
5
|
import type { FC } from 'react';
|
|
6
|
-
import React, { forwardRef, useId } from 'react';
|
|
6
|
+
import React, { forwardRef, useEffect, useId } from 'react';
|
|
7
7
|
import { usePanelChrome } from './StackedModal.hooks';
|
|
8
8
|
import { modalAriaIds, ModalPanelContents, resolveModalContent } from './StackedModal.parts';
|
|
9
9
|
import type { PanelStyleProps } from './StackedModal.styles';
|
|
@@ -59,16 +59,33 @@ const withDefaults = (props: StackedModalProps): StackedModalProps => {
|
|
|
59
59
|
/** The modal's props once defaults are applied and its stack identity is settled. */
|
|
60
60
|
type ResolvedProps = StackedModalProps & { modalId: string };
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* `hideHeader` removes the bar that names the dialog; without an
|
|
64
|
+
* `aria-labelledby` of the caller's own, the dialog has no accessible name.
|
|
65
|
+
*/
|
|
66
|
+
const useUnnamedDialogWarning = (unnamed: boolean): void => {
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
const development = typeof process !== 'undefined' && process.env?.NODE_ENV !== 'production';
|
|
69
|
+
if (unnamed && development) {
|
|
70
|
+
// eslint-disable-next-line no-console -- a config warning has no other channel.
|
|
71
|
+
console.warn(
|
|
72
|
+
'StackedModal: `hideHeader` without `aria-labelledby` leaves the dialog unnamed. ' +
|
|
73
|
+
"Point `aria-labelledby` at your content header's title.",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}, [unnamed]);
|
|
77
|
+
};
|
|
78
|
+
|
|
62
79
|
const StackedModalPanel: FC<ResolvedProps> = (props) => {
|
|
63
80
|
const {
|
|
64
|
-
open, onClose, glass, navigationTitle, backLabel, hideClose, children, actions, modalId,
|
|
81
|
+
open, onClose, glass, navigationTitle, backLabel, hideClose, hideHeader, children, actions, modalId,
|
|
65
82
|
closeOnClickOutside, closeOnEsc, loading, loadingText, fullScreen, maxWidth, size, disableBackdrop,
|
|
66
83
|
disableFocusTrap, keepMounted, rtl, dataTestId,
|
|
67
84
|
'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, ...otherProps
|
|
68
85
|
} = props;
|
|
69
86
|
|
|
70
87
|
const {
|
|
71
|
-
dialogRef, modalRole, isAnimating, showSkeleton, zIndex, isMobile, canGoBack,
|
|
88
|
+
dialogRef, modalRole, isAnimating, showSkeleton, zIndex, isMobile, canGoBack, isRoot,
|
|
72
89
|
handleBack, handleClose,
|
|
73
90
|
} = usePanelChrome({
|
|
74
91
|
open, modalId, loading, closeOnEsc, closeOnClickOutside, disableFocusTrap, onClose,
|
|
@@ -83,6 +100,7 @@ const StackedModalPanel: FC<ResolvedProps> = (props) => {
|
|
|
83
100
|
isMobile,
|
|
84
101
|
);
|
|
85
102
|
const { titleId, descId } = modalAriaIds(modalId, ariaLabelledBy, ariaDescribedBy);
|
|
103
|
+
useUnnamedDialogWarning(Boolean(hideHeader) && !ariaLabelledBy);
|
|
86
104
|
|
|
87
105
|
return (
|
|
88
106
|
<StyledDialog
|
|
@@ -115,6 +133,7 @@ const StackedModalPanel: FC<ResolvedProps> = (props) => {
|
|
|
115
133
|
descId={descId}
|
|
116
134
|
navigationTitle={navigationTitle}
|
|
117
135
|
hideClose={hideClose}
|
|
136
|
+
hideHeader={Boolean(hideHeader) && isRoot}
|
|
118
137
|
canGoBack={canGoBack}
|
|
119
138
|
onBack={handleBack}
|
|
120
139
|
onClose={onClose}
|
|
@@ -32,6 +32,18 @@ export interface StackedModalProps {
|
|
|
32
32
|
* different action, and it is the only way out of depth ≥2.
|
|
33
33
|
*/
|
|
34
34
|
hideClose?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Draws no navigation bar at all, for a ROOT panel whose content carries its
|
|
37
|
+
* own header — the ✕ and the panel's name in one sticky bar. A bar above it
|
|
38
|
+
* holding only a breadcrumb is a second header on a screen that already has
|
|
39
|
+
* one, and on a phone it costs the first 64px of the viewport.
|
|
40
|
+
*
|
|
41
|
+
* Pass `aria-labelledby` with it, naming the content header's title: the bar
|
|
42
|
+
* is what names the dialog otherwise (a dev warning says so). Applies to the
|
|
43
|
+
* ROOT panel only — a stacked panel's back arrow lives in the bar and is the
|
|
44
|
+
* only way out — and the root stays bar-less while a child is open over it.
|
|
45
|
+
*/
|
|
46
|
+
hideHeader?: boolean;
|
|
35
47
|
/** Modal content */
|
|
36
48
|
children?: ReactNode;
|
|
37
49
|
/** Actions to display in the modal header (desktop) or footer (mobile) */
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/feedback/StackedModal/StackedModal.hooks.ts"],"sourcesContent":["import { useTheme } from '@mui/material/styles/index.js';\nimport useMediaQuery from '@mui/material/useMediaQuery/index.js';\nimport type { RefObject } from 'react';\nimport { useEffect, useRef, useState } from 'react';\nimport { useModalStack } from './modal-stack';\nimport type { ModalPanelRole } from './StackedModal.types';\n\nconst FOCUSABLE = 'a[href], button, textarea, input, select, [tabindex]:not([tabindex=\"-1\"])';\n/** MUI Dialog's own default, used when the modal isn't registered in the stack yet. */\nconst FALLBACK_Z_INDEX = 1300;\n/** Matches the panel's slide duration, so role swaps animate rather than jump. */\nconst ROLE_TRANSITION_MS = 300;\n\n/** Keeps Tab cycling inside the open panel instead of escaping to the page behind. */\nconst useFocusTrap = (\n ref: RefObject<HTMLElement | null>,\n isActive: boolean,\n disabled?: boolean,\n): void => {\n useEffect(() => {\n if (!isActive || disabled || !ref.current) return;\n\n const element = ref.current;\n const focusable = element.querySelectorAll(FOCUSABLE);\n const first = focusable[0] as HTMLElement | undefined;\n const last = focusable[focusable.length - 1] as HTMLElement | undefined;\n\n window.setTimeout(() => first?.focus(), 100);\n\n const handleTabKey = (e: globalThis.KeyboardEvent): void => {\n if (e.key !== 'Tab') return;\n const atEdge = e.shiftKey ? first : last;\n if (document.activeElement !== atEdge) return;\n e.preventDefault();\n (e.shiftKey ? last : first)?.focus();\n };\n\n element.addEventListener('keydown', handleTabKey);\n return () => element.removeEventListener('keydown', handleTabKey);\n }, [ref, isActive, disabled]);\n};\n\n/** Closes the panel on Escape — only while it is the top one. */\nconst useEscapeToClose = (active: boolean, onClose: () => void): void => {\n useEffect(() => {\n if (!active) return;\n\n const handleEsc = (e: globalThis.KeyboardEvent): void => {\n if (e.key !== 'Escape') return;\n e.preventDefault();\n onClose();\n };\n\n window.addEventListener('keydown', handleEsc);\n return () => window.removeEventListener('keydown', handleEsc);\n }, [active, onClose]);\n};\n\n/** Holds the skeleton a beat past `loading` so the swap to content isn't a flash. */\nconst useSkeleton = (loading: boolean): boolean => {\n const [showSkeleton, setShowSkeleton] = useState(loading);\n\n useEffect(() => {\n if (loading) {\n setShowSkeleton(true);\n return;\n }\n const timer = window.setTimeout(() => setShowSkeleton(false), 200);\n return () => window.clearTimeout(timer);\n }, [loading]);\n\n return showSkeleton;\n};\n\n/** Registers the modal in the stack while open, and unregisters it after it slides out. */\nconst useStackRegistration = (open: boolean, modalId: string): void => {\n const { pushModal, popModal, isModalInStack } = useModalStack();\n const hasRegisteredRef = useRef(false);\n\n useEffect(() => {\n if (open && !hasRegisteredRef.current) {\n pushModal(modalId);\n hasRegisteredRef.current = true;\n } else if (!open) {\n hasRegisteredRef.current = false;\n }\n }, [open, modalId, pushModal]);\n\n useEffect(() => {\n if (open || !isModalInStack(modalId)) return;\n const timer = window.setTimeout(() => popModal(modalId), ROLE_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [open, modalId, popModal, isModalInStack]);\n};\n\ninterface PanelChromeOptions {\n open?: boolean;\n modalId: string;\n loading?: boolean;\n closeOnEsc?: boolean;\n closeOnClickOutside?: boolean;\n disableFocusTrap?: boolean;\n onClose: () => void;\n}\n\ninterface PanelChrome {\n dialogRef: RefObject<HTMLDivElement | null>;\n modalRole: ModalPanelRole;\n isAnimating: boolean;\n showSkeleton: boolean;\n zIndex: number;\n isMobile: boolean;\n canGoBack: boolean;\n handleBack: () => void;\n handleClose: (event: object, reason: 'backdropClick' | 'escapeKeyDown') => void;\n}\n\n/**\n * Everything the panel needs to render itself: its place in the stack, the\n * viewport it is on, and the handlers that dismiss it. Bundled into one hook so\n * the component stays a description of the markup.\n */\nexport const usePanelChrome = (options: PanelChromeOptions): PanelChrome => {\n const { open, modalId, loading, closeOnEsc, closeOnClickOutside, disableFocusTrap, onClose } =\n options;\n\n const dialogRef = useRef<HTMLDivElement>(null);\n const { currentDepth } = useModalStack();\n const { modalRole, isAnimating } = useModalRole(Boolean(open), modalId);\n const showSkeleton = useSkeleton(Boolean(loading));\n const zIndex = usePanelZIndex(modalId, FALLBACK_Z_INDEX);\n\n const theme = useTheme();\n const isMobile = useMediaQuery(theme.breakpoints.down('sm'));\n const isPrimary = modalRole === 'primary';\n const canGoBack = currentDepth > 1;\n\n useFocusTrap(dialogRef, Boolean(open) && isPrimary, disableFocusTrap);\n useEscapeToClose(Boolean(open && closeOnEsc) && isPrimary, onClose);\n\n const { handleBack, handleClose } = useCloseHandlers({\n isPrimary,\n closeOnClickOutside,\n closeOnEsc,\n canGoBack,\n onClose,\n });\n\n return {\n dialogRef,\n modalRole,\n isAnimating,\n showSkeleton,\n zIndex,\n isMobile,\n canGoBack,\n handleBack,\n handleClose,\n };\n};\n\ninterface CloseHandlerOptions {\n /** Only the top panel responds to a backdrop click or Escape. */\n isPrimary: boolean;\n closeOnClickOutside?: boolean;\n closeOnEsc?: boolean;\n /** Deeper than one panel, so the leading control goes back rather than closing. */\n canGoBack: boolean;\n onClose: () => void;\n}\n\n/** The panel's dismissal handlers, honouring which gestures the caller allows. */\nconst useCloseHandlers = ({\n isPrimary,\n closeOnClickOutside,\n closeOnEsc,\n canGoBack,\n onClose,\n}: CloseHandlerOptions): {\n handleBack: () => void;\n handleClose: (event: object, reason: 'backdropClick' | 'escapeKeyDown') => void;\n} => ({\n handleBack: () => {\n if (canGoBack) onClose();\n },\n handleClose: (_event, reason) => {\n if (!isPrimary) return;\n if (reason === 'backdropClick' && !closeOnClickOutside) return;\n if (reason === 'escapeKeyDown' && !closeOnEsc) return;\n onClose();\n },\n});\n\n/** The z-index this panel was assigned when it joined the stack. */\nconst usePanelZIndex = (modalId: string, fallback: number): number => {\n const { stack } = useModalStack();\n return stack.find((m) => m.id === modalId)?.zIndex ?? fallback;\n};\n\n/**\n * This modal's role in the stack, plus whether it is mid-transition between two\n * roles (which drives the expand/contract animation).\n */\nconst useModalRole = (\n open: boolean,\n modalId: string,\n): { modalRole: ModalPanelRole; isAnimating: boolean } => {\n const { stack } = useModalStack();\n const [modalRole, setModalRole] = useState<ModalPanelRole>('primary');\n const [isAnimating, setIsAnimating] = useState(false);\n\n useStackRegistration(open, modalId);\n\n useEffect(() => {\n if (!open) return;\n\n const newRole = stack.find((m) => m.id === modalId)?.role;\n if (!newRole || newRole === modalRole) return;\n\n setIsAnimating(true);\n setModalRole(newRole);\n const timer = window.setTimeout(() => setIsAnimating(false), ROLE_TRANSITION_MS);\n return () => window.clearTimeout(timer);\n }, [stack, modalId, open, modalRole]);\n\n return { modalRole, isAnimating };\n};\n"],"mappings":"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","names":[]}
|
|
@@ -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, 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"]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|