@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
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import {describe, it, expect, vi, beforeAll, afterAll} from 'vitest';
13
- import {render, screen, fireEvent, act} from '@testing-library/react';
13
+ import {render, screen, fireEvent, act, waitFor} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
15
  import {Tokenizer} from './Tokenizer';
16
16
  import type {SearchSource, SearchableItem} from '../Typeahead/types';
@@ -763,4 +763,108 @@ describe('Tokenizer', () => {
763
763
  expect(screen.getByText('Create "NewTag"')).toBeInTheDocument();
764
764
  });
765
765
  });
766
+
767
+ describe('disabledMessage', () => {
768
+ const h = {hidden: true} as const;
769
+ const isOpen = (el: Element) => el.matches(':popover-open');
770
+
771
+ function renderTokenizer(props?: {onChange?: () => void}) {
772
+ return render(
773
+ <Tokenizer
774
+ label="Members"
775
+ searchSource={userSource}
776
+ value={[]}
777
+ onChange={props?.onChange ?? (() => {})}
778
+ isDisabled
779
+ disabledMessage="You need edit access to change members"
780
+ />,
781
+ );
782
+ }
783
+
784
+ it('shows the reason tooltip on hover when disabled with a reason', async () => {
785
+ renderTokenizer();
786
+ const tooltip = screen.getByRole('tooltip', h);
787
+ expect(tooltip).toHaveTextContent(
788
+ 'You need edit access to change members',
789
+ );
790
+ const wrapper = screen.getByRole('group', {name: 'Members'});
791
+ fireEvent.mouseEnter(wrapper);
792
+ await waitFor(() => expect(isOpen(tooltip)).toBe(true));
793
+ fireEvent.mouseLeave(wrapper);
794
+ await waitFor(() => expect(isOpen(tooltip)).toBe(false));
795
+ });
796
+
797
+ it('shows the reason tooltip on keyboard focus', async () => {
798
+ const user = userEvent.setup();
799
+ renderTokenizer();
800
+ const tooltip = screen.getByRole('tooltip', h);
801
+ await user.tab();
802
+ expect(screen.getByRole('combobox')).toHaveFocus();
803
+ await waitFor(() => expect(isOpen(tooltip)).toBe(true));
804
+ });
805
+
806
+ it('does not render a tooltip when not disabled', () => {
807
+ render(
808
+ <Tokenizer
809
+ label="Members"
810
+ searchSource={userSource}
811
+ value={[]}
812
+ onChange={() => {}}
813
+ disabledMessage="You need edit access to change members"
814
+ />,
815
+ );
816
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
817
+ });
818
+
819
+ it('does not render a tooltip when disabled without a reason', () => {
820
+ render(
821
+ <Tokenizer
822
+ label="Members"
823
+ searchSource={userSource}
824
+ value={[]}
825
+ onChange={() => {}}
826
+ isDisabled
827
+ />,
828
+ );
829
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
830
+ });
831
+
832
+ it('keeps the input focusable via aria-disabled when a reason is provided', () => {
833
+ renderTokenizer();
834
+ const input = screen.getByRole('combobox');
835
+ expect(input).not.toBeDisabled();
836
+ expect(input).toHaveAttribute('aria-disabled', 'true');
837
+ });
838
+
839
+ it('links the reason tooltip via aria-describedby', () => {
840
+ renderTokenizer();
841
+ const input = screen.getByRole('combobox');
842
+ const tooltip = screen.getByRole('tooltip', h);
843
+ expect(input.getAttribute('aria-describedby')).toContain(tooltip.id);
844
+ });
845
+
846
+ it('blocks input while focusable-disabled', async () => {
847
+ const user = userEvent.setup();
848
+ const onChange = vi.fn();
849
+ renderTokenizer({onChange});
850
+ const input = screen.getByRole('combobox');
851
+ input.focus();
852
+ await user.keyboard('Ali');
853
+ expect((input as HTMLInputElement).value).toBe('');
854
+ expect(onChange).not.toHaveBeenCalled();
855
+ });
856
+
857
+ it('keeps the input natively disabled when disabled without a reason', () => {
858
+ render(
859
+ <Tokenizer
860
+ label="Members"
861
+ searchSource={userSource}
862
+ value={[]}
863
+ onChange={() => {}}
864
+ isDisabled
865
+ />,
866
+ );
867
+ expect(screen.getByRole('combobox')).toBeDisabled();
868
+ });
869
+ });
766
870
  });
