@astryxdesign/core 0.1.1 → 0.1.2-canary.04e71b2

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 (631) hide show
  1. package/CHANGELOG.md +105 -0
  2. package/README.md +131 -13
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +11 -5
  5. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  6. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  7. package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
  8. package/dist/Banner/Banner.d.ts +7 -0
  9. package/dist/Banner/Banner.d.ts.map +1 -1
  10. package/dist/Banner/Banner.js +9 -2
  11. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
  12. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  13. package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
  14. package/dist/Button/Button.d.ts +12 -2
  15. package/dist/Button/Button.d.ts.map +1 -1
  16. package/dist/Button/Button.js +53 -17
  17. package/dist/Calendar/Calendar.d.ts +5 -4
  18. package/dist/Calendar/Calendar.d.ts.map +1 -1
  19. package/dist/Calendar/Calendar.js +82 -43
  20. package/dist/Calendar/hooks/index.d.ts +0 -2
  21. package/dist/Calendar/hooks/index.d.ts.map +1 -1
  22. package/dist/Calendar/hooks/index.js +1 -2
  23. package/dist/Calendar/index.d.ts +3 -3
  24. package/dist/Calendar/index.d.ts.map +1 -1
  25. package/dist/Calendar/index.js +1 -1
  26. package/dist/Calendar/styles.d.ts +3 -9
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +3 -11
  29. package/dist/Carousel/Carousel.d.ts.map +1 -1
  30. package/dist/Carousel/Carousel.js +17 -3
  31. package/dist/Center/Center.d.ts +11 -1
  32. package/dist/Center/Center.d.ts.map +1 -1
  33. package/dist/Center/Center.js +9 -3
  34. package/dist/Chat/ChatMessageList.d.ts +14 -1
  35. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  36. package/dist/Chat/ChatMessageList.js +2 -0
  37. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  38. package/dist/Chat/useTriggerMenu.js +4 -1
  39. package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
  40. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  41. package/dist/CheckboxInput/CheckboxInput.js +51 -9
  42. package/dist/CheckboxList/CheckboxList.d.ts +13 -1
  43. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  44. package/dist/CheckboxList/CheckboxList.js +39 -9
  45. package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
  46. package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
  47. package/dist/Citation/Citation.d.ts.map +1 -1
  48. package/dist/Citation/Citation.js +3 -3
  49. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  50. package/dist/CodeBlock/CodeBlock.js +49 -37
  51. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  52. package/dist/CommandPalette/CommandPalette.js +5 -5
  53. package/dist/ContextMenu/ContextMenu.d.ts +4 -5
  54. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  55. package/dist/ContextMenu/ContextMenu.js +93 -11
  56. package/dist/DateInput/DateInput.d.ts +23 -1
  57. package/dist/DateInput/DateInput.d.ts.map +1 -1
  58. package/dist/DateInput/DateInput.js +59 -8
  59. package/dist/DateRangeInput/DateRangeInput.d.ts +23 -1
  60. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  61. package/dist/DateRangeInput/DateRangeInput.js +42 -9
  62. package/dist/DateTimeInput/DateTimeInput.d.ts +35 -2
  63. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  64. package/dist/DateTimeInput/DateTimeInput.js +78 -15
  65. package/dist/Dialog/Dialog.d.ts.map +1 -1
  66. package/dist/Dialog/Dialog.js +12 -0
  67. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -8
  68. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  69. package/dist/DropdownMenu/DropdownMenu.js +42 -14
  70. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  71. package/dist/EmptyState/EmptyState.js +7 -1
  72. package/dist/Field/Field.d.ts +19 -2
  73. package/dist/Field/Field.d.ts.map +1 -1
  74. package/dist/Field/Field.js +4 -0
  75. package/dist/Field/FieldLabel.d.ts +21 -2
  76. package/dist/Field/FieldLabel.d.ts.map +1 -1
  77. package/dist/Field/FieldLabel.js +41 -26
  78. package/dist/FileInput/FileInput.d.ts +22 -1
  79. package/dist/FileInput/FileInput.d.ts.map +1 -1
  80. package/dist/FileInput/FileInput.js +56 -10
  81. package/dist/Grid/Grid.d.ts +11 -1
  82. package/dist/Grid/Grid.d.ts.map +1 -1
  83. package/dist/Grid/Grid.js +8 -0
  84. package/dist/HoverCard/HoverCard.d.ts +2 -2
  85. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  86. package/dist/HoverCard/HoverCard.js +18 -6
  87. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  88. package/dist/HoverCard/useHoverCard.js +7 -3
  89. package/dist/InputGroup/InputGroup.d.ts +2 -2
  90. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  91. package/dist/InputGroup/InputGroup.js +14 -5
  92. package/dist/InputGroup/InputGroupContext.d.ts +4 -0
  93. package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
  94. package/dist/InputGroup/InputGroupContext.js +2 -2
  95. package/dist/InputGroup/index.d.ts +1 -0
  96. package/dist/InputGroup/index.d.ts.map +1 -1
  97. package/dist/Kbd/Kbd.d.ts.map +1 -1
  98. package/dist/Kbd/Kbd.js +34 -2
  99. package/dist/Layer/anchorName.d.ts +20 -0
  100. package/dist/Layer/anchorName.d.ts.map +1 -0
  101. package/dist/Layer/anchorName.js +36 -0
  102. package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
  103. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  104. package/dist/Layer/layerAnimations.stylex.js +8 -4
  105. package/dist/Layer/useLayer.d.ts +29 -0
  106. package/dist/Layer/useLayer.d.ts.map +1 -1
  107. package/dist/Layer/useLayer.js +55 -11
  108. package/dist/Layout/Layout.d.ts +4 -11
  109. package/dist/Layout/Layout.d.ts.map +1 -1
  110. package/dist/Layout/Layout.js +10 -11
  111. package/dist/Layout/LayoutFooter.d.ts +2 -2
  112. package/dist/Layout/LayoutFooter.d.ts.map +1 -1
  113. package/dist/Layout/LayoutHeader.d.ts +2 -2
  114. package/dist/Layout/LayoutHeader.d.ts.map +1 -1
  115. package/dist/Layout/LayoutPanel.d.ts +2 -2
  116. package/dist/Layout/LayoutPanel.d.ts.map +1 -1
  117. package/dist/Layout/padding.stylex.d.ts +51 -0
  118. package/dist/Layout/padding.stylex.d.ts.map +1 -1
  119. package/dist/Layout/padding.stylex.js +63 -0
  120. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  121. package/dist/Lightbox/Lightbox.js +4 -2
  122. package/dist/Link/Link.d.ts +17 -2
  123. package/dist/Link/Link.d.ts.map +1 -1
  124. package/dist/Link/Link.js +20 -9
  125. package/dist/Link/LinkProvider.d.ts +1 -0
  126. package/dist/Link/LinkProvider.d.ts.map +1 -1
  127. package/dist/Link/LinkProvider.js +1 -0
  128. package/dist/Markdown/Markdown.d.ts.map +1 -1
  129. package/dist/Markdown/Markdown.js +18 -3
  130. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  131. package/dist/MobileNav/MobileNav.js +13 -0
  132. package/dist/MoreMenu/MoreMenu.d.ts +1 -7
  133. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  134. package/dist/MoreMenu/MoreMenu.js +0 -2
  135. package/dist/MultiSelector/MultiSelector.d.ts +25 -2
  136. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  137. package/dist/MultiSelector/MultiSelector.js +103 -22
  138. package/dist/MultiSelector/hooks.d.ts +12 -1
  139. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  140. package/dist/MultiSelector/hooks.js +14 -1
  141. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  142. package/dist/NavMenu/NavHeadingMenu.js +34 -3
  143. package/dist/NumberInput/NumberInput.d.ts +23 -2
  144. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  145. package/dist/NumberInput/NumberInput.js +62 -12
  146. package/dist/Pagination/Pagination.d.ts +1 -1
  147. package/dist/Pagination/Pagination.d.ts.map +1 -1
  148. package/dist/Pagination/Pagination.js +46 -28
  149. package/dist/Popover/usePopover.d.ts +25 -2
  150. package/dist/Popover/usePopover.d.ts.map +1 -1
  151. package/dist/Popover/usePopover.js +18 -6
  152. package/dist/PowerSearch/PowerSearch.d.ts +11 -1
  153. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  154. package/dist/PowerSearch/PowerSearch.js +6 -1
  155. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  156. package/dist/ProgressBar/ProgressBar.js +3 -5
  157. package/dist/RadioList/RadioList.d.ts +20 -2
  158. package/dist/RadioList/RadioList.d.ts.map +1 -1
  159. package/dist/RadioList/RadioList.js +105 -9
  160. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  161. package/dist/RadioList/RadioListItem.js +13 -2
  162. package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
  163. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  164. package/dist/SegmentedControl/SegmentedControl.js +78 -44
  165. package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
  166. package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
  167. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  168. package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
  169. package/dist/Selector/Selector.d.ts +22 -1
  170. package/dist/Selector/Selector.d.ts.map +1 -1
  171. package/dist/Selector/Selector.js +84 -23
  172. package/dist/Selector/hooks.d.ts +8 -1
  173. package/dist/Selector/hooks.d.ts.map +1 -1
  174. package/dist/Selector/hooks.js +14 -1
  175. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  176. package/dist/SideNav/SideNavItem.js +1 -1
  177. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  178. package/dist/Skeleton/Skeleton.js +8 -2
  179. package/dist/Slider/Slider.d.ts +21 -0
  180. package/dist/Slider/Slider.d.ts.map +1 -1
  181. package/dist/Slider/Slider.js +38 -11
  182. package/dist/Spinner/Spinner.d.ts.map +1 -1
  183. package/dist/Spinner/Spinner.js +1 -1
  184. package/dist/Stack/Stack.d.ts +38 -23
  185. package/dist/Stack/Stack.d.ts.map +1 -1
  186. package/dist/Stack/Stack.js +25 -1
  187. package/dist/Stack/StackItem.d.ts +12 -23
  188. package/dist/Stack/StackItem.d.ts.map +1 -1
  189. package/dist/Stack/StackItem.js +8 -1
  190. package/dist/Switch/Switch.d.ts +23 -2
  191. package/dist/Switch/Switch.d.ts.map +1 -1
  192. package/dist/Switch/Switch.js +41 -11
  193. package/dist/TabList/Tab.d.ts.map +1 -1
  194. package/dist/TabList/Tab.js +6 -0
  195. package/dist/TabList/TabList.d.ts +16 -4
  196. package/dist/TabList/TabList.d.ts.map +1 -1
  197. package/dist/TabList/TabList.js +86 -10
  198. package/dist/TabList/TabListContext.d.ts +5 -0
  199. package/dist/TabList/TabListContext.d.ts.map +1 -1
  200. package/dist/TabList/TabListContext.js +5 -0
  201. package/dist/TabList/TabMenu.d.ts.map +1 -1
  202. package/dist/TabList/TabMenu.js +6 -1
  203. package/dist/Table/BaseTable.d.ts.map +1 -1
  204. package/dist/Table/BaseTable.js +38 -16
  205. package/dist/Table/Table.d.ts.map +1 -1
  206. package/dist/Table/Table.js +36 -7
  207. package/dist/Table/TableCell.d.ts +8 -1
  208. package/dist/Table/TableCell.d.ts.map +1 -1
  209. package/dist/Table/TableCell.js +10 -10
  210. package/dist/Table/TableHeaderCell.d.ts +8 -1
  211. package/dist/Table/TableHeaderCell.d.ts.map +1 -1
  212. package/dist/Table/TableHeaderCell.js +16 -16
  213. package/dist/Table/TableRow.d.ts +6 -1
  214. package/dist/Table/TableRow.d.ts.map +1 -1
  215. package/dist/Table/TableRow.js +15 -7
  216. package/dist/Table/index.d.ts +4 -1
  217. package/dist/Table/index.d.ts.map +1 -1
  218. package/dist/Table/index.js +3 -2
  219. package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
  220. package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
  221. package/dist/Table/plugins/pagination/paginateData.js +8 -3
  222. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  223. package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
  224. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  225. package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
  226. package/dist/Table/plugins/stickyColumns/index.d.ts +3 -0
  227. package/dist/Table/plugins/stickyColumns/index.d.ts.map +1 -0
  228. package/dist/Table/plugins/stickyColumns/index.js +3 -0
  229. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts +25 -0
  230. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -0
  231. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +369 -0
  232. package/dist/Table/tableContextMenu.d.ts +33 -0
  233. package/dist/Table/tableContextMenu.d.ts.map +1 -0
  234. package/dist/Table/tableContextMenu.js +133 -0
  235. package/dist/Table/types.d.ts +161 -5
  236. package/dist/Table/types.d.ts.map +1 -1
  237. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  238. package/dist/Table/useBaseTablePlugins.js +1 -1
  239. package/dist/Text/text.stylex.d.ts +2 -2
  240. package/dist/Text/text.stylex.js +2 -2
  241. package/dist/TextArea/TextArea.d.ts +22 -1
  242. package/dist/TextArea/TextArea.d.ts.map +1 -1
  243. package/dist/TextArea/TextArea.js +41 -9
  244. package/dist/TextInput/TextInput.d.ts +23 -2
  245. package/dist/TextInput/TextInput.d.ts.map +1 -1
  246. package/dist/TextInput/TextInput.js +55 -10
  247. package/dist/TimeInput/TimeInput.d.ts +23 -1
  248. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  249. package/dist/TimeInput/TimeInput.js +53 -10
  250. package/dist/Timestamp/Timestamp.d.ts +1 -1
  251. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  252. package/dist/Timestamp/Timestamp.js +28 -3
  253. package/dist/Toast/Toast.d.ts.map +1 -1
  254. package/dist/Toast/Toast.js +14 -0
  255. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  256. package/dist/Toast/ToastViewport.js +132 -3
  257. package/dist/ToggleButton/ToggleButton.d.ts +7 -9
  258. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  259. package/dist/ToggleButton/ToggleButton.js +34 -57
  260. package/dist/Tokenizer/Tokenizer.d.ts +12 -1
  261. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  262. package/dist/Tokenizer/Tokenizer.js +27 -5
  263. package/dist/Toolbar/Toolbar.d.ts +3 -3
  264. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  265. package/dist/Toolbar/Toolbar.js +51 -7
  266. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  267. package/dist/Tooltip/useTooltip.js +57 -9
  268. package/dist/TreeList/TreeList.d.ts +1 -1
  269. package/dist/TreeList/TreeList.d.ts.map +1 -1
  270. package/dist/TreeList/TreeList.js +72 -2
  271. package/dist/TreeList/TreeListItem.d.ts +11 -1
  272. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  273. package/dist/TreeList/TreeListItem.js +51 -12
  274. package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
  275. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
  276. package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
  277. package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
  278. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  279. package/dist/Typeahead/BaseTypeahead.js +67 -6
  280. package/dist/Typeahead/Typeahead.d.ts +24 -1
  281. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  282. package/dist/Typeahead/Typeahead.js +29 -5
  283. package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
  284. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  285. package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
  286. package/dist/VisuallyHidden/index.d.ts +11 -0
  287. package/dist/VisuallyHidden/index.d.ts.map +1 -0
  288. package/dist/VisuallyHidden/index.js +13 -0
  289. package/dist/astryx.css +40 -1
  290. package/dist/astryx.umd.js +147 -0
  291. package/dist/astryx.umd.js.map +7 -0
  292. package/dist/hooks/focusableSelector.d.ts +22 -0
  293. package/dist/hooks/focusableSelector.d.ts.map +1 -0
  294. package/dist/hooks/focusableSelector.js +24 -0
  295. package/dist/hooks/index.d.ts +12 -2
  296. package/dist/hooks/index.d.ts.map +1 -1
  297. package/dist/hooks/index.js +7 -2
  298. package/dist/hooks/useAnnounce.d.ts +40 -0
  299. package/dist/hooks/useAnnounce.d.ts.map +1 -0
  300. package/dist/hooks/useAnnounce.js +142 -0
  301. package/dist/hooks/useClickableContainer.d.ts +16 -1
  302. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  303. package/dist/hooks/useClickableContainer.js +16 -4
  304. package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
  305. package/dist/hooks/useEntryAnimation.js +4 -4
  306. package/dist/hooks/useFocusTrap.d.ts +18 -0
  307. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  308. package/dist/hooks/useFocusTrap.js +87 -3
  309. package/dist/hooks/useGridFocus.d.ts +88 -1
  310. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  311. package/dist/hooks/useGridFocus.js +261 -62
  312. package/dist/hooks/useKeyboardHint.d.ts +82 -0
  313. package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
  314. package/dist/hooks/useKeyboardHint.js +220 -0
  315. package/dist/hooks/useListFocus.d.ts +78 -7
  316. package/dist/hooks/useListFocus.d.ts.map +1 -1
  317. package/dist/hooks/useListFocus.js +305 -52
  318. package/dist/hooks/useLongPress.d.ts +21 -0
  319. package/dist/hooks/useLongPress.d.ts.map +1 -0
  320. package/dist/hooks/useLongPress.js +89 -0
  321. package/dist/hooks/useTreeFocus.d.ts +157 -0
  322. package/dist/hooks/useTreeFocus.d.ts.map +1 -0
  323. package/dist/hooks/useTreeFocus.js +337 -0
  324. package/dist/hooks/useTypeahead.d.ts +63 -0
  325. package/dist/hooks/useTypeahead.d.ts.map +1 -0
  326. package/dist/hooks/useTypeahead.js +117 -0
  327. package/dist/index.d.ts +1 -0
  328. package/dist/index.d.ts.map +1 -1
  329. package/dist/index.js +1 -0
  330. package/dist/theme/generateThemeRules.js +1 -1
  331. package/dist/theme/syntax/SyntaxTheme.d.ts +1 -1
  332. package/dist/theme/syntax/SyntaxTheme.js +1 -1
  333. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  334. package/dist/theme/syntax/defineSyntaxTheme.js +2 -2
  335. package/dist/theme/syntax/presets.d.ts +1 -1
  336. package/dist/theme/syntax/presets.d.ts.map +1 -1
  337. package/dist/theme/syntax/presets.js +1 -1
  338. package/dist/theme/syntax/tokens.d.ts +1 -1
  339. package/dist/theme/syntax/tokens.js +1 -1
  340. package/dist/theme/types.d.ts +1 -1
  341. package/dist/utils/dateTypes.d.ts +12 -0
  342. package/dist/utils/dateTypes.d.ts.map +1 -1
  343. package/dist/utils/dateTypes.js +41 -1
  344. package/dist/utils/index.d.ts +4 -0
  345. package/dist/utils/index.d.ts.map +1 -1
  346. package/dist/utils/index.js +3 -1
  347. package/dist/utils/inputAria.d.ts +29 -0
  348. package/dist/utils/inputAria.d.ts.map +1 -0
  349. package/dist/utils/inputAria.js +30 -0
  350. package/dist/utils/timeParser.d.ts.map +1 -1
  351. package/dist/utils/timeParser.js +5 -2
  352. package/package.json +15 -5
  353. package/src/Avatar/Avatar.test.tsx +37 -0
  354. package/src/Avatar/Avatar.tsx +10 -5
  355. package/src/AvatarGroup/AvatarGroupOverflow.tsx +3 -0
  356. package/src/Banner/Banner.doc.mjs +8 -0
  357. package/src/Banner/Banner.test.tsx +16 -7
  358. package/src/Banner/Banner.tsx +9 -2
  359. package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
  360. package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
  361. package/src/Button/Button.doc.mjs +6 -0
  362. package/src/Button/Button.test.tsx +105 -11
  363. package/src/Button/Button.tsx +76 -21
  364. package/src/Calendar/Calendar.doc.mjs +4 -4
  365. package/src/Calendar/Calendar.test.tsx +168 -30
  366. package/src/Calendar/Calendar.tsx +121 -66
  367. package/src/Calendar/hooks/index.ts +0 -6
  368. package/src/Calendar/index.ts +1 -3
  369. package/src/Calendar/styles.ts +4 -9
  370. package/src/Carousel/Carousel.doc.mjs +7 -1
  371. package/src/Carousel/Carousel.test.tsx +20 -0
  372. package/src/Carousel/Carousel.tsx +16 -1
  373. package/src/Center/Center.doc.mjs +12 -2
  374. package/src/Center/Center.tsx +28 -3
  375. package/src/Chat/ChatComposer.doc.mjs +3 -0
  376. package/src/Chat/ChatComposerDrawer.doc.mjs +12 -0
  377. package/src/Chat/ChatMessageList.doc.mjs +8 -0
  378. package/src/Chat/ChatMessageList.test.tsx +18 -0
  379. package/src/Chat/ChatMessageList.tsx +16 -0
  380. package/src/Chat/useTriggerMenu.tsx +3 -0
  381. package/src/CheckboxInput/CheckboxInput.doc.mjs +18 -0
  382. package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
  383. package/src/CheckboxInput/CheckboxInput.tsx +78 -6
  384. package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
  385. package/src/CheckboxList/CheckboxList.test.tsx +169 -16
  386. package/src/CheckboxList/CheckboxList.tsx +56 -3
  387. package/src/CheckboxList/CheckboxListContext.tsx +7 -0
  388. package/src/Citation/Citation.doc.mjs +10 -0
  389. package/src/Citation/Citation.test.tsx +117 -0
  390. package/src/Citation/Citation.tsx +9 -1
  391. package/src/ClickableCard/ClickableCard.doc.mjs +15 -0
  392. package/src/CodeBlock/CodeBlock.test.tsx +115 -0
  393. package/src/CodeBlock/CodeBlock.tsx +61 -33
  394. package/src/CommandPalette/CommandPalette.test.tsx +47 -1
  395. package/src/CommandPalette/CommandPalette.tsx +9 -21
  396. package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
  397. package/src/ContextMenu/ContextMenu.test.tsx +155 -1
  398. package/src/ContextMenu/ContextMenu.tsx +113 -16
  399. package/src/DateInput/DateInput.doc.mjs +281 -56
  400. package/src/DateInput/DateInput.test.tsx +188 -2
  401. package/src/DateInput/DateInput.tsx +89 -10
  402. package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
  403. package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
  404. package/src/DateRangeInput/DateRangeInput.tsx +63 -5
  405. package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
  406. package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
  407. package/src/DateTimeInput/DateTimeInput.tsx +125 -17
  408. package/src/Dialog/Dialog.doc.mjs +2 -2
  409. package/src/Dialog/Dialog.tsx +12 -0
  410. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
  411. package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
  412. package/src/DropdownMenu/DropdownMenu.tsx +52 -18
  413. package/src/EmptyState/EmptyState.test.tsx +4 -2
  414. package/src/EmptyState/EmptyState.tsx +6 -2
  415. package/src/Field/Field.test.tsx +32 -0
  416. package/src/Field/Field.tsx +23 -5
  417. package/src/Field/FieldLabel.tsx +55 -17
  418. package/src/FileInput/FileInput.doc.mjs +17 -0
  419. package/src/FileInput/FileInput.test.tsx +283 -49
  420. package/src/FileInput/FileInput.tsx +76 -4
  421. package/src/Grid/Grid.doc.mjs +14 -4
  422. package/src/Grid/Grid.tsx +20 -0
  423. package/src/HoverCard/HoverCard.doc.mjs +3 -0
  424. package/src/HoverCard/HoverCard.test.tsx +189 -2
  425. package/src/HoverCard/HoverCard.tsx +20 -16
  426. package/src/HoverCard/useHoverCard.tsx +13 -10
  427. package/src/Icon/Icon.doc.mjs +8 -0
  428. package/src/InputGroup/InputGroup.doc.mjs +2 -2
  429. package/src/InputGroup/InputGroup.test.tsx +98 -60
  430. package/src/InputGroup/InputGroup.tsx +21 -4
  431. package/src/InputGroup/InputGroupContext.ts +9 -4
  432. package/src/InputGroup/index.ts +1 -0
  433. package/src/Kbd/Kbd.test.tsx +22 -4
  434. package/src/Kbd/Kbd.tsx +37 -12
  435. package/src/Layer/anchorName.test.ts +146 -0
  436. package/src/Layer/anchorName.ts +46 -0
  437. package/src/Layer/layerAnimations.stylex.ts +20 -4
  438. package/src/Layer/useLayer.doc.mjs +12 -2
  439. package/src/Layer/useLayer.tsx +100 -15
  440. package/src/Layout/Layout.doc.mjs +1 -1
  441. package/src/Layout/Layout.tsx +8 -16
  442. package/src/Layout/LayoutFooter.doc.mjs +4 -4
  443. package/src/Layout/LayoutFooter.tsx +3 -3
  444. package/src/Layout/LayoutHeader.doc.mjs +4 -4
  445. package/src/Layout/LayoutHeader.tsx +3 -3
  446. package/src/Layout/LayoutPanel.tsx +3 -3
  447. package/src/Layout/padding.stylex.ts +52 -0
  448. package/src/Lightbox/Lightbox.doc.mjs +9 -2
  449. package/src/Lightbox/Lightbox.test.tsx +53 -5
  450. package/src/Lightbox/Lightbox.tsx +9 -4
  451. package/src/Link/Link.doc.mjs +14 -0
  452. package/src/Link/Link.test.tsx +52 -2
  453. package/src/Link/Link.tsx +42 -7
  454. package/src/Link/LinkProvider.tsx +1 -0
  455. package/src/List/List.doc.mjs +7 -0
  456. package/src/Markdown/Markdown.doc.mjs +2 -0
  457. package/src/Markdown/Markdown.test.tsx +28 -26
  458. package/src/Markdown/Markdown.tsx +21 -6
  459. package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
  460. package/src/MobileNav/MobileNav.doc.mjs +8 -8
  461. package/src/MobileNav/MobileNav.tsx +13 -0
  462. package/src/MobileNav/MobileNavReopen.test.tsx +118 -0
  463. package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
  464. package/src/MoreMenu/MoreMenu.tsx +0 -9
  465. package/src/MultiSelector/MultiSelector.doc.mjs +25 -0
  466. package/src/MultiSelector/MultiSelector.test.tsx +375 -8
  467. package/src/MultiSelector/MultiSelector.tsx +145 -21
  468. package/src/MultiSelector/hooks.ts +27 -0
  469. package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
  470. package/src/NavMenu/NavHeadingMenu.tsx +50 -3
  471. package/src/NumberInput/NumberInput.doc.mjs +17 -0
  472. package/src/NumberInput/NumberInput.test.tsx +242 -40
  473. package/src/NumberInput/NumberInput.tsx +89 -11
  474. package/src/OverflowList/OverflowList.doc.mjs +17 -0
  475. package/src/Pagination/Pagination.doc.mjs +3 -3
  476. package/src/Pagination/Pagination.test.tsx +250 -14
  477. package/src/Pagination/Pagination.tsx +54 -29
  478. package/src/Popover/usePopover.doc.mjs +7 -3
  479. package/src/Popover/usePopover.tsx +49 -6
  480. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  481. package/src/PowerSearch/PowerSearch.test.tsx +97 -1
  482. package/src/PowerSearch/PowerSearch.tsx +16 -3
  483. package/src/ProgressBar/ProgressBar.test.tsx +45 -27
  484. package/src/ProgressBar/ProgressBar.tsx +3 -4
  485. package/src/RadioList/RadioList.doc.mjs +9 -0
  486. package/src/RadioList/RadioList.test.tsx +252 -16
  487. package/src/RadioList/RadioList.tsx +166 -10
  488. package/src/RadioList/RadioListItem.tsx +14 -2
  489. package/src/Resizable/Resizable.doc.mjs +1 -1
  490. package/src/Section/Section.doc.mjs +11 -0
  491. package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
  492. package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
  493. package/src/SegmentedControl/SegmentedControl.tsx +102 -54
  494. package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
  495. package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
  496. package/src/SelectableCard/SelectableCard.doc.mjs +15 -0
  497. package/src/Selector/Selector.doc.mjs +25 -0
  498. package/src/Selector/Selector.test.tsx +322 -15
  499. package/src/Selector/Selector.tsx +126 -40
  500. package/src/Selector/hooks.ts +23 -0
  501. package/src/SideNav/SideNav.test.tsx +16 -0
  502. package/src/SideNav/SideNavItem.tsx +2 -4
  503. package/src/Skeleton/Skeleton.doc.mjs +11 -1
  504. package/src/Skeleton/Skeleton.test.tsx +25 -0
  505. package/src/Skeleton/Skeleton.tsx +11 -1
  506. package/src/Slider/Slider.doc.mjs +19 -0
  507. package/src/Slider/Slider.test.tsx +158 -18
  508. package/src/Slider/Slider.tsx +54 -6
  509. package/src/Spinner/Spinner.tsx +7 -1
  510. package/src/Stack/Stack.doc.mjs +77 -0
  511. package/src/Stack/Stack.test.tsx +55 -5
  512. package/src/Stack/Stack.tsx +73 -24
  513. package/src/Stack/StackItem.test.tsx +23 -0
  514. package/src/Stack/StackItem.tsx +20 -23
  515. package/src/Switch/Switch.doc.mjs +15 -0
  516. package/src/Switch/Switch.test.tsx +162 -27
  517. package/src/Switch/Switch.tsx +61 -21
  518. package/src/TabList/Tab.tsx +6 -0
  519. package/src/TabList/TabList.doc.mjs +12 -0
  520. package/src/TabList/TabList.test.tsx +208 -0
  521. package/src/TabList/TabList.tsx +102 -12
  522. package/src/TabList/TabListContext.ts +7 -3
  523. package/src/TabList/TabMenu.tsx +6 -3
  524. package/src/Table/BaseTable.tsx +72 -41
  525. package/src/Table/Table.doc.mjs +14 -0
  526. package/src/Table/Table.test.tsx +39 -30
  527. package/src/Table/Table.tsx +27 -1
  528. package/src/Table/TableCell.tsx +25 -23
  529. package/src/Table/TableHeaderCell.tsx +28 -29
  530. package/src/Table/TableRow.tsx +37 -7
  531. package/src/Table/index.ts +6 -2
  532. package/src/Table/plugins/pagination/paginateData.ts +10 -3
  533. package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
  534. package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
  535. package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
  536. package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
  537. package/src/Table/plugins/stickyColumns/index.ts +4 -0
  538. package/src/Table/plugins/stickyColumns/useTableStickyColumns.test.tsx +163 -0
  539. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +407 -0
  540. package/src/Table/tableContextMenu.test.tsx +157 -0
  541. package/src/Table/tableContextMenu.tsx +142 -0
  542. package/src/Table/types.ts +175 -4
  543. package/src/Table/useBaseTablePlugins.ts +1 -0
  544. package/src/Table/useTableColumnResize.doc.mjs +96 -0
  545. package/src/Table/useTableStickyColumns.doc.mjs +59 -0
  546. package/src/Text/Heading.doc.mjs +15 -2
  547. package/src/Text/Text.doc.mjs +7 -1
  548. package/src/Text/text.stylex.ts +2 -2
  549. package/src/TextArea/TextArea.doc.mjs +17 -0
  550. package/src/TextArea/TextArea.test.tsx +167 -35
  551. package/src/TextArea/TextArea.tsx +62 -15
  552. package/src/TextInput/TextInput.doc.mjs +17 -0
  553. package/src/TextInput/TextInput.test.tsx +168 -34
  554. package/src/TextInput/TextInput.tsx +77 -9
  555. package/src/TimeInput/TimeInput.doc.mjs +335 -60
  556. package/src/TimeInput/TimeInput.test.tsx +144 -7
  557. package/src/TimeInput/TimeInput.tsx +74 -5
  558. package/src/Timestamp/Timestamp.doc.mjs +9 -0
  559. package/src/Timestamp/Timestamp.test.tsx +44 -18
  560. package/src/Timestamp/Timestamp.tsx +30 -10
  561. package/src/Toast/Toast.tsx +14 -0
  562. package/src/Toast/ToastViewport.test.tsx +204 -0
  563. package/src/Toast/ToastViewport.tsx +167 -21
  564. package/src/ToggleButton/ToggleButton.doc.mjs +9 -3
  565. package/src/ToggleButton/ToggleButton.test.tsx +39 -18
  566. package/src/ToggleButton/ToggleButton.tsx +46 -83
  567. package/src/Tokenizer/Tokenizer.doc.mjs +15 -0
  568. package/src/Tokenizer/Tokenizer.test.tsx +105 -1
  569. package/src/Tokenizer/Tokenizer.tsx +41 -2
  570. package/src/Toolbar/Toolbar.doc.mjs +65 -5
  571. package/src/Toolbar/Toolbar.test.tsx +109 -6
  572. package/src/Toolbar/Toolbar.tsx +59 -5
  573. package/src/Tooltip/Tooltip.test.tsx +81 -0
  574. package/src/Tooltip/useTooltip.tsx +57 -11
  575. package/src/TreeList/TreeList.test.tsx +295 -6
  576. package/src/TreeList/TreeList.tsx +73 -1
  577. package/src/TreeList/TreeListItem.tsx +51 -5
  578. package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
  579. package/src/Typeahead/BaseTypeahead.tsx +86 -9
  580. package/src/Typeahead/Typeahead.doc.mjs +136 -30
  581. package/src/Typeahead/Typeahead.test.tsx +331 -1
  582. package/src/Typeahead/Typeahead.tsx +52 -1
  583. package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
  584. package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
  585. package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
  586. package/src/VisuallyHidden/index.ts +15 -0
  587. package/src/hooks/focusableSelector.ts +25 -0
  588. package/src/hooks/index.ts +28 -2
  589. package/src/hooks/useAnnounce.test.tsx +101 -0
  590. package/src/hooks/useAnnounce.ts +168 -0
  591. package/src/hooks/useClickableContainer.ts +16 -4
  592. package/src/hooks/useEntryAnimation.ts +16 -4
  593. package/src/hooks/useFocusTrap.test.tsx +132 -0
  594. package/src/hooks/useFocusTrap.ts +98 -4
  595. package/src/hooks/useGridFocus.doc.mjs +40 -2
  596. package/src/hooks/useGridFocus.test.tsx +132 -0
  597. package/src/hooks/useGridFocus.ts +343 -67
  598. package/src/hooks/useImageMode.test.ts +133 -0
  599. package/src/hooks/useKeyboardHint.doc.mjs +101 -0
  600. package/src/hooks/useKeyboardHint.test.tsx +70 -0
  601. package/src/hooks/useKeyboardHint.tsx +332 -0
  602. package/src/hooks/useListFocus.doc.mjs +50 -10
  603. package/src/hooks/useListFocus.test.tsx +375 -0
  604. package/src/hooks/useListFocus.ts +395 -57
  605. package/src/hooks/useLongPress.test.tsx +134 -0
  606. package/src/hooks/useLongPress.ts +119 -0
  607. package/src/hooks/useTreeFocus.doc.mjs +140 -0
  608. package/src/hooks/useTreeFocus.test.tsx +214 -0
  609. package/src/hooks/useTreeFocus.ts +559 -0
  610. package/src/hooks/useTypeahead.test.tsx +109 -0
  611. package/src/hooks/useTypeahead.ts +183 -0
  612. package/src/index.ts +1 -0
  613. package/src/theme/derivedVarRegistry.test.ts +4 -0
  614. package/src/theme/generateThemeRules.test.ts +7 -8
  615. package/src/theme/generateThemeRules.ts +1 -1
  616. package/src/theme/syntax/SyntaxTheme.tsx +1 -1
  617. package/src/theme/syntax/defineSyntaxTheme.ts +20 -11
  618. package/src/theme/syntax/presets.ts +5 -2
  619. package/src/theme/syntax/tokens.ts +1 -1
  620. package/src/theme/types.ts +1 -1
  621. package/src/utils/dateTypes.test.ts +40 -0
  622. package/src/utils/dateTypes.ts +40 -0
  623. package/src/utils/index.ts +9 -0
  624. package/src/utils/inputAria.test.ts +39 -0
  625. package/src/utils/inputAria.ts +58 -0
  626. package/src/utils/timeParser.test.ts +10 -0
  627. package/src/utils/timeParser.ts +5 -2
  628. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
  629. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
  630. package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
  631. package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file Switch.tsx
