@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
@@ -37,6 +37,13 @@ import {
37
37
  typeScaleVars,
38
38
  } from '../theme/tokens.stylex';
39
39
 
40
+ /**
41
+ * Grace period (ms) before hiding on pointer-leave when no explicit `hideDelay`
42
+ * is set, so the pointer can travel across the small gap from the trigger onto
43
+ * the tooltip surface without the tooltip disappearing (WCAG 1.4.13 hoverable).
44
+ */
45
+ const HOVER_BRIDGE_DELAY = 100;
46
+
40
47
  const styles = stylex.create({
41
48
  // Base container styles - inverted colors for high contrast
42
49
  container: {
@@ -233,9 +240,7 @@ function isFocusable(element: HTMLElement): boolean {
233
240
  * {tooltip.renderTooltip('Helpful tooltip text')}
234
241
  * ```
235
242
  */
236
- export function useTooltip(
237
- options: TooltipOptions = {},
238
- ): TooltipReturn {
243
+ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
239
244
  const {
240
245
  placement = 'above',
241
246
  alignment = 'center',
@@ -293,21 +298,29 @@ export function useTooltip(
293
298
  }, delay);
294
299
  }, [isEnabled, isOpen, clearTimeouts, layer, delay]);
295
300
 
296
- // Schedule hide with delay (suppressed when isOpen is true)
301
+ // Schedule hide with delay (suppressed when isOpen is true).
302
+ // A small hover bridge (when hideDelay is 0) lets the pointer travel from the
303
+ // trigger onto the tooltip surface without the tooltip vanishing — required
304
+ // for WCAG 1.4.13 (Content on Hover or Focus: hoverable).
297
305
  const scheduleHide = useCallback(() => {
298
306
  if (isOpen === true) {
299
307
  return;
300
308
  }
301
309
  clearTimeouts();
302
- if (hideDelay > 0) {
303
- hideTimeoutRef.current = setTimeout(() => {
304
- layer.hide();
305
- }, hideDelay);
306
- } else {
310
+ const effectiveHideDelay = hideDelay > 0 ? hideDelay : HOVER_BRIDGE_DELAY;
311
+ hideTimeoutRef.current = setTimeout(() => {
307
312
  layer.hide();
308
- }
313
+ }, effectiveHideDelay);
309
314
  }, [isOpen, clearTimeouts, layer, hideDelay]);
310
315
 
316
+ // Cancel a pending hide (e.g. the pointer entered the tooltip surface).
317
+ const cancelHide = useCallback(() => {
318
+ if (hideTimeoutRef.current) {
319
+ clearTimeout(hideTimeoutRef.current);
320
+ hideTimeoutRef.current = null;
321
+ }
322
+ }, []);
323
+
311
324
  // Event handlers
312
325
  const handleMouseEnter = useCallback(() => {
313
326
  // Suppress tooltips on touch devices — hover is simulated and eats a tap
@@ -422,6 +435,32 @@ export function useTooltip(
422
435
  }
423
436
  }, [isOpen, clearTimeouts, layer]);
424
437
 
438
+ // Dismiss on Escape (WCAG 1.4.13 — dismissible). Uncontrolled tooltips only;
439
+ // a controlled tooltip's visibility is owned by the consumer. The listener is
440
+ // mounted for the lifetime of an uncontrolled tooltip rather than gated on
441
+ // `layer.isOpen` (React state, which can lag a frame behind the DOM) —
442
+ // `layer.hide()` self-guards and no-ops when the layer is already closed.
443
+ // Guarded against IME composition-cancel.
444
+ useEffect(() => {
445
+ if (isOpen !== undefined) {
446
+ return;
447
+ }
448
+ const handleKeyDown = (e: KeyboardEvent) => {
449
+ if (e.key !== 'Escape') {
450
+ return;
451
+ }
452
+ if (e.isComposing || e.keyCode === 229) {
453
+ return;
454
+ }
455
+ clearTimeouts();
456
+ layer.hide();
457
+ };
458
+ document.addEventListener('keydown', handleKeyDown);
459
+ return () => {
460
+ document.removeEventListener('keydown', handleKeyDown);
461
+ };
462
+ }, [isOpen, layer, clearTimeouts]);
463
+
425
464
  // Render function that wraps layer.render with tooltip styling
426
465
  const renderTooltip = useCallback(
427
466
  (children: ReactNode, props?: ContextRenderProps): ReactNode => {
@@ -429,8 +468,15 @@ export function useTooltip(
429
468
  const renderProps = {
430
469
  placement: renderPlacement,
431
470
  alignment: props?.alignment ?? alignment,
471
+ role: 'tooltip',
432
472
  xstyle: [popoverXstyle, layerAnimations[renderPlacement]],
433
473
  className: themeProps('tooltip').className,
474
+ // Keep the tooltip open while the pointer is over the surface itself
475
+ // (WCAG 1.4.13 hoverable). These sit on the layer container — the
476
+ // element the user actually hovers — not the inner content div, since
477
+ // mouseenter/leave do not bubble.
478
+ onMouseEnter: cancelHide,
479
+ onMouseLeave: scheduleHide,
434
480
  };
435
481
 
436
482
  return layer.render(
@@ -438,7 +484,7 @@ export function useTooltip(
438
484
  renderProps,
439
485
  );
440
486
  },
441
- [layer, placement, alignment, popoverXstyle],
487
+ [layer, placement, alignment, popoverXstyle, cancelHide, scheduleHide],
442
488
  );
443
489
 
444
490
  return {
@@ -61,6 +61,44 @@ const deepItems: TreeListItemData[] = [
61
61
  },
62
62
  ];
63
63
 
64
+ // APG keyboard fixtures (module-level to satisfy no-unstable-default-props).
65
+ const flatItems: TreeListItemData[] = [
66
+ {id: 'a', label: 'Apple'},
67
+ {id: 'b', label: 'Banana'},
68
+ {id: 'c', label: 'Cherry'},
69
+ ];
70
+
71
+ const withDisabledItems: TreeListItemData[] = [
72
+ {id: 'a', label: 'Apple'},
73
+ {id: 'b', label: 'Banana', isDisabled: true},
74
+ {id: 'c', label: 'Cherry'},
75
+ ];
76
+
77
+ const collapsedParentItems: TreeListItemData[] = [
78
+ {
79
+ id: 'parent',
80
+ label: 'Parent',
81
+ children: [
82
+ {id: 'child-1', label: 'Child 1'},
83
+ {id: 'child-2', label: 'Child 2'},
84
+ ],
85
+ },
86
+ {id: 'sibling', label: 'Sibling'},
87
+ ];
88
+
89
+ const expandedParentItems: TreeListItemData[] = [
90
+ {
91
+ id: 'parent',
92
+ label: 'Parent',
93
+ isExpanded: true,
94
+ children: [
95
+ {id: 'child-1', label: 'Child 1'},
96
+ {id: 'child-2', label: 'Child 2'},
97
+ ],
98
+ },
99
+ {id: 'sibling', label: 'Sibling'},
100
+ ];
101
+
64
102
  describe('TreeList', () => {
65
103
  // ===========================================================================
66
104
  // Basic rendering
@@ -160,6 +198,26 @@ describe('TreeList', () => {
160
198
  expect(item).not.toHaveAttribute('aria-expanded');
161
199
  });
162
200
 
201
+ it('renders a keyboard-focusable toggle button for parents without onClick/href', () => {
202
+ render(<TreeList items={nestedItems} />);
203
+ const toggle = screen.getByRole('button', {name: 'Toggle children'});
204
+ expect(toggle).toBeInTheDocument();
205
+ expect(toggle).toHaveAttribute('aria-expanded', 'false');
206
+ });
207
+
208
+ it('expands a parent from the keyboard via the toggle button', async () => {
209
+ const user = userEvent.setup();
210
+ render(<TreeList items={nestedItems} />);
211
+ // Collapsed: children are not rendered.
212
+ expect(screen.queryByText('Child 1')).not.toBeInTheDocument();
213
+ const toggle = screen.getByRole('button', {name: 'Toggle children'});
214
+ toggle.focus();
215
+ expect(toggle).toHaveFocus();
216
+ await user.keyboard('{Enter}');
217
+ expect(screen.getByText('Child 1')).toBeInTheDocument();
218
+ expect(toggle).toHaveAttribute('aria-expanded', 'true');
219
+ });
220
+
163
221
  it('renders group role for nested children', () => {
164
222
  render(<TreeList items={nestedItemsExpanded} />);
165
223
  const groups = document.querySelectorAll('[role="group"]');
@@ -210,18 +268,14 @@ describe('TreeList', () => {
210
268
  it('fires onClick when invisible button is clicked', async () => {
211
269
  const user = userEvent.setup();
212
270
  const onClick = vi.fn();
213
- const items: TreeListItemData[] = [
214
- {id: 'a', label: 'Clickable', onClick},
215
- ];
271
+ const items: TreeListItemData[] = [{id: 'a', label: 'Clickable', onClick}];
216
272
  render(<TreeList items={items} />);
217
273
  await user.click(screen.getByRole('button'));
218
274
  expect(onClick).toHaveBeenCalledTimes(1);
219
275
  });
220
276
 
221
277
  it('renders an invisible anchor when href is provided', () => {
222
- const items: TreeListItemData[] = [
223
- {id: 'a', label: 'Link', href: '/docs'},
224
- ];
278
+ const items: TreeListItemData[] = [{id: 'a', label: 'Link', href: '/docs'}];
225
279
  const {container} = render(<TreeList items={items} />);
226
280
  const anchor = container.querySelector('a');
227
281
  expect(anchor).toBeInTheDocument();
@@ -317,4 +371,239 @@ describe('TreeList', () => {
317
371
  const root = screen.getByTestId('tree');
318
372
  expect(root.className).toContain('astryx-tree-list');
319
373
  });
374
+
375
+ // ===========================================================================
376
+ // APG structural ARIA (aria-level / aria-posinset / aria-setsize)
377
+ // ===========================================================================
378
+
379
+ it('sets aria-level, aria-posinset, and aria-setsize at the top level', () => {
380
+ render(<TreeList items={flatItems} />);
381
+ const apple = screen.getByText('Apple').closest('li');
382
+ expect(apple).toHaveAttribute('aria-level', '1');
383
+ expect(apple).toHaveAttribute('aria-posinset', '1');
384
+ expect(apple).toHaveAttribute('aria-setsize', '3');
385
+
386
+ const cherry = screen.getByText('Cherry').closest('li');
387
+ expect(cherry).toHaveAttribute('aria-posinset', '3');
388
+ expect(cherry).toHaveAttribute('aria-setsize', '3');
389
+ });
390
+
391
+ it('sets aria-level/posinset/setsize correctly at deeper levels', () => {
392
+ render(<TreeList items={expandedParentItems} />);
393
+ const parent = screen.getByText('Parent').closest('li');
394
+ expect(parent).toHaveAttribute('aria-level', '1');
395
+ expect(parent).toHaveAttribute('aria-setsize', '2');
396
+
397
+ const child1 = screen.getByText('Child 1').closest('li');
398
+ expect(child1).toHaveAttribute('aria-level', '2');
399
+ expect(child1).toHaveAttribute('aria-posinset', '1');
400
+ expect(child1).toHaveAttribute('aria-setsize', '2');
401
+
402
+ const child2 = screen.getByText('Child 2').closest('li');
403
+ expect(child2).toHaveAttribute('aria-level', '2');
404
+ expect(child2).toHaveAttribute('aria-posinset', '2');
405
+ });
406
+
407
+ it('sets aria-level across three depths', () => {
408
+ render(<TreeList items={deepItems} />);
409
+ expect(screen.getByText('Root').closest('li')).toHaveAttribute(
410
+ 'aria-level',
411
+ '1',
412
+ );
413
+ expect(screen.getByText('Mid').closest('li')).toHaveAttribute(
414
+ 'aria-level',
415
+ '2',
416
+ );
417
+ expect(screen.getByText('Leaf').closest('li')).toHaveAttribute(
418
+ 'aria-level',
419
+ '3',
420
+ );
421
+ });
422
+
423
+ // ===========================================================================
424
+ // Roving tabindex
425
+ // ===========================================================================
426
+
427
+ it('makes exactly one treeitem tabbable by default (the first enabled)', () => {
428
+ render(<TreeList items={flatItems} />);
429
+ const treeitems = screen.getAllByRole('treeitem');
430
+ const tabbable = treeitems.filter(
431
+ el => el.getAttribute('tabindex') === '0',
432
+ );
433
+ expect(tabbable).toHaveLength(1);
434
+ expect(tabbable[0]).toBe(screen.getByText('Apple').closest('li'));
435
+ expect(screen.getByText('Banana').closest('li')).toHaveAttribute(
436
+ 'tabindex',
437
+ '-1',
438
+ );
439
+ });
440
+
441
+ it('defaults the tab stop to the selected item when one is selected', () => {
442
+ const items: TreeListItemData[] = [
443
+ {id: 'a', label: 'Apple'},
444
+ {id: 'b', label: 'Banana', isSelected: true},
445
+ {id: 'c', label: 'Cherry'},
446
+ ];
447
+ render(<TreeList items={items} />);
448
+ expect(screen.getByText('Banana').closest('li')).toHaveAttribute(
449
+ 'tabindex',
450
+ '0',
451
+ );
452
+ expect(screen.getByText('Apple').closest('li')).toHaveAttribute(
453
+ 'tabindex',
454
+ '-1',
455
+ );
456
+ });
457
+
458
+ it('moves the single tab stop when focus moves via keyboard', async () => {
459
+ const user = userEvent.setup();
460
+ render(<TreeList items={flatItems} />);
461
+ const apple = screen.getByText('Apple').closest('li')!;
462
+ apple.focus();
463
+ await user.keyboard('{ArrowDown}');
464
+ const treeitems = screen.getAllByRole('treeitem');
465
+ const tabbable = treeitems.filter(
466
+ el => el.getAttribute('tabindex') === '0',
467
+ );
468
+ expect(tabbable).toHaveLength(1);
469
+ expect(tabbable[0]).toBe(screen.getByText('Banana').closest('li'));
470
+ });
471
+
472
+ // ===========================================================================
473
+ // APG keyboard navigation
474
+ // ===========================================================================
475
+
476
+ it('ArrowDown / ArrowUp move focus between visible treeitems', async () => {
477
+ const user = userEvent.setup();
478
+ render(<TreeList items={flatItems} />);
479
+ const apple = screen.getByText('Apple').closest('li')!;
480
+ apple.focus();
481
+ await user.keyboard('{ArrowDown}');
482
+ expect(document.activeElement).toBe(
483
+ screen.getByText('Banana').closest('li'),
484
+ );
485
+ await user.keyboard('{ArrowDown}');
486
+ expect(document.activeElement).toBe(
487
+ screen.getByText('Cherry').closest('li'),
488
+ );
489
+ await user.keyboard('{ArrowUp}');
490
+ expect(document.activeElement).toBe(
491
+ screen.getByText('Banana').closest('li'),
492
+ );
493
+ });
494
+
495
+ it('ArrowDown / ArrowUp skip disabled treeitems', async () => {
496
+ const user = userEvent.setup();
497
+ render(<TreeList items={withDisabledItems} />);
498
+ const apple = screen.getByText('Apple').closest('li')!;
499
+ apple.focus();
500
+ await user.keyboard('{ArrowDown}');
501
+ // Banana is disabled → skipped, lands on Cherry.
502
+ expect(document.activeElement).toBe(
503
+ screen.getByText('Cherry').closest('li'),
504
+ );
505
+ await user.keyboard('{ArrowUp}');
506
+ expect(document.activeElement).toBe(
507
+ screen.getByText('Apple').closest('li'),
508
+ );
509
+ });
510
+
511
+ it('ArrowRight expands a collapsed parent, then enters the first child', async () => {
512
+ const user = userEvent.setup();
513
+ render(<TreeList items={collapsedParentItems} />);
514
+ const parent = screen.getByText('Parent').closest('li')!;
515
+ parent.focus();
516
+ expect(screen.queryByText('Child 1')).not.toBeInTheDocument();
517
+ await user.keyboard('{ArrowRight}');
518
+ // First ArrowRight expands.
519
+ expect(screen.getByText('Child 1')).toBeInTheDocument();
520
+ expect(document.activeElement).toBe(parent);
521
+ await user.keyboard('{ArrowRight}');
522
+ // Second ArrowRight moves into first child.
523
+ expect(document.activeElement).toBe(
524
+ screen.getByText('Child 1').closest('li'),
525
+ );
526
+ });
527
+
528
+ it('ArrowRight on a leaf is a no-op', async () => {
529
+ const user = userEvent.setup();
530
+ render(<TreeList items={flatItems} />);
531
+ const apple = screen.getByText('Apple').closest('li')!;
532
+ apple.focus();
533
+ await user.keyboard('{ArrowRight}');
534
+ expect(document.activeElement).toBe(apple);
535
+ });
536
+
537
+ it('ArrowLeft collapses an expanded parent, then moves to parent', async () => {
538
+ const user = userEvent.setup();
539
+ render(<TreeList items={expandedParentItems} />);
540
+ const parent = screen.getByText('Parent').closest('li')!;
541
+ // Focus a child first.
542
+ const child1 = screen.getByText('Child 1').closest('li')!;
543
+ child1.focus();
544
+ await user.keyboard('{ArrowLeft}');
545
+ // Child is a leaf → ArrowLeft moves to parent.
546
+ expect(document.activeElement).toBe(parent);
547
+ await user.keyboard('{ArrowLeft}');
548
+ // Parent is expanded → ArrowLeft collapses it.
549
+ expect(screen.queryByText('Child 1')).not.toBeInTheDocument();
550
+ });
551
+
552
+ it('Home and End move to the first and last visible treeitems', async () => {
553
+ const user = userEvent.setup();
554
+ render(<TreeList items={flatItems} />);
555
+ const banana = screen.getByText('Banana').closest('li')!;
556
+ banana.focus();
557
+ await user.keyboard('{End}');
558
+ expect(document.activeElement).toBe(
559
+ screen.getByText('Cherry').closest('li'),
560
+ );
561
+ await user.keyboard('{Home}');
562
+ expect(document.activeElement).toBe(
563
+ screen.getByText('Apple').closest('li'),
564
+ );
565
+ });
566
+
567
+ it('Enter activates the item onClick', async () => {
568
+ const user = userEvent.setup();
569
+ const onClick = vi.fn();
570
+ const items: TreeListItemData[] = [{id: 'a', label: 'Apple', onClick}];
571
+ render(<TreeList items={items} />);
572
+ const apple = screen.getByText('Apple').closest('li')!;
573
+ apple.focus();
574
+ await user.keyboard('{Enter}');
575
+ expect(onClick).toHaveBeenCalledTimes(1);
576
+ });
577
+
578
+ it('Space activates the item onClick', async () => {
579
+ const user = userEvent.setup();
580
+ const onClick = vi.fn();
581
+ const items: TreeListItemData[] = [{id: 'a', label: 'Apple', onClick}];
582
+ render(<TreeList items={items} />);
583
+ const apple = screen.getByText('Apple').closest('li')!;
584
+ apple.focus();
585
+ await user.keyboard(' ');
586
+ expect(onClick).toHaveBeenCalledTimes(1);
587
+ });
588
+
589
+ it('Enter toggles expansion for a parent without its own action', async () => {
590
+ const user = userEvent.setup();
591
+ render(<TreeList items={collapsedParentItems} />);
592
+ const parent = screen.getByText('Parent').closest('li')!;
593
+ parent.focus();
594
+ expect(screen.queryByText('Child 1')).not.toBeInTheDocument();
595
+ await user.keyboard('{Enter}');
596
+ expect(screen.getByText('Child 1')).toBeInTheDocument();
597
+ });
598
+
599
+ it('typeahead moves focus to the next item matching typed characters', async () => {
600
+ const user = userEvent.setup();
601
+ render(<TreeList items={flatItems} />);
602
+ const apple = screen.getByText('Apple').closest('li')!;
603
+ apple.focus();
604
+ await user.keyboard('c');
605
+ expect(document.activeElement).toBe(
606
+ screen.getByText('Cherry').closest('li'),
607
+ );
608
+ });
320
609
  });
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file TreeList.tsx
7
- * @input Uses React, StyleX, theme tokens, TreeListItem, TreeListTypes
7
+ * @input Uses React, StyleX, theme tokens, TreeListItem, TreeListTypes, useTreeFocus
8
8
  * @output Exports TreeList component, TreeListProps type
9
9
  * @position Core implementation; consumed by index.ts
10
10
  *
@@ -23,6 +23,7 @@ import type {BaseProps} from '../BaseProps';
23
23
  import {TreeListItem} from './TreeListItem';
24
24
  import type {TreeListItemData, TreeListDensity} from './TreeListTypes';
25
25
  import {themeProps} from '../utils/themeProps';
26
+ import {useTreeFocus} from '../hooks/useTreeFocus';
26
27
 
27
28
  // =============================================================================
28
29
  // Types
@@ -97,6 +98,35 @@ function collectExpandedKeys(items: TreeListItemData[]): string[] {
97
98
  return keys;
98
99
  }
99
100
 
101
+ /**
102
+ * Compute the initial roving-tabindex seed: the first selected enabled item in
103
+ * document order, else the first enabled item, else the first item. The hook
104
+ * (useTreeFocus with hasRovingTabIndex) takes ownership after mount — it
105
+ * preserves this seeded `tabindex="0"` on its repair pass and moves the stop
106
+ * with keyboard navigation.
107
+ */
108
+ function findInitialTabbableId(items: TreeListItemData[]): string | undefined {
109
+ let firstEnabled: string | undefined;
110
+ const walk = (list: TreeListItemData[]): string | undefined => {
111
+ for (const item of list) {
112
+ if (item.isSelected && item.isDisabled !== true) {
113
+ return item.id;
114
+ }
115
+ if (firstEnabled == null && item.isDisabled !== true) {
116
+ firstEnabled = item.id;
117
+ }
118
+ if (item.children != null && item.children.length > 0) {
119
+ const selected = walk(item.children);
120
+ if (selected != null) {
121
+ return selected;
122
+ }
123
+ }
124
+ }
125
+ return undefined;
126
+ };
127
+ return walk(items) ?? firstEnabled ?? items[0]?.id;
128
+ }
129
+
100
130
  // =============================================================================
101
131
  // Component
102
132
  // =============================================================================
@@ -160,6 +190,42 @@ export function TreeList({
160
190
  [expandedKeysFromProps],
161
191
  );
162
192
 
193
+ // ---------------------------------------------------------------------------
194
+ // Roving tabindex + APG tree keyboard model (via useTreeFocus)
195
+ // ---------------------------------------------------------------------------
196
+
197
+ // The hook (hasRovingTabIndex) owns the tree's single tab stop: it repairs
198
+ // the stop on mount and moves it with keyboard navigation. We only seed the
199
+ // initially-tabbable treeitem in the render (selected item or first enabled);
200
+ // the hook's repair pass preserves that seeded `tabindex="0"`.
201
+ const initialTabbableId = useMemo(
202
+ () => findInitialTabbableId(items),
203
+ [items],
204
+ );
205
+
206
+ // Enter/Space activation: prefer the treeitem's own inner action (link or
207
+ // button); return true when handled so the hook does not also toggle. Scoped
208
+ // to this treeitem's own row — never a descendant treeitem's action inside an
209
+ // expanded group.
210
+ const activateItem = useCallback((current: HTMLElement): boolean => {
211
+ const candidates = current.querySelectorAll<HTMLElement>(
212
+ 'a[href], button:not([aria-label="Toggle children"])',
213
+ );
214
+ for (const candidate of candidates) {
215
+ if (candidate.closest('[role="treeitem"]') === current) {
216
+ candidate.click();
217
+ return true;
218
+ }
219
+ }
220
+ return false;
221
+ }, []);
222
+
223
+ const {treeRef, handleKeyDown, handleFocus} = useTreeFocus<HTMLUListElement>({
224
+ onToggleExpand: handleToggle,
225
+ onActivate: activateItem,
226
+ hasRovingTabIndex: true,
227
+ });
228
+
163
229
  function renderItems(
164
230
  items: TreeListItemData[],
165
231
  nestedLevel: number,
@@ -206,6 +272,9 @@ export function TreeList({
206
272
  onToggle={handleToggle}
207
273
  density={density}
208
274
  renderedChildren={renderedChildren}
275
+ posInSet={index + 1}
276
+ setSize={items.length}
277
+ isTabbable={item.id === initialTabbableId}
209
278
  />
210
279
  );
211
280
  });
@@ -227,8 +296,11 @@ export function TreeList({
227
296
  </div>
228
297
  )}
229
298
  <ul
299
+ ref={treeRef}
230
300
  role="tree"
231
301
  aria-labelledby={header != null ? headerId : undefined}
302
+ onKeyDown={handleKeyDown}
303
+ onFocus={handleFocus}
232
304
  {...stylex.props(styles.list)}>
233
305
  {renderItems(items, 0, [])}
234
306
  </ul>