@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.
Files changed (56) hide show
  1. package/dist/_internal/components/form/Textarea/Textarea.js +1 -1
  2. package/dist/_internal/components/form/index.js +1 -1
  3. package/dist/_internal/components/index.js +1 -1
  4. package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.items.js +3 -3
  5. package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.js +8 -8
  6. package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.rail.js +4 -4
  7. package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.styles.js +3 -1
  8. package/dist/_internal/components/layout/SettingsLayout/SettingsPanel.js +5 -5
  9. package/dist/_internal/components/layout/SettingsLayout/SettingsSectionChips.js +3 -3
  10. package/dist/_internal/components/layout/SettingsLayout/SettingsSectionHeader.js +2 -2
  11. package/dist/_internal/components/layout/SettingsLayout/SettingsStatusMarker.js +2 -2
  12. package/dist/{chunk-V5EWCJBT.js → chunk-4BLVVMY7.js} +3 -3
  13. package/dist/{chunk-OKYYHBGS.js → chunk-6KM3TL4Q.js} +11 -4
  14. package/dist/chunk-6KM3TL4Q.js.map +1 -0
  15. package/dist/{chunk-DBFRCTI5.js → chunk-7Y2VWMGS.js} +2 -2
  16. package/dist/{chunk-F3Q4CMRB.js → chunk-GBVNY2LG.js} +3 -3
  17. package/dist/{chunk-KKVM723A.js → chunk-LY5I3ZSV.js} +4 -4
  18. package/dist/{chunk-NYFNF7I5.js → chunk-NK4T624E.js} +3 -1
  19. package/dist/chunk-NK4T624E.js.map +1 -0
  20. package/dist/{chunk-X47MWURD.js → chunk-Q6MZHT2F.js} +10 -8
  21. package/dist/chunk-Q6MZHT2F.js.map +1 -0
  22. package/dist/{chunk-TNYKM4UU.js → chunk-SWQXAUUG.js} +55 -21
  23. package/dist/chunk-SWQXAUUG.js.map +1 -0
  24. package/dist/{chunk-6KEXHOIF.js → chunk-WOXNVM52.js} +2 -2
  25. package/dist/form/Textarea.js +1 -1
  26. package/dist/layout/SettingsLayout.js +8 -8
  27. package/dist/types/components/form/Textarea/Textarea.d.ts.map +1 -1
  28. package/dist/types/components/form/Textarea/Textarea.types.d.ts +4 -2
  29. package/dist/types/components/form/Textarea/Textarea.types.d.ts.map +1 -1
  30. package/dist/types/components/layout/SettingsLayout/SettingsLayout.d.ts.map +1 -1
  31. package/dist/types/components/layout/SettingsLayout/SettingsLayout.rail.d.ts +6 -2
  32. package/dist/types/components/layout/SettingsLayout/SettingsLayout.rail.d.ts.map +1 -1
  33. package/dist/types/components/layout/SettingsLayout/SettingsLayout.styles.d.ts +2 -0
  34. package/dist/types/components/layout/SettingsLayout/SettingsLayout.styles.d.ts.map +1 -1
  35. package/dist/types/components/layout/SettingsLayout/SettingsLayout.types.d.ts +19 -0
  36. package/dist/types/components/layout/SettingsLayout/SettingsLayout.types.d.ts.map +1 -1
  37. package/dist/types/components/layout/SettingsLayout/index.d.ts +1 -1
  38. package/dist/types/components/layout/SettingsLayout/index.d.ts.map +1 -1
  39. package/package.json +1 -1
  40. package/src/components/form/Textarea/Textarea.tsx +14 -7
  41. package/src/components/form/Textarea/Textarea.types.ts +4 -2
  42. package/src/components/layout/SettingsLayout/SettingsLayout.md +19 -0
  43. package/src/components/layout/SettingsLayout/SettingsLayout.rail.tsx +67 -23
  44. package/src/components/layout/SettingsLayout/SettingsLayout.styles.ts +3 -0
  45. package/src/components/layout/SettingsLayout/SettingsLayout.tsx +12 -0
  46. package/src/components/layout/SettingsLayout/SettingsLayout.types.ts +20 -0
  47. package/src/components/layout/SettingsLayout/index.ts +1 -0
  48. package/dist/chunk-NYFNF7I5.js.map +0 -1
  49. package/dist/chunk-OKYYHBGS.js.map +0 -1
  50. package/dist/chunk-TNYKM4UU.js.map +0 -1
  51. package/dist/chunk-X47MWURD.js.map +0 -1
  52. /package/dist/{chunk-V5EWCJBT.js.map → chunk-4BLVVMY7.js.map} +0 -0
  53. /package/dist/{chunk-DBFRCTI5.js.map → chunk-7Y2VWMGS.js.map} +0 -0
  54. /package/dist/{chunk-F3Q4CMRB.js.map → chunk-GBVNY2LG.js.map} +0 -0
  55. /package/dist/{chunk-KKVM723A.js.map → chunk-LY5I3ZSV.js.map} +0 -0
  56. /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-OKYYHBGS.js";
