@12-apps/ui 5.0.1 → 5.2.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 +7 -0
- package/dist/layout/SettingsLayout.js +563 -109
- package/dist/layout/SettingsLayout.js.map +1 -1
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.d.ts +19 -2
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.d.ts.map +1 -1
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.filters.d.ts +6 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.filters.d.ts.map +1 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.items.d.ts +31 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.items.d.ts.map +1 -0
- package/dist/types/components/layout/SettingsLayout/{SettingsLayout.parts.d.ts → SettingsLayout.rail.d.ts} +6 -9
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.rail.d.ts.map +1 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.styles.d.ts +35 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.styles.d.ts.map +1 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.types.d.ts +109 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.types.d.ts.map +1 -1
- package/dist/types/components/layout/SettingsLayout/SettingsPanel.d.ts +29 -0
- package/dist/types/components/layout/SettingsLayout/SettingsPanel.d.ts.map +1 -0
- package/dist/types/components/layout/SettingsLayout/SettingsSectionChips.d.ts +26 -0
- package/dist/types/components/layout/SettingsLayout/SettingsSectionChips.d.ts.map +1 -0
- package/dist/types/components/layout/SettingsLayout/SettingsStatusMarker.d.ts +28 -0
- package/dist/types/components/layout/SettingsLayout/SettingsStatusMarker.d.ts.map +1 -0
- package/dist/types/components/layout/SettingsLayout/index.d.ts +5 -1
- package/dist/types/components/layout/SettingsLayout/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/layout/SettingsLayout/SettingsLayout.filters.ts +21 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.items.tsx +228 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.md +93 -1
- package/src/components/layout/SettingsLayout/SettingsLayout.rail.tsx +279 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.styles.ts +64 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.tsx +118 -25
- package/src/components/layout/SettingsLayout/SettingsLayout.types.ts +113 -0
- package/src/components/layout/SettingsLayout/SettingsPanel.tsx +140 -0
- package/src/components/layout/SettingsLayout/SettingsSectionChips.tsx +0 -0
- package/src/components/layout/SettingsLayout/SettingsStatusMarker.tsx +75 -0
- package/src/components/layout/SettingsLayout/index.ts +8 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.parts.d.ts.map +0 -1
- package/src/components/layout/SettingsLayout/SettingsLayout.parts.tsx +0 -358
|
@@ -1,34 +1,145 @@
|
|
|
1
|
+
import {
|
|
2
|
+
withDefaults
|
|
3
|
+
} from "../chunk-Y2JYDXL7.js";
|
|
1
4
|
import "../chunk-PZ5AY32C.js";
|
|
2
5
|
|
|
3
6
|
// src/components/layout/SettingsLayout/SettingsLayout.tsx
|
|
4
|
-
import { Box as
|
|
7
|
+
import { Box as Box6 } from "@mui/material";
|
|
5
8
|
import { useMemo, useState } from "react";
|
|
6
9
|
|
|
7
|
-
// src/components/layout/SettingsLayout/SettingsLayout.
|
|
10
|
+
// src/components/layout/SettingsLayout/SettingsLayout.filters.ts
|
|
11
|
+
function filterGroups(groups, query) {
|
|
12
|
+
const needle = query.trim().toLowerCase();
|
|
13
|
+
if (!needle) return groups;
|
|
14
|
+
const matches = (item) => item.label.toLowerCase().includes(needle) || (item.keywords ?? []).some((keyword) => keyword.toLowerCase().includes(needle));
|
|
15
|
+
return groups.map((group) => ({ ...group, items: group.items.filter(matches) })).filter((group) => group.items.length > 0);
|
|
16
|
+
}
|
|
17
|
+
function activeItemLabel(groups, activeItemId) {
|
|
18
|
+
return groups.flatMap((group) => group.items).find((item) => item.id === activeItemId)?.label;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// src/components/layout/SettingsLayout/SettingsLayout.rail.tsx
|
|
8
22
|
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
|
|
9
23
|
import SearchIcon from "@mui/icons-material/Search";
|
|
24
|
+
import { Box as Box3, Button, InputAdornment, TextField, Typography as Typography2 } from "@mui/material";
|
|
25
|
+
|
|
26
|
+
// src/components/layout/SettingsLayout/SettingsLayout.items.tsx
|
|
10
27
|
import {
|
|
11
28
|
alpha,
|
|
12
|
-
Box,
|
|
13
|
-
InputAdornment,
|
|
29
|
+
Box as Box2,
|
|
14
30
|
List,
|
|
31
|
+
ListItem,
|
|
15
32
|
ListItemButton,
|
|
16
33
|
ListItemIcon,
|
|
17
34
|
ListItemText,
|
|
18
|
-
TextField,
|
|
19
35
|
Typography,
|
|
20
36
|
useTheme
|
|
21
37
|
} from "@mui/material";
|
|
22
|
-
|
|
38
|
+
|
|
39
|
+
// src/components/layout/SettingsLayout/SettingsLayout.styles.ts
|
|
23
40
|
var RAIL_WIDTH = 300;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
41
|
+
var SR_ONLY_SX = {
|
|
42
|
+
position: "absolute",
|
|
43
|
+
width: "1px",
|
|
44
|
+
height: "1px",
|
|
45
|
+
padding: 0,
|
|
46
|
+
margin: "-1px",
|
|
47
|
+
overflow: "hidden",
|
|
48
|
+
clip: "rect(0, 0, 0, 0)",
|
|
49
|
+
whiteSpace: "nowrap",
|
|
50
|
+
border: 0
|
|
51
|
+
};
|
|
52
|
+
function atLeastRail(theme, breakpoint) {
|
|
53
|
+
return theme.breakpoints.up(breakpoint);
|
|
29
54
|
}
|
|
30
|
-
function
|
|
31
|
-
return
|
|
55
|
+
function displayAcrossRail(theme, breakpoint, narrow, wide) {
|
|
56
|
+
return { display: narrow, [atLeastRail(theme, breakpoint)]: { display: wide } };
|
|
57
|
+
}
|
|
58
|
+
var TOUCH_TARGET = 44;
|
|
59
|
+
var STATUS_COLOR = {
|
|
60
|
+
ok: "success.main",
|
|
61
|
+
off: "text.disabled",
|
|
62
|
+
new: "error.main"
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/components/layout/SettingsLayout/SettingsStatusMarker.tsx
|
|
66
|
+
import LockOutlinedIcon from "@mui/icons-material/LockOutlined";
|
|
67
|
+
import { Box } from "@mui/material";
|
|
68
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
69
|
+
function SettingsStatusMarker({
|
|
70
|
+
status,
|
|
71
|
+
label,
|
|
72
|
+
testId
|
|
73
|
+
}) {
|
|
74
|
+
const hidden = label ? /* @__PURE__ */ jsx(Box, { component: "span", sx: SR_ONLY_SX, children: label }) : null;
|
|
75
|
+
if (status === "locked") {
|
|
76
|
+
return /* @__PURE__ */ jsxs(
|
|
77
|
+
Box,
|
|
78
|
+
{
|
|
79
|
+
component: "span",
|
|
80
|
+
"data-testid": testId,
|
|
81
|
+
"data-status": status,
|
|
82
|
+
sx: { display: "inline-flex", alignItems: "center", color: "text.disabled" },
|
|
83
|
+
children: [
|
|
84
|
+
/* @__PURE__ */ jsx(LockOutlinedIcon, { sx: { fontSize: 16 } }),
|
|
85
|
+
hidden
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return /* @__PURE__ */ jsxs(
|
|
91
|
+
Box,
|
|
92
|
+
{
|
|
93
|
+
component: "span",
|
|
94
|
+
"data-testid": testId,
|
|
95
|
+
"data-status": status,
|
|
96
|
+
sx: { display: "inline-flex", alignItems: "center" },
|
|
97
|
+
children: [
|
|
98
|
+
/* @__PURE__ */ jsx(
|
|
99
|
+
Box,
|
|
100
|
+
{
|
|
101
|
+
component: "span",
|
|
102
|
+
sx: {
|
|
103
|
+
width: 8,
|
|
104
|
+
height: 8,
|
|
105
|
+
borderRadius: "50%",
|
|
106
|
+
flex: "0 0 auto",
|
|
107
|
+
bgcolor: STATUS_COLOR[status]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
),
|
|
111
|
+
hidden
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
SettingsStatusMarker.displayName = "SettingsStatusMarker";
|
|
117
|
+
|
|
118
|
+
// src/components/layout/SettingsLayout/SettingsLayout.items.tsx
|
|
119
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
120
|
+
function RailItemContent({
|
|
121
|
+
item,
|
|
122
|
+
active,
|
|
123
|
+
testIdPrefix
|
|
124
|
+
}) {
|
|
125
|
+
return /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
126
|
+
item.icon ? /* @__PURE__ */ jsx2(ListItemIcon, { sx: { minWidth: 0, color: "inherit" }, children: item.icon }) : null,
|
|
127
|
+
/* @__PURE__ */ jsx2(
|
|
128
|
+
ListItemText,
|
|
129
|
+
{
|
|
130
|
+
primary: item.label,
|
|
131
|
+
primaryTypographyProps: { variant: "body2", noWrap: true, fontWeight: active ? 600 : 500 }
|
|
132
|
+
}
|
|
133
|
+
),
|
|
134
|
+
item.status ? /* @__PURE__ */ jsx2(
|
|
135
|
+
SettingsStatusMarker,
|
|
136
|
+
{
|
|
137
|
+
status: item.status,
|
|
138
|
+
label: item.statusLabel,
|
|
139
|
+
testId: `${testIdPrefix}-status-${item.id}`
|
|
140
|
+
}
|
|
141
|
+
) : null
|
|
142
|
+
] });
|
|
32
143
|
}
|
|
33
144
|
function SettingsRailItem({
|
|
34
145
|
item,
|
|
@@ -36,17 +147,19 @@ function SettingsRailItem({
|
|
|
36
147
|
linkComponent,
|
|
37
148
|
onSelectItem,
|
|
38
149
|
onNavigate,
|
|
39
|
-
testIdPrefix
|
|
150
|
+
testIdPrefix,
|
|
151
|
+
variant,
|
|
152
|
+
breakpoint
|
|
40
153
|
}) {
|
|
41
154
|
const theme = useTheme();
|
|
155
|
+
const touchFloor = variant === "drilldown" ? { minHeight: TOUCH_TARGET, [atLeastRail(theme, breakpoint)]: { minHeight: "auto" } } : null;
|
|
42
156
|
const shared = {
|
|
43
|
-
selected: active,
|
|
44
|
-
"aria-current": active ? "page" : void 0,
|
|
45
157
|
"data-testid": `${testIdPrefix}-item-${item.id}`,
|
|
46
158
|
sx: {
|
|
47
159
|
borderRadius: 1.5,
|
|
48
160
|
mb: 0.25,
|
|
49
161
|
gap: 1.5,
|
|
162
|
+
...touchFloor,
|
|
50
163
|
color: active ? "primary.main" : "text.secondary",
|
|
51
164
|
"&.Mui-selected": {
|
|
52
165
|
bgcolor: alpha(theme.palette.primary.main, 0.12),
|
|
@@ -54,42 +167,62 @@ function SettingsRailItem({
|
|
|
54
167
|
}
|
|
55
168
|
}
|
|
56
169
|
};
|
|
57
|
-
const content = /* @__PURE__ */
|
|
58
|
-
|
|
59
|
-
/* @__PURE__ */
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
] });
|
|
170
|
+
const content = /* @__PURE__ */ jsx2(RailItemContent, { item, active, testIdPrefix });
|
|
171
|
+
if (item.inert) {
|
|
172
|
+
return /* @__PURE__ */ jsx2(ListItem, { ...shared, "data-inert": "true", children: content });
|
|
173
|
+
}
|
|
174
|
+
const interactive = {
|
|
175
|
+
...shared,
|
|
176
|
+
selected: active,
|
|
177
|
+
"aria-current": active ? "page" : void 0
|
|
178
|
+
};
|
|
67
179
|
if (item.href && linkComponent) {
|
|
68
180
|
const LinkComponent = linkComponent;
|
|
69
|
-
return /* @__PURE__ */
|
|
181
|
+
return /* @__PURE__ */ jsx2(
|
|
182
|
+
ListItemButton,
|
|
183
|
+
{
|
|
184
|
+
component: LinkComponent,
|
|
185
|
+
href: item.href,
|
|
186
|
+
onClick: onNavigate,
|
|
187
|
+
...interactive,
|
|
188
|
+
children: content
|
|
189
|
+
}
|
|
190
|
+
);
|
|
70
191
|
}
|
|
71
|
-
return /* @__PURE__ */
|
|
192
|
+
return /* @__PURE__ */ jsx2(
|
|
72
193
|
ListItemButton,
|
|
73
194
|
{
|
|
74
195
|
onClick: () => {
|
|
75
196
|
onSelectItem?.(item.id);
|
|
76
197
|
onNavigate?.();
|
|
77
198
|
},
|
|
78
|
-
...
|
|
199
|
+
...interactive,
|
|
79
200
|
children: content
|
|
80
201
|
}
|
|
81
202
|
);
|
|
82
203
|
}
|
|
204
|
+
function indexListSx(shape) {
|
|
205
|
+
if (shape.variant !== "drilldown" || !shape.atIndex) return null;
|
|
206
|
+
return (theme) => ({
|
|
207
|
+
display: "grid",
|
|
208
|
+
gridTemplateColumns: "1fr",
|
|
209
|
+
columnGap: 8,
|
|
210
|
+
[theme.breakpoints.up("sm")]: { gridTemplateColumns: "1fr 1fr" },
|
|
211
|
+
[atLeastRail(theme, shape.breakpoint)]: { gridTemplateColumns: "1fr" }
|
|
212
|
+
});
|
|
213
|
+
}
|
|
83
214
|
function SettingsRailGroup({
|
|
84
215
|
group,
|
|
85
216
|
activeItemId,
|
|
86
217
|
linkComponent,
|
|
87
218
|
onSelectItem,
|
|
88
219
|
onNavigate,
|
|
89
|
-
testIdPrefix
|
|
220
|
+
testIdPrefix,
|
|
221
|
+
...shape
|
|
90
222
|
}) {
|
|
91
|
-
|
|
92
|
-
|
|
223
|
+
const grid = indexListSx(shape);
|
|
224
|
+
return /* @__PURE__ */ jsxs2(Box2, { "data-testid": `${testIdPrefix}-group-${group.id}`, sx: { mb: 2 }, children: [
|
|
225
|
+
/* @__PURE__ */ jsx2(
|
|
93
226
|
Typography,
|
|
94
227
|
{
|
|
95
228
|
variant: "caption",
|
|
@@ -104,30 +237,42 @@ function SettingsRailGroup({
|
|
|
104
237
|
children: group.label
|
|
105
238
|
}
|
|
106
239
|
),
|
|
107
|
-
group.description ? /* @__PURE__ */
|
|
108
|
-
/* @__PURE__ */
|
|
109
|
-
|
|
240
|
+
group.description ? /* @__PURE__ */ jsx2(Typography, { variant: "caption", component: "p", sx: { px: 1, mt: 0.25, color: "text.disabled" }, children: group.description }) : null,
|
|
241
|
+
/* @__PURE__ */ jsx2(
|
|
242
|
+
List,
|
|
110
243
|
{
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
244
|
+
disablePadding: true,
|
|
245
|
+
sx: (theme) => ({ mt: 0.5, ...grid ? grid(theme) : null }),
|
|
246
|
+
children: group.items.map((item) => /* @__PURE__ */ jsx2(
|
|
247
|
+
SettingsRailItem,
|
|
248
|
+
{
|
|
249
|
+
item,
|
|
250
|
+
active: item.id === activeItemId,
|
|
251
|
+
linkComponent,
|
|
252
|
+
onSelectItem,
|
|
253
|
+
onNavigate,
|
|
254
|
+
testIdPrefix,
|
|
255
|
+
...shape
|
|
256
|
+
},
|
|
257
|
+
item.id
|
|
258
|
+
))
|
|
259
|
+
}
|
|
260
|
+
)
|
|
120
261
|
] });
|
|
121
262
|
}
|
|
263
|
+
|
|
264
|
+
// src/components/layout/SettingsLayout/SettingsLayout.rail.tsx
|
|
265
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
122
266
|
function SettingsRailToggle({
|
|
123
267
|
title,
|
|
124
268
|
activeLabel,
|
|
125
269
|
open,
|
|
126
270
|
onToggle,
|
|
271
|
+
breakpoint,
|
|
127
272
|
testIdPrefix
|
|
128
273
|
}) {
|
|
129
|
-
return /* @__PURE__ */
|
|
130
|
-
|
|
274
|
+
return /* @__PURE__ */ jsxs3(
|
|
275
|
+
Box3,
|
|
131
276
|
{
|
|
132
277
|
component: "button",
|
|
133
278
|
type: "button",
|
|
@@ -135,12 +280,13 @@ function SettingsRailToggle({
|
|
|
135
280
|
"aria-expanded": open,
|
|
136
281
|
"aria-label": typeof title === "string" ? title : "Settings",
|
|
137
282
|
"data-testid": `${testIdPrefix}-toggle`,
|
|
138
|
-
sx: {
|
|
139
|
-
|
|
283
|
+
sx: (theme) => ({
|
|
284
|
+
...displayAcrossRail(theme, breakpoint, "flex", "none"),
|
|
140
285
|
alignItems: "center",
|
|
141
286
|
justifyContent: "space-between",
|
|
142
287
|
gap: 1,
|
|
143
288
|
width: "100%",
|
|
289
|
+
minHeight: TOUCH_TARGET,
|
|
144
290
|
px: 1.5,
|
|
145
291
|
py: 1,
|
|
146
292
|
mb: 1,
|
|
@@ -148,15 +294,15 @@ function SettingsRailToggle({
|
|
|
148
294
|
cursor: "pointer",
|
|
149
295
|
color: "text.primary",
|
|
150
296
|
background: "transparent",
|
|
151
|
-
border:
|
|
297
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
152
298
|
borderRadius: 1.5
|
|
153
|
-
},
|
|
299
|
+
}),
|
|
154
300
|
children: [
|
|
155
|
-
/* @__PURE__ */
|
|
156
|
-
title ? /* @__PURE__ */
|
|
157
|
-
/* @__PURE__ */
|
|
301
|
+
/* @__PURE__ */ jsxs3(Box3, { sx: { minWidth: 0 }, children: [
|
|
302
|
+
title ? /* @__PURE__ */ jsx3(Typography2, { variant: "caption", sx: { display: "block", color: "text.secondary" }, children: title }) : null,
|
|
303
|
+
/* @__PURE__ */ jsx3(Typography2, { variant: "body2", noWrap: true, sx: { fontWeight: 600 }, children: activeLabel ?? "" })
|
|
158
304
|
] }),
|
|
159
|
-
/* @__PURE__ */
|
|
305
|
+
/* @__PURE__ */ jsx3(
|
|
160
306
|
ExpandMoreIcon,
|
|
161
307
|
{
|
|
162
308
|
fontSize: "small",
|
|
@@ -164,7 +310,8 @@ function SettingsRailToggle({
|
|
|
164
310
|
flex: "0 0 auto",
|
|
165
311
|
color: "text.secondary",
|
|
166
312
|
transition: "transform 150ms ease",
|
|
167
|
-
transform: open ? "rotate(180deg)" : "none"
|
|
313
|
+
transform: open ? "rotate(180deg)" : "none",
|
|
314
|
+
"@media (prefers-reduced-motion: reduce)": { transition: "none" }
|
|
168
315
|
}
|
|
169
316
|
}
|
|
170
317
|
)
|
|
@@ -172,26 +319,53 @@ function SettingsRailToggle({
|
|
|
172
319
|
}
|
|
173
320
|
);
|
|
174
321
|
}
|
|
322
|
+
function SettingsSearchEmpty({
|
|
323
|
+
label,
|
|
324
|
+
action,
|
|
325
|
+
onClear,
|
|
326
|
+
testIdPrefix
|
|
327
|
+
}) {
|
|
328
|
+
return /* @__PURE__ */ jsxs3(Box3, { "data-testid": `${testIdPrefix}-empty`, sx: { px: 1, py: 2 }, children: [
|
|
329
|
+
/* @__PURE__ */ jsx3(Typography2, { variant: "body2", color: "text.secondary", children: label }),
|
|
330
|
+
action ? /* @__PURE__ */ jsx3(
|
|
331
|
+
Button,
|
|
332
|
+
{
|
|
333
|
+
size: "small",
|
|
334
|
+
variant: "outlined",
|
|
335
|
+
onClick: () => {
|
|
336
|
+
onClear();
|
|
337
|
+
action.onClear?.();
|
|
338
|
+
},
|
|
339
|
+
"data-testid": `${testIdPrefix}-empty-action`,
|
|
340
|
+
sx: { mt: 1.5, minHeight: TOUCH_TARGET },
|
|
341
|
+
children: action.label
|
|
342
|
+
}
|
|
343
|
+
) : null
|
|
344
|
+
] });
|
|
345
|
+
}
|
|
175
346
|
function SettingsRailBody({
|
|
176
347
|
navOpen,
|
|
177
348
|
query,
|
|
178
349
|
onQueryChange,
|
|
179
350
|
searchPlaceholder,
|
|
180
351
|
emptySearchLabel,
|
|
352
|
+
emptySearchAction,
|
|
181
353
|
filteredGroups,
|
|
182
354
|
activeItemId,
|
|
183
355
|
linkComponent,
|
|
184
356
|
onSelectItem,
|
|
185
357
|
onNavigate,
|
|
186
|
-
testIdPrefix
|
|
358
|
+
testIdPrefix,
|
|
359
|
+
...shape
|
|
187
360
|
}) {
|
|
188
|
-
|
|
189
|
-
|
|
361
|
+
const hidden = navOpen ? "block" : "none";
|
|
362
|
+
return /* @__PURE__ */ jsxs3(
|
|
363
|
+
Box3,
|
|
190
364
|
{
|
|
191
365
|
"data-testid": `${testIdPrefix}-rail-body`,
|
|
192
|
-
sx:
|
|
366
|
+
sx: (theme) => shape.variant === "drilldown" ? { display: "block" } : displayAcrossRail(theme, shape.breakpoint, hidden, "block"),
|
|
193
367
|
children: [
|
|
194
|
-
/* @__PURE__ */
|
|
368
|
+
/* @__PURE__ */ jsx3(
|
|
195
369
|
TextField,
|
|
196
370
|
{
|
|
197
371
|
value: query,
|
|
@@ -202,21 +376,20 @@ function SettingsRailBody({
|
|
|
202
376
|
"aria-label": searchPlaceholder,
|
|
203
377
|
"data-testid": `${testIdPrefix}-search`,
|
|
204
378
|
InputProps: {
|
|
205
|
-
startAdornment: /* @__PURE__ */
|
|
379
|
+
startAdornment: /* @__PURE__ */ jsx3(InputAdornment, { position: "start", children: /* @__PURE__ */ jsx3(SearchIcon, { fontSize: "small", sx: { color: "text.secondary" } }) })
|
|
206
380
|
},
|
|
207
381
|
sx: { mb: 2 }
|
|
208
382
|
}
|
|
209
383
|
),
|
|
210
|
-
filteredGroups.length === 0 ? /* @__PURE__ */
|
|
211
|
-
|
|
384
|
+
filteredGroups.length === 0 ? /* @__PURE__ */ jsx3(
|
|
385
|
+
SettingsSearchEmpty,
|
|
212
386
|
{
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
"
|
|
216
|
-
|
|
217
|
-
children: emptySearchLabel
|
|
387
|
+
label: emptySearchLabel,
|
|
388
|
+
action: emptySearchAction,
|
|
389
|
+
onClear: () => onQueryChange(""),
|
|
390
|
+
testIdPrefix
|
|
218
391
|
}
|
|
219
|
-
) : filteredGroups.map((group) => /* @__PURE__ */
|
|
392
|
+
) : filteredGroups.map((group) => /* @__PURE__ */ jsx3(
|
|
220
393
|
SettingsRailGroup,
|
|
221
394
|
{
|
|
222
395
|
group,
|
|
@@ -224,7 +397,8 @@ function SettingsRailBody({
|
|
|
224
397
|
linkComponent,
|
|
225
398
|
onSelectItem,
|
|
226
399
|
onNavigate,
|
|
227
|
-
testIdPrefix
|
|
400
|
+
testIdPrefix,
|
|
401
|
+
...shape
|
|
228
402
|
},
|
|
229
403
|
group.id
|
|
230
404
|
))
|
|
@@ -240,75 +414,333 @@ function SettingsRail({
|
|
|
240
414
|
testIdPrefix,
|
|
241
415
|
...bodyProps
|
|
242
416
|
}) {
|
|
243
|
-
const
|
|
244
|
-
|
|
245
|
-
|
|
417
|
+
const { variant, breakpoint, atIndex } = bodyProps;
|
|
418
|
+
const hiddenWhileInSection = variant === "drilldown" && !atIndex;
|
|
419
|
+
return /* @__PURE__ */ jsxs3(
|
|
420
|
+
Box3,
|
|
246
421
|
{
|
|
247
422
|
component: "nav",
|
|
248
423
|
"aria-label": typeof title === "string" ? title : "Settings",
|
|
249
424
|
"data-testid": `${testIdPrefix}-rail`,
|
|
250
|
-
sx: {
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
425
|
+
sx: (theme) => ({
|
|
426
|
+
display: hiddenWhileInSection ? "none" : "block",
|
|
427
|
+
flex: "0 0 auto",
|
|
428
|
+
width: "100%",
|
|
429
|
+
[atLeastRail(theme, breakpoint)]: {
|
|
430
|
+
display: "block",
|
|
431
|
+
flex: `0 0 ${RAIL_WIDTH}px`,
|
|
432
|
+
width: RAIL_WIDTH,
|
|
433
|
+
borderRight: `1px solid ${theme.palette.divider}`,
|
|
434
|
+
pr: 2
|
|
435
|
+
}
|
|
436
|
+
}),
|
|
256
437
|
children: [
|
|
257
|
-
title ? /* @__PURE__ */
|
|
258
|
-
|
|
438
|
+
title ? /* @__PURE__ */ jsx3(
|
|
439
|
+
Typography2,
|
|
259
440
|
{
|
|
260
441
|
variant: "h6",
|
|
261
442
|
"data-testid": `${testIdPrefix}-title`,
|
|
262
|
-
sx:
|
|
443
|
+
sx: (theme) => ({
|
|
444
|
+
...variant === "drilldown" ? { display: "block" } : displayAcrossRail(theme, breakpoint, "none", "block"),
|
|
445
|
+
fontWeight: 700,
|
|
446
|
+
mb: 1.5
|
|
447
|
+
}),
|
|
263
448
|
children: title
|
|
264
449
|
}
|
|
265
450
|
) : null,
|
|
266
|
-
/* @__PURE__ */
|
|
451
|
+
variant === "switcher" ? /* @__PURE__ */ jsx3(
|
|
267
452
|
SettingsRailToggle,
|
|
268
453
|
{
|
|
269
454
|
title,
|
|
270
455
|
activeLabel,
|
|
271
456
|
open: navOpen,
|
|
272
457
|
onToggle: onToggleNav,
|
|
458
|
+
breakpoint,
|
|
273
459
|
testIdPrefix
|
|
274
460
|
}
|
|
275
|
-
),
|
|
276
|
-
/* @__PURE__ */
|
|
461
|
+
) : null,
|
|
462
|
+
/* @__PURE__ */ jsx3(SettingsRailBody, { navOpen, testIdPrefix, ...bodyProps })
|
|
277
463
|
]
|
|
278
464
|
}
|
|
279
465
|
);
|
|
280
466
|
}
|
|
281
467
|
|
|
282
|
-
// src/components/layout/SettingsLayout/
|
|
283
|
-
import
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
468
|
+
// src/components/layout/SettingsLayout/SettingsPanel.tsx
|
|
469
|
+
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
|
470
|
+
import { Box as Box5 } from "@mui/material";
|
|
471
|
+
|
|
472
|
+
// src/components/layout/SettingsLayout/SettingsSectionChips.tsx
|
|
473
|
+
import { alpha as alpha2, Box as Box4, useTheme as useTheme2 } from "@mui/material";
|
|
474
|
+
import { useEffect, useRef } from "react";
|
|
475
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
476
|
+
function prefersReducedMotion() {
|
|
477
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
478
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
479
|
+
}
|
|
480
|
+
function useCentreActiveChip(stripRef, activeItemId, itemsKey) {
|
|
481
|
+
useEffect(() => {
|
|
482
|
+
const strip = stripRef.current;
|
|
483
|
+
if (!strip || !activeItemId) return;
|
|
484
|
+
const chip = Array.from(strip.children).find(
|
|
485
|
+
(node) => node instanceof HTMLElement && node.dataset.chipId === activeItemId
|
|
486
|
+
);
|
|
487
|
+
if (!chip) return;
|
|
488
|
+
const target = chip.offsetLeft + chip.offsetWidth / 2 - strip.clientWidth / 2;
|
|
489
|
+
const left = Math.max(0, Math.min(target, strip.scrollWidth - strip.clientWidth));
|
|
490
|
+
strip.scrollTo({ left, behavior: prefersReducedMotion() ? "auto" : "smooth" });
|
|
491
|
+
}, [stripRef, activeItemId, itemsKey]);
|
|
492
|
+
}
|
|
493
|
+
function SectionChip({
|
|
494
|
+
item,
|
|
495
|
+
active,
|
|
496
|
+
theme,
|
|
497
|
+
linkComponent,
|
|
498
|
+
onSelectItem,
|
|
499
|
+
testIdPrefix
|
|
500
|
+
}) {
|
|
501
|
+
const asLink = item.href !== void 0 && linkComponent !== void 0;
|
|
502
|
+
const behaviour = asLink ? { component: linkComponent, href: item.href } : { component: "button", type: "button", onClick: () => onSelectItem?.(item.id) };
|
|
503
|
+
return /* @__PURE__ */ jsxs4(
|
|
504
|
+
Box4,
|
|
505
|
+
{
|
|
506
|
+
...behaviour,
|
|
507
|
+
"data-chip-id": item.id,
|
|
508
|
+
"data-testid": `${testIdPrefix}-chip-${item.id}`,
|
|
509
|
+
"aria-current": active ? "page" : void 0,
|
|
510
|
+
sx: {
|
|
511
|
+
display: "inline-flex",
|
|
512
|
+
alignItems: "center",
|
|
513
|
+
gap: 0.75,
|
|
514
|
+
flex: "0 0 auto",
|
|
515
|
+
minHeight: TOUCH_TARGET,
|
|
516
|
+
px: 1.5,
|
|
517
|
+
borderRadius: 999,
|
|
518
|
+
cursor: "pointer",
|
|
519
|
+
font: "inherit",
|
|
520
|
+
fontSize: "0.8125rem",
|
|
521
|
+
fontWeight: active ? 700 : 500,
|
|
522
|
+
textDecoration: "none",
|
|
523
|
+
whiteSpace: "nowrap",
|
|
524
|
+
color: active ? "primary.main" : "text.secondary",
|
|
525
|
+
bgcolor: active ? alpha2(theme.palette.primary.main, 0.12) : "transparent",
|
|
526
|
+
border: `1px solid ${active ? alpha2(theme.palette.primary.main, 0.4) : theme.palette.divider}`
|
|
527
|
+
},
|
|
528
|
+
children: [
|
|
529
|
+
item.status ? /* @__PURE__ */ jsx4(
|
|
530
|
+
SettingsStatusMarker,
|
|
531
|
+
{
|
|
532
|
+
status: item.status,
|
|
533
|
+
label: item.statusLabel,
|
|
534
|
+
testId: `${testIdPrefix}-chip-status-${item.id}`
|
|
535
|
+
}
|
|
536
|
+
) : null,
|
|
537
|
+
item.label
|
|
538
|
+
]
|
|
539
|
+
}
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
function SettingsSectionChips({
|
|
543
|
+
items,
|
|
287
544
|
activeItemId,
|
|
545
|
+
ariaLabel,
|
|
546
|
+
linkComponent,
|
|
288
547
|
onSelectItem,
|
|
289
|
-
|
|
290
|
-
|
|
548
|
+
testIdPrefix
|
|
549
|
+
}) {
|
|
550
|
+
const theme = useTheme2();
|
|
551
|
+
const stripRef = useRef(null);
|
|
552
|
+
useCentreActiveChip(stripRef, activeItemId, items.map((item) => item.id).join("\0"));
|
|
553
|
+
return /* @__PURE__ */ jsx4(
|
|
554
|
+
Box4,
|
|
555
|
+
{
|
|
556
|
+
ref: stripRef,
|
|
557
|
+
component: "nav",
|
|
558
|
+
"aria-label": ariaLabel,
|
|
559
|
+
"data-testid": `${testIdPrefix}-chips`,
|
|
560
|
+
sx: {
|
|
561
|
+
display: "flex",
|
|
562
|
+
alignItems: "center",
|
|
563
|
+
gap: 0.75,
|
|
564
|
+
px: 0.25,
|
|
565
|
+
py: 0.75,
|
|
566
|
+
overflowX: "auto",
|
|
567
|
+
overflowY: "hidden",
|
|
568
|
+
scrollbarWidth: "none",
|
|
569
|
+
"&::-webkit-scrollbar": { display: "none" }
|
|
570
|
+
},
|
|
571
|
+
children: items.map((item) => /* @__PURE__ */ jsx4(
|
|
572
|
+
SectionChip,
|
|
573
|
+
{
|
|
574
|
+
item,
|
|
575
|
+
active: item.id === activeItemId,
|
|
576
|
+
theme,
|
|
577
|
+
linkComponent,
|
|
578
|
+
onSelectItem,
|
|
579
|
+
testIdPrefix
|
|
580
|
+
},
|
|
581
|
+
item.id
|
|
582
|
+
))
|
|
583
|
+
}
|
|
584
|
+
);
|
|
585
|
+
}
|
|
586
|
+
SettingsSectionChips.displayName = "SettingsSectionChips";
|
|
587
|
+
|
|
588
|
+
// src/components/layout/SettingsLayout/SettingsPanel.tsx
|
|
589
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
590
|
+
function BackLink({
|
|
591
|
+
href,
|
|
592
|
+
label,
|
|
593
|
+
breakpoint,
|
|
291
594
|
linkComponent,
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
595
|
+
testIdPrefix
|
|
596
|
+
}) {
|
|
597
|
+
return /* @__PURE__ */ jsxs5(
|
|
598
|
+
Box5,
|
|
599
|
+
{
|
|
600
|
+
component: linkComponent,
|
|
601
|
+
href,
|
|
602
|
+
"aria-label": label,
|
|
603
|
+
"data-testid": `${testIdPrefix}-back`,
|
|
604
|
+
sx: (theme) => ({
|
|
605
|
+
...displayAcrossRail(theme, breakpoint, "inline-flex", "none"),
|
|
606
|
+
alignItems: "center",
|
|
607
|
+
gap: 0.5,
|
|
608
|
+
minHeight: TOUCH_TARGET,
|
|
609
|
+
pr: 1,
|
|
610
|
+
textDecoration: "none",
|
|
611
|
+
color: "text.secondary",
|
|
612
|
+
font: "inherit",
|
|
613
|
+
fontSize: "0.875rem"
|
|
614
|
+
}),
|
|
615
|
+
children: [
|
|
616
|
+
/* @__PURE__ */ jsx5(ChevronLeftIcon, { fontSize: "small" }),
|
|
617
|
+
label
|
|
618
|
+
]
|
|
619
|
+
}
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
function SettingsPanel({
|
|
623
|
+
inSection,
|
|
624
|
+
hideOnNarrow,
|
|
625
|
+
breakpoint,
|
|
626
|
+
indexHref,
|
|
627
|
+
backLabel,
|
|
628
|
+
ariaLabel,
|
|
629
|
+
sectionChips,
|
|
630
|
+
activeItemId,
|
|
631
|
+
linkComponent,
|
|
632
|
+
onSelectItem,
|
|
633
|
+
testIdPrefix,
|
|
634
|
+
children
|
|
635
|
+
}) {
|
|
636
|
+
const showBack = inSection && indexHref !== void 0 && linkComponent !== void 0;
|
|
637
|
+
const showChips = inSection && sectionChips !== void 0 && sectionChips.length > 0;
|
|
638
|
+
return /* @__PURE__ */ jsxs5(
|
|
639
|
+
Box5,
|
|
640
|
+
{
|
|
641
|
+
"data-testid": `${testIdPrefix}-panel`,
|
|
642
|
+
sx: (theme) => ({
|
|
643
|
+
...hideOnNarrow ? displayAcrossRail(theme, breakpoint, "none", "block") : { display: "block" },
|
|
644
|
+
flex: "1 1 auto",
|
|
645
|
+
minWidth: 0,
|
|
646
|
+
width: "100%"
|
|
647
|
+
}),
|
|
648
|
+
children: [
|
|
649
|
+
showBack ? /* @__PURE__ */ jsx5(
|
|
650
|
+
BackLink,
|
|
651
|
+
{
|
|
652
|
+
href: indexHref,
|
|
653
|
+
label: backLabel,
|
|
654
|
+
breakpoint,
|
|
655
|
+
linkComponent,
|
|
656
|
+
testIdPrefix
|
|
657
|
+
}
|
|
658
|
+
) : null,
|
|
659
|
+
showChips ? /* @__PURE__ */ jsx5(
|
|
660
|
+
Box5,
|
|
661
|
+
{
|
|
662
|
+
sx: (theme) => ({
|
|
663
|
+
...displayAcrossRail(theme, breakpoint, "block", "none"),
|
|
664
|
+
mb: 1,
|
|
665
|
+
minWidth: 0
|
|
666
|
+
}),
|
|
667
|
+
children: /* @__PURE__ */ jsx5(
|
|
668
|
+
SettingsSectionChips,
|
|
669
|
+
{
|
|
670
|
+
items: sectionChips,
|
|
671
|
+
activeItemId,
|
|
672
|
+
ariaLabel,
|
|
673
|
+
linkComponent,
|
|
674
|
+
onSelectItem,
|
|
675
|
+
testIdPrefix
|
|
676
|
+
}
|
|
677
|
+
)
|
|
678
|
+
}
|
|
679
|
+
) : null,
|
|
680
|
+
children
|
|
681
|
+
]
|
|
682
|
+
}
|
|
683
|
+
);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/components/layout/SettingsLayout/SettingsLayout.tsx
|
|
687
|
+
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
688
|
+
var DEFAULTS = {
|
|
689
|
+
searchPlaceholder: "Search settings",
|
|
690
|
+
defaultQuery: "",
|
|
691
|
+
emptySearchLabel: "No settings match your search.",
|
|
692
|
+
testIdPrefix: "settings",
|
|
693
|
+
railBreakpoint: "md",
|
|
694
|
+
navVariant: "switcher",
|
|
695
|
+
atIndex: false,
|
|
696
|
+
backLabel: "Back"
|
|
697
|
+
};
|
|
698
|
+
function shellSx(breakpoint) {
|
|
699
|
+
return (theme) => ({
|
|
700
|
+
display: "flex",
|
|
701
|
+
flexDirection: "column",
|
|
702
|
+
alignItems: "stretch",
|
|
703
|
+
gap: 1.5,
|
|
704
|
+
width: "100%",
|
|
705
|
+
minWidth: 0,
|
|
706
|
+
[atLeastRail(theme, breakpoint ?? "md")]: { flexDirection: "row", gap: 3 }
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
var SettingsLayout = (props) => {
|
|
710
|
+
const {
|
|
711
|
+
title,
|
|
712
|
+
groups,
|
|
713
|
+
activeItemId,
|
|
714
|
+
onSelectItem,
|
|
715
|
+
searchPlaceholder,
|
|
716
|
+
defaultQuery,
|
|
717
|
+
emptySearchLabel,
|
|
718
|
+
emptySearchAction,
|
|
719
|
+
linkComponent,
|
|
720
|
+
children,
|
|
721
|
+
testIdPrefix,
|
|
722
|
+
railBreakpoint,
|
|
723
|
+
navVariant,
|
|
724
|
+
atIndex,
|
|
725
|
+
indexHref,
|
|
726
|
+
backLabel,
|
|
727
|
+
sectionChips
|
|
728
|
+
} = withDefaults(props, DEFAULTS);
|
|
729
|
+
const [query, setQuery] = useState(defaultQuery);
|
|
296
730
|
const [navOpen, setNavOpen] = useState(false);
|
|
297
731
|
const filteredGroups = useMemo(() => filterGroups(groups, query), [groups, query]);
|
|
298
732
|
const activeLabel = useMemo(() => activeItemLabel(groups, activeItemId), [groups, activeItemId]);
|
|
299
|
-
|
|
300
|
-
|
|
733
|
+
const drilldown = navVariant === "drilldown";
|
|
734
|
+
const ariaLabel = typeof title === "string" ? title : "Settings";
|
|
735
|
+
return /* @__PURE__ */ jsxs6(
|
|
736
|
+
Box6,
|
|
301
737
|
{
|
|
302
738
|
"data-testid": testIdPrefix,
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
alignItems: "stretch",
|
|
307
|
-
gap: { xs: 1.5, md: 3 },
|
|
308
|
-
width: "100%"
|
|
309
|
-
},
|
|
739
|
+
"data-nav-variant": navVariant,
|
|
740
|
+
"data-at-index": atIndex ? "true" : "false",
|
|
741
|
+
sx: shellSx(railBreakpoint),
|
|
310
742
|
children: [
|
|
311
|
-
/* @__PURE__ */
|
|
743
|
+
/* @__PURE__ */ jsx6(
|
|
312
744
|
SettingsRail,
|
|
313
745
|
{
|
|
314
746
|
title,
|
|
@@ -319,21 +751,43 @@ var SettingsLayout = ({
|
|
|
319
751
|
onQueryChange: setQuery,
|
|
320
752
|
searchPlaceholder,
|
|
321
753
|
emptySearchLabel,
|
|
754
|
+
emptySearchAction,
|
|
322
755
|
filteredGroups,
|
|
323
756
|
activeItemId,
|
|
324
757
|
linkComponent,
|
|
325
758
|
onSelectItem,
|
|
326
759
|
onNavigate: () => setNavOpen(false),
|
|
327
|
-
testIdPrefix
|
|
760
|
+
testIdPrefix,
|
|
761
|
+
variant: navVariant,
|
|
762
|
+
breakpoint: railBreakpoint,
|
|
763
|
+
atIndex
|
|
328
764
|
}
|
|
329
765
|
),
|
|
330
|
-
/* @__PURE__ */
|
|
766
|
+
/* @__PURE__ */ jsx6(
|
|
767
|
+
SettingsPanel,
|
|
768
|
+
{
|
|
769
|
+
inSection: drilldown && !atIndex,
|
|
770
|
+
hideOnNarrow: drilldown && atIndex,
|
|
771
|
+
breakpoint: railBreakpoint,
|
|
772
|
+
indexHref,
|
|
773
|
+
backLabel,
|
|
774
|
+
ariaLabel,
|
|
775
|
+
sectionChips,
|
|
776
|
+
activeItemId,
|
|
777
|
+
linkComponent,
|
|
778
|
+
onSelectItem,
|
|
779
|
+
testIdPrefix,
|
|
780
|
+
children
|
|
781
|
+
}
|
|
782
|
+
)
|
|
331
783
|
]
|
|
332
784
|
}
|
|
333
785
|
);
|
|
334
786
|
};
|
|
335
787
|
SettingsLayout.displayName = "SettingsLayout";
|
|
336
788
|
export {
|
|
337
|
-
SettingsLayout
|
|
789
|
+
SettingsLayout,
|
|
790
|
+
SettingsSectionChips,
|
|
791
|
+
SettingsStatusMarker
|
|
338
792
|
};
|
|
339
793
|
//# sourceMappingURL=SettingsLayout.js.map
|