@@ -42,6 +42,7 @@ import {Token} from '../Token';
42
42
  import {renderIconSlot, type IconType} from '../Icon';
43
43
  import {OverflowList} from '../OverflowList';
44
44
  import {useLayer} from '../Layer/useLayer';
45
+ import {useTooltip} from '../Tooltip';
45
46
  import {
46
47
  colorVars,
47
48
  spacingVars,
@@ -145,6 +146,17 @@ export interface TokenizerProps<T extends SearchableItem> extends Omit<
145
146
  emptySearchResultsText?: string;
146
147
  /** Whether the input is disabled. @default false */
147
148
  isDisabled?: boolean;
149
+ /**
150
+ * Explains why the tokenizer is disabled. When set together with
151
+ * `isDisabled`, the tokenizer shows a tooltip with this text on hover and
152
+ * keyboard focus, and the input stays focusable (via `aria-disabled`) so the
153
+ * reason is discoverable by keyboard and assistive technology. Input stays
154
+ * blocked.
155
+ *
156
+ * Use this instead of wrapping a disabled tokenizer in `Tooltip` — disabled
157
+ * controls don't emit the pointer events an external tooltip needs.
158
+ */
159
+ disabledMessage?: string;
148
160
  /** Show clear button (clears all tokens). @default false */
149
161
  hasClear?: boolean;
150
162
  /**
@@ -222,7 +234,10 @@ const styles = stylex.create({
222
234
  },
223
235
  endSection: {
224
236
  position: 'absolute',
225
- insetInlineEnd: `calc(${spacingVars['--spacing-1']} - 1px)`,
237
+ // Match the field's inline padding (inputWrapperStyles.base uses
238
+ // spacing-2) so end content (clear button, resultCount) lines up with
239
+ // the text/start-icon inset instead of hugging the border at ~3px.
240
+ insetInlineEnd: spacingVars['--spacing-2'],
226
241
  display: 'flex',
227
242
  alignItems: 'center',
228
243
  gap: spacingVars['--spacing-2'],
@@ -362,6 +377,7 @@ export function Tokenizer<T extends SearchableItem>({
362
377
  maxMenuItems,
363
378
  emptySearchResultsText,
364
379
  isDisabled = false,
380
+ disabledMessage,
365
381
  hasClear = false,
366
382
  endContent,
367
383
  hasAutoFocus,
@@ -387,6 +403,19 @@ export function Tokenizer<T extends SearchableItem>({
387
403
  const inputRef = useRef<HTMLInputElement>(null);
388
404
  const wrapperRef = useRef<HTMLDivElement>(null);
389
405
 
406
+ // Disabled-reason tooltip. Disabled controls swallow pointer events, so the
407
+ // tooltip listeners attach to the input wrapper and the typeahead input stays
408
+ // perceivable via aria-disabled instead of the disabled attribute. Input is
409
+ // blocked by the isDisabled guards in BaseTypeahead and handleWrapperClick.
410
+ const showsDisabledMessage = isDisabled && !!disabledMessage;
411
+ const disabledMessageTooltip = useTooltip({
412
+ placement: 'above',
413
+ // The wrapper is not naturally focusable; focusin bubbles up from the
414
+ // input, so always attach focus listeners.
415
+ focusTrigger: 'always',
416
+ isEnabled: showsDisabledMessage,
417
+ });
418
+
390
419
  useImperativeHandle(handleRef, () => ({
391
420
  focus() {
392
421
  inputRef.current?.focus();
@@ -617,6 +646,7 @@ export function Tokenizer<T extends SearchableItem>({
617
646
  [
618
647
  description ? descriptionId : null,
619
648
  status?.message ? statusMessageId : null,
649
+ showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
620
650
  ]
621
651
  .filter(Boolean)
622
652
  .join(' ') || undefined;
@@ -656,7 +686,13 @@ export function Tokenizer<T extends SearchableItem>({
656
686
 
657
687
  const wrapperContent = (
658
688
  <div
659
- ref={wrapperRef}
689
+ ref={el => {
690
+ wrapperRef.current = el;
691
+ // Anchor + hover/focus listeners for the disabled-message tooltip.
692
+ // Handlers are gated internally by isEnabled, so attaching
693
+ // unconditionally is safe.
694
+ disabledMessageTooltip.ref(el);
695
+ }}
660
696
  role="group"
661
697
  aria-label={label}
662
698
  onClick={handleWrapperClick}
@@ -707,6 +743,7 @@ export function Tokenizer<T extends SearchableItem>({
707
743
  maxMenuItems={maxMenuItems}
708
744
  emptySearchResultsText={emptySearchResultsText}
709
745
  isDisabled={isDisabled}
746
+ isFocusableDisabled={showsDisabledMessage}
710
747
  hasAutoFocus={hasAutoFocus}
711
748
  inputId={inputId}
712
749
  ariaDescribedBy={ariaDescribedBy}
@@ -828,6 +865,8 @@ export function Tokenizer<T extends SearchableItem>({
828
865
  className={className}
829
866
  style={style}>
830
867
  {tokenizerContent}
868
+ {showsDisabledMessage &&
869
+ disabledMessageTooltip.renderTooltip(disabledMessage)}
831
870
  </Field>
832
871
  );
833
872
  }
@@ -7,6 +7,25 @@ export const docs = {
7
7
  displayName: 'Toolbar',
8
8
  category: 'Action',
9
9
  keywords: ['toolbar', 'nav', 'bar', 'actions', 'buttonbar', 'header', 'footer', 'action-bar', 'control-bar'],
10
+ playground: {
11
+ defaults: {
12
+ label: 'Table actions',
13
+ size: 'sm',
14
+ dividers: ['bottom'],
15
+ startContent: {
16
+ __element: 'TabList',
17
+ props: {value: 'overview'},
18
+ children: [
19
+ {__element: 'Tab', props: {label: 'Overview', value: 'overview'}},
20
+ {__element: 'Tab', props: {label: 'Activity', value: 'activity'}},
21
+ ],
22
+ },
23
+ endContent: [
24
+ {__element: 'Selector', props: {label: 'Status', isLabelHidden: true, placeholder: 'Status', size: 'sm', options: ['Open', 'In progress', 'Done']}},
25
+ {__element: 'Button', props: {label: 'New item', variant: 'primary', size: 'sm'}},
26
+ ],
27
+ },
28
+ },
10
29
  theming: {
11
30
  targets: [
12
31
  {className: 'astryx-toolbar', states: ['size']},
@@ -29,21 +48,62 @@ export const docs = {
29
48
  name: 'startContent',
30
49
  type: 'ReactNode',
31
50
  description: 'Content aligned to the start (left in LTR).',
32
- slotElements: [{__element: 'Icon', props: {icon: 'check', size: 'sm'}}],
51
+ slotElements: [
52
+ {__element: 'Text', props: {type: 'body', weight: 'bold'}, children: 'Title'},
53
+ {__element: 'Button', props: {label: 'Back', variant: 'ghost', size: 'sm'}},
54
+ {__element: 'IconButton', props: {label: 'Filter', icon: {__element: 'Icon', props: {icon: 'check', size: 'sm'}}, variant: 'ghost', size: 'sm'}},
55
+ {
56
+ __element: 'TabList',
57
+ props: {value: 'overview'},
58
+ children: [
59
+ {__element: 'Tab', props: {label: 'Overview', value: 'overview'}},
60
+ {__element: 'Tab', props: {label: 'Activity', value: 'activity'}},
61
+ ],
62
+ },
63
+ {
64
+ __element: 'SegmentedControl',
65
+ props: {label: 'View', value: 'list'},
66
+ children: [
67
+ {__element: 'SegmentedControlItem', props: {label: 'List', value: 'list'}},
68
+ {__element: 'SegmentedControlItem', props: {label: 'Grid', value: 'grid'}},
69
+ ],
70
+ },
71
+ {__element: 'Selector', props: {label: 'Status', isLabelHidden: true, placeholder: 'Status', size: 'sm', options: ['Open', 'In progress', 'Done']}},
72
+ ],
33
73
  },
34
74
  {
35
75
  name: 'centerContent',
36
76
  type: 'ReactNode',
37
77
  description:
38
78
  'Centered content. Switches layout to CSS grid (1fr auto 1fr).',
39
- slotElements: [{__element: 'Text', props: {type: 'body', weight: 'bold'}, children: 'Center'}],
79
+ slotElements: [
80
+ {__element: 'Text', props: {type: 'body', weight: 'bold'}, children: 'Center'},
81
+ {
82
+ __element: 'SegmentedControl',
83
+ props: {label: 'View', value: 'list'},
84
+ children: [
85
+ {__element: 'SegmentedControlItem', props: {label: 'List', value: 'list'}},
86
+ {__element: 'SegmentedControlItem', props: {label: 'Grid', value: 'grid'}},
87
+ ],
88
+ },
89
+ {
90
+ __element: 'TabList',
91
+ props: {value: 'overview'},
92
+ children: [
93
+ {__element: 'Tab', props: {label: 'Overview', value: 'overview'}},
94
+ {__element: 'Tab', props: {label: 'Activity', value: 'activity'}},
95
+ ],
96
+ },
97
+ ],
40
98
  },
41
99
  {
42
100
  name: 'endContent',
43
101
  type: 'ReactNode',
44
102
  description: 'Content aligned to the end (right in LTR).',
45
103
  slotElements: [
46
- {__element: 'Icon', props: {icon: 'chevronDown', size: 'sm'}},
104
+ {__element: 'Button', props: {label: 'Save', variant: 'primary', size: 'sm'}},
105
+ {__element: 'IconButton', props: {label: 'More', icon: {__element: 'Icon', props: {icon: 'chevronDown', size: 'sm'}}, variant: 'ghost', size: 'sm'}},
106
+ {__element: 'Selector', props: {label: 'Sort', isLabelHidden: true, placeholder: 'Sort by', size: 'sm', options: ['Newest', 'Oldest', 'A–Z']}},
47
107
  {__element: 'Badge', props: {label: '3'}},
48
108
  ],
49
109
  },
@@ -51,14 +111,14 @@ export const docs = {
51
111
  name: 'size',
52
112
  type: "'sm' | 'md' | 'lg'",
53
113
  description:
54
- 'Size of the toolbar. Controls minimum height and coordinates with Button, TextInput, TabList, and Selector — children inherit this size as their default via SizeContext.',
114
+ 'Size of the toolbar. Controls minimum height and coordinates with Button, TextInput, TabList, and Selector; children inherit this size as their default via SizeContext.',
55
115
  default: "'md'",
56
116
  },
57
117
  {
58
118
  name: 'gap',
59
119
  type: 'SpacingStep',
60
120
  description: 'Gap between items within each slot.',
61
- default: '2',
121
+ default: '1',
62
122
  },
63
123
  {
64
124
  name: 'orientation',
@@ -71,9 +71,12 @@ describe('Toolbar', () => {
71
71
  expect(screen.getByTestId('center')).toBeInTheDocument();
72
72
  expect(screen.getByTestId('end')).toBeInTheDocument();
73
73
 
74
- // Three-slot layout produces 3 child divs
74
+ // Three-slot layout produces 3 child divs (plus the aria-hidden
75
+ // keyboard-hint popover, which is excluded here as an implementation detail)
75
76
  const toolbar = screen.getByRole('toolbar');
76
- expect(toolbar.children).toHaveLength(3);
77
+ expect(toolbar.querySelectorAll(':scope > :not([popover])')).toHaveLength(
78
+ 3,
79
+ );
77
80
  });
78
81
 
79
82
  it('renders two-slot layout without centerContent', () => {
@@ -87,9 +90,12 @@ describe('Toolbar', () => {
87
90
  expect(screen.getByTestId('start')).toBeInTheDocument();
88
91
  expect(screen.getByTestId('end')).toBeInTheDocument();
89
92
 
90
- // Two-slot layout produces 2 child divs
93
+ // Two-slot layout produces 2 child divs (plus the aria-hidden
94
+ // keyboard-hint popover, excluded here)
91
95
  const toolbar = screen.getByRole('toolbar');
92
- expect(toolbar.children).toHaveLength(2);
96
+ expect(toolbar.querySelectorAll(':scope > :not([popover])')).toHaveLength(
97
+ 2,
98
+ );
93
99
  });
94
100
 
95
101
  it('renders start-only layout', () => {
@@ -101,7 +107,9 @@ describe('Toolbar', () => {
101
107
  );
102
108
  expect(screen.getByTestId('start')).toBeInTheDocument();
103
109
  const toolbar = screen.getByRole('toolbar');
104
- expect(toolbar.children).toHaveLength(1);
110
+ expect(toolbar.querySelectorAll(':scope > :not([popover])')).toHaveLength(
111
+ 1,
112
+ );
105
113
  });
106
114
 
107
115
  it('renders end-only layout', () => {
@@ -113,7 +121,9 @@ describe('Toolbar', () => {
113
121
  );
114
122
  expect(screen.getByTestId('end')).toBeInTheDocument();
115
123
  const toolbar = screen.getByRole('toolbar');
116
- expect(toolbar.children).toHaveLength(1);
124
+ expect(toolbar.querySelectorAll(':scope > :not([popover])')).toHaveLength(
125
+ 1,
126
+ );
117
127
  });
118
128
 
119
129
  it('sets aria-orientation to horizontal by default', () => {
@@ -256,4 +266,97 @@ describe('Toolbar', () => {
256
266
  render(<Toolbar label="Actions" data-testid="my-toolbar" />);
257
267
  expect(screen.getByTestId('my-toolbar')).toBe(screen.getByRole('toolbar'));
258
268
  });
269
+
270
+ it('is a single tab stop — only one item is tabbable (navigation-3)', () => {
271
+ render(
272
+ <Toolbar
273
+ label="Actions"
274
+ startContent={
275
+ <>
276
+ <button type="button">Cut</button>
277
+ <button type="button">Copy</button>
278
+ <button type="button">Paste</button>
279
+ </>
280
+ }
281
+ />,
282
+ );
283
+ const buttons = screen.getAllByRole('button');
284
+ const tabbable = buttons.filter(b => b.getAttribute('tabindex') === '0');
285
+ expect(tabbable).toHaveLength(1);
286
+ expect(buttons[0]).toHaveAttribute('tabindex', '0');
287
+ expect(buttons[1]).toHaveAttribute('tabindex', '-1');
288
+ expect(buttons[2]).toHaveAttribute('tabindex', '-1');
289
+ });
290
+
291
+ it('does not steal caret keys from a text input mid-line (navigation-4)', async () => {
292
+ const user = userEvent.setup();
293
+ render(
294
+ <Toolbar
295
+ label="Search"
296
+ startContent={
297
+ <>
298
+ <input type="text" aria-label="Query" defaultValue="hello" />
299
+ <button type="button">Go</button>
300
+ </>
301
+ }
302
+ />,
303
+ );
304
+ const inputEl = screen.getByLabelText('Query');
305
+ if (!(inputEl instanceof HTMLInputElement)) {
306
+ throw new Error('expected an input');
307
+ }
308
+ inputEl.focus();
309
+ inputEl.setSelectionRange(1, 1); // caret mid-line
310
+ await user.keyboard('{ArrowRight}');
311
+ // Caret movement stays in the input; focus is not stolen by the toolbar.
312
+ expect(document.activeElement).toBe(inputEl);
313
+ });
314
+
315
+ it('composes consumer onKeyDown with internal arrow navigation', async () => {
316
+ const user = userEvent.setup();
317
+ const onKeyDown = vi.fn();
318
+
319
+ render(
320
+ <Toolbar
321
+ label="Actions"
322
+ onKeyDown={onKeyDown}
323
+ startContent={
324
+ <>
325
+ <button type="button">Cut</button>
326
+ <button type="button">Copy</button>
327
+ </>
328
+ }
329
+ />,
330
+ );
331
+
332
+ const buttons = screen.getAllByRole('button');
333
+ buttons[0].focus();
334
+ await user.keyboard('{ArrowRight}');
335
+
336
+ expect(onKeyDown).toHaveBeenCalled();
337
+ expect(buttons[1]).toHaveFocus();
338
+ });
339
+
340
+ it('respects preventDefault from consumer onKeyDown', async () => {
341
+ const user = userEvent.setup();
342
+
343
+ render(
344
+ <Toolbar
345
+ label="Actions"
346
+ onKeyDown={e => e.preventDefault()}
347
+ startContent={
348
+ <>
349
+ <button type="button">Cut</button>
350
+ <button type="button">Copy</button>
351
+ </>
352
+ }
353
+ />,
354
+ );
355
+
356
+ const buttons = screen.getAllByRole('button');
357
+ buttons[0].focus();
358
+ await user.keyboard('{ArrowRight}');
359
+
360
+ expect(buttons[0]).toHaveFocus();
361
+ });
259
362
  });
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file Toolbar.tsx
7
- * @input Uses Section, SizeContext, useListFocus, StyleX, spacingVars, sizeVars
7
+ * @input Uses Section, SizeContext, useListFocus, useKeyboardHint, StyleX, spacingVars, sizeVars
8
8
  * @output Exports Toolbar component and ToolbarProps
9
9
  * @position Core implementation; consumed by index.ts
10
10
  *
@@ -16,7 +16,7 @@
16
16
  * - /packages/cli/templates/blocks/components/Toolbar/ (showcase blocks)
17
17
  */
18
18
 
19
- import type {ReactNode} from 'react';
19
+ import {useCallback, type ReactNode} from 'react';
20
20
  import type {BaseProps} from '../BaseProps';
21
21
  import type {SectionVariant} from '../Section/Section';
22
22
  import type {SpacingStep} from '../utils/types';
@@ -26,6 +26,7 @@ import {spacingVars, sizeVars} from '../theme/tokens.stylex';
26
26
  import {mergeProps} from '../utils';
27
27
  import {Section} from '../Section/Section';
28
28
  import {useListFocus} from '../hooks/useListFocus';
29
+ import {useKeyboardHint} from '../hooks/useKeyboardHint';
29
30
  import {SizeProvider} from '../SizeContext/SizeContext';
30
31
  import {edgeCompSlot} from '../Layout/edgeCompensation.stylex';
31
32
  import {themeProps} from '../utils/themeProps';
@@ -227,6 +228,12 @@ export function Toolbar({
227
228
  className,
228
229
  style,
229
230
  ref,
231
+ onKeyDown: onKeyDownProp,
232
+ onFocus: onFocusProp,
233
+ onBlur: onBlurProp,
234
+ role: _role,
235
+ 'aria-label': _ariaLabel,
236
+ 'aria-orientation': _ariaOrientation,
230
237
  ...props
231
238
  }: ToolbarProps) {
232
239
  const hasCenterContent = centerContent != null;
@@ -235,11 +242,55 @@ export function Toolbar({
235
242
 
236
243
  const gapVar = spacingVars[spacingStepToVar[gap]] as string;
237
244
 
238
- const {listRef, handleKeyDown} = useListFocus<HTMLDivElement>({
239
- itemSelector: 'button, input, [tabindex="0"]',
245
+ const {listRef, handleKeyDown, handleFocus} = useListFocus<HTMLDivElement>({
246
+ itemSelector: 'button, input, [tabindex]',
240
247
  orientation,
248
+ hasRovingTabIndex: true,
249
+ hasCaretGuard: true,
241
250
  });
242
251
 
252
+ const {
253
+ hintElement,
254
+ onKeyDown: onHintKeyDown,
255
+ onFocus: onHintFocus,
256
+ onBlur: onHintBlur,
257
+ } = useKeyboardHint({orientation});
258
+
259
+ const handleToolbarKeyDown = useCallback(
260
+ (e: React.KeyboardEvent<HTMLDivElement>) => {
261
+ onKeyDownProp?.(e);
262
+ if (e.defaultPrevented) {
263
+ return;
264
+ }
265
+ onHintKeyDown(e);
266
+ handleKeyDown(e);
267
+ },
268
+ [onKeyDownProp, onHintKeyDown, handleKeyDown],
269
+ );
270
+
271
+ const handleToolbarFocus = useCallback(
272
+ (e: React.FocusEvent<HTMLDivElement>) => {
273
+ onFocusProp?.(e);
274
+ if (e.defaultPrevented) {
275
+ return;
276
+ }
277
+ onHintFocus(e);
278
+ handleFocus(e);
279
+ },
280
+ [onFocusProp, onHintFocus, handleFocus],
281
+ );
282
+
283
+ const handleToolbarBlur = useCallback(
284
+ (e: React.FocusEvent<HTMLDivElement>) => {
285
+ onBlurProp?.(e);
286
+ if (e.defaultPrevented) {
287
+ return;
288
+ }
289
+ onHintBlur(e);
290
+ },
291
+ [onBlurProp, onHintBlur],
292
+ );
293
+
243
294
  return (
244
295
  <SizeProvider value={size}>
245
296
  <Section
@@ -255,7 +306,9 @@ export function Toolbar({
255
306
  role="toolbar"
256
307
  aria-label={label}
257
308
  aria-orientation={orientation}
258
- onKeyDown={handleKeyDown}
309
+ onKeyDown={handleToolbarKeyDown}
310
+ onFocus={handleToolbarFocus}
311
+ onBlur={handleToolbarBlur}
259
312
  {...mergeProps(
260
313
  themeProps('toolbar', {size}),
261
314
  stylex.props(
@@ -320,6 +373,7 @@ export function Toolbar({
320
373
  )}
321
374
  </>
322
375
  )}
376
+ {hintElement}
323
377
  </div>
324
378
  </Section>
325
379
  </SizeProvider>
@@ -55,6 +55,19 @@ describe('Tooltip', () => {
55
55
  expect(screen.getByRole('button', {name: 'Trigger'})).toBeInTheDocument();
56
56
  });
57
57
 
58
+ it('gives the tooltip layer role="tooltip" linked from the trigger', () => {
59
+ render(
60
+ <Tooltip content="Tooltip text">
61
+ <button type="button">Trigger</button>
62
+ </Tooltip>,
63
+ );
64
+ const layer = screen.getByRole('tooltip', {hidden: true});
65
+ expect(layer).toHaveTextContent('Tooltip text');
66
+ // ARIA tooltip pattern: trigger references the layer via aria-describedby.
67
+ const trigger = screen.getByRole('button', {name: 'Trigger'});
68
+ expect(trigger.getAttribute('aria-describedby')).toBe(layer.id);
69
+ });
70
+
58
71
  it('calls onOpenChange(true) when shown via hover', async () => {
59
72
  const onOpenChange = vi.fn();
60
73
  render(
@@ -140,4 +153,72 @@ describe('Tooltip', () => {
140
153
  });
141
154
  });
142
155
  });
156
+
157
+ describe('WCAG 1.4.13 — content on hover or focus', () => {
158
+ it('dismisses on Escape while visible (dismissible)', async () => {
159
+ const onOpenChange = vi.fn();
160
+ render(
161
+ <Tooltip content="Dismiss me" onOpenChange={onOpenChange} delay={0}>
162
+ <button type="button">Trigger</button>
163
+ </Tooltip>,
164
+ );
165
+
166
+ const trigger = screen.getByRole('button', {name: 'Trigger'});
167
+ fireEvent.mouseEnter(trigger);
168
+ await waitFor(() => {
169
+ expect(onOpenChange).toHaveBeenCalledWith(true);
170
+ });
171
+
172
+ fireEvent.keyDown(document, {key: 'Escape'});
173
+ await waitFor(() => {
174
+ expect(onOpenChange).toHaveBeenCalledWith(false);
175
+ });
176
+ });
177
+
178
+ it('ignores Escape during IME composition', async () => {
179
+ const onOpenChange = vi.fn();
180
+ render(
181
+ <Tooltip content="Stay" onOpenChange={onOpenChange} delay={0}>
182
+ <button type="button">Trigger</button>
183
+ </Tooltip>,
184
+ );
185
+
186
+ const trigger = screen.getByRole('button', {name: 'Trigger'});
187
+ fireEvent.mouseEnter(trigger);
188
+ await waitFor(() => {
189
+ expect(onOpenChange).toHaveBeenCalledWith(true);
190
+ });
191
+ onOpenChange.mockClear();
192
+
193
+ fireEvent.keyDown(document, {key: 'Escape', isComposing: true});
194
+ // Give any (incorrect) async hide a chance to run.
195
+ await new Promise(r => setTimeout(r, 20));
196
+ expect(onOpenChange).not.toHaveBeenCalledWith(false);
197
+ });
198
+
199
+ it('stays open when the pointer moves onto the tooltip surface (hoverable)', async () => {
200
+ const onOpenChange = vi.fn();
201
+ render(
202
+ <Tooltip content="Hover me" onOpenChange={onOpenChange} delay={0}>
203
+ <button type="button">Trigger</button>
204
+ </Tooltip>,
205
+ );
206
+
207
+ const trigger = screen.getByRole('button', {name: 'Trigger'});
208
+ fireEvent.mouseEnter(trigger);
209
+ await waitFor(() => {
210
+ expect(onOpenChange).toHaveBeenCalledWith(true);
211
+ });
212
+ onOpenChange.mockClear();
213
+
214
+ // Pointer leaves the trigger but enters the tooltip surface before the
215
+ // hover-bridge grace period elapses — the tooltip must not hide.
216
+ fireEvent.mouseLeave(trigger);
217
+ const layer = screen.getByRole('tooltip', {hidden: true});
218
+ fireEvent.mouseEnter(layer);
219
+
220
+ await new Promise(r => setTimeout(r, 150));
221
+ expect(onOpenChange).not.toHaveBeenCalledWith(false);
222
+ });
223
+ });
143
224
  });