@12-apps/ui 6.72.0 → 6.73.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/components-catalog.md +1 -1
- package/dist/_internal/components/index.js +7 -7
- package/dist/_internal/components/navigation/SectionNav/SectionNav.bar.js +5 -4
- package/dist/_internal/components/navigation/SectionNav/SectionNav.js +8 -7
- package/dist/_internal/components/navigation/SectionNav/SectionNav.parts.js +8 -3
- package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js +3 -2
- package/dist/_internal/components/navigation/SectionNav/SectionNav.rail.js +4 -3
- package/dist/_internal/components/navigation/SectionNav/SectionNav.railCreate.js +3 -2
- package/dist/_internal/components/navigation/SectionNav/SectionNav.sheet.js +3 -2
- package/dist/_internal/components/navigation/index.js +8 -7
- package/dist/{chunk-XS4NQ6LD.js → chunk-23LPXHR2.js} +61 -35
- package/dist/chunk-23LPXHR2.js.map +1 -0
- package/dist/{chunk-WP7KPWCP.js → chunk-24HHUCWB.js} +14 -2
- package/dist/chunk-24HHUCWB.js.map +1 -0
- package/dist/{chunk-WY7FR7I4.js → chunk-ILJ3FXIC.js} +17 -8
- package/dist/chunk-ILJ3FXIC.js.map +1 -0
- package/dist/{chunk-VI2IXBOO.js → chunk-KPEKD5SG.js} +24 -13
- package/dist/chunk-KPEKD5SG.js.map +1 -0
- package/dist/{chunk-2STYL5PF.js → chunk-NM46HQSW.js} +2 -2
- package/dist/{chunk-LWQGIN2M.js → chunk-NQP72RTD.js} +9 -6
- package/dist/chunk-NQP72RTD.js.map +1 -0
- package/dist/{chunk-OBGUD2PG.js → chunk-SNWCT6JN.js} +91 -42
- package/dist/chunk-SNWCT6JN.js.map +1 -0
- package/dist/navigation/SectionNav.js +8 -7
- package/dist/types/components/navigation/SectionNav/SectionNav.bar.d.ts +6 -2
- package/dist/types/components/navigation/SectionNav/SectionNav.bar.d.ts.map +1 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.d.ts +4 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.d.ts.map +1 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.parts.d.ts +12 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.parts.d.ts.map +1 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.primary.d.ts +7 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.primary.d.ts.map +1 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.rail.d.ts +3 -2
- package/dist/types/components/navigation/SectionNav/SectionNav.rail.d.ts.map +1 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.railCreate.d.ts +3 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.railCreate.d.ts.map +1 -1
- package/dist/types/components/navigation/SectionNav/SectionNav.types.d.ts +12 -0
- package/dist/types/components/navigation/SectionNav/SectionNav.types.d.ts.map +1 -1
- package/dist/types/components/navigation/SectionNav/index.d.ts +1 -0
- package/dist/types/components/navigation/SectionNav/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/navigation/SectionNav/SectionNav.bar.tsx +77 -29
- package/src/components/navigation/SectionNav/SectionNav.md +24 -3
- package/src/components/navigation/SectionNav/SectionNav.parts.tsx +19 -1
- package/src/components/navigation/SectionNav/SectionNav.primary.tsx +39 -11
- package/src/components/navigation/SectionNav/SectionNav.rail.tsx +90 -35
- package/src/components/navigation/SectionNav/SectionNav.railCreate.tsx +23 -5
- package/src/components/navigation/SectionNav/SectionNav.tsx +6 -0
- package/src/components/navigation/SectionNav/SectionNav.types.ts +12 -0
- package/src/components/navigation/SectionNav/index.ts +1 -0
- package/dist/chunk-LWQGIN2M.js.map +0 -1
- package/dist/chunk-OBGUD2PG.js.map +0 -1
- package/dist/chunk-VI2IXBOO.js.map +0 -1
- package/dist/chunk-WP7KPWCP.js.map +0 -1
- package/dist/chunk-WY7FR7I4.js.map +0 -1
- package/dist/chunk-XS4NQ6LD.js.map +0 -1
- /package/dist/{chunk-2STYL5PF.js.map → chunk-NM46HQSW.js.map} +0 -0
package/components-catalog.md
CHANGED
|
@@ -737,7 +737,7 @@ Components for site and app navigation.
|
|
|
737
737
|
### SectionNav
|
|
738
738
|
**Purpose**: A section's own navigation — the few screens one kind of work moves between
|
|
739
739
|
**Use Cases**: A phone bottom bar for a work area (a shift, a till, a field app); the same destinations as a rail on a wide screen
|
|
740
|
-
**Features**: `bar` (destinations with counts, a `more` sheet, a raised `primary` action in the middle opening its own sheet) and `rail` (a way back, destinations, every menu listed); router-agnostic links via `linkComponent`; copy as a required prop; also a bar of VERBS pinned at a screen's foot — action slots (`onSelect`, `disabled`, `dimmed` — looks disabled but still answers a tap, `loading` — focusable and busy, `active` as a pressed toggle), a raised `primary` that acts on tap with its label under it, disabled menu entries, host-owned `dataTestId`s
|
|
740
|
+
**Features**: `bar` (destinations with counts, a `more` sheet, a raised `primary` action in the middle opening its own sheet) and `rail` (a way back, destinations, every menu listed); router-agnostic links via `linkComponent`; copy as a required prop; also a bar of VERBS pinned at a screen's foot — action slots (`onSelect`, `disabled`, `dimmed` — looks disabled but still answers a tap, `loading` — focusable and busy, `active` as a pressed toggle), a raised `primary` that acts on tap with its label under it, disabled menu entries, host-owned `dataTestId`s; `compact` — both layouts as icons only, a size down (48px bar, 40px raised button, a rail for a 64px column), every label kept as the control's name, for a host that folds its chrome
|
|
741
741
|
**Also exports**: `RaisedActionButton` — the raised round action alone, for a bar the host already draws
|
|
742
742
|
**Types**: `SectionNavProps`, `SectionNavDestination`, `SectionNavAction`, `SectionNavMenu`, `SectionNavGroup`, `SectionNavEntry`, `SectionNavCopy`
|
|
743
743
|
**Location**: `src/components/navigation/SectionNav`
|
|
@@ -105,17 +105,17 @@ import "../../chunk-3L5OZCGA.js";
|
|
|
105
105
|
import "../../chunk-R26KYJHK.js";
|
|
106
106
|
import {
|
|
107
107
|
SectionNav
|
|
108
|
-
} from "../../chunk-
|
|
109
|
-
import "../../chunk-
|
|
110
|
-
import "../../chunk-
|
|
108
|
+
} from "../../chunk-NQP72RTD.js";
|
|
109
|
+
import "../../chunk-SNWCT6JN.js";
|
|
110
|
+
import "../../chunk-ILJ3FXIC.js";
|
|
111
111
|
import {
|
|
112
112
|
sectionNavBarInset
|
|
113
|
-
} from "../../chunk-
|
|
114
|
-
import "../../chunk-
|
|
113
|
+
} from "../../chunk-23LPXHR2.js";
|
|
114
|
+
import "../../chunk-NM46HQSW.js";
|
|
115
115
|
import {
|
|
116
116
|
RaisedActionButton
|
|
117
|
-
} from "../../chunk-
|
|
118
|
-
import "../../chunk-
|
|
117
|
+
} from "../../chunk-KPEKD5SG.js";
|
|
118
|
+
import "../../chunk-24HHUCWB.js";
|
|
119
119
|
import "../../chunk-YCCWJ5XQ.js";
|
|
120
120
|
import "../../chunk-R445KMGG.js";
|
|
121
121
|
import {
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SectionNavBar,
|
|
3
3
|
sectionNavBarInset
|
|
4
|
-
} from "../../../../chunk-
|
|
5
|
-
import "../../../../chunk-
|
|
6
|
-
import "../../../../chunk-
|
|
7
|
-
import "../../../../chunk-
|
|
4
|
+
} from "../../../../chunk-23LPXHR2.js";
|
|
5
|
+
import "../../../../chunk-NM46HQSW.js";
|
|
6
|
+
import "../../../../chunk-KPEKD5SG.js";
|
|
7
|
+
import "../../../../chunk-24HHUCWB.js";
|
|
8
8
|
import "../../../../chunk-YCCWJ5XQ.js";
|
|
9
9
|
import "../../../../chunk-TMSWLFL4.js";
|
|
10
10
|
import "../../../../chunk-UALPKKAY.js";
|
|
11
|
+
import "../../../../chunk-PUFA7FQ7.js";
|
|
11
12
|
import "../../../../chunk-5AK2EZG5.js";
|
|
12
13
|
import "../../../../chunk-N5PVD4J5.js";
|
|
13
14
|
import "../../../../chunk-6C5D6O3D.js";
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SectionNav
|
|
3
|
-
} from "../../../../chunk-
|
|
4
|
-
import "../../../../chunk-
|
|
5
|
-
import "../../../../chunk-
|
|
6
|
-
import "../../../../chunk-
|
|
7
|
-
import "../../../../chunk-
|
|
8
|
-
import "../../../../chunk-
|
|
9
|
-
import "../../../../chunk-
|
|
3
|
+
} from "../../../../chunk-NQP72RTD.js";
|
|
4
|
+
import "../../../../chunk-SNWCT6JN.js";
|
|
5
|
+
import "../../../../chunk-ILJ3FXIC.js";
|
|
6
|
+
import "../../../../chunk-23LPXHR2.js";
|
|
7
|
+
import "../../../../chunk-NM46HQSW.js";
|
|
8
|
+
import "../../../../chunk-KPEKD5SG.js";
|
|
9
|
+
import "../../../../chunk-24HHUCWB.js";
|
|
10
10
|
import "../../../../chunk-YCCWJ5XQ.js";
|
|
11
11
|
import "../../../../chunk-TMSWLFL4.js";
|
|
12
12
|
import "../../../../chunk-UALPKKAY.js";
|
|
13
|
+
import "../../../../chunk-PUFA7FQ7.js";
|
|
13
14
|
import "../../../../chunk-5AK2EZG5.js";
|
|
14
15
|
import "../../../../chunk-N5PVD4J5.js";
|
|
15
16
|
import "../../../../chunk-6C5D6O3D.js";
|
|
@@ -4,11 +4,14 @@ import {
|
|
|
4
4
|
CountedIcon,
|
|
5
5
|
NOT_LIVE,
|
|
6
6
|
SlotIcon,
|
|
7
|
+
VISUALLY_HIDDEN,
|
|
7
8
|
controlProps,
|
|
8
9
|
destinationControl,
|
|
9
|
-
focusRing
|
|
10
|
-
|
|
10
|
+
focusRing,
|
|
11
|
+
useMounted
|
|
12
|
+
} from "../../../../chunk-24HHUCWB.js";
|
|
11
13
|
import "../../../../chunk-YCCWJ5XQ.js";
|
|
14
|
+
import "../../../../chunk-PUFA7FQ7.js";
|
|
12
15
|
import "../../../../chunk-5AK2EZG5.js";
|
|
13
16
|
import "../../../../chunk-N5PVD4J5.js";
|
|
14
17
|
import "../../../../chunk-6C5D6O3D.js";
|
|
@@ -48,8 +51,10 @@ export {
|
|
|
48
51
|
CountedIcon,
|
|
49
52
|
NOT_LIVE,
|
|
50
53
|
SlotIcon,
|
|
54
|
+
VISUALLY_HIDDEN,
|
|
51
55
|
controlProps,
|
|
52
56
|
destinationControl,
|
|
53
|
-
focusRing
|
|
57
|
+
focusRing,
|
|
58
|
+
useMounted
|
|
54
59
|
};
|
|
55
60
|
//# sourceMappingURL=SectionNav.parts.js.map
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RaisedActionButton
|
|
3
|
-
} from "../../../../chunk-
|
|
4
|
-
import "../../../../chunk-
|
|
3
|
+
} from "../../../../chunk-KPEKD5SG.js";
|
|
4
|
+
import "../../../../chunk-24HHUCWB.js";
|
|
5
5
|
import "../../../../chunk-YCCWJ5XQ.js";
|
|
6
|
+
import "../../../../chunk-PUFA7FQ7.js";
|
|
6
7
|
import "../../../../chunk-5AK2EZG5.js";
|
|
7
8
|
import "../../../../chunk-N5PVD4J5.js";
|
|
8
9
|
import "../../../../chunk-6C5D6O3D.js";
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SectionNavRail
|
|
3
|
-
} from "../../../../chunk-
|
|
4
|
-
import "../../../../chunk-
|
|
5
|
-
import "../../../../chunk-
|
|
3
|
+
} from "../../../../chunk-SNWCT6JN.js";
|
|
4
|
+
import "../../../../chunk-ILJ3FXIC.js";
|
|
5
|
+
import "../../../../chunk-24HHUCWB.js";
|
|
6
6
|
import "../../../../chunk-YCCWJ5XQ.js";
|
|
7
|
+
import "../../../../chunk-PUFA7FQ7.js";
|
|
7
8
|
import "../../../../chunk-5AK2EZG5.js";
|
|
8
9
|
import "../../../../chunk-N5PVD4J5.js";
|
|
9
10
|
import "../../../../chunk-6C5D6O3D.js";
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RailCreateMenu
|
|
3
|
-
} from "../../../../chunk-
|
|
4
|
-
import "../../../../chunk-
|
|
3
|
+
} from "../../../../chunk-ILJ3FXIC.js";
|
|
4
|
+
import "../../../../chunk-24HHUCWB.js";
|
|
5
5
|
import "../../../../chunk-YCCWJ5XQ.js";
|
|
6
|
+
import "../../../../chunk-PUFA7FQ7.js";
|
|
6
7
|
import "../../../../chunk-5AK2EZG5.js";
|
|
7
8
|
import "../../../../chunk-N5PVD4J5.js";
|
|
8
9
|
import "../../../../chunk-6C5D6O3D.js";
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SectionNavSheet
|
|
3
|
-
} from "../../../../chunk-
|
|
4
|
-
import "../../../../chunk-
|
|
3
|
+
} from "../../../../chunk-NM46HQSW.js";
|
|
4
|
+
import "../../../../chunk-24HHUCWB.js";
|
|
5
5
|
import "../../../../chunk-YCCWJ5XQ.js";
|
|
6
6
|
import "../../../../chunk-TMSWLFL4.js";
|
|
7
7
|
import "../../../../chunk-UALPKKAY.js";
|
|
8
|
+
import "../../../../chunk-PUFA7FQ7.js";
|
|
8
9
|
import "../../../../chunk-5AK2EZG5.js";
|
|
9
10
|
import "../../../../chunk-N5PVD4J5.js";
|
|
10
11
|
import "../../../../chunk-6C5D6O3D.js";
|
|
@@ -29,17 +29,17 @@ import "../../../chunk-3L5OZCGA.js";
|
|
|
29
29
|
import "../../../chunk-R26KYJHK.js";
|
|
30
30
|
import {
|
|
31
31
|
SectionNav
|
|
32
|
-
} from "../../../chunk-
|
|
33
|
-
import "../../../chunk-
|
|
34
|
-
import "../../../chunk-
|
|
32
|
+
} from "../../../chunk-NQP72RTD.js";
|
|
33
|
+
import "../../../chunk-SNWCT6JN.js";
|
|
34
|
+
import "../../../chunk-ILJ3FXIC.js";
|
|
35
35
|
import {
|
|
36
36
|
sectionNavBarInset
|
|
37
|
-
} from "../../../chunk-
|
|
38
|
-
import "../../../chunk-
|
|
37
|
+
} from "../../../chunk-23LPXHR2.js";
|
|
38
|
+
import "../../../chunk-NM46HQSW.js";
|
|
39
39
|
import {
|
|
40
40
|
RaisedActionButton
|
|
41
|
-
} from "../../../chunk-
|
|
42
|
-
import "../../../chunk-
|
|
41
|
+
} from "../../../chunk-KPEKD5SG.js";
|
|
42
|
+
import "../../../chunk-24HHUCWB.js";
|
|
43
43
|
import "../../../chunk-YCCWJ5XQ.js";
|
|
44
44
|
import "../../../chunk-R445KMGG.js";
|
|
45
45
|
import {
|
|
@@ -92,6 +92,7 @@ import "../../../chunk-5UX5QAFJ.js";
|
|
|
92
92
|
import "../../../chunk-Z2JH5KW5.js";
|
|
93
93
|
import "../../../chunk-AL5E624U.js";
|
|
94
94
|
import "../../../chunk-LV7LSPBF.js";
|
|
95
|
+
import "../../../chunk-PUFA7FQ7.js";
|
|
95
96
|
import "../../../chunk-5AK2EZG5.js";
|
|
96
97
|
import "../../../chunk-N5PVD4J5.js";
|
|
97
98
|
import "../../../chunk-6C5D6O3D.js";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SectionNavSheet
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NM46HQSW.js";
|
|
4
4
|
import {
|
|
5
5
|
RaisedActionButton
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-KPEKD5SG.js";
|
|
7
7
|
import {
|
|
8
8
|
Box,
|
|
9
9
|
CONTROL_RESET,
|
|
@@ -12,8 +12,9 @@ import {
|
|
|
12
12
|
SlotIcon,
|
|
13
13
|
controlProps,
|
|
14
14
|
destinationControl,
|
|
15
|
-
focusRing
|
|
16
|
-
|
|
15
|
+
focusRing,
|
|
16
|
+
useMounted
|
|
17
|
+
} from "./chunk-24HHUCWB.js";
|
|
17
18
|
import {
|
|
18
19
|
barSlots,
|
|
19
20
|
destinationState,
|
|
@@ -33,9 +34,9 @@ import Typography from "@mui/material/Typography/index.js";
|
|
|
33
34
|
import { alpha, useTheme } from "@mui/material/styles/index.js";
|
|
34
35
|
import { useState } from "react";
|
|
35
36
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
36
|
-
var barHeight = (theme) => rem(theme, 60);
|
|
37
|
-
function sectionNavBarInset(theme) {
|
|
38
|
-
return `calc(${barHeight(theme)} + env(safe-area-inset-bottom))`;
|
|
37
|
+
var barHeight = (theme, compact = false) => rem(theme, compact ? 48 : 60);
|
|
38
|
+
function sectionNavBarInset(theme, options = {}) {
|
|
39
|
+
return `calc(${barHeight(theme, options.compact === true)} + env(safe-area-inset-bottom))`;
|
|
39
40
|
}
|
|
40
41
|
function Slot({
|
|
41
42
|
label,
|
|
@@ -47,19 +48,22 @@ function Slot({
|
|
|
47
48
|
testId,
|
|
48
49
|
control,
|
|
49
50
|
expanded,
|
|
50
|
-
loading = false
|
|
51
|
+
loading = false,
|
|
52
|
+
compact = false
|
|
51
53
|
}) {
|
|
52
54
|
const theme = useTheme();
|
|
55
|
+
const animate = useMounted();
|
|
53
56
|
return /* @__PURE__ */ jsxs(
|
|
54
57
|
Box,
|
|
55
58
|
{
|
|
56
59
|
...control,
|
|
60
|
+
title: compact ? label : void 0,
|
|
57
61
|
"aria-current": current ? "page" : void 0,
|
|
58
62
|
"aria-expanded": expanded,
|
|
59
63
|
"aria-busy": loading || void 0,
|
|
60
64
|
"data-lit": lit ? "true" : void 0,
|
|
61
65
|
"data-testid": testId,
|
|
62
|
-
sx: slotSx(theme, lit),
|
|
66
|
+
sx: slotSx(theme, lit, compact),
|
|
63
67
|
children: [
|
|
64
68
|
/* @__PURE__ */ jsx(
|
|
65
69
|
CountedIcon,
|
|
@@ -83,7 +87,8 @@ function Slot({
|
|
|
83
87
|
whiteSpace: "nowrap",
|
|
84
88
|
lineHeight: 1.3,
|
|
85
89
|
fontWeight: lit ? 700 : 600,
|
|
86
|
-
color: lit ? "text.primary" : "inherit"
|
|
90
|
+
color: lit ? "text.primary" : "inherit",
|
|
91
|
+
...labelFoldSx(theme, compact, animate)
|
|
87
92
|
},
|
|
88
93
|
children: label
|
|
89
94
|
}
|
|
@@ -92,6 +97,14 @@ function Slot({
|
|
|
92
97
|
}
|
|
93
98
|
);
|
|
94
99
|
}
|
|
100
|
+
function labelFoldSx(theme, compact, animate) {
|
|
101
|
+
return {
|
|
102
|
+
maxHeight: compact ? 0 : rem(theme, 24),
|
|
103
|
+
opacity: compact ? 0 : 1,
|
|
104
|
+
transition: animate ? theme.transitions.create(["max-height", "opacity"], { duration: theme.transitions.duration.shorter }) : "none",
|
|
105
|
+
"@media (prefers-reduced-motion: reduce)": { transition: "none" }
|
|
106
|
+
};
|
|
107
|
+
}
|
|
95
108
|
function pillSx(theme) {
|
|
96
109
|
return {
|
|
97
110
|
display: "inline-flex",
|
|
@@ -103,7 +116,7 @@ function pillSx(theme) {
|
|
|
103
116
|
transition: theme.transitions.create("background-color", { duration: theme.transitions.duration.shorter })
|
|
104
117
|
};
|
|
105
118
|
}
|
|
106
|
-
function slotSx(theme, lit) {
|
|
119
|
+
function slotSx(theme, lit, compact) {
|
|
107
120
|
return {
|
|
108
121
|
...CONTROL_RESET,
|
|
109
122
|
...focusRing(theme),
|
|
@@ -113,7 +126,7 @@ function slotSx(theme, lit) {
|
|
|
113
126
|
flexDirection: "column",
|
|
114
127
|
alignItems: "center",
|
|
115
128
|
justifyContent: "center",
|
|
116
|
-
gap: 0.25,
|
|
129
|
+
gap: compact ? 0 : 0.25,
|
|
117
130
|
position: "relative",
|
|
118
131
|
color: lit ? "primary.main" : "text.secondary",
|
|
119
132
|
// The current slot is marked by more than its colour: a tinted pill behind
|
|
@@ -135,6 +148,7 @@ function PrimarySlot({
|
|
|
135
148
|
label: primary.label,
|
|
136
149
|
icon: primary.icon,
|
|
137
150
|
captioned: true,
|
|
151
|
+
compact: context.compact,
|
|
138
152
|
disabled: primary.disabled,
|
|
139
153
|
loading: primary.loading,
|
|
140
154
|
dataTestId: testId,
|
|
@@ -152,6 +166,7 @@ function PrimarySlot({
|
|
|
152
166
|
icon: primary.icon,
|
|
153
167
|
open: context.open === "primary",
|
|
154
168
|
closeLabel: context.copy.close,
|
|
169
|
+
compact: context.compact,
|
|
155
170
|
disabled: primary.disabled,
|
|
156
171
|
dataTestId: testId,
|
|
157
172
|
onClick: () => context.toggle("primary")
|
|
@@ -171,6 +186,7 @@ function MoreSlot({ more, context }) {
|
|
|
171
186
|
expanded: open === "more",
|
|
172
187
|
copy: context.copy,
|
|
173
188
|
testId: more.dataTestId ?? `${context.dataTestId}-more`,
|
|
189
|
+
compact: context.compact,
|
|
174
190
|
control: controlProps({
|
|
175
191
|
href: void 0,
|
|
176
192
|
linkComponent: context.linkComponent,
|
|
@@ -196,6 +212,7 @@ function DestinationSlot({
|
|
|
196
212
|
copy: context.copy,
|
|
197
213
|
testId: destination.dataTestId ?? `${context.dataTestId}-dest-${destination.id}`,
|
|
198
214
|
loading: destination.loading === true,
|
|
215
|
+
compact: context.compact,
|
|
199
216
|
control: destinationControl(destination, context.linkComponent, () => {
|
|
200
217
|
context.close();
|
|
201
218
|
destination.onSelect?.();
|
|
@@ -213,6 +230,30 @@ function BarSlotView({
|
|
|
213
230
|
if (slot.kind === "more") return more ? /* @__PURE__ */ jsx(MoreSlot, { more, context }) : null;
|
|
214
231
|
return /* @__PURE__ */ jsx(DestinationSlot, { destination: slot.destination, context });
|
|
215
232
|
}
|
|
233
|
+
function barSx(theme, sheetOpen, compact, animate) {
|
|
234
|
+
return {
|
|
235
|
+
flex: "none",
|
|
236
|
+
display: "flex",
|
|
237
|
+
alignItems: "stretch",
|
|
238
|
+
boxSizing: "border-box",
|
|
239
|
+
height: sectionNavBarInset(theme, { compact }),
|
|
240
|
+
// Folding to icons and back is a change of height the eye follows;
|
|
241
|
+
// with reduced motion it simply happens.
|
|
242
|
+
transition: animate ? theme.transitions.create("height", { duration: theme.transitions.duration.shorter }) : "none",
|
|
243
|
+
"@media (prefers-reduced-motion: reduce)": { transition: "none" },
|
|
244
|
+
paddingBottom: "env(safe-area-inset-bottom)",
|
|
245
|
+
borderTop: `1px solid ${theme.palette.divider}`,
|
|
246
|
+
bgcolor: "background.paper",
|
|
247
|
+
// Above the backdrop ONLY while one of its own sheets is open, so the
|
|
248
|
+
// primary button can close what it opened. Raised all the time it
|
|
249
|
+
// would sit over every dialog the page opens, and on a small phone a
|
|
250
|
+
// dialog's own footer is exactly where the bar is. `stackedOverlayZIndex`,
|
|
251
|
+
// not `zIndex.modal + 1`: a host lifting a bottom Drawer clear of a
|
|
252
|
+
// stacked sheet catches this bar's OWN sheets too.
|
|
253
|
+
position: "relative",
|
|
254
|
+
zIndex: sheetOpen ? stackedOverlayZIndex(theme) + 1 : "auto"
|
|
255
|
+
};
|
|
256
|
+
}
|
|
216
257
|
function SectionNavBar({
|
|
217
258
|
label,
|
|
218
259
|
destinations,
|
|
@@ -220,10 +261,12 @@ function SectionNavBar({
|
|
|
220
261
|
more,
|
|
221
262
|
linkComponent,
|
|
222
263
|
copy,
|
|
223
|
-
dataTestId
|
|
264
|
+
dataTestId,
|
|
265
|
+
compact = false
|
|
224
266
|
}) {
|
|
225
267
|
const sheetMenu = isMenu(primary) ? primary : void 0;
|
|
226
268
|
const theme = useTheme();
|
|
269
|
+
const animate = useMounted();
|
|
227
270
|
const [open, setOpen] = useState(null);
|
|
228
271
|
const toggle = (menu) => setOpen((current) => current === menu ? null : menu);
|
|
229
272
|
const close = () => setOpen(null);
|
|
@@ -234,31 +277,14 @@ function SectionNavBar({
|
|
|
234
277
|
component: "nav",
|
|
235
278
|
"aria-label": label,
|
|
236
279
|
"data-testid": dataTestId,
|
|
237
|
-
sx:
|
|
238
|
-
flex: "none",
|
|
239
|
-
display: "flex",
|
|
240
|
-
alignItems: "stretch",
|
|
241
|
-
boxSizing: "border-box",
|
|
242
|
-
height: sectionNavBarInset(theme),
|
|
243
|
-
paddingBottom: "env(safe-area-inset-bottom)",
|
|
244
|
-
borderTop: `1px solid ${theme.palette.divider}`,
|
|
245
|
-
bgcolor: "background.paper",
|
|
246
|
-
// Above the backdrop ONLY while one of its own sheets is open, so the
|
|
247
|
-
// primary button can close what it opened. Raised all the time it
|
|
248
|
-
// would sit over every dialog the page opens, and on a small phone a
|
|
249
|
-
// dialog's own footer is exactly where the bar is. `stackedOverlayZIndex`,
|
|
250
|
-
// not `zIndex.modal + 1`: a host lifting a bottom Drawer clear of a
|
|
251
|
-
// stacked sheet catches this bar's OWN sheets too.
|
|
252
|
-
position: "relative",
|
|
253
|
-
zIndex: open === null ? "auto" : stackedOverlayZIndex(theme) + 1
|
|
254
|
-
},
|
|
280
|
+
sx: barSx(theme, open !== null, compact, animate),
|
|
255
281
|
children: barSlots(destinations, more !== void 0, primary !== void 0).map((slot) => /* @__PURE__ */ jsx(
|
|
256
282
|
BarSlotView,
|
|
257
283
|
{
|
|
258
284
|
slot,
|
|
259
285
|
primary,
|
|
260
286
|
more,
|
|
261
|
-
context: { open, toggle, close, linkComponent, copy, dataTestId }
|
|
287
|
+
context: { open, toggle, close, linkComponent, copy, dataTestId, compact }
|
|
262
288
|
},
|
|
263
289
|
slot.kind === "destination" ? `dest-${slot.destination.id}` : `menu-${slot.kind}`
|
|
264
290
|
))
|
|
@@ -273,7 +299,7 @@ function SectionNavBar({
|
|
|
273
299
|
linkComponent,
|
|
274
300
|
copy,
|
|
275
301
|
testId: `${dataTestId}-primary-sheet`,
|
|
276
|
-
bottomOffset: sectionNavBarInset(theme)
|
|
302
|
+
bottomOffset: sectionNavBarInset(theme, { compact })
|
|
277
303
|
}
|
|
278
304
|
) : null,
|
|
279
305
|
more ? /* @__PURE__ */ jsx(
|
|
@@ -285,7 +311,7 @@ function SectionNavBar({
|
|
|
285
311
|
linkComponent,
|
|
286
312
|
copy,
|
|
287
313
|
testId: `${dataTestId}-more-sheet`,
|
|
288
|
-
bottomOffset: sectionNavBarInset(theme)
|
|
314
|
+
bottomOffset: sectionNavBarInset(theme, { compact })
|
|
289
315
|
}
|
|
290
316
|
) : null
|
|
291
317
|
] });
|
|
@@ -295,4 +321,4 @@ export {
|
|
|
295
321
|
sectionNavBarInset,
|
|
296
322
|
SectionNavBar
|
|
297
323
|
};
|
|
298
|
-
//# sourceMappingURL=chunk-
|
|
324
|
+
//# sourceMappingURL=chunk-23LPXHR2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.bar.tsx"],"sourcesContent":["import Typography from '@mui/material/Typography/index.js';\nimport { alpha, useTheme, type SxProps, type Theme } from '@mui/material/styles/index.js';\nimport { useState, type ElementType, type ReactNode } from 'react';\n\nimport type { SectionNavCopy } from '../../../copy';\nimport { stackedOverlayZIndex } from '../../../tokens/layers';\nimport { rem } from '../../../tokens/scales';\n\nimport { barSlots, destinationState, isMenu, menuActive, menuCount, type BarSlot } from './SectionNav.helpers';\nimport {\n Box,\n CONTROL_RESET,\n CountedIcon,\n NOT_LIVE,\n SlotIcon,\n controlProps,\n useMounted,\n destinationControl,\n focusRing,\n} from './SectionNav.parts';\nimport { RaisedActionButton } from './SectionNav.primary';\nimport { SectionNavSheet } from './SectionNav.sheet';\nimport type { SectionNavAction, SectionNavBadge, SectionNavDestination, SectionNavMenu, SectionNavProps } from './SectionNav.types';\n\n/** Which of the bar's two menus is open, if any. */\ntype OpenMenu = 'primary' | 'more' | null;\n\n/**\n * The bar's height above the safe area — tall enough for an icon over a label;\n * a compact bar holds the icon alone.\n */\nconst barHeight = (theme: Parameters<typeof rem>[0], compact = false): string => rem(theme, compact ? 48 : 60);\n\n/** How the bar is drawn — `compact` is `SectionNavProps.compact`. */\nexport interface SectionNavBarOptions {\n compact?: boolean;\n}\n\n/**\n * The bar's full height on screen, the safe area included — where its sheets\n * stop, and what a host reserves at the foot of its content so nothing it\n * floats (a toast, a receipt) lands under the bar.\n */\nexport function sectionNavBarInset(theme: Parameters<typeof rem>[0], options: SectionNavBarOptions = {}): string {\n return `calc(${barHeight(theme, options.compact === true)} + env(safe-area-inset-bottom))`;\n}\n\n/**\n * One slot: icon over label, a count on the icon.\n *\n * `current` is the page the viewer is on and is what `aria-current` reports —\n * a link's claim only; an action slot that is ON says so with `aria-pressed`,\n * which arrives in `control`. `lit` is only how the slot looks, and goes out\n * while a sheet is open so the bar shows where the thumb is. Opening a sheet\n * is `aria-expanded`'s to say.\n *\n * A destination is a link or an action; the \"more\" slot is a button that\n * opens its sheet. Either way the whole slot is the target, so a thumb landing\n * on the label lands on the control. A `disabled` slot is a disabled button,\n * dimmed — the act is still where the hand expects it. A `loading` or\n * `dimmed` slot is drawn the same and stays focusable (`aria-disabled`).\n */\nfunction Slot({\n label,\n icon,\n count,\n current,\n lit,\n copy,\n testId,\n control,\n expanded,\n loading = false,\n compact = false,\n}: {\n label: string;\n icon: ReactNode;\n count: SectionNavBadge | undefined;\n current: boolean;\n lit: boolean;\n copy: SectionNavCopy;\n testId: string;\n control: Record<string, unknown>;\n expanded?: boolean;\n loading?: boolean;\n /** Icon only: the label stays the slot's name, out of sight, and its tooltip. */\n compact?: boolean;\n}): React.JSX.Element {\n const theme = useTheme();\n const animate = useMounted();\n return (\n <Box\n {...control}\n title={compact ? label : undefined}\n aria-current={current ? 'page' : undefined}\n aria-expanded={expanded}\n aria-busy={loading || undefined}\n data-lit={lit ? 'true' : undefined}\n data-testid={testId}\n sx={slotSx(theme, lit, compact)}\n >\n <CountedIcon\n icon={\n <Box component=\"span\" data-slot-pill=\"\" sx={pillSx(theme)}>\n <SlotIcon icon={icon} loading={loading} />\n </Box>\n }\n count={count}\n label={copy.badge}\n attentionLabel={copy.attention}\n testId={`${testId}-badge`}\n />\n <Typography\n component=\"span\"\n variant=\"caption\"\n sx={{\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n lineHeight: 1.3,\n fontWeight: lit ? 700 : 600,\n color: lit ? 'text.primary' : 'inherit',\n ...labelFoldSx(theme, compact, animate),\n }}\n >\n {label}\n </Typography>\n </Box>\n );\n}\n\n/**\n * The label folding away in a compact bar: it shrinks to no height and fades\n * while the bar shrinks, rather than leaving in one frame. Never `display:\n * none` — it is still the slot's accessible name. With reduced motion it\n * simply goes.\n */\nfunction labelFoldSx(theme: Theme, compact: boolean, animate: boolean): Record<string, unknown> {\n return {\n maxHeight: compact ? 0 : rem(theme, 24),\n opacity: compact ? 0 : 1,\n transition: animate\n ? theme.transitions.create(['max-height', 'opacity'], { duration: theme.transitions.duration.shorter })\n : 'none',\n '@media (prefers-reduced-motion: reduce)': { transition: 'none' },\n };\n}\n\n/** The pill behind a slot's icon — tinted while the slot is lit. */\nfunction pillSx(theme: Theme): SxProps<Theme> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n px: 1.75,\n py: 0.25,\n borderRadius: rem(theme, 999),\n transition: theme.transitions.create('background-color', { duration: theme.transitions.duration.shorter }),\n };\n}\n\n/** A slot's look: icon over label, a pill behind the lit icon, dimmed when disabled. */\nfunction slotSx(theme: Theme, lit: boolean, compact: boolean): SxProps<Theme> {\n return {\n ...CONTROL_RESET,\n ...focusRing(theme),\n flex: 1,\n minWidth: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: compact ? 0 : 0.25,\n position: 'relative',\n color: lit ? 'primary.main' : 'text.secondary',\n // The current slot is marked by more than its colour: a tinted pill behind\n // its icon and a bolder label, so the state survives a colour-blind reading.\n '&[data-lit=\"true\"] [data-slot-pill]': { bgcolor: alpha(theme.palette.primary.main, 0.14) },\n '& svg': { fontSize: rem(theme, 22) },\n [NOT_LIVE]: { color: 'text.disabled' },\n } as SxProps<Theme>;\n}\n\n/** What every slot kind is handed: the bar's open state and how to change it. */\ninterface SlotContext {\n open: OpenMenu;\n toggle: (menu: Exclude<OpenMenu, null>) => void;\n close: () => void;\n linkComponent: ElementType | undefined;\n copy: SectionNavCopy;\n dataTestId: string;\n compact: boolean;\n}\n\n/** The raised button: an action runs on tap; a menu opens its sheet. */\nfunction PrimarySlot({\n primary,\n context,\n}: {\n primary: SectionNavMenu | SectionNavAction;\n context: SlotContext;\n}): React.JSX.Element {\n const testId = primary.dataTestId ?? `${context.dataTestId}-primary`;\n if (!isMenu(primary)) {\n return (\n <RaisedActionButton\n label={primary.label}\n icon={primary.icon}\n captioned\n compact={context.compact}\n disabled={primary.disabled}\n loading={primary.loading}\n dataTestId={testId}\n onClick={() => {\n context.close();\n primary.onSelect();\n }}\n />\n );\n }\n return (\n <RaisedActionButton\n label={primary.label}\n icon={primary.icon}\n open={context.open === 'primary'}\n closeLabel={context.copy.close}\n compact={context.compact}\n disabled={primary.disabled}\n dataTestId={testId}\n onClick={() => context.toggle('primary')}\n />\n );\n}\n\n/** The \"more\" slot: a button that opens its sheet, carrying its entries' counts. */\nfunction MoreSlot({ more, context }: { more: SectionNavMenu; context: SlotContext }): React.JSX.Element {\n const { open } = context;\n return (\n <Slot\n label={more.label}\n icon={more.icon}\n count={menuCount(more)}\n current={false}\n lit={open === 'more' || (open === null && menuActive(more))}\n expanded={open === 'more'}\n copy={context.copy}\n testId={more.dataTestId ?? `${context.dataTestId}-more`}\n compact={context.compact}\n control={controlProps({\n href: undefined,\n linkComponent: context.linkComponent,\n inert: more.disabled === true,\n onClick: () => context.toggle('more'),\n })}\n />\n );\n}\n\n/** A destination: a link, or an action slot (a toggle when it carries `active`). */\nfunction DestinationSlot({\n destination,\n context,\n}: {\n destination: SectionNavDestination;\n context: SlotContext;\n}): React.JSX.Element {\n const { current, lit } = destinationState(destination);\n return (\n <Slot\n label={destination.label}\n icon={destination.icon}\n count={destination.badge}\n current={current}\n lit={context.open === null && lit}\n copy={context.copy}\n testId={destination.dataTestId ?? `${context.dataTestId}-dest-${destination.id}`}\n loading={destination.loading === true}\n compact={context.compact}\n control={destinationControl(destination, context.linkComponent, () => {\n context.close();\n destination.onSelect?.();\n })}\n />\n );\n}\n\n/** One slot of the bar, whichever kind it is. */\nfunction BarSlotView({\n slot,\n primary,\n more,\n context,\n}: {\n slot: BarSlot;\n primary: SectionNavMenu | SectionNavAction | undefined;\n more: SectionNavMenu | undefined;\n context: SlotContext;\n}): React.JSX.Element | null {\n if (slot.kind === 'primary') return primary ? <PrimarySlot primary={primary} context={context} /> : null;\n if (slot.kind === 'more') return more ? <MoreSlot more={more} context={context} /> : null;\n return <DestinationSlot destination={slot.destination} context={context} />;\n}\n\n/** The bar's own box: docked, a hairline on top, raised over the backdrop only while its sheet is open. */\nfunction barSx(theme: Theme, sheetOpen: boolean, compact: boolean, animate: boolean): SxProps<Theme> {\n return {\n flex: 'none',\n display: 'flex',\n alignItems: 'stretch',\n boxSizing: 'border-box',\n height: sectionNavBarInset(theme, { compact }),\n // Folding to icons and back is a change of height the eye follows;\n // with reduced motion it simply happens.\n transition: animate ? theme.transitions.create('height', { duration: theme.transitions.duration.shorter }) : 'none',\n '@media (prefers-reduced-motion: reduce)': { transition: 'none' },\n paddingBottom: 'env(safe-area-inset-bottom)',\n borderTop: `1px solid ${theme.palette.divider}`,\n bgcolor: 'background.paper',\n // Above the backdrop ONLY while one of its own sheets is open, so the\n // primary button can close what it opened. Raised all the time it\n // would sit over every dialog the page opens, and on a small phone a\n // dialog's own footer is exactly where the bar is. `stackedOverlayZIndex`,\n // not `zIndex.modal + 1`: a host lifting a bottom Drawer clear of a\n // stacked sheet catches this bar's OWN sheets too.\n position: 'relative',\n zIndex: sheetOpen ? stackedOverlayZIndex(theme) + 1 : 'auto',\n } as SxProps<Theme>;\n}\n\n/** The phone layout: a bottom bar, with its menus as bottom sheets. */\nexport function SectionNavBar({\n label,\n destinations,\n primary,\n more,\n linkComponent,\n copy,\n dataTestId,\n compact = false,\n}: Required<Pick<SectionNavProps, 'label' | 'destinations' | 'copy' | 'dataTestId'>> &\n Pick<SectionNavProps, 'primary' | 'more' | 'compact'> & { linkComponent: ElementType | undefined }): React.JSX.Element {\n const sheetMenu = isMenu(primary) ? primary : undefined;\n const theme = useTheme();\n const animate = useMounted();\n const [open, setOpen] = useState<OpenMenu>(null);\n const toggle = (menu: Exclude<OpenMenu, null>): void => setOpen((current) => (current === menu ? null : menu));\n const close = (): void => setOpen(null);\n\n return (\n <>\n <Box\n component=\"nav\"\n aria-label={label}\n data-testid={dataTestId}\n sx={barSx(theme, open !== null, compact, animate)}\n >\n {barSlots(destinations, more !== undefined, primary !== undefined).map((slot) => (\n <BarSlotView\n key={slot.kind === 'destination' ? `dest-${slot.destination.id}` : `menu-${slot.kind}`}\n slot={slot}\n primary={primary}\n more={more}\n context={{ open, toggle, close, linkComponent, copy, dataTestId, compact }}\n />\n ))}\n </Box>\n {sheetMenu ? (\n <SectionNavSheet\n menu={sheetMenu}\n open={open === 'primary'}\n onClose={close}\n linkComponent={linkComponent}\n copy={copy}\n testId={`${dataTestId}-primary-sheet`}\n bottomOffset={sectionNavBarInset(theme, { compact })}\n />\n ) : null}\n {more ? (\n <SectionNavSheet\n menu={more}\n open={open === 'more'}\n onClose={close}\n linkComponent={linkComponent}\n copy={copy}\n testId={`${dataTestId}-more-sheet`}\n bottomOffset={sectionNavBarInset(theme, { compact })}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
shownCount
|
|
3
3
|
} from "./chunk-YCCWJ5XQ.js";
|
|
4
|
+
import {
|
|
5
|
+
SR_ONLY_SX
|
|
6
|
+
} from "./chunk-PUFA7FQ7.js";
|
|
4
7
|
import {
|
|
5
8
|
Badge
|
|
6
9
|
} from "./chunk-N5PVD4J5.js";
|
|
@@ -11,6 +14,7 @@ import {
|
|
|
11
14
|
// src/components/navigation/SectionNav/SectionNav.parts.tsx
|
|
12
15
|
import Box from "@mui/material/Box/index.js";
|
|
13
16
|
import CircularProgress from "@mui/material/CircularProgress/index.js";
|
|
17
|
+
import { useEffect, useState } from "react";
|
|
14
18
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
15
19
|
function CountedIcon({
|
|
16
20
|
icon,
|
|
@@ -92,6 +96,12 @@ var CONTROL_RESET = {
|
|
|
92
96
|
margin: 0,
|
|
93
97
|
[NOT_LIVE]: { cursor: "default" }
|
|
94
98
|
};
|
|
99
|
+
var VISUALLY_HIDDEN = SR_ONLY_SX;
|
|
100
|
+
function useMounted() {
|
|
101
|
+
const [mounted, setMounted] = useState(false);
|
|
102
|
+
useEffect(() => setMounted(true), []);
|
|
103
|
+
return mounted;
|
|
104
|
+
}
|
|
95
105
|
|
|
96
106
|
export {
|
|
97
107
|
Box,
|
|
@@ -101,6 +111,8 @@ export {
|
|
|
101
111
|
destinationControl,
|
|
102
112
|
NOT_LIVE,
|
|
103
113
|
SlotIcon,
|
|
104
|
-
CONTROL_RESET
|
|
114
|
+
CONTROL_RESET,
|
|
115
|
+
VISUALLY_HIDDEN,
|
|
116
|
+
useMounted
|
|
105
117
|
};
|
|
106
|
-
//# sourceMappingURL=chunk-
|
|
118
|
+
//# sourceMappingURL=chunk-24HHUCWB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.parts.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport CircularProgress from '@mui/material/CircularProgress/index.js';\nimport type { SxProps, Theme } from '@mui/material/styles/index.js';\nimport { useEffect, useState, type ElementType, type ReactNode } from 'react';\n\nimport { rem } from '../../../tokens/scales';\nimport { SR_ONLY_SX } from '../../form/Label/Label.styles';\nimport { Badge } from '../../data-display/Badge';\n\nimport { shownCount } from './SectionNav.helpers';\nimport type { SectionNavBadge, SectionNavDestination } from './SectionNav.types';\n\n/**\n * An icon with its count on the shoulder.\n *\n * Quiet to assistive tech on change: the count moves on a poll, and a control\n * that announces itself every minute is noise. Its NAME carries the number,\n * so it is read when the control is.\n */\nexport function CountedIcon({\n icon,\n count,\n label,\n testId,\n attentionLabel,\n}: {\n icon: ReactNode;\n count: SectionNavBadge | undefined;\n label: (count: number) => string;\n testId: string;\n /** The \"!\" badge's accessible name (`SectionNavCopy.attention`). */\n attentionLabel?: string;\n}): React.JSX.Element {\n if (count === '!') {\n return (\n <Badge content=\"!\" variant=\"count\" color=\"warning\" aria-label={attentionLabel ?? label(1)} aria-live=\"off\" data-testid={testId}>\n {icon}\n </Badge>\n );\n }\n const shown = shownCount(count);\n if (shown === undefined) return <>{icon}</>;\n return (\n // The library's corner count, in the warning role the sidebar's pill is\n // drawn from.\n <Badge\n content={shown}\n variant=\"count\"\n color=\"warning\"\n max={99}\n aria-label={label(shown)}\n aria-live=\"off\"\n data-testid={testId}\n >\n {icon}\n </Badge>\n );\n}\n\n/** The keyboard ring every control in the nav draws, in the theme's own colour. */\nexport function focusRing(theme: Theme): SxProps<Theme> {\n return {\n '&:focus-visible': {\n outline: `${rem(theme, 2)} solid ${theme.palette.primary.main}`,\n outlineOffset: rem(theme, -2),\n },\n };\n}\n\n/**\n * The element an entry or destination renders as: the host's link for an\n * `href`, a button for an `onSelect`.\n *\n * Returned as props for a `Box`, so the control stays ONE interactive\n * element — never a button wrapped around a link. Whatever it would lead to,\n * a control that is not live is a BUTTON: a link cannot be disabled, and one\n * that looks dimmed but still navigates is the lie this rules out.\n *\n * - `inert` — a native `disabled` button: no focus, no click.\n * - `busy` — a write is in flight: `aria-disabled`, still focusable, and the\n * click is dropped, so the keyboard keeps its place until the write answers.\n * - `dimmed` — `aria-disabled`, still focusable, and the click STILL runs, so\n * the host can explain why the act cannot be done now.\n */\nexport function controlProps({\n href,\n onClick,\n linkComponent,\n inert = false,\n busy = false,\n dimmed = false,\n}: {\n href: string | undefined;\n onClick?: () => void;\n linkComponent: ElementType | undefined;\n inert?: boolean;\n busy?: boolean;\n dimmed?: boolean;\n}): Record<string, unknown> {\n if (inert) return { component: 'button', type: 'button', disabled: true };\n if (busy) return { component: 'button', type: 'button', 'aria-disabled': 'true' };\n if (dimmed) return { component: 'button', type: 'button', 'aria-disabled': 'true', onClick };\n if (href !== undefined) return { component: linkComponent ?? 'a', href, onClick };\n return { component: 'button', type: 'button', onClick };\n}\n\n/**\n * A destination's control: `controlProps` from its own state, plus\n * `aria-pressed` when it is an action slot that is a toggle. A link reports\n * where the viewer is through `aria-current` instead — the row draws that.\n */\nexport function destinationControl(\n destination: SectionNavDestination,\n linkComponent: ElementType | undefined,\n onClick: () => void,\n): Record<string, unknown> {\n return {\n ...controlProps({\n href: destination.href,\n linkComponent,\n inert: destination.disabled === true,\n busy: destination.loading === true,\n dimmed: destination.dimmed === true,\n onClick,\n }),\n 'aria-pressed': destination.href === undefined ? destination.active : undefined,\n };\n}\n\n/**\n * The selector for a control drawn as not live: natively disabled, or\n * `aria-disabled` (in flight, or dimmed) and still focusable.\n */\nexport const NOT_LIVE = '&:disabled, &[aria-disabled=\"true\"]';\n\n/**\n * The icon, or the spinner that stands in for it while the slot's write is in\n * flight — the same box, so the label under it does not move.\n */\nexport function SlotIcon({ icon, loading }: { icon: ReactNode; loading: boolean }): React.JSX.Element {\n if (!loading) return <>{icon}</>;\n return <CircularProgress size=\"1em\" color=\"inherit\" thickness={5} data-testid=\"section-nav-spinner\" />;\n}\n\n/** The base reset every clickable in the nav shares: no underline, no button chrome. */\nexport const CONTROL_RESET = {\n border: 0,\n background: 'none',\n font: 'inherit',\n color: 'inherit',\n textDecoration: 'none',\n cursor: 'pointer',\n margin: 0,\n [NOT_LIVE]: { cursor: 'default' },\n} as const;\n\n/**\n * Out of sight, still read: a compact nav keeps each label as its control's\n * accessible name. The same box `Label`'s `srOnly` draws.\n */\nexport const VISUALLY_HIDDEN = SR_ONLY_SX;\n\n/**\n * False on the first render, true from then on — so a fold animates when the\n * host CHANGES `compact`, never when a page simply opens folded (which drew\n * the labels sliding out over the neighbouring badges on every load).\n */\nexport function useMounted(): boolean {\n const [mounted, setMounted] = useState(false);\n useEffect(() => setMounted(true), []);\n return mounted;\n}\n\nexport { Box };\n"],"mappings":";;;;;;;;;;;;;;AAAA,OAAO,SAAS;AAChB,OAAO,sBAAsB;AAE7B,SAAS,WAAW,gBAAkD;AAgChE,SAM4B,UAN5B;AAhBC,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAOsB;AACpB,MAAI,UAAU,KAAK;AACjB,WACE,oBAAC,SAAM,SAAQ,KAAI,SAAQ,SAAQ,OAAM,WAAU,cAAY,kBAAkB,MAAM,CAAC,GAAG,aAAU,OAAM,eAAa,QACrH,gBACH;AAAA,EAEJ;AACA,QAAM,QAAQ,WAAW,KAAK;AAC9B,MAAI,UAAU,OAAW,QAAO,gCAAG,gBAAK;AACxC;AAAA;AAAA;AAAA,IAGE;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,SAAQ;AAAA,QACR,OAAM;AAAA,QACN,KAAK;AAAA,QACL,cAAY,MAAM,KAAK;AAAA,QACvB,aAAU;AAAA,QACV,eAAa;AAAA,QAEZ;AAAA;AAAA,IACH;AAAA;AAEJ;AAGO,SAAS,UAAU,OAA8B;AACtD,SAAO;AAAA,IACL,mBAAmB;AAAA,MACjB,SAAS,GAAG,IAAI,OAAO,CAAC,CAAC,UAAU,MAAM,QAAQ,QAAQ,IAAI;AAAA,MAC7D,eAAe,IAAI,OAAO,EAAE;AAAA,IAC9B;AAAA,EACF;AACF;AAiBO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,SAAS;AACX,GAO4B;AAC1B,MAAI,MAAO,QAAO,EAAE,WAAW,UAAU,MAAM,UAAU,UAAU,KAAK;AACxE,MAAI,KAAM,QAAO,EAAE,WAAW,UAAU,MAAM,UAAU,iBAAiB,OAAO;AAChF,MAAI,OAAQ,QAAO,EAAE,WAAW,UAAU,MAAM,UAAU,iBAAiB,QAAQ,QAAQ;AAC3F,MAAI,SAAS,OAAW,QAAO,EAAE,WAAW,iBAAiB,KAAK,MAAM,QAAQ;AAChF,SAAO,EAAE,WAAW,UAAU,MAAM,UAAU,QAAQ;AACxD;AAOO,SAAS,mBACd,aACA,eACA,SACyB;AACzB,SAAO;AAAA,IACL,GAAG,aAAa;AAAA,MACd,MAAM,YAAY;AAAA,MAClB;AAAA,MACA,OAAO,YAAY,aAAa;AAAA,MAChC,MAAM,YAAY,YAAY;AAAA,MAC9B,QAAQ,YAAY,WAAW;AAAA,MAC/B;AAAA,IACF,CAAC;AAAA,IACD,gBAAgB,YAAY,SAAS,SAAY,YAAY,SAAS;AAAA,EACxE;AACF;AAMO,IAAM,WAAW;AAMjB,SAAS,SAAS,EAAE,MAAM,QAAQ,GAA6D;AACpG,MAAI,CAAC,QAAS,QAAO,gCAAG,gBAAK;AAC7B,SAAO,oBAAC,oBAAiB,MAAK,OAAM,OAAM,WAAU,WAAW,GAAG,eAAY,uBAAsB;AACtG;AAGO,IAAM,gBAAgB;AAAA,EAC3B,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,CAAC,QAAQ,GAAG,EAAE,QAAQ,UAAU;AAClC;AAMO,IAAM,kBAAkB;AAOxB,SAAS,aAAsB;AACpC,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,YAAU,MAAM,WAAW,IAAI,GAAG,CAAC,CAAC;AACpC,SAAO;AACT;","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CountedIcon
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-24HHUCWB.js";
|
|
4
4
|
import {
|
|
5
5
|
rem
|
|
6
6
|
} from "./chunk-YKCAJ2TN.js";
|
|
@@ -59,11 +59,19 @@ function entryItem(groupId, entry, linkComponent, copy, testId, close) {
|
|
|
59
59
|
`${groupId}:${entry.id}`
|
|
60
60
|
);
|
|
61
61
|
}
|
|
62
|
+
function createButtonForm(menu, compact) {
|
|
63
|
+
if (!compact) return { startIcon: menu.icon, "aria-label": void 0, title: void 0 };
|
|
64
|
+
return { startIcon: void 0, "aria-label": menu.label, title: menu.label };
|
|
65
|
+
}
|
|
66
|
+
function createButtonLayoutSx(compact) {
|
|
67
|
+
return compact ? { justifyContent: "center", minWidth: 0, px: 0 } : { justifyContent: "flex-start", px: 1.75 };
|
|
68
|
+
}
|
|
62
69
|
function RailCreateMenu({
|
|
63
70
|
menu,
|
|
64
71
|
linkComponent,
|
|
65
72
|
copy,
|
|
66
|
-
testId
|
|
73
|
+
testId,
|
|
74
|
+
compact = false
|
|
67
75
|
}) {
|
|
68
76
|
const theme = useTheme();
|
|
69
77
|
const menuId = useId();
|
|
@@ -81,7 +89,7 @@ function RailCreateMenu({
|
|
|
81
89
|
{
|
|
82
90
|
variant: "contained",
|
|
83
91
|
fullWidth: true,
|
|
84
|
-
|
|
92
|
+
...createButtonForm(menu, compact),
|
|
85
93
|
disabled: menu.disabled === true,
|
|
86
94
|
"aria-haspopup": "menu",
|
|
87
95
|
"aria-expanded": open,
|
|
@@ -91,13 +99,14 @@ function RailCreateMenu({
|
|
|
91
99
|
sx: {
|
|
92
100
|
my: 1,
|
|
93
101
|
minHeight: rem(theme, 40),
|
|
94
|
-
|
|
95
|
-
px: 1.75,
|
|
102
|
+
...createButtonLayoutSx(compact),
|
|
96
103
|
fontWeight: 600,
|
|
97
104
|
// A place in the rail reads in sentence case, like the rows under it.
|
|
98
|
-
textTransform: "none"
|
|
105
|
+
textTransform: "none",
|
|
106
|
+
// The ring outside the filled button, where it can be seen.
|
|
107
|
+
"&.Mui-focusVisible": { outline: `${rem(theme, 2)} solid ${theme.palette.primary.main}`, outlineOffset: rem(theme, 2) }
|
|
99
108
|
},
|
|
100
|
-
children: menu.label
|
|
109
|
+
children: compact ? menu.icon : menu.label
|
|
101
110
|
}
|
|
102
111
|
),
|
|
103
112
|
/* @__PURE__ */ jsx(
|
|
@@ -124,4 +133,4 @@ function RailCreateMenu({
|
|
|
124
133
|
export {
|
|
125
134
|
RailCreateMenu
|
|
126
135
|
};
|
|
127
|
-
//# sourceMappingURL=chunk-
|
|
136
|
+
//# sourceMappingURL=chunk-ILJ3FXIC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.railCreate.tsx"],"sourcesContent":["import Button from '@mui/material/Button/index.js';\nimport ListItemIcon from '@mui/material/ListItemIcon/index.js';\nimport ListItemText from '@mui/material/ListItemText/index.js';\nimport ListSubheader from '@mui/material/ListSubheader/index.js';\nimport Menu from '@mui/material/Menu/index.js';\nimport MenuItem from '@mui/material/MenuItem/index.js';\nimport { useTheme, type SxProps, type Theme } from '@mui/material/styles/index.js';\nimport { useId, useState, type ElementType, type ReactNode } from 'react';\n\nimport type { SectionNavCopy } from '../../../copy';\nimport { rem } from '../../../tokens/scales';\n\nimport { CountedIcon } from './SectionNav.parts';\nimport type { SectionNavEntry, SectionNavMenu } from './SectionNav.types';\n\n/** One entry of the open menu: a link through the host's router, or an act. */\nfunction entryItem(\n groupId: string,\n entry: SectionNavEntry,\n linkComponent: ElementType | undefined,\n copy: SectionNavCopy,\n testId: string,\n close: () => void,\n): ReactNode {\n const link =\n entry.href === undefined || entry.disabled === true\n ? {}\n : { component: linkComponent ?? 'a', href: entry.href };\n const itemTestId = entry.dataTestId ?? `${testId}-entry-${entry.id}`;\n return (\n <MenuItem\n key={`${groupId}:${entry.id}`}\n {...link}\n disabled={entry.disabled === true}\n selected={entry.active === true}\n aria-current={entry.active === true ? 'page' : undefined}\n data-testid={itemTestId}\n onClick={() => {\n entry.onSelect?.();\n close();\n }}\n sx={{ gap: 1.5, py: 1, whiteSpace: 'normal' }}\n >\n <ListItemIcon sx={{ minWidth: 0, color: 'primary.main' }}>\n <CountedIcon\n icon={entry.icon}\n count={entry.badge}\n label={copy.badge}\n attentionLabel={copy.attention}\n testId={`${itemTestId}-badge`}\n />\n </ListItemIcon>\n <ListItemText\n primary={entry.label}\n secondary={entry.description}\n slotProps={{\n primary: { variant: 'body2', fontWeight: 500 },\n secondary: { variant: 'caption' },\n }}\n sx={{ my: 0 }}\n />\n </MenuItem>\n );\n}\n\n/** The button's icon and names: the icon in front of the label, or — compact — the icon alone, named by the label. */\nfunction createButtonForm(\n menu: SectionNavMenu,\n compact: boolean,\n): { startIcon: ReactNode; 'aria-label': string | undefined; title: string | undefined } {\n if (!compact) return { startIcon: menu.icon, 'aria-label': undefined, title: undefined };\n return { startIcon: undefined, 'aria-label': menu.label, title: menu.label };\n}\n\n/** Where the button's content sits: the label's start, or — compact — the icon centred. */\nfunction createButtonLayoutSx(compact: boolean): SxProps<Theme> {\n return compact ? { justifyContent: 'center', minWidth: 0, px: 0 } : { justifyContent: 'flex-start', px: 1.75 };\n}\n\n/**\n * A rail's `primary` menu as ONE button at the top of the rail, opening an\n * anchored menu of its groups (FUT-3015).\n *\n * The rail lists `more` in full, but a create menu listed that way costs a\n * heading and a two-line row per entry above the fold, for acts a person takes\n * once in a while. Folded behind '+ Criar' it costs one row. The button\n * carries the menu's `label`; the open menu is named by its `title`.\n *\n * `MenuList` skips the group subheaders when the keyboard moves, and the\n * popover hands focus back to the button when it closes on Escape or an\n * outside click. Choosing an entry closes it too, and the entry's link or act\n * takes over.\n */\nexport function RailCreateMenu({\n menu,\n linkComponent,\n copy,\n testId,\n compact = false,\n}: {\n menu: SectionNavMenu;\n linkComponent: ElementType | undefined;\n copy: SectionNavCopy;\n testId: string;\n /** The button as its icon only — the label stays its name and its tooltip. */\n compact?: boolean;\n}): React.JSX.Element {\n const theme = useTheme();\n const menuId = useId();\n const [anchor, setAnchor] = useState<HTMLElement | null>(null);\n const open = anchor !== null;\n const close = (): void => setAnchor(null);\n const paperTestId: Record<string, string> = { 'data-testid': `${testId}-menu` };\n // One flat list: MUI's MenuList walks its direct children, so a group's\n // subheader and entries cannot sit inside a wrapper.\n const items: ReactNode[] = menu.groups.flatMap((group) => [\n group.title ? (\n <ListSubheader key={`${group.id}-title`} disableSticky sx={{ lineHeight: 2.5, bgcolor: 'transparent' }}>\n {group.title}\n </ListSubheader>\n ) : null,\n ...group.entries.map((entry) => entryItem(group.id, entry, linkComponent, copy, testId, close)),\n ]);\n return (\n <>\n <Button\n variant=\"contained\"\n fullWidth\n {...createButtonForm(menu, compact)}\n disabled={menu.disabled === true}\n aria-haspopup=\"menu\"\n aria-expanded={open}\n aria-controls={open ? menuId : undefined}\n data-testid={menu.dataTestId ?? testId}\n onClick={(event) => setAnchor(event.currentTarget)}\n sx={{\n my: 1,\n minHeight: rem(theme, 40),\n ...(createButtonLayoutSx(compact) as object),\n fontWeight: 600,\n // A place in the rail reads in sentence case, like the rows under it.\n textTransform: 'none',\n // The ring outside the filled button, where it can be seen.\n '&.Mui-focusVisible': { outline: `${rem(theme, 2)} solid ${theme.palette.primary.main}`, outlineOffset: rem(theme, 2) },\n }}\n >\n {compact ? menu.icon : menu.label}\n </Button>\n <Menu\n id={menuId}\n anchorEl={anchor}\n open={open}\n onClose={close}\n variant=\"menu\"\n anchorOrigin={{ vertical: 'bottom', horizontal: 'left' }}\n transformOrigin={{ vertical: 'top', horizontal: 'left' }}\n slotProps={{\n list: { 'aria-label': menu.title },\n // A data attribute is not a declared slot prop, so it rides a spread.\n paper: { ...paperTestId, sx: { minWidth: rem(theme, 260), maxWidth: rem(theme, 340) } },\n }}\n >\n {items}\n </Menu>\n </>\n );\n}\n"],"mappings":"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","names":[]}
|