7
- * @input Uses React, useId, ChangeEvent, FieldLabel, FieldStatus, IconType, InputStatus
7
+ * @input Uses React, useId, ChangeEvent, FieldLabel, FieldStatus, IconType, InputStatus, useTooltip
8
8
  * @output Exports Switch component, SwitchProps, SwitchLabelPosition, SwitchLabelSpacing
9
9
  * @position Core implementation; consumed by index.ts, tested by Switch.test.tsx
10
10
  *
@@ -39,11 +39,13 @@ import {FieldStatus} from '../FieldStatus/FieldStatus';
39
39
  import type {IconType} from '../Icon';
40
40
  import type {InputStatus} from '../Field/types';
41
41
  import {Spinner} from '../Spinner';
42
- import {mergeProps} from '../utils';
42
+ import {useTooltip} from '../Tooltip';
43
+ import {mergeProps, mergeRefs} from '../utils';
43
44
  import {switchScope} from './switch.markers.stylex';
44
45
  import type {BaseProps} from '../BaseProps';
45
46
  import type {SizeValue} from '../utils/types';
46
47
  import {themeProps} from '../utils/themeProps';
48
+ import {VisuallyHidden} from '../VisuallyHidden';
47
49
 
48
50
  // Fixed dimensions: 40px width, 24px height, 16px thumb (off), 20px thumb (on)
