@duro-app/ui 5.11.0 → 5.13.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 (331) hide show
  1. package/dist/Table-Bms2ftt3.js +1694 -0
  2. package/dist/Table-Bms2ftt3.js.map +1 -0
  3. package/dist/compiler-runtime-BuugS4D0.js.map +1 -1
  4. package/dist/components/Alert/Alert.d.ts.map +1 -1
  5. package/dist/components/AppShell/native.css.d.ts +53 -0
  6. package/dist/components/AppShell/native.css.d.ts.map +1 -0
  7. package/dist/components/Button/Button.d.ts +2 -1
  8. package/dist/components/Button/Button.d.ts.map +1 -1
  9. package/dist/components/Button/styles.css.d.ts +1 -0
  10. package/dist/components/Button/styles.css.d.ts.map +1 -1
  11. package/dist/components/Callout/Callout.d.ts.map +1 -1
  12. package/dist/components/Callout/styles.css.d.ts +3 -0
  13. package/dist/components/Callout/styles.css.d.ts.map +1 -1
  14. package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
  15. package/dist/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -1
  16. package/dist/components/DetailPanel/DetailPanel.d.ts.map +1 -1
  17. package/dist/components/Dialog/Dialog.d.ts +2 -17
  18. package/dist/components/Dialog/Dialog.d.ts.map +1 -1
  19. package/dist/components/Dialog/Dialog.stories.d.ts +4 -0
  20. package/dist/components/Dialog/Dialog.stories.d.ts.map +1 -1
  21. package/dist/components/Dialog/native.css.d.ts +82 -0
  22. package/dist/components/Dialog/native.css.d.ts.map +1 -0
  23. package/dist/components/Dialog/parts.css.d.ts +82 -0
  24. package/dist/components/Dialog/parts.css.d.ts.map +1 -0
  25. package/dist/components/Dialog/parts.d.ts +35 -0
  26. package/dist/components/Dialog/parts.d.ts.map +1 -0
  27. package/dist/components/Dialog/styles.css.d.ts +1 -74
  28. package/dist/components/Dialog/styles.css.d.ts.map +1 -1
  29. package/dist/components/Drawer/Drawer.d.ts +7 -35
  30. package/dist/components/Drawer/Drawer.d.ts.map +1 -1
  31. package/dist/components/Drawer/Drawer.meta.d.ts.map +1 -1
  32. package/dist/components/Drawer/DrawerScroll.stories.d.ts.map +1 -1
  33. package/dist/components/Drawer/DrawerSnap.stories.d.ts +20 -0
  34. package/dist/components/Drawer/DrawerSnap.stories.d.ts.map +1 -0
  35. package/dist/components/Drawer/native.css.d.ts +55 -0
  36. package/dist/components/Drawer/native.css.d.ts.map +1 -0
  37. package/dist/components/Drawer/parts.css.d.ts +96 -0
  38. package/dist/components/Drawer/parts.css.d.ts.map +1 -0
  39. package/dist/components/Drawer/parts.d.ts +56 -0
  40. package/dist/components/Drawer/parts.d.ts.map +1 -0
  41. package/dist/components/Drawer/sheetPhysics.d.ts +56 -0
  42. package/dist/components/Drawer/sheetPhysics.d.ts.map +1 -0
  43. package/dist/components/Drawer/styles.css.d.ts +15 -58
  44. package/dist/components/Drawer/styles.css.d.ts.map +1 -1
  45. package/dist/components/Drawer/touchInput.d.ts +35 -0
  46. package/dist/components/Drawer/touchInput.d.ts.map +1 -0
  47. package/dist/components/Drawer/useDrawerRoot.d.ts +33 -0
  48. package/dist/components/Drawer/useDrawerRoot.d.ts.map +1 -0
  49. package/dist/components/Drawer/useSheetHeights.d.ts +7 -0
  50. package/dist/components/Drawer/useSheetHeights.d.ts.map +1 -0
  51. package/dist/components/Drawer/useSwipeDismiss.d.ts +13 -2
  52. package/dist/components/Drawer/useSwipeDismiss.d.ts.map +1 -1
  53. package/dist/components/Grid/styles.css.d.ts +1 -0
  54. package/dist/components/Grid/styles.css.d.ts.map +1 -1
  55. package/dist/components/Icon/Icon.d.ts +3 -9
  56. package/dist/components/Icon/Icon.d.ts.map +1 -1
  57. package/dist/components/Icon/geometry.d.ts +60 -0
  58. package/dist/components/Icon/geometry.d.ts.map +1 -0
  59. package/dist/components/Icon/types.d.ts +15 -0
  60. package/dist/components/Icon/types.d.ts.map +1 -0
  61. package/dist/components/Input/Input.d.ts +5 -1
  62. package/dist/components/Input/Input.d.ts.map +1 -1
  63. package/dist/components/Input/styles.css.d.ts +1 -0
  64. package/dist/components/Input/styles.css.d.ts.map +1 -1
  65. package/dist/components/LinkButton/styles.css.d.ts +1 -0
  66. package/dist/components/LinkButton/styles.css.d.ts.map +1 -1
  67. package/dist/components/Menu/Menu.d.ts +7 -1
  68. package/dist/components/Menu/Menu.d.ts.map +1 -1
  69. package/dist/components/Menu/native.css.d.ts +14 -0
  70. package/dist/components/Menu/native.css.d.ts.map +1 -0
  71. package/dist/components/Menu/useMenuOpen.d.ts +16 -0
  72. package/dist/components/Menu/useMenuOpen.d.ts.map +1 -0
  73. package/dist/components/Menu/useMenuRoot.d.ts +3 -6
  74. package/dist/components/Menu/useMenuRoot.d.ts.map +1 -1
  75. package/dist/components/Meter/styles.css.d.ts +1 -0
  76. package/dist/components/Meter/styles.css.d.ts.map +1 -1
  77. package/dist/components/PageShell/styles.css.d.ts +2 -0
  78. package/dist/components/PageShell/styles.css.d.ts.map +1 -1
  79. package/dist/components/Popover/native.css.d.ts +11 -0
  80. package/dist/components/Popover/native.css.d.ts.map +1 -0
  81. package/dist/components/RadioGroup/RadioGroup.d.ts +1 -17
  82. package/dist/components/RadioGroup/RadioGroup.d.ts.map +1 -1
  83. package/dist/components/RadioGroup/RadioGroup.stories.d.ts +3 -0
  84. package/dist/components/RadioGroup/RadioGroup.stories.d.ts.map +1 -1
  85. package/dist/components/RadioGroup/group.d.ts +31 -0
  86. package/dist/components/RadioGroup/group.d.ts.map +1 -0
  87. package/dist/components/RadioGroup/styles.css.d.ts +10 -0
  88. package/dist/components/RadioGroup/styles.css.d.ts.map +1 -1
  89. package/dist/components/ScrollArea/styles.css.d.ts +1 -0
  90. package/dist/components/ScrollArea/styles.css.d.ts.map +1 -1
  91. package/dist/components/SideNav/Chevron.d.ts +4 -0
  92. package/dist/components/SideNav/Chevron.d.ts.map +1 -0
  93. package/dist/components/SideNav/SideNav.d.ts.map +1 -1
  94. package/dist/components/SideNav/styles.css.d.ts +6 -0
  95. package/dist/components/SideNav/styles.css.d.ts.map +1 -1
  96. package/dist/components/SideNav/types.d.ts +6 -0
  97. package/dist/components/SideNav/types.d.ts.map +1 -0
  98. package/dist/components/Spinner/Spinner.d.ts +2 -6
  99. package/dist/components/Spinner/Spinner.d.ts.map +1 -1
  100. package/dist/components/Spinner/Spinner.types.d.ts +6 -0
  101. package/dist/components/Spinner/Spinner.types.d.ts.map +1 -0
  102. package/dist/components/Spinner/ring.css.d.ts +39 -0
  103. package/dist/components/Spinner/ring.css.d.ts.map +1 -0
  104. package/dist/components/Spinner/styles.css.d.ts +1 -28
  105. package/dist/components/Spinner/styles.css.d.ts.map +1 -1
  106. package/dist/components/SplitPane/SplitPane.d.ts +38 -0
  107. package/dist/components/SplitPane/SplitPane.d.ts.map +1 -0
  108. package/dist/components/SplitPane/SplitPane.meta.d.ts +3 -0
  109. package/dist/components/SplitPane/SplitPane.meta.d.ts.map +1 -0
  110. package/dist/components/SplitPane/SplitPane.stories.d.ts +17 -0
  111. package/dist/components/SplitPane/SplitPane.stories.d.ts.map +1 -0
  112. package/dist/components/SplitPane/styles.css.d.ts +78 -0
  113. package/dist/components/SplitPane/styles.css.d.ts.map +1 -0
  114. package/dist/components/StatusIcon/StatusIcon.d.ts.map +1 -1
  115. package/dist/components/StatusIcon/styles.css.d.ts +3 -0
  116. package/dist/components/StatusIcon/styles.css.d.ts.map +1 -1
  117. package/dist/components/Switch/Switch.d.ts +2 -18
  118. package/dist/components/Switch/Switch.d.ts.map +1 -1
  119. package/dist/components/Switch/Switch.types.d.ts +18 -0
  120. package/dist/components/Switch/Switch.types.d.ts.map +1 -0
  121. package/dist/components/TableOfContents/styles.css.d.ts +1 -0
  122. package/dist/components/TableOfContents/styles.css.d.ts.map +1 -1
  123. package/dist/components/Tabs/TabLayout.d.ts +7 -0
  124. package/dist/components/Tabs/TabLayout.d.ts.map +1 -0
  125. package/dist/components/Tabs/Tabs.d.ts.map +1 -1
  126. package/dist/components/Tabs/indicator.d.ts +28 -0
  127. package/dist/components/Tabs/indicator.d.ts.map +1 -0
  128. package/dist/components/Tabs/styles.css.d.ts +4 -0
  129. package/dist/components/Tabs/styles.css.d.ts.map +1 -1
  130. package/dist/components/Tabs/useTabIndicator.d.ts +4 -0
  131. package/dist/components/Tabs/useTabIndicator.d.ts.map +1 -0
  132. package/dist/components/Tabs/useTabKeys.d.ts +13 -0
  133. package/dist/components/Tabs/useTabKeys.d.ts.map +1 -0
  134. package/dist/components/Tag/RemoveGlyph.d.ts +4 -0
  135. package/dist/components/Tag/RemoveGlyph.d.ts.map +1 -0
  136. package/dist/components/Tag/Tag.d.ts +2 -24
  137. package/dist/components/Tag/Tag.d.ts.map +1 -1
  138. package/dist/components/Tag/styles.css.d.ts +8 -0
  139. package/dist/components/Tag/styles.css.d.ts.map +1 -1
  140. package/dist/components/Tag/types.d.ts +39 -0
  141. package/dist/components/Tag/types.d.ts.map +1 -0
  142. package/dist/components/Textarea/styles.css.d.ts +1 -0
  143. package/dist/components/Textarea/styles.css.d.ts.map +1 -1
  144. package/dist/components/Toast/ToastProvider.d.ts +2 -21
  145. package/dist/components/Toast/ToastProvider.d.ts.map +1 -1
  146. package/dist/components/Toast/native.css.d.ts +81 -0
  147. package/dist/components/Toast/native.css.d.ts.map +1 -0
  148. package/dist/components/Toast/store.d.ts +47 -0
  149. package/dist/components/Toast/store.d.ts.map +1 -0
  150. package/dist/components/Toggle/Toggle.d.ts.map +1 -1
  151. package/dist/components/Toggle/styles.css.d.ts +11 -2
  152. package/dist/components/Toggle/styles.css.d.ts.map +1 -1
  153. package/dist/components/Tooltip/TooltipHint.d.ts +9 -0
  154. package/dist/components/Tooltip/TooltipHint.d.ts.map +1 -0
  155. package/dist/components/Tree/Tree.d.ts.map +1 -1
  156. package/dist/components/Tree/styles.css.d.ts +6 -0
  157. package/dist/components/Tree/styles.css.d.ts.map +1 -1
  158. package/dist/components/Tree/useTreeKeyboard.d.ts +19 -0
  159. package/dist/components/Tree/useTreeKeyboard.d.ts.map +1 -0
  160. package/dist/components/VirtualList/VirtualList.d.ts +33 -0
  161. package/dist/components/VirtualList/VirtualList.d.ts.map +1 -0
  162. package/dist/components/VirtualList/VirtualList.meta.d.ts +3 -0
  163. package/dist/components/VirtualList/VirtualList.meta.d.ts.map +1 -0
  164. package/dist/components/VirtualList/VirtualList.stories.d.ts +15 -0
  165. package/dist/components/VirtualList/VirtualList.stories.d.ts.map +1 -0
  166. package/dist/components/VirtualList/styles.css.d.ts +28 -0
  167. package/dist/components/VirtualList/styles.css.d.ts.map +1 -0
  168. package/dist/components/VirtualTable/styles.css.d.ts +6 -0
  169. package/dist/components/VirtualTable/styles.css.d.ts.map +1 -1
  170. package/dist/index.css +1 -1
  171. package/dist/index.d.ts +3 -1
  172. package/dist/index.d.ts.map +1 -1
  173. package/dist/index.js +6202 -4794
  174. package/dist/index.js.map +1 -1
  175. package/dist/shared/ButtonHost.d.ts +11 -0
  176. package/dist/shared/ButtonHost.d.ts.map +1 -0
  177. package/dist/shared/portal/hostRegistry.d.ts +33 -0
  178. package/dist/shared/portal/hostRegistry.d.ts.map +1 -0
  179. package/dist/shared/pressableChild.d.ts +14 -0
  180. package/dist/shared/pressableChild.d.ts.map +1 -0
  181. package/dist/shared/useOverlayOpenState.d.ts +40 -0
  182. package/dist/shared/useOverlayOpenState.d.ts.map +1 -0
  183. package/dist/table.js +141 -135
  184. package/dist/table.js.map +1 -1
  185. package/package.json +34 -4
  186. package/src/components/Alert/Alert.tsx +14 -2
  187. package/src/components/AppShell/AppShell.meta.ts +1 -1
  188. package/src/components/AppShell/AppShell.native.tsx +174 -0
  189. package/src/components/AppShell/native.css.ts +56 -0
  190. package/src/components/Button/Button.tsx +6 -5
  191. package/src/components/Button/styles.css.ts +2 -0
  192. package/src/components/Callout/Callout.tsx +17 -3
  193. package/src/components/Callout/styles.css.ts +5 -0
  194. package/src/components/Checkbox/Checkbox.native.tsx +67 -0
  195. package/src/components/Checkbox/Checkbox.tsx +1 -50
  196. package/src/components/ConfirmDialog/ConfirmDialog.tsx +3 -0
  197. package/src/components/DetailPanel/DetailPanel.tsx +9 -45
  198. package/src/components/Dialog/Dialog.native.tsx +296 -0
  199. package/src/components/Dialog/Dialog.stories.tsx +71 -0
  200. package/src/components/Dialog/Dialog.tsx +41 -130
  201. package/src/components/Dialog/native.css.ts +78 -0
  202. package/src/components/Dialog/parts.css.ts +101 -0
  203. package/src/components/Dialog/parts.tsx +61 -0
  204. package/src/components/Dialog/styles.css.ts +2 -89
  205. package/src/components/Drawer/Drawer.meta.ts +2 -1
  206. package/src/components/Drawer/Drawer.native.tsx +469 -0
  207. package/src/components/Drawer/Drawer.tsx +63 -179
  208. package/src/components/Drawer/DrawerScroll.stories.tsx +4 -54
  209. package/src/components/Drawer/DrawerSnap.stories.tsx +205 -0
  210. package/src/components/Drawer/native.css.ts +58 -0
  211. package/src/components/Drawer/parts.css.ts +125 -0
  212. package/src/components/Drawer/parts.tsx +110 -0
  213. package/src/components/Drawer/sheetPhysics.ts +103 -0
  214. package/src/components/Drawer/styles.css.ts +19 -74
  215. package/src/components/Drawer/touchInput.ts +81 -0
  216. package/src/components/Drawer/useDrawerRoot.ts +90 -0
  217. package/src/components/Drawer/useSheetHeights.ts +42 -0
  218. package/src/components/Drawer/useSwipeDismiss.ts +146 -23
  219. package/src/components/Grid/styles.css.ts +2 -0
  220. package/src/components/Icon/Icon.native.tsx +54 -0
  221. package/src/components/Icon/Icon.tsx +19 -430
  222. package/src/components/Icon/geometry.ts +456 -0
  223. package/src/components/Icon/types.ts +74 -0
  224. package/src/components/Input/Input.tsx +8 -0
  225. package/src/components/Input/styles.css.ts +2 -0
  226. package/src/components/LinkButton/styles.css.ts +2 -0
  227. package/src/components/Menu/Menu.meta.ts +1 -1
  228. package/src/components/Menu/Menu.native.tsx +268 -0
  229. package/src/components/Menu/Menu.tsx +11 -2
  230. package/src/components/Menu/native.css.ts +18 -0
  231. package/src/components/Menu/useMenuOpen.ts +33 -0
  232. package/src/components/Menu/useMenuRoot.ts +7 -26
  233. package/src/components/Meter/styles.css.ts +2 -0
  234. package/src/components/PageShell/styles.css.ts +4 -0
  235. package/src/components/Popover/Popover.meta.ts +1 -1
  236. package/src/components/Popover/Popover.native.tsx +205 -0
  237. package/src/components/Popover/native.css.ts +13 -0
  238. package/src/components/RadioGroup/RadioGroup.meta.ts +1 -1
  239. package/src/components/RadioGroup/RadioGroup.native.tsx +48 -0
  240. package/src/components/RadioGroup/RadioGroup.stories.tsx +64 -1
  241. package/src/components/RadioGroup/RadioGroup.tsx +8 -83
  242. package/src/components/RadioGroup/group.tsx +85 -0
  243. package/src/components/RadioGroup/styles.css.ts +13 -0
  244. package/src/components/ScrollArea/styles.css.ts +2 -0
  245. package/src/components/SideNav/Chevron.native.tsx +20 -0
  246. package/src/components/SideNav/Chevron.tsx +20 -0
  247. package/src/components/SideNav/SideNav.meta.ts +1 -1
  248. package/src/components/SideNav/SideNav.tsx +57 -41
  249. package/src/components/SideNav/styles.css.ts +8 -0
  250. package/src/components/SideNav/types.ts +6 -0
  251. package/src/components/Spinner/Spinner.native.tsx +37 -0
  252. package/src/components/Spinner/Spinner.tsx +6 -15
  253. package/src/components/Spinner/Spinner.types.ts +6 -0
  254. package/src/components/Spinner/ring.css.ts +45 -0
  255. package/src/components/Spinner/styles.css.ts +2 -32
  256. package/src/components/SplitPane/SplitPane.meta.ts +40 -0
  257. package/src/components/SplitPane/SplitPane.native.tsx +47 -0
  258. package/src/components/SplitPane/SplitPane.stories.tsx +148 -0
  259. package/src/components/SplitPane/SplitPane.tsx +218 -0
  260. package/src/components/SplitPane/styles.css.ts +81 -0
  261. package/src/components/StatusIcon/StatusIcon.tsx +13 -2
  262. package/src/components/StatusIcon/styles.css.ts +5 -0
  263. package/src/components/Switch/Switch.native.tsx +45 -0
  264. package/src/components/Switch/Switch.tsx +22 -44
  265. package/src/components/Switch/Switch.types.ts +18 -0
  266. package/src/components/TableOfContents/styles.css.ts +2 -0
  267. package/src/components/Tabs/TabLayout.native.tsx +9 -0
  268. package/src/components/Tabs/TabLayout.tsx +6 -0
  269. package/src/components/Tabs/Tabs.meta.ts +1 -1
  270. package/src/components/Tabs/Tabs.tsx +38 -136
  271. package/src/components/Tabs/indicator.ts +36 -0
  272. package/src/components/Tabs/styles.css.ts +7 -0
  273. package/src/components/Tabs/useTabIndicator.native.ts +35 -0
  274. package/src/components/Tabs/useTabIndicator.ts +49 -0
  275. package/src/components/Tabs/useTabKeys.native.ts +2 -0
  276. package/src/components/Tabs/useTabKeys.ts +99 -0
  277. package/src/components/Tag/RemoveGlyph.native.tsx +17 -0
  278. package/src/components/Tag/RemoveGlyph.tsx +10 -0
  279. package/src/components/Tag/Tag.meta.ts +1 -1
  280. package/src/components/Tag/Tag.native.tsx +70 -0
  281. package/src/components/Tag/Tag.tsx +9 -37
  282. package/src/components/Tag/styles.css.ts +9 -0
  283. package/src/components/Tag/types.ts +43 -0
  284. package/src/components/Textarea/styles.css.ts +2 -0
  285. package/src/components/ThemeProvider/ThemeProvider.native.tsx +70 -10
  286. package/src/components/Toast/Toast.meta.ts +1 -1
  287. package/src/components/Toast/ToastProvider.native.tsx +226 -0
  288. package/src/components/Toast/ToastProvider.tsx +22 -84
  289. package/src/components/Toast/native.css.ts +78 -0
  290. package/src/components/Toast/store.ts +96 -0
  291. package/src/components/Toggle/Toggle.tsx +5 -3
  292. package/src/components/Toggle/styles.css.ts +14 -2
  293. package/src/components/Tooltip/Tooltip.meta.ts +1 -1
  294. package/src/components/Tooltip/Tooltip.native.tsx +36 -0
  295. package/src/components/Tooltip/TooltipHint.ts +13 -0
  296. package/src/components/Tree/Tree.meta.ts +1 -1
  297. package/src/components/Tree/Tree.tsx +23 -135
  298. package/src/components/Tree/styles.css.ts +6 -0
  299. package/src/components/Tree/useTreeKeyboard.native.ts +5 -0
  300. package/src/components/Tree/useTreeKeyboard.ts +152 -0
  301. package/src/components/VirtualList/VirtualList.meta.ts +39 -0
  302. package/src/components/VirtualList/VirtualList.stories.tsx +95 -0
  303. package/src/components/VirtualList/VirtualList.tsx +103 -0
  304. package/src/components/VirtualList/styles.css.ts +31 -0
  305. package/src/components/VirtualTable/styles.css.ts +12 -0
  306. package/src/hooks/useContainerBelow.native.ts +30 -0
  307. package/src/index.native.ts +61 -1
  308. package/src/index.ts +8 -1
  309. package/src/native-guard/globals.d.ts +10 -0
  310. package/src/native-guard/react-dom.d.ts +3 -0
  311. package/src/shared/ButtonHost.native.tsx +70 -0
  312. package/src/shared/ButtonHost.tsx +12 -0
  313. package/src/shared/accessibilityFocus.native.ts +23 -0
  314. package/src/shared/portal/AnchoredOverlay.native.tsx +117 -0
  315. package/src/shared/portal/OverlayModal.native.tsx +51 -0
  316. package/src/shared/portal/PortalHost.native.tsx +102 -0
  317. package/src/shared/portal/hostRegistry.ts +76 -0
  318. package/src/shared/portal/themeScope.native.ts +18 -0
  319. package/src/shared/pressableChild.ts +33 -0
  320. package/src/shared/safeArea.native.ts +22 -0
  321. package/src/shared/useKeyboardHeight.native.ts +18 -0
  322. package/src/shared/useOverlayOpenState.ts +128 -0
  323. package/src/shared/useScreenReaderEnabled.native.ts +19 -0
  324. package/dist/Table-ColfpgKV.js +0 -1552
  325. package/dist/Table-ColfpgKV.js.map +0 -1
  326. package/dist/components/ThemeProvider/ThemeProvider.native.d.ts +0 -10
  327. package/dist/components/ThemeProvider/ThemeProvider.native.d.ts.map +0 -1
  328. package/dist/index.native.d.ts +0 -33
  329. package/dist/index.native.d.ts.map +0 -1
  330. package/dist/platform.native.d.ts +0 -2
  331. package/dist/platform.native.d.ts.map +0 -1
