@12-apps/ui 6.50.0 → 6.51.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 (222) hide show
  1. package/components-catalog.md +2 -2
  2. package/dist/_internal/components/data-display/Badge/Badge.js +4 -4
  3. package/dist/_internal/components/data-display/Badge/Badge.styles.js +4 -4
  4. package/dist/_internal/components/data-display/Badge/BadgeContent.js +4 -4
  5. package/dist/_internal/components/data-display/Carousel/Carousel.chrome.js +4 -4
  6. package/dist/_internal/components/data-display/Carousel/Carousel.js +4 -4
  7. package/dist/_internal/components/data-display/Carousel/Carousel.parts.js +4 -4
  8. package/dist/_internal/components/data-display/Carousel/Carousel.styles.js +4 -4
  9. package/dist/_internal/components/data-display/Chart/Chart.js +4 -4
  10. package/dist/_internal/components/data-display/Chart/SpecChart.js +4 -4
  11. package/dist/_internal/components/data-display/Chart/chart-context.js +4 -4
  12. package/dist/_internal/components/data-display/Chart/chart-internals.js +4 -4
  13. package/dist/_internal/components/data-display/Chart/chart-renderers.js +4 -4
  14. package/dist/_internal/components/data-display/DataGrid/DataGrid.js +6 -6
  15. package/dist/_internal/components/data-display/DataGrid/DataGrid.model.js +5 -5
  16. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +16 -16
  17. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +17 -17
  18. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +8 -8
  19. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +7 -7
  20. package/dist/_internal/components/data-display/DataViews/base-list-card.js +9 -9
  21. package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +7 -7
  22. package/dist/_internal/components/data-display/DataViews/data-views-display-tabs.js +6 -6
  23. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +9 -9
  24. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +15 -15
  25. package/dist/_internal/components/data-display/DataViews/data-views-layout-context.js +5 -5
  26. package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +6 -6
  27. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +9 -9
  28. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +8 -8
  29. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +6 -6
  30. package/dist/_internal/components/data-display/FleetMap/FleetMap.js +4 -4
  31. package/dist/_internal/components/data-display/Sheet/Sheet.body.js +4 -4
  32. package/dist/_internal/components/data-display/Sheet/Sheet.js +4 -4
  33. package/dist/_internal/components/data-display/Sheet/Sheet.styles.js +4 -4
  34. package/dist/_internal/components/data-display/Table/Table.js +5 -5
  35. package/dist/_internal/components/data-display/index.js +7 -7
  36. package/dist/_internal/components/form/Command/Command.js +4 -4
  37. package/dist/_internal/components/form/Command/Command.styles.js +4 -4
  38. package/dist/_internal/components/form/Label/Label.js +4 -4
  39. package/dist/_internal/components/form/Label/Label.styles.js +4 -4
  40. package/dist/_internal/components/form/Menubar/Menubar.item.js +4 -4
  41. package/dist/_internal/components/form/Menubar/Menubar.js +4 -4
  42. package/dist/_internal/components/form/Menubar/Menubar.styles.js +4 -4
  43. package/dist/_internal/components/form/Menubar/Menubar.toolbar.js +4 -4
  44. package/dist/_internal/components/form/index.js +4 -4
  45. package/dist/_internal/components/index.js +23 -23
  46. package/dist/_internal/components/layout/Box/Box.js +7 -7
  47. package/dist/_internal/components/layout/SettingCard/SettingCard.js +9 -9
  48. package/dist/_internal/components/layout/SettingCard/SettingCard.parts.js +8 -8
  49. package/dist/_internal/components/layout/SettingCard/SettingGrid.js +9 -9
  50. package/dist/_internal/components/layout/SettingCard/SettingGroup.js +10 -10
  51. package/dist/_internal/components/layout/SettingCard/SettingSwitch.js +9 -9
  52. package/dist/_internal/components/layout/SettingCard/SettingToggle.js +10 -10
  53. package/dist/_internal/components/layout/Stack/Stack.js +8 -8
  54. package/dist/_internal/components/layout/index.js +13 -13
  55. package/dist/_internal/components/navigation/AppHeader/AppHeader.details.js +4 -4
  56. package/dist/_internal/components/navigation/AppHeader/AppHeader.identity.js +4 -4
  57. package/dist/_internal/components/navigation/SectionNav/SectionNav.bar.js +9 -9
  58. package/dist/_internal/components/navigation/SectionNav/SectionNav.helpers.js +5 -1
  59. package/dist/_internal/components/navigation/SectionNav/SectionNav.js +11 -11
  60. package/dist/_internal/components/navigation/SectionNav/SectionNav.parts.js +12 -6
  61. package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js +7 -7
  62. package/dist/_internal/components/navigation/SectionNav/SectionNav.rail.js +7 -7
  63. package/dist/_internal/components/navigation/SectionNav/SectionNav.sheet.js +7 -7
  64. package/dist/_internal/components/navigation/SectionNav/__stories__/fixtures.js +16 -4
  65. package/dist/_internal/components/navigation/SectionNav/__stories__/fixtures.js.map +1 -1
  66. package/dist/_internal/components/navigation/index.js +11 -11
  67. package/dist/_internal/components/utility/WorkflowStep/WorkflowStep.helpers.js +4 -4
  68. package/dist/_internal/components/utility/WorkflowStep/WorkflowStep.js +4 -4
  69. package/dist/_internal/components/utility/WorkflowStep/WorkflowStep.parts.js +4 -4
  70. package/dist/_internal/components/utility/WorkflowStep/WorkflowStepRow.js +4 -4
  71. package/dist/_internal/components/utility/index.js +4 -4
  72. package/dist/_internal/icons/Icon.js +7 -7
  73. package/dist/_internal/provider/UiProvider.js +6 -6
  74. package/dist/_internal/provider/mui-bridge.js +5 -5
  75. package/dist/_internal/provider/use-ui-theme.js +6 -6
  76. package/dist/_internal/tokens/density-overrides.js +3 -3
  77. package/dist/_internal/tokens/density-overrides.navigation.js +1 -1
  78. package/dist/_internal/tokens/density-overrides.selection.js +1 -1
  79. package/dist/_internal/tokens/density.js +4 -4
  80. package/dist/charts.js +4 -4
  81. package/dist/{chunk-XK77FY42.js → chunk-25MSGLNU.js} +4 -3
  82. package/dist/chunk-25MSGLNU.js.map +1 -0
  83. package/dist/{chunk-7VC6YBD3.js → chunk-3U45DRNS.js} +2 -2
  84. package/dist/{chunk-ZQCZMSLO.js → chunk-4B5WSVS7.js} +2 -2
  85. package/dist/{chunk-F4FOBTLJ.js → chunk-4BI5PCOM.js} +2 -2
  86. package/dist/{chunk-HVZ4HF4M.js → chunk-5N2UJOCT.js} +2 -2
  87. package/dist/{chunk-DFCX3FNB.js → chunk-5ZBFADBL.js} +2 -2
  88. package/dist/{chunk-GLKQT2DS.js → chunk-A436VORP.js} +33 -4
  89. package/dist/chunk-A436VORP.js.map +1 -0
  90. package/dist/{chunk-LWBR5U6V.js → chunk-ABPTS3XK.js} +2 -2
  91. package/dist/{chunk-43EQITNF.js → chunk-BHPLHGZP.js} +4 -4
  92. package/dist/{chunk-YMW2VYGU.js → chunk-DLO5V4AV.js} +2 -2
  93. package/dist/{chunk-7FQF5BC2.js → chunk-ESW4Z5I7.js} +2 -2
  94. package/dist/{chunk-ZPD6MGAO.js → chunk-FDJLYYDA.js} +4 -4
  95. package/dist/{chunk-LZL6HDTZ.js → chunk-FM5RBGG7.js} +2 -2
  96. package/dist/{chunk-V2SAZOT2.js → chunk-FYTC4LOD.js} +2 -2
  97. package/dist/{chunk-4ELI2MM3.js → chunk-GAXHYRX6.js} +9 -6
  98. package/dist/chunk-GAXHYRX6.js.map +1 -0
  99. package/dist/{chunk-CT45KNCT.js → chunk-GPTICJVN.js} +3 -3
  100. package/dist/{chunk-URGH4673.js → chunk-H556NMKE.js} +4 -4
  101. package/dist/{chunk-VOF6QVCF.js → chunk-HF7V3RI5.js} +2 -2
  102. package/dist/{chunk-NKJMOWY3.js → chunk-HJUR6ZY6.js} +2 -2
  103. package/dist/{chunk-RX7J6VRI.js → chunk-HKEBTPKY.js} +119 -42
  104. package/dist/chunk-HKEBTPKY.js.map +1 -0
  105. package/dist/{chunk-ZC3NEUNQ.js → chunk-I2LF53MJ.js} +2 -2
  106. package/dist/{chunk-ZFQVT6HZ.js → chunk-II7Z5UB6.js} +2 -2
  107. package/dist/{chunk-K65NSHQI.js → chunk-L3CQTVFU.js} +4 -4
  108. package/dist/{chunk-EY4GPLMF.js → chunk-MT7XMJUJ.js} +5 -5
  109. package/dist/{chunk-TELVW2OI.js → chunk-MYCR7FMI.js} +2 -2
  110. package/dist/{chunk-56TGECKZ.js → chunk-NP6SHLQ3.js} +4 -3
  111. package/dist/chunk-NP6SHLQ3.js.map +1 -0
  112. package/dist/{chunk-WB6BTUXQ.js → chunk-OWILUXWM.js} +2 -2
  113. package/dist/{chunk-VHVI3D4R.js → chunk-P3GBXE73.js} +11 -2
  114. package/dist/chunk-P3GBXE73.js.map +1 -0
  115. package/dist/{chunk-WSBTMZJM.js → chunk-P7YUOH2E.js} +2 -2
  116. package/dist/{chunk-VOP2BXKL.js → chunk-QWTPK3FT.js} +2 -2
  117. package/dist/{chunk-XQ6Y5Z7R.js → chunk-RCJOTNIW.js} +2 -2
  118. package/dist/{chunk-32JMSHEA.js → chunk-S4ZUZ6DS.js} +10 -6
  119. package/dist/chunk-S4ZUZ6DS.js.map +1 -0
  120. package/dist/{chunk-SWDDXMV7.js → chunk-SJ4IAZ3V.js} +4 -4
  121. package/dist/{chunk-FHWBOOS3.js → chunk-TH7RBREI.js} +2 -2
  122. package/dist/{chunk-SA2ERYVV.js → chunk-VAO63IIP.js} +3 -3
  123. package/dist/{chunk-43Q6CVPB.js → chunk-VELGOFCL.js} +127 -78
  124. package/dist/chunk-VELGOFCL.js.map +1 -0
  125. package/dist/{chunk-RCJYLDXV.js → chunk-VJBTFWDK.js} +4 -4
  126. package/dist/chunk-WNKRFMSI.js +113 -0
  127. package/dist/chunk-WNKRFMSI.js.map +1 -0
  128. package/dist/{chunk-LM2YOONY.js → chunk-XYHNXO6Q.js} +2 -2
  129. package/dist/{chunk-FT7BNFGS.js → chunk-YK4ZG5Y4.js} +2 -2
  130. package/dist/data-display/Badge.js +4 -4
  131. package/dist/data-display/Carousel.js +4 -4
  132. package/dist/data-display/Chart.js +4 -4
  133. package/dist/data-display/DataGrid.js +6 -6
  134. package/dist/data-display/DataViews.js +20 -20
  135. package/dist/data-display/FleetMap.js +4 -4
  136. package/dist/data-display/Sheet.js +4 -4
  137. package/dist/data-display/Table.js +5 -5
  138. package/dist/form/Command.js +4 -4
  139. package/dist/form/Label.js +4 -4
  140. package/dist/form/Menubar.js +4 -4
  141. package/dist/icons.js +7 -7
  142. package/dist/layout/Box.js +7 -7
  143. package/dist/layout/SettingCard.js +13 -13
  144. package/dist/layout/Stack.js +8 -8
  145. package/dist/navigation/AppHeader.js +4 -4
  146. package/dist/navigation/SectionNav.js +11 -11
  147. package/dist/provider.js +7 -7
  148. package/dist/tokens.js +4 -4
  149. package/dist/types/components/navigation/SectionNav/SectionNav.bar.d.ts.map +1 -1
  150. package/dist/types/components/navigation/SectionNav/SectionNav.helpers.d.ts +12 -1
  151. package/dist/types/components/navigation/SectionNav/SectionNav.helpers.d.ts.map +1 -1
  152. package/dist/types/components/navigation/SectionNav/SectionNav.parts.d.ts +36 -2
  153. package/dist/types/components/navigation/SectionNav/SectionNav.parts.d.ts.map +1 -1
  154. package/dist/types/components/navigation/SectionNav/SectionNav.primary.d.ts +22 -4
  155. package/dist/types/components/navigation/SectionNav/SectionNav.primary.d.ts.map +1 -1
  156. package/dist/types/components/navigation/SectionNav/SectionNav.rail.d.ts.map +1 -1
  157. package/dist/types/components/navigation/SectionNav/SectionNav.sheet.d.ts.map +1 -1
  158. package/dist/types/components/navigation/SectionNav/SectionNav.types.d.ts +81 -5
  159. package/dist/types/components/navigation/SectionNav/SectionNav.types.d.ts.map +1 -1
  160. package/dist/types/components/navigation/SectionNav/__stories__/fixtures.d.ts +11 -1
  161. package/dist/types/components/navigation/SectionNav/__stories__/fixtures.d.ts.map +1 -1
  162. package/dist/types/components/navigation/SectionNav/index.d.ts +1 -1
  163. package/dist/types/components/navigation/SectionNav/index.d.ts.map +1 -1
  164. package/dist/types/tokens/density-overrides.d.ts.map +1 -1
  165. package/dist/types/tokens/density-overrides.navigation.d.ts.map +1 -1
  166. package/dist/types/tokens/density-overrides.selection.d.ts.map +1 -1
  167. package/dist/utility/WorkflowStep.js +4 -4
  168. package/package.json +1 -1
  169. package/src/components/navigation/SectionNav/SectionNav.bar.tsx +161 -88
  170. package/src/components/navigation/SectionNav/SectionNav.helpers.ts +16 -1
  171. package/src/components/navigation/SectionNav/SectionNav.md +40 -4
  172. package/src/components/navigation/SectionNav/SectionNav.parts.tsx +59 -1
  173. package/src/components/navigation/SectionNav/SectionNav.primary.tsx +107 -30
  174. package/src/components/navigation/SectionNav/SectionNav.rail.tsx +154 -41
  175. package/src/components/navigation/SectionNav/SectionNav.sheet.tsx +6 -2
  176. package/src/components/navigation/SectionNav/SectionNav.types.ts +82 -5
  177. package/src/components/navigation/SectionNav/__stories__/fixtures.tsx +21 -1
  178. package/src/components/navigation/SectionNav/index.ts +1 -0
  179. package/src/tokens/density-overrides.navigation.ts +15 -2
  180. package/src/tokens/density-overrides.selection.ts +31 -14
  181. package/src/tokens/density-overrides.ts +27 -11
  182. package/dist/chunk-32JMSHEA.js.map +0 -1
  183. package/dist/chunk-43Q6CVPB.js.map +0 -1
  184. package/dist/chunk-4ELI2MM3.js.map +0 -1
  185. package/dist/chunk-56TGECKZ.js.map +0 -1
  186. package/dist/chunk-GLKQT2DS.js.map +0 -1
  187. package/dist/chunk-RX7J6VRI.js.map +0 -1
  188. package/dist/chunk-RZ4SBSLP.js +0 -62
  189. package/dist/chunk-RZ4SBSLP.js.map +0 -1
  190. package/dist/chunk-VHVI3D4R.js.map +0 -1
  191. package/dist/chunk-XK77FY42.js.map +0 -1
  192. /package/dist/{chunk-7VC6YBD3.js.map → chunk-3U45DRNS.js.map} +0 -0
  193. /package/dist/{chunk-ZQCZMSLO.js.map → chunk-4B5WSVS7.js.map} +0 -0
  194. /package/dist/{chunk-F4FOBTLJ.js.map → chunk-4BI5PCOM.js.map} +0 -0
  195. /package/dist/{chunk-HVZ4HF4M.js.map → chunk-5N2UJOCT.js.map} +0 -0
  196. /package/dist/{chunk-DFCX3FNB.js.map → chunk-5ZBFADBL.js.map} +0 -0
  197. /package/dist/{chunk-LWBR5U6V.js.map → chunk-ABPTS3XK.js.map} +0 -0
  198. /package/dist/{chunk-43EQITNF.js.map → chunk-BHPLHGZP.js.map} +0 -0
  199. /package/dist/{chunk-YMW2VYGU.js.map → chunk-DLO5V4AV.js.map} +0 -0
  200. /package/dist/{chunk-7FQF5BC2.js.map → chunk-ESW4Z5I7.js.map} +0 -0
  201. /package/dist/{chunk-ZPD6MGAO.js.map → chunk-FDJLYYDA.js.map} +0 -0
  202. /package/dist/{chunk-LZL6HDTZ.js.map → chunk-FM5RBGG7.js.map} +0 -0
  203. /package/dist/{chunk-V2SAZOT2.js.map → chunk-FYTC4LOD.js.map} +0 -0
  204. /package/dist/{chunk-CT45KNCT.js.map → chunk-GPTICJVN.js.map} +0 -0
  205. /package/dist/{chunk-URGH4673.js.map → chunk-H556NMKE.js.map} +0 -0
  206. /package/dist/{chunk-VOF6QVCF.js.map → chunk-HF7V3RI5.js.map} +0 -0
  207. /package/dist/{chunk-NKJMOWY3.js.map → chunk-HJUR6ZY6.js.map} +0 -0
  208. /package/dist/{chunk-ZC3NEUNQ.js.map → chunk-I2LF53MJ.js.map} +0 -0
  209. /package/dist/{chunk-ZFQVT6HZ.js.map → chunk-II7Z5UB6.js.map} +0 -0
  210. /package/dist/{chunk-K65NSHQI.js.map → chunk-L3CQTVFU.js.map} +0 -0
  211. /package/dist/{chunk-EY4GPLMF.js.map → chunk-MT7XMJUJ.js.map} +0 -0
  212. /package/dist/{chunk-TELVW2OI.js.map → chunk-MYCR7FMI.js.map} +0 -0
  213. /package/dist/{chunk-WB6BTUXQ.js.map → chunk-OWILUXWM.js.map} +0 -0
  214. /package/dist/{chunk-WSBTMZJM.js.map → chunk-P7YUOH2E.js.map} +0 -0
  215. /package/dist/{chunk-VOP2BXKL.js.map → chunk-QWTPK3FT.js.map} +0 -0
  216. /package/dist/{chunk-XQ6Y5Z7R.js.map → chunk-RCJOTNIW.js.map} +0 -0
  217. /package/dist/{chunk-SWDDXMV7.js.map → chunk-SJ4IAZ3V.js.map} +0 -0
  218. /package/dist/{chunk-FHWBOOS3.js.map → chunk-TH7RBREI.js.map} +0 -0
  219. /package/dist/{chunk-SA2ERYVV.js.map → chunk-VAO63IIP.js.map} +0 -0
  220. /package/dist/{chunk-RCJYLDXV.js.map → chunk-VJBTFWDK.js.map} +0 -0
  221. /package/dist/{chunk-LM2YOONY.js.map → chunk-XYHNXO6Q.js.map} +0 -0
  222. /package/dist/{chunk-FT7BNFGS.js.map → chunk-YK4ZG5Y4.js.map} +0 -0
