@12-apps/ui 6.75.0 → 6.76.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/form/Textarea/Textarea.js +1 -1
- package/dist/_internal/components/form/index.js +1 -1
- package/dist/_internal/components/index.js +1 -1
- package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.items.js +3 -3
- package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.js +8 -8
- package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.rail.js +4 -4
- package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.styles.js +3 -1
- package/dist/_internal/components/layout/SettingsLayout/SettingsPanel.js +5 -5
- package/dist/_internal/components/layout/SettingsLayout/SettingsSectionChips.js +3 -3
- package/dist/_internal/components/layout/SettingsLayout/SettingsSectionHeader.js +2 -2
- package/dist/_internal/components/layout/SettingsLayout/SettingsStatusMarker.js +2 -2
- package/dist/{chunk-V5EWCJBT.js → chunk-4BLVVMY7.js} +3 -3
- package/dist/{chunk-OKYYHBGS.js → chunk-6KM3TL4Q.js} +11 -4
- package/dist/chunk-6KM3TL4Q.js.map +1 -0
- package/dist/{chunk-DBFRCTI5.js → chunk-7Y2VWMGS.js} +2 -2
- package/dist/{chunk-F3Q4CMRB.js → chunk-GBVNY2LG.js} +3 -3
- package/dist/{chunk-KKVM723A.js → chunk-LY5I3ZSV.js} +4 -4
- package/dist/{chunk-NYFNF7I5.js → chunk-NK4T624E.js} +3 -1
- package/dist/chunk-NK4T624E.js.map +1 -0
- package/dist/{chunk-X47MWURD.js → chunk-Q6MZHT2F.js} +10 -8
- package/dist/chunk-Q6MZHT2F.js.map +1 -0
- package/dist/{chunk-TNYKM4UU.js → chunk-SWQXAUUG.js} +55 -21
- package/dist/chunk-SWQXAUUG.js.map +1 -0
- package/dist/{chunk-6KEXHOIF.js → chunk-WOXNVM52.js} +2 -2
- package/dist/form/Textarea.js +1 -1
- package/dist/layout/SettingsLayout.js +8 -8
- package/dist/types/components/form/Textarea/Textarea.d.ts.map +1 -1
- package/dist/types/components/form/Textarea/Textarea.types.d.ts +4 -2
- package/dist/types/components/form/Textarea/Textarea.types.d.ts.map +1 -1
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.d.ts.map +1 -1
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.rail.d.ts +6 -2
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.rail.d.ts.map +1 -1
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.styles.d.ts +2 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.styles.d.ts.map +1 -1
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.types.d.ts +19 -0
- package/dist/types/components/layout/SettingsLayout/SettingsLayout.types.d.ts.map +1 -1
- package/dist/types/components/layout/SettingsLayout/index.d.ts +1 -1
- package/dist/types/components/layout/SettingsLayout/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/form/Textarea/Textarea.tsx +14 -7
- package/src/components/form/Textarea/Textarea.types.ts +4 -2
- package/src/components/layout/SettingsLayout/SettingsLayout.md +19 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.rail.tsx +67 -23
- package/src/components/layout/SettingsLayout/SettingsLayout.styles.ts +3 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.tsx +12 -0
- package/src/components/layout/SettingsLayout/SettingsLayout.types.ts +20 -0
- package/src/components/layout/SettingsLayout/index.ts +1 -0
- package/dist/chunk-NYFNF7I5.js.map +0 -1
- package/dist/chunk-OKYYHBGS.js.map +0 -1
- package/dist/chunk-TNYKM4UU.js.map +0 -1
- package/dist/chunk-X47MWURD.js.map +0 -1
- /package/dist/{chunk-V5EWCJBT.js.map → chunk-4BLVVMY7.js.map} +0 -0
- /package/dist/{chunk-DBFRCTI5.js.map → chunk-7Y2VWMGS.js.map} +0 -0
- /package/dist/{chunk-F3Q4CMRB.js.map → chunk-GBVNY2LG.js.map} +0 -0
- /package/dist/{chunk-KKVM723A.js.map → chunk-LY5I3ZSV.js.map} +0 -0
- /package/dist/{chunk-6KEXHOIF.js.map → chunk-WOXNVM52.js.map} +0 -0
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
SettingsLayout
|
|
3
|
-
} from "../chunk-
|
|
3
|
+
} from "../chunk-6KM3TL4Q.js";
|
|
4
4
|
import "../chunk-BXC6GRLE.js";
|
|
5
|
-
import "../chunk-
|
|
5
|
+
import "../chunk-LY5I3ZSV.js";
|
|
6
6
|
import {
|
|
7
7
|
SettingsSectionChips
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-GBVNY2LG.js";
|
|
9
9
|
import "../chunk-AJUSBPWG.js";
|
|
10
|
-
import "../chunk-
|
|
11
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-SWQXAUUG.js";
|
|
11
|
+
import "../chunk-4BLVVMY7.js";
|
|
12
12
|
import {
|
|
13
13
|
SettingsStatusMarker
|
|
14
|
-
} from "../chunk-
|
|
15
|
-
import "../chunk-
|
|
16
|
-
import "../chunk-
|
|
14
|
+
} from "../chunk-7Y2VWMGS.js";
|
|
15
|
+
import "../chunk-WOXNVM52.js";
|
|
16
|
+
import "../chunk-NK4T624E.js";
|
|
17
17
|
import "../chunk-HPK33ACY.js";
|
|
18
18
|
import "../chunk-YKCAJ2TN.js";
|
|
19
19
|
import "../chunk-PZ5AY32C.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Textarea/Textarea.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAmC,MAAM,OAAO,CAAC;AAwBxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"Textarea.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Textarea/Textarea.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAmC,MAAM,OAAO,CAAC;AAwBxD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AA2NtD,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA0E5C,CAAC"}
|
|
@@ -65,11 +65,13 @@ export interface TextareaBaseProps extends Omit<TextareaAutosizeProps, 'variant'
|
|
|
65
65
|
*/
|
|
66
66
|
gradient?: boolean;
|
|
67
67
|
/**
|
|
68
|
-
*
|
|
68
|
+
* How many lines of its own text the box opens at, in every variant.
|
|
69
|
+
* Defaults to 4; pass it to override.
|
|
69
70
|
*/
|
|
70
71
|
minRows?: number;
|
|
71
72
|
/**
|
|
72
|
-
*
|
|
73
|
+
* The most lines the `autosize` variant grows to before it scrolls.
|
|
74
|
+
* The other variants ignore it.
|
|
73
75
|
*/
|
|
74
76
|
maxRows?: number;
|
|
75
77
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Textarea.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Textarea/Textarea.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrF,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;;;GAIG;AACH,KAAK,gBAAgB,GACjB;IAAE,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IAAC,cAAc,CAAC,EAAE,KAAK,CAAA;CAAE,GAC1E;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAE/D,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAEjE,MAAM,WAAW,iBACf,SAAQ,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IACjE;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAC;IAExD;;OAEG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IAEnB;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEvB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAE/B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB
|
|
1
|
+
{"version":3,"file":"Textarea.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/form/Textarea/Textarea.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACpE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AACrF,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B;;;;GAIG;AACH,KAAK,gBAAgB,GACjB;IAAE,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,CAAC;IAAC,cAAc,CAAC,EAAE,KAAK,CAAA;CAAE,GAC1E;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAE/D,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG,gBAAgB,CAAC;AAEjE,MAAM,WAAW,iBACf,SAAQ,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,OAAO,GAAG,MAAM,CAAC;IACjE;;OAEG;IACH,OAAO,CAAC,EAAE,SAAS,GAAG,UAAU,GAAG,WAAW,GAAG,MAAM,CAAC;IAExD;;OAEG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IAEnB;;OAEG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;IAEjB;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAEvB;;OAEG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,KAAK,CAAC;IAE/B;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsLayout.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/SettingsLayout.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAOjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"SettingsLayout.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/SettingsLayout.tsx"],"names":[],"mappings":"AAIA,OAAO,KAA4B,MAAM,OAAO,CAAC;AAOjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAoElE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA+ExD,CAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { type RailShape } from './SettingsLayout.items';
|
|
3
|
-
import type { SettingsEmptySearchAction, SettingsLayoutProps, SettingsNavGroup } from './SettingsLayout.types';
|
|
3
|
+
import type { SettingsEmptySearchAction, SettingsLayoutProps, SettingsNavGroup, SettingsRailVariant } from './SettingsLayout.types';
|
|
4
4
|
export interface RailBodyProps extends RailShape {
|
|
5
5
|
navOpen: boolean;
|
|
6
6
|
query: string;
|
|
@@ -14,6 +14,8 @@ export interface RailBodyProps extends RailShape {
|
|
|
14
14
|
onSelectItem?: (id: string) => void;
|
|
15
15
|
onNavigate?: () => void;
|
|
16
16
|
testIdPrefix: string;
|
|
17
|
+
/** Whether the search field is drawn (`SettingsLayoutProps.searchable`). */
|
|
18
|
+
searchable: boolean;
|
|
17
19
|
}
|
|
18
20
|
/** Props for {@link SettingsRail}: the rail body's inputs plus the mobile chrome. */
|
|
19
21
|
export type SettingsRailProps = RailBodyProps & {
|
|
@@ -22,7 +24,9 @@ export type SettingsRailProps = RailBodyProps & {
|
|
|
22
24
|
onToggleNav: () => void;
|
|
23
25
|
/** Scroll inside the rail rather than with the page. See `fillHeight`. */
|
|
24
26
|
fillHeight?: boolean;
|
|
27
|
+
/** How the rail's own column is drawn. See `SettingsLayoutProps.railVariant`. */
|
|
28
|
+
railVariant?: SettingsRailVariant;
|
|
25
29
|
};
|
|
26
30
|
/** The navigation column: title, the `switcher`'s disclosure, and the body. */
|
|
27
|
-
export declare function SettingsRail({ title, activeLabel, navOpen, onToggleNav, testIdPrefix, fillHeight, ...bodyProps }: SettingsRailProps): React.JSX.Element;
|
|
31
|
+
export declare function SettingsRail({ title, activeLabel, navOpen, onToggleNav, testIdPrefix, fillHeight, railVariant, ...bodyProps }: SettingsRailProps): React.JSX.Element;
|
|
28
32
|
//# sourceMappingURL=SettingsLayout.rail.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsLayout.rail.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/SettingsLayout.rail.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SettingsLayout.rail.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/SettingsLayout.rail.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,KAAK,EACV,yBAAyB,EACzB,mBAAmB,EACnB,gBAAgB,EAEhB,mBAAmB,EACpB,MAAM,wBAAwB,CAAC;AA6GhC,MAAM,WAAW,aAAc,SAAQ,SAAS;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,gBAAgB,EAAE,KAAK,CAAC,SAAS,CAAC;IAClC,iBAAiB,CAAC,EAAE,yBAAyB,CAAC;IAC9C,cAAc,EAAE,gBAAgB,EAAE,CAAC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,mBAAmB,CAAC,eAAe,CAAC,CAAC;IACrD,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,4EAA4E;IAC5E,UAAU,EAAE,OAAO,CAAC;CACrB;AA4FD,qFAAqF;AACrF,MAAM,MAAM,iBAAiB,GAAG,aAAa,GAAG;IAC9C,KAAK,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,IAAI,CAAC;IACxB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iFAAiF;IACjF,WAAW,CAAC,EAAE,mBAAmB,CAAC;CACnC,CAAC;AAqBF,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,WAAW,EACX,OAAO,EACP,WAAW,EACX,YAAY,EACZ,UAAkB,EAClB,WAAuB,EACvB,GAAG,SAAS,EACb,EAAE,iBAAiB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA6DvC"}
|
|
@@ -2,6 +2,8 @@ import type { CSSObject, SxProps, Theme } from '@mui/material/styles/index.js';
|
|
|
2
2
|
import type { SettingsNavStatus, SettingsRailBreakpoint } from './SettingsLayout.types';
|
|
3
3
|
/** Fixed width of the left navigation rail once it has its own column (300 design px). */
|
|
4
4
|
export declare const railWidth: (theme: Theme) => string;
|
|
5
|
+
/** Width of the rail drawn as a card (`railVariant="card"`, 200 design px). */
|
|
6
|
+
export declare const railCardWidth: (theme: Theme) => string;
|
|
5
7
|
/** Visually hidden, still read aloud — for text a marker's colour cannot carry. */
|
|
6
8
|
export declare const SR_ONLY_SX: SxProps<Theme>;
|
|
7
9
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsLayout.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/SettingsLayout.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAI/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAExF,0FAA0F;AAC1F,eAAO,MAAM,SAAS,GAAI,OAAO,KAAK,KAAG,MAAyB,CAAC;AAEnE,mFAAmF;AACnF,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,KAAK,CAUrC,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,sBAAsB,GAAG,MAAM,CAEpF;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,sBAAsB,EAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,SAAS,CAEX;AAED,iFAAiF;AACjF,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC,EAAE,MAAM,CAI7E,CAAC"}
|
|
1
|
+
{"version":3,"file":"SettingsLayout.styles.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/SettingsLayout.styles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAI/E,OAAO,KAAK,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAExF,0FAA0F;AAC1F,eAAO,MAAM,SAAS,GAAI,OAAO,KAAK,KAAG,MAAyB,CAAC;AAEnE,+EAA+E;AAC/E,eAAO,MAAM,aAAa,GAAI,OAAO,KAAK,KAAG,MAAyB,CAAC;AAEvE,mFAAmF;AACnF,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,KAAK,CAUrC,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,sBAAsB,GAAG,MAAM,CAEpF;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,KAAK,EACZ,UAAU,EAAE,sBAAsB,EAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,SAAS,CAEX;AAED,iFAAiF;AACjF,eAAO,MAAM,YAAY,KAAK,CAAC;AAE/B;;;;;GAKG;AACH,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,EAAE,QAAQ,CAAC,EAAE,MAAM,CAI7E,CAAC"}
|
|
@@ -83,6 +83,11 @@ export type SettingsRailBreakpoint = 'sm' | 'md' | 'lg' | 'xl' | number;
|
|
|
83
83
|
* does, and what fits at 375px, where a 300px rail would leave 75px of content.
|
|
84
84
|
*/
|
|
85
85
|
export type SettingsNavVariant = 'switcher' | 'drilldown';
|
|
86
|
+
/**
|
|
87
|
+
* How the rail is drawn once it has its own column: `divided` — a 300px column
|
|
88
|
+
* ruled off from the panel; `card` — a 200px bordered card beside it.
|
|
89
|
+
*/
|
|
90
|
+
export type SettingsRailVariant = 'divided' | 'card';
|
|
86
91
|
/** The exit offered inside the empty-search state, so the dead end has a door. */
|
|
87
92
|
export interface SettingsEmptySearchAction {
|
|
88
93
|
/** Button label, e.g. `"Limpar a busca"`. */
|
|
@@ -160,6 +165,20 @@ export interface SettingsLayoutProps {
|
|
|
160
165
|
railBreakpoint?: SettingsRailBreakpoint;
|
|
161
166
|
/** Narrow-width navigation shape. Defaults to `"switcher"`. */
|
|
162
167
|
navVariant?: SettingsNavVariant;
|
|
168
|
+
/**
|
|
169
|
+
* Whether the rail carries its search field. Defaults to `true`.
|
|
170
|
+
*
|
|
171
|
+
* A settings area with twenty categories needs the field; an area of eight
|
|
172
|
+
* rows a reader takes in at a glance is better without one, which is how a
|
|
173
|
+
* storefront's own account area draws it. Off, the rail shows every group.
|
|
174
|
+
*/
|
|
175
|
+
searchable?: boolean;
|
|
176
|
+
/**
|
|
177
|
+
* How the rail is drawn from `railBreakpoint` up. Defaults to `"divided"`
|
|
178
|
+
* (a 300px column ruled off from the panel); `"card"` draws it as a 200px
|
|
179
|
+
* bordered card. Below the breakpoint both look the same.
|
|
180
|
+
*/
|
|
181
|
+
railVariant?: SettingsRailVariant;
|
|
163
182
|
/**
|
|
164
183
|
* True when the router is at the area's index rather than inside a section.
|
|
165
184
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SettingsLayout.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/SettingsLayout.types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SettingsLayout.types.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/SettingsLayout.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,5 +3,5 @@ export { SettingsSectionChips } from './SettingsSectionChips';
|
|
|
3
3
|
export type { SettingsSectionChipsProps } from './SettingsSectionChips';
|
|
4
4
|
export { SettingsStatusMarker } from './SettingsStatusMarker';
|
|
5
5
|
export type { SettingsStatusMarkerProps } from './SettingsStatusMarker';
|
|
6
|
-
export type { SettingsEmptySearchAction, SettingsLayoutProps, SettingsNavGroup, SettingsNavItem, SettingsNavStatus, SettingsNavVariant, SettingsRailBreakpoint, } from './SettingsLayout.types';
|
|
6
|
+
export type { SettingsEmptySearchAction, SettingsLayoutProps, SettingsNavGroup, SettingsNavItem, SettingsNavStatus, SettingsNavVariant, SettingsRailVariant, SettingsRailBreakpoint, } from './SettingsLayout.types';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,YAAY,EACV,yBAAyB,EACzB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/components/layout/SettingsLayout/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACxE,YAAY,EACV,yBAAyB,EACzB,mBAAmB,EACnB,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,wBAAwB,CAAC"}
|
package/package.json
CHANGED
|
@@ -65,12 +65,17 @@ const StyledTextarea = styled(TextareaAutosize, {
|
|
|
65
65
|
const colorPalette = getColorFromTheme(theme, customColor);
|
|
66
66
|
const errorColor = theme.palette.error;
|
|
67
67
|
|
|
68
|
+
// No min-height here: the box's height is counted in LINES of its own text
|
|
69
|
+
// (`minRows`). A pixel floor broke that twice over — it ignored the font, and
|
|
70
|
+
// `TextareaAutosize` measures one row on a hidden copy carrying this same
|
|
71
|
+
// class, so a "row" came out as the whole floor and `minRows={2}` drew about
|
|
72
|
+
// 200px (FUT-3504, FUT-3534).
|
|
68
73
|
const sizeMap = {
|
|
69
|
-
xs: { padding: rems(theme, 6, 8), fontSize: rem(theme, 12)
|
|
70
|
-
sm: { padding: rems(theme, 8, 10), fontSize: rem(theme, 14)
|
|
71
|
-
md: { padding: rems(theme, 10, 12), fontSize: rem(theme, 16)
|
|
72
|
-
lg: { padding: rems(theme, 12, 14), fontSize: rem(theme, 18)
|
|
73
|
-
xl: { padding: rems(theme, 14, 16), fontSize: rem(theme, 20)
|
|
74
|
+
xs: { padding: rems(theme, 6, 8), fontSize: rem(theme, 12) },
|
|
75
|
+
sm: { padding: rems(theme, 8, 10), fontSize: rem(theme, 14) },
|
|
76
|
+
md: { padding: rems(theme, 10, 12), fontSize: rem(theme, 16) },
|
|
77
|
+
lg: { padding: rems(theme, 12, 14), fontSize: rem(theme, 18) },
|
|
78
|
+
xl: { padding: rems(theme, 14, 16), fontSize: rem(theme, 20) } };
|
|
74
79
|
|
|
75
80
|
const baseStyles = {
|
|
76
81
|
width: '100%',
|
|
@@ -143,7 +148,9 @@ const TEXTAREA_DEFAULTS = {
|
|
|
143
148
|
glass: false,
|
|
144
149
|
gradient: false,
|
|
145
150
|
iconPosition: 'start',
|
|
146
|
-
|
|
151
|
+
// Four lines of its own text, whatever the variant or size (FUT-3534); a
|
|
152
|
+
// screen that wants another height passes `minRows`.
|
|
153
|
+
minRows: 4 } satisfies Partial<TextareaProps>;
|
|
147
154
|
|
|
148
155
|
// Strips explicitly-undefined props before the merge, so `prop={undefined}`
|
|
149
156
|
// still falls back to the default as a destructuring default would.
|
|
@@ -304,7 +311,7 @@ export const Textarea: React.FC<TextareaProps> = (textareaProps) => {
|
|
|
304
311
|
glass={glass}
|
|
305
312
|
gradient={gradient}
|
|
306
313
|
error={error}
|
|
307
|
-
minRows={
|
|
314
|
+
minRows={minRows}
|
|
308
315
|
maxRows={variant === 'autosize' ? maxRows : undefined}
|
|
309
316
|
style={textareaStyle}
|
|
310
317
|
aria-label={label || props['aria-label']}
|
|
@@ -77,12 +77,14 @@ export interface TextareaBaseProps
|
|
|
77
77
|
gradient?: boolean;
|
|
78
78
|
|
|
79
79
|
/**
|
|
80
|
-
*
|
|
80
|
+
* How many lines of its own text the box opens at, in every variant.
|
|
81
|
+
* Defaults to 4; pass it to override.
|
|
81
82
|
*/
|
|
82
83
|
minRows?: number;
|
|
83
84
|
|
|
84
85
|
/**
|
|
85
|
-
*
|
|
86
|
+
* The most lines the `autosize` variant grows to before it scrolls.
|
|
87
|
+
* The other variants ignore it.
|
|
86
88
|
*/
|
|
87
89
|
maxRows?: number;
|
|
88
90
|
|
|
@@ -165,6 +165,23 @@ it: a `position: sticky` toolbar inside `children` pins to the top of the
|
|
|
165
165
|
the scroll container.
|
|
166
166
|
|
|
167
167
|
|
|
168
|
+
## A small area: no search, a card rail (`searchable`, `railVariant`)
|
|
169
|
+
|
|
170
|
+
The search field earns its place in an area of twenty categories. In one of
|
|
171
|
+
eight rows a reader takes in at a glance it is a control nobody needs, so
|
|
172
|
+
`searchable={false}` leaves it out and the rail shows every group.
|
|
173
|
+
|
|
174
|
+
`railVariant="card"` draws the rail, from `railBreakpoint` up, as a 200px
|
|
175
|
+
bordered card beside the panel instead of the default 300px column ruled off
|
|
176
|
+
from it. Below the breakpoint both variants look the same.
|
|
177
|
+
|
|
178
|
+
```tsx
|
|
179
|
+
<SettingsLayout searchable={false} railVariant="card" …>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Both default to today's shape, so an upgrade changes nothing for an area that
|
|
183
|
+
does not ask.
|
|
184
|
+
|
|
168
185
|
## Props
|
|
169
186
|
|
|
170
187
|
### SettingsLayoutProps
|
|
@@ -184,6 +201,8 @@ the scroll container.
|
|
|
184
201
|
| railBreakpoint | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Width at which the rail takes its own column |
|
|
185
202
|
| fillHeight | boolean | `false` | Rail and panel each scroll themselves (needs a definite height) |
|
|
186
203
|
| navVariant | `'switcher' \| 'drilldown'` | `'switcher'` | Narrow-width navigation shape |
|
|
204
|
+
| searchable | boolean | `true` | Whether the rail carries its search field |
|
|
205
|
+
| railVariant | `'divided' \| 'card'` | `'divided'` | From the breakpoint up: a 300px ruled column, or a 200px card |
|
|
187
206
|
| atIndex | boolean | `false` | `drilldown`: the router is at the area's index, not in a section |
|
|
188
207
|
| indexHref | string | - | `drilldown`: where the back link goes |
|
|
189
208
|
| backLabel | string | `'Back'` | Label on the back control |
|
|
@@ -6,17 +6,19 @@ import Box from '@mui/material/Box/index.js';
|
|
|
6
6
|
import Button from '@mui/material/Button/index.js';
|
|
7
7
|
import InputAdornment from '@mui/material/InputAdornment/index.js';
|
|
8
8
|
import TextField from '@mui/material/TextField/index.js';
|
|
9
|
+
import type { Theme } from '@mui/material/styles/index.js';
|
|
9
10
|
import Typography from '@mui/material/Typography/index.js';
|
|
10
11
|
import React from 'react';
|
|
11
12
|
|
|
12
13
|
import { SettingsRailGroup, type RailShape } from './SettingsLayout.items';
|
|
13
|
-
import { atLeastRail, displayAcrossRail, railWidth, TOUCH_TARGET } from './SettingsLayout.styles';
|
|
14
|
+
import { atLeastRail, displayAcrossRail, railCardWidth, railWidth, TOUCH_TARGET } from './SettingsLayout.styles';
|
|
14
15
|
import { rem, sxRem } from '../../../tokens/relative';
|
|
15
16
|
import type {
|
|
16
17
|
SettingsEmptySearchAction,
|
|
17
18
|
SettingsLayoutProps,
|
|
18
19
|
SettingsNavGroup,
|
|
19
20
|
SettingsRailBreakpoint,
|
|
21
|
+
SettingsRailVariant,
|
|
20
22
|
} from './SettingsLayout.types';
|
|
21
23
|
|
|
22
24
|
interface RailToggleProps {
|
|
@@ -139,9 +141,39 @@ export interface RailBodyProps extends RailShape {
|
|
|
139
141
|
onSelectItem?: (id: string) => void;
|
|
140
142
|
onNavigate?: () => void;
|
|
141
143
|
testIdPrefix: string;
|
|
144
|
+
/** Whether the search field is drawn (`SettingsLayoutProps.searchable`). */
|
|
145
|
+
searchable: boolean;
|
|
142
146
|
}
|
|
143
147
|
|
|
144
|
-
/** The
|
|
148
|
+
/** The rail's search field. */
|
|
149
|
+
function RailSearch({
|
|
150
|
+
query,
|
|
151
|
+
onQueryChange,
|
|
152
|
+
searchPlaceholder,
|
|
153
|
+
testIdPrefix,
|
|
154
|
+
}: Pick<RailBodyProps, 'query' | 'onQueryChange' | 'searchPlaceholder' | 'testIdPrefix'>): React.JSX.Element {
|
|
155
|
+
return (
|
|
156
|
+
<TextField
|
|
157
|
+
value={query}
|
|
158
|
+
onChange={(event) => onQueryChange(event.target.value)}
|
|
159
|
+
placeholder={searchPlaceholder}
|
|
160
|
+
size="small"
|
|
161
|
+
fullWidth
|
|
162
|
+
aria-label={searchPlaceholder}
|
|
163
|
+
data-testid={`${testIdPrefix}-search`}
|
|
164
|
+
InputProps={{
|
|
165
|
+
startAdornment: (
|
|
166
|
+
<InputAdornment position="start">
|
|
167
|
+
<SearchIcon fontSize="small" sx={{ color: 'text.secondary' }} />
|
|
168
|
+
</InputAdornment>
|
|
169
|
+
),
|
|
170
|
+
}}
|
|
171
|
+
sx={{ mb: 2 }}
|
|
172
|
+
/>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** The rail body: the search field when the area has one, then the groups. */
|
|
145
177
|
function SettingsRailBody({
|
|
146
178
|
navOpen,
|
|
147
179
|
query,
|
|
@@ -155,6 +187,7 @@ function SettingsRailBody({
|
|
|
155
187
|
onSelectItem,
|
|
156
188
|
onNavigate,
|
|
157
189
|
testIdPrefix,
|
|
190
|
+
searchable,
|
|
158
191
|
...shape
|
|
159
192
|
}: RailBodyProps): React.JSX.Element {
|
|
160
193
|
// `drilldown` has no disclosure to be closed behind: below the breakpoint the
|
|
@@ -169,23 +202,14 @@ function SettingsRailBody({
|
|
|
169
202
|
: displayAcrossRail(theme, shape.breakpoint, hidden, 'block')
|
|
170
203
|
}
|
|
171
204
|
>
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
InputProps={{
|
|
181
|
-
startAdornment: (
|
|
182
|
-
<InputAdornment position="start">
|
|
183
|
-
<SearchIcon fontSize="small" sx={{ color: 'text.secondary' }} />
|
|
184
|
-
</InputAdornment>
|
|
185
|
-
),
|
|
186
|
-
}}
|
|
187
|
-
sx={{ mb: 2 }}
|
|
188
|
-
/>
|
|
205
|
+
{searchable ? (
|
|
206
|
+
<RailSearch
|
|
207
|
+
query={query}
|
|
208
|
+
onQueryChange={onQueryChange}
|
|
209
|
+
searchPlaceholder={searchPlaceholder}
|
|
210
|
+
testIdPrefix={testIdPrefix}
|
|
211
|
+
/>
|
|
212
|
+
) : null}
|
|
189
213
|
{filteredGroups.length === 0 ? (
|
|
190
214
|
<SettingsSearchEmpty
|
|
191
215
|
label={emptySearchLabel}
|
|
@@ -218,8 +242,29 @@ export type SettingsRailProps = RailBodyProps & {
|
|
|
218
242
|
onToggleNav: () => void;
|
|
219
243
|
/** Scroll inside the rail rather than with the page. See `fillHeight`. */
|
|
220
244
|
fillHeight?: boolean;
|
|
245
|
+
/** How the rail's own column is drawn. See `SettingsLayoutProps.railVariant`. */
|
|
246
|
+
railVariant?: SettingsRailVariant;
|
|
221
247
|
};
|
|
222
248
|
|
|
249
|
+
/** The rail's own column, as the variant draws it: ruled off, or a card. */
|
|
250
|
+
function railColumnSx(theme: Theme, railVariant: SettingsRailVariant): Record<string, unknown> {
|
|
251
|
+
if (railVariant === 'card') {
|
|
252
|
+
const width = railCardWidth(theme);
|
|
253
|
+
return {
|
|
254
|
+
flex: `0 0 ${width}`,
|
|
255
|
+
width,
|
|
256
|
+
alignSelf: 'flex-start',
|
|
257
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
258
|
+
borderRadius: sxRem(14),
|
|
259
|
+
bgcolor: 'background.paper',
|
|
260
|
+
px: sxRem(12),
|
|
261
|
+
py: sxRem(16),
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
const width = railWidth(theme);
|
|
265
|
+
return { flex: `0 0 ${width}`, width, borderRight: `1px solid ${theme.palette.divider}`, pr: sxRem(16) };
|
|
266
|
+
}
|
|
267
|
+
|
|
223
268
|
/** The navigation column: title, the `switcher`'s disclosure, and the body. */
|
|
224
269
|
export function SettingsRail({
|
|
225
270
|
title,
|
|
@@ -228,6 +273,7 @@ export function SettingsRail({
|
|
|
228
273
|
onToggleNav,
|
|
229
274
|
testIdPrefix,
|
|
230
275
|
fillHeight = false,
|
|
276
|
+
railVariant = 'divided',
|
|
231
277
|
...bodyProps
|
|
232
278
|
}: SettingsRailProps): React.JSX.Element {
|
|
233
279
|
const { variant, breakpoint, atIndex } = bodyProps;
|
|
@@ -243,16 +289,14 @@ export function SettingsRail({
|
|
|
243
289
|
component="nav"
|
|
244
290
|
aria-label={typeof title === 'string' ? title : 'Settings'}
|
|
245
291
|
data-testid={`${testIdPrefix}-rail`}
|
|
292
|
+
data-rail-variant={railVariant}
|
|
246
293
|
sx={(theme) => ({
|
|
247
294
|
display: hiddenWhileInSection ? 'none' : 'block',
|
|
248
295
|
flex: '0 0 auto',
|
|
249
296
|
width: '100%',
|
|
250
297
|
[atLeastRail(theme, breakpoint)]: {
|
|
251
298
|
display: 'block',
|
|
252
|
-
|
|
253
|
-
width: railWidth(theme),
|
|
254
|
-
borderRight: `1px solid ${theme.palette.divider}`,
|
|
255
|
-
pr: 2,
|
|
299
|
+
...railColumnSx(theme, railVariant),
|
|
256
300
|
// Its own scrollbar, so a settings area with twenty categories does
|
|
257
301
|
// not make the thing you NAVIGATE with scroll away while you read the
|
|
258
302
|
// panel. `minHeight: 0` is the load-bearing half: without it a flex
|
|
@@ -7,6 +7,9 @@ import type { SettingsNavStatus, SettingsRailBreakpoint } from './SettingsLayout
|
|
|
7
7
|
/** Fixed width of the left navigation rail once it has its own column (300 design px). */
|
|
8
8
|
export const railWidth = (theme: Theme): string => rem(theme, 300);
|
|
9
9
|
|
|
10
|
+
/** Width of the rail drawn as a card (`railVariant="card"`, 200 design px). */
|
|
11
|
+
export const railCardWidth = (theme: Theme): string => rem(theme, 200);
|
|
12
|
+
|
|
10
13
|
/** Visually hidden, still read aloud — for text a marker's colour cannot carry. */
|
|
11
14
|
export const SR_ONLY_SX: SxProps<Theme> = {
|
|
12
15
|
position: 'absolute',
|
|
@@ -46,6 +46,17 @@ const DEFAULTS = {
|
|
|
46
46
|
backLabel: 'Back',
|
|
47
47
|
} satisfies Partial<SettingsLayoutProps>;
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* How the rail looks: its search field, and its frame from the breakpoint up.
|
|
51
|
+
* Both default to the shape every consumer had before they existed.
|
|
52
|
+
*/
|
|
53
|
+
function railLookOf({
|
|
54
|
+
searchable = true,
|
|
55
|
+
railVariant = 'divided',
|
|
56
|
+
}: SettingsLayoutProps): Required<Pick<SettingsLayoutProps, 'searchable' | 'railVariant'>> {
|
|
57
|
+
return { searchable, railVariant };
|
|
58
|
+
}
|
|
59
|
+
|
|
49
60
|
/** Stacked below the rail's breakpoint, two columns at and above it. */
|
|
50
61
|
function shellSx(breakpoint: SettingsLayoutProps['railBreakpoint'], fillHeight: boolean): SxProps<Theme> {
|
|
51
62
|
return (theme: Theme) => ({
|
|
@@ -145,6 +156,7 @@ export const SettingsLayout: React.FC<SettingsLayoutProps> = (props) => {
|
|
|
145
156
|
onNavigate={() => setNavOpen(false)}
|
|
146
157
|
testIdPrefix={testIdPrefix}
|
|
147
158
|
variant={navVariant}
|
|
159
|
+
{...railLookOf(props)}
|
|
148
160
|
breakpoint={railBreakpoint}
|
|
149
161
|
atIndex={atIndex}
|
|
150
162
|
fillHeight={fillHeight}
|
|
@@ -89,6 +89,12 @@ export type SettingsRailBreakpoint = 'sm' | 'md' | 'lg' | 'xl' | number;
|
|
|
89
89
|
*/
|
|
90
90
|
export type SettingsNavVariant = 'switcher' | 'drilldown';
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* How the rail is drawn once it has its own column: `divided` — a 300px column
|
|
94
|
+
* ruled off from the panel; `card` — a 200px bordered card beside it.
|
|
95
|
+
*/
|
|
96
|
+
export type SettingsRailVariant = 'divided' | 'card';
|
|
97
|
+
|
|
92
98
|
/** The exit offered inside the empty-search state, so the dead end has a door. */
|
|
93
99
|
export interface SettingsEmptySearchAction {
|
|
94
100
|
/** Button label, e.g. `"Limpar a busca"`. */
|
|
@@ -168,6 +174,20 @@ export interface SettingsLayoutProps {
|
|
|
168
174
|
railBreakpoint?: SettingsRailBreakpoint;
|
|
169
175
|
/** Narrow-width navigation shape. Defaults to `"switcher"`. */
|
|
170
176
|
navVariant?: SettingsNavVariant;
|
|
177
|
+
/**
|
|
178
|
+
* Whether the rail carries its search field. Defaults to `true`.
|
|
179
|
+
*
|
|
180
|
+
* A settings area with twenty categories needs the field; an area of eight
|
|
181
|
+
* rows a reader takes in at a glance is better without one, which is how a
|
|
182
|
+
* storefront's own account area draws it. Off, the rail shows every group.
|
|
183
|
+
*/
|
|
184
|
+
searchable?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* How the rail is drawn from `railBreakpoint` up. Defaults to `"divided"`
|
|
187
|
+
* (a 300px column ruled off from the panel); `"card"` draws it as a 200px
|
|
188
|
+
* bordered card. Below the breakpoint both look the same.
|
|
189
|
+
*/
|
|
190
|
+
railVariant?: SettingsRailVariant;
|
|
171
191
|
/**
|
|
172
192
|
* True when the router is at the area's index rather than inside a section.
|
|
173
193
|
*
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/SettingsLayout/SettingsLayout.styles.ts"],"sourcesContent":["import type { CSSObject, SxProps, Theme } from '@mui/material/styles/index.js';\n\nimport { rem, sxRem } from '../../../tokens/relative';\n\nimport type { SettingsNavStatus, SettingsRailBreakpoint } from './SettingsLayout.types';\n\n/** Fixed width of the left navigation rail once it has its own column (300 design px). */\nexport const railWidth = (theme: Theme): string => rem(theme, 300);\n\n/** Visually hidden, still read aloud — for text a marker's colour cannot carry. */\nexport const SR_ONLY_SX: SxProps<Theme> = {\n position: 'absolute',\n width: sxRem(1),\n height: sxRem(1),\n padding: 0,\n margin: sxRem(-1),\n overflow: 'hidden',\n clip: 'rect(0, 0, 0, 0)',\n whiteSpace: 'nowrap',\n border: 0,\n};\n\n/**\n * The media query for \"the rail has its own column\".\n *\n * `theme.breakpoints.up` takes a NUMBER as happily as a name, which is why\n * `railBreakpoint` accepts one: a settings area whose structural switch is at\n * 1024px has no MUI breakpoint to name (the default `lg` is 1200), and rounding\n * the design to the nearest named breakpoint moves 176px of behaviour to keep a\n * string tidy.\n */\nexport function atLeastRail(theme: Theme, breakpoint: SettingsRailBreakpoint): string {\n return theme.breakpoints.up(breakpoint);\n}\n\n/**\n * A `display` pair across that query: `narrow` below it, `wide` at and above.\n *\n * Everything that changes shape between the two navigation modes goes through\n * this, so \"which width am I?\" is answered once, in CSS, for every part at\n * once — rather than by each part asking a media query in JavaScript and\n * answering slightly differently.\n */\nexport function displayAcrossRail(\n theme: Theme,\n breakpoint: SettingsRailBreakpoint,\n narrow: string,\n wide: string,\n): CSSObject {\n return { display: narrow, [atLeastRail(theme, breakpoint)]: { display: wide } };\n}\n\n/** Minimum touch target, in px. Held down to 320px-wide phones, deliberately. */\nexport const TOUCH_TARGET = 44;\n\n/**\n * Palette role per situation.\n *\n * Returned as theme keys rather than hex so a marker follows the host's theme —\n * and so light and dark do not need two copies of this table.\n */\nexport const STATUS_COLOR: Record<Exclude<SettingsNavStatus, 'locked'>, string> = {\n ok: 'success.main',\n off: 'text.disabled',\n new: 'error.main',\n};\n"],"mappings":";;;;;;AAOO,IAAM,YAAY,CAAC,UAAyB,IAAI,OAAO,GAAG;AAG1D,IAAM,aAA6B;AAAA,EACxC,UAAU;AAAA,EACV,OAAO,MAAM,CAAC;AAAA,EACd,QAAQ,MAAM,CAAC;AAAA,EACf,SAAS;AAAA,EACT,QAAQ,MAAM,EAAE;AAAA,EAChB,UAAU;AAAA,EACV,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,QAAQ;AACV;AAWO,SAAS,YAAY,OAAc,YAA4C;AACpF,SAAO,MAAM,YAAY,GAAG,UAAU;AACxC;AAUO,SAAS,kBACd,OACA,YACA,QACA,MACW;AACX,SAAO,EAAE,SAAS,QAAQ,CAAC,YAAY,OAAO,UAAU,CAAC,GAAG,EAAE,SAAS,KAAK,EAAE;AAChF;AAGO,IAAM,eAAe;AAQrB,IAAM,eAAqE;AAAA,EAChF,IAAI;AAAA,EACJ,KAAK;AAAA,EACL,KAAK;AACP;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/SettingsLayout/SettingsLayout.tsx"],"sourcesContent":["'use client';\n\nimport Box from '@mui/material/Box/index.js';\nimport type { SxProps, Theme } from '@mui/material/styles/index.js';\nimport React, { useMemo, useState } from 'react';\n\nimport { withDefaults } from '../../../utils/withDefaults';\nimport { activeItemLabel, filterGroups } from './SettingsLayout.filters';\nimport { SettingsRail } from './SettingsLayout.rail';\nimport { atLeastRail } from './SettingsLayout.styles';\nimport { SettingsPanel } from './SettingsPanel';\nimport type { SettingsLayoutProps } from './SettingsLayout.types';\n\n/**\n * The props with every default already applied.\n *\n * A table through `withDefaults` rather than a `= default` per destructured\n * prop: each of those is a branch, and seven of them put the component over the\n * complexity bar before it renders anything. The single cast is what buys the\n * body non-optional values — without it every use site would restate the\n * default as a `??`, which is the same default written twice and free to drift.\n */\ntype ResolvedProps = SettingsLayoutProps &\n Required<\n Pick<\n SettingsLayoutProps,\n | 'searchPlaceholder'\n | 'defaultQuery'\n | 'emptySearchLabel'\n | 'testIdPrefix'\n | 'railBreakpoint'\n | 'navVariant'\n | 'atIndex'\n | 'backLabel'\n >\n >;\n\nconst DEFAULTS = {\n searchPlaceholder: 'Search settings',\n defaultQuery: '',\n emptySearchLabel: 'No settings match your search.',\n testIdPrefix: 'settings',\n railBreakpoint: 'md',\n navVariant: 'switcher',\n atIndex: false,\n backLabel: 'Back',\n} satisfies Partial<SettingsLayoutProps>;\n\n/** Stacked below the rail's breakpoint, two columns at and above it. */\nfunction shellSx(breakpoint: SettingsLayoutProps['railBreakpoint'], fillHeight: boolean): SxProps<Theme> {\n return (theme: Theme) => ({\n display: 'flex',\n flexDirection: 'column' as const,\n alignItems: 'stretch',\n gap: 1.5,\n width: '100%',\n minWidth: 0,\n // Only ever at the wide shape. Narrow, the rail is a disclosure or the page\n // itself, and two independent scrollbars on a phone is a trap rather than a\n // convenience.\n [atLeastRail(theme, breakpoint ?? 'md')]: {\n flexDirection: 'row',\n gap: 3,\n ...(fillHeight ? { height: '100%', minHeight: 0 } : {}),\n },\n });\n}\n\n/**\n * A reusable, agnostic Facebook-style settings shell: a searchable left rail of\n * grouped categories/subcategories and a central panel that renders the selected\n * configuration screen (`children`). Navigation is data-driven via `groups`; the\n * host owns routing (pass `linkComponent` + item `href`, or handle `onSelectItem`).\n *\n * ## Two narrow-width shapes\n *\n * `navVariant=\"switcher\"` (the default) folds the rail into a disclosure above\n * the panel. `navVariant=\"drilldown\"` gives the phone shape instead: at the\n * area's index the LIST is the page, and inside a section the panel is the page\n * with a back link and a scrollable strip of sibling sections above it.\n *\n * ## Why the width decision is CSS and not JavaScript\n *\n * Every part that changes between the two shapes does it through a `display`\n * pair keyed on `railBreakpoint`. Nothing here asks a media query in JS and\n * renders one branch.\n *\n * That is not a performance preference. A layout that RENDERS one navigation and\n * not the other can offer the narrow width less than the wide one, and no test\n * or review catches it — the missing control simply is not in the tree to be\n * asserted about. With both forms always mounted, \"the narrow width reaches\n * everything the wide one does\" holds by construction, and an audit that counts\n * controls per width gets the same answer at both.\n */\nexport const SettingsLayout: React.FC<SettingsLayoutProps> = (props) => {\n const {\n title,\n groups,\n activeItemId,\n onSelectItem,\n searchPlaceholder,\n defaultQuery,\n emptySearchLabel,\n emptySearchAction,\n linkComponent,\n children,\n testIdPrefix,\n railBreakpoint,\n fillHeight = false,\n navVariant,\n atIndex,\n indexHref,\n backLabel,\n sectionChips,\n } = withDefaults(props, DEFAULTS) as ResolvedProps;\n const [query, setQuery] = useState(defaultQuery);\n const [navOpen, setNavOpen] = useState(false);\n const filteredGroups = useMemo(() => filterGroups(groups, query), [groups, query]);\n const activeLabel = useMemo(() => activeItemLabel(groups, activeItemId), [groups, activeItemId]);\n\n const drilldown = navVariant === 'drilldown';\n const ariaLabel = typeof title === 'string' ? title : 'Settings';\n\n return (\n <Box\n data-testid={testIdPrefix}\n data-nav-variant={navVariant}\n data-at-index={atIndex ? 'true' : 'false'}\n sx={shellSx(railBreakpoint, fillHeight)}\n >\n <SettingsRail\n title={title}\n activeLabel={activeLabel}\n navOpen={navOpen}\n onToggleNav={() => setNavOpen((open) => !open)}\n query={query}\n onQueryChange={setQuery}\n searchPlaceholder={searchPlaceholder}\n emptySearchLabel={emptySearchLabel}\n emptySearchAction={emptySearchAction}\n filteredGroups={filteredGroups}\n activeItemId={activeItemId}\n linkComponent={linkComponent}\n onSelectItem={onSelectItem}\n onNavigate={() => setNavOpen(false)}\n testIdPrefix={testIdPrefix}\n variant={navVariant}\n breakpoint={railBreakpoint}\n atIndex={atIndex}\n fillHeight={fillHeight}\n />\n\n <SettingsPanel\n inSection={drilldown && !atIndex}\n hideOnNarrow={drilldown && atIndex}\n breakpoint={railBreakpoint}\n indexHref={indexHref}\n sectionTitle={props.sectionTitle}\n sectionDescription={props.sectionDescription}\n backLabel={backLabel}\n ariaLabel={ariaLabel}\n sectionChips={sectionChips}\n activeItemId={activeItemId}\n linkComponent={linkComponent}\n onSelectItem={onSelectItem}\n testIdPrefix={testIdPrefix}\n fillHeight={fillHeight}\n >\n {children}\n </SettingsPanel>\n </Box>\n );\n};\n\nSettingsLayout.displayName = 'SettingsLayout';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAEA,OAAO,SAAS;AAEhB,SAAgB,SAAS,gBAAgB;AAwHrC,SAME,KANF;AAvFJ,IAAM,WAAW;AAAA,EACf,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,WAAW;AACb;AAGA,SAAS,QAAQ,YAAmD,YAAqC;AACvG,SAAO,CAAC,WAAkB;AAAA,IACxB,SAAS;AAAA,IACT,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,OAAO;AAAA,IACP,UAAU;AAAA;AAAA;AAAA;AAAA,IAIV,CAAC,YAAY,OAAO,cAAc,IAAI,CAAC,GAAG;AAAA,MACxC,eAAe;AAAA,MACf,KAAK;AAAA,MACL,GAAI,aAAa,EAAE,QAAQ,QAAQ,WAAW,EAAE,IAAI,CAAC;AAAA,IACvD;AAAA,EACF;AACF;AA4BO,IAAM,iBAAgD,CAAC,UAAU;AACtE,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,aAAa,OAAO,QAAQ;AAChC,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,YAAY;AAC/C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,QAAM,iBAAiB,QAAQ,MAAM,aAAa,QAAQ,KAAK,GAAG,CAAC,QAAQ,KAAK,CAAC;AACjF,QAAM,cAAc,QAAQ,MAAM,gBAAgB,QAAQ,YAAY,GAAG,CAAC,QAAQ,YAAY,CAAC;AAE/F,QAAM,YAAY,eAAe;AACjC,QAAM,YAAY,OAAO,UAAU,WAAW,QAAQ;AAEtD,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAa;AAAA,MACb,oBAAkB;AAAA,MAClB,iBAAe,UAAU,SAAS;AAAA,MAClC,IAAI,QAAQ,gBAAgB,UAAU;AAAA,MAEtC;AAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA,aAAa,MAAM,WAAW,CAAC,SAAS,CAAC,IAAI;AAAA,YAC7C;AAAA,YACA,eAAe;AAAA,YACf;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA,YAAY,MAAM,WAAW,KAAK;AAAA,YAClC;AAAA,YACA,SAAS;AAAA,YACT,YAAY;AAAA,YACZ;AAAA,YACA;AAAA;AAAA,QACF;AAAA,QAEA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,aAAa,CAAC;AAAA,YACzB,cAAc,aAAa;AAAA,YAC3B,YAAY;AAAA,YACZ;AAAA,YACA,cAAc,MAAM;AAAA,YACpB,oBAAoB,MAAM;AAAA,YAC1B;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YAEC;AAAA;AAAA,QACH;AAAA;AAAA;AAAA,EACF;AAEJ;AAEA,eAAe,cAAc;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/layout/SettingsLayout/SettingsLayout.rail.tsx"],"sourcesContent":["'use client';\n\nimport ExpandMoreIcon from '@mui/icons-material/ExpandMore';\nimport SearchIcon from '@mui/icons-material/Search';\nimport Box from '@mui/material/Box/index.js';\nimport Button from '@mui/material/Button/index.js';\nimport InputAdornment from '@mui/material/InputAdornment/index.js';\nimport TextField from '@mui/material/TextField/index.js';\nimport Typography from '@mui/material/Typography/index.js';\nimport React from 'react';\n\nimport { SettingsRailGroup, type RailShape } from './SettingsLayout.items';\nimport { atLeastRail, displayAcrossRail, railWidth, TOUCH_TARGET } from './SettingsLayout.styles';\nimport { rem, sxRem } from '../../../tokens/relative';\nimport type {\n SettingsEmptySearchAction,\n SettingsLayoutProps,\n SettingsNavGroup,\n SettingsRailBreakpoint,\n} from './SettingsLayout.types';\n\ninterface RailToggleProps {\n title?: React.ReactNode;\n activeLabel?: string;\n open: boolean;\n onToggle: () => void;\n breakpoint: SettingsRailBreakpoint;\n testIdPrefix: string;\n}\n\n/**\n * `switcher`-only collapse control: shows the current section (a compact\n * switcher) so the panel content stays at the top of the screen. Hidden once the\n * rail has its own column.\n */\nfunction SettingsRailToggle({\n title,\n activeLabel,\n open,\n onToggle,\n breakpoint,\n testIdPrefix,\n}: RailToggleProps): React.JSX.Element {\n return (\n <Box\n component=\"button\"\n type=\"button\"\n onClick={onToggle}\n aria-expanded={open}\n aria-label={typeof title === 'string' ? title : 'Settings'}\n data-testid={`${testIdPrefix}-toggle`}\n sx={(theme) => ({\n ...displayAcrossRail(theme, breakpoint, 'flex', 'none'),\n alignItems: 'center',\n justifyContent: 'space-between',\n gap: 1,\n width: '100%',\n minHeight: rem(theme, TOUCH_TARGET),\n px: 1.5,\n py: 1,\n mb: 1,\n textAlign: 'left',\n cursor: 'pointer',\n color: 'text.primary',\n background: 'transparent',\n border: `1px solid ${theme.palette.divider}`,\n borderRadius: 1.5,\n })}\n >\n <Box sx={{ minWidth: 0 }}>\n {title ? (\n <Typography variant=\"caption\" sx={{ display: 'block', color: 'text.secondary' }}>\n {title}\n </Typography>\n ) : null}\n <Typography variant=\"body2\" noWrap sx={{ fontWeight: 600 }}>\n {activeLabel ?? ''}\n </Typography>\n </Box>\n <ExpandMoreIcon\n fontSize=\"small\"\n sx={{\n flex: '0 0 auto',\n color: 'text.secondary',\n transition: 'transform 150ms ease',\n transform: open ? 'rotate(180deg)' : 'none',\n '@media (prefers-reduced-motion: reduce)': { transition: 'none' },\n }}\n />\n </Box>\n );\n}\n\n/** The empty-search state, with the way out of it rendered inside. */\nfunction SettingsSearchEmpty({\n label,\n action,\n onClear,\n testIdPrefix,\n}: {\n label: React.ReactNode;\n action?: SettingsEmptySearchAction;\n onClear: () => void;\n testIdPrefix: string;\n}): React.JSX.Element {\n return (\n <Box data-testid={`${testIdPrefix}-empty`} sx={{ px: 1, py: 2 }}>\n <Typography variant=\"body2\" color=\"text.secondary\">\n {label}\n </Typography>\n {action ? (\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => {\n onClear();\n action.onClear?.();\n }}\n data-testid={`${testIdPrefix}-empty-action`}\n sx={{ mt: 1.5, minHeight: sxRem(TOUCH_TARGET) }}\n >\n {action.label}\n </Button>\n ) : null}\n </Box>\n );\n}\n\nexport interface RailBodyProps extends RailShape {\n navOpen: boolean;\n query: string;\n onQueryChange: (value: string) => void;\n searchPlaceholder: string;\n emptySearchLabel: React.ReactNode;\n emptySearchAction?: SettingsEmptySearchAction;\n filteredGroups: SettingsNavGroup[];\n activeItemId?: string;\n linkComponent?: SettingsLayoutProps['linkComponent'];\n onSelectItem?: (id: string) => void;\n onNavigate?: () => void;\n testIdPrefix: string;\n}\n\n/** The searchable rail body (search + groups). */\nfunction SettingsRailBody({\n navOpen,\n query,\n onQueryChange,\n searchPlaceholder,\n emptySearchLabel,\n emptySearchAction,\n filteredGroups,\n activeItemId,\n linkComponent,\n onSelectItem,\n onNavigate,\n testIdPrefix,\n ...shape\n}: RailBodyProps): React.JSX.Element {\n // `drilldown` has no disclosure to be closed behind: below the breakpoint the\n // body is the page, above it the rail. Only `switcher` hides it.\n const hidden = navOpen ? 'block' : 'none';\n return (\n <Box\n data-testid={`${testIdPrefix}-rail-body`}\n sx={(theme) =>\n shape.variant === 'drilldown'\n ? { display: 'block' }\n : displayAcrossRail(theme, shape.breakpoint, hidden, 'block')\n }\n >\n <TextField\n value={query}\n onChange={(event) => onQueryChange(event.target.value)}\n placeholder={searchPlaceholder}\n size=\"small\"\n fullWidth\n aria-label={searchPlaceholder}\n data-testid={`${testIdPrefix}-search`}\n InputProps={{\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon fontSize=\"small\" sx={{ color: 'text.secondary' }} />\n </InputAdornment>\n ),\n }}\n sx={{ mb: 2 }}\n />\n {filteredGroups.length === 0 ? (\n <SettingsSearchEmpty\n label={emptySearchLabel}\n action={emptySearchAction}\n onClear={() => onQueryChange('')}\n testIdPrefix={testIdPrefix}\n />\n ) : (\n filteredGroups.map((group) => (\n <SettingsRailGroup\n key={group.id}\n group={group}\n activeItemId={activeItemId}\n linkComponent={linkComponent}\n onSelectItem={onSelectItem}\n onNavigate={onNavigate}\n testIdPrefix={testIdPrefix}\n {...shape}\n />\n ))\n )}\n </Box>\n );\n}\n\n/** Props for {@link SettingsRail}: the rail body's inputs plus the mobile chrome. */\nexport type SettingsRailProps = RailBodyProps & {\n title?: React.ReactNode;\n activeLabel?: string;\n onToggleNav: () => void;\n /** Scroll inside the rail rather than with the page. See `fillHeight`. */\n fillHeight?: boolean;\n};\n\n/** The navigation column: title, the `switcher`'s disclosure, and the body. */\nexport function SettingsRail({\n title,\n activeLabel,\n navOpen,\n onToggleNav,\n testIdPrefix,\n fillHeight = false,\n ...bodyProps\n}: SettingsRailProps): React.JSX.Element {\n const { variant, breakpoint, atIndex } = bodyProps;\n // In `drilldown` the rail is the index's list below the breakpoint and the\n // left column above it — so inside a section it steps aside for the chip\n // strip. It is `display: none`, never unmounted: the two navigation forms\n // both stay in the DOM at every width, which is what makes \"the narrow width\n // offers what the wide one offers\" true by construction instead of by review.\n const hiddenWhileInSection = variant === 'drilldown' && !atIndex;\n\n return (\n <Box\n component=\"nav\"\n aria-label={typeof title === 'string' ? title : 'Settings'}\n data-testid={`${testIdPrefix}-rail`}\n sx={(theme) => ({\n display: hiddenWhileInSection ? 'none' : 'block',\n flex: '0 0 auto',\n width: '100%',\n [atLeastRail(theme, breakpoint)]: {\n display: 'block',\n flex: `0 0 ${railWidth(theme)}`,\n width: railWidth(theme),\n borderRight: `1px solid ${theme.palette.divider}`,\n pr: 2,\n // Its own scrollbar, so a settings area with twenty categories does\n // not make the thing you NAVIGATE with scroll away while you read the\n // panel. `minHeight: 0` is the load-bearing half: without it a flex\n // child refuses to shrink below its content and `overflow` never\n // engages.\n ...(fillHeight\n ? { height: '100%', minHeight: 0, overflowY: 'auto' as const, overscrollBehavior: 'contain' as const }\n : {}),\n },\n })}\n >\n {title ? (\n <Typography\n variant=\"h6\"\n data-testid={`${testIdPrefix}-title`}\n sx={(theme) => ({\n ...(variant === 'drilldown'\n ? { display: 'block' }\n : displayAcrossRail(theme, breakpoint, 'none', 'block')),\n fontWeight: 700,\n mb: 1.5,\n })}\n >\n {title}\n </Typography>\n ) : null}\n {variant === 'switcher' ? (\n <SettingsRailToggle\n title={title}\n activeLabel={activeLabel}\n open={navOpen}\n onToggle={onToggleNav}\n breakpoint={breakpoint}\n testIdPrefix={testIdPrefix}\n />\n ) : null}\n <SettingsRailBody navOpen={navOpen} testIdPrefix={testIdPrefix} {...bodyProps} />\n </Box>\n );\n}\n"],"mappings":"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","names":[]}
|