@@ -0,0 +1,45 @@
1
+ import {useCallback} from 'react'
2
+ import {html} from 'react-strict-dom'
3
+ import {useControllableValue} from '../../hooks/useControllableValue'
4
+ import {styles} from './styles.css'
5
+ import type {SwitchProps} from './Switch.types'
6
+
7
+ export type {SwitchProps} from './Switch.types'
8
+
9
+ /**
10
+ * Native Switch: RSD has no `<input type="checkbox">` on native, so the track
11
+ * button carries the switch role. `name` and `value` have no form to submit
12
+ * to here.
13
+ */
14
+ export function Switch({
15
+ checked: controlledChecked,
16
+ defaultChecked = false,
17
+ onCheckedChange,
18
+ disabled = false,
19
+ children,
20
+ }: SwitchProps) {
21
+ const [checked, setChecked] = useControllableValue(
22
+ controlledChecked,
23
+ defaultChecked,
24
+ onCheckedChange,
25
+ )
26
+ const handleClick = useCallback(() => {
27
+ if (!disabled) setChecked(!checked)
28
+ }, [disabled, checked, setChecked])
29
+
30
+ return (
31
+ <html.label style={[styles.root, styles.nativeFlex, disabled && styles.rootDisabled]}>
32
+ <html.button
33
+ type="button"
34
+ role="switch"
35
+ aria-checked={checked}
36
+ disabled={disabled}
37
+ onClick={handleClick}
38
+ style={[styles.track, checked ? styles.trackChecked : styles.trackUnchecked]}
39
+ >
40
+ <html.span style={[styles.thumb, checked && styles.thumbChecked]} />
41
+ </html.button>
42
+ {children && <html.span>{children}</html.span>}
43
+ </html.label>
44
+ )
45
+ }
@@ -1,26 +1,11 @@
1
- import {type ReactNode, useCallback, useRef} from 'react'
1
+ import {useCallback, useRef} from 'react'
2
2
  import {html} from 'react-strict-dom'
