@12-apps/ui 6.44.2 → 6.45.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 (414) hide show
  1. package/NATIVE.md +1 -1
  2. package/components-catalog.md +13 -4
  3. package/dist/_internal/components/data-display/AsyncStateContainer/AsyncStateContainer.js +4 -4
  4. package/dist/_internal/components/data-display/Avatar/Avatar.js +2 -2
  5. package/dist/_internal/components/data-display/Badge/Badge.js +2 -2
  6. package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +1 -1
  7. package/dist/_internal/components/data-display/CardKit/use-row-confirm.js +1 -1
  8. package/dist/_internal/components/data-display/Carousel/Carousel.js +2 -2
  9. package/dist/_internal/components/data-display/Chart/Chart.js +4 -4
  10. package/dist/_internal/components/data-display/Chart/SpecChart.js +6 -6
  11. package/dist/_internal/components/data-display/Chart/chart-context.js +2 -2
  12. package/dist/_internal/components/data-display/Chart/chart-renderers.js +3 -3
  13. package/dist/_internal/components/data-display/DataGrid/DataGrid.js +2 -2
  14. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +37 -37
  15. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +53 -53
  16. package/dist/_internal/components/data-display/DataViews/DeleteViewDialog.js +4 -4
  17. package/dist/_internal/components/data-display/DataViews/ManageViewsDialog.js +5 -5
  18. package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +11 -11
  19. package/dist/_internal/components/data-display/DataViews/base-card.js +5 -5
  20. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +1 -1
  21. package/dist/_internal/components/data-display/DataViews/base-list-card-gutters.js +3 -3
  22. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +1 -1
  23. package/dist/_internal/components/data-display/DataViews/base-list-card.js +7 -7
  24. package/dist/_internal/components/data-display/DataViews/data-views-category-pill.js +8 -8
  25. package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +1 -1
  26. package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +15 -15
  27. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +4 -4
  28. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +33 -33
  29. package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +14 -14
  30. package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +12 -12
  31. package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +13 -13
  32. package/dist/_internal/components/data-display/DataViews/data-views-pagination.js +3 -3
  33. package/dist/_internal/components/data-display/DataViews/data-views-range-pill.js +3 -3
  34. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +6 -6
  35. package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +16 -16
  36. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +5 -5
  37. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +1 -1
  38. package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +3 -3
  39. package/dist/_internal/components/data-display/FleetMap/FleetBody.js +10 -10
  40. package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +6 -6
  41. package/dist/_internal/components/data-display/FleetMap/FleetMap.js +11 -11
  42. package/dist/_internal/components/data-display/FleetMap/FleetRoster.js +3 -3
  43. package/dist/_internal/components/data-display/HoverCard/HoverCard.js +3 -3
  44. package/dist/_internal/components/data-display/LazyImage/LazyImage.js +3 -3
  45. package/dist/_internal/components/data-display/Lightbox/Lightbox.js +3 -3
  46. package/dist/_internal/components/data-display/LoadingState/LoadingState.js +3 -3
  47. package/dist/_internal/components/data-display/MapPreview/MapLayers.js +2 -2
  48. package/dist/_internal/components/data-display/MapPreview/MapPreview.js +5 -5
  49. package/dist/_internal/components/data-display/StatCard/StatCard.js +3 -3
  50. package/dist/_internal/components/data-display/index.js +35 -35
  51. package/dist/_internal/components/feedback/Dialog/Dialog.js +3 -3
  52. package/dist/_internal/components/feedback/StackedModal/StackedModal.js +6 -6
  53. package/dist/_internal/components/feedback/TutorialOverlay/TutorialOverlay.js +2 -2
  54. package/dist/_internal/components/feedback/index.js +14 -14
  55. package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.hooks.js +3 -3
  56. package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.js +5 -5
  57. package/dist/_internal/components/form/AddressAutocomplete/AddressAutocompleteField.js +2 -2
  58. package/dist/_internal/components/form/Calendar/Calendar.js +4 -4
  59. package/dist/_internal/components/form/Calendar/CalendarDayCell.js +2 -2
  60. package/dist/_internal/components/form/Calendar/CalendarMonth.js +3 -3
  61. package/dist/_internal/components/form/CategorySelect/CategoryPanel.js +2 -2
  62. package/dist/_internal/components/form/CategorySelect/CategorySelect.js +5 -5
  63. package/dist/_internal/components/form/CepField/CepField.js +3 -3
  64. package/dist/_internal/components/form/Checkbox/Checkbox.js +2 -2
  65. package/dist/_internal/components/form/CodeEditor/CodeEditor.js +2 -2
  66. package/dist/_internal/components/form/Command/Command.js +2 -2
  67. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +7 -7
  68. package/dist/_internal/components/form/Input/Input.js +2 -2
  69. package/dist/_internal/components/form/Menubar/Menubar.js +2 -2
  70. package/dist/_internal/components/form/NumberField/NumberField.js +3 -3
  71. package/dist/_internal/components/form/RichTextEditor/RichTextEditor.js +2 -2
  72. package/dist/_internal/components/form/Switch/Switch.js +5 -5
  73. package/dist/_internal/components/form/Switch/Switch.parts.js +3 -3
  74. package/dist/_internal/components/form/Switch/Switch.styles.js +2 -2
  75. package/dist/_internal/components/form/UploadButton/UploadButton.js +2 -2
  76. package/dist/_internal/components/form/index.js +35 -35
  77. package/dist/_internal/components/form/total-form/Fields/CategoryField.js +6 -6
  78. package/dist/_internal/components/form/total-form/Fields/CepField.js +4 -4
  79. package/dist/_internal/components/form/total-form/Fields/TextField.js +3 -3
  80. package/dist/_internal/components/form/total-form/Fields/index.js +12 -12
  81. package/dist/_internal/components/index.js +130 -112
  82. package/dist/_internal/components/layout/Card/Card.js +2 -2
  83. package/dist/_internal/components/layout/SettingCard/SettingGroup.js +7 -7
  84. package/dist/_internal/components/layout/SettingCard/SettingSwitch.js +6 -6
  85. package/dist/_internal/components/layout/SettingCard/SettingToggle.js +7 -7
  86. package/dist/_internal/components/layout/SettingsLayout/SettingsLayout.js +4 -4
  87. package/dist/_internal/components/layout/SettingsLayout/SettingsPanel.js +3 -3
  88. package/dist/_internal/components/layout/SettingsLayout/SettingsSectionChips.js +2 -2
  89. package/dist/_internal/components/layout/Skeleton/Skeleton.js +2 -2
  90. package/dist/_internal/components/layout/index.js +19 -19
  91. package/dist/_internal/components/navigation/AppHeader/AppHeader.details.js +4 -4
  92. package/dist/_internal/components/navigation/CommandPalette/CommandPalette.js +2 -2
  93. package/dist/_internal/components/navigation/Pagination/Pagination.js +2 -2
  94. package/dist/_internal/components/navigation/SectionNav/SectionNav.bar.js +45 -0
  95. package/dist/_internal/components/navigation/SectionNav/SectionNav.helpers.js +14 -0
  96. package/dist/_internal/components/navigation/SectionNav/SectionNav.helpers.js.map +1 -0
  97. package/dist/_internal/components/navigation/SectionNav/SectionNav.js +45 -0
  98. package/dist/_internal/components/navigation/SectionNav/SectionNav.js.map +1 -0
  99. package/dist/_internal/components/navigation/SectionNav/SectionNav.parts.js +46 -0
  100. package/dist/_internal/components/navigation/SectionNav/SectionNav.parts.js.map +1 -0
  101. package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js +39 -0
  102. package/dist/_internal/components/navigation/SectionNav/SectionNav.primary.js.map +1 -0
  103. package/dist/_internal/components/navigation/SectionNav/SectionNav.rail.js +39 -0
  104. package/dist/_internal/components/navigation/SectionNav/SectionNav.rail.js.map +1 -0
  105. package/dist/_internal/components/navigation/SectionNav/SectionNav.sheet.js +41 -0
  106. package/dist/_internal/components/navigation/SectionNav/SectionNav.sheet.js.map +1 -0
  107. package/dist/_internal/components/navigation/SectionNav/SectionNav.types.js +1 -0
  108. package/dist/_internal/components/navigation/SectionNav/SectionNav.types.js.map +1 -0
  109. package/dist/_internal/components/navigation/SectionNav/__stories__/fixtures.js +127 -0
  110. package/dist/_internal/components/navigation/SectionNav/__stories__/fixtures.js.map +1 -0
  111. package/dist/_internal/components/navigation/index.js +39 -12
  112. package/dist/_internal/components/utility/InfiniteScroll/InfiniteScroll.js +2 -2
  113. package/dist/_internal/components/utility/InstallPrompt/InstallPrompt.js +2 -2
  114. package/dist/_internal/components/utility/index.js +8 -8
  115. package/dist/_internal/en-US.navigation.js +5 -3
  116. package/dist/_internal/pt-BR.navigation.js +5 -3
  117. package/dist/_internal/social-login-button/social-login-button.js +3 -3
  118. package/dist/_internal/user-avatar/user-avatar.js +5 -5
  119. package/dist/charts.js +6 -6
  120. package/dist/{chunk-J6TIK47Z.js → chunk-2HPNN5XA.js} +2 -2
  121. package/dist/{chunk-BEGTLELZ.js → chunk-2K2B5QM2.js} +5 -5
  122. package/dist/chunk-2OP2FYB3.js +174 -0
  123. package/dist/chunk-2OP2FYB3.js.map +1 -0
  124. package/dist/chunk-3WCUGTRH.js +240 -0
  125. package/dist/chunk-3WCUGTRH.js.map +1 -0
  126. package/dist/{chunk-3I77A65F.js → chunk-442FSG7G.js} +4 -4
  127. package/dist/{chunk-ZOUWHGV3.js → chunk-4MGFUPQT.js} +4 -4
  128. package/dist/{chunk-26QYVCDK.js → chunk-525AOF6I.js} +2 -2
  129. package/dist/chunk-5AK2EZG5.js +1 -0
  130. package/dist/chunk-5AK2EZG5.js.map +1 -0
  131. package/dist/{chunk-5752357K.js → chunk-5KGABAQB.js} +4 -4
  132. package/dist/{chunk-SDKOOVEX.js → chunk-6GAZAJXB.js} +4 -4
  133. package/dist/{chunk-EO6LCGGQ.js → chunk-6J32H2RN.js} +2 -2
  134. package/dist/chunk-6OLJ2RAT.js +62 -0
  135. package/dist/chunk-6OLJ2RAT.js.map +1 -0
  136. package/dist/{chunk-7XDET7PL.js → chunk-6OQHZVK6.js} +4 -4
  137. package/dist/{chunk-F3AYISXT.js → chunk-6PU3JYVY.js} +4 -4
  138. package/dist/{chunk-RRAWJQIO.js → chunk-A64MQ7GW.js} +2 -2
  139. package/dist/{chunk-ADSA76T7.js → chunk-AG3DY5TH.js} +2 -2
  140. package/dist/{chunk-CIBTYBBN.js → chunk-AJ4MRDKM.js} +3 -3
  141. package/dist/{chunk-RJ35IXFD.js → chunk-B7HYM3QB.js} +2 -2
  142. package/dist/{chunk-X3C3VTYS.js → chunk-BEX3FLHB.js} +2 -2
  143. package/dist/{chunk-C5RTSOXD.js → chunk-BUAFRLSB.js} +2 -2
  144. package/dist/{chunk-DH6SL3SY.js → chunk-DSDNGTH6.js} +6 -6
  145. package/dist/{chunk-AUQRGZE7.js → chunk-EDZYPHZT.js} +7 -2
  146. package/dist/chunk-EDZYPHZT.js.map +1 -0
  147. package/dist/{chunk-JZ7ZRZTF.js → chunk-EJMSSDLM.js} +2 -2
  148. package/dist/{chunk-62OGPVCL.js → chunk-EPZ7B35I.js} +7 -2
  149. package/dist/chunk-EPZ7B35I.js.map +1 -0
  150. package/dist/{chunk-GP4BJI3F.js → chunk-ETCS6OBJ.js} +4 -4
  151. package/dist/{chunk-MVR4GURP.js → chunk-EU76OQGR.js} +2 -2
  152. package/dist/{chunk-DHW5UMUG.js → chunk-FNLD2KCQ.js} +4 -4
  153. package/dist/{chunk-XRUW7DMH.js → chunk-FPKVHR5L.js} +2 -2
  154. package/dist/{chunk-HKBJZX3C.js → chunk-FQ637IDM.js} +7 -7
  155. package/dist/{chunk-DDL6W7JS.js → chunk-FRD7U6QO.js} +5 -5
  156. package/dist/{chunk-YCHOWWRE.js → chunk-G6T7KRQ3.js} +2 -2
  157. package/dist/{chunk-EKBUM7HK.js → chunk-GYZUJ7HH.js} +4 -4
  158. package/dist/{chunk-ZQ7IESR7.js → chunk-H7HEB4UC.js} +5 -5
  159. package/dist/{chunk-JYLBVHG2.js → chunk-HAPELHNW.js} +7 -7
  160. package/dist/{chunk-HNFZLXZI.js → chunk-HBP2OU4Q.js} +5 -5
  161. package/dist/{chunk-K7FSTB2K.js → chunk-HSNOWYEE.js} +2 -2
  162. package/dist/chunk-HYEOKBFV.js +73 -0
  163. package/dist/chunk-HYEOKBFV.js.map +1 -0
  164. package/dist/{chunk-GI63FQEJ.js → chunk-HYNDC3FP.js} +4 -4
  165. package/dist/{chunk-ZBVU2YWV.js → chunk-IITZA6U2.js} +9 -9
  166. package/dist/{chunk-BZFRBG2H.js → chunk-IIXMTC65.js} +4 -4
  167. package/dist/{chunk-JFLFZLOA.js → chunk-IJAUHR3M.js} +4 -4
  168. package/dist/{chunk-K5CCQBNN.js → chunk-ILKNYENU.js} +4 -4
  169. package/dist/{chunk-DJIFXJ4C.js → chunk-IPI3OU2P.js} +4 -4
  170. package/dist/{chunk-6JGATEOF.js → chunk-IWYTOCCV.js} +3 -3
  171. package/dist/{chunk-5ZOJLYD2.js → chunk-JE6RZ5L6.js} +4 -4
  172. package/dist/{chunk-DE6A46AE.js → chunk-JFL5WT3S.js} +5 -5
  173. package/dist/{chunk-CYPBF3BI.js → chunk-JO4UMHWR.js} +3 -3
  174. package/dist/{chunk-LRFXCZB4.js → chunk-JWNOM5QT.js} +4 -4
  175. package/dist/{chunk-NU55QUMO.js → chunk-K45ML7M7.js} +2 -2
  176. package/dist/{chunk-OAVRXSAS.js → chunk-K7PWC44N.js} +2 -2
  177. package/dist/{chunk-ZGCPDA3F.js → chunk-KQS4ZJGS.js} +5 -5
  178. package/dist/{chunk-PAICZOL5.js → chunk-KTX7XME6.js} +4 -4
  179. package/dist/{chunk-KPZ53JY6.js → chunk-L3APNYI5.js} +3 -3
  180. package/dist/{chunk-GKNMKPR6.js → chunk-L6Q2A32O.js} +5 -5
  181. package/dist/{chunk-IG26N6J2.js → chunk-MD3ND6DT.js} +3 -3
  182. package/dist/{chunk-DTLKF4AX.js → chunk-MQ277OLB.js} +9 -9
  183. package/dist/{chunk-BA6Z52QN.js → chunk-NF4GHTZ4.js} +2 -2
  184. package/dist/{chunk-MSAAOQAD.js → chunk-NFA7STJA.js} +4 -4
  185. package/dist/{chunk-7HZTYK7U.js → chunk-NLYNRE7L.js} +4 -4
  186. package/dist/{chunk-HOIHO2YQ.js → chunk-NRI2TZDS.js} +2 -2
  187. package/dist/{chunk-VQUPB7F7.js → chunk-O25RFGPX.js} +4 -4
  188. package/dist/{chunk-Z3HSRNJT.js → chunk-OARM5RX4.js} +5 -5
  189. package/dist/{chunk-JDEKR77O.js → chunk-OERKNBKK.js} +2 -2
  190. package/dist/{chunk-WN5PNP6F.js → chunk-OP5JR5Q5.js} +4 -4
  191. package/dist/{chunk-XP522FFM.js → chunk-PARTZ7XI.js} +2 -2
  192. package/dist/{chunk-BHE44AQE.js → chunk-PCHUIDMT.js} +2 -2
  193. package/dist/{chunk-NYFGFELX.js → chunk-PGPPN63I.js} +6 -6
  194. package/dist/{chunk-Y2CMWGIU.js → chunk-PKXCQKPB.js} +2 -2
  195. package/dist/{chunk-6B3QXFF5.js → chunk-PNWGQAXQ.js} +2 -2
  196. package/dist/{chunk-IO2X6DVH.js → chunk-PSX7DAMV.js} +4 -4
  197. package/dist/{chunk-OL2BEJZR.js → chunk-Q2LQVYXY.js} +2 -2
  198. package/dist/{chunk-CMV6BRQ3.js → chunk-Q534UJ34.js} +4 -4
  199. package/dist/chunk-R26KYJHK.js +1 -0
  200. package/dist/chunk-R26KYJHK.js.map +1 -0
  201. package/dist/chunk-R73CRAAI.js +1 -0
  202. package/dist/chunk-R73CRAAI.js.map +1 -0
  203. package/dist/{chunk-VKFZQSQC.js → chunk-RPFQQP5S.js} +6 -6
  204. package/dist/chunk-SENCNTMV.js +55 -0
  205. package/dist/chunk-SENCNTMV.js.map +1 -0
  206. package/dist/{chunk-X4VWYWFK.js → chunk-SJY4DDG7.js} +4 -4
  207. package/dist/{chunk-DYCTIOER.js → chunk-SRZY6QG3.js} +5 -5
  208. package/dist/chunk-TCFBCTZD.js +168 -0
  209. package/dist/chunk-TCFBCTZD.js.map +1 -0
  210. package/dist/{chunk-44USLRMT.js → chunk-TPPFWETI.js} +6 -6
  211. package/dist/{chunk-XXL4PM4M.js → chunk-TWVRPT7J.js} +2 -2
  212. package/dist/{chunk-SM4MT4YC.js → chunk-U2UT2NDH.js} +3 -3
  213. package/dist/{chunk-5MW7OYBM.js → chunk-UJOFRJLX.js} +2 -2
  214. package/dist/{chunk-O6IF4BZT.js → chunk-UUJ7J7NE.js} +3 -3
  215. package/dist/{chunk-5JCGBCFJ.js → chunk-V2GHNHP6.js} +2 -2
  216. package/dist/{chunk-WQ3KTELX.js → chunk-V4R6Q5ED.js} +8 -8
  217. package/dist/{chunk-B3QWQG62.js → chunk-V54LG3QG.js} +2 -2
  218. package/dist/{chunk-6B4UTB4O.js → chunk-VDSQ5H4Y.js} +3 -3
  219. package/dist/chunk-VHVI3D4R.js +26 -0
  220. package/dist/chunk-VHVI3D4R.js.map +1 -0
  221. package/dist/{chunk-AEKHSORY.js → chunk-VOBVYVPN.js} +5 -5
  222. package/dist/{chunk-B2WBDMHE.js → chunk-VPH47OIV.js} +4 -4
  223. package/dist/{chunk-JSOJKHEI.js → chunk-WHYVVKRS.js} +2 -2
  224. package/dist/{chunk-KUKY5GEX.js → chunk-WU2KXA6I.js} +2 -2
  225. package/dist/{chunk-VNOXUWK7.js → chunk-X5F4FRH7.js} +4 -4
  226. package/dist/{chunk-EOEYOPOS.js → chunk-YKALXHCS.js} +11 -11
  227. package/dist/{chunk-BKBELIUR.js → chunk-YWQ7QCWR.js} +6 -6
  228. package/dist/data-display/AsyncStateContainer.js +4 -4
  229. package/dist/data-display/Avatar.js +2 -2
  230. package/dist/data-display/Badge.js +3 -2
  231. package/dist/data-display/CardKit.js +11 -11
  232. package/dist/data-display/Carousel.js +2 -2
  233. package/dist/data-display/Chart.js +6 -6
  234. package/dist/data-display/DataGrid.js +2 -2
  235. package/dist/data-display/DataViews.js +65 -65
  236. package/dist/data-display/FleetMap.js +11 -11
  237. package/dist/data-display/HoverCard.js +3 -3
  238. package/dist/data-display/LazyImage.js +3 -3
  239. package/dist/data-display/Lightbox.js +3 -3
  240. package/dist/data-display/LoadingState.js +3 -3
  241. package/dist/data-display/MapPreview.js +5 -5
  242. package/dist/data-display/StatCard.js +3 -3
  243. package/dist/en-US.js +8 -6
  244. package/dist/feedback/ConfirmAction.js +3 -3
  245. package/dist/feedback/Dialog.js +3 -3
  246. package/dist/feedback/StackedModal.js +6 -6
  247. package/dist/feedback/TutorialOverlay.js +2 -2
  248. package/dist/form/AddressAutocomplete.js +5 -5
  249. package/dist/form/Calendar.js +4 -4
  250. package/dist/form/CategorySelect.js +5 -5
  251. package/dist/form/CepField.js +3 -3
  252. package/dist/form/Checkbox.js +2 -2
  253. package/dist/form/CodeEditor.js +2 -2
  254. package/dist/form/Command.js +2 -2
  255. package/dist/form/DateRangePicker.js +9 -9
  256. package/dist/form/Input.js +2 -2
  257. package/dist/form/Menubar.js +2 -2
  258. package/dist/form/NumberField.js +3 -3
  259. package/dist/form/RichTextEditor.js +2 -2
  260. package/dist/form/Switch.js +5 -5
  261. package/dist/form/UploadButton.js +2 -2
  262. package/dist/form/total-form.js +18 -18
  263. package/dist/layout/Card.js +2 -2
  264. package/dist/layout/ContentToolbar.js +4 -4
  265. package/dist/layout/SettingCard.js +11 -11
  266. package/dist/layout/SettingsLayout.js +4 -4
  267. package/dist/layout/Skeleton.js +2 -2
  268. package/dist/locales.js +15 -8
  269. package/dist/locales.js.map +1 -1
  270. package/dist/navigation/AppHeader.js +6 -6
  271. package/dist/navigation/CommandPalette.js +2 -2
  272. package/dist/navigation/Pagination.js +2 -2
  273. package/dist/navigation/SectionNav.js +52 -0
  274. package/dist/navigation/SectionNav.js.map +1 -0
  275. package/dist/pt-BR.js +4 -2
  276. package/dist/social-login-button.js +3 -3
  277. package/dist/types/components/navigation/SectionNav/SectionNav.bar.d.ts +14 -0
  278. package/dist/types/components/navigation/SectionNav/SectionNav.bar.d.ts.map +1 -0
  279. package/dist/types/components/navigation/SectionNav/SectionNav.d.ts +16 -0
  280. package/dist/types/components/navigation/SectionNav/SectionNav.d.ts.map +1 -0
  281. package/dist/types/components/navigation/SectionNav/SectionNav.helpers.d.ts +32 -0
  282. package/dist/types/components/navigation/SectionNav/SectionNav.helpers.d.ts.map +1 -0
  283. package/dist/types/components/navigation/SectionNav/SectionNav.parts.d.ts +42 -0
  284. package/dist/types/components/navigation/SectionNav/SectionNav.parts.d.ts.map +1 -0
  285. package/dist/types/components/navigation/SectionNav/SectionNav.primary.d.ts +29 -0
  286. package/dist/types/components/navigation/SectionNav/SectionNav.primary.d.ts.map +1 -0
  287. package/dist/types/components/navigation/SectionNav/SectionNav.rail.d.ts +13 -0
  288. package/dist/types/components/navigation/SectionNav/SectionNav.rail.d.ts.map +1 -0
  289. package/dist/types/components/navigation/SectionNav/SectionNav.sheet.d.ts +20 -0
  290. package/dist/types/components/navigation/SectionNav/SectionNav.sheet.d.ts.map +1 -0
  291. package/dist/types/components/navigation/SectionNav/SectionNav.types.d.ts +102 -0
  292. package/dist/types/components/navigation/SectionNav/SectionNav.types.d.ts.map +1 -0
  293. package/dist/types/components/navigation/SectionNav/__stories__/fixtures.d.ts +20 -0
  294. package/dist/types/components/navigation/SectionNav/__stories__/fixtures.d.ts.map +1 -0
  295. package/dist/types/components/navigation/SectionNav/index.d.ts +7 -0
  296. package/dist/types/components/navigation/SectionNav/index.d.ts.map +1 -0
  297. package/dist/types/components/navigation/index.d.ts +1 -0
  298. package/dist/types/components/navigation/index.d.ts.map +1 -1
  299. package/dist/types/copy/navigation.d.ts +10 -0
  300. package/dist/types/copy/navigation.d.ts.map +1 -1
  301. package/dist/types/en-US.navigation.d.ts +2 -1
  302. package/dist/types/en-US.navigation.d.ts.map +1 -1
  303. package/dist/types/locales.d.ts +2 -1
  304. package/dist/types/locales.d.ts.map +1 -1
  305. package/dist/types/pt-BR.navigation.d.ts +2 -1
  306. package/dist/types/pt-BR.navigation.d.ts.map +1 -1
  307. package/dist/user-avatar.js +5 -5
  308. package/dist/utility/InfiniteScroll.js +2 -2
  309. package/dist/utility/InstallPrompt.js +2 -2
  310. package/package.json +5 -1
  311. package/src/components/navigation/SectionNav/SectionNav.bar.tsx +258 -0
  312. package/src/components/navigation/SectionNav/SectionNav.helpers.ts +51 -0
  313. package/src/components/navigation/SectionNav/SectionNav.md +91 -0
  314. package/src/components/navigation/SectionNav/SectionNav.parts.tsx +88 -0
  315. package/src/components/navigation/SectionNav/SectionNav.primary.tsx +81 -0
  316. package/src/components/navigation/SectionNav/SectionNav.rail.tsx +208 -0
  317. package/src/components/navigation/SectionNav/SectionNav.sheet.tsx +206 -0
  318. package/src/components/navigation/SectionNav/SectionNav.tsx +56 -0
  319. package/src/components/navigation/SectionNav/SectionNav.types.ts +108 -0
  320. package/src/components/navigation/SectionNav/__stories__/fixtures.tsx +111 -0
  321. package/src/components/navigation/SectionNav/index.ts +13 -0
  322. package/src/components/navigation/index.ts +1 -0
  323. package/src/copy/navigation.ts +11 -0
  324. package/src/en-US.navigation.ts +6 -0
  325. package/src/locales.ts +5 -0
  326. package/src/pt-BR.navigation.ts +6 -0
  327. package/dist/chunk-62OGPVCL.js.map +0 -1
  328. package/dist/chunk-AUQRGZE7.js.map +0 -1
  329. package/dist/chunk-OJSVHBQO.js +0 -1
  330. /package/dist/{chunk-OJSVHBQO.js.map → _internal/components/navigation/SectionNav/SectionNav.bar.js.map} +0 -0
  331. /package/dist/{chunk-J6TIK47Z.js.map → chunk-2HPNN5XA.js.map} +0 -0
  332. /package/dist/{chunk-BEGTLELZ.js.map → chunk-2K2B5QM2.js.map} +0 -0
  333. /package/dist/{chunk-3I77A65F.js.map → chunk-442FSG7G.js.map} +0 -0
  334. /package/dist/{chunk-ZOUWHGV3.js.map → chunk-4MGFUPQT.js.map} +0 -0
  335. /package/dist/{chunk-26QYVCDK.js.map → chunk-525AOF6I.js.map} +0 -0
  336. /package/dist/{chunk-5752357K.js.map → chunk-5KGABAQB.js.map} +0 -0
  337. /package/dist/{chunk-SDKOOVEX.js.map → chunk-6GAZAJXB.js.map} +0 -0
  338. /package/dist/{chunk-EO6LCGGQ.js.map → chunk-6J32H2RN.js.map} +0 -0
  339. /package/dist/{chunk-7XDET7PL.js.map → chunk-6OQHZVK6.js.map} +0 -0
  340. /package/dist/{chunk-F3AYISXT.js.map → chunk-6PU3JYVY.js.map} +0 -0
  341. /package/dist/{chunk-RRAWJQIO.js.map → chunk-A64MQ7GW.js.map} +0 -0
  342. /package/dist/{chunk-ADSA76T7.js.map → chunk-AG3DY5TH.js.map} +0 -0
  343. /package/dist/{chunk-CIBTYBBN.js.map → chunk-AJ4MRDKM.js.map} +0 -0
  344. /package/dist/{chunk-RJ35IXFD.js.map → chunk-B7HYM3QB.js.map} +0 -0
  345. /package/dist/{chunk-X3C3VTYS.js.map → chunk-BEX3FLHB.js.map} +0 -0
  346. /package/dist/{chunk-C5RTSOXD.js.map → chunk-BUAFRLSB.js.map} +0 -0
  347. /package/dist/{chunk-DH6SL3SY.js.map → chunk-DSDNGTH6.js.map} +0 -0
  348. /package/dist/{chunk-JZ7ZRZTF.js.map → chunk-EJMSSDLM.js.map} +0 -0
  349. /package/dist/{chunk-GP4BJI3F.js.map → chunk-ETCS6OBJ.js.map} +0 -0
  350. /package/dist/{chunk-MVR4GURP.js.map → chunk-EU76OQGR.js.map} +0 -0
  351. /package/dist/{chunk-DHW5UMUG.js.map → chunk-FNLD2KCQ.js.map} +0 -0
  352. /package/dist/{chunk-XRUW7DMH.js.map → chunk-FPKVHR5L.js.map} +0 -0
  353. /package/dist/{chunk-HKBJZX3C.js.map → chunk-FQ637IDM.js.map} +0 -0
  354. /package/dist/{chunk-DDL6W7JS.js.map → chunk-FRD7U6QO.js.map} +0 -0
  355. /package/dist/{chunk-YCHOWWRE.js.map → chunk-G6T7KRQ3.js.map} +0 -0
  356. /package/dist/{chunk-EKBUM7HK.js.map → chunk-GYZUJ7HH.js.map} +0 -0
  357. /package/dist/{chunk-ZQ7IESR7.js.map → chunk-H7HEB4UC.js.map} +0 -0
  358. /package/dist/{chunk-JYLBVHG2.js.map → chunk-HAPELHNW.js.map} +0 -0
  359. /package/dist/{chunk-HNFZLXZI.js.map → chunk-HBP2OU4Q.js.map} +0 -0
  360. /package/dist/{chunk-K7FSTB2K.js.map → chunk-HSNOWYEE.js.map} +0 -0
  361. /package/dist/{chunk-GI63FQEJ.js.map → chunk-HYNDC3FP.js.map} +0 -0
  362. /package/dist/{chunk-ZBVU2YWV.js.map → chunk-IITZA6U2.js.map} +0 -0
  363. /package/dist/{chunk-BZFRBG2H.js.map → chunk-IIXMTC65.js.map} +0 -0
  364. /package/dist/{chunk-JFLFZLOA.js.map → chunk-IJAUHR3M.js.map} +0 -0
  365. /package/dist/{chunk-K5CCQBNN.js.map → chunk-ILKNYENU.js.map} +0 -0
  366. /package/dist/{chunk-DJIFXJ4C.js.map → chunk-IPI3OU2P.js.map} +0 -0
  367. /package/dist/{chunk-6JGATEOF.js.map → chunk-IWYTOCCV.js.map} +0 -0
  368. /package/dist/{chunk-5ZOJLYD2.js.map → chunk-JE6RZ5L6.js.map} +0 -0
  369. /package/dist/{chunk-DE6A46AE.js.map → chunk-JFL5WT3S.js.map} +0 -0
  370. /package/dist/{chunk-CYPBF3BI.js.map → chunk-JO4UMHWR.js.map} +0 -0
  371. /package/dist/{chunk-LRFXCZB4.js.map → chunk-JWNOM5QT.js.map} +0 -0
  372. /package/dist/{chunk-NU55QUMO.js.map → chunk-K45ML7M7.js.map} +0 -0
  373. /package/dist/{chunk-OAVRXSAS.js.map → chunk-K7PWC44N.js.map} +0 -0
  374. /package/dist/{chunk-ZGCPDA3F.js.map → chunk-KQS4ZJGS.js.map} +0 -0
  375. /package/dist/{chunk-PAICZOL5.js.map → chunk-KTX7XME6.js.map} +0 -0
  376. /package/dist/{chunk-KPZ53JY6.js.map → chunk-L3APNYI5.js.map} +0 -0
  377. /package/dist/{chunk-GKNMKPR6.js.map → chunk-L6Q2A32O.js.map} +0 -0
  378. /package/dist/{chunk-IG26N6J2.js.map → chunk-MD3ND6DT.js.map} +0 -0
  379. /package/dist/{chunk-DTLKF4AX.js.map → chunk-MQ277OLB.js.map} +0 -0
  380. /package/dist/{chunk-BA6Z52QN.js.map → chunk-NF4GHTZ4.js.map} +0 -0
  381. /package/dist/{chunk-MSAAOQAD.js.map → chunk-NFA7STJA.js.map} +0 -0
  382. /package/dist/{chunk-7HZTYK7U.js.map → chunk-NLYNRE7L.js.map} +0 -0
  383. /package/dist/{chunk-HOIHO2YQ.js.map → chunk-NRI2TZDS.js.map} +0 -0
  384. /package/dist/{chunk-VQUPB7F7.js.map → chunk-O25RFGPX.js.map} +0 -0
  385. /package/dist/{chunk-Z3HSRNJT.js.map → chunk-OARM5RX4.js.map} +0 -0
  386. /package/dist/{chunk-JDEKR77O.js.map → chunk-OERKNBKK.js.map} +0 -0
  387. /package/dist/{chunk-WN5PNP6F.js.map → chunk-OP5JR5Q5.js.map} +0 -0
  388. /package/dist/{chunk-XP522FFM.js.map → chunk-PARTZ7XI.js.map} +0 -0
  389. /package/dist/{chunk-BHE44AQE.js.map → chunk-PCHUIDMT.js.map} +0 -0
  390. /package/dist/{chunk-NYFGFELX.js.map → chunk-PGPPN63I.js.map} +0 -0
  391. /package/dist/{chunk-Y2CMWGIU.js.map → chunk-PKXCQKPB.js.map} +0 -0
  392. /package/dist/{chunk-6B3QXFF5.js.map → chunk-PNWGQAXQ.js.map} +0 -0
  393. /package/dist/{chunk-IO2X6DVH.js.map → chunk-PSX7DAMV.js.map} +0 -0
  394. /package/dist/{chunk-OL2BEJZR.js.map → chunk-Q2LQVYXY.js.map} +0 -0
  395. /package/dist/{chunk-CMV6BRQ3.js.map → chunk-Q534UJ34.js.map} +0 -0
  396. /package/dist/{chunk-VKFZQSQC.js.map → chunk-RPFQQP5S.js.map} +0 -0
  397. /package/dist/{chunk-X4VWYWFK.js.map → chunk-SJY4DDG7.js.map} +0 -0
  398. /package/dist/{chunk-DYCTIOER.js.map → chunk-SRZY6QG3.js.map} +0 -0
  399. /package/dist/{chunk-44USLRMT.js.map → chunk-TPPFWETI.js.map} +0 -0
  400. /package/dist/{chunk-XXL4PM4M.js.map → chunk-TWVRPT7J.js.map} +0 -0
  401. /package/dist/{chunk-SM4MT4YC.js.map → chunk-U2UT2NDH.js.map} +0 -0
  402. /package/dist/{chunk-5MW7OYBM.js.map → chunk-UJOFRJLX.js.map} +0 -0
  403. /package/dist/{chunk-O6IF4BZT.js.map → chunk-UUJ7J7NE.js.map} +0 -0
  404. /package/dist/{chunk-5JCGBCFJ.js.map → chunk-V2GHNHP6.js.map} +0 -0
  405. /package/dist/{chunk-WQ3KTELX.js.map → chunk-V4R6Q5ED.js.map} +0 -0
  406. /package/dist/{chunk-B3QWQG62.js.map → chunk-V54LG3QG.js.map} +0 -0
  407. /package/dist/{chunk-6B4UTB4O.js.map → chunk-VDSQ5H4Y.js.map} +0 -0
  408. /package/dist/{chunk-AEKHSORY.js.map → chunk-VOBVYVPN.js.map} +0 -0
  409. /package/dist/{chunk-B2WBDMHE.js.map → chunk-VPH47OIV.js.map} +0 -0
  410. /package/dist/{chunk-JSOJKHEI.js.map → chunk-WHYVVKRS.js.map} +0 -0
  411. /package/dist/{chunk-KUKY5GEX.js.map → chunk-WU2KXA6I.js.map} +0 -0
  412. /package/dist/{chunk-VNOXUWK7.js.map → chunk-X5F4FRH7.js.map} +0 -0
  413. /package/dist/{chunk-EOEYOPOS.js.map → chunk-YKALXHCS.js.map} +0 -0
  414. /package/dist/{chunk-BKBELIUR.js.map → chunk-YWQ7QCWR.js.map} +0 -0