@@ -3,21 +3,61 @@ import type { ElementType, ReactNode } from 'react';
3
3
  import type { SectionNavCopy } from '../../../copy';
4
4
 
5
5
  /**
6
- * One place the section leads to — a bar slot on a phone, a row in the rail.
6
+ * One slot of the section — a bar slot on a phone, a row in the rail.
7
+ *
8
+ * A slot either LEADS somewhere (`href`, rendered through `linkComponent`) or
9
+ * DOES something (`onSelect`), the way a menu entry does. A bar of places is a
10
+ * section's navigation; a bar of verbs is a screen's actions pinned at its
11
+ * foot, and it is the same bar, so the two cannot be drawn two ways. Give a
12
+ * slot one or the other.
7
13
  */
8
14
  export interface SectionNavDestination {
9
15
  /** Stable key. Also the suffix of the slot's `data-testid`. */
10
16
  id: string;
11
17
  label: string;
12
18
  icon: ReactNode;
13
- href: string;
19
+ href?: string;
20
+ /**
21
+ * What the slot does, for an action slot. Ignored while `disabled` or
22
+ * `loading`; still called while `dimmed`.
23
+ */
24
+ onSelect?: () => void;
25
+ /**
26
+ * Drawn dimmed and not operable: the act exists here, and cannot be done
27
+ * now. A native `disabled` button — a tap does nothing, and `onSelect` is
28
+ * not called.
29
+ */
30
+ disabled?: boolean;
31
+ /**
32
+ * Drawn exactly like `disabled`, but still TAPPABLE: for an act the screen
33
+ * cannot do now and should EXPLAIN when tapped. It reports
34
+ * `aria-disabled="true"`, stays focusable, never lights up, and its
35
+ * `onSelect` still fires so the host can answer with a message (why not,
36
+ * and what would make it possible).
37
+ */
38
+ dimmed?: boolean;
39
+ /**
40
+ * A write this slot started is in flight — a spinner replaces the icon, the
41
+ * slot reports `aria-busy` and `aria-disabled`, and a tap is ignored. It
42
+ * stays focusable, so the keyboard does not lose its place mid-write.
43
+ */
44
+ loading?: boolean;
45
+ /**
46
+ * The control's own `data-testid`, in place of the one the nav derives. For
47
+ * a host whose suites already drive an id of their own shape.
48
+ */
49
+ dataTestId?: string;
14
50
  /**
15
51
  * How many things behind this destination wait on the viewer. `0` and
16
52
  * `undefined` render no badge — "nothing waiting" and "not known yet" are
17
53
  * different claims and neither is a number.
18
54
  */
19
55
  badge?: number;
20
- /** The destination the viewer is on. The host decides; the nav never reads the URL. */
56
+ /**
57
+ * For a link: the destination the viewer is on (`aria-current="page"`). For
58
+ * an action slot: a toggle that is ON (`aria-pressed`). The host decides;
59
+ * the nav never reads the URL.
60
+ */
21
61
  active?: boolean;
22
62
  }
23
63
 
@@ -37,6 +77,13 @@ export interface SectionNavEntry {
37
77
  onSelect?: () => void;
38
78
  badge?: number;
39
79
  active?: boolean;
80
+ /** Drawn dimmed and not operable — a print already on its way, an act this state refuses. */
81
+ disabled?: boolean;
82
+ /**
83
+ * The control's own `data-testid`, in place of the one the nav derives. For
84
+ * a host whose suites already drive an id of their own shape.
85
+ */
86
+ dataTestId?: string;
40
87
  }
41
88
 
42
89
  /** A titled run of entries inside a menu. */
@@ -67,6 +114,33 @@ export interface SectionNavMenu {
67
114
  /** The sheet's heading, and the rail section's. */
68
115
  title: string;
69
116
  groups: SectionNavGroup[];
117
+ /** The trigger is drawn dimmed and does not open; in the rail every row of it is inert. */
118
+ disabled?: boolean;
119
+ /**
120
+ * The control's own `data-testid`, in place of the one the nav derives. For
121
+ * a host whose suites already drive an id of their own shape.
122
+ */
123
+ dataTestId?: string;
124
+ }
125
+
126
+ /**
127
+ * The raised primary as a plain ACTION rather than a menu: one act, done on
128
+ * tap. Its label is drawn under the button, because a bar of verbs names the
129
+ * act it is for rather than leaving it to an icon.
130
+ */
131
+ export interface SectionNavAction {
132
+ label: string;
133
+ icon: ReactNode;
134
+ onSelect: () => void;
135
+ /** A native `disabled` button: a tap does nothing. */
136
+ disabled?: boolean;
137
+ /** In flight: a spinner, `aria-busy`, `aria-disabled`; focusable, and a tap is ignored. */
138
+ loading?: boolean;
139
+ /**
140
+ * The control's own `data-testid`, in place of the one the nav derives. For
141
+ * a host whose suites already drive an id of their own shape.
142
+ */
143
+ dataTestId?: string;
70
144
  }
71
145
 
72
146
  /** The way out of the section, drawn at the top of the rail. */