3
- import {isNative} from '../../platform'
4
3
  import {useControllableValue} from '../../hooks/useControllableValue'
5
4
  import {styles} from './styles.css'
6
5
  import {visuallyHidden} from '../../styles/visually-hidden.css'
6
+ import type {SwitchProps} from './Switch.types'
7
7
 
8
- interface SwitchProps {
9
- /** Controlled checked state. */
10
- checked?: boolean
11
- /** Initial checked state (uncontrolled). */
12
- defaultChecked?: boolean
13
- /** Callback fired when the checked state changes. */
14
- onCheckedChange?: (checked: boolean) => void
15
- /** Prevents user interaction. */
16
- disabled?: boolean
17
- /** Form field name for the hidden input. */
18
- name?: string
19
- /** Value submitted when checked. */
20
- value?: string
21
- /** Label content rendered beside the switch. */
22
- children?: ReactNode
23
- }
8
+ export type {SwitchProps} from './Switch.types'
24
9
 
25
10
  export function Switch({
26
11
  checked: controlledChecked,
@@ -48,35 +33,28 @@ export function Switch({
48
33
  }, [disabled, checked, setChecked])
49
34
 
50
35
  return (
51
- <html.label
52
- style={[styles.root, isNative && styles.nativeFlex, disabled && styles.rootDisabled]}
53
- >
54
- {!isNative && (
55
- // Web: hidden real checkbox carries a11y + form submission. RSD has no
56
- // <input type=checkbox> on native, so it's omitted there and the
57
- // button below carries the switch role instead.
58
- <html.input
59
- ref={inputRef}
60
- type="checkbox"
61
- role="switch"
62
- name={name}
63
- value={value}
64
- checked={controlledChecked !== undefined ? controlledChecked : undefined}
65
- defaultChecked={controlledChecked === undefined ? defaultChecked : undefined}
66
- disabled={disabled}
67
- aria-checked={checked}
68
- onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
69
- onCheckedChange?.(e.target.checked)
70
- }}
71
- style={[visuallyHidden.base, styles.input]}
72
- />
73
- )}
36
+ <html.label style={[styles.root, disabled && styles.rootDisabled]}>
37
+ {/* The hidden real checkbox carries a11y and form submission (native:
38
+ Switch.native.tsx, whose button carries the switch role). */}
39
+ <html.input
40
+ ref={inputRef}
41
+ type="checkbox"
42
+ role="switch"
43
+ name={name}
44
+ value={value}
45
+ checked={controlledChecked !== undefined ? controlledChecked : undefined}
46
+ defaultChecked={controlledChecked === undefined ? defaultChecked : undefined}
47
+ disabled={disabled}
48
+ aria-checked={checked}
49
+ onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
50
+ onCheckedChange?.(e.target.checked)
51
+ }}
52
+ style={[visuallyHidden.base, styles.input]}
53
+ />
74
54
  <html.button