3
+ } from "../chunk-6KM3TL4Q.js";
4
4
  import "../chunk-BXC6GRLE.js";
5
- import "../chunk-KKVM723A.js";
5
+ import "../chunk-LY5I3ZSV.js";
6
6
  import {
7
7
  SettingsSectionChips
8
- } from "../chunk-F3Q4CMRB.js";
8
+ } from "../chunk-GBVNY2LG.js";
9
9
  import "../chunk-AJUSBPWG.js";
10
- import "../chunk-TNYKM4UU.js";
11
- import "../chunk-V5EWCJBT.js";
10
+ import "../chunk-SWQXAUUG.js";
11
+ import "../chunk-4BLVVMY7.js";
12
12
  import {
13
13
  SettingsStatusMarker
14
- } from "../chunk-DBFRCTI5.js";
15
- import "../chunk-6KEXHOIF.js";
16
- import "../chunk-NYFNF7I5.js";
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;AAoNtD,eAAO,MAAM,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,aAAa,CA0E5C,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
- * Minimum number of rows for autosize variant
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
- * Maximum number of rows for autosize variant
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;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB"}
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;AAyDlE;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA8ExD,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":"AASA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAG3E,OAAO,KAAK,EACV,yBAAyB,EACzB,mBAAmB,EACnB,gBAAgB,EAEjB,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;CACtB;AAwED,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;CACtB,CAAC;AAEF,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,WAAW,EACX,OAAO,EACP,WAAW,EACX,YAAY,EACZ,UAAkB,EAClB,GAAG,SAAS,EACb,EAAE,iBAAiB,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CA+DvC"}
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":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEpD;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,iBAAiB,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,0FAA0F;IAC1F,EAAE,EAAE,MAAM,CAAC;IACX,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,uEAAuE;IACvE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,uEAAuE;IACvE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;;;OAKG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,KAAK,EAAE,MAAM,CAAC;IACd,4DAA4D;IAC5D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC;AAExE;;;;;;;;;;GAUG;AACH,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,WAAW,CAAC;AAE1D;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,MAAM,CAAC;AAErD,kFAAkF;AAClF,MAAM,WAAW,yBAAyB;IACxC,6CAA6C;IAC7C,KAAK,EAAE,SAAS,CAAC;IACjB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC,kEAAkE;IAClE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,4CAA4C;IAC5C,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC3B,+DAA+D;IAC/D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,yEAAyE;IACzE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE,SAAS,CAAC;IAC7B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,yBAAyB,CAAC;IAC9C;;;;OAIG;IACH,aAAa,CAAC,EAAE,WAAW,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,EAAE,SAAS,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE;;;;;;;;;;;;;;;;OAgBG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB,cAAc,CAAC,EAAE,sBAAsB,CAAC;IACxC,+DAA+D;IAC/D,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;CAClC"}
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@12-apps/ui",
3
- "version": "6.75.0",
3
+ "version": "6.76.0",
4
4
  "license": "MIT",
5
5
  "packageManager": "pnpm@10.34.5",
6
6
  "type": "module",
@@ -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), minHeight: rem(theme, 60) },
70
- sm: { padding: rems(theme, 8, 10), fontSize: rem(theme, 14), minHeight: rem(theme, 80) },
71
- md: { padding: rems(theme, 10, 12), fontSize: rem(theme, 16), minHeight: rem(theme, 100) },
72
- lg: { padding: rems(theme, 12, 14), fontSize: rem(theme, 18), minHeight: rem(theme, 120) },
73
- xl: { padding: rems(theme, 14, 16), fontSize: rem(theme, 20), minHeight: rem(theme, 140) } };
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
- minRows: 3 } satisfies Partial<TextareaProps>;
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={variant === 'autosize' ? minRows : undefined}
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
- * Minimum number of rows for autosize variant
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
- * Maximum number of rows for autosize variant
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 searchable rail body (search + groups). */
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
- <TextField
173
- value={query}
174
- onChange={(event) => onQueryChange(event.target.value)}
175
- placeholder={searchPlaceholder}
176
- size="small"
177
- fullWidth
178
- aria-label={searchPlaceholder}
179
- data-testid={`${testIdPrefix}-search`}
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
- flex: `0 0 ${railWidth(theme)}`,
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
  *
@@ -10,5 +10,6 @@ export type {
10
10
  SettingsNavItem,
11
11
  SettingsNavStatus,
12
12
  SettingsNavVariant,
13
+ SettingsRailVariant,
13
14
  SettingsRailBreakpoint,
14
15
  } from './SettingsLayout.types';
@@ -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":[]}