@@ -88,8 +162,11 @@ export interface SectionNavProps {
88
162
  /** The navigation landmark's accessible name. */
89
163
  label: string;
90
164
  destinations: SectionNavDestination[];
91
- /** The raised action in the middle of the bar. */
92
- primary?: SectionNavMenu;
165
+ /**
166
+ * The raised button in the middle of the bar: a menu it opens as a sheet,
167
+ * or an action it does on tap (drawn with its label under it).
168
+ */
169
+ primary?: SectionNavMenu | SectionNavAction;
93
170
  /** The last slot of the bar. Its badge is the sum of its entries' badges. */
94
171
  more?: SectionNavMenu;
95
172
  /** Rail only: the way back out of the section. */
@@ -16,7 +16,7 @@ import React from 'react';
16
16
 
17
17
  import { sxRem } from '../../../../tokens/scales';
18
18
 
19
- import type { SectionNavDestination, SectionNavMenu } from '../SectionNav.types';
19
+ import type { SectionNavAction, SectionNavDestination, SectionNavMenu } from '../SectionNav.types';
20
20
 
21
21
  /**
22
22
  * The stories' example section, shared by the showcase and the interaction
@@ -109,3 +109,23 @@ export function PhoneFrame({ children }: { children: React.ReactNode }): React.R
109
109
  export function RailFrame({ children }: { children: React.ReactNode }): React.ReactElement {
110
110
  return <Box sx={{ width: sxRem(240), height: sxRem(560), border: 1, borderColor: 'divider' }}>{children}</Box>;
111
111
  }
112
+
113
+ /**
114
+ * A screen's ACTIONS pinned at its foot — the same bar, drawn with verbs: a
115
+ * bill being settled, one person at a time.
116
+ *
117
+ * `split` is DIMMED — it cannot be done yet, and a tap still reaches the host
118
+ * so it can say why. `equal` is a TOGGLE that is on: `aria-pressed`, never
119
+ * `aria-current`, because an action is not a page.
120
+ */
121
+ export const ACTIONS: SectionNavDestination[] = [
122
+ { id: 'split', label: 'Split', icon: <ReceiptLongOutlinedIcon />, onSelect: () => undefined, dimmed: true },
123
+ { id: 'equal', label: 'Equally', icon: <GroupsOutlinedIcon />, onSelect: () => undefined, active: true },
124
+ { id: 'person', label: 'Person', icon: <AddIcon />, onSelect: () => undefined },
125
+ ];
126
+
127
+ export const PAY_ALL: SectionNavAction = {
128
+ label: 'Pay all',
129
+ icon: <StorefrontOutlinedIcon />,
130
+ onSelect: () => undefined,
131
+ };
@@ -3,6 +3,7 @@ export { sectionNavBarInset } from './SectionNav.bar';
3
3
  export { RaisedActionButton } from './SectionNav.primary';
4
4
  export type { RaisedActionButtonProps } from './SectionNav.primary';
5
5
  export type {
6
+ SectionNavAction,
6
7
  SectionNavBack,
7
8
  SectionNavDestination,
8
9
  SectionNavEntry,
@@ -1,4 +1,4 @@
1
- import { tableCellClasses } from '@mui/material/TableCell/index.js';
1
+ import generateUtilityClass from '@mui/material/generateUtilityClass/index.js';
2
2
  import type { Components, CSSObject, Theme } from '@mui/material/styles/index.js';
3
3
 
4
4
  import { fieldRadius } from './field-radius';
@@ -123,9 +123,22 @@ const isDefaultTableCellPadding = (padding: TableCellOwnerStateForOverrides['pad
123
123
  const tableCellRootPadding: TableCellStyleFn = ({ theme, ownerState }) =>
124
124
  isDefaultTableCellPadding(ownerState?.padding) ? { padding: rem(theme, 16) } : {};
125
125
 
126
+ /**
127
+ * Built with `generateUtilityClass`, not imported from
128
+ * `@mui/material/TableCell`'s own `tableCellClasses` — the same generated
129
+ * string (`TableCell.js` builds `tableCellClasses` from this exact helper),
130
+ * but without pulling `MuiTableCell` onto the critical path of every host
131
+ * that imports `densityThemeOptions`, the same reason `density-overrides.ts`'s
132
+ * `CHIP_LABEL` and `density-overrides.selection.ts`'s `SWITCH_*` constants
133
+ * are built this way instead of read off the component's own classes module
134
+ * (FUT-2993). It also honours a host's own `ClassNameGenerator.configure`,
135
+ * which a hand-typed `.MuiTableCell-paddingCheckbox` string would not.
136
+ */
137
+ const TABLE_CELL_PADDING_CHECKBOX = generateUtilityClass('MuiTableCell', 'paddingCheckbox');
138
+
126
139
  const tableCellSmallPadding: TableCellStyleFn = ({ theme, ownerState }) => {
127
140
  const style: CSSObject = {
128
- [`&.${tableCellClasses.paddingCheckbox}`]: { padding: rems(theme, 0, 12, 0, 16) },
141
+ [`&.${TABLE_CELL_PADDING_CHECKBOX}`]: { padding: rems(theme, 0, 12, 0, 16) },
129
142
  };
130
143
  if (isDefaultTableCellPadding(ownerState?.padding)) style.padding = rems(theme, 6, 16);
131
144
  return style;
@@ -1,4 +1,4 @@
1
- import { switchClasses } from '@mui/material/Switch/index.js';
1
+ import generateUtilityClass from '@mui/material/generateUtilityClass/index.js';
2
2
  import type { Components, CSSObject, Theme } from '@mui/material/styles/index.js';
3
3
 
4
4
  import { rem, rems } from './relative';
@@ -94,14 +94,17 @@ import { rem, rems } from './relative';
94
94
  * (one class) cannot out-specificity it, so at `size="small"` it would
95
95
  * silently keep rendering MUI's unthemed `4px`/`16×16` at every density,
96
96
  * the click target and thumb staying full-size while the track around them
97
- * shrank. Fixed the same way: `sizeSmall`'s OWN nested `& .${switchClasses
98
- * .switchBase}` / `& .${switchClasses.thumb}` rules, read through
99
- * `switchClasses` (not a hand-typed selector string) for the same
100
- * `ClassNameGenerator.configure` reason `chipClasses` is above, inserted
101
- * as part of the SAME `sizeSmall` override object so they land AFTER
102
- * `SwitchRoot`'s own baked-in small variant in the generated class's CSS
103
- * text (later wins at matching two-class specificity) rather than trying
104
- * to out-specificity it from a different slot.
97
+ * shrank. Fixed the same way: `sizeSmall`'s OWN nested `& .${SWITCH_SWITCH_
98
+ * BASE}` / `& .${SWITCH_THUMB}` rules, built with `generateUtilityClass`
99
+ * (not a hand-typed selector string) for the same `ClassNameGenerator
100
+ * .configure` reason `density-overrides.ts`'s `CHIP_LABEL` is — and, unlike
101
+ * reading `switchClasses` off `@mui/material/Switch` itself, without
102
+ * putting `MuiSwitch` on the critical path of every host that imports
103
+ * `densityThemeOptions` (FUT-2993) — inserted as part of the SAME
104
+ * `sizeSmall` override object so they land AFTER `SwitchRoot`'s own baked-in
105
+ * small variant in the generated class's CSS text (later wins at matching
106
+ * two-class specificity) rather than trying to out-specificity it from a
107
+ * different slot.
105
108
  *
106
109
  * **The checked thumb's own travel distance is a FOURTH literal, found only
107
110
  * on adversarial review of the PR this doc comment first shipped in.**
@@ -111,7 +114,7 @@ import { rem, rems } from './relative';
111
114
  * `density: 'compact'` the checked thumb kept travelling the FULL, unscaled
112
115
  * distance while the track around it shrank ×0.9 — a visible overshoot.
113
116
  * `switchSwitchBasePadding`/`switchSizeSmall` each now carry their own
114
- * `&.${switchClasses.checked}` rule (`translateX(rem(theme, 20))`/`rem(theme,
117
+ * `&.${SWITCH_CHECKED}` rule (`translateX(rem(theme, 20))`/`rem(theme,
115
118
  * 16)`), composed onto the SAME generated class, in the SAME position
116
119
  * `padding` already occupies — so it wins by the identical mechanism, not a
117
120
  * new one. Proven at the pixel level, both sizes/densities: `switch-md-
@@ -146,6 +149,20 @@ export function checkboxRadioDensityOverrides(): Components<Theme> {
146
149
  };
147
150
  }
148
151
 
152
+ /**
153
+ * Built with `generateUtilityClass`, not imported from `@mui/material/Switch`'s
154
+ * own `switchClasses` — the same generated strings (`Switch.js` builds
155
+ * `switchClasses` from this exact helper), but without pulling `MuiSwitch`
156
+ * onto the critical path of every host that imports `densityThemeOptions`
157
+ * (see the module doc comment, and FUT-2993). `SWITCH_CHECKED` is a GLOBAL
158
+ * state slot (`generateUtilityClass`'s `globalStateClasses` table), so it
159
+ * resolves to `Mui-checked`, not `MuiSwitch-checked` — the same string
160
+ * `switchClasses.checked` gives.
161
+ */
162
+ const SWITCH_SWITCH_BASE = generateUtilityClass('MuiSwitch', 'switchBase');
163
+ const SWITCH_THUMB = generateUtilityClass('MuiSwitch', 'thumb');
164
+ const SWITCH_CHECKED = generateUtilityClass('MuiSwitch', 'checked');
165
+
149
166
  const switchRootGeometry = ({ theme }: { theme: Theme }): CSSObject => ({
150
167
  width: rems(theme, 34 + 12 * 2),
151
168
  height: rems(theme, 14 + 12 * 2),
@@ -163,7 +180,7 @@ const switchSwitchBasePadding = ({ theme }: { theme: Theme }): CSSObject => ({
163
180
  // own base/variants — see the module doc comment), so this nested rule
164
181
  // wins at the SAME (two-class, `.<hash>.Mui-checked`) specificity, the same
165
182
  // mechanism this function's own `padding` line already relies on.
166
- [`&.${switchClasses.checked}`]: { transform: `translateX(${rem(theme, 20)})` },
183
+ [`&.${SWITCH_CHECKED}`]: { transform: `translateX(${rem(theme, 20)})` },
167
184
  });
168
185
  const switchThumbSize = ({ theme }: { theme: Theme }): CSSObject => ({
169
186
  width: rem(theme, 20),
@@ -177,7 +194,7 @@ const switchSizeSmall = ({ theme }: { theme: Theme }): CSSObject => ({
177
194
  // overrides above, inserted as part of THIS SAME generated class — see the
178
195
  // module doc comment for why a flat override cannot reach these at
179
196
  // `size="small"` on its own.
180
- [`& .${switchClasses.switchBase}`]: {
197
+ [`& .${SWITCH_SWITCH_BASE}`]: {
181
198
  padding: rem(theme, 4),
182
199
  // Same overshoot as medium's, at `size="small"`'s OWN literal
183
200
  // (`SwitchRoot`'s baked-in `size: 'small'` variant, `Switch.js`:
@@ -187,9 +204,9 @@ const switchSizeSmall = ({ theme }: { theme: Theme }): CSSObject => ({
187
204
  // this rule, composed after it in the same generated class, so it wins
188
205
  // at matching specificity the same way the sibling `padding: rem(theme,
189
206
  // 4)` line above already does.
190
- [`&.${switchClasses.checked}`]: { transform: `translateX(${rem(theme, 16)})` },
207
+ [`&.${SWITCH_CHECKED}`]: { transform: `translateX(${rem(theme, 16)})` },
191
208
  },
192
- [`& .${switchClasses.thumb}`]: { width: rem(theme, 16), height: rem(theme, 16) },
209
+ [`& .${SWITCH_THUMB}`]: { width: rem(theme, 16), height: rem(theme, 16) },
193
210
  });
194
211
 
195
212
  /**
@@ -1,4 +1,4 @@
1
- import { chipClasses } from '@mui/material/Chip/index.js';
1
+ import generateUtilityClass from '@mui/material/generateUtilityClass/index.js';
2
2
  import type { Components, CSSObject, Theme } from '@mui/material/styles/index.js';
3
3
 
4
4
  import { rem } from './relative';
@@ -81,8 +81,13 @@ interface ChipOwnerStateForOverrides {
81
81
  * own single-class rule (`0,1,0`), so it wins regardless of source order —
82
82
  * the same technique `ChipRoot`'s OWN style already uses for its avatar/
83
83
  * icon/delete-icon sub-parts (`& .${chipClasses.avatar}`, etc., in
84
- * `Chip.js`), and read through the SAME `chipClasses` MUI's own `Chip.js`
85
- * generates the real DOM class from, not a hand-typed copy of it.
84
+ * `Chip.js`), and built the same way `Chip.js` itself builds that class:
85
+ * `generateUtilityClass('MuiChip', 'label')`, MUI's own public helper
86
+ * (`@mui/material/generateUtilityClass`), not a hand-typed copy of it and not
87
+ * `chipClasses` — importing `chipClasses` pulls in `@mui/material/Chip`
88
+ * itself, which puts `MuiChip` on the critical path of every host that
89
+ * imports `densityThemeOptions`, including one that never renders a density
90
+ * at all (FUT-2993).
86
91
  *
87
92
  * **That same higher specificity also outranks a HOST's own theming.** A
88
93
  * host writing `theme.components.MuiChip.styleOverrides.label` for its own
@@ -121,6 +126,15 @@ interface ChipOwnerStateForOverrides {
121
126
  * make them differ on nothing but identity.
122
127
  */
123
128
 
129
+ /**
130
+ * Built with `generateUtilityClass`, not imported from `@mui/material/Chip`'s
131
+ * own `chipClasses` — the same generated string (`Chip.js` builds
132
+ * `chipClasses` from this exact helper), but without pulling `MuiChip` onto
133
+ * the critical path of every host that imports `densityThemeOptions` (see the
134
+ * module doc comment, and FUT-2993).
135
+ */
136
+ const CHIP_LABEL = generateUtilityClass('MuiChip', 'label');
137
+
124
138
  const iconButtonRootPadding = ({ theme }: { theme: Theme }): CSSObject => ({ padding: rem(theme, 8) });
125
139
  const iconButtonSmallPadding = ({ theme }: { theme: Theme }): CSSObject => ({ padding: rem(theme, 5) });
126
140
  const iconButtonLargePadding = ({ theme }: { theme: Theme }): CSSObject => ({ padding: rem(theme, 12) });
@@ -155,14 +169,16 @@ const chipRootHeight = ({
155
169
  // (two classes vs one) — wins over `chipLabelPadding`/`chipLabelSmallPadding`
156
170
  // below regardless of stylesheet insertion order. See the module doc
157
171
  // comment for why this must live here and not on the label slot itself.
158
- // `chipClasses.label`, not a hand-typed `.MuiChip-label` string — the same
159
- // module `Chip.js`'s own root style reads for its avatar/icon/delete-icon
160
- // selectors, so this tracks whatever `Chip.js` itself puts on the label
161
- // element rather than a separately-maintained copy of it. A host that
162
- // calls `ClassNameGenerator.configure` before any `MuiChip` module loads
163
- // renames the real class; a literal string would silently stop matching
164
- // it, `chipClasses.label` cannot.
165
- style[`& .${chipClasses.label}`] = { paddingLeft: rem(theme, px), paddingRight: rem(theme, px) };
172
+ // `CHIP_LABEL` (`generateUtilityClass('MuiChip', 'label')`), not a
173
+ // hand-typed `.MuiChip-label` string — the same helper `Chip.js`'s own
174
+ // root style reads for its avatar/icon/delete-icon selectors (via
175
+ // `chipClasses`), so this tracks whatever `Chip.js` itself puts on the
176
+ // label element rather than a separately-maintained copy of it. A host
177
+ // that calls `ClassNameGenerator.configure` before any `MuiChip` module
178
+ // loads renames the real class; a literal string would silently stop
179
+ // matching it, `generateUtilityClass` cannot — and unlike `chipClasses`,
180
+ // it does so without importing `@mui/material/Chip` at all (FUT-2993).
181
+ style[`& .${CHIP_LABEL}`] = { paddingLeft: rem(theme, px), paddingRight: rem(theme, px) };
166
182
  }
167
183
  return style;
168
184
  };
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.sheet.tsx"],"sourcesContent":["import Typography from '@mui/material/Typography/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport type { ElementType } from 'react';\n\nimport { rem } from '../../../tokens/scales';\nimport { Drawer, DrawerContent, DrawerHeader } from '../../layout/Drawer';\n\nimport { Box, CONTROL_RESET, CountedIcon, controlProps, focusRing } from './SectionNav.parts';\nimport type { SectionNavEntry, SectionNavGroup, SectionNavMenu } from './SectionNav.types';\nimport type { SectionNavCopy } from '../../../copy';\n\ninterface EntryProps {\n entry: SectionNavEntry;\n linkComponent: ElementType | undefined;\n copy: SectionNavCopy;\n testId: string;\n onDone: () => void;\n}\n\n/** A tile in a `grid` group: icon over a short label. */\nfunction GridEntry({ entry, linkComponent, copy, testId, onDone }: EntryProps): React.JSX.Element {\n const theme = useTheme();\n return (\n <Box\n {...controlProps({\n href: entry.href,\n linkComponent,\n onClick: () => {\n entry.onSelect?.();\n onDone();\n },\n })}\n aria-current={entry.active ? 'page' : undefined}\n data-testid={`${testId}-entry-${entry.id}`}\n sx={{\n ...CONTROL_RESET,\n ...focusRing(theme),\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 0.75,\n minHeight: rem(theme, 76),\n px: 0.5,\n py: 1,\n borderRadius: 1.5,\n textAlign: 'center',\n bgcolor: entry.active ? 'action.selected' : 'action.hover',\n color: entry.active ? 'primary.main' : 'text.primary',\n '& svg': { color: 'primary.main' },\n }}\n >\n <CountedIcon icon={entry.icon} count={entry.badge} label={copy.badge} testId={`${testId}-badge-${entry.id}`} />\n <Typography component=\"span\" variant=\"caption\" sx={{ lineHeight: 1.2, fontWeight: entry.active ? 700 : 500 }}>\n {entry.label}\n </Typography>\n </Box>\n );\n}\n\n/** A row in a `list` group: icon, label, and the description under it. */\nfunction ListEntry({ entry, linkComponent, copy, testId, onDone }: EntryProps): React.JSX.Element {\n const theme = useTheme();\n return (\n <Box\n {...controlProps({\n href: entry.href,\n linkComponent,\n onClick: () => {\n entry.onSelect?.();\n onDone();\n },\n })}\n aria-current={entry.active ? 'page' : undefined}\n data-testid={`${testId}-entry-${entry.id}`}\n sx={{\n ...CONTROL_RESET,\n ...focusRing(theme),\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n width: '100%',\n minHeight: rem(theme, 52),\n px: 1.5,\n py: 1,\n borderRadius: 1.5,\n textAlign: 'start',\n bgcolor: entry.active ? 'action.selected' : 'action.hover',\n '& svg': { color: 'primary.main' },\n }}\n >\n <CountedIcon icon={entry.icon} count={entry.badge} label={copy.badge} testId={`${testId}-badge-${entry.id}`} />\n <Box component=\"span\" sx={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>\n <Typography component=\"span\" variant=\"body2\" sx={{ fontWeight: 600 }}>\n {entry.label}\n </Typography>\n {entry.description ? (\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">\n {entry.description}\n </Typography>\n ) : null}\n </Box>\n </Box>\n );\n}\n\n/** One titled run of entries, as tiles or rows. */\nfunction SheetGroup({\n group,\n linkComponent,\n copy,\n testId,\n onDone,\n}: Omit<EntryProps, 'entry'> & { group: SectionNavGroup }): React.JSX.Element {\n const grid = group.layout === 'grid';\n const Entry = grid ? GridEntry : ListEntry;\n return (\n <Box component=\"section\" data-testid={`${testId}-group-${group.id}`} sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>\n {group.title ? (\n <Typography variant=\"overline\" color=\"text.secondary\" sx={{ lineHeight: 1.6 }}>\n {group.title}\n </Typography>\n ) : null}\n <Box\n sx={\n grid\n ? { display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 1 }\n : { display: 'flex', flexDirection: 'column', gap: 0.75 }\n }\n >\n {group.entries.map((entry) => (\n <Entry key={entry.id} entry={entry} linkComponent={linkComponent} copy={copy} testId={testId} onDone={onDone} />\n ))}\n </Box>\n </Box>\n );\n}\n\n/**\n * A menu opened from the bar: a bottom sheet over the page.\n *\n * Choosing an entry closes it — a link has somewhere to go and an action has\n * something to do, and neither wants the sheet still covering the screen.\n */\nexport function SectionNavSheet({\n menu,\n open,\n onClose,\n linkComponent,\n copy,\n testId,\n bottomOffset,\n}: {\n menu: SectionNavMenu;\n open: boolean;\n onClose: () => void;\n linkComponent: ElementType | undefined;\n copy: SectionNavCopy;\n testId: string;\n /** How far above the viewport's foot the sheet stops — the bar's own height, so the bar stays visible. */\n bottomOffset: string;\n}): React.JSX.Element {\n const theme = useTheme();\n return (\n <Drawer\n open={open}\n onClose={onClose}\n anchor=\"bottom\"\n height=\"auto\"\n dataTestId={testId}\n paperSx={{\n borderTopLeftRadius: rem(theme, Number(theme.shape.borderRadius) * 3),\n borderTopRightRadius: rem(theme, Number(theme.shape.borderRadius) * 3),\n maxHeight: `calc(85dvh - ${bottomOffset})`,\n bottom: bottomOffset,\n }}\n >\n {/* The library Drawer names nothing: the dialog role and its name live\n here, around everything the focus trap holds. */}\n <Box\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={menu.title}\n sx={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }}\n >\n <DrawerHeader onClose={onClose} closeLabel={copy.close} dataTestId={`${testId}-header`}>\n {menu.title}\n </DrawerHeader>\n <DrawerContent>\n <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>\n {menu.groups.map((group) => (\n <SheetGroup\n key={group.id}\n group={group}\n linkComponent={linkComponent}\n copy={copy}\n testId={testId}\n onDone={onClose}\n />\n ))}\n </Box>\n </DrawerContent>\n </Box>\n </Drawer>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.bar.tsx"],"sourcesContent":["import Typography from '@mui/material/Typography/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport { useState, type ElementType, type ReactNode } from 'react';\n\nimport type { SectionNavCopy } from '../../../copy';\nimport { rem } from '../../../tokens/scales';\n\nimport { barSlots, menuActive, menuCount, type BarSlot } from './SectionNav.helpers';\nimport { Box, CONTROL_RESET, CountedIcon, controlProps, focusRing } from './SectionNav.parts';\nimport { RaisedActionButton } from './SectionNav.primary';\nimport { SectionNavSheet } from './SectionNav.sheet';\nimport type { SectionNavMenu, SectionNavProps } from './SectionNav.types';\n\n/** Which of the bar's two menus is open, if any. */\ntype OpenMenu = 'primary' | 'more' | null;\n\n/** The bar's height above the safe area — tall enough for an icon over a label. */\nconst barHeight = (theme: Parameters<typeof rem>[0]): string => rem(theme, 60);\n\n/**\n * The bar's full height on screen, the safe area included — where its sheets\n * stop, and what a host reserves at the foot of its content so nothing it\n * floats (a toast, a receipt) lands under the bar.\n */\nexport function sectionNavBarInset(theme: Parameters<typeof rem>[0]): string {\n return `calc(${barHeight(theme)} + env(safe-area-inset-bottom))`;\n}\n\n/**\n * One slot: icon over label, a count on the icon.\n *\n * `current` is the page the viewer is on and is what `aria-current` reports;\n * `lit` is only how the slot looks, and goes out while a sheet is open so the\n * bar shows where the thumb is. Opening a sheet is `aria-expanded`'s to say.\n *\n * A destination is a link; the \"more\" slot is a button that opens its sheet.\n * Either way the whole slot is the target, so a thumb landing on the label\n * lands on the control.\n */\nfunction Slot({\n label,\n icon,\n count,\n current,\n lit,\n copy,\n testId,\n control,\n expanded,\n}: {\n label: string;\n icon: ReactNode;\n count: number | undefined;\n current: boolean;\n lit: boolean;\n copy: SectionNavCopy;\n testId: string;\n control: Record<string, unknown>;\n expanded?: boolean;\n}): React.JSX.Element {\n const theme = useTheme();\n return (\n <Box\n {...control}\n aria-current={current ? 'page' : undefined}\n aria-expanded={expanded}\n data-lit={lit ? 'true' : undefined}\n data-testid={testId}\n sx={{\n ...CONTROL_RESET,\n ...focusRing(theme),\n flex: 1,\n minWidth: 0,\n display: 'flex',\n flexDirection: 'column',\n alignItems: 'center',\n justifyContent: 'center',\n gap: 0.25,\n position: 'relative',\n color: lit ? 'primary.main' : 'text.secondary',\n // The current slot is marked by more than its colour: a short rule on\n // its top edge, so the state survives a colour-blind reading.\n '&[data-lit=\"true\"]::before': {\n content: '\"\"',\n position: 'absolute',\n top: 0,\n insetInline: '22%',\n height: rem(theme, 3),\n borderBottomLeftRadius: rem(theme, 3),\n borderBottomRightRadius: rem(theme, 3),\n bgcolor: 'primary.main',\n },\n '& svg': { fontSize: rem(theme, 22) },\n }}\n >\n <CountedIcon icon={icon} count={count} label={copy.badge} testId={`${testId}-badge`} />\n <Typography\n component=\"span\"\n variant=\"caption\"\n sx={{\n maxWidth: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n lineHeight: 1.3,\n fontWeight: lit ? 700 : 400,\n }}\n >\n {label}\n </Typography>\n </Box>\n );\n}\n\n/** One slot of the bar, whichever kind it is. */\nfunction BarSlotView({\n slot,\n primary,\n more,\n open,\n toggle,\n close,\n linkComponent,\n copy,\n dataTestId,\n}: {\n slot: BarSlot;\n primary: SectionNavMenu | undefined;\n more: SectionNavMenu | undefined;\n open: OpenMenu;\n toggle: (menu: Exclude<OpenMenu, null>) => void;\n close: () => void;\n linkComponent: ElementType | undefined;\n copy: SectionNavCopy;\n dataTestId: string;\n}): React.JSX.Element | null {\n if (slot.kind === 'primary' && primary) {\n return (\n <RaisedActionButton\n label={primary.label}\n icon={primary.icon}\n open={open === 'primary'}\n closeLabel={copy.close}\n dataTestId={`${dataTestId}-primary`}\n onClick={() => toggle('primary')}\n />\n );\n }\n if (slot.kind === 'more' && more) {\n return (\n <Slot\n label={more.label}\n icon={more.icon}\n count={menuCount(more)}\n current={false}\n lit={open === 'more' || (open === null && menuActive(more))}\n expanded={open === 'more'}\n copy={copy}\n testId={`${dataTestId}-more`}\n control={controlProps({ href: undefined, linkComponent, onClick: () => toggle('more') })}\n />\n );\n }\n if (slot.kind !== 'destination') return null;\n const { destination } = slot;\n return (\n <Slot\n label={destination.label}\n icon={destination.icon}\n count={destination.badge}\n current={destination.active === true}\n lit={open === null && destination.active === true}\n copy={copy}\n testId={`${dataTestId}-dest-${destination.id}`}\n control={controlProps({ href: destination.href, linkComponent, onClick: close })}\n />\n );\n}\n\n/** The phone layout: a bottom bar, with its menus as bottom sheets. */\nexport function SectionNavBar({\n label,\n destinations,\n primary,\n more,\n linkComponent,\n copy,\n dataTestId,\n}: Required<Pick<SectionNavProps, 'label' | 'destinations' | 'copy' | 'dataTestId'>> &\n Pick<SectionNavProps, 'primary' | 'more'> & { linkComponent: ElementType | undefined }): React.JSX.Element {\n const theme = useTheme();\n const [open, setOpen] = useState<OpenMenu>(null);\n const toggle = (menu: Exclude<OpenMenu, null>): void => setOpen((current) => (current === menu ? null : menu));\n const close = (): void => setOpen(null);\n\n return (\n <>\n <Box\n component=\"nav\"\n aria-label={label}\n data-testid={dataTestId}\n sx={{\n flex: 'none',\n display: 'flex',\n alignItems: 'stretch',\n boxSizing: 'border-box',\n height: sectionNavBarInset(theme),\n paddingBottom: 'env(safe-area-inset-bottom)',\n borderTop: `1px solid ${theme.palette.divider}`,\n bgcolor: 'background.paper',\n // Above the backdrop ONLY while one of its own sheets is open, so the\n // primary button can close what it opened. Raised all the time it\n // would sit over every dialog the page opens, and on a small phone a\n // dialog's own footer is exactly where the bar is.\n position: 'relative',\n zIndex: open === null ? 'auto' : theme.zIndex.modal + 1,\n }}\n >\n {barSlots(destinations, more !== undefined, primary !== undefined).map((slot) => (\n <BarSlotView\n key={slot.kind === 'destination' ? `dest-${slot.destination.id}` : `menu-${slot.kind}`}\n slot={slot}\n primary={primary}\n more={more}\n open={open}\n toggle={toggle}\n close={close}\n linkComponent={linkComponent}\n copy={copy}\n dataTestId={dataTestId}\n />\n ))}\n </Box>\n {primary ? (\n <SectionNavSheet\n menu={primary}\n open={open === 'primary'}\n onClose={close}\n linkComponent={linkComponent}\n copy={copy}\n testId={`${dataTestId}-primary-sheet`}\n bottomOffset={sectionNavBarInset(theme)}\n />\n ) : null}\n {more ? (\n <SectionNavSheet\n menu={more}\n open={open === 'more'}\n onClose={close}\n linkComponent={linkComponent}\n copy={copy}\n testId={`${dataTestId}-more-sheet`}\n bottomOffset={sectionNavBarInset(theme)}\n />\n ) : null}\n </>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tokens/density-overrides.selection.ts"],"sourcesContent":["import { switchClasses } from '@mui/material/Switch/index.js';\nimport type { Components, CSSObject, Theme } from '@mui/material/styles/index.js';\n\nimport { rem, rems } from './relative';\n\n/**\n * CHECKBOX / RADIO / SWITCH GEOMETRY, DENSITY-AWARE (FUT-2767).\n *\n * `Checkbox`/`Radio`/`Switch` are MUI's own components, unwrapped — but\n * **only two of the three `@12-apps/ui` wrappers actually forward their\n * geometry to MUI**, corrected here after an earlier revision of this doc\n * comment claimed all three did.\n *\n * - `Checkbox.tsx`'s `StyledCheckbox` and `RadioGroup.variants.tsx`'s\n * `DefaultRadios` (the ONLY variant rendering a raw `<Radio>` — `cards`/\n * `buttons`/`segments` draw custom controls, outside this ticket) set NO\n * `padding` of their own, so `checkboxRadioDensityOverrides()` reaches\n * both directly — confirmed by a real render, same computed padding as\n * raw `MuiCheckbox`/`MuiRadio` at both densities\n * (`density-overrides.test.stories.tsx`'s `ui-checkbox`/`ui-radio-group`).\n * - `Switch.styles.ts`'s `switchSx` is DIFFERENT: it draws root/switchBase/\n * thumb geometry itself, per instance, from its own `SWITCH_SIZES` table\n * (`Switch.metrics.ts`), every number already through `rem(theme, px)`.\n * `Switch.parts.tsx`'s `StyledSwitch = styled(MuiSwitch, {...})(...)`\n * composes these as an OUTER wrapper class whose nested `& .MuiSwitch-\n * switchBase`/`& .MuiSwitch-thumb` selectors are a TWO-class compound —\n * higher specificity than this file's `MuiSwitch.styleOverrides.\n * switchBase`/`thumb`, which compose onto a single-class generated class.\n * `switchDensityOverrides()` therefore has **NO effect on `@12-apps/ui`'s\n * own `<Switch>`** — it only reaches a raw `@mui/material/Switch` consumer\n * (a host's own `Table.tsx` density-toggle column, say). Not a gap:\n * `switchSx` already reacts to `theme.typography.fontSize` on its own —\n * including the CHECKED thumb's own travel distance, computed as\n * `rem(theme, width - thumbSize - padding * 2)` from the SAME per-instance\n * geometry, so it moves consistently with no help from this file.\n * Confirmed by measurement, both sizes, both states, both densities\n * (`ui-switch-*` cases); documented at `Switch.md`'s \"Density\" section.\n *\n * **The ticket's open question — does a `MuiSwitchBase` theme override reach\n * `Checkbox`/`Radio` at all? — is NO, verified two ways.** `Checkbox`/`Radio`\n * both render through `internal/SwitchBase.js`'s `SwitchBaseRoot`, which is\n * `styled(ButtonBase, { name: 'MuiSwitchBase' })({ padding: 9, ... })` — with\n * NO `slot` key. `@mui/system`'s `createStyled.js` computes\n * `overridesResolver = defaultOverridesResolver(lowercaseFirstLetter(slot))`,\n * and `defaultOverridesResolver` (`if (!slot) return null`) returns `null`\n * for an absent slot; the styled call itself then only pushes its\n * `styleThemeOverrides` expression `if (componentName && overridesResolver)`\n * — `null` is falsy, so for THIS styled call `theme.components.MuiSwitchBase\n * .styleOverrides` is never read at all. (`variants` is a SEPARATE check,\n * gated on `skipVariantsResolver` rather than `overridesResolver`, which is\n * why the ticket's own two-part specificity proof for Chip's label — probing\n * with `variants` — does not transfer here; `styleOverrides` is what dies.)\n * A render-level probe confirms it: a theme with `components.MuiSwitchBase\n * .styleOverrides.root = { padding: '999px' }`, rendering `<Switch />`,\n * `<Checkbox />` and `<Radio />` through it, leaves EVERY ONE of `.MuiSwitch-\n * switchBase`, `.MuiCheckbox-root` and `.MuiRadio-root` at their unthemed\n * padding (`9px`/`4px` — see below), never `999px`. The Decision's own\n * suggested `MuiSwitchBase` route is therefore the ticket's documented\n * fallback in disguise: this file skips straight to duplicating the override\n * under `MuiCheckbox` and `MuiRadio`, each independently confirmed LIVE by\n * the same probe (`components.MuiCheckbox.styleOverrides.root.padding` DOES\n * reach `.MuiCheckbox-root`, and the same for `MuiRadio`).\n *\n * - `Checkbox`/`Radio` (`internal/SwitchBase.js`, `Checkbox.js`, `Radio.js`):\n * `padding: 9` — constant across `size=\"small\"`/`\"medium\"` today (neither\n * `CheckboxRoot` nor `RadioRoot` carries a size-conditional padding rule),\n * so ONE `root` override, no `sizeSmall`/`sizeMedium` split, covers both\n * sizes without disturbing the glyph-driven size difference FUT-2585 left\n * alone.\n * - `Switch` (`Switch.js`): root (the track) `width: 34+12*2`, `height:\n * 14+12*2`, `padding: 12` (medium); `switchBase` (the thumb's absolutely-\n * positioned wrapper) — its OWN literal is NOT the `12` the ticket's\n * Decision sketch names (that `12` is `SwitchRoot`'s own padding, a\n * DIFFERENT slot); `switchBase` inherits `internal/SwitchBase.js`'s generic\n * `padding: 9` unmodified at medium (`SwitchSwitchBase`'s own styles never\n * set `padding`), confirmed by the same render probe with NO theme\n * override at all (`.MuiSwitch-switchBase` computed padding: `9px`). This\n * file overrides `MuiSwitch.styleOverrides.switchBase` (a LIVE key —\n * `SwitchSwitchBase = styled(SwitchBase, { name: 'MuiSwitch', slot:\n * 'SwitchBase', ... })` DOES pass a `slot`) with `rem(theme, 9)`, the\n * MEASURED default, not the ticket's `12` — using `12` here would move\n * today's real 9px to 12px at `density: 'normal'`, failing the Done-when's\n * own pixel-identical requirement, so the number is corrected against the\n * probe rather than the sketch. `thumb`: `20×20`, unconditional.\n * - `Switch` `size=\"small\"` (`:82-100`, a `variants` entry on `SwitchRoot`\n * itself): root `width: 40`, `height: 24`, `padding: 7`; a NESTED `&\n * .${switchClasses.switchBase}` selector sets `padding: 4` (not 9); a\n * NESTED `& .${switchClasses.thumb}` selector sets `20×20` down to\n * `16×16`. Both nested rules are baked into `SwitchRoot`'s OWN generated\n * class at TWO-class specificity (the size-small instance's unique class,\n * plus `.MuiSwitch-switchBase`/`.MuiSwitch-thumb`) — exactly the Chip\n * outlined-label shape this file already has above, and the SAME failure\n * mode Lesson 1 warns about: a FLAT `styleOverrides.switchBase`/`thumb`\n * (one class) cannot out-specificity it, so at `size=\"small\"` it would\n * silently keep rendering MUI's unthemed `4px`/`16×16` at every density,\n * the click target and thumb staying full-size while the track around them\n * shrank. Fixed the same way: `sizeSmall`'s OWN nested `& .${switchClasses\n * .switchBase}` / `& .${switchClasses.thumb}` rules, read through\n * `switchClasses` (not a hand-typed selector string) for the same\n * `ClassNameGenerator.configure` reason `chipClasses` is above, inserted\n * as part of the SAME `sizeSmall` override object so they land AFTER\n * `SwitchRoot`'s own baked-in small variant in the generated class's CSS\n * text (later wins at matching two-class specificity) rather than trying\n * to out-specificity it from a different slot.\n *\n * **The checked thumb's own travel distance is a FOURTH literal, found only\n * on adversarial review of the PR this doc comment first shipped in.**\n * `SwitchSwitchBase`'s base style bakes in `&.Mui-checked { transform:\n * translateX(20px) }` (medium), and `SwitchRoot`'s `size: 'small'` variant\n * nests the same at `16px` — both bare, never run through `pxToRem`, so at\n * `density: 'compact'` the checked thumb kept travelling the FULL, unscaled\n * distance while the track around it shrank ×0.9 — a visible overshoot.\n * `switchSwitchBasePadding`/`switchSizeSmall` each now carry their own\n * `&.${switchClasses.checked}` rule (`translateX(rem(theme, 20))`/`rem(theme,\n * 16)`), composed onto the SAME generated class, in the SAME position\n * `padding` already occupies — so it wins by the identical mechanism, not a\n * new one. Proven at the pixel level, both sizes/densities: `switch-md-\n * checked`/`switch-sm-checked` measure the thumb's final position against\n * the track's own edge, not just the transform string.\n *\n * At `density: 'normal'` every number above computes back to the literal it\n * replaces (`rem(theme, 9)` is `0.5625rem`, `9px` at the 16px root — no\n * visible change), the same geometry-neutral guarantee `iconButtonDensity\n * Overrides`/`chipDensityOverrides` give above. The same non-default-\n * `fontSize` caveat those two give applies here unchanged: `rem()` only ever\n * reads `theme.typography.fontSize`, so a host adopting\n * `checkboxRadioDensityOverrides`/`switchDensityOverrides` standalone moves\n * every number here by that one coefficient, same as everything else `rem()`\n * touches.\n */\n\nconst checkboxRadioRootPadding = ({ theme }: { theme: Theme }): CSSObject => ({ padding: rem(theme, 9) });\n\n/**\n * `MuiCheckbox`/`MuiRadio`'s own padding — duplicated under both component\n * keys, the ticket's own documented fallback, since `MuiSwitchBase` cannot\n * reach either (see the module doc comment above). One module-level function\n * shared by both keys, and by `checkboxRadioDensityOverrides()`'s own two\n * calls across the two theme-build paths, for the same identity reason the\n * rest of this file's slots are module-level.\n */\nexport function checkboxRadioDensityOverrides(): Components<Theme> {\n return {\n MuiCheckbox: { styleOverrides: { root: checkboxRadioRootPadding } },\n MuiRadio: { styleOverrides: { root: checkboxRadioRootPadding } },\n };\n}\n\nconst switchRootGeometry = ({ theme }: { theme: Theme }): CSSObject => ({\n width: rems(theme, 34 + 12 * 2),\n height: rems(theme, 14 + 12 * 2),\n padding: rem(theme, 12),\n});\nconst switchSwitchBasePadding = ({ theme }: { theme: Theme }): CSSObject => ({\n padding: rem(theme, 9),\n // FUT-2767 (adversarial-review fix) — `SwitchSwitchBase`'s OWN base style\n // (`Switch.js`, medium) bakes in `&.Mui-checked { transform:\n // translateX(20px) }`, a bare literal never run through `pxToRem` — at\n // `density: 'compact'` the track/padding/thumb above all shrink ×0.9 but\n // this offset stayed at a full 20px, so the checked thumb overshot the now-\n // smaller track. Composed onto the SAME generated class as that base style,\n // AFTER it (`createStyled` composes `styleThemeOverrides` after a slot's\n // own base/variants — see the module doc comment), so this nested rule\n // wins at the SAME (two-class, `.<hash>.Mui-checked`) specificity, the same\n // mechanism this function's own `padding` line already relies on.\n [`&.${switchClasses.checked}`]: { transform: `translateX(${rem(theme, 20)})` },\n});\nconst switchThumbSize = ({ theme }: { theme: Theme }): CSSObject => ({\n width: rem(theme, 20),\n height: rem(theme, 20),\n});\nconst switchSizeSmall = ({ theme }: { theme: Theme }): CSSObject => ({\n width: rem(theme, 40),\n height: rem(theme, 24),\n padding: rem(theme, 7),\n // Higher (two-class) specificity than the flat `switchBase`/`thumb`\n // overrides above, inserted as part of THIS SAME generated class — see the\n // module doc comment for why a flat override cannot reach these at\n // `size=\"small\"` on its own.\n [`& .${switchClasses.switchBase}`]: {\n padding: rem(theme, 4),\n // Same overshoot as medium's, at `size=\"small\"`'s OWN literal\n // (`SwitchRoot`'s baked-in `size: 'small'` variant, `Switch.js`:\n // `translateX(16px)`). Nested one level deeper so the compiled selector\n // is `.<root-hash> .MuiSwitch-switchBase.Mui-checked` — the same THREE-\n // class descendant compound MUI's own baked-in small variant uses for\n // this rule, composed after it in the same generated class, so it wins\n // at matching specificity the same way the sibling `padding: rem(theme,\n // 4)` line above already does.\n [`&.${switchClasses.checked}`]: { transform: `translateX(${rem(theme, 16)})` },\n },\n [`& .${switchClasses.thumb}`]: { width: rem(theme, 16), height: rem(theme, 16) },\n});\n\n/**\n * `MuiSwitch`'s own track (root), thumb wrapper (switchBase) and thumb\n * (thumb) geometry, at both sizes MUI has.\n */\nexport function switchDensityOverrides(): Components<Theme> {\n return {\n MuiSwitch: {\n styleOverrides: {\n root: switchRootGeometry,\n switchBase: switchSwitchBasePadding,\n thumb: switchThumbSize,\n sizeSmall: switchSizeSmall,\n },\n },\n };\n}\n"],"mappings":";;;;;;AAAA,SAAS,qBAAqB;AAmI9B,IAAM,2BAA2B,CAAC,EAAE,MAAM,OAAoC,EAAE,SAAS,IAAI,OAAO,CAAC,EAAE;AAUhG,SAAS,gCAAmD;AACjE,SAAO;AAAA,IACL,aAAa,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,EAAE;AAAA,IAClE,UAAU,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,EAAE;AAAA,EACjE;AACF;AAEA,IAAM,qBAAqB,CAAC,EAAE,MAAM,OAAoC;AAAA,EACtE,OAAO,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,EAC9B,QAAQ,KAAK,OAAO,KAAK,KAAK,CAAC;AAAA,EAC/B,SAAS,IAAI,OAAO,EAAE;AACxB;AACA,IAAM,0BAA0B,CAAC,EAAE,MAAM,OAAoC;AAAA,EAC3E,SAAS,IAAI,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWrB,CAAC,KAAK,cAAc,OAAO,EAAE,GAAG,EAAE,WAAW,cAAc,IAAI,OAAO,EAAE,CAAC,IAAI;AAC/E;AACA,IAAM,kBAAkB,CAAC,EAAE,MAAM,OAAoC;AAAA,EACnE,OAAO,IAAI,OAAO,EAAE;AAAA,EACpB,QAAQ,IAAI,OAAO,EAAE;AACvB;AACA,IAAM,kBAAkB,CAAC,EAAE,MAAM,OAAoC;AAAA,EACnE,OAAO,IAAI,OAAO,EAAE;AAAA,EACpB,QAAQ,IAAI,OAAO,EAAE;AAAA,EACrB,SAAS,IAAI,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrB,CAAC,MAAM,cAAc,UAAU,EAAE,GAAG;AAAA,IAClC,SAAS,IAAI,OAAO,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASrB,CAAC,KAAK,cAAc,OAAO,EAAE,GAAG,EAAE,WAAW,cAAc,IAAI,OAAO,EAAE,CAAC,IAAI;AAAA,EAC/E;AAAA,EACA,CAAC,MAAM,cAAc,KAAK,EAAE,GAAG,EAAE,OAAO,IAAI,OAAO,EAAE,GAAG,QAAQ,IAAI,OAAO,EAAE,EAAE;AACjF;AAMO,SAAS,yBAA4C;AAC1D,SAAO;AAAA,IACL,WAAW;AAAA,MACT,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,OAAO;AAAA,QACP,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tokens/density-overrides.navigation.ts"],"sourcesContent":["import { tableCellClasses } from '@mui/material/TableCell/index.js';\nimport type { Components, CSSObject, Theme } from '@mui/material/styles/index.js';\n\nimport { fieldRadius } from './field-radius';\nimport { rem, rems } from './relative';\n\n/**\n * TOGGLEBUTTON / TAB / TABLECELL / PAGINATIONITEM / SLIDER GEOMETRY,\n * DENSITY-AWARE (FUT-2768).\n *\n * The remainder of the fixed-px geometry the density audit catalogued, none\n * of it hard-coded in `@12-apps/ui`'s own source. Verified against the\n * installed `@mui/material@6.5.0` source; each goes through the SAME\n * per-size/per-slot `overridesResolver` key MUI itself resolves\n * (`iconButtonDensityOverrides`/`chipDensityOverrides`'s own mechanism), so a\n * theme value composes with MUI's baked-in `variants` instead of replacing\n * them outright:\n *\n * - `ToggleButton`: `padding: 11/7/15` at medium(root)/small/large — same\n * `root`/`sizeSmall`/`sizeLarge` shape as `iconButtonDensityOverrides`. The\n * `root` slot ALSO carries `theme.fieldRadius` (FUT-2967, `field-radius.ts`)\n * — see the note at the end of this docblock.\n * - `Tab`: `minHeight: 48`, `padding: '12px 16px'` on the root (via `rems()`).\n * The icon+label combo (`minHeight: 72`, `paddingTop`/`Bottom: 9`) is a\n * SEPARATE MUI variant, exposed as the `labelIcon` key.\n * - `TableCell`: `padding: 16` on the root, `'6px 16px'` at small, nested\n * inside it `'0 12px 0 16px'` on the small+checkbox combo — all gated on\n * `ownerState.padding === 'normal'` (MUI's default): `checkbox`/`none` are\n * separate variants with their OWN unscaled padding (`'0 0 0 4px'`/`0`) an\n * unconditional rule clobbered at every size but small (FUT-2861 review —\n * the SAME Lesson-1 clobber the ellipsis fix above avoids, missed here).\n * `@12-apps/ui`'s own `Table` (FUT-2769) wins regardless (two classes deep\n * under its styled root); this reaches a BARE `<TableCell>`.\n * - `PaginationItem`: `minWidth/height: 32/26/40` at medium(root)/small/large.\n * The ellipsis shares the SAME slot and `minWidth` but has NO `height` of\n * its own (`'auto'`), gated on `ownerState.type` being neither\n * `'start-ellipsis'` nor `'end-ellipsis'` — skipping it would force a\n * height onto the ellipsis (Lesson 1).\n * - `Slider`: rail `height: 4/2` at `orientation=\"horizontal\"`/`size=\"small\"`\n * — gated on `ownerState.orientation` since the SAME key answers for either\n * axis (MUI sets `height` horizontal / `width` vertical, leaving the other\n * `'100%'`). Thumb `20×20`/`12×12` needs no gate. `@12-apps/ui`'s own\n * `Slider` already sets rail/thumb size through `rem()` and never forwards\n * `size` — a no-op THERE, reaches a BARE `<Slider>`. The thumb's ring and\n * the value-label offset were checked and left OUT — that story's own doc.\n *\n * `Avatar` is NOT in this file: `@12-apps/ui`'s own `Avatar` wraps `MuiAvatar`\n * in a `StyledAvatar` that ALREADY sets `width`/`height` through\n * `rem(theme, boxPx(size))` (`40` at `md`) — higher specificity than any\n * `MuiAvatar.styleOverrides.root`, dead code here, so it ships none.\n *\n * PADDING is geometry-neutral at `normal` — the same 11/7/15 literals\n * `ToggleButton.js` hard-codes; each slot a MODULE-LEVEL function, as above.\n *\n * `MuiToggleButton.root` is the one exception, and it is NOT neutral even at\n * `normal` (FUT-2967): `fieldRadiusOverrides` (`field-radius.ts`) and this\n * callback both style `MuiToggleButton.root` — the radius override's own\n * `{ borderRadius }` and this one's `{ padding }` — and a `styleOverrides`\n * slot two sources touch is replaced WHOLESALE by whichever is spread last\n * (`mergeMuiComponents`), so a theme built with density silently dropped the\n * field radius off a bare `<ToggleButton>` the moment density's `root`\n * callback (this one) was the later source. Fixed AT THE SOURCE rather than\n * in the merge: this MODULE-LEVEL callback (still a single, stable reference,\n * so two builds still compare equal) reads `theme.fieldRadius` itself and\n * returns the corner alongside the padding, so there is no second `root`\n * value for a later merge to lose. The consequence is deliberate and worth\n * naming: a host that applies ONLY `toggleButtonDensityOverrides()` to a\n * plain MUI theme now gets the FIELD radius (8px, `DEFAULT_FIELD_RADIUS`) on\n * `<ToggleButton>`, not MUI's own `shape.borderRadius` (4px) — matching the\n * fields beside it, not a MUI default nothing else in this package still\n * draws with.\n */\n\nconst toggleButtonRootPadding = ({ theme }: { theme: Theme }): CSSObject => ({\n padding: rem(theme, 11),\n borderRadius: fieldRadius(theme),\n});\nconst toggleButtonSmallPadding = ({ theme }: { theme: Theme }): CSSObject => ({ padding: rem(theme, 7) });\nconst toggleButtonLargePadding = ({ theme }: { theme: Theme }): CSSObject => ({ padding: rem(theme, 15) });\n\n/** `MuiToggleButton`'s own padding, at every size MUI has. */\nexport function toggleButtonDensityOverrides(): Components<Theme> {\n return {\n MuiToggleButton: {\n styleOverrides: {\n root: toggleButtonRootPadding,\n sizeSmall: toggleButtonSmallPadding,\n sizeLarge: toggleButtonLargePadding,\n },\n },\n };\n}\n\nconst tabRootGeometry = ({ theme }: { theme: Theme }): CSSObject => ({\n minHeight: rem(theme, 48),\n padding: rems(theme, 12, 16),\n});\nconst tabLabelIconGeometry = ({ theme }: { theme: Theme }): CSSObject => ({\n minHeight: rem(theme, 72),\n paddingTop: rem(theme, 9),\n paddingBottom: rem(theme, 9),\n});\n\n/** `MuiTab`'s own root height/padding, and the icon+label combo's taller box. */\nexport function tabDensityOverrides(): Components<Theme> {\n return {\n MuiTab: {\n styleOverrides: {\n root: tabRootGeometry,\n labelIcon: tabLabelIconGeometry,\n },\n },\n };\n}\n\ninterface TableCellOwnerStateForOverrides {\n padding?: 'normal' | 'checkbox' | 'none';\n}\ntype TableCellStyleFn = (props: { theme: Theme; ownerState?: TableCellOwnerStateForOverrides }) => CSSObject;\nconst isDefaultTableCellPadding = (padding: TableCellOwnerStateForOverrides['padding']): boolean =>\n padding === undefined || padding === 'normal';\n\nconst tableCellRootPadding: TableCellStyleFn = ({ theme, ownerState }) =>\n isDefaultTableCellPadding(ownerState?.padding) ? { padding: rem(theme, 16) } : {};\n\nconst tableCellSmallPadding: TableCellStyleFn = ({ theme, ownerState }) => {\n const style: CSSObject = {\n [`&.${tableCellClasses.paddingCheckbox}`]: { padding: rems(theme, 0, 12, 0, 16) },\n };\n if (isDefaultTableCellPadding(ownerState?.padding)) style.padding = rems(theme, 6, 16);\n return style;\n};\n\n/** Reaches a BARE `<TableCell>` only — module doc comment above. */\nexport function tableCellDensityOverrides(): Components<Theme> {\n return {\n MuiTableCell: {\n styleOverrides: {\n root: tableCellRootPadding,\n sizeSmall: tableCellSmallPadding,\n },\n },\n };\n}\n\n/** The `ownerState` field that tells the ellipsis item apart from a real button. */\ninterface PaginationItemOwnerStateForOverrides {\n type?: 'page' | 'first' | 'last' | 'start-ellipsis' | 'end-ellipsis' | 'previous' | 'next';\n}\ntype PaginationItemStyleFn = (props: {\n theme: Theme;\n ownerState?: PaginationItemOwnerStateForOverrides;\n}) => CSSObject;\n\nconst isPaginationEllipsis = (type: PaginationItemOwnerStateForOverrides['type']): boolean =>\n type === 'start-ellipsis' || type === 'end-ellipsis';\n\n/** `minWidth` always; `height` only off the ellipsis, which has none of its own. */\nfunction paginationItemGeometryAt(px: number): PaginationItemStyleFn {\n return ({ theme, ownerState }) => {\n const style: CSSObject = { minWidth: rem(theme, px) };\n if (!isPaginationEllipsis(ownerState?.type)) style.height = rem(theme, px);\n return style;\n };\n}\nconst paginationItemRootGeometry = paginationItemGeometryAt(32);\nconst paginationItemSmallGeometry = paginationItemGeometryAt(26);\nconst paginationItemLargeGeometry = paginationItemGeometryAt(40);\n\n/**\n * `MuiPaginationItem`'s own `minWidth`/`height`, at every size MUI has —\n * `height` skipped on the ellipsis item, which has none of its own (`auto`).\n */\nexport function paginationItemDensityOverrides(): Components<Theme> {\n return {\n MuiPaginationItem: {\n styleOverrides: {\n root: paginationItemRootGeometry,\n sizeSmall: paginationItemSmallGeometry,\n sizeLarge: paginationItemLargeGeometry,\n },\n },\n };\n}\n\n/** The `ownerState` field that tells which axis the rail's `height`/`4` reads as. */\ninterface SliderOwnerStateForOverrides {\n orientation?: 'horizontal' | 'vertical';\n}\ntype SliderStyleFn = (props: { theme: Theme; ownerState?: SliderOwnerStateForOverrides }) => CSSObject;\n\n/** The rail's `4`/`2` reads as `height` for a horizontal slider, `width` for a vertical one. */\nfunction sliderRailAxisAt(px: number): SliderStyleFn {\n return ({ theme, ownerState }) =>\n ownerState?.orientation === 'vertical' ? { width: rem(theme, px) } : { height: rem(theme, px) };\n}\nconst sliderRootGeometry = sliderRailAxisAt(4);\nconst sliderSmallGeometry = sliderRailAxisAt(2);\nconst sliderThumbGeometry = ({ theme }: { theme: Theme }): CSSObject => ({\n width: rem(theme, 20),\n height: rem(theme, 20),\n});\nconst sliderThumbSmallGeometry = ({ theme }: { theme: Theme }): CSSObject => ({\n width: rem(theme, 12),\n height: rem(theme, 12),\n});\n\n/** `MuiSlider`'s own rail thickness (root/sizeSmall) and thumb box (thumb/thumbSizeSmall). */\nexport function sliderDensityOverrides(): Components<Theme> {\n return {\n MuiSlider: {\n styleOverrides: {\n root: sliderRootGeometry,\n sizeSmall: sliderSmallGeometry,\n thumb: sliderThumbGeometry,\n thumbSizeSmall: sliderThumbSmallGeometry,\n },\n },\n };\n}\n\n/**\n * `MuiTabs`' own indicator thickness (`height: 2` horizontal, `width: 2`\n * vertical) — one short of `Tab` in the ticket's own literal list, added\n * after a FUT-2767-review pass over state/orientation-gated literals; same\n * orientation gate as the Slider rail. `@12-apps/ui`'s own `Tabs` draws its\n * OWN 3px indicator through `rem()` already, blocking THIS override there —\n * `tabDensityOverrides` reaches `Tab.root`'s `minHeight` instead (both\n * measured in `density-wrapper-reach.test.stories.tsx`).\n */\ninterface TabsIndicatorOwnerStateForOverrides {\n orientation?: 'horizontal' | 'vertical';\n}\ntype TabsIndicatorStyleFn = (props: {\n theme: Theme;\n ownerState?: TabsIndicatorOwnerStateForOverrides;\n}) => CSSObject;\n\nconst tabsIndicatorAxisAt: TabsIndicatorStyleFn = ({ theme, ownerState }) =>\n ownerState?.orientation === 'vertical' ? { width: rem(theme, 2) } : { height: rem(theme, 2) };\n\n/** `MuiTabs`' own indicator thickness, by orientation. */\nexport function tabsIndicatorDensityOverrides(): Components<Theme> {\n return {\n MuiTabs: {\n styleOverrides: {\n indicator: tabsIndicatorAxisAt,\n },\n },\n };\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.parts.tsx"],"sourcesContent":["import Box from '@mui/material/Box/index.js';\nimport type { SxProps, Theme } from '@mui/material/styles/index.js';\nimport type { ElementType, ReactNode } from 'react';\n\nimport { rem } from '../../../tokens/scales';\nimport { Badge } from '../../data-display/Badge';\n\nimport { shownCount } from './SectionNav.helpers';\n\n/**\n * An icon with its count on the shoulder.\n *\n * Quiet to assistive tech on change: the count moves on a poll, and a control\n * that announces itself every minute is noise. Its NAME carries the number,\n * so it is read when the control is.\n */\nexport function CountedIcon({\n icon,\n count,\n label,\n testId,\n}: {\n icon: ReactNode;\n count: number | undefined;\n label: (count: number) => string;\n testId: string;\n}): React.JSX.Element {\n const shown = shownCount(count);\n if (shown === undefined) return <>{icon}</>;\n return (\n // The library's corner count, in the warning role the sidebar's pill is\n // drawn from.\n <Badge\n content={shown}\n variant=\"count\"\n color=\"warning\"\n max={99}\n aria-label={label(shown)}\n aria-live=\"off\"\n data-testid={testId}\n >\n {icon}\n </Badge>\n );\n}\n\n/** The keyboard ring every control in the nav draws, in the theme's own colour. */\nexport function focusRing(theme: Theme): SxProps<Theme> {\n return {\n '&:focus-visible': {\n outline: `${rem(theme, 2)} solid ${theme.palette.primary.main}`,\n outlineOffset: rem(theme, -2),\n },\n };\n}\n\n/**\n * The element an entry or destination renders as: the host's link for an\n * `href`, a button for an `onSelect`.\n *\n * Returned as props for a `Box`, so the control stays ONE interactive\n * element — never a button wrapped around a link.\n */\nexport function controlProps({\n href,\n onClick,\n linkComponent,\n}: {\n href: string | undefined;\n onClick?: () => void;\n linkComponent: ElementType | undefined;\n}): Record<string, unknown> {\n if (href !== undefined) return { component: linkComponent ?? 'a', href, onClick };\n return { component: 'button', type: 'button', onClick };\n}\n\n/** The base reset every clickable in the nav shares: no underline, no button chrome. */\nexport const CONTROL_RESET = {\n border: 0,\n background: 'none',\n font: 'inherit',\n color: 'inherit',\n textDecoration: 'none',\n cursor: 'pointer',\n margin: 0,\n} as const;\n\nexport { Box };\n"],"mappings":";;;;;;;;;;;AAAA,OAAO,SAAS;AA4BkB;AAZ3B,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKsB;AACpB,QAAM,QAAQ,WAAW,KAAK;AAC9B,MAAI,UAAU,OAAW,QAAO,gCAAG,gBAAK;AACxC;AAAA;AAAA;AAAA,IAGE;AAAA,MAAC;AAAA;AAAA,QACC,SAAS;AAAA,QACT,SAAQ;AAAA,QACR,OAAM;AAAA,QACN,KAAK;AAAA,QACL,cAAY,MAAM,KAAK;AAAA,QACvB,aAAU;AAAA,QACV,eAAa;AAAA,QAEZ;AAAA;AAAA,IACH;AAAA;AAEJ;AAGO,SAAS,UAAU,OAA8B;AACtD,SAAO;AAAA,IACL,mBAAmB;AAAA,MACjB,SAAS,GAAG,IAAI,OAAO,CAAC,CAAC,UAAU,MAAM,QAAQ,QAAQ,IAAI;AAAA,MAC7D,eAAe,IAAI,OAAO,EAAE;AAAA,IAC9B;AAAA,EACF;AACF;AASO,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AACF,GAI4B;AAC1B,MAAI,SAAS,OAAW,QAAO,EAAE,WAAW,iBAAiB,KAAK,MAAM,QAAQ;AAChF,SAAO,EAAE,WAAW,UAAU,MAAM,UAAU,QAAQ;AACxD;AAGO,IAAM,gBAAgB;AAAA,EAC3B,QAAQ;AAAA,EACR,YAAY;AAAA,EACZ,MAAM;AAAA,EACN,OAAO;AAAA,EACP,gBAAgB;AAAA,EAChB,QAAQ;AAAA,EACR,QAAQ;AACV;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.rail.tsx"],"sourcesContent":["import Typography from '@mui/material/Typography/index.js';\nimport { useTheme } from '@mui/material/styles/index.js';\nimport type { ElementType, ReactNode } from 'react';\n\nimport type { SectionNavCopy } from '../../../copy';\nimport { rem } from '../../../tokens/scales';\n\nimport { Box, CONTROL_RESET, CountedIcon, controlProps, focusRing } from './SectionNav.parts';\nimport type { SectionNavMenu, SectionNavProps } from './SectionNav.types';\n\n/**\n * One rail row: icon, label, and the count at the far end.\n *\n * Destinations and menu entries draw the same row — in the rail there is room\n * for everything, so the difference between \"a place\" and \"an action\" is the\n * section it sits in, not its shape.\n */\nfunction RailRow({\n label,\n description,\n icon,\n count,\n active,\n copy,\n testId,\n control,\n}: {\n label: string;\n description?: string;\n icon: ReactNode;\n count: number | undefined;\n active: boolean;\n copy: SectionNavCopy;\n testId: string;\n control: Record<string, unknown>;\n}): React.JSX.Element {\n const theme = useTheme();\n return (\n <Box\n {...control}\n aria-current={active ? 'page' : undefined}\n data-testid={testId}\n sx={{\n ...CONTROL_RESET,\n ...focusRing(theme),\n display: 'flex',\n alignItems: 'center',\n gap: 1.5,\n width: '100%',\n minHeight: rem(theme, 40),\n px: 1.25,\n py: 0.75,\n borderRadius: 1,\n textAlign: 'start',\n color: active ? 'primary.main' : 'text.primary',\n bgcolor: active ? 'action.selected' : 'transparent',\n '&:hover': { bgcolor: active ? 'action.selected' : 'action.hover' },\n '& svg': { color: 'primary.main', fontSize: rem(theme, 20) },\n }}\n >\n <CountedIcon icon={icon} count={count} label={copy.badge} testId={`${testId}-badge`} />\n <Box component=\"span\" sx={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>\n <Typography component=\"span\" variant=\"body2\" sx={{ fontWeight: active ? 700 : 500 }}>\n {label}\n </Typography>\n {description ? (\n <Typography component=\"span\" variant=\"caption\" color=\"text.secondary\">\n {description}\n </Typography>\n ) : null}\n </Box>\n </Box>\n );\n}\n\n/** A heading between the rail's sections, in the sidebar's small-caps voice. */\nfunction RailHeading({ children }: { children: ReactNode }): React.JSX.Element {\n return (\n <Typography variant=\"overline\" color=\"text.secondary\" sx={{ px: 1.25, pt: 1.5, lineHeight: 1.6 }}>\n {children}\n </Typography>\n );\n}\n\n/** A menu's groups, listed under its title — nothing folded away on a wide screen. */\nfunction RailMenu({\n menu,\n linkComponent,\n copy,\n testId,\n}: {\n menu: SectionNavMenu;\n linkComponent: ElementType | undefined;\n copy: SectionNavCopy;\n testId: string;\n}): React.JSX.Element {\n return (\n <Box component=\"section\" data-testid={testId} sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}>\n <RailHeading>{menu.title}</RailHeading>\n {menu.groups.map((group) => (\n <Box key={group.id} sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}>\n {group.title ? (\n <Typography variant=\"caption\" color=\"text.secondary\" sx={{ px: 1.25, pt: 0.5 }}>\n {group.title}\n </Typography>\n ) : null}\n {group.entries.map((entry) => (\n <RailRow\n key={entry.id}\n label={entry.label}\n description={entry.description}\n icon={entry.icon}\n count={entry.badge}\n active={entry.active === true}\n copy={copy}\n testId={`${testId}-entry-${entry.id}`}\n control={controlProps({ href: entry.href, linkComponent, onClick: () => entry.onSelect?.() })}\n />\n ))}\n </Box>\n ))}\n </Box>\n );\n}\n\n/**\n * The wide-screen layout: a vertical rail — the way back, the destinations,\n * then every menu's entries.\n *\n * It fills the column the host gives it and scrolls on its own, like the\n * sidebar it stands in for.\n */\nexport function SectionNavRail({\n label,\n destinations,\n primary,\n more,\n back,\n heading,\n linkComponent,\n copy,\n dataTestId,\n}: Required<Pick<SectionNavProps, 'label' | 'destinations' | 'copy' | 'dataTestId'>> &\n Pick<SectionNavProps, 'primary' | 'more' | 'back' | 'heading'> & {\n linkComponent: ElementType | undefined;\n }): React.JSX.Element {\n const theme = useTheme();\n return (\n <Box\n component=\"nav\"\n aria-label={label}\n data-testid={dataTestId}\n sx={{\n display: 'flex',\n flexDirection: 'column',\n gap: 0.25,\n height: '100%',\n overflowY: 'auto',\n px: 1,\n py: 1.5,\n bgcolor: 'background.paper',\n }}\n >\n {back ? (\n <Box\n {...controlProps({ href: back.href, linkComponent })}\n data-testid={`${dataTestId}-back`}\n sx={{\n ...CONTROL_RESET,\n ...focusRing(theme),\n display: 'flex',\n alignItems: 'center',\n gap: 1,\n px: 1.25,\n py: 0.75,\n mb: 0.5,\n borderRadius: 1,\n color: 'text.secondary',\n '&:hover': { bgcolor: 'action.hover', color: 'text.primary' },\n '& svg': { fontSize: rem(theme, 20) },\n }}\n >\n {back.icon}\n <Typography component=\"span\" variant=\"body2\" sx={{ fontWeight: 600 }}>\n {back.label}\n </Typography>\n </Box>\n ) : null}\n {heading ? <RailHeading>{heading}</RailHeading> : null}\n {destinations.map((destination) => (\n <RailRow\n key={destination.id}\n label={destination.label}\n icon={destination.icon}\n count={destination.badge}\n active={destination.active === true}\n copy={copy}\n testId={`${dataTestId}-dest-${destination.id}`}\n control={controlProps({ href: destination.href, linkComponent })}\n />\n ))}\n {primary ? (\n <RailMenu menu={primary} linkComponent={linkComponent} copy={copy} testId={`${dataTestId}-primary`} />\n ) : null}\n {more ? <RailMenu menu={more} linkComponent={linkComponent} copy={copy} testId={`${dataTestId}-more`} /> : null}\n </Box>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1,62 +0,0 @@
1
- import {
2
- Box,
3
- CONTROL_RESET,
4
- focusRing
5
- } from "./chunk-GLKQT2DS.js";
6
- import {
7
- rem
8
- } from "./chunk-YKCAJ2TN.js";
9
-
10
- // src/components/navigation/SectionNav/SectionNav.primary.tsx
11
- import { useTheme } from "@mui/material/styles/index.js";
12
- import { jsx } from "react/jsx-runtime";
13
- function RaisedActionButton({
14
- label,
15
- icon,
16
- onClick,
17
- open,
18
- closeLabel,
19
- dataTestId = "raised-action"
20
- }) {
21
- const theme = useTheme();
22
- const size = rem(theme, 52);
23
- const expanded = open === true;
24
- return /* @__PURE__ */ jsx(Box, { sx: { flex: "none", display: "flex", alignItems: "flex-start", justifyContent: "center", px: 0.5 }, children: /* @__PURE__ */ jsx(
25
- Box,
26
- {
27
- component: "button",
28
- type: "button",
29
- onClick,
30
- "aria-label": expanded && closeLabel ? closeLabel : label,
31
- "aria-expanded": open,
32
- "data-testid": dataTestId,
33
- sx: {
34
- ...CONTROL_RESET,
35
- ...focusRing(theme),
36
- width: size,
37
- height: size,
38
- // Lifted half out of the bar: the one control that is not a place.
39
- marginTop: rem(theme, -18),
40
- borderRadius: "50%",
41
- display: "flex",
42
- alignItems: "center",
43
- justifyContent: "center",
44
- bgcolor: "primary.main",
45
- color: "primary.contrastText",
46
- boxShadow: theme.shadows[6],
47
- "& svg": {
48
- fontSize: rem(theme, 26),
49
- transition: theme.transitions.create("transform", { duration: theme.transitions.duration.shorter }),
50
- transform: expanded ? "rotate(45deg)" : "none"
51
- },
52
- "@media (prefers-reduced-motion: reduce)": { "& svg": { transition: "none" } }
53
- },
54
- children: icon
55
- }
56
- ) });
57
- }
58
-
59
- export {
60
- RaisedActionButton
61
- };
62
- //# sourceMappingURL=chunk-RZ4SBSLP.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.primary.tsx"],"sourcesContent":["import { useTheme } from '@mui/material/styles/index.js';\nimport type { ReactNode } from 'react';\n\nimport { rem } from '../../../tokens/scales';\n\nimport { Box, CONTROL_RESET, focusRing } from './SectionNav.parts';\n\nexport interface RaisedActionButtonProps {\n /** The button's accessible name — it has no visible label. */\n label: string;\n icon: ReactNode;\n onClick: () => void;\n /**\n * Whether what the button opens is open. Omit for a button that opens\n * nothing (a plain action): it then carries no `aria-expanded` and its icon\n * never turns.\n */\n open?: boolean;\n /** The name it takes while `open` — the same control closes what it opened. REQUIRED with `open`. */\n closeLabel?: string;\n dataTestId?: string;\n}\n\n/**\n * The raised round button in the middle of a bottom bar — the one control in\n * the row that is an ACTION rather than a place.\n *\n * Lifted half out of the bar so it reads as different in kind from the tabs\n * beside it, and unlabelled so it costs the row less width than a tab: that\n * width is what lets a bar keep four labelled tabs AND this button at 320px.\n *\n * `SectionNav` draws it for its `primary` menu. It is exported on its own for\n * a bar the host already draws — drop it between two tabs, in a flex row.\n */\nexport function RaisedActionButton({\n label,\n icon,\n onClick,\n open,\n closeLabel,\n dataTestId = 'raised-action',\n}: RaisedActionButtonProps): React.JSX.Element {\n const theme = useTheme();\n const size = rem(theme, 52);\n const expanded = open === true;\n return (\n <Box sx={{ flex: 'none', display: 'flex', alignItems: 'flex-start', justifyContent: 'center', px: 0.5 }}>\n <Box\n component=\"button\"\n type=\"button\"\n onClick={onClick}\n aria-label={expanded && closeLabel ? closeLabel : label}\n aria-expanded={open}\n data-testid={dataTestId}\n sx={{\n ...CONTROL_RESET,\n ...focusRing(theme),\n width: size,\n height: size,\n // Lifted half out of the bar: the one control that is not a place.\n marginTop: rem(theme, -18),\n borderRadius: '50%',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n bgcolor: 'primary.main',\n color: 'primary.contrastText',\n boxShadow: theme.shadows[6],\n '& svg': {\n fontSize: rem(theme, 26),\n transition: theme.transitions.create('transform', { duration: theme.transitions.duration.shorter }),\n transform: expanded ? 'rotate(45deg)' : 'none',\n },\n '@media (prefers-reduced-motion: reduce)': { '& svg': { transition: 'none' } },\n }}\n >\n {icon}\n </Box>\n </Box>\n );\n}\n"],"mappings":";;;;;;;;;;AAAA,SAAS,gBAAgB;AA+CnB;AAbC,SAAS,mBAAmB;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AACf,GAA+C;AAC7C,QAAM,QAAQ,SAAS;AACvB,QAAM,OAAO,IAAI,OAAO,EAAE;AAC1B,QAAM,WAAW,SAAS;AAC1B,SACE,oBAAC,OAAI,IAAI,EAAE,MAAM,QAAQ,SAAS,QAAQ,YAAY,cAAc,gBAAgB,UAAU,IAAI,IAAI,GACpG;AAAA,IAAC;AAAA;AAAA,MACC,WAAU;AAAA,MACV,MAAK;AAAA,MACL;AAAA,MACA,cAAY,YAAY,aAAa,aAAa;AAAA,MAClD,iBAAe;AAAA,MACf,eAAa;AAAA,MACb,IAAI;AAAA,QACF,GAAG;AAAA,QACH,GAAG,UAAU,KAAK;AAAA,QAClB,OAAO;AAAA,QACP,QAAQ;AAAA;AAAA,QAER,WAAW,IAAI,OAAO,GAAG;AAAA,QACzB,cAAc;AAAA,QACd,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,SAAS;AAAA,QACT,OAAO;AAAA,QACP,WAAW,MAAM,QAAQ,CAAC;AAAA,QAC1B,SAAS;AAAA,UACP,UAAU,IAAI,OAAO,EAAE;AAAA,UACvB,YAAY,MAAM,YAAY,OAAO,aAAa,EAAE,UAAU,MAAM,YAAY,SAAS,QAAQ,CAAC;AAAA,UAClG,WAAW,WAAW,kBAAkB;AAAA,QAC1C;AAAA,QACA,2CAA2C,EAAE,SAAS,EAAE,YAAY,OAAO,EAAE;AAAA,MAC/E;AAAA,MAEC;AAAA;AAAA,EACH,GACF;AAEJ;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/navigation/SectionNav/SectionNav.helpers.ts"],"sourcesContent":["import type { SectionNavDestination, SectionNavMenu } from './SectionNav.types';\n\n/** A count worth drawing: positive and finite. Zero and \"unknown\" draw nothing. */\nexport function shownCount(count: number | undefined): number | undefined {\n return count !== undefined && Number.isFinite(count) && count > 0 ? count : undefined;\n}\n\n/**\n * The \"more\" slot's badge: its entries' counts, rolled up.\n *\n * The same reason a folded sidebar parent shows its children's counts — the\n * sheet starts closed, so a count only visible once it is opened is one nobody\n * sees.\n */\nexport function menuCount(menu: SectionNavMenu | undefined): number | undefined {\n if (!menu) return undefined;\n const total = menu.groups\n .flatMap((group) => group.entries)\n .reduce((sum, entry) => sum + (shownCount(entry.badge) ?? 0), 0);\n return shownCount(total);\n}\n\n/** Is the viewer on one of this menu's entries? Then its slot reads as current. */\nexport function menuActive(menu: SectionNavMenu | undefined): boolean {\n return menu?.groups.some((group) => group.entries.some((entry) => entry.active === true)) ?? false;\n}\n\n/** What one bar slot holds, in left-to-right order. */\nexport type BarSlot =\n | { kind: 'destination'; destination: SectionNavDestination }\n | { kind: 'more' }\n | { kind: 'primary' };\n\n/**\n * The bar's slots: the destinations, then `more`, with `primary` in the MIDDLE.\n *\n * The middle is where a thumb rests and where a raised button reads as the\n * one thing this bar is for. With four slots it lands between the second and\n * the third; with an odd count it takes the lower middle, so the heavier side\n * is the right one, under the thumb of a right-handed phone.\n */\nexport function barSlots(\n destinations: readonly SectionNavDestination[],\n hasMore: boolean,\n hasPrimary: boolean,\n): BarSlot[] {\n const slots: BarSlot[] = destinations.map((destination) => ({ kind: 'destination', destination }));\n if (hasMore) slots.push({ kind: 'more' });\n if (hasPrimary) slots.splice(Math.floor(slots.length / 2), 0, { kind: 'primary' });\n return slots;\n}\n"],"mappings":";AAGO,SAAS,WAAW,OAA+C;AACxE,SAAO,UAAU,UAAa,OAAO,SAAS,KAAK,KAAK,QAAQ,IAAI,QAAQ;AAC9E;AASO,SAAS,UAAU,MAAsD;AAC9E,MAAI,CAAC,KAAM,QAAO;AAClB,QAAM,QAAQ,KAAK,OAChB,QAAQ,CAAC,UAAU,MAAM,OAAO,EAChC,OAAO,CAAC,KAAK,UAAU,OAAO,WAAW,MAAM,KAAK,KAAK,IAAI,CAAC;AACjE,SAAO,WAAW,KAAK;AACzB;AAGO,SAAS,WAAW,MAA2C;AACpE,SAAO,MAAM,OAAO,KAAK,CAAC,UAAU,MAAM,QAAQ,KAAK,CAAC,UAAU,MAAM,WAAW,IAAI,CAAC,KAAK;AAC/F;AAgBO,SAAS,SACd,cACA,SACA,YACW;AACX,QAAM,QAAmB,aAAa,IAAI,CAAC,iBAAiB,EAAE,MAAM,eAAe,YAAY,EAAE;AACjG,MAAI,QAAS,OAAM,KAAK,EAAE,MAAM,OAAO,CAAC;AACxC,MAAI,WAAY,OAAM,OAAO,KAAK,MAAM,MAAM,SAAS,CAAC,GAAG,GAAG,EAAE,MAAM,UAAU,CAAC;AACjF,SAAO;AACT;","names":[]}