@12-apps/ui 6.26.0 → 6.27.1

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 (493) hide show
  1. package/dist/_internal/components/data-display/Alert/Alert.js +4 -4
  2. package/dist/_internal/components/data-display/Alert/Alert.metrics.js +2 -2
  3. package/dist/_internal/components/data-display/Alert/Alert.styles.js +3 -3
  4. package/dist/_internal/components/data-display/Avatar/Avatar.js +3 -3
  5. package/dist/_internal/components/data-display/Avatar/Avatar.view.js +2 -2
  6. package/dist/_internal/components/data-display/Badge/Badge.animations.js +3 -3
  7. package/dist/_internal/components/data-display/Badge/Badge.js +7 -7
  8. package/dist/_internal/components/data-display/Badge/Badge.metrics.js +2 -2
  9. package/dist/_internal/components/data-display/Badge/Badge.styles.js +5 -5
  10. package/dist/_internal/components/data-display/Badge/Badge.variants.js +3 -3
  11. package/dist/_internal/components/data-display/Badge/BadgeContent.js +6 -6
  12. package/dist/_internal/components/data-display/Banner/Banner.js +4 -4
  13. package/dist/_internal/components/data-display/Banner/Banner.styles.js +3 -3
  14. package/dist/_internal/components/data-display/CardKit/CardKebab.js +4 -4
  15. package/dist/_internal/components/data-display/CardKit/card-actions-context.js +5 -5
  16. package/dist/_internal/components/data-display/CardKit/use-remove-confirm.js +9 -9
  17. package/dist/_internal/components/data-display/CardKit/use-row-confirm.js +4 -4
  18. package/dist/_internal/components/data-display/Carousel/Carousel.chrome.js +1 -1
  19. package/dist/_internal/components/data-display/Carousel/Carousel.js +1 -1
  20. package/dist/_internal/components/data-display/Carousel/Carousel.parts.js +1 -1
  21. package/dist/_internal/components/data-display/Carousel/Carousel.styles.js +1 -1
  22. package/dist/_internal/components/data-display/Chart/Chart.js +5 -5
  23. package/dist/_internal/components/data-display/Chart/SpecChart.js +6 -6
  24. package/dist/_internal/components/data-display/Chart/chart-context.js +3 -3
  25. package/dist/_internal/components/data-display/Chart/chart-internals.js +1 -1
  26. package/dist/_internal/components/data-display/Chart/chart-renderers.js +4 -4
  27. package/dist/_internal/components/data-display/DataViews/DataViewsBoard.js +4 -4
  28. package/dist/_internal/components/data-display/DataViews/DataViewsGrid.js +37 -37
  29. package/dist/_internal/components/data-display/DataViews/DataViewsTableBase.js +54 -53
  30. package/dist/_internal/components/data-display/DataViews/DeleteViewDialog.js +6 -6
  31. package/dist/_internal/components/data-display/DataViews/ManageViewsDialog.js +7 -7
  32. package/dist/_internal/components/data-display/DataViews/SaveViewModal.js +12 -11
  33. package/dist/_internal/components/data-display/DataViews/base-card.js +9 -9
  34. package/dist/_internal/components/data-display/DataViews/base-list-card-geometry.js +12 -12
  35. package/dist/_internal/components/data-display/DataViews/base-list-card-gutters.js +3 -3
  36. package/dist/_internal/components/data-display/DataViews/base-list-card-slots.js +8 -8
  37. package/dist/_internal/components/data-display/DataViews/base-list-card.js +16 -16
  38. package/dist/_internal/components/data-display/DataViews/card-surface.js +4 -4
  39. package/dist/_internal/components/data-display/DataViews/data-views-category-pill.js +5 -5
  40. package/dist/_internal/components/data-display/DataViews/data-views-columns-tab.js +4 -4
  41. package/dist/_internal/components/data-display/DataViews/data-views-columns.js +5 -5
  42. package/dist/_internal/components/data-display/DataViews/data-views-display-panel.js +11 -11
  43. package/dist/_internal/components/data-display/DataViews/data-views-display-tabs.js +6 -6
  44. package/dist/_internal/components/data-display/DataViews/data-views-empty.js +6 -6
  45. package/dist/_internal/components/data-display/DataViews/data-views-export.js +6 -6
  46. package/dist/_internal/components/data-display/DataViews/data-views-filter-panel.js +6 -6
  47. package/dist/_internal/components/data-display/DataViews/data-views-grid-bodies.js +12 -12
  48. package/dist/_internal/components/data-display/DataViews/data-views-grid-helpers.js +4 -4
  49. package/dist/_internal/components/data-display/DataViews/data-views-grid-parts.js +34 -34
  50. package/dist/_internal/components/data-display/DataViews/data-views-header-row.js +4 -4
  51. package/dist/_internal/components/data-display/DataViews/data-views-inline-bar.js +13 -13
  52. package/dist/_internal/components/data-display/DataViews/data-views-layout-context.js +2 -2
  53. package/dist/_internal/components/data-display/DataViews/data-views-more-fields.js +4 -4
  54. package/dist/_internal/components/data-display/DataViews/data-views-more-filters.js +7 -7
  55. package/dist/_internal/components/data-display/DataViews/data-views-scope-tabs.js +3 -3
  56. package/dist/_internal/components/data-display/DataViews/data-views-select-all-strip.js +6 -6
  57. package/dist/_internal/components/data-display/DataViews/data-views-shell-toolbar.js +15 -15
  58. package/dist/_internal/components/data-display/DataViews/data-views-table-parts.js +18 -17
  59. package/dist/_internal/components/data-display/DataViews/data-views-toolbar.js +14 -14
  60. package/dist/_internal/components/data-display/DataViews/data-views-view-nav.js +6 -6
  61. package/dist/_internal/components/data-display/DataViews/list-card-rails.js +3 -3
  62. package/dist/_internal/components/data-display/DataViews/save-view-preview.js +4 -4
  63. package/dist/_internal/components/data-display/DataViews/use-data-views-state.js +7 -7
  64. package/dist/_internal/components/data-display/DataViews/use-saved-views-controller.js +2 -2
  65. package/dist/_internal/components/data-display/DescriptionItem/DescriptionItem.js +4 -4
  66. package/dist/_internal/components/data-display/FleetMap/FleetBody.js +11 -11
  67. package/dist/_internal/components/data-display/FleetMap/FleetCanvas.js +8 -8
  68. package/dist/_internal/components/data-display/FleetMap/FleetMap.js +13 -13
  69. package/dist/_internal/components/data-display/FleetMap/FleetRoster.js +2 -2
  70. package/dist/_internal/components/data-display/Lightbox/Lightbox.js +1 -1
  71. package/dist/_internal/components/data-display/MapPreview/MapDecorations.js +2 -2
  72. package/dist/_internal/components/data-display/MapPreview/MapPreview.hooks.js +2 -2
  73. package/dist/_internal/components/data-display/MapPreview/MapPreview.js +7 -7
  74. package/dist/_internal/components/data-display/MapPreview/MapTiles.js +2 -2
  75. package/dist/_internal/components/data-display/MapPreview/StaticMapView.js +4 -4
  76. package/dist/_internal/components/data-display/MapPreview/useMapPreview.js +3 -3
  77. package/dist/_internal/components/data-display/Progress/Progress.js +4 -4
  78. package/dist/_internal/components/data-display/Progress/Progress.metrics.js +2 -2
  79. package/dist/_internal/components/data-display/Progress/Progress.styles.js +3 -3
  80. package/dist/_internal/components/data-display/Sheet/Sheet.body.js +1 -1
  81. package/dist/_internal/components/data-display/Sheet/Sheet.js +4 -4
  82. package/dist/_internal/components/data-display/Sheet/Sheet.styles.js +1 -1
  83. package/dist/_internal/components/data-display/Table/Table.js +2 -2
  84. package/dist/_internal/components/data-display/index.js +43 -43
  85. package/dist/_internal/components/feedback/ConfirmAction/ConfirmButton.js +4 -4
  86. package/dist/_internal/components/feedback/index.js +4 -4
  87. package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.hooks.js +2 -2
  88. package/dist/_internal/components/form/AddressAutocomplete/AddressAutocomplete.js +5 -5
  89. package/dist/_internal/components/form/Autocomplete/Autocomplete.js +2 -2
  90. package/dist/_internal/components/form/Button/Button.js +3 -3
  91. package/dist/_internal/components/form/Button/Button.styles.js +2 -2
  92. package/dist/_internal/components/form/Calendar/Calendar.hooks.js +2 -2
  93. package/dist/_internal/components/form/Calendar/Calendar.js +3 -3
  94. package/dist/_internal/components/form/CategorySelect/CategoryPanel.js +1 -1
  95. package/dist/_internal/components/form/CategorySelect/CategorySelect.js +4 -4
  96. package/dist/_internal/components/form/Checkbox/Checkbox.js +2 -2
  97. package/dist/_internal/components/form/Command/Command.js +4 -4
  98. package/dist/_internal/components/form/Command/Command.styles.js +1 -1
  99. package/dist/_internal/components/form/DateRangePicker/DateRangePicker.js +5 -5
  100. package/dist/_internal/components/form/Label/Label.js +1 -1
  101. package/dist/_internal/components/form/Label/Label.styles.js +1 -1
  102. package/dist/_internal/components/form/Menubar/Menubar.item.js +1 -1
  103. package/dist/_internal/components/form/Menubar/Menubar.js +1 -1
  104. package/dist/_internal/components/form/Menubar/Menubar.styles.js +1 -1
  105. package/dist/_internal/components/form/Menubar/Menubar.toolbar.js +1 -1
  106. package/dist/_internal/components/form/PhoneInput/PhoneInput.hooks.js +2 -2
  107. package/dist/_internal/components/form/PhoneInput/PhoneInput.js +3 -3
  108. package/dist/_internal/components/form/RichTextEditor/RichTextEditor.js +2 -2
  109. package/dist/_internal/components/form/Switch/Switch.ids.js +8 -0
  110. package/dist/_internal/components/form/Switch/Switch.ids.js.map +1 -0
  111. package/dist/_internal/components/form/Switch/Switch.js +6 -5
  112. package/dist/_internal/components/form/Switch/Switch.metrics.js +5 -1
  113. package/dist/_internal/components/form/Switch/Switch.parts.js +6 -8
  114. package/dist/_internal/components/form/Switch/Switch.styles.js +5 -3
  115. package/dist/_internal/components/form/index.js +34 -33
  116. package/dist/_internal/components/form/total-form/Fields/CategoryField.js +5 -5
  117. package/dist/_internal/components/form/total-form/Fields/index.js +6 -6
  118. package/dist/_internal/components/form/total-form/SubmitButton.js +4 -4
  119. package/dist/_internal/components/index.js +83 -82
  120. package/dist/_internal/components/layout/Box/Box.js +4 -4
  121. package/dist/_internal/components/layout/Stack/Stack.js +5 -5
  122. package/dist/_internal/components/navigation/AppHeader/AppHeader.details.js +7 -7
  123. package/dist/_internal/components/navigation/AppHeader/AppHeader.identity.js +1 -1
  124. package/dist/_internal/components/navigation/Tabs/Tabs.js +1 -1
  125. package/dist/_internal/components/navigation/index.js +8 -8
  126. package/dist/_internal/components/typography/Heading/Heading.js +4 -4
  127. package/dist/_internal/components/typography/Heading/Heading.metrics.js +2 -2
  128. package/dist/_internal/components/typography/Heading/Heading.styles.js +3 -3
  129. package/dist/_internal/components/typography/Paragraph/Paragraph.js +2 -2
  130. package/dist/_internal/components/typography/Text/Text.js +3 -3
  131. package/dist/_internal/components/typography/Text/Text.metrics.js +2 -2
  132. package/dist/_internal/components/typography/index.js +7 -7
  133. package/dist/_internal/icons/Icon.js +4 -4
  134. package/dist/_internal/provider/UiProvider.js +3 -3
  135. package/dist/_internal/provider/mui-bridge.js +2 -2
  136. package/dist/_internal/provider/use-ui-theme.js +3 -3
  137. package/dist/_internal/social-login-button/social-login-button.js +9 -9
  138. package/dist/_internal/tokens/theme.js +3 -1
  139. package/dist/_internal/user-avatar/user-avatar.js +8 -8
  140. package/dist/charts.js +6 -6
  141. package/dist/{chunk-2GI7ANEL.js → chunk-22X7TT6Z.js} +4 -4
  142. package/dist/{chunk-WR5JFDQ5.js → chunk-27BL3DNT.js} +8 -8
  143. package/dist/{chunk-E55CJV65.js → chunk-2KVQIGVE.js} +2 -2
  144. package/dist/{chunk-BB2OUERT.js → chunk-2LSCK45B.js} +7 -4
  145. package/dist/chunk-2LSCK45B.js.map +1 -0
  146. package/dist/{chunk-W3FAKT3D.js → chunk-2SWQ6HIK.js} +4 -4
  147. package/dist/{chunk-ISW5K72V.js → chunk-2ZRZTGWP.js} +5 -5
  148. package/dist/{chunk-I5SBTNV2.js → chunk-3GB6KWHH.js} +2 -2
  149. package/dist/{chunk-ZEG2LNBY.js → chunk-3PJLT5FX.js} +2 -2
  150. package/dist/{chunk-CXLAJZSE.js → chunk-3VZT2FAI.js} +3 -3
  151. package/dist/{chunk-MLCFODJO.js → chunk-3W2IS5RH.js} +5 -1
  152. package/dist/{chunk-MLCFODJO.js.map → chunk-3W2IS5RH.js.map} +1 -1
  153. package/dist/{chunk-PFDM2OIP.js → chunk-45OHGD2B.js} +4 -4
  154. package/dist/{chunk-BH5BXLGI.js → chunk-4A2Q22HO.js} +3 -3
  155. package/dist/{chunk-46UPILLK.js → chunk-4ETQRBZC.js} +4 -4
  156. package/dist/{chunk-TWY5FOBY.js → chunk-5QUSX3TC.js} +5 -5
  157. package/dist/{chunk-AVGTTWTE.js → chunk-65DLYC4S.js} +4 -4
  158. package/dist/{chunk-TVPPA4RD.js → chunk-65METCKT.js} +16 -16
  159. package/dist/{chunk-OQFSYMHJ.js → chunk-67ALTEWH.js} +2 -2
  160. package/dist/{chunk-OGGHD64H.js → chunk-6SK3MTYJ.js} +2 -2
  161. package/dist/{chunk-OE2ZVL67.js → chunk-6VHCSPKK.js} +3 -3
  162. package/dist/{chunk-WAPJ2DL3.js → chunk-72T5PAW7.js} +4 -4
  163. package/dist/{chunk-SLVQ33AN.js → chunk-77DF5LKI.js} +2 -2
  164. package/dist/{chunk-7KWBGMQC.js → chunk-77OXG6DH.js} +5 -5
  165. package/dist/{chunk-Y3KRUT7O.js → chunk-7AIHK2XM.js} +2 -2
  166. package/dist/{chunk-MHV5Y5MR.js → chunk-7KEGJH3Q.js} +3 -3
  167. package/dist/{chunk-KMXAPYU2.js → chunk-7NEUPEV5.js} +2 -2
  168. package/dist/{chunk-67L7HMEP.js → chunk-7Z2AQEC5.js} +2 -2
  169. package/dist/{chunk-PQECNGDE.js → chunk-AGYGNNOM.js} +2 -2
  170. package/dist/{chunk-ZTF5C2GA.js → chunk-B5SW7I5W.js} +2 -2
  171. package/dist/{chunk-TXHJX2NG.js → chunk-BGYLL467.js} +4 -4
  172. package/dist/{chunk-R7R3LOKW.js → chunk-CA7TA36R.js} +2 -2
  173. package/dist/{chunk-FPFUXRD2.js → chunk-CKJI7JO5.js} +2 -2
  174. package/dist/{chunk-HMV4QMXS.js → chunk-CMN26J5Y.js} +4 -4
  175. package/dist/{chunk-KVEHH4SA.js → chunk-DB2MAYPK.js} +2 -2
  176. package/dist/{chunk-2ECT4IY2.js → chunk-DIHVWBQV.js} +36 -17
  177. package/dist/chunk-DIHVWBQV.js.map +1 -0
  178. package/dist/{chunk-V4FKHLEB.js → chunk-DTIB5KWP.js} +3 -3
  179. package/dist/{chunk-MESRKY67.js → chunk-DW6GBMLQ.js} +3 -3
  180. package/dist/{chunk-JO6BBSGY.js → chunk-DWJBOR47.js} +3 -3
  181. package/dist/{chunk-YW5T6KZ5.js → chunk-DYESJJ3Q.js} +9 -9
  182. package/dist/{chunk-TZDDL3DR.js → chunk-ECMJ5VPW.js} +2 -2
  183. package/dist/{chunk-OH3YGJT5.js → chunk-EMNGIYH6.js} +5 -5
  184. package/dist/{chunk-CZJLWCEG.js → chunk-EPNCYUQ7.js} +4 -4
  185. package/dist/{chunk-JZXWCEH5.js → chunk-EQA4VQEO.js} +2 -2
  186. package/dist/{chunk-3N6EK6K5.js → chunk-ERX4XIYC.js} +2 -2
  187. package/dist/{chunk-TTLI6PF7.js → chunk-FF3R67WD.js} +5 -5
  188. package/dist/{chunk-4Y6SPFKW.js → chunk-FOF2RAVQ.js} +4 -4
  189. package/dist/{chunk-KLREH4X6.js → chunk-G2JPUHEJ.js} +2 -2
  190. package/dist/{chunk-BBC4KT5G.js → chunk-G76H5PEM.js} +20 -2
  191. package/dist/chunk-G76H5PEM.js.map +1 -0
  192. package/dist/{chunk-4J5EN4FQ.js → chunk-GBX5ACPF.js} +5 -5
  193. package/dist/{chunk-ZZMZF7PZ.js → chunk-GQJ4NCZ6.js} +3 -3
  194. package/dist/{chunk-IPVYEPXO.js → chunk-GSTRPZS4.js} +5 -5
  195. package/dist/{chunk-HFXTAEYY.js → chunk-GTLJYAEG.js} +2 -2
  196. package/dist/{chunk-M4LFDGI6.js → chunk-GYQT47YZ.js} +2 -2
  197. package/dist/{chunk-JSH3HFDQ.js → chunk-H3BQFEN5.js} +2 -2
  198. package/dist/{chunk-OV4WREMW.js → chunk-HKB5C2KY.js} +7 -7
  199. package/dist/{chunk-BLBOYCOV.js → chunk-HKV4MQ2W.js} +5 -5
  200. package/dist/{chunk-4MGFUPQT.js → chunk-HOJL2GKW.js} +4 -4
  201. package/dist/{chunk-HR7YTBR7.js → chunk-IASDP44E.js} +4 -4
  202. package/dist/{chunk-YMRI5QKG.js → chunk-IV5QQLCS.js} +2 -2
  203. package/dist/{chunk-JUHUKZGU.js → chunk-JD3D6Y4U.js} +2 -2
  204. package/dist/{chunk-FR67FG2U.js → chunk-JFRKBSWI.js} +35 -25
  205. package/dist/chunk-JFRKBSWI.js.map +1 -0
  206. package/dist/{chunk-AXTLFK4T.js → chunk-KAV63FBG.js} +2 -2
  207. package/dist/{chunk-2PBGVMM2.js → chunk-KOFO6QZY.js} +2 -2
  208. package/dist/{chunk-RP5FK3SO.js → chunk-L7LCSZ3H.js} +3 -3
  209. package/dist/{chunk-MNXVXW4T.js → chunk-L7S6N67X.js} +2 -2
  210. package/dist/{chunk-JXPHU3K5.js → chunk-LGJ2H4AH.js} +5 -5
  211. package/dist/{chunk-W4YWU7LQ.js → chunk-LO2B7FDQ.js} +2 -2
  212. package/dist/{chunk-PWR7K5OP.js → chunk-LV4UTYAD.js} +2 -2
  213. package/dist/{chunk-OG2FP6SE.js → chunk-M4NFXC5R.js} +4 -4
  214. package/dist/{chunk-ZPIMPOHV.js → chunk-M7E66OSC.js} +4 -4
  215. package/dist/{chunk-OGGPQVIG.js → chunk-MDTSMJ7C.js} +3 -3
  216. package/dist/{chunk-YDI6IJ6F.js → chunk-MI2MVH3I.js} +4 -4
  217. package/dist/{chunk-UIZH4DAE.js → chunk-MQPT254A.js} +4 -4
  218. package/dist/{chunk-EWT3WMVY.js → chunk-MYH7VISV.js} +5 -5
  219. package/dist/{chunk-7NSX7A5H.js → chunk-N5PY7IXI.js} +3 -3
  220. package/dist/{chunk-BHIGHSXA.js → chunk-NNXZ5RK5.js} +4 -4
  221. package/dist/{chunk-EQ7PWGBN.js → chunk-O7HLQTB7.js} +3 -3
  222. package/dist/{chunk-DW5FRWRQ.js → chunk-OAWEUKUC.js} +2 -2
  223. package/dist/{chunk-O4VCZTK4.js → chunk-OGHW7RQC.js} +2 -2
  224. package/dist/{chunk-XR6WBW23.js → chunk-OVGASVPW.js} +2 -2
  225. package/dist/{chunk-HEBQS7QP.js → chunk-OXYR2HVK.js} +3 -3
  226. package/dist/{chunk-TNVO2DTB.js → chunk-P7FQUGED.js} +5 -5
  227. package/dist/{chunk-343TTIHD.js → chunk-PENJBKPH.js} +3 -3
  228. package/dist/{chunk-2RQINU5T.js → chunk-PKFFJAQ6.js} +2 -2
  229. package/dist/{chunk-M4LQRQFL.js → chunk-PW2WLDX3.js} +2 -2
  230. package/dist/{chunk-WRDPWEIC.js → chunk-Q3GSDSK2.js} +6 -6
  231. package/dist/{chunk-VNTOBLIB.js → chunk-Q3OFOOO7.js} +2 -2
  232. package/dist/{chunk-GGI7GM5O.js → chunk-QE2C35TO.js} +4 -4
  233. package/dist/{chunk-NQN5Z36J.js → chunk-QLI7ES7Z.js} +10 -1
  234. package/dist/chunk-QLI7ES7Z.js.map +1 -0
  235. package/dist/{chunk-CT5K725B.js → chunk-QQLGSMGE.js} +2 -2
  236. package/dist/{chunk-7MN6I5NK.js → chunk-QXFPTRHB.js} +3 -3
  237. package/dist/{chunk-CZPU5TW3.js → chunk-RFZU5BTG.js} +2 -2
  238. package/dist/{chunk-JB67KPGM.js → chunk-RRO2EOJB.js} +4 -4
  239. package/dist/{chunk-MZQTHSLN.js → chunk-S7HRED4D.js} +2 -2
  240. package/dist/{chunk-NYEA7JAI.js → chunk-SC72DRTX.js} +6 -6
  241. package/dist/{chunk-JWW2Z3RH.js → chunk-SMZBGHR2.js} +7 -7
  242. package/dist/{chunk-EZSEAYYT.js → chunk-SSWZHR46.js} +5 -5
  243. package/dist/{chunk-NA7MIEG6.js → chunk-SZETT7QV.js} +2 -2
  244. package/dist/chunk-SZS7VZJN.js +25 -0
  245. package/dist/chunk-SZS7VZJN.js.map +1 -0
  246. package/dist/{chunk-2HPP6RVC.js → chunk-TQOPF7LD.js} +2 -2
  247. package/dist/{chunk-OLVZ6TOV.js → chunk-TUO47RL2.js} +4 -4
  248. package/dist/{chunk-N5IVVLTH.js → chunk-UG76BO5K.js} +79 -19
  249. package/dist/chunk-UG76BO5K.js.map +1 -0
  250. package/dist/{chunk-4IVDVZZ2.js → chunk-UGL6SJN6.js} +3 -3
  251. package/dist/{chunk-QJRDDVZ2.js → chunk-V5P5Q6HM.js} +3 -3
  252. package/dist/{chunk-73NJCGQG.js → chunk-VIK3HAUQ.js} +2 -2
  253. package/dist/{chunk-7LCXGJN5.js → chunk-VK4ULJFH.js} +2 -2
  254. package/dist/{chunk-QYNCPS5W.js → chunk-WBKWIFXA.js} +6 -6
  255. package/dist/{chunk-X4Z62ZQY.js → chunk-WETAIIKC.js} +2 -2
  256. package/dist/{chunk-GMTM6EN7.js → chunk-WKF54CCK.js} +7 -7
  257. package/dist/{chunk-KT6HWAEN.js → chunk-WZUNBSS7.js} +2 -2
  258. package/dist/{chunk-Y2B3I3IH.js → chunk-X5RDHO6G.js} +2 -2
  259. package/dist/{chunk-TXKZEKJN.js → chunk-XNOSTV5F.js} +2 -2
  260. package/dist/{chunk-7JXLGOM2.js → chunk-Y55ILY2F.js} +3 -3
  261. package/dist/{chunk-HI2OFZSZ.js → chunk-YPILHGEO.js} +2 -2
  262. package/dist/{chunk-V3PLFYKO.js → chunk-ZAJO2B75.js} +2 -2
  263. package/dist/data-display/Alert.js +4 -4
  264. package/dist/data-display/Avatar.js +3 -3
  265. package/dist/data-display/Badge.js +7 -7
  266. package/dist/data-display/Banner.js +4 -4
  267. package/dist/data-display/CardKit.js +13 -13
  268. package/dist/data-display/Carousel.js +1 -1
  269. package/dist/data-display/Chart.js +6 -6
  270. package/dist/data-display/DataViews.js +68 -67
  271. package/dist/data-display/DescriptionItem.js +4 -4
  272. package/dist/data-display/FleetMap.js +13 -13
  273. package/dist/data-display/Lightbox.js +1 -1
  274. package/dist/data-display/MapPreview.js +7 -7
  275. package/dist/data-display/Progress.js +4 -4
  276. package/dist/data-display/Sheet.js +4 -4
  277. package/dist/data-display/Table.js +2 -2
  278. package/dist/feedback/ConfirmAction.js +4 -4
  279. package/dist/form/AddressAutocomplete.js +5 -5
  280. package/dist/form/Autocomplete.js +2 -2
  281. package/dist/form/Button.js +3 -3
  282. package/dist/form/Calendar.js +3 -3
  283. package/dist/form/CategorySelect.js +4 -4
  284. package/dist/form/Checkbox.js +2 -2
  285. package/dist/form/Command.js +4 -4
  286. package/dist/form/DateRangePicker.js +10 -10
  287. package/dist/form/Label.js +1 -1
  288. package/dist/form/Menubar.js +1 -1
  289. package/dist/form/PhoneInput.js +3 -3
  290. package/dist/form/RichTextEditor.js +2 -2
  291. package/dist/form/Switch.js +6 -5
  292. package/dist/form/total-form.js +10 -10
  293. package/dist/icons.js +4 -4
  294. package/dist/layout/Box.js +4 -4
  295. package/dist/layout/Stack.js +5 -5
  296. package/dist/native/chunks/{chunk-2R2R35C5.js → chunk-2SBTJSQE.js} +5 -5
  297. package/dist/native/chunks/{chunk-WL5LXVCK.js → chunk-6L4UZBQP.js} +3 -3
  298. package/dist/native/chunks/{chunk-LEMMXZFN.js → chunk-MP3UDWTT.js} +10 -1
  299. package/dist/native/chunks/{chunk-LEMMXZFN.js.map → chunk-MP3UDWTT.js.map} +1 -1
  300. package/dist/native/chunks/{chunk-GW7TQ7HO.js → chunk-QEQZ5AF6.js} +3 -3
  301. package/dist/native/chunks/{chunk-7LTVGW23.js → chunk-UII3IFLP.js} +2 -2
  302. package/dist/native/chunks/{chunk-75JQYVDZ.js → chunk-UYREIOEM.js} +2 -2
  303. package/dist/native/chunks/{chunk-GWGIWQO7.js → chunk-XI7HTAVN.js} +2 -2
  304. package/dist/native/chunks/{chunk-QYUD3S6F.js → chunk-ZOP7UAZK.js} +2 -2
  305. package/dist/native/data-display/Alert.js +3 -3
  306. package/dist/native/data-display/Avatar.js +3 -3
  307. package/dist/native/data-display/Badge.js +3 -3
  308. package/dist/native/data-display/Chip.js +3 -3
  309. package/dist/native/data-display/EmptyState.js +5 -5
  310. package/dist/native/data-display/ErrorState.js +4 -4
  311. package/dist/native/data-display/FleetMap.js +6 -6
  312. package/dist/native/data-display/LoadingState.js +2 -2
  313. package/dist/native/data-display/Progress.js +2 -2
  314. package/dist/native/feedback/Dialog.js +3 -3
  315. package/dist/native/form/Button.js +3 -3
  316. package/dist/native/form/Checkbox.js +3 -3
  317. package/dist/native/form/Input.js +3 -3
  318. package/dist/native/form/Select.js +4 -4
  319. package/dist/native/form/Switch.js +26 -8
  320. package/dist/native/form/Switch.js.map +1 -1
  321. package/dist/native/icons.js +3 -3
  322. package/dist/native/layout/Box.js +3 -3
  323. package/dist/native/layout/Card.js +2 -2
  324. package/dist/native/layout/Container.js +2 -2
  325. package/dist/native/layout/Skeleton.js +3 -3
  326. package/dist/native/layout/Spacer.js +2 -2
  327. package/dist/native/layout/Stack.js +3 -3
  328. package/dist/native/provider.js +2 -2
  329. package/dist/native/tokens.js +3 -1
  330. package/dist/native/typography/Heading.js +2 -2
  331. package/dist/native/typography/Paragraph.js +2 -2
  332. package/dist/native/typography/Text.js +2 -2
  333. package/dist/navigation/AppHeader.js +7 -7
  334. package/dist/navigation/Tabs.js +1 -1
  335. package/dist/provider.js +4 -4
  336. package/dist/social-login-button.js +9 -9
  337. package/dist/tokens.js +3 -1
  338. package/dist/types/components/form/Button/Button.styles.d.ts.map +1 -1
  339. package/dist/types/components/form/Switch/Switch.d.ts.map +1 -1
  340. package/dist/types/components/form/Switch/Switch.ids.d.ts +42 -0
  341. package/dist/types/components/form/Switch/Switch.ids.d.ts.map +1 -0
  342. package/dist/types/components/form/Switch/Switch.metrics.d.ts +19 -0
  343. package/dist/types/components/form/Switch/Switch.metrics.d.ts.map +1 -1
  344. package/dist/types/components/form/Switch/Switch.parts.d.ts +31 -11
  345. package/dist/types/components/form/Switch/Switch.parts.d.ts.map +1 -1
  346. package/dist/types/components/form/Switch/Switch.styles.d.ts +6 -0
  347. package/dist/types/components/form/Switch/Switch.styles.d.ts.map +1 -1
  348. package/dist/types/components/navigation/Tabs/Tabs.d.ts.map +1 -1
  349. package/dist/types/tokens/theme.d.ts +38 -0
  350. package/dist/types/tokens/theme.d.ts.map +1 -1
  351. package/dist/types-native/components/form/Switch/Switch.look.native.d.ts +26 -2
  352. package/dist/types-native/components/form/Switch/Switch.look.native.d.ts.map +1 -1
  353. package/dist/types-native/components/form/Switch/Switch.metrics.d.ts +19 -0
  354. package/dist/types-native/components/form/Switch/Switch.metrics.d.ts.map +1 -1
  355. package/dist/types-native/components/form/Switch/Switch.native.d.ts.map +1 -1
  356. package/dist/types-native/tokens/theme.d.ts +38 -0
  357. package/dist/types-native/tokens/theme.d.ts.map +1 -1
  358. package/dist/typography/Heading.js +4 -4
  359. package/dist/typography/Paragraph.js +2 -2
  360. package/dist/typography/Text.js +3 -3
  361. package/dist/user-avatar.js +8 -8
  362. package/package.json +1 -1
  363. package/src/components/form/Button/Button.md +8 -0
  364. package/src/components/form/Button/Button.styles.ts +24 -3
  365. package/src/components/form/Switch/Switch.ids.ts +63 -0
  366. package/src/components/form/Switch/Switch.look.native.ts +45 -2
  367. package/src/components/form/Switch/Switch.md +34 -9
  368. package/src/components/form/Switch/Switch.metrics.ts +21 -0
  369. package/src/components/form/Switch/Switch.native.tsx +19 -6
  370. package/src/components/form/Switch/Switch.parts.tsx +150 -17
  371. package/src/components/form/Switch/Switch.styles.ts +59 -6
  372. package/src/components/form/Switch/Switch.tsx +32 -30
  373. package/src/components/navigation/Tabs/Tabs.tsx +46 -1
  374. package/src/tokens/theme.ts +50 -0
  375. package/dist/chunk-2ECT4IY2.js.map +0 -1
  376. package/dist/chunk-BB2OUERT.js.map +0 -1
  377. package/dist/chunk-BBC4KT5G.js.map +0 -1
  378. package/dist/chunk-FR67FG2U.js.map +0 -1
  379. package/dist/chunk-N5IVVLTH.js.map +0 -1
  380. package/dist/chunk-NQN5Z36J.js.map +0 -1
  381. /package/dist/{chunk-2GI7ANEL.js.map → chunk-22X7TT6Z.js.map} +0 -0
  382. /package/dist/{chunk-WR5JFDQ5.js.map → chunk-27BL3DNT.js.map} +0 -0
  383. /package/dist/{chunk-E55CJV65.js.map → chunk-2KVQIGVE.js.map} +0 -0
  384. /package/dist/{chunk-W3FAKT3D.js.map → chunk-2SWQ6HIK.js.map} +0 -0
  385. /package/dist/{chunk-ISW5K72V.js.map → chunk-2ZRZTGWP.js.map} +0 -0
  386. /package/dist/{chunk-I5SBTNV2.js.map → chunk-3GB6KWHH.js.map} +0 -0
  387. /package/dist/{chunk-ZEG2LNBY.js.map → chunk-3PJLT5FX.js.map} +0 -0
  388. /package/dist/{chunk-CXLAJZSE.js.map → chunk-3VZT2FAI.js.map} +0 -0
  389. /package/dist/{chunk-PFDM2OIP.js.map → chunk-45OHGD2B.js.map} +0 -0
  390. /package/dist/{chunk-BH5BXLGI.js.map → chunk-4A2Q22HO.js.map} +0 -0
  391. /package/dist/{chunk-46UPILLK.js.map → chunk-4ETQRBZC.js.map} +0 -0
  392. /package/dist/{chunk-TWY5FOBY.js.map → chunk-5QUSX3TC.js.map} +0 -0
  393. /package/dist/{chunk-AVGTTWTE.js.map → chunk-65DLYC4S.js.map} +0 -0
  394. /package/dist/{chunk-TVPPA4RD.js.map → chunk-65METCKT.js.map} +0 -0
  395. /package/dist/{chunk-OQFSYMHJ.js.map → chunk-67ALTEWH.js.map} +0 -0
  396. /package/dist/{chunk-OGGHD64H.js.map → chunk-6SK3MTYJ.js.map} +0 -0
  397. /package/dist/{chunk-OE2ZVL67.js.map → chunk-6VHCSPKK.js.map} +0 -0
  398. /package/dist/{chunk-WAPJ2DL3.js.map → chunk-72T5PAW7.js.map} +0 -0
  399. /package/dist/{chunk-SLVQ33AN.js.map → chunk-77DF5LKI.js.map} +0 -0
  400. /package/dist/{chunk-7KWBGMQC.js.map → chunk-77OXG6DH.js.map} +0 -0
  401. /package/dist/{chunk-Y3KRUT7O.js.map → chunk-7AIHK2XM.js.map} +0 -0
  402. /package/dist/{chunk-MHV5Y5MR.js.map → chunk-7KEGJH3Q.js.map} +0 -0
  403. /package/dist/{chunk-KMXAPYU2.js.map → chunk-7NEUPEV5.js.map} +0 -0
  404. /package/dist/{chunk-67L7HMEP.js.map → chunk-7Z2AQEC5.js.map} +0 -0
  405. /package/dist/{chunk-PQECNGDE.js.map → chunk-AGYGNNOM.js.map} +0 -0
  406. /package/dist/{chunk-ZTF5C2GA.js.map → chunk-B5SW7I5W.js.map} +0 -0
  407. /package/dist/{chunk-TXHJX2NG.js.map → chunk-BGYLL467.js.map} +0 -0
  408. /package/dist/{chunk-R7R3LOKW.js.map → chunk-CA7TA36R.js.map} +0 -0
  409. /package/dist/{chunk-FPFUXRD2.js.map → chunk-CKJI7JO5.js.map} +0 -0
  410. /package/dist/{chunk-HMV4QMXS.js.map → chunk-CMN26J5Y.js.map} +0 -0
  411. /package/dist/{chunk-KVEHH4SA.js.map → chunk-DB2MAYPK.js.map} +0 -0
  412. /package/dist/{chunk-V4FKHLEB.js.map → chunk-DTIB5KWP.js.map} +0 -0
  413. /package/dist/{chunk-MESRKY67.js.map → chunk-DW6GBMLQ.js.map} +0 -0
  414. /package/dist/{chunk-JO6BBSGY.js.map → chunk-DWJBOR47.js.map} +0 -0
  415. /package/dist/{chunk-YW5T6KZ5.js.map → chunk-DYESJJ3Q.js.map} +0 -0
  416. /package/dist/{chunk-TZDDL3DR.js.map → chunk-ECMJ5VPW.js.map} +0 -0
  417. /package/dist/{chunk-OH3YGJT5.js.map → chunk-EMNGIYH6.js.map} +0 -0
  418. /package/dist/{chunk-CZJLWCEG.js.map → chunk-EPNCYUQ7.js.map} +0 -0
  419. /package/dist/{chunk-JZXWCEH5.js.map → chunk-EQA4VQEO.js.map} +0 -0
  420. /package/dist/{chunk-3N6EK6K5.js.map → chunk-ERX4XIYC.js.map} +0 -0
  421. /package/dist/{chunk-TTLI6PF7.js.map → chunk-FF3R67WD.js.map} +0 -0
  422. /package/dist/{chunk-4Y6SPFKW.js.map → chunk-FOF2RAVQ.js.map} +0 -0
  423. /package/dist/{chunk-KLREH4X6.js.map → chunk-G2JPUHEJ.js.map} +0 -0
  424. /package/dist/{chunk-4J5EN4FQ.js.map → chunk-GBX5ACPF.js.map} +0 -0
  425. /package/dist/{chunk-ZZMZF7PZ.js.map → chunk-GQJ4NCZ6.js.map} +0 -0
  426. /package/dist/{chunk-IPVYEPXO.js.map → chunk-GSTRPZS4.js.map} +0 -0
  427. /package/dist/{chunk-HFXTAEYY.js.map → chunk-GTLJYAEG.js.map} +0 -0
  428. /package/dist/{chunk-M4LFDGI6.js.map → chunk-GYQT47YZ.js.map} +0 -0
  429. /package/dist/{chunk-JSH3HFDQ.js.map → chunk-H3BQFEN5.js.map} +0 -0
  430. /package/dist/{chunk-OV4WREMW.js.map → chunk-HKB5C2KY.js.map} +0 -0
  431. /package/dist/{chunk-BLBOYCOV.js.map → chunk-HKV4MQ2W.js.map} +0 -0
  432. /package/dist/{chunk-4MGFUPQT.js.map → chunk-HOJL2GKW.js.map} +0 -0
  433. /package/dist/{chunk-HR7YTBR7.js.map → chunk-IASDP44E.js.map} +0 -0
  434. /package/dist/{chunk-YMRI5QKG.js.map → chunk-IV5QQLCS.js.map} +0 -0
  435. /package/dist/{chunk-JUHUKZGU.js.map → chunk-JD3D6Y4U.js.map} +0 -0
  436. /package/dist/{chunk-AXTLFK4T.js.map → chunk-KAV63FBG.js.map} +0 -0
  437. /package/dist/{chunk-2PBGVMM2.js.map → chunk-KOFO6QZY.js.map} +0 -0
  438. /package/dist/{chunk-RP5FK3SO.js.map → chunk-L7LCSZ3H.js.map} +0 -0
  439. /package/dist/{chunk-MNXVXW4T.js.map → chunk-L7S6N67X.js.map} +0 -0
  440. /package/dist/{chunk-JXPHU3K5.js.map → chunk-LGJ2H4AH.js.map} +0 -0
  441. /package/dist/{chunk-W4YWU7LQ.js.map → chunk-LO2B7FDQ.js.map} +0 -0
  442. /package/dist/{chunk-PWR7K5OP.js.map → chunk-LV4UTYAD.js.map} +0 -0
  443. /package/dist/{chunk-OG2FP6SE.js.map → chunk-M4NFXC5R.js.map} +0 -0
  444. /package/dist/{chunk-ZPIMPOHV.js.map → chunk-M7E66OSC.js.map} +0 -0
  445. /package/dist/{chunk-OGGPQVIG.js.map → chunk-MDTSMJ7C.js.map} +0 -0
  446. /package/dist/{chunk-YDI6IJ6F.js.map → chunk-MI2MVH3I.js.map} +0 -0
  447. /package/dist/{chunk-UIZH4DAE.js.map → chunk-MQPT254A.js.map} +0 -0
  448. /package/dist/{chunk-EWT3WMVY.js.map → chunk-MYH7VISV.js.map} +0 -0
  449. /package/dist/{chunk-7NSX7A5H.js.map → chunk-N5PY7IXI.js.map} +0 -0
  450. /package/dist/{chunk-BHIGHSXA.js.map → chunk-NNXZ5RK5.js.map} +0 -0
  451. /package/dist/{chunk-EQ7PWGBN.js.map → chunk-O7HLQTB7.js.map} +0 -0
  452. /package/dist/{chunk-DW5FRWRQ.js.map → chunk-OAWEUKUC.js.map} +0 -0
  453. /package/dist/{chunk-O4VCZTK4.js.map → chunk-OGHW7RQC.js.map} +0 -0
  454. /package/dist/{chunk-XR6WBW23.js.map → chunk-OVGASVPW.js.map} +0 -0
  455. /package/dist/{chunk-HEBQS7QP.js.map → chunk-OXYR2HVK.js.map} +0 -0
  456. /package/dist/{chunk-TNVO2DTB.js.map → chunk-P7FQUGED.js.map} +0 -0
  457. /package/dist/{chunk-343TTIHD.js.map → chunk-PENJBKPH.js.map} +0 -0
  458. /package/dist/{chunk-2RQINU5T.js.map → chunk-PKFFJAQ6.js.map} +0 -0
  459. /package/dist/{chunk-M4LQRQFL.js.map → chunk-PW2WLDX3.js.map} +0 -0
  460. /package/dist/{chunk-WRDPWEIC.js.map → chunk-Q3GSDSK2.js.map} +0 -0
  461. /package/dist/{chunk-VNTOBLIB.js.map → chunk-Q3OFOOO7.js.map} +0 -0
  462. /package/dist/{chunk-GGI7GM5O.js.map → chunk-QE2C35TO.js.map} +0 -0
  463. /package/dist/{chunk-CT5K725B.js.map → chunk-QQLGSMGE.js.map} +0 -0
  464. /package/dist/{chunk-7MN6I5NK.js.map → chunk-QXFPTRHB.js.map} +0 -0
  465. /package/dist/{chunk-CZPU5TW3.js.map → chunk-RFZU5BTG.js.map} +0 -0
  466. /package/dist/{chunk-JB67KPGM.js.map → chunk-RRO2EOJB.js.map} +0 -0
  467. /package/dist/{chunk-MZQTHSLN.js.map → chunk-S7HRED4D.js.map} +0 -0
  468. /package/dist/{chunk-NYEA7JAI.js.map → chunk-SC72DRTX.js.map} +0 -0
  469. /package/dist/{chunk-JWW2Z3RH.js.map → chunk-SMZBGHR2.js.map} +0 -0
  470. /package/dist/{chunk-EZSEAYYT.js.map → chunk-SSWZHR46.js.map} +0 -0
  471. /package/dist/{chunk-NA7MIEG6.js.map → chunk-SZETT7QV.js.map} +0 -0
  472. /package/dist/{chunk-2HPP6RVC.js.map → chunk-TQOPF7LD.js.map} +0 -0
  473. /package/dist/{chunk-OLVZ6TOV.js.map → chunk-TUO47RL2.js.map} +0 -0
  474. /package/dist/{chunk-4IVDVZZ2.js.map → chunk-UGL6SJN6.js.map} +0 -0
  475. /package/dist/{chunk-QJRDDVZ2.js.map → chunk-V5P5Q6HM.js.map} +0 -0
  476. /package/dist/{chunk-73NJCGQG.js.map → chunk-VIK3HAUQ.js.map} +0 -0
  477. /package/dist/{chunk-7LCXGJN5.js.map → chunk-VK4ULJFH.js.map} +0 -0
  478. /package/dist/{chunk-QYNCPS5W.js.map → chunk-WBKWIFXA.js.map} +0 -0
  479. /package/dist/{chunk-X4Z62ZQY.js.map → chunk-WETAIIKC.js.map} +0 -0
  480. /package/dist/{chunk-GMTM6EN7.js.map → chunk-WKF54CCK.js.map} +0 -0
  481. /package/dist/{chunk-KT6HWAEN.js.map → chunk-WZUNBSS7.js.map} +0 -0
  482. /package/dist/{chunk-Y2B3I3IH.js.map → chunk-X5RDHO6G.js.map} +0 -0
  483. /package/dist/{chunk-TXKZEKJN.js.map → chunk-XNOSTV5F.js.map} +0 -0
  484. /package/dist/{chunk-7JXLGOM2.js.map → chunk-Y55ILY2F.js.map} +0 -0
  485. /package/dist/{chunk-HI2OFZSZ.js.map → chunk-YPILHGEO.js.map} +0 -0
  486. /package/dist/{chunk-V3PLFYKO.js.map → chunk-ZAJO2B75.js.map} +0 -0
  487. /package/dist/native/chunks/{chunk-2R2R35C5.js.map → chunk-2SBTJSQE.js.map} +0 -0
  488. /package/dist/native/chunks/{chunk-WL5LXVCK.js.map → chunk-6L4UZBQP.js.map} +0 -0
  489. /package/dist/native/chunks/{chunk-GW7TQ7HO.js.map → chunk-QEQZ5AF6.js.map} +0 -0
  490. /package/dist/native/chunks/{chunk-7LTVGW23.js.map → chunk-UII3IFLP.js.map} +0 -0
  491. /package/dist/native/chunks/{chunk-75JQYVDZ.js.map → chunk-UYREIOEM.js.map} +0 -0
  492. /package/dist/native/chunks/{chunk-GWGIWQO7.js.map → chunk-XI7HTAVN.js.map} +0 -0
  493. /package/dist/native/chunks/{chunk-QYUD3S6F.js.map → chunk-ZOP7UAZK.js.map} +0 -0