49
51
  const SWITCH_WIDTH = 40;
@@ -179,17 +181,6 @@ const styles = stylex.create({
179
181
  fontSize: typeScaleVars['--text-supporting-size'],
180
182
  color: colorVars['--color-text-secondary'],
181
183
  },
182
- srOnly: {
183
- position: 'absolute',
184
- width: 1,
185
- height: 1,
186
- padding: 0,
187
- margin: -1,
188
- overflow: 'hidden',
189
- clip: 'rect(0, 0, 0, 0)',
190
- whiteSpace: 'nowrap',
191
- borderWidth: 0,
192
- },
193
184
  });
194
185
 
195
186
  export type SwitchLabelPosition = 'start' | 'end';
@@ -237,6 +228,27 @@ export interface SwitchProps extends Omit<BaseProps, 'onChange'> {
237
228
  * @default false
238
229
  */
239
230
  isDisabled?: boolean;
231
+ /**
232
+ * Explains why the switch is disabled. When set together with `isDisabled`,
233
+ * the switch shows a tooltip with this text on hover and keyboard focus, and
234
+ * the control stays focusable (via `aria-disabled`) so the reason is
235
+ * discoverable by keyboard and assistive technology. Activation stays
236
+ * blocked.
237
+ *
238
+ * Use this instead of wrapping a disabled switch in `Tooltip` — disabled
239
+ * controls don't emit the pointer events an external tooltip needs.
240
+ *
241
+ * @example
242
+ * ```
243
+ * <Switch
244
+ * label="Enable notifications"
245
+ * value={enabled}
246
+ * isDisabled
247
+ * disabledMessage="Notifications are turned off org-wide"
248
+ * />
249
+ * ```
250
+ */
251
+ disabledMessage?: string;
240
252
  /**
241
253
  * Whether the field is optional. Mutually exclusive with isRequired.
242
254
  * @default false
@@ -322,6 +334,7 @@ export function Switch({
322
334
  isLoading = false,
323
335
  value,
324
336
  isDisabled = false,
337
+ disabledMessage,
325
338
  isOptional = false,
326
339
  isRequired = false,
327
340
  onFocus,
@@ -347,6 +360,19 @@ export function Switch({
347
360
 
348
361
  const isOn = optimisticValue === true;
349
362
 
363
+ // Disabled-reason tooltip. Disabled controls swallow pointer events, so the
364
+ // tooltip listeners attach to the switch row (which already exists) and the
365
+ // native checkbox stays perceivable via aria-disabled instead of the disabled
366
+ // attribute. Toggling is blocked by the isDisabled guard in onChange.
367
+ const showsDisabledMessage = isDisabled && !!disabledMessage;
368
+ const disabledMessageTooltip = useTooltip({
369
+ placement: 'above',
370
+ // The container row is not naturally focusable; focusin bubbles up from the
371
+ // native input, so always attach focus listeners.
372
+ focusTrigger: 'always',
373
+ isEnabled: showsDisabledMessage,
374
+ });
375
+
350
376
  // Build aria-describedby from description and status message
351
377
  // Only include descriptionID when the element actually renders
352
378
  const describedByParts: string[] = [];
@@ -356,21 +382,28 @@ export function Switch({
356
382
  if (status?.message) {
357
383
  describedByParts.push(statusMessageID);
358
384
  }
385
+ if (showsDisabledMessage) {
386
+ describedByParts.push(disabledMessageTooltip.describedBy);
387
+ }
359
388
  const ariaDescribedBy =
360
389
  describedByParts.length > 0 ? describedByParts.join(' ') : undefined;
361
390
 
362
391
  const switchElement = (
363
392
  <div {...stylex.props(styles.switchWrapper)}>
364
393
  <input
365
- ref={ref}
394
+ ref={mergeRefs(ref, disabledMessageTooltip.positionRef)}
366
395
  id={id}
367
396
  type="checkbox"
368
397
  role="switch"
369
398
  checked={isOn}
370
- disabled={isDisabled}
399
+ // With a disabledMessage the switch keeps focusability via aria-disabled
400
+ // so the reason is focus-discoverable; toggling is still blocked by the
401
+ // isDisabled guard in onChange below.
402
+ disabled={isDisabled && !showsDisabledMessage}
403
+ aria-disabled={showsDisabledMessage ? 'true' : undefined}
371
404
  required={isRequired}
372
405
  onChange={e => {
373
- if (isBusy) {
406
+ if (isDisabled || isBusy) {
374
407
  return;
375
408
  }
376
409
  const checked = e.target.checked;
@@ -416,11 +449,7 @@ export function Switch({
416
449
  {isBusy && <Spinner size="sm" />}
417
450
  </div>
418
451
  </div>
419
- {isBusy && (
420
- <span {...stylex.props(styles.srOnly)} role="status">
421
- Loading
422
- </span>
423
- )}
452
+ {isBusy && <VisuallyHidden role="status">Loading</VisuallyHidden>}
424
453
  </div>
425
454
  );
426
455
 
@@ -453,6 +482,15 @@ export function Switch({
453
482
  style,
454
483
  )}>
455
484
  <div
485
+ ref={el => {
486
+ // Interaction (hover/focus) listeners for the disabled-message
487
+ // tooltip attach to the whole row for a larger trigger target;
488
+ // positioning anchors on the switch itself (above) so the tooltip
489
+ // appears next to the control, not the far edge of the row.
490
+ // Handlers are gated internally by isEnabled, so attaching
491
+ // unconditionally is safe.
492
+ disabledMessageTooltip.interactionRef(el);
493
+ }}
456
494
  {...stylex.props(
457
495
  styles.container,
458
496
  labelSpacing === 'spread' && styles.containerSpread,
@@ -481,6 +519,8 @@ export function Switch({
481
519
  />
482
520
  </div>
483
521
  )}
522
+ {showsDisabledMessage &&
523
+ disabledMessageTooltip.renderTooltip(disabledMessage)}
484
524
  </div>
485
525
  );
486
526
  }
@@ -259,7 +259,13 @@ export function Tab({
259
259
  ...restProps,
260
260
  ...(isLabelHidden ? {'aria-label': label} : {}),
261
261
  [EDGE_COMP_ATTR]: '',
262
+ 'data-tab-value': value,
262
263
  'aria-current': isSelected ? ('page' as const) : undefined,
264
+ // Roving tabindex: the tab strip is a single Tab stop. The selected tab is
265
+ // the tabbable one; the rest are reachable via arrow keys (handled by
266
+ // TabList's onKeyDown). When no tab is selected, TabList's repair effect
267
+ // makes the first stop tabbable.
268
+ tabIndex: isSelected ? 0 : -1,
263
269
  ...mergeProps(
264
270
  themeProps('tab', {
265
271
  selected: isSelected ? 'selected' : null,
@@ -43,12 +43,24 @@ export const docs = {
43
43
  description: 'Size variant applied to all child tabs.',
44
44
  default: "'md'",
45
45
  },
46
+ {
47
+ name: 'layout',
48
+ type: "'hug' | 'fill'",
49
+ description: "Layout mode for tab sizing. 'hug': each tab hugs its content width. 'fill': tabs stretch equally to fill the container width.",
50
+ default: "'hug'",
51
+ },
46
52
  {
47
53
  name: 'hasDivider',
48
54
  type: 'boolean',
49
55
  description: 'Whether to show a bottom border divider under the tab list.',
50
56
  default: 'false',
51
57
  },
58
+ {
59
+ name: 'orientation',
60
+ type: "'horizontal' | 'vertical'",
61
+ description: "Orientation of the tab strip, controlling which arrow keys move focus between tabs and the reported aria-orientation. 'horizontal': ArrowLeft/ArrowRight. 'vertical': ArrowUp/ArrowDown. Both axes' arrows are accepted regardless.",
62
+ default: "'horizontal'",
63
+ },
52
64
  {
53
65
  name: 'children',
54
66
  type: 'ReactNode',
@@ -280,6 +280,214 @@ describe('TabList', () => {
280
280
  });
281
281
  });
282
282
 
283
+ describe('TabList keyboard navigation (roving tabindex)', () => {
284
+ it('exposes the tab strip as a single Tab stop (only selected tab is tabbable)', () => {
285
+ render(
286
+ <TabList value="settings" onChange={() => {}}>
287
+ <Tab value="home" label="Home" />
288
+ <Tab value="settings" label="Settings" />
289
+ <Tab value="profile" label="Profile" />
290
+ </TabList>,
291
+ );
292
+
293
+ expect(screen.getByRole('button', {name: 'Home'})).toHaveAttribute(
294
+ 'tabindex',
295
+ '-1',
296
+ );
297
+ expect(screen.getByRole('button', {name: 'Settings'})).toHaveAttribute(
298
+ 'tabindex',
299
+ '0',
300
+ );
301
+ expect(screen.getByRole('button', {name: 'Profile'})).toHaveAttribute(
302
+ 'tabindex',
303
+ '-1',
304
+ );
305
+ });
306
+
307
+ it('makes the first tab tabbable when the selected value matches no tab', () => {
308
+ render(
309
+ <TabList value="__none__" onChange={() => {}}>
310
+ <Tab value="home" label="Home" />
311
+ <Tab value="settings" label="Settings" />
312
+ </TabList>,
313
+ );
314
+
315
+ expect(screen.getByRole('button', {name: 'Home'})).toHaveAttribute(
316
+ 'tabindex',
317
+ '0',
318
+ );
319
+ expect(screen.getByRole('button', {name: 'Settings'})).toHaveAttribute(
320
+ 'tabindex',
321
+ '-1',
322
+ );
323
+ });
324
+
325
+ it('moves focus with ArrowRight and ArrowLeft', async () => {
326
+ const user = userEvent.setup();
327
+ render(
328
+ <TabList value="home" onChange={() => {}}>
329
+ <Tab value="home" label="Home" />
330
+ <Tab value="settings" label="Settings" />
331
+ <Tab value="profile" label="Profile" />
332
+ </TabList>,
333
+ );
334
+
335
+ const home = screen.getByRole('button', {name: 'Home'});
336
+ const settings = screen.getByRole('button', {name: 'Settings'});
337
+ const profile = screen.getByRole('button', {name: 'Profile'});
338
+
339
+ home.focus();
340
+ expect(home).toHaveFocus();
341
+
342
+ await user.keyboard('{ArrowRight}');
343
+ expect(settings).toHaveFocus();
344
+
345
+ await user.keyboard('{ArrowRight}');
346
+ expect(profile).toHaveFocus();
347
+
348
+ await user.keyboard('{ArrowLeft}');
349
+ expect(settings).toHaveFocus();
350
+ });
351
+
352
+ it('supports ArrowDown and ArrowUp as forward/backward as well', async () => {
353
+ const user = userEvent.setup();
354
+ render(
355
+ <TabList value="home" onChange={() => {}}>
356
+ <Tab value="home" label="Home" />
357
+ <Tab value="settings" label="Settings" />
358
+ </TabList>,
359
+ );
360
+
361
+ const home = screen.getByRole('button', {name: 'Home'});
362
+ const settings = screen.getByRole('button', {name: 'Settings'});
363
+
364
+ home.focus();
365
+ await user.keyboard('{ArrowDown}');
366
+ expect(settings).toHaveFocus();
367
+
368
+ await user.keyboard('{ArrowUp}');
369
+ expect(home).toHaveFocus();
370
+ });
371
+
372
+ it('jumps to first and last tab with Home and End', async () => {
373
+ const user = userEvent.setup();
374
+ render(
375
+ <TabList value="settings" onChange={() => {}}>
376
+ <Tab value="home" label="Home" />
377
+ <Tab value="settings" label="Settings" />
378
+ <Tab value="profile" label="Profile" />
379
+ </TabList>,
380
+ );
381
+
382
+ const home = screen.getByRole('button', {name: 'Home'});
383
+ const settings = screen.getByRole('button', {name: 'Settings'});
384
+ const profile = screen.getByRole('button', {name: 'Profile'});
385
+
386
+ settings.focus();
387
+
388
+ await user.keyboard('{End}');
389
+ expect(profile).toHaveFocus();
390
+
391
+ await user.keyboard('{Home}');
392
+ expect(home).toHaveFocus();
393
+ });
394
+
395
+ it('wraps around at the ends', async () => {
396
+ const user = userEvent.setup();
397
+ render(
398
+ <TabList value="home" onChange={() => {}}>
399
+ <Tab value="home" label="Home" />
400
+ <Tab value="settings" label="Settings" />
401
+ <Tab value="profile" label="Profile" />
402
+ </TabList>,
403
+ );
404
+
405
+ const home = screen.getByRole('button', {name: 'Home'});
406
+ const profile = screen.getByRole('button', {name: 'Profile'});
407
+
408
+ home.focus();
409
+ await user.keyboard('{ArrowLeft}');
410
+ expect(profile).toHaveFocus();
411
+
412
+ await user.keyboard('{ArrowRight}');
413
+ expect(home).toHaveFocus();
414
+ });
415
+
416
+ it('skips disabled tabs during arrow navigation', async () => {
417
+ const user = userEvent.setup();
418
+ render(
419
+ <TabList value="home" onChange={() => {}}>
420
+ <Tab value="home" label="Home" />
421
+ <Tab value="settings" label="Settings" aria-disabled="true" />
422
+ <Tab value="profile" label="Profile" />
423
+ </TabList>,
424
+ );
425
+
426
+ const home = screen.getByRole('button', {name: 'Home'});
427
+ const profile = screen.getByRole('button', {name: 'Profile'});
428
+
429
+ home.focus();
430
+ await user.keyboard('{ArrowRight}');
431
+ expect(profile).toHaveFocus();
432
+ });
433
+
434
+ it('does not intercept unrelated keys', async () => {
435
+ const user = userEvent.setup();
436
+ render(
437
+ <TabList value="home" onChange={() => {}}>
438
+ <Tab value="home" label="Home" />
439
+ <Tab value="settings" label="Settings" />
440
+ </TabList>,
441
+ );
442
+
443
+ const home = screen.getByRole('button', {name: 'Home'});
444
+ home.focus();
445
+ await user.keyboard('a');
446
+ expect(home).toHaveFocus();
447
+ });
448
+
449
+ it('composes consumer onKeyDown with internal arrow navigation', async () => {
450
+ const user = userEvent.setup();
451
+ const onKeyDown = vi.fn();
452
+
453
+ render(
454
+ <TabList value="home" onChange={() => {}} onKeyDown={onKeyDown}>
455
+ <Tab value="home" label="Home" />
456
+ <Tab value="settings" label="Settings" />
457
+ </TabList>,
458
+ );
459
+
460
+ const home = screen.getByRole('button', {name: 'Home'});
461
+ const settings = screen.getByRole('button', {name: 'Settings'});
462
+
463
+ home.focus();
464
+ await user.keyboard('{ArrowRight}');
465
+
466
+ expect(onKeyDown).toHaveBeenCalled();
467
+ expect(settings).toHaveFocus();
468
+ });
469
+
470
+ it('respects preventDefault from consumer onKeyDown', async () => {
471
+ const user = userEvent.setup();
472
+
473
+ render(
474
+ <TabList
475
+ value="home"
476
+ onChange={() => {}}
477
+ onKeyDown={e => e.preventDefault()}>
478
+ <Tab value="home" label="Home" />
479
+ <Tab value="settings" label="Settings" />
480
+ </TabList>,
481
+ );
482
+
483
+ const home = screen.getByRole('button', {name: 'Home'});
484
+ home.focus();
485
+ await user.keyboard('{ArrowRight}');
486
+
487
+ expect(home).toHaveFocus();
488
+ });
489
+ });
490
+
283
491
  describe('Tab polymorphic link', () => {
284
492
  it('renders custom component when href and as are provided', () => {
285
493
  render(
@@ -4,9 +4,11 @@
4
4
 
5
5
  /**
6
6
  * @file TabList.tsx
7
- * @input Uses React, StyleX, TabListContext
7
+ * @input Uses React, StyleX, TabListContext, useListFocus, useKeyboardHint
8
8
  * @output Exports TabList component and TabListProps type
9
- * @position Nav wrapper; provides TabListContext to Tab and TabMenu children
9
+ * @position Nav wrapper; provides TabListContext to Tab and TabMenu children.
10
+ * Owns roving-tabindex keyboard navigation (Arrow/Home/End) across the tab
11
+ * strip via the shared useListFocus hook so it is a single Tab stop.
10
12
  *
11
13
  * SYNC: When modified, update:
12
14
  * - /packages/core/src/TabList/TabList.doc.mjs
@@ -15,21 +17,27 @@
15
17
  * - /packages/cli/templates/blocks/components/TabList/ (showcase blocks)
16
18
  */
17
19
 
18
- import React, {useMemo, type ReactNode} from 'react';
20
+ import React, {useCallback, useMemo, type ReactNode} from 'react';
19
21
  import * as stylex from '@stylexjs/stylex';
20
22
  import {borderVars, colorVars, spacingVars} from '../theme/tokens.stylex';
21
23
  import type {BaseProps} from '../BaseProps';
22
24
  import {TabListContext} from './TabListContext';
23
- import type {TabListSize} from './TabListContext';
25
+ import type {TabListOrientation, TabListSize} from './TabListContext';
24
26
  import {useSize} from '../SizeContext/SizeContext';
25
- import {mergeProps} from '../utils';
27
+ import {mergeProps, mergeRefs} from '../utils';
28
+ import {useListFocus} from '../hooks/useListFocus';
29
+ import {useKeyboardHint} from '../hooks/useKeyboardHint';
26
30
  import {EDGE_COMP_ATTR} from '../Layout/edgeCompensation.stylex';
27
31
  import {themeProps} from '../utils/themeProps';
28
32
 
29
- export interface TabListProps extends Omit<
30
- BaseProps<HTMLElement>,
31
- 'onChange'
32
- > {
33
+ /**
34
+ * Selector matching the focusable stops in the tab strip: every Tab
35
+ * (`[data-tab-value]`) and every TabMenu trigger (`[data-tab-menu]`),
36
+ * in DOM order. Disabled stops are filtered out by the handler.
37
+ */
38
+ const TAB_STOP_SELECTOR = '[data-tab-value],[data-tab-menu]';
39
+
40
+ export interface TabListProps extends Omit<BaseProps<HTMLElement>, 'onChange'> {
33
41
  ref?: React.Ref<HTMLElement>;
34
42
  /**
35
43
  * The currently selected tab value.
@@ -57,6 +65,15 @@ export interface TabListProps extends Omit<
57
65
  * @default false
58
66
  */
59
67
  hasDivider?: boolean;
68
+ /**
69
+ * Orientation of the tab strip, controlling which arrow keys move
70
+ * focus between tabs.
71
+ * - `'horizontal'` (default): ArrowLeft / ArrowRight (ArrowUp / ArrowDown
72
+ * also work per the WAI-ARIA APG).
73
+ * - `'vertical'`: ArrowUp / ArrowDown (ArrowLeft / ArrowRight also work).
74
+ * @default 'horizontal'
75
+ */
76
+ orientation?: TabListOrientation;
60
77
  /**
61
78
  * Tab and TabMenu children.
62
79
  */
@@ -104,26 +121,98 @@ export function TabList({
104
121
  size: sizeProp,
105
122
  layout = 'hug',
106
123
  hasDivider = false,
124
+ orientation = 'horizontal',
107
125
  xstyle,
108
126
  className,
109
127
  style,
110
128
  children,
129
+ onKeyDown: onKeyDownProp,
130
+ onFocus: onFocusProp,
131
+ onBlur: onBlurProp,
132
+ 'aria-label': ariaLabel = 'Tabs',
133
+ 'aria-orientation': _ariaOrientation,
134
+ [EDGE_COMP_ATTR]: _edgeCompAttr,
111
135
  ...restProps
112
136
  }: TabListProps) {
113
137
  const size = useSize(sizeProp, 'md');
114
138
 
139
+ // Roving-tabindex keyboard navigation across the tab strip via the shared
140
+ // hook. `orientation: 'both'` accepts both arrow axes per the WAI-ARIA APG
141
+ // allowance for tab strips (ArrowRight/ArrowDown advance, ArrowLeft/ArrowUp
142
+ // retreat) regardless of the component's `orientation` prop, which only
143
+ // drives the reported `aria-orientation`.
144
+ //
145
+ // `hasRovingTabIndex` makes the hook own the single tab stop: it stamps
146
+ // tabindex 0/-1, repairs the stop on mount and as stops mount/unmount or
147
+ // toggle disabled, and — via `handleFocus` on the nav — keeps the stop in
148
+ // sync after clicks or programmatic focus. Individual Tabs still render
149
+ // `tabIndex={isSelected ? 0 : -1}` (see Tab.tsx) as the initial source of
150
+ // truth; the hook's repair preserves an existing tab stop and only promotes
151
+ // the first enabled stop when none is tabbable.
152
+ const {listRef, handleKeyDown, handleFocus} = useListFocus<HTMLElement>({
153
+ itemSelector: TAB_STOP_SELECTOR,
154
+ orientation: 'both',
155
+ hasRovingTabIndex: true,
156
+ });
157
+
158
+ const {
159
+ hintElement,
160
+ onKeyDown: onHintKeyDown,
161
+ onFocus: onHintFocus,
162
+ onBlur: onHintBlur,
163
+ } = useKeyboardHint({orientation});
164
+
115
165
  const contextValue = useMemo(
116
166
  () => ({value, onChange, size, layout}),
117
167
  [value, onChange, size, layout],
118
168
  );
119
169
 
170
+ const handleRootKeyDown = useCallback(
171
+ (e: React.KeyboardEvent<HTMLElement>) => {
172
+ onKeyDownProp?.(e);
173
+ if (e.defaultPrevented) {
174
+ return;
175
+ }
176
+ onHintKeyDown(e);
177
+ handleKeyDown(e);
178
+ },
179
+ [onKeyDownProp, onHintKeyDown, handleKeyDown],
180
+ );
181
+
182
+ const handleRootFocus = useCallback(
183
+ (e: React.FocusEvent<HTMLElement>) => {
184
+ onFocusProp?.(e);
185
+ if (e.defaultPrevented) {
186
+ return;
187
+ }
188
+ onHintFocus(e);
189
+ handleFocus(e);
190
+ },
191
+ [onFocusProp, onHintFocus, handleFocus],
192
+ );
193
+
194
+ const handleRootBlur = useCallback(
195
+ (e: React.FocusEvent<HTMLElement>) => {
196
+ onBlurProp?.(e);
197
+ if (e.defaultPrevented) {
198
+ return;
199
+ }
200
+ onHintBlur(e);
201
+ },
202
+ [onBlurProp, onHintBlur],
203
+ );
204
+
120
205
  return (
121
206
  <TabListContext value={contextValue}>
122
207
  <nav
123
- ref={ref}
124
- aria-label="Tabs"
125
- {...{[EDGE_COMP_ATTR]: ''}}
208
+ ref={mergeRefs(ref, listRef)}
126
209
  {...restProps}
210
+ aria-label={ariaLabel}
211
+ aria-orientation={orientation}
212
+ onKeyDown={handleRootKeyDown}
213
+ onFocus={handleRootFocus}
214
+ onBlur={handleRootBlur}
215
+ {...{[EDGE_COMP_ATTR]: ''}}
127
216
  {...mergeProps(
128
217
  themeProps('tab-list', {size}),
129
218
  stylex.props(
@@ -136,6 +225,7 @@ export function TabList({
136
225
  style,
137
226
  )}>
138
227
  {children}
228
+ {hintElement}
139
229
  </nav>
140
230
  </TabListContext>
141
231
  );
@@ -26,6 +26,12 @@ export type TabListSize = 'sm' | 'md' | 'lg';
26
26
  */
27
27
  export type TabListLayout = 'hug' | 'fill';
28
28
 
29
+ /**
30
+ * Orientation of the tab strip. Controls which arrow keys move focus
31
+ * between tabs and the reported `aria-orientation`.
32
+ */
33
+ export type TabListOrientation = 'horizontal' | 'vertical';
34
+
29
35
  /**
30
36
  * Context for communicating value/onChange/size/layout from TabList to children.
31
37
  */
@@ -36,9 +42,7 @@ export interface TabListContextValue {
36
42
  layout: TabListLayout;
37
43
  }
38
44
 
39
- export const TabListContext = createContext<TabListContextValue | null>(
40
- null,
41
- );
45
+ export const TabListContext = createContext<TabListContextValue | null>(null);
42
46
  TabListContext.displayName = 'TabListContext';
43
47
 
44
48
  /**
@@ -267,6 +267,9 @@ export function TabMenu({
267
267
  hasLightDismiss: true,
268
268
  hasCloseButton: false,
269
269
  hasAutoFocus: false,
270
+ // The popup's own role="menu" is the exposed semantics; a modal dialog
271
+ // wrapper would announce an unnamed dialog around the menu.
272
+ role: 'none',
270
273
  });
271
274
 
272
275
  const {listRef, handleKeyDown: handleListKeyDown} =
@@ -306,6 +309,8 @@ export function TabMenu({
306
309
  aria-haspopup="menu"
307
310
  aria-expanded={popover.isOpen}
308
311
  aria-controls={menuId}
312
+ data-tab-menu=""
313
+ tabIndex={hasSelectedOption ? 0 : -1}
309
314
  onClick={handleToggle}
310
315
  {...mergeProps(
311
316
  themeProps('tab-menu'),
@@ -390,9 +395,7 @@ export function TabMenu({
390
395
  })}
391
396
  {option.label}
392
397
  </span>
393
- {isSelected && (
394
- <Icon icon="check" size="sm" color="accent" />
395
- )}
398
+ {isSelected && <Icon icon="check" size="sm" color="accent" />}
396
399
  </div>
397
400
  );
398
401
  })}