@@ -0,0 +1,208 @@
1
+ import Typography from '@mui/material/Typography/index.js';
2
+ import { useTheme } from '@mui/material/styles/index.js';
3
+ import type { ElementType, ReactNode } from 'react';
4
+
5
+ import type { SectionNavCopy } from '../../../copy';
6
+ import { rem } from '../../../tokens/scales';
7
+
8
+ import { Box, CONTROL_RESET, CountedIcon, controlProps, focusRing } from './SectionNav.parts';
9
+ import type { SectionNavMenu, SectionNavProps } from './SectionNav.types';
10
+
11
+ /**
12
+ * One rail row: icon, label, and the count at the far end.
13
+ *
14
+ * Destinations and menu entries draw the same row — in the rail there is room
15
+ * for everything, so the difference between "a place" and "an action" is the
16
+ * section it sits in, not its shape.
17
+ */
18
+ function RailRow({
19
+ label,
20
+ description,
21
+ icon,
22
+ count,
23
+ active,
24
+ copy,
25
+ testId,
26
+ control,
27
+ }: {
28
+ label: string;
29
+ description?: string;
30
+ icon: ReactNode;
31
+ count: number | undefined;
32
+ active: boolean;
33
+ copy: SectionNavCopy;
34
+ testId: string;
35
+ control: Record<string, unknown>;
36
+ }): React.JSX.Element {
37
+ const theme = useTheme();
38
+ return (
39
+ <Box
40
+ {...control}
41
+ aria-current={active ? 'page' : undefined}
42
+ data-testid={testId}
43
+ sx={{
44
+ ...CONTROL_RESET,
45
+ ...focusRing(theme),
46
+ display: 'flex',
47
+ alignItems: 'center',
48
+ gap: 1.5,
49
+ width: '100%',
50
+ minHeight: rem(theme, 40),
51
+ px: 1.25,
52
+ py: 0.75,
53
+ borderRadius: 1,
54
+ textAlign: 'start',
55
+ color: active ? 'primary.main' : 'text.primary',
56
+ bgcolor: active ? 'action.selected' : 'transparent',
57
+ '&:hover': { bgcolor: active ? 'action.selected' : 'action.hover' },
58
+ '& svg': { color: 'primary.main', fontSize: rem(theme, 20) },
59
+ }}
60
+ >
61
+ <CountedIcon icon={icon} count={count} label={copy.badge} testId={`${testId}-badge`} />
62
+ <Box component="span" sx={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>
63
+ <Typography component="span" variant="body2" sx={{ fontWeight: active ? 700 : 500 }}>
64
+ {label}
65
+ </Typography>
66
+ {description ? (
67
+ <Typography component="span" variant="caption" color="text.secondary">
68
+ {description}
69
+ </Typography>
70
+ ) : null}
71
+ </Box>
72
+ </Box>
73
+ );
74
+ }
75
+
76
+ /** A heading between the rail's sections, in the sidebar's small-caps voice. */
77
+ function RailHeading({ children }: { children: ReactNode }): React.JSX.Element {
78
+ return (
79
+ <Typography variant="overline" color="text.secondary" sx={{ px: 1.25, pt: 1.5, lineHeight: 1.6 }}>
80
+ {children}
81
+ </Typography>
82
+ );
83
+ }
84
+
85
+ /** A menu's groups, listed under its title — nothing folded away on a wide screen. */
86
+ function RailMenu({
87
+ menu,
88
+ linkComponent,
89
+ copy,
90
+ testId,
91
+ }: {
92
+ menu: SectionNavMenu;
93
+ linkComponent: ElementType | undefined;
94
+ copy: SectionNavCopy;
95
+ testId: string;
96
+ }): React.JSX.Element {
97
+ return (
98
+ <Box component="section" data-testid={testId} sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}>
99
+ <RailHeading>{menu.title}</RailHeading>
100
+ {menu.groups.map((group) => (
101
+ <Box key={group.id} sx={{ display: 'flex', flexDirection: 'column', gap: 0.25 }}>
102
+ {group.title ? (
103
+ <Typography variant="caption" color="text.secondary" sx={{ px: 1.25, pt: 0.5 }}>
104
+ {group.title}
105
+ </Typography>
106
+ ) : null}
107
+ {group.entries.map((entry) => (
108
+ <RailRow
109
+ key={entry.id}
110
+ label={entry.label}
111
+ description={entry.description}
112
+ icon={entry.icon}
113
+ count={entry.badge}
114
+ active={entry.active === true}
115
+ copy={copy}
116
+ testId={`${testId}-entry-${entry.id}`}
117
+ control={controlProps({ href: entry.href, linkComponent, onClick: () => entry.onSelect?.() })}
118
+ />
119
+ ))}
120
+ </Box>
121
+ ))}
122
+ </Box>
123
+ );
124
+ }
125
+
126
+ /**
127
+ * The wide-screen layout: a vertical rail — the way back, the destinations,
128
+ * then every menu's entries.
129
+ *
130
+ * It fills the column the host gives it and scrolls on its own, like the
131
+ * sidebar it stands in for.
132
+ */
133
+ export function SectionNavRail({
134
+ label,
135
+ destinations,
136
+ primary,
137
+ more,
138
+ back,
139
+ heading,
140
+ linkComponent,
141
+ copy,
142
+ dataTestId,
143
+ }: Required<Pick<SectionNavProps, 'label' | 'destinations' | 'copy' | 'dataTestId'>> &
144
+ Pick<SectionNavProps, 'primary' | 'more' | 'back' | 'heading'> & {
145
+ linkComponent: ElementType | undefined;
146
+ }): React.JSX.Element {
147
+ const theme = useTheme();
148
+ return (
149
+ <Box
150
+ component="nav"
151
+ aria-label={label}
152
+ data-testid={dataTestId}
153
+ sx={{
154
+ display: 'flex',
155
+ flexDirection: 'column',
156
+ gap: 0.25,
157
+ height: '100%',
158
+ overflowY: 'auto',
159
+ px: 1,
160
+ py: 1.5,
161
+ bgcolor: 'background.paper',
162
+ }}
163
+ >
164
+ {back ? (
165
+ <Box
166
+ {...controlProps({ href: back.href, linkComponent })}
167
+ data-testid={`${dataTestId}-back`}
168
+ sx={{
169
+ ...CONTROL_RESET,
170
+ ...focusRing(theme),
171
+ display: 'flex',
172
+ alignItems: 'center',
173
+ gap: 1,
174
+ px: 1.25,
175
+ py: 0.75,
176
+ mb: 0.5,
177
+ borderRadius: 1,
178
+ color: 'text.secondary',
179
+ '&:hover': { bgcolor: 'action.hover', color: 'text.primary' },
180
+ '& svg': { fontSize: rem(theme, 20) },
181
+ }}
182
+ >
183
+ {back.icon}
184
+ <Typography component="span" variant="body2" sx={{ fontWeight: 600 }}>
185
+ {back.label}
186
+ </Typography>
187
+ </Box>
188
+ ) : null}
189
+ {heading ? <RailHeading>{heading}</RailHeading> : null}
190
+ {destinations.map((destination) => (
191
+ <RailRow
192
+ key={destination.id}
193
+ label={destination.label}
194
+ icon={destination.icon}
195
+ count={destination.badge}
196
+ active={destination.active === true}
197
+ copy={copy}
198
+ testId={`${dataTestId}-dest-${destination.id}`}
199
+ control={controlProps({ href: destination.href, linkComponent })}
200
+ />
201
+ ))}
202
+ {primary ? (
203
+ <RailMenu menu={primary} linkComponent={linkComponent} copy={copy} testId={`${dataTestId}-primary`} />
204
+ ) : null}
205
+ {more ? <RailMenu menu={more} linkComponent={linkComponent} copy={copy} testId={`${dataTestId}-more`} /> : null}
206
+ </Box>
207
+ );
208
+ }
@@ -0,0 +1,206 @@
1
+ import Typography from '@mui/material/Typography/index.js';
2
+ import { useTheme } from '@mui/material/styles/index.js';
3
+ import type { ElementType } from 'react';
4
+
5
+ import { rem } from '../../../tokens/scales';
6
+ import { Drawer, DrawerContent, DrawerHeader } from '../../layout/Drawer';
7
+
8
+ import { Box, CONTROL_RESET, CountedIcon, controlProps, focusRing } from './SectionNav.parts';
9
+ import type { SectionNavEntry, SectionNavGroup, SectionNavMenu } from './SectionNav.types';
10
+ import type { SectionNavCopy } from '../../../copy';
11
+
12
+ interface EntryProps {
13
+ entry: SectionNavEntry;
14
+ linkComponent: ElementType | undefined;
15
+ copy: SectionNavCopy;
16
+ testId: string;
17
+ onDone: () => void;
18
+ }
19
+
20
+ /** A tile in a `grid` group: icon over a short label. */
21
+ function GridEntry({ entry, linkComponent, copy, testId, onDone }: EntryProps): React.JSX.Element {
22
+ const theme = useTheme();
23
+ return (
24
+ <Box
25
+ {...controlProps({
26
+ href: entry.href,
27
+ linkComponent,
28
+ onClick: () => {
29
+ entry.onSelect?.();
30
+ onDone();
31
+ },
32
+ })}
33
+ aria-current={entry.active ? 'page' : undefined}
34
+ data-testid={`${testId}-entry-${entry.id}`}
35
+ sx={{
36
+ ...CONTROL_RESET,
37
+ ...focusRing(theme),
38
+ display: 'flex',
39
+ flexDirection: 'column',
40
+ alignItems: 'center',
41
+ justifyContent: 'center',
42
+ gap: 0.75,
43
+ minHeight: rem(theme, 76),
44
+ px: 0.5,
45
+ py: 1,
46
+ borderRadius: 1.5,
47
+ textAlign: 'center',
48
+ bgcolor: entry.active ? 'action.selected' : 'action.hover',
49
+ color: entry.active ? 'primary.main' : 'text.primary',
50
+ '& svg': { color: 'primary.main' },
51
+ }}
52
+ >
53
+ <CountedIcon icon={entry.icon} count={entry.badge} label={copy.badge} testId={`${testId}-badge-${entry.id}`} />
54
+ <Typography component="span" variant="caption" sx={{ lineHeight: 1.2, fontWeight: entry.active ? 700 : 500 }}>
55
+ {entry.label}
56
+ </Typography>
57
+ </Box>
58
+ );
59
+ }
60
+
61
+ /** A row in a `list` group: icon, label, and the description under it. */
62
+ function ListEntry({ entry, linkComponent, copy, testId, onDone }: EntryProps): React.JSX.Element {
63
+ const theme = useTheme();
64
+ return (
65
+ <Box
66
+ {...controlProps({
67
+ href: entry.href,
68
+ linkComponent,
69
+ onClick: () => {
70
+ entry.onSelect?.();
71
+ onDone();
72
+ },
73
+ })}
74
+ aria-current={entry.active ? 'page' : undefined}
75
+ data-testid={`${testId}-entry-${entry.id}`}
76
+ sx={{
77
+ ...CONTROL_RESET,
78
+ ...focusRing(theme),
79
+ display: 'flex',
80
+ alignItems: 'center',
81
+ gap: 1.5,
82
+ width: '100%',
83
+ minHeight: rem(theme, 52),
84
+ px: 1.5,
85
+ py: 1,
86
+ borderRadius: 1.5,
87
+ textAlign: 'start',
88
+ bgcolor: entry.active ? 'action.selected' : 'action.hover',
89
+ '& svg': { color: 'primary.main' },
90
+ }}
91
+ >
92
+ <CountedIcon icon={entry.icon} count={entry.badge} label={copy.badge} testId={`${testId}-badge-${entry.id}`} />
93
+ <Box component="span" sx={{ display: 'flex', flexDirection: 'column', minWidth: 0 }}>
94
+ <Typography component="span" variant="body2" sx={{ fontWeight: 600 }}>
95
+ {entry.label}
96
+ </Typography>
97
+ {entry.description ? (
98
+ <Typography component="span" variant="caption" color="text.secondary">
99
+ {entry.description}
100
+ </Typography>
101
+ ) : null}
102
+ </Box>
103
+ </Box>
104
+ );
105
+ }
106
+
107
+ /** One titled run of entries, as tiles or rows. */
108
+ function SheetGroup({
109
+ group,
110
+ linkComponent,
111
+ copy,
112
+ testId,
113
+ onDone,
114
+ }: Omit<EntryProps, 'entry'> & { group: SectionNavGroup }): React.JSX.Element {
115
+ const grid = group.layout === 'grid';
116
+ const Entry = grid ? GridEntry : ListEntry;
117
+ return (
118
+ <Box component="section" data-testid={`${testId}-group-${group.id}`} sx={{ display: 'flex', flexDirection: 'column', gap: 1 }}>
119
+ {group.title ? (
120
+ <Typography variant="overline" color="text.secondary" sx={{ lineHeight: 1.6 }}>
121
+ {group.title}
122
+ </Typography>
123
+ ) : null}
124
+ <Box
125
+ sx={
126
+ grid
127
+ ? { display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 1 }
128
+ : { display: 'flex', flexDirection: 'column', gap: 0.75 }
129
+ }
130
+ >
131
+ {group.entries.map((entry) => (
132
+ <Entry key={entry.id} entry={entry} linkComponent={linkComponent} copy={copy} testId={testId} onDone={onDone} />
133
+ ))}
134
+ </Box>
135
+ </Box>
136
+ );
137
+ }
138
+
139
+ /**
140
+ * A menu opened from the bar: a bottom sheet over the page.
141
+ *
142
+ * Choosing an entry closes it — a link has somewhere to go and an action has
143
+ * something to do, and neither wants the sheet still covering the screen.
144
+ */
145
+ export function SectionNavSheet({
146
+ menu,
147
+ open,
148
+ onClose,
149
+ linkComponent,
150
+ copy,
151
+ testId,
152
+ bottomOffset,
153
+ }: {
154
+ menu: SectionNavMenu;
155
+ open: boolean;
156
+ onClose: () => void;
157
+ linkComponent: ElementType | undefined;
158
+ copy: SectionNavCopy;
159
+ testId: string;
160
+ /** How far above the viewport's foot the sheet stops — the bar's own height, so the bar stays visible. */
161
+ bottomOffset: string;
162
+ }): React.JSX.Element {
163
+ const theme = useTheme();
164
+ return (
165
+ <Drawer
166
+ open={open}
167
+ onClose={onClose}
168
+ anchor="bottom"
169
+ height="auto"
170
+ dataTestId={testId}
171
+ paperSx={{
172
+ borderTopLeftRadius: rem(theme, Number(theme.shape.borderRadius) * 3),
173
+ borderTopRightRadius: rem(theme, Number(theme.shape.borderRadius) * 3),
174
+ maxHeight: `calc(85dvh - ${bottomOffset})`,
175
+ bottom: bottomOffset,
176
+ }}
177
+ >
178
+ {/* The library Drawer names nothing: the dialog role and its name live
179
+ here, around everything the focus trap holds. */}
180
+ <Box
181
+ role="dialog"
182
+ aria-modal="true"
183
+ aria-label={menu.title}
184
+ sx={{ display: 'flex', flexDirection: 'column', flex: 1, minHeight: 0 }}
185
+ >
186
+ <DrawerHeader onClose={onClose} closeLabel={copy.close} dataTestId={`${testId}-header`}>
187
+ {menu.title}
188
+ </DrawerHeader>
189
+ <DrawerContent>
190
+ <Box sx={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
191
+ {menu.groups.map((group) => (
192
+ <SheetGroup
193
+ key={group.id}
194
+ group={group}
195
+ linkComponent={linkComponent}
196
+ copy={copy}
197
+ testId={testId}
198
+ onDone={onClose}
199
+ />
200
+ ))}
201
+ </Box>
202
+ </DrawerContent>
203
+ </Box>
204
+ </Drawer>
205
+ );
206
+ }
@@ -0,0 +1,56 @@
1
+ import { SectionNavBar } from './SectionNav.bar';
2
+ import { SectionNavRail } from './SectionNav.rail';
3
+ import type { SectionNavProps } from './SectionNav.types';
4
+
5
+ /**
6
+ * A section's own navigation — the handful of screens one kind of work moves
7
+ * between — as a bottom bar on a phone or a rail on a wide screen.
8
+ *
9
+ * It knows no product. The host decides every destination, label, icon,
10
+ * count and which one is current, and renders links through its own router
11
+ * (`linkComponent`). The nav decides only how they are drawn: the order of the
12
+ * bar's slots, the raised primary action, the sheets, the rail's sections.
13
+ *
14
+ * Which layout to use is the host's call too, because the host knows what
15
+ * else is on screen: a bar next to a sidebar is two navigations competing for
16
+ * one glance.
17
+ */
18
+ export function SectionNav({
19
+ layout,
20
+ label,
21
+ destinations,
22
+ primary,
23
+ more,
24
+ back,
25
+ heading,
26
+ linkComponent,
27
+ copy,
28
+ dataTestId = 'section-nav',
29
+ }: SectionNavProps): React.JSX.Element {
30
+ if (layout === 'rail') {
31
+ return (
32
+ <SectionNavRail
33
+ label={label}
34
+ destinations={destinations}
35
+ primary={primary}
36
+ more={more}
37
+ back={back}
38
+ heading={heading}
39
+ linkComponent={linkComponent}
40
+ copy={copy}
41
+ dataTestId={dataTestId}
42
+ />
43
+ );
44
+ }
45
+ return (
46
+ <SectionNavBar
47
+ label={label}
48
+ destinations={destinations}
49
+ primary={primary}
50
+ more={more}
51
+ linkComponent={linkComponent}
52
+ copy={copy}
53
+ dataTestId={dataTestId}
54
+ />
55
+ );
56
+ }
@@ -0,0 +1,108 @@
1
+ import type { ElementType, ReactNode } from 'react';
2
+
3
+ import type { SectionNavCopy } from '../../../copy';
4
+
5
+ /**
6
+ * One place the section leads to — a bar slot on a phone, a row in the rail.
7
+ */
8
+ export interface SectionNavDestination {
9
+ /** Stable key. Also the suffix of the slot's `data-testid`. */
10
+ id: string;
11
+ label: string;
12
+ icon: ReactNode;
13
+ href: string;
14
+ /**
15
+ * How many things behind this destination wait on the viewer. `0` and
16
+ * `undefined` render no badge — "nothing waiting" and "not known yet" are
17
+ * different claims and neither is a number.
18
+ */
19
+ badge?: number;
20
+ /** The destination the viewer is on. The host decides; the nav never reads the URL. */
21
+ active?: boolean;
22
+ }
23
+
24
+ /**
25
+ * One entry inside a menu — a sheet tile on a phone, a row in the rail.
26
+ *
27
+ * An entry either LEADS somewhere (`href`, rendered through `linkComponent`)
28
+ * or DOES something (`onSelect`). Give it one or the other.
29
+ */
30
+ export interface SectionNavEntry {
31
+ id: string;
32
+ label: string;
33
+ /** A second line under the label. Shown by `list` groups and in the rail. */
34
+ description?: string;
35
+ icon: ReactNode;
36
+ href?: string;
37
+ onSelect?: () => void;
38
+ badge?: number;
39
+ active?: boolean;
40
+ }
41
+
42
+ /** A titled run of entries inside a menu. */
43
+ export interface SectionNavGroup {
44
+ id: string;
45
+ /** Heading above the entries. Omit for a group that needs none. */
46
+ title?: string;
47
+ /**
48
+ * How the phone sheet draws the entries: `grid` is three tiles across,
49
+ * `list` one row each with its description. The rail always lists.
50
+ * Defaults to `list`.
51
+ */
52
+ layout?: 'grid' | 'list';
53
+ entries: SectionNavEntry[];
54
+ }
55
+
56
+ /**
57
+ * A menu the nav opens: the centred primary action, or the "more" slot.
58
+ *
59
+ * On a phone it opens as a bottom sheet over the page. In the rail there is
60
+ * room for everything, so its groups are listed under `title` instead of
61
+ * hiding behind a trigger.
62
+ */
63
+ export interface SectionNavMenu {
64
+ /** The trigger's accessible name, and the visible label of the "more" slot. */
65
+ label: string;
66
+ icon: ReactNode;
67
+ /** The sheet's heading, and the rail section's. */
68
+ title: string;
69
+ groups: SectionNavGroup[];
70
+ }
71
+
72
+ /** The way out of the section, drawn at the top of the rail. */
73
+ export interface SectionNavBack {
74
+ label: string;
75
+ href: string;
76
+ icon?: ReactNode;
77
+ }
78
+
79
+ export interface SectionNavProps {
80
+ /**
81
+ * `bar` — a bottom tab bar for a phone: the destinations, `more` as the last
82
+ * slot, and `primary` as a raised button in the middle.
83
+ *
84
+ * `rail` — a vertical list for a wide screen, with `back` and `heading` on
85
+ * top and every menu's entries listed rather than folded away.
86
+ */
87
+ layout: 'bar' | 'rail';
88
+ /** The navigation landmark's accessible name. */
89
+ label: string;
90
+ destinations: SectionNavDestination[];
91
+ /** The raised action in the middle of the bar. */
92
+ primary?: SectionNavMenu;
93
+ /** The last slot of the bar. Its badge is the sum of its entries' badges. */
94
+ more?: SectionNavMenu;
95
+ /** Rail only: the way back out of the section. */
96
+ back?: SectionNavBack;
97
+ /** Rail only: a heading above the destinations. */
98
+ heading?: string;
99
+ /**
100
+ * The component every `href` renders through — a router's link adapter that
101
+ * takes `href`. Omitted, a plain `<a>` is used and navigation reloads.
102
+ */
103
+ linkComponent?: ElementType;
104
+ /** The nav's own words. REQUIRED — the component carries none. */
105
+ copy: SectionNavCopy;
106
+ /** Prefix for every `data-testid`. Defaults to `"section-nav"`. */
107
+ dataTestId?: string;
108
+ }
@@ -0,0 +1,111 @@
1
+ import AddIcon from '@mui/icons-material/Add';
2
+ import AppsIcon from '@mui/icons-material/Apps';
3
+ import CalendarMonthOutlinedIcon from '@mui/icons-material/CalendarMonthOutlined';
4
+ import DashboardOutlinedIcon from '@mui/icons-material/DashboardOutlined';
5
+ import DeliveryDiningOutlinedIcon from '@mui/icons-material/DeliveryDiningOutlined';
6
+ import GridViewOutlinedIcon from '@mui/icons-material/GridViewOutlined';
7
+ import GroupsOutlinedIcon from '@mui/icons-material/GroupsOutlined';
8
+ import PauseCircleOutlineIcon from '@mui/icons-material/PauseCircleOutline';
9
+ import ReceiptLongOutlinedIcon from '@mui/icons-material/ReceiptLongOutlined';
10
+ import RoomServiceOutlinedIcon from '@mui/icons-material/RoomServiceOutlined';
11
+ import ShoppingBagOutlinedIcon from '@mui/icons-material/ShoppingBagOutlined';
12
+ import StorefrontOutlinedIcon from '@mui/icons-material/StorefrontOutlined';
13
+ import TableRestaurantOutlinedIcon from '@mui/icons-material/TableRestaurantOutlined';
14
+ import Box from '@mui/material/Box/index.js';
15
+ import React from 'react';
16
+
17
+ import { sxRem } from '../../../../tokens/scales';
18
+
19
+ import type { SectionNavDestination, SectionNavMenu } from '../SectionNav.types';
20
+
21
+ /**
22
+ * The stories' example section, shared by the showcase and the interaction
23
+ * tests. Kept out of the `*.stories.tsx` files because Storybook reads every
24
+ * named export there as a story.
25
+ */
26
+
27
+ /** A restaurant's shift, as the example section: the floor, the board, the waiter's round. */
28
+ export const DESTINATIONS: SectionNavDestination[] = [
29
+ { id: 'floor', label: 'Floor', icon: <GridViewOutlinedIcon />, href: '#floor' },
30
+ { id: 'board', label: 'Board', icon: <DashboardOutlinedIcon />, href: '#board', badge: 3, active: true },
31
+ { id: 'serve', label: 'Serve', icon: <TableRestaurantOutlinedIcon />, href: '#serve', badge: 2 },
32
+ ];
33
+
34
+ export const PRIMARY: SectionNavMenu = {
35
+ label: 'Create',
36
+ icon: <AddIcon />,
37
+ title: 'Create now',
38
+ groups: [
39
+ {
40
+ id: 'order',
41
+ title: 'New order',
42
+ layout: 'grid',
43
+ entries: [
44
+ { id: 'delivery', label: 'Delivery', icon: <DeliveryDiningOutlinedIcon />, onSelect: () => undefined },
45
+ { id: 'pickup', label: 'Pickup', icon: <ShoppingBagOutlinedIcon />, onSelect: () => undefined },
46
+ { id: 'counter', label: 'Counter', icon: <StorefrontOutlinedIcon />, onSelect: () => undefined },
47
+ ],
48
+ },
49
+ {
50
+ id: 'menu',
51
+ title: 'Menu',
52
+ entries: [
53
+ {
54
+ id: 'pause',
55
+ label: 'Pause an item',
56
+ description: 'Take it off sale until it is back',
57
+ icon: <PauseCircleOutlineIcon />,
58
+ onSelect: () => undefined,
59
+ },
60
+ ],
61
+ },
62
+ ],
63
+ };
64
+
65
+ export const MORE: SectionNavMenu = {
66
+ label: 'More',
67
+ icon: <AppsIcon />,
68
+ title: 'More',
69
+ groups: [
70
+ {
71
+ id: 'rest',
72
+ layout: 'grid',
73
+ entries: [
74
+ { id: 'queue', label: 'Queue', icon: <GroupsOutlinedIcon />, href: '#queue', badge: 1 },
75
+ { id: 'pass', label: 'Pass', icon: <RoomServiceOutlinedIcon />, href: '#pass' },
76
+ { id: 'runs', label: 'Deliveries', icon: <DeliveryDiningOutlinedIcon />, href: '#runs' },
77
+ { id: 'booked', label: 'Bookings', icon: <CalendarMonthOutlinedIcon />, href: '#booked' },
78
+ { id: 'orders', label: 'Orders', icon: <ReceiptLongOutlinedIcon />, href: '#orders' },
79
+ ],
80
+ },
81
+ ],
82
+ };
83
+
84
+ /** A phone-sized frame with the bar at its foot, the way a host docks it. */
85
+ export function PhoneFrame({ children }: { children: React.ReactNode }): React.ReactElement {
86
+ return (
87
+ <Box
88
+ sx={{
89
+ width: sxRem(360),
90
+ maxWidth: '100%',
91
+ height: sxRem(640),
92
+ display: 'flex',
93
+ flexDirection: 'column',
94
+ border: 1,
95
+ borderColor: 'divider',
96
+ borderRadius: 3,
97
+ overflow: 'hidden',
98
+ bgcolor: 'background.default',
99
+ }}
100
+ >
101
+ <Box sx={{ flex: 1, p: 2 }} />
102
+ {children}
103
+ </Box>
104
+ );
105
+ }
106
+
107
+
108
+ /** A desktop-column-sized frame for the rail. */
109
+ export function RailFrame({ children }: { children: React.ReactNode }): React.ReactElement {
110
+ return <Box sx={{ width: sxRem(240), height: sxRem(560), border: 1, borderColor: 'divider' }}>{children}</Box>;
111
+ }