75
55
  type="button"
76
56
  tabIndex={-1}
77
- aria-hidden={isNative ? undefined : true}
78
- role={isNative ? 'switch' : undefined}
79
- aria-checked={isNative ? checked : undefined}
57
+ aria-hidden
80
58
  disabled={disabled}
81
59
  onClick={handleClick}
82
60
  style={[styles.track, checked ? styles.trackChecked : styles.trackUnchecked]}
@@ -0,0 +1,18 @@
1
+ import type {ReactNode} from 'react'
2
+
3
+ export interface SwitchProps {
4
+ /** Controlled checked state. */
5
+ checked?: boolean
6
+ /** Initial checked state (uncontrolled). */
7
+ defaultChecked?: boolean
8
+ /** Callback fired when the checked state changes. */
9
+ onCheckedChange?: (checked: boolean) => void
10
+ /** Prevents user interaction. */
11
+ disabled?: boolean
12
+ /** Form field name for the hidden input. */
13
+ name?: string
14
+ /** Value submitted when checked. */
15
+ value?: string
16
+ /** Label content rendered beside the switch. */
17
+ children?: ReactNode
18
+ }
@@ -94,6 +94,8 @@ export const styles = css.create({
94
94
  justifyContent: 'space-between',
95
95
  gap: spacing.sm,
96
96
  width: '100%',
97
+ // Native has no border-box reset (the web's global-reset.css); declare it.
98
+ boxSizing: 'border-box',
97
99
  minHeight: sizes.touchTarget,
98
100
  paddingTop: spacing.sm,
99
101
  paddingBottom: spacing.sm,
@@ -0,0 +1,9 @@
1
+ import type {ReactNode} from 'react'
2
+ import {View} from 'react-native'
3
+ import {useReportTabLayout} from './indicator'
4
+
5
+ /** Native: reports the tab's box to its List, which places the sliding indicator. */
6
+ export function TabLayout({value, children}: {value: string; children: ReactNode}) {
7
+ const report = useReportTabLayout()
8
+ return <View onLayout={(e) => report?.(value, e.nativeEvent.layout)}>{children}</View>
9
+ }
@@ -0,0 +1,6 @@
1
+ import type {ReactNode} from 'react'
2
+
3
+ /** Web: the tab itself; the List measures it in the DOM (TabLayout.native.tsx reports it). */
4
+ export function TabLayout({children}: {value: string; children: ReactNode}) {
5
+ return children
6
+ }
@@ -2,7 +2,7 @@ import type {ComponentMeta} from '../component-meta'
2
2
 
3
3
  export const meta: ComponentMeta = {
4
4
  description:
5
- 'Tabbed interface with keyboard navigation. Supports horizontal and vertical orientation. Compound component — Root is required.',
5
+ 'Tabbed interface with keyboard navigation. Supports horizontal and vertical orientation. Compound component — Root is required. On React Native the indicator follows each tab layout; there is no arrow-key navigation there, each tab is its own screen-reader stop.',
6
6
  whenToUse: [
7
7
  'Switching between content panels in the same view',
8
8
  'Settings pages with multiple sections',
@@ -1,8 +1,13 @@
1
- import {type ReactNode, useRef, useId, useEffect, useLayoutEffect, useState} from 'react'
1
+ import {type ReactNode, useRef, useId, useEffect} from 'react'
2
2
  import {html} from 'react-strict-dom'
3
3
  import {styles} from './styles.css'
4
+ import {isNative} from '../../platform'
4
5
  import {TabsContext, useTabs} from './TabsContext'
5
6
  import {useTabsRoot} from './useTabsRoot'
7
+ import {useTabIndicator} from './useTabIndicator'
8
+ import {useTabKeys} from './useTabKeys'
9
+ import {TabLayoutContext} from './indicator'
10
+ import {TabLayout} from './TabLayout'
6
11
 
7
12
  // --- Root ---
8
13
 
@@ -41,120 +46,14 @@ interface ListProps {
41
46
  function List({children}: ListProps) {
42
47
  const {orientation, activeValue, onSelect, tabsRef, orderRef, setIndicatorActive} = useTabs()
43
48
  const listRef = useRef<HTMLDivElement>(null)
44
- const [indicator, setIndicator] = useState<{offset: number; size: number} | null>(null)
45
49
 
46
- // Measure the active tab and drive the sliding indicator. useLayoutEffect so
47
- // the first position is set before paint (the indicator element mounts already
48
- // in place — no slide-in from zero; only later tab changes animate). Observes
49
- // the active tab (its own size, e.g. a changing "(3)" count) and the list
50
- // (container resize / reflow). A non-active sibling resizing while you're on
51
- // another tab is the one case not caught; it self-corrects on the next
52
- // selection or resize.
53
- useLayoutEffect(() => {
54
- const list = listRef.current
55
- if (!list || !activeValue) {
56
- setIndicator(null)
57
- setIndicatorActive(false)
58
- return
59
- }
60
- const el = list.querySelector<HTMLElement>(`[data-tab-value="${CSS.escape(activeValue)}"]`)
61
- if (!el) {
62
- setIndicator(null)
63
- setIndicatorActive(false)
64
- return
65
- }
66
- const measure = () => {
67
- setIndicator(
68
- orientation === 'horizontal'
69
- ? {offset: el.offsetLeft, size: el.offsetWidth}
70
- : {offset: el.offsetTop, size: el.offsetHeight},
71
- )
72
- setIndicatorActive(true)
73
- }
74
- measure()
75
- const ro = new ResizeObserver(measure)
76
- ro.observe(el)
77
- ro.observe(list)
78
- return () => ro.disconnect()
79
- }, [activeValue, orientation, setIndicatorActive])
80
-
81
- useEffect(() => {
82
- const el = listRef.current
83
- if (!el) return
84
- const listEl = el
85
-
86
- function handleKeyDown(e: KeyboardEvent) {
87
- const order = orderRef.current
88
- const tabs = tabsRef.current
89
- if (order.length === 0) return
90
-
91
- const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'
92
- const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'
93
-
94
- let targetValue: string | null = null
95
-
96
- switch (e.key) {
97
- case nextKey: {
98
- e.preventDefault()
99
- const currentIdx = activeValue ? order.indexOf(activeValue) : -1
100
- for (let i = 1; i <= order.length; i++) {
101
- const idx = (currentIdx + i) % order.length
102
- const val = order[idx]
103
- if (!tabs.get(val)) {
104
- targetValue = val
105
- break
106
- }
107
- }
108
- break
109
- }
110
- case prevKey: {
111
- e.preventDefault()
112
- const currentIdx = activeValue ? order.indexOf(activeValue) : 0
113
- for (let i = 1; i <= order.length; i++) {
114
- const idx = (currentIdx - i + order.length) % order.length
115
- const val = order[idx]
116
- if (!tabs.get(val)) {
117
- targetValue = val
118
- break
119
- }
120
- }
121
- break
122
- }
123
- case 'Home': {
124
- e.preventDefault()
125
- for (const val of order) {
126
- if (!tabs.get(val)) {
127
- targetValue = val
128
- break
129
- }
130
- }
131
- break
132
- }
133
- case 'End': {
134
- e.preventDefault()
135
- for (let i = order.length - 1; i >= 0; i--) {
136
- if (!tabs.get(order[i])) {
137
- targetValue = order[i]
138
- break
139
- }
140
- }
141
- break
142
- }
143
- }
144
-
145
- if (targetValue) {
146
- onSelect(targetValue)
147
- // Focus the newly activated tab button
148
- const tabEl = listEl.querySelector(
149
- `[data-tab-value="${targetValue}"]`,
150
- ) as HTMLElement | null
151
- tabEl?.focus()
152
- }
153
- }
154
-
155
- el.addEventListener('keydown', handleKeyDown)
156
- return () => el.removeEventListener('keydown', handleKeyDown)
157
- }, [orientation, activeValue, onSelect, tabsRef, orderRef])
50
+ const {indicator, reportTabLayout} = useTabIndicator({
51
+ listRef,
52
+ activeValue,
53
+ orientation,
54
+ setIndicatorActive,
55
+ })
56
+ useTabKeys({listRef, orientation, activeValue, onSelect, tabsRef, orderRef})
158
57
 
159
58
  return (
160
59
  <html.div
@@ -163,7 +62,7 @@ function List({children}: ListProps) {
163
62
  aria-orientation={orientation}
164
63
  style={[styles.list, orientation === 'vertical' && styles.listVertical]}
165
64
  >
166
- {children}
65
+ <TabLayoutContext.Provider value={reportTabLayout}>{children}</TabLayoutContext.Provider>
167
66
  {indicator && (
168
67
  <html.div
169
68
  aria-hidden
@@ -205,27 +104,30 @@ function Tab({value, disabled = false, children}: TabProps) {
205
104
  }
206
105
 
207
106
  return (
208
- <html.button
209
- type="button"
210
- role="tab"
211
- id={tabId}
212
- aria-selected={isActive}
213
- aria-controls={panelId}
214
- aria-disabled={disabled || undefined}
215
- data-tab-value={value}
216
- tabIndex={isActive ? 0 : -1}
217
- onClick={handleClick}
218
- style={[
219
- styles.tab,
220
- orientation === 'vertical' && styles.tabVertical,
221
- isActive &&
222
- (orientation === 'vertical' ? styles.tabActiveVertical : styles.tabActiveHorizontal),
223
- isActive && indicatorActive && styles.tabIndicatorActive,
224
- disabled && styles.tabDisabled,
225
- ]}
226
- >
227
- {children}
228
- </html.button>
107
+ <TabLayout value={value}>
108
+ <html.button
109
+ type="button"
110
+ role="tab"
111
+ id={tabId}
112
+ aria-selected={isActive}
113
+ aria-controls={panelId}
114
+ aria-disabled={disabled || undefined}
115
+ data-tab-value={value}
116
+ tabIndex={isActive ? 0 : -1}
117
+ onClick={handleClick}
118
+ style={[
119
+ styles.tab,
120
+ isNative && styles.nativeFlex,
121
+ orientation === 'vertical' && styles.tabVertical,
122
+ isActive &&
123
+ (orientation === 'vertical' ? styles.tabActiveVertical : styles.tabActiveHorizontal),
124
+ isActive && indicatorActive && styles.tabIndicatorActive,
125
+ disabled && styles.tabDisabled,
126
+ ]}
127
+ >
128
+ {children}
129
+ </html.button>
130
+ </TabLayout>
229
131
  )
230
132
  }
231
133
 
@@ -0,0 +1,36 @@
1
+ import {createContext, useContext} from 'react'
2
+ import type {Orientation} from '../../shared/types'
3
+
4
+ /** Where the sliding indicator sits along the list, in px. */
5
+ export interface IndicatorBox {
6
+ offset: number
7
+ size: number
8
+ }
9
+
10
+ /** A tab's box inside its list, as native `onLayout` reports it. */
11
+ export interface TabBox {
12
+ x: number
13
+ y: number
14
+ width: number
15
+ height: number
16
+ }
17
+
18
+ /** Native: each Tab reports its box here, so the List places the indicator. */
19
+ export const TabLayoutContext = createContext<((value: string, box: TabBox) => void) | null>(null)
20
+
21
+ export function useReportTabLayout() {
22
+ return useContext(TabLayoutContext)
23
+ }
24
+
25
+ export interface TabIndicatorInput {
26
+ listRef: React.RefObject<HTMLDivElement | null>
27
+ activeValue: string | null
28
+ orientation: Orientation
29
+ setIndicatorActive: (active: boolean) => void
30
+ }
31
+
32
+ export interface TabIndicator {
33
+ indicator: IndicatorBox | null
34
+ /** Native only: what the Tabs report their layout to. */
35
+ reportTabLayout: ((value: string, box: TabBox) => void) | null
36
+ }
@@ -32,6 +32,13 @@ export const styles = css.create({
32
32
  borderRightColor: colors.border,
33
33
  gap: 0,
34
34
  },
35
+ // RSD on native lays out only display: flex, not the web's inline-flex,
36
+ // and its Animated colour transition ends on a near-black colour: native
37
+ // tabs transition nothing that changes (colour and underline switch at once).
38
+ nativeFlex: {
39
+ display: 'flex',
40
+ transitionProperty: 'opacity',
41
+ },
35
42
  tab: {
36
43
  display: 'inline-flex',
37
44
  alignItems: 'center',
@@ -0,0 +1,35 @@
1
+ import {useCallback, useEffect, useState} from 'react'
2
+ import type {TabBox, TabIndicator, TabIndicatorInput} from './indicator'
3
+
4
+ /** Native: the indicator follows the active tab's `onLayout` box. */
5
+ export function useTabIndicator({
6
+ activeValue,
7
+ orientation,
8
+ setIndicatorActive,
9
+ }: TabIndicatorInput): TabIndicator {
10
+ const [boxes, setBoxes] = useState<ReadonlyMap<string, TabBox>>(() => new Map())
11
+ const reportTabLayout = useCallback((value: string, box: TabBox) => {
12
+ setBoxes((prev) => {
13
+ const old = prev.get(value)
14
+ if (
15
+ old &&
16
+ old.x === box.x &&
17
+ old.y === box.y &&
18
+ old.width === box.width &&
19
+ old.height === box.height
20
+ ) {
21
+ return prev
22
+ }
23
+ return new Map(prev).set(value, box)
24
+ })
25
+ }, [])
26
+ const box = activeValue ? boxes.get(activeValue) : undefined
27
+ const indicator = box
28
+ ? orientation === 'horizontal'
29
+ ? {offset: box.x, size: box.width}
30
+ : {offset: box.y, size: box.height}
31
+ : null
32
+ const active = indicator !== null
33
+ useEffect(() => setIndicatorActive(active), [active, setIndicatorActive])
34
+ return {indicator, reportTabLayout}
35
+ }
@@ -0,0 +1,49 @@
1
+ import {useLayoutEffect, useState} from 'react'
2
+ import type {IndicatorBox, TabIndicator, TabIndicatorInput} from './indicator'
3
+
4
+ /** Web: the active tab measured in the DOM, kept current by a ResizeObserver. */
5
+ export function useTabIndicator({
6
+ listRef,
7
+ activeValue,
8
+ orientation,
9
+ setIndicatorActive,
10
+ }: TabIndicatorInput): TabIndicator {
11
+ const [indicator, setIndicator] = useState<IndicatorBox | null>(null)
12
+
13
+ // Measure the active tab and drive the sliding indicator. useLayoutEffect so
14
+ // the first position is set before paint (the indicator element mounts already
15
+ // in place — no slide-in from zero; only later tab changes animate). Observes
16
+ // the active tab (its own size, e.g. a changing "(3)" count) and the list
17
+ // (container resize / reflow). A non-active sibling resizing while you're on
18
+ // another tab is the one case not caught; it self-corrects on the next
19
+ // selection or resize.
20
+ useLayoutEffect(() => {
21
+ const list = listRef.current
22
+ if (!list || !activeValue) {
23
+ setIndicator(null)
24
+ setIndicatorActive(false)
25
+ return
26
+ }
27
+ const el = list.querySelector<HTMLElement>(`[data-tab-value="${CSS.escape(activeValue)}"]`)
28
+ if (!el) {
29
+ setIndicator(null)
30
+ setIndicatorActive(false)
31
+ return
32
+ }
33
+ const measure = () => {
34
+ setIndicator(
35
+ orientation === 'horizontal'
36
+ ? {offset: el.offsetLeft, size: el.offsetWidth}
37
+ : {offset: el.offsetTop, size: el.offsetHeight},
38
+ )
39
+ setIndicatorActive(true)
40
+ }
41
+ measure()
42
+ const ro = new ResizeObserver(measure)
43
+ ro.observe(el)
44
+ ro.observe(list)
45
+ return () => ro.disconnect()
46
+ }, [listRef, activeValue, orientation, setIndicatorActive])
47
+
48
+ return {indicator, reportTabLayout: null}
49
+ }
@@ -0,0 +1,2 @@
1
+ /** Native has no arrow-key navigation (plan N0, Decision 6): each tab is its own stop. */
2
+ export function useTabKeys(_input: unknown) {}
@@ -0,0 +1,99 @@
1
+ import {useEffect} from 'react'
2
+ import type {Orientation} from '../../shared/types'
3
+
4
+ interface TabKeysInput {
5
+ listRef: React.RefObject<HTMLDivElement | null>
6
+ orientation: Orientation
7
+ activeValue: string | null
8
+ onSelect: (value: string) => void
9
+ tabsRef: React.RefObject<Map<string, boolean>>
10
+ orderRef: React.RefObject<string[]>
11
+ }
12
+
13
+ /** Web: arrow keys, Home and End move the selection and focus along the list. */
14
+ export function useTabKeys({
15
+ listRef,
16
+ orientation,
17
+ activeValue,
18
+ onSelect,
19
+ tabsRef,
20
+ orderRef,
21
+ }: TabKeysInput) {
22
+ useEffect(() => {
23
+ const el = listRef.current
24
+ if (!el) return
25
+ const listEl = el
26
+
27
+ function handleKeyDown(e: KeyboardEvent) {
28
+ const order = orderRef.current
29
+ const tabs = tabsRef.current
30
+ if (order.length === 0) return
31
+
32
+ const prevKey = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'
33
+ const nextKey = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'
34
+
35
+ let targetValue: string | null = null
36
+
37
+ switch (e.key) {
38
+ case nextKey: {
39
+ e.preventDefault()
40
+ const currentIdx = activeValue ? order.indexOf(activeValue) : -1
41
+ for (let i = 1; i <= order.length; i++) {
42
+ const idx = (currentIdx + i) % order.length
43
+ const val = order[idx]
44
+ if (!tabs.get(val)) {
45
+ targetValue = val
46
+ break
47
+ }
48
+ }
49
+ break
50
+ }
51
+ case prevKey: {
52
+ e.preventDefault()
53
+ const currentIdx = activeValue ? order.indexOf(activeValue) : 0
54
+ for (let i = 1; i <= order.length; i++) {
55
+ const idx = (currentIdx - i + order.length) % order.length
56
+ const val = order[idx]
57
+ if (!tabs.get(val)) {
58
+ targetValue = val
59
+ break
60
+ }
61
+ }
62
+ break
63
+ }
64
+ case 'Home': {
65
+ e.preventDefault()
66
+ for (const val of order) {
67
+ if (!tabs.get(val)) {
68
+ targetValue = val
69
+ break
70
+ }
71
+ }
72
+ break
73
+ }
74
+ case 'End': {
75
+ e.preventDefault()
76
+ for (let i = order.length - 1; i >= 0; i--) {
77
+ if (!tabs.get(order[i])) {
78
+ targetValue = order[i]
79
+ break
80
+ }
81
+ }
82
+ break
83
+ }
84
+ }
85
+
86
+ if (targetValue) {
87
+ onSelect(targetValue)
88
+ // Focus the newly activated tab button
89
+ const tabEl = listEl.querySelector(
90
+ `[data-tab-value="${targetValue}"]`,
91
+ ) as HTMLElement | null
92
+ tabEl?.focus()
93
+ }
94
+ }
95
+
96
+ el.addEventListener('keydown', handleKeyDown)
97
+ return () => el.removeEventListener('keydown', handleKeyDown)
98
+ }, [listRef, orientation, activeValue, onSelect, tabsRef, orderRef])
99
+ }
@@ -0,0 +1,17 @@
1
+ import Svg, {Path} from 'react-native-svg'
2
+ import {useResolvedColors} from '../ThemeProvider/ThemeProvider'
3
+ import type {RemoveGlyphProps} from './types'
4
+
5
+ /**
6
+ * The same cross as the web's, drawn with react-native-svg (the native icon
7
+ * renderer, plan N0 Decision 9) in the tag's resolved text colour: a raw
8
+ * host has no CSS `currentColor` to inherit.
9
+ */
10
+ export function RemoveGlyph({size, color}: RemoveGlyphProps) {
11
+ const stroke = useResolvedColors()[color]
12
+ return (
13
+ <Svg width={size} height={size} viewBox="0 0 12 12" fill="none" aria-hidden>
14
+ <Path d="M3 3l6 6M9 3l-6 6" stroke={stroke} strokeWidth={1.5} strokeLinecap="round" />
15
+ </Svg>
16
+ )
17
+ }
@@ -0,0 +1,10 @@
1
+ import type {RemoveGlyphProps} from './types'
2
+
3
+ /** The tag's remove cross: 1.5 strokes on a 12 box, drawn in the tag's text colour. */
4
+ export function RemoveGlyph({size}: RemoveGlyphProps) {
5
+ return (
6
+ <svg width={size} height={size} viewBox="0 0 12 12" fill="none">
7
+ <path d="M3 3l6 6M9 3l-6 6" stroke="currentColor" strokeWidth={1.5} strokeLinecap="round" />
8
+ </svg>
9
+ )
10
+ }
@@ -2,7 +2,7 @@ import type {ComponentMeta} from '../component-meta'
2
2
 
3
3
  export const meta: ComponentMeta = {
4
4
  description:
5
- 'Interactive tag/chip with optional remove button. Works standalone or inside TagGroup for collection management. Visually similar to Badge but supports interaction.',
5
+ 'Interactive tag/chip with optional remove button. Works standalone or inside TagGroup for collection management. Visually similar to Badge but supports interaction. On React Native a Tag stands alone (TagGroup is web only): the label and, when removable, a remove button named from a string label.',
6
6
  whenToUse: [
7
7
  'Removable items in a list (emails, categories)',
8
8
  'Inside TagGroup for editable tag collections',