@@ -0,0 +1,63 @@
1
+ import type { InputHTMLAttributes, ReactNode } from 'react';
2
+
3
+ /** The ids the DOM `Switch` wires its label and its two descriptions with. */
4
+ export interface SwitchIds {
5
+ /** The input's id. Always set — the label has to have something to point at. */
6
+ inputId: string;
7
+ descriptionId?: string;
8
+ helperId?: string;
9
+ /** Everything that DESCRIBES the control, the caller's own included. */
10
+ describedBy?: string;
11
+ }
12
+
13
+ export interface SwitchIdSource {
14
+ /** `useId()`'s value, passed in so this stays a pure function. */
15
+ generated: string;
16
+ id?: string;
17
+ inputProps?: InputHTMLAttributes<HTMLInputElement>;
18
+ description?: ReactNode;
19
+ helperText?: ReactNode;
20
+ callerDescribedBy?: unknown;
21
+ }
22
+
23
+ /**
24
+ * Derive every id one `Switch` needs, in one place (FUT-1905).
25
+ *
26
+ * The precedence is the point: an id the caller spelled — as `inputProps.id` or
27
+ * as `id` — wins, because a consumer that chose one is usually pointing its own
28
+ * `<label>` or a test at it. Only when there is none does the generated one
29
+ * apply, and it comes from `useId` rather than from the test id: two call sites
30
+ * sharing a `dataTestId` would otherwise share a `for`, and the second label
31
+ * would toggle the first control.
32
+ *
33
+ * `describedBy` APPENDS rather than replaces. The description and the helper
34
+ * line are the component's own, but a consumer that passed `aria-describedby`
35
+ * meant it, and dropping it to make room would trade one silent omission for
36
+ * another.
37
+ *
38
+ * It has TWO spellings and both count — top-level and inside `inputProps` —
39
+ * because that is a consumer's choice of spelling, not a choice of meaning.
40
+ * Reading only the first is how this shipped for one round: a caller writing
41
+ * `inputProps={{ 'aria-describedby': … }}` had it silently dropped, which is the
42
+ * omission the paragraph above says it must not trade for.
43
+ */
44
+ export function switchIds({
45
+ generated,
46
+ id,
47
+ inputProps,
48
+ description,
49
+ helperText,
50
+ callerDescribedBy,
51
+ }: SwitchIdSource): SwitchIds {
52
+ const inputId = inputProps?.id ?? id ?? `switch-${generated}`;
53
+ const descriptionId = description ? `${inputId}-description` : undefined;
54
+ const helperId = helperText ? `${inputId}-helper` : undefined;
55
+ const described = [callerDescribedBy, inputProps?.['aria-describedby'], descriptionId, helperId];
56
+
57
+ return {
58
+ inputId,
59
+ descriptionId,
60
+ helperId,
61
+ describedBy: described.filter(Boolean).join(' ') || undefined,
62
+ };
63
+ }
@@ -6,6 +6,7 @@ import {
6
6
  IOS_THUMB_SHADOW,
7
7
  MUI_SHADOWS,
8
8
  NEUTRAL_CONTRAST,
9
+ RESTING_THUMB,
9
10
  NEUTRAL_FALLBACK,
10
11
  NEUTRAL_GREY,
11
12
  SWITCH_BLACK,
@@ -23,6 +24,7 @@ import {
23
24
  type SwitchLook,
24
25
  } from './Switch.metrics';
25
26
  import { alpha } from '../../../tokens/color';
27
+ import { inkOver } from '../../../tokens/theme';
26
28
  import type { UiTheme } from '../../../tokens/theme';
27
29
  import type { ColorValue } from '../../../tokens/vocabulary';
28
30
 
@@ -111,6 +113,31 @@ export function trackStyle(
111
113
  return base;
112
114
  }
113
115
 
116
+ /**
117
+ * The ink on the CHECKED track — the thumb, and the `on` wording (FUT-1924).
118
+ *
119
+ * Both halves of the component had a stated `#fff` here, and the checked track
120
+ * is the one surface a tenant chooses: a pale brand got a white knob on a pale
121
+ * bar, which reads as OFF while it is on.
122
+ *
123
+ * **The fills are THIS renderer's, not the web's, and they differ.** The web
124
+ * paints a real three-stop gradient and hands `checkedInk` all three
125
+ * (`Switch.styles.ts`); React Native has no gradient without a dependency, so
126
+ * `trackStyle` shows `gradientFirstStop` — `palette.light`, FLAT — and
127
+ * `NATIVE-NOTES.md` records that as a known divergence. Passing the web's set
128
+ * here would judge the ink against two fills native never draws, and the two
129
+ * renderers then disagree on the same palette: measured on `#00897b`, the web
130
+ * answers white and this answered dark ink, because `main` and `dark` were in
131
+ * the list and only `light` is on screen.
132
+ *
133
+ * So the gradient case is ONE fill, which is the one it paints.
134
+ */
135
+ export function checkedInk(paint: SwitchPaint, palette: SwitchPalette): string {
136
+ const fills = [paint.gradient ? palette.light || palette.main : palette.main];
137
+
138
+ return inkOver(fills, palette.contrastText || NEUTRAL_CONTRAST);
139
+ }
140
+
114
141
  /** The web's two gradients, at the stop a flat fill can show. */
115
142
  function gradientFirstStop(palette: SwitchPalette, checked: boolean): string {
116
143
  if (checked) return palette.light || palette.main;
@@ -125,10 +152,26 @@ const disabledTrackOpacity = (state: SwitchState): number => {
125
152
  /** React Native has no `StyleSheet.absoluteFillObject` constant worth importing for four keys. */
126
153
  const StyleSheetAbsoluteFill = { position: 'absolute', top: 0, left: 0, right: 0, bottom: 0 } as const;
127
154
 
128
- /** The knob: white, round for iOS and the default, squarer for Android and Material. */
155
+ /** Disabled greys out; checked takes the track's ink; resting stays white. */
156
+ function thumbFill(
157
+ paint: SwitchPaint,
158
+ palette: SwitchPalette,
159
+ state: SwitchState,
160
+ theme: UiTheme,
161
+ ): string {
162
+ if (state.disabled) return theme.palette.grey[DISABLED.thumbGrey] ?? RESTING_THUMB;
163
+ return state.checked ? checkedInk(paint, palette) : RESTING_THUMB;
164
+ }
165
+
166
+ /**
167
+ * The knob: round for iOS and the default, squarer for Android and Material.
168
+ * White while resting, the checked track's own ink once on — see
169
+ * {@link RESTING_THUMB} and {@link checkedInk}.
170
+ */
129
171
  export function thumbStyle(
130
172
  theme: UiTheme,
131
173
  paint: SwitchPaint,
174
+ palette: SwitchPalette,
132
175
  geometry: SwitchGeometry,
133
176
  look: SwitchLook,
134
177
  state: SwitchState,
@@ -138,7 +181,7 @@ export function thumbStyle(
138
181
  width: geometry.thumbSize,
139
182
  height: geometry.thumbSize,
140
183
  borderRadius: thumbRadius(look, geometry.thumbSize),
141
- backgroundColor: state.disabled ? theme.palette.grey[DISABLED.thumbGrey] : '#fff',
184
+ backgroundColor: thumbFill(paint, palette, state, theme),
142
185
  boxShadow: look === 'ios' ? IOS_THUMB_SHADOW : (MUI_SHADOWS[THUMB_ELEVATION[look]] ?? 'none'),
143
186
  alignItems: 'center',
144
187
  justifyContent: 'center',
@@ -273,15 +273,28 @@ import Close from '@mui/icons-material/Close';
273
273
 
274
274
  ## Accessibility
275
275
 
276
- The Switch component follows WCAG 2.1 AA guidelines:
277
-
278
- - **Keyboard Navigation**: Supports Tab and Space key activation
279
- - **Focus Management**: Clear focus indicators with visible outline
280
- - **ARIA Attributes**: Supports aria-label, aria-describedby, role="switch"
281
- - **Screen Reader**: Properly announces switch state (on/off)
282
- - **Disabled State**: Communicates disabled state to assistive technologies
283
- - **Error State**: Associates error messages with the switch
284
- - **Helper Text**: Properly linked via aria-describedby
276
+ - **The label names the control.** `label` renders a real `<label for>` pointing
277
+ at the input, so the switch announces by its visible words and clicking those
278
+ words toggles it. Pass `aria-label` only where there is no visible label —
279
+ with one, it would override the text on screen.
280
+ - **The id is minted for you.** An explicit `id` (or `inputProps.id`) wins;
281
+ otherwise each instance gets its own from `useId`. Do not derive one from a
282
+ test id: two call sites sharing a test id would share a `for`, and the second
283
+ label would toggle the first control.
284
+ - **`description` and `helperText` are described, not named.** Both are linked
285
+ by `aria-describedby` and stay out of the accessible name — a two-line
286
+ explanation read as the control's NAME is worse than no description at all. A
287
+ caller's own `aria-describedby` is kept alongside them, not replaced.
288
+ - **Keyboard:** `Tab` to reach it, `Space` to toggle, with a visible focus ring.
289
+ - **It announces as a checkbox, not as a switch.** MUI's `SwitchBase` renders an
290
+ `<input type="checkbox">` and this component does not override the role.
291
+ Earlier revisions of this document claimed `role="switch"`; that was never
292
+ true. Announcing as a checkbox is correct and understood — do not "fix" it by
293
+ hand-setting the role without also handling `aria-checked`.
294
+ - **The tap target is the LABEL.** `SWITCH_SIZES.xl`, the largest, is 34px tall
295
+ against the 40px floor, so no `size` clears it. The label carries the floor
296
+ instead (`TAP_TARGET_MIN`), which is why an unlabelled `Switch` at a phone
297
+ width still wants a target around it drawn by the caller.
285
298
 
286
299
  ### Keyboard Shortcuts
287
300
 
@@ -373,6 +386,18 @@ The Switch component follows WCAG 2.1 AA guidelines:
373
386
  />
374
387
  ```
375
388
 
389
+ ## Ink on the track
390
+
391
+ The thumb, the `on` wording of the `label` variant and the on-icon all take
392
+ their colour from the palette, NOT from a stated white. The checked track is
393
+ `palette.main` — the one surface a white-labelled host picks — so a pale brand
394
+ gets dark ink and reads as ON, where a white knob on a pale bar reads as OFF.
395
+ Under `gradient` the whole bar (`light → main → dark`) is considered, not just
396
+ the colour in the middle of it.
397
+
398
+ The RESTING thumb stays white by design: that track is `action.disabled` washed
399
+ over the page, which no tenant chooses.
400
+
376
401
  ## Theming
377
402
 
378
403
  The Switch component integrates with MUI's theme system:
@@ -168,6 +168,15 @@ export const SWITCH_HELPER = { fontSize: 12, lineHeight: 1.66, marginTopUnits: 1
168
168
  /** The label row: 16px from the control beside it, 8px above or below it. */
169
169
  export const LABEL_GAP_UNITS = { beside: 2, stacked: 1 } as const;
170
170
 
171
+ /**
172
+ * The minimum height of a touch target, in px (FUT-1905).
173
+ *
174
+ * No entry in {@link SWITCH_SIZES} reaches it — `xl`, the largest, is 34px tall
175
+ * and `md` is 26 — so a consumer cannot buy a legal target by passing a bigger
176
+ * `size`. The label is what clears it: see `SwitchLabel` in `Switch.parts.tsx`.
177
+ */
178
+ export const TAP_TARGET_MIN = 40;
179
+
171
180
  /**
172
181
  * `neutral`'s three greys, and the literals the web falls back to for a theme
173
182
  * whose grey ramp omits a step. Same three steps `Button` draws its neutral
@@ -177,6 +186,18 @@ export const NEUTRAL_GREY = { main: 700, dark: 800, light: 500 } as const;
177
186
  export const NEUTRAL_FALLBACK = { main: '#616161', dark: '#424242', light: '#9e9e9e' } as const;
178
187
  export const NEUTRAL_CONTRAST = '#fff';
179
188
 
189
+ /**
190
+ * The RESTING thumb — the knob while the switch is off (FUT-1924).
191
+ *
192
+ * It stays white, and the reason is worth stating because the checked thumb no
193
+ * longer is: the resting track is `theme.palette.action.disabled` washed over
194
+ * the page, which no tenant picks, and a white knob on it is the conventional
195
+ * look in both modes. The CHECKED track is `palette.main`, a colour the tenant
196
+ * does pick, and that is where a stated white was a defect. See `checkedInk`
197
+ * in `Switch.styles.ts` and its native twin.
198
+ */
199
+ export const RESTING_THUMB = '#fff';
200
+
180
201
  /** Hover: the thumb lifts a shade and takes a halo of the hue. */
181
202
  export const SWITCH_HOVER = { thumbScale: 1.05, elevation: 4, blur: 12, alpha: 0.2 } as const;
182
203
 
@@ -17,6 +17,7 @@ import {
17
17
  descriptionTextStyle,
18
18
  helperTextStyle,
19
19
  labelTextStyle,
20
+ checkedInk,
20
21
  switchPalette,
21
22
  thumbStyle,
22
23
  trackStyle,
@@ -45,9 +46,6 @@ import type { UiTheme } from '../../../tokens/theme';
45
46
 
46
47
  const nativeDriver = Platform.OS !== 'web';
47
48
 
48
- /** The web writes the `on` wording in white, whatever the hue behind it. */
49
- const TRACK_LABEL_ON_INK = '#fff';
50
-
51
49
  /** A 0→1 value that follows `on`, over MUI's 300ms curve unless animation is off. */
52
50
  function useProgress(on: boolean, animated: boolean): Animated.Value {
53
51
  const progress = React.useRef(new Animated.Value(on ? 1 : 0)).current;
@@ -167,7 +165,16 @@ interface ControlProps {
167
165
  testID: string;
168
166
  }
169
167
 
170
- /** The track, the thumb, and everything overlaid on them. */
168
+ /**
169
+ * The track, the thumb, and everything overlaid on them.
170
+ *
171
+ * The control carries its own NAME (FUT-1905). React Native has no `<label
172
+ * for>` to wire the words beside it with, so the name has to be stated on the
173
+ * pressable itself or the control announces as "checkbox, checked" and nothing
174
+ * else — which is the defect the web half of this ticket fixed, still live
175
+ * here. A caller's own `aria-label` wins, because a caller that wrote one meant
176
+ * it to differ from the visible words.
177
+ */
171
178
  function SwitchControl({ props, theme, checked, inactive, onToggle, rest, testID }: ControlProps): React.JSX.Element {
172
179
  const { variant, color, size, animated, loading, onIcon, offIcon, onText, offText } = props;
173
180
  const geometry: SwitchGeometry = geometryOf(size, props.trackWidth, props.trackHeight);
@@ -184,6 +191,7 @@ function SwitchControl({ props, theme, checked, inactive, onToggle, rest, testID
184
191
  <Pressable
185
192
  testID={testID}
186
193
  role="checkbox"
194
+ aria-label={(rest['aria-label'] as string | undefined) ?? props.label}
187
195
  aria-checked={checked}
188
196
  aria-disabled={inactive}
189
197
  disabled={inactive}
@@ -196,7 +204,12 @@ function SwitchControl({ props, theme, checked, inactive, onToggle, rest, testID
196
204
  >
197
205
  <View style={trackStyle(theme, paint, palette, geometry, look, state)} />
198
206
  {showsTrackLabels(variant, onText, offText) ? (
199
- <TrackLabels theme={theme} onText={onText} offText={offText} contrastText={TRACK_LABEL_ON_INK} />
207
+ <TrackLabels
208
+ theme={theme}
209
+ onText={onText}
210
+ offText={offText}
211
+ contrastText={checkedInk(paint, palette)}
212
+ />
200
213
  ) : null}
201
214
  {onIcon == null ? null : (
202
215
  <SwitchIcon icon={onIcon} shown={checked} animated={animated} size={iconSize} side="on" width={geometry.width} />
@@ -206,7 +219,7 @@ function SwitchControl({ props, theme, checked, inactive, onToggle, rest, testID
206
219
  )}
207
220
  <Animated.View
208
221
  style={[
209
- thumbStyle(theme, paint, geometry, look, state),
222
+ thumbStyle(theme, paint, palette, geometry, look, state),
210
223
  { top: geometry.padding, left: restX, opacity: pulse.opacity },
211
224
  {
212
225
  transform: [
@@ -2,11 +2,11 @@ import Box from '@mui/material/Box/index.js';
2
2
  import FormHelperText from '@mui/material/FormHelperText/index.js';
3
3
  import MuiSwitch from '@mui/material/Switch/index.js';
4
4
  import Typography from '@mui/material/Typography/index.js';
5
- import { styled } from '@mui/material/styles/index.js';
5
+ import { styled, useTheme } from '@mui/material/styles/index.js';
6
6
  import React from 'react';
7
7
 
8
- import { LABEL_GAP_UNITS, SWITCH_ICON_SIZES } from './Switch.metrics';
9
- import { switchSx } from './Switch.styles';
8
+ import { LABEL_GAP_UNITS, SWITCH_ICON_SIZES, TAP_TARGET_MIN } from './Switch.metrics';
9
+ import { onTrackInk, switchSx } from './Switch.styles';
10
10
  import type { SwitchFlags } from './Switch.styles';
11
11
  import type { SwitchProps } from './Switch.types';
12
12
  import type { SizeValue } from '../../../tokens/vocabulary';
@@ -54,7 +54,7 @@ const StyledLabelContainer = styled(Box, {
54
54
  * A plain wrapper over the styled row. Exporting the styled component itself
55
55
  * needs a @mui/system reference tsc calls unportable (TS2742).
56
56
  */
57
- export const LabelContainer: React.FC<{
57
+ const LabelContainer: React.FC<{
58
58
  labelPosition?: string;
59
59
  error?: boolean;
60
60
  children: React.ReactNode;
@@ -71,6 +71,8 @@ export interface SwitchIconProps {
71
71
  animated: boolean;
72
72
  size: string;
73
73
  side: 'on' | 'off';
74
+ /** The ink for the ON icon, which sits on the brand-filled track (FUT-1924). */
75
+ onInk: string;
74
76
  }
75
77
 
76
78
  /**
@@ -78,7 +80,14 @@ export interface SwitchIconProps {
78
80
  * edge when checked and the off icon to the right when unchecked; they are
79
81
  * mirror images, so they share this component rather than being written twice.
80
82
  */
81
- export const SwitchIcon: React.FC<SwitchIconProps> = ({ icon, shown, animated, size, side }) => {
83
+ export const SwitchIcon: React.FC<SwitchIconProps> = ({
84
+ icon,
85
+ shown,
86
+ animated,
87
+ size,
88
+ side,
89
+ onInk,
90
+ }) => {
82
91
  const isOn = side === 'on';
83
92
  const translate = isOn ? 'translate(-50%, -50%)' : 'translate(50%, -50%)';
84
93
 
@@ -93,7 +102,7 @@ export const SwitchIcon: React.FC<SwitchIconProps> = ({ icon, shown, animated, s
93
102
  transform: `${translate} scale(${shown && animated ? 1 : 0.8})`,
94
103
  pointerEvents: 'none',
95
104
  zIndex: 2,
96
- color: isOn ? '#fff' : 'text.secondary',
105
+ color: isOn ? onInk : 'text.secondary',
97
106
  fontSize: SWITCH_ICON_SIZES[size as SizeValue] ?? SWITCH_ICON_SIZES.md,
98
107
  }}
99
108
  >
@@ -111,6 +120,12 @@ export interface SwitchControlProps extends SwitchFlags {
111
120
  size: string;
112
121
  dataTestId?: string;
113
122
  switchRef?: React.Ref<HTMLButtonElement>;
123
+ /** The id the label points at — always set, so the input always has one. */
124
+ inputId: string;
125
+ /** The caller's own `inputProps`, merged rather than spread over (FUT-1905). */
126
+ inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
127
+ /** The description's id, appended to whatever the caller described it by. */
128
+ describedBy?: string;
114
129
  rest: Record<string, unknown>;
115
130
  }
116
131
 
@@ -124,13 +139,15 @@ export const SwitchControl: React.FC<SwitchControlProps> = ({
124
139
  size,
125
140
  dataTestId,
126
141
  switchRef,
142
+ inputId,
143
+ inputProps,
144
+ describedBy,
127
145
  rest,
128
146
  ...flags
129
147
  }) => {
130
- const props = rest as Record<string, unknown> & {
131
- disabled?: boolean;
132
- inputProps?: React.InputHTMLAttributes<HTMLInputElement>;
133
- };
148
+ const props = rest as Record<string, unknown> & { disabled?: boolean };
149
+ const theme = useTheme();
150
+ const onInk = onTrackInk(theme, flags);
134
151
 
135
152
  return (
136
153
  <Box sx={{ position: 'relative', display: 'inline-flex' }}>
@@ -140,15 +157,31 @@ export const SwitchControl: React.FC<SwitchControlProps> = ({
140
157
  checked={checked}
141
158
  onChange={onChange}
142
159
  disabled={Boolean(flags.loading) || props.disabled}
160
+ {...props}
161
+ /*
162
+ AFTER `props`, not before it (FUT-1905). `inputProps` used to be
163
+ written first and `{...props}` spread over it, so a caller passing
164
+ `inputProps` of its own silently replaced the whole object — losing
165
+ the `data-testid` every spec finds this control by, and the `id` the
166
+ label points at.
167
+
168
+ The order inside is the contract. Everything the component DEFAULTS
169
+ goes first, so a caller's own key still wins — that is what it could
170
+ do before, and a fix for a clobber must not become a clobber the
171
+ other way. Only the two the component OWNS come last: the `id`, which
172
+ already resolved the caller's spelling of it (`switchIds`), and
173
+ `aria-describedby`, which by then already CONTAINS whatever the
174
+ caller passed, in either spelling.
175
+ */
143
176
  inputProps={
144
177
  {
145
178
  'aria-label': props['aria-label'],
146
- 'aria-describedby': props['aria-describedby'],
147
- ...props.inputProps,
148
179
  'data-testid': dataTestId || 'switch',
180
+ ...inputProps,
181
+ id: inputId,
182
+ 'aria-describedby': describedBy,
149
183
  } as React.InputHTMLAttributes<HTMLInputElement>
150
184
  }
151
- {...props}
152
185
  />
153
186
 
154
187
  {onIcon && (
@@ -158,6 +191,7 @@ export const SwitchControl: React.FC<SwitchControlProps> = ({
158
191
  animated={animated}
159
192
  size={size}
160
193
  side="on"
194
+ onInk={onInk}
161
195
  />
162
196
  )}
163
197
  {offIcon && (
@@ -167,19 +201,30 @@ export const SwitchControl: React.FC<SwitchControlProps> = ({
167
201
  animated={animated}
168
202
  size={size}
169
203
  side="off"
204
+ onInk={onInk}
170
205
  />
171
206
  )}
172
207
  </Box>
173
208
  );
174
209
  };
175
210
 
211
+ /**
212
+ * The helper line, which is where a validation message lands — so it is
213
+ * `aria-describedby`'d like the description (FUT-1905).
214
+ *
215
+ * It carried no `id` and nothing pointed at it, which means an `error` state
216
+ * announced as "checkbox, checked" and nothing else: the one sentence saying
217
+ * WHY was on screen and outside the accessibility tree.
218
+ */
176
219
  export const SwitchHelper: React.FC<{
177
220
  helperText?: React.ReactNode;
178
221
  error?: boolean;
179
222
  dataTestId?: string;
180
- }> = ({ helperText, error, dataTestId }) =>
223
+ id?: string;
224
+ }> = ({ helperText, error, dataTestId, id }) =>
181
225
  helperText ? (
182
226
  <FormHelperText
227
+ id={id}
183
228
  error={error}
184
229
  sx={{ mt: 1 }}
185
230
  data-testid={dataTestId ? `${dataTestId}-helper` : 'switch-helper'}
@@ -188,23 +233,62 @@ export const SwitchHelper: React.FC<{
188
233
  </FormHelperText>
189
234
  ) : null;
190
235
 
191
- export const SwitchLabel: React.FC<{
236
+ /**
237
+ * The label, WIRED to the input it names (FUT-1905).
238
+ *
239
+ * It used to be a `<p>` rendered as the control's sibling, with no `for`, no
240
+ * `id` on the input and no `aria-labelledby` — so a labelled `Switch` announced
241
+ * as "checkbox, checked" with no name, and clicking the words did nothing. Every
242
+ * `Switch` in a consumer app was affected, not one call site, and the workaround
243
+ * each had to write was a hand-typed `aria-label` duplicating the text already
244
+ * on screen.
245
+ *
246
+ * A real `<label for>` fixes the name and the pointer in the same stroke, and it
247
+ * is also the answer to the TAP TARGET: no size in `SWITCH_SIZES` clears the
248
+ * 40px floor (`xl` is 34px tall), so the control cannot be made big enough by
249
+ * passing a bigger `size` — instead the label becomes the target, which is how
250
+ * this is normally solved. Hence `display: flex` and `TAP_TARGET_MIN`: the
251
+ * label fills its half of the row and is never shorter than the floor.
252
+ *
253
+ * The DESCRIPTION stays outside the label and is pointed at by
254
+ * `aria-describedby` instead: inside it, a two-line explanation would be read
255
+ * out as part of the control's name.
256
+ */
257
+ const SwitchLabel: React.FC<{
192
258
  label: React.ReactNode;
193
259
  description?: React.ReactNode;
194
260
  error?: boolean;
195
261
  dataTestId?: string;
196
- }> = ({ label, description, error, dataTestId }) => (
197
- <Box sx={{ flex: 1 }}>
262
+ /** The input's id. Omitted only where there is no input to point at. */
263
+ htmlFor?: string;
264
+ descriptionId?: string;
265
+ disabled?: boolean;
266
+ }> = ({ label, description, error, dataTestId, htmlFor, descriptionId, disabled }) => (
267
+ <Box sx={{ flex: 1, minWidth: 0 }}>
198
268
  <Typography
269
+ component="label"
270
+ htmlFor={htmlFor}
199
271
  variant="body2"
200
272
  fontWeight={500}
201
273
  color={error ? 'error.main' : 'text.primary'}
274
+ sx={{
275
+ display: 'flex',
276
+ alignItems: 'center',
277
+ // The floor applies to the row the label shares with the control. A
278
+ // description already makes the row taller than 40px, so forcing it
279
+ // there would only add blank space.
280
+ ...(description ? {} : { minHeight: TAP_TARGET_MIN }),
281
+ // A disabled control's label toggles nothing, so it must not wear the
282
+ // cursor that says it does.
283
+ ...(htmlFor && !disabled ? { cursor: 'pointer' } : {}),
284
+ }}
202
285
  data-testid={dataTestId ? `${dataTestId}-label` : 'switch-label'}
203
286
  >
204
287
  {label}
205
288
  </Typography>
206
289
  {description && (
207
290
  <Typography
291
+ id={descriptionId}
208
292
  variant="caption"
209
293
  color={error ? 'error.main' : 'text.secondary'}
210
294
  sx={{ display: 'block', mt: 0.5 }}
@@ -214,3 +298,52 @@ export const SwitchLabel: React.FC<{
214
298
  )}
215
299
  </Box>
216
300
  );
301
+
302
+ /**
303
+ * The control and its label in one row, or the control alone.
304
+ *
305
+ * Lives here rather than inline in `Switch.tsx` because the two branches only
306
+ * differ in what surrounds the control — and the component that assembles them
307
+ * was long enough that the wiring got hard to see between them.
308
+ */
309
+ export const SwitchRow: React.FC<{
310
+ label?: React.ReactNode;
311
+ description?: React.ReactNode;
312
+ labelPosition?: string;
313
+ error?: boolean;
314
+ dataTestId?: string;
315
+ htmlFor: string;
316
+ descriptionId?: string;
317
+ disabled?: boolean;
318
+ control: React.ReactNode;
319
+ }> = ({
320
+ label,
321
+ description,
322
+ labelPosition,
323
+ error,
324
+ dataTestId,
325
+ htmlFor,
326
+ descriptionId,
327
+ disabled,
328
+ control,
329
+ }) => {
330
+ if (!label) return <>{control}</>;
331
+
332
+ return (
333
+ <LabelContainer labelPosition={labelPosition} error={error}>
334
+ {labelPosition === 'start' && control}
335
+
336
+ <SwitchLabel
337
+ label={label}
338
+ description={description}
339
+ error={error}
340
+ dataTestId={dataTestId}
341
+ htmlFor={htmlFor}
342
+ descriptionId={descriptionId}
343
+ disabled={disabled}
344
+ />
345
+
346
+ {labelPosition !== 'start' && control}
347
+ </LabelContainer>
348
+ );
349
+ };