@astryxdesign/core 0.1.2 → 0.1.3-canary.6d57c8d

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 (567) hide show
  1. package/CHANGELOG.md +165 -0
  2. package/README.md +12 -12
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +11 -5
  5. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
  6. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  7. package/dist/Breadcrumbs/BreadcrumbItem.js +24 -5
  8. package/dist/Button/Button.d.ts.map +1 -1
  9. package/dist/Button/Button.js +2 -4
  10. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  11. package/dist/ButtonGroup/ButtonGroup.js +0 -1
  12. package/dist/Calendar/Calendar.d.ts +5 -4
  13. package/dist/Calendar/Calendar.d.ts.map +1 -1
  14. package/dist/Calendar/Calendar.js +82 -43
  15. package/dist/Calendar/hooks/index.d.ts +0 -2
  16. package/dist/Calendar/hooks/index.d.ts.map +1 -1
  17. package/dist/Calendar/hooks/index.js +1 -2
  18. package/dist/Calendar/index.d.ts +3 -3
  19. package/dist/Calendar/index.d.ts.map +1 -1
  20. package/dist/Calendar/index.js +1 -1
  21. package/dist/Calendar/styles.d.ts +3 -9
  22. package/dist/Calendar/styles.d.ts.map +1 -1
  23. package/dist/Calendar/styles.js +3 -11
  24. package/dist/Carousel/Carousel.d.ts.map +1 -1
  25. package/dist/Carousel/Carousel.js +17 -3
  26. package/dist/Center/Center.d.ts +11 -1
  27. package/dist/Center/Center.d.ts.map +1 -1
  28. package/dist/Center/Center.js +9 -3
  29. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  30. package/dist/Chat/ChatComposerInput.js +0 -1
  31. package/dist/Chat/ChatMessageList.d.ts +14 -1
  32. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  33. package/dist/Chat/ChatMessageList.js +2 -0
  34. package/dist/Chat/useTriggerMenu.d.ts +8 -1
  35. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  36. package/dist/Chat/useTriggerMenu.js +15 -3
  37. package/dist/CheckboxInput/CheckboxInput.d.ts +23 -2
  38. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  39. package/dist/CheckboxInput/CheckboxInput.js +51 -9
  40. package/dist/CheckboxList/CheckboxList.d.ts +13 -1
  41. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  42. package/dist/CheckboxList/CheckboxList.js +39 -9
  43. package/dist/CheckboxList/CheckboxListContext.d.ts +7 -0
  44. package/dist/CheckboxList/CheckboxListContext.d.ts.map +1 -1
  45. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  46. package/dist/CheckboxList/CheckboxListItem.js +0 -1
  47. package/dist/Citation/Citation.d.ts.map +1 -1
  48. package/dist/Citation/Citation.js +9 -5
  49. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  50. package/dist/CodeBlock/CodeBlock.js +51 -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 +167 -99
  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/Field/Field.d.ts +19 -2
  71. package/dist/Field/Field.d.ts.map +1 -1
  72. package/dist/Field/Field.js +4 -0
  73. package/dist/Field/FieldLabel.d.ts +21 -2
  74. package/dist/Field/FieldLabel.d.ts.map +1 -1
  75. package/dist/Field/FieldLabel.js +41 -26
  76. package/dist/FileInput/FileInput.d.ts +22 -1
  77. package/dist/FileInput/FileInput.d.ts.map +1 -1
  78. package/dist/FileInput/FileInput.js +56 -10
  79. package/dist/Grid/Grid.d.ts +11 -1
  80. package/dist/Grid/Grid.d.ts.map +1 -1
  81. package/dist/Grid/Grid.js +32 -6
  82. package/dist/InputGroup/InputGroup.d.ts +4 -3
  83. package/dist/InputGroup/InputGroup.d.ts.map +1 -1
  84. package/dist/InputGroup/InputGroup.js +16 -6
  85. package/dist/InputGroup/InputGroupContext.d.ts +4 -0
  86. package/dist/InputGroup/InputGroupContext.d.ts.map +1 -1
  87. package/dist/InputGroup/InputGroupContext.js +2 -2
  88. package/dist/InputGroup/groupStyles.d.ts +1 -1
  89. package/dist/InputGroup/groupStyles.d.ts.map +1 -1
  90. package/dist/InputGroup/groupStyles.js +3 -3
  91. package/dist/InputGroup/index.d.ts +1 -0
  92. package/dist/InputGroup/index.d.ts.map +1 -1
  93. package/dist/Kbd/Kbd.d.ts.map +1 -1
  94. package/dist/Kbd/Kbd.js +33 -1
  95. package/dist/Layer/layerAnimations.stylex.d.ts +4 -0
  96. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  97. package/dist/Layer/layerAnimations.stylex.js +8 -4
  98. package/dist/Layer/useLayer.d.ts +10 -0
  99. package/dist/Layer/useLayer.d.ts.map +1 -1
  100. package/dist/Layer/useLayer.js +64 -9
  101. package/dist/Layout/Layout.d.ts +4 -11
  102. package/dist/Layout/Layout.d.ts.map +1 -1
  103. package/dist/Layout/Layout.js +10 -11
  104. package/dist/Layout/LayoutFooter.d.ts +2 -2
  105. package/dist/Layout/LayoutFooter.d.ts.map +1 -1
  106. package/dist/Layout/LayoutHeader.d.ts +2 -2
  107. package/dist/Layout/LayoutHeader.d.ts.map +1 -1
  108. package/dist/Layout/LayoutPanel.d.ts +2 -2
  109. package/dist/Layout/LayoutPanel.d.ts.map +1 -1
  110. package/dist/Layout/padding.stylex.d.ts +51 -0
  111. package/dist/Layout/padding.stylex.d.ts.map +1 -1
  112. package/dist/Layout/padding.stylex.js +63 -0
  113. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  114. package/dist/Lightbox/Lightbox.js +4 -2
  115. package/dist/Link/Link.d.ts +16 -1
  116. package/dist/Link/Link.d.ts.map +1 -1
  117. package/dist/Link/Link.js +18 -7
  118. package/dist/Markdown/Markdown.d.ts.map +1 -1
  119. package/dist/Markdown/Markdown.js +7 -0
  120. package/dist/MoreMenu/MoreMenu.d.ts +1 -7
  121. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  122. package/dist/MoreMenu/MoreMenu.js +0 -2
  123. package/dist/MultiSelector/MultiSelector.d.ts +27 -2
  124. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  125. package/dist/MultiSelector/MultiSelector.js +141 -42
  126. package/dist/MultiSelector/hooks.d.ts +12 -1
  127. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  128. package/dist/MultiSelector/hooks.js +14 -1
  129. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  130. package/dist/NavMenu/NavHeadingMenu.js +34 -3
  131. package/dist/NumberInput/NumberInput.d.ts +23 -2
  132. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  133. package/dist/NumberInput/NumberInput.js +62 -12
  134. package/dist/Pagination/Pagination.d.ts +1 -1
  135. package/dist/Pagination/Pagination.d.ts.map +1 -1
  136. package/dist/Pagination/Pagination.js +15 -1
  137. package/dist/Popover/Popover.d.ts +18 -2
  138. package/dist/Popover/Popover.d.ts.map +1 -1
  139. package/dist/Popover/Popover.js +5 -2
  140. package/dist/Popover/usePopover.d.ts +38 -3
  141. package/dist/Popover/usePopover.d.ts.map +1 -1
  142. package/dist/Popover/usePopover.js +24 -9
  143. package/dist/PowerSearch/PowerSearch.d.ts +11 -1
  144. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  145. package/dist/PowerSearch/PowerSearch.js +6 -1
  146. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  147. package/dist/ProgressBar/ProgressBar.js +3 -5
  148. package/dist/RadioList/RadioList.d.ts +20 -2
  149. package/dist/RadioList/RadioList.d.ts.map +1 -1
  150. package/dist/RadioList/RadioList.js +105 -9
  151. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  152. package/dist/RadioList/RadioListItem.js +13 -2
  153. package/dist/SegmentedControl/SegmentedControl.d.ts +13 -2
  154. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  155. package/dist/SegmentedControl/SegmentedControl.js +78 -44
  156. package/dist/SegmentedControl/SegmentedControlContext.d.ts +7 -0
  157. package/dist/SegmentedControl/SegmentedControlContext.d.ts.map +1 -1
  158. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  159. package/dist/SegmentedControl/SegmentedControlItem.js +13 -2
  160. package/dist/Selector/Selector.d.ts +24 -1
  161. package/dist/Selector/Selector.d.ts.map +1 -1
  162. package/dist/Selector/Selector.js +122 -43
  163. package/dist/Selector/hooks.d.ts +8 -1
  164. package/dist/Selector/hooks.d.ts.map +1 -1
  165. package/dist/Selector/hooks.js +14 -1
  166. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  167. package/dist/SideNav/SideNavHeading.js +2 -0
  168. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  169. package/dist/SideNav/SideNavItem.js +1 -1
  170. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  171. package/dist/Skeleton/Skeleton.js +8 -2
  172. package/dist/Slider/Slider.d.ts +21 -0
  173. package/dist/Slider/Slider.d.ts.map +1 -1
  174. package/dist/Slider/Slider.js +36 -9
  175. package/dist/Spinner/Spinner.d.ts.map +1 -1
  176. package/dist/Spinner/Spinner.js +1 -1
  177. package/dist/Stack/Stack.d.ts +38 -23
  178. package/dist/Stack/Stack.d.ts.map +1 -1
  179. package/dist/Stack/Stack.js +25 -1
  180. package/dist/Stack/StackItem.d.ts +12 -23
  181. package/dist/Stack/StackItem.d.ts.map +1 -1
  182. package/dist/Stack/StackItem.js +8 -1
  183. package/dist/Switch/Switch.d.ts +23 -2
  184. package/dist/Switch/Switch.d.ts.map +1 -1
  185. package/dist/Switch/Switch.js +41 -11
  186. package/dist/TabList/Tab.d.ts.map +1 -1
  187. package/dist/TabList/Tab.js +6 -0
  188. package/dist/TabList/TabList.d.ts +16 -4
  189. package/dist/TabList/TabList.d.ts.map +1 -1
  190. package/dist/TabList/TabList.js +87 -10
  191. package/dist/TabList/TabListContext.d.ts +5 -0
  192. package/dist/TabList/TabListContext.d.ts.map +1 -1
  193. package/dist/TabList/TabListContext.js +5 -0
  194. package/dist/TabList/TabMenu.d.ts.map +1 -1
  195. package/dist/TabList/TabMenu.js +6 -1
  196. package/dist/Table/BaseTable.d.ts.map +1 -1
  197. package/dist/Table/BaseTable.js +11 -8
  198. package/dist/Table/Table.d.ts.map +1 -1
  199. package/dist/Table/Table.js +10 -1
  200. package/dist/Table/TableCell.d.ts +8 -1
  201. package/dist/Table/TableCell.d.ts.map +1 -1
  202. package/dist/Table/TableCell.js +10 -10
  203. package/dist/Table/TableHeaderCell.d.ts +8 -1
  204. package/dist/Table/TableHeaderCell.d.ts.map +1 -1
  205. package/dist/Table/TableHeaderCell.js +16 -16
  206. package/dist/Table/index.d.ts +2 -1
  207. package/dist/Table/index.d.ts.map +1 -1
  208. package/dist/Table/index.js +2 -2
  209. package/dist/Table/plugins/pagination/paginateData.d.ts +2 -1
  210. package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
  211. package/dist/Table/plugins/pagination/paginateData.js +8 -3
  212. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  213. package/dist/Table/plugins/pagination/useTablePagination.js +6 -1
  214. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  215. package/dist/Table/plugins/sortable/useTableSortable.js +59 -3
  216. package/dist/Table/tableContextMenu.d.ts +33 -0
  217. package/dist/Table/tableContextMenu.d.ts.map +1 -0
  218. package/dist/Table/tableContextMenu.js +133 -0
  219. package/dist/Table/types.d.ts +66 -0
  220. package/dist/Table/types.d.ts.map +1 -1
  221. package/dist/TextArea/TextArea.d.ts +22 -1
  222. package/dist/TextArea/TextArea.d.ts.map +1 -1
  223. package/dist/TextArea/TextArea.js +41 -9
  224. package/dist/TextInput/TextInput.d.ts +23 -2
  225. package/dist/TextInput/TextInput.d.ts.map +1 -1
  226. package/dist/TextInput/TextInput.js +55 -10
  227. package/dist/TimeInput/TimeInput.d.ts +23 -1
  228. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  229. package/dist/TimeInput/TimeInput.js +147 -76
  230. package/dist/Toast/Toast.d.ts.map +1 -1
  231. package/dist/Toast/Toast.js +14 -0
  232. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  233. package/dist/Toast/ToastViewport.js +131 -3
  234. package/dist/Tokenizer/Tokenizer.d.ts +12 -1
  235. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  236. package/dist/Tokenizer/Tokenizer.js +26 -4
  237. package/dist/Toolbar/Toolbar.d.ts +3 -3
  238. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  239. package/dist/Toolbar/Toolbar.js +51 -7
  240. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  241. package/dist/Tooltip/useTooltip.js +56 -9
  242. package/dist/TopNav/TopNavHeading.d.ts +7 -1
  243. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  244. package/dist/TopNav/TopNavHeading.js +8 -0
  245. package/dist/TreeList/TreeList.d.ts +1 -1
  246. package/dist/TreeList/TreeList.d.ts.map +1 -1
  247. package/dist/TreeList/TreeList.js +72 -2
  248. package/dist/TreeList/TreeListItem.d.ts +11 -1
  249. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  250. package/dist/TreeList/TreeListItem.js +51 -12
  251. package/dist/TreeList/treeListItem.markers.stylex.d.ts +16 -0
  252. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +1 -0
  253. package/dist/TreeList/treeListItem.markers.stylex.js +22 -0
  254. package/dist/Typeahead/BaseTypeahead.d.ts +13 -0
  255. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  256. package/dist/Typeahead/BaseTypeahead.js +69 -6
  257. package/dist/Typeahead/Typeahead.d.ts +26 -3
  258. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  259. package/dist/Typeahead/Typeahead.js +65 -29
  260. package/dist/VisuallyHidden/VisuallyHidden.d.ts +61 -0
  261. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -0
  262. package/dist/VisuallyHidden/VisuallyHidden.js +65 -0
  263. package/dist/VisuallyHidden/index.d.ts +11 -0
  264. package/dist/VisuallyHidden/index.d.ts.map +1 -0
  265. package/dist/VisuallyHidden/index.js +13 -0
  266. package/dist/astryx.css +18 -0
  267. package/dist/astryx.umd.js +55 -55
  268. package/dist/astryx.umd.js.map +4 -4
  269. package/dist/hooks/focusableSelector.d.ts +22 -0
  270. package/dist/hooks/focusableSelector.d.ts.map +1 -0
  271. package/dist/hooks/focusableSelector.js +24 -0
  272. package/dist/hooks/index.d.ts +12 -2
  273. package/dist/hooks/index.d.ts.map +1 -1
  274. package/dist/hooks/index.js +7 -2
  275. package/dist/hooks/useAnnounce.d.ts +40 -0
  276. package/dist/hooks/useAnnounce.d.ts.map +1 -0
  277. package/dist/hooks/useAnnounce.js +142 -0
  278. package/dist/hooks/useClickableContainer.d.ts +16 -1
  279. package/dist/hooks/useClickableContainer.d.ts.map +1 -1
  280. package/dist/hooks/useClickableContainer.js +16 -4
  281. package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
  282. package/dist/hooks/useEntryAnimation.js +4 -4
  283. package/dist/hooks/useFocusTrap.d.ts +18 -0
  284. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  285. package/dist/hooks/useFocusTrap.js +87 -3
  286. package/dist/hooks/useGridFocus.d.ts +88 -1
  287. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  288. package/dist/hooks/useGridFocus.js +261 -62
  289. package/dist/hooks/useKeyboardHint.d.ts +82 -0
  290. package/dist/hooks/useKeyboardHint.d.ts.map +1 -0
  291. package/dist/hooks/useKeyboardHint.js +220 -0
  292. package/dist/hooks/useListFocus.d.ts +78 -7
  293. package/dist/hooks/useListFocus.d.ts.map +1 -1
  294. package/dist/hooks/useListFocus.js +305 -52
  295. package/dist/hooks/useLongPress.d.ts +21 -0
  296. package/dist/hooks/useLongPress.d.ts.map +1 -0
  297. package/dist/hooks/useLongPress.js +89 -0
  298. package/dist/hooks/useTreeFocus.d.ts +157 -0
  299. package/dist/hooks/useTreeFocus.d.ts.map +1 -0
  300. package/dist/hooks/useTreeFocus.js +337 -0
  301. package/dist/hooks/useTypeahead.d.ts +63 -0
  302. package/dist/hooks/useTypeahead.d.ts.map +1 -0
  303. package/dist/hooks/useTypeahead.js +117 -0
  304. package/dist/index.d.ts +1 -0
  305. package/dist/index.d.ts.map +1 -1
  306. package/dist/index.js +1 -0
  307. package/dist/utils/dateTypes.d.ts +12 -0
  308. package/dist/utils/dateTypes.d.ts.map +1 -1
  309. package/dist/utils/dateTypes.js +41 -1
  310. package/dist/utils/index.d.ts +4 -0
  311. package/dist/utils/index.d.ts.map +1 -1
  312. package/dist/utils/index.js +3 -1
  313. package/dist/utils/inputAria.d.ts +29 -0
  314. package/dist/utils/inputAria.d.ts.map +1 -0
  315. package/dist/utils/inputAria.js +30 -0
  316. package/dist/utils/timeParser.d.ts.map +1 -1
  317. package/dist/utils/timeParser.js +5 -2
  318. package/docs.mjs +2 -2
  319. package/package.json +12 -8
  320. package/src/Avatar/Avatar.test.tsx +37 -0
  321. package/src/Avatar/Avatar.tsx +10 -5
  322. package/src/Breadcrumbs/BreadcrumbItem.tsx +25 -7
  323. package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -10
  324. package/src/Button/Button.tsx +3 -16
  325. package/src/ButtonGroup/ButtonGroup.test.tsx +9 -9
  326. package/src/ButtonGroup/ButtonGroup.tsx +0 -1
  327. package/src/Calendar/Calendar.doc.mjs +4 -4
  328. package/src/Calendar/Calendar.test.tsx +168 -30
  329. package/src/Calendar/Calendar.tsx +121 -66
  330. package/src/Calendar/hooks/index.ts +0 -6
  331. package/src/Calendar/index.ts +1 -3
  332. package/src/Calendar/styles.ts +4 -9
  333. package/src/Carousel/Carousel.doc.mjs +7 -1
  334. package/src/Carousel/Carousel.test.tsx +20 -0
  335. package/src/Carousel/Carousel.tsx +16 -1
  336. package/src/Center/Center.doc.mjs +12 -2
  337. package/src/Center/Center.tsx +28 -3
  338. package/src/Chat/ChatComposerInput.test.tsx +26 -7
  339. package/src/Chat/ChatComposerInput.tsx +0 -1
  340. package/src/Chat/ChatDictationButton.doc.mjs +1 -1
  341. package/src/Chat/ChatMessageList.doc.mjs +8 -0
  342. package/src/Chat/ChatMessageList.test.tsx +18 -0
  343. package/src/Chat/ChatMessageList.tsx +16 -0
  344. package/src/Chat/useTriggerMenu.tsx +22 -4
  345. package/src/CheckboxInput/CheckboxInput.doc.mjs +10 -0
  346. package/src/CheckboxInput/CheckboxInput.test.tsx +172 -27
  347. package/src/CheckboxInput/CheckboxInput.tsx +78 -6
  348. package/src/CheckboxList/CheckboxList.doc.mjs +9 -0
  349. package/src/CheckboxList/CheckboxList.test.tsx +192 -26
  350. package/src/CheckboxList/CheckboxList.tsx +56 -3
  351. package/src/CheckboxList/CheckboxListContext.tsx +7 -0
  352. package/src/CheckboxList/CheckboxListItem.tsx +0 -3
  353. package/src/Citation/Citation.doc.mjs +10 -0
  354. package/src/Citation/Citation.test.tsx +121 -0
  355. package/src/Citation/Citation.tsx +15 -3
  356. package/src/CodeBlock/CodeBlock.test.tsx +115 -0
  357. package/src/CodeBlock/CodeBlock.tsx +63 -33
  358. package/src/CommandPalette/CommandPalette.test.tsx +47 -1
  359. package/src/CommandPalette/CommandPalette.tsx +9 -21
  360. package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
  361. package/src/ContextMenu/ContextMenu.test.tsx +155 -1
  362. package/src/ContextMenu/ContextMenu.tsx +113 -16
  363. package/src/DateInput/DateInput.doc.mjs +286 -56
  364. package/src/DateInput/DateInput.test.tsx +248 -2
  365. package/src/DateInput/DateInput.tsx +196 -100
  366. package/src/DateRangeInput/DateRangeInput.doc.mjs +251 -46
  367. package/src/DateRangeInput/DateRangeInput.test.tsx +182 -20
  368. package/src/DateRangeInput/DateRangeInput.tsx +63 -5
  369. package/src/DateTimeInput/DateTimeInput.doc.mjs +368 -67
  370. package/src/DateTimeInput/DateTimeInput.test.tsx +279 -11
  371. package/src/DateTimeInput/DateTimeInput.tsx +125 -17
  372. package/src/Dialog/Dialog.doc.mjs +2 -2
  373. package/src/Dialog/Dialog.tsx +12 -0
  374. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -8
  375. package/src/DropdownMenu/DropdownMenu.test.tsx +56 -42
  376. package/src/DropdownMenu/DropdownMenu.tsx +52 -18
  377. package/src/Field/Field.doc.mjs +59 -18
  378. package/src/Field/Field.test.tsx +32 -0
  379. package/src/Field/Field.tsx +23 -5
  380. package/src/Field/FieldLabel.tsx +55 -17
  381. package/src/FileInput/FileInput.doc.mjs +17 -0
  382. package/src/FileInput/FileInput.test.tsx +283 -49
  383. package/src/FileInput/FileInput.tsx +76 -4
  384. package/src/Grid/Grid.doc.mjs +17 -4
  385. package/src/Grid/Grid.test.tsx +43 -30
  386. package/src/Grid/Grid.tsx +38 -3
  387. package/src/Icon/Icon.doc.mjs +3 -3
  388. package/src/InputGroup/InputGroup.doc.mjs +111 -23
  389. package/src/InputGroup/InputGroup.test.tsx +257 -60
  390. package/src/InputGroup/InputGroup.tsx +23 -5
  391. package/src/InputGroup/InputGroupContext.ts +9 -4
  392. package/src/InputGroup/groupStyles.ts +7 -1
  393. package/src/InputGroup/index.ts +1 -0
  394. package/src/Kbd/Kbd.test.tsx +22 -4
  395. package/src/Kbd/Kbd.tsx +35 -3
  396. package/src/Layer/layerAnimations.stylex.ts +20 -4
  397. package/src/Layer/useLayer.doc.mjs +5 -0
  398. package/src/Layer/useLayer.test.tsx +111 -0
  399. package/src/Layer/useLayer.tsx +90 -9
  400. package/src/Layout/Layout.tsx +8 -16
  401. package/src/Layout/LayoutFooter.doc.mjs +4 -4
  402. package/src/Layout/LayoutFooter.tsx +3 -3
  403. package/src/Layout/LayoutHeader.doc.mjs +4 -4
  404. package/src/Layout/LayoutHeader.tsx +3 -3
  405. package/src/Layout/LayoutPanel.tsx +3 -3
  406. package/src/Layout/padding.stylex.ts +52 -0
  407. package/src/Lightbox/Lightbox.doc.mjs +9 -0
  408. package/src/Lightbox/Lightbox.test.tsx +53 -5
  409. package/src/Lightbox/Lightbox.tsx +9 -4
  410. package/src/Link/Link.doc.mjs +14 -0
  411. package/src/Link/Link.test.tsx +50 -0
  412. package/src/Link/Link.tsx +39 -4
  413. package/src/Markdown/Markdown.test.tsx +11 -0
  414. package/src/Markdown/Markdown.tsx +7 -0
  415. package/src/MetadataList/MetadataListItem.doc.mjs +4 -0
  416. package/src/MoreMenu/MoreMenu.doc.mjs +2 -17
  417. package/src/MoreMenu/MoreMenu.tsx +0 -9
  418. package/src/MultiSelector/MultiSelector.doc.mjs +30 -0
  419. package/src/MultiSelector/MultiSelector.test.tsx +375 -8
  420. package/src/MultiSelector/MultiSelector.tsx +194 -48
  421. package/src/MultiSelector/hooks.ts +27 -0
  422. package/src/NavMenu/NavHeadingMenu.test.tsx +77 -1
  423. package/src/NavMenu/NavHeadingMenu.tsx +50 -3
  424. package/src/NumberInput/NumberInput.doc.mjs +17 -0
  425. package/src/NumberInput/NumberInput.test.tsx +242 -40
  426. package/src/NumberInput/NumberInput.tsx +89 -11
  427. package/src/Pagination/Pagination.doc.mjs +3 -3
  428. package/src/Pagination/Pagination.test.tsx +117 -5
  429. package/src/Pagination/Pagination.tsx +21 -1
  430. package/src/Popover/Popover.doc.mjs +26 -0
  431. package/src/Popover/Popover.test.tsx +121 -0
  432. package/src/Popover/Popover.tsx +23 -2
  433. package/src/Popover/usePopover.doc.mjs +9 -3
  434. package/src/Popover/usePopover.tsx +70 -12
  435. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  436. package/src/PowerSearch/PowerSearch.test.tsx +97 -1
  437. package/src/PowerSearch/PowerSearch.tsx +16 -3
  438. package/src/ProgressBar/ProgressBar.test.tsx +34 -26
  439. package/src/ProgressBar/ProgressBar.tsx +3 -4
  440. package/src/RadioList/RadioList.doc.mjs +9 -0
  441. package/src/RadioList/RadioList.test.tsx +252 -16
  442. package/src/RadioList/RadioList.tsx +166 -10
  443. package/src/RadioList/RadioListItem.tsx +14 -2
  444. package/src/SegmentedControl/SegmentedControl.doc.mjs +9 -0
  445. package/src/SegmentedControl/SegmentedControl.test.tsx +214 -42
  446. package/src/SegmentedControl/SegmentedControl.tsx +102 -54
  447. package/src/SegmentedControl/SegmentedControlContext.ts +7 -0
  448. package/src/SegmentedControl/SegmentedControlItem.tsx +14 -1
  449. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  450. package/src/Selector/Selector.doc.mjs +26 -0
  451. package/src/Selector/Selector.test.tsx +387 -15
  452. package/src/Selector/Selector.tsx +175 -67
  453. package/src/Selector/hooks.ts +23 -0
  454. package/src/SideNav/SideNav.test.tsx +48 -0
  455. package/src/SideNav/SideNavHeading.tsx +8 -2
  456. package/src/SideNav/SideNavItem.tsx +2 -4
  457. package/src/Skeleton/Skeleton.test.tsx +25 -0
  458. package/src/Skeleton/Skeleton.tsx +11 -1
  459. package/src/Slider/Slider.doc.mjs +15 -0
  460. package/src/Slider/Slider.test.tsx +155 -2
  461. package/src/Slider/Slider.tsx +53 -5
  462. package/src/Spinner/Spinner.tsx +7 -1
  463. package/src/Stack/Stack.doc.mjs +77 -0
  464. package/src/Stack/Stack.test.tsx +55 -5
  465. package/src/Stack/Stack.tsx +73 -24
  466. package/src/Stack/StackItem.test.tsx +23 -0
  467. package/src/Stack/StackItem.tsx +20 -23
  468. package/src/Switch/Switch.doc.mjs +15 -0
  469. package/src/Switch/Switch.test.tsx +162 -27
  470. package/src/Switch/Switch.tsx +61 -21
  471. package/src/TabList/Tab.tsx +6 -0
  472. package/src/TabList/TabList.doc.mjs +6 -0
  473. package/src/TabList/TabList.test.tsx +251 -0
  474. package/src/TabList/TabList.tsx +103 -12
  475. package/src/TabList/TabListContext.ts +7 -3
  476. package/src/TabList/TabMenu.tsx +6 -3
  477. package/src/Table/BaseTable.tsx +21 -17
  478. package/src/Table/Table.doc.mjs +2 -0
  479. package/src/Table/Table.test.tsx +10 -0
  480. package/src/Table/Table.tsx +8 -0
  481. package/src/Table/TableCell.tsx +25 -23
  482. package/src/Table/TableHeaderCell.tsx +28 -29
  483. package/src/Table/index.ts +3 -2
  484. package/src/Table/plugins/pagination/paginateData.ts +10 -3
  485. package/src/Table/plugins/pagination/useTablePagination.test.tsx +16 -0
  486. package/src/Table/plugins/pagination/useTablePagination.tsx +8 -1
  487. package/src/Table/plugins/sortable/useTableSortable.test.tsx +91 -2
  488. package/src/Table/plugins/sortable/useTableSortable.tsx +53 -1
  489. package/src/Table/tableContextMenu.test.tsx +157 -0
  490. package/src/Table/tableContextMenu.tsx +142 -0
  491. package/src/Table/types.ts +74 -0
  492. package/src/Table/useTableColumnResize.doc.mjs +3 -3
  493. package/src/Table/useTableStickyColumns.doc.mjs +2 -2
  494. package/src/Text/Text.doc.mjs +18 -18
  495. package/src/TextArea/TextArea.doc.mjs +17 -0
  496. package/src/TextArea/TextArea.test.tsx +167 -35
  497. package/src/TextArea/TextArea.tsx +62 -15
  498. package/src/TextInput/TextInput.doc.mjs +17 -0
  499. package/src/TextInput/TextInput.test.tsx +168 -34
  500. package/src/TextInput/TextInput.tsx +77 -9
  501. package/src/Thumbnail/Thumbnail.doc.mjs +4 -4
  502. package/src/TimeInput/TimeInput.doc.mjs +340 -60
  503. package/src/TimeInput/TimeInput.test.tsx +255 -7
  504. package/src/TimeInput/TimeInput.tsx +176 -70
  505. package/src/Timestamp/Timestamp.doc.mjs +19 -19
  506. package/src/Toast/Toast.tsx +14 -0
  507. package/src/Toast/ToastViewport.test.tsx +214 -0
  508. package/src/Toast/ToastViewport.tsx +167 -21
  509. package/src/Tokenizer/Tokenizer.doc.mjs +29 -14
  510. package/src/Tokenizer/Tokenizer.test.tsx +105 -1
  511. package/src/Tokenizer/Tokenizer.tsx +37 -1
  512. package/src/Toolbar/Toolbar.test.tsx +109 -6
  513. package/src/Toolbar/Toolbar.tsx +59 -5
  514. package/src/Tooltip/Tooltip.test.tsx +68 -0
  515. package/src/Tooltip/useTooltip.tsx +55 -8
  516. package/src/TopNav/TopNav.test.tsx +50 -0
  517. package/src/TopNav/TopNavHeading.tsx +17 -1
  518. package/src/TreeList/TreeList.test.tsx +295 -6
  519. package/src/TreeList/TreeList.tsx +73 -1
  520. package/src/TreeList/TreeListItem.tsx +51 -5
  521. package/src/TreeList/treeListItem.markers.stylex.ts +20 -0
  522. package/src/Typeahead/BaseTypeahead.tsx +93 -9
  523. package/src/Typeahead/Typeahead.doc.mjs +141 -30
  524. package/src/Typeahead/Typeahead.test.tsx +331 -1
  525. package/src/Typeahead/Typeahead.tsx +105 -33
  526. package/src/VisuallyHidden/VisuallyHidden.doc.mjs +80 -0
  527. package/src/VisuallyHidden/VisuallyHidden.test.tsx +76 -0
  528. package/src/VisuallyHidden/VisuallyHidden.tsx +113 -0
  529. package/src/VisuallyHidden/index.ts +15 -0
  530. package/src/docs-script.test.mjs +50 -0
  531. package/src/hooks/focusableSelector.ts +25 -0
  532. package/src/hooks/index.ts +28 -2
  533. package/src/hooks/useAnnounce.test.tsx +101 -0
  534. package/src/hooks/useAnnounce.ts +168 -0
  535. package/src/hooks/useClickableContainer.ts +16 -4
  536. package/src/hooks/useEntryAnimation.ts +16 -4
  537. package/src/hooks/useFocusTrap.test.tsx +132 -0
  538. package/src/hooks/useFocusTrap.ts +98 -4
  539. package/src/hooks/useGridFocus.doc.mjs +40 -2
  540. package/src/hooks/useGridFocus.test.tsx +132 -0
  541. package/src/hooks/useGridFocus.ts +343 -67
  542. package/src/hooks/useKeyboardHint.doc.mjs +101 -0
  543. package/src/hooks/useKeyboardHint.test.tsx +70 -0
  544. package/src/hooks/useKeyboardHint.tsx +332 -0
  545. package/src/hooks/useListFocus.doc.mjs +50 -10
  546. package/src/hooks/useListFocus.test.tsx +375 -0
  547. package/src/hooks/useListFocus.ts +395 -57
  548. package/src/hooks/useLongPress.test.tsx +134 -0
  549. package/src/hooks/useLongPress.ts +119 -0
  550. package/src/hooks/useTreeFocus.doc.mjs +140 -0
  551. package/src/hooks/useTreeFocus.test.tsx +214 -0
  552. package/src/hooks/useTreeFocus.ts +559 -0
  553. package/src/hooks/useTypeahead.test.tsx +109 -0
  554. package/src/hooks/useTypeahead.ts +183 -0
  555. package/src/index.ts +1 -0
  556. package/src/theme/derivedVarRegistry.test.ts +10 -5
  557. package/src/utils/dateTypes.test.ts +40 -0
  558. package/src/utils/dateTypes.ts +40 -0
  559. package/src/utils/index.ts +9 -0
  560. package/src/utils/inputAria.test.ts +39 -0
  561. package/src/utils/inputAria.ts +58 -0
  562. package/src/utils/timeParser.test.ts +10 -0
  563. package/src/utils/timeParser.ts +5 -2
  564. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts +0 -57
  565. package/dist/Calendar/hooks/useCalendarRovingTabindex.d.ts.map +0 -1
  566. package/dist/Calendar/hooks/useCalendarRovingTabindex.js +0 -96
  567. package/src/Calendar/hooks/useCalendarRovingTabindex.ts +0 -118
@@ -29,6 +29,7 @@ import {mergeProps} from '../utils';
29
29
  import {useLinkComponent} from '../Link/useLinkComponent';
30
30
  import {TreeListBranches} from './TreeListBranches';
31
31
  import type {TreeListDensity} from './TreeListTypes';
32
+ import {treeItemScope} from './treeListItem.markers.stylex';
32
33
  import {themeProps} from '../utils/themeProps';
33
34
 
34
35
  // =============================================================================
@@ -42,6 +43,9 @@ const styles = stylex.create({
42
43
  padding: 0,
43
44
  position: 'relative',
44
45
  width: '100%',
46
+ // The treeitem row is the roving-tabindex focus owner; suppress the
47
+ // native focus ring in favor of the row's :focus-visible outline below.
48
+ outline: 'none',
45
49
  },
46
50
  childGroup: {
47
51
  margin: 0,
@@ -82,10 +86,16 @@ const styles = stylex.create({
82
86
  focusVisibleOutline: {
83
87
  outline: {
84
88
  default: 'none',
89
+ // Focus lives on the treeitem row (the <li>) via roving tabindex.
90
+ // Scoped to the row's OWN treeitem so focusing a parent does not leak
91
+ // the ring onto descendant rows. Also support inner focusable actions.
92
+ [stylex.when.ancestor(':focus-visible', treeItemScope)]:
93
+ `2px solid ${colorVars['--color-accent']}`,
85
94
  ':has(:focus-visible)': `2px solid ${colorVars['--color-accent']}`,
86
95
  },
87
96
  outlineOffset: {
88
97
  default: '0',
98
+ [stylex.when.ancestor(':focus-visible', treeItemScope)]: '2px',
89
99
  ':has(:focus-visible)': '2px',
90
100
  },
91
101
  },
@@ -250,6 +260,16 @@ export interface TreeListItemInternalProps {
250
260
  density: TreeListDensity;
251
261
  /** Pre-rendered children subtree (rendered by the parent recursion) */
252
262
  renderedChildren?: ReactNode;
263
+ /** 1-based position of this item among its siblings (aria-posinset). */
264
+ posInSet: number;
265
+ /** Number of siblings at this level (aria-setsize). */
266
+ setSize: number;
267
+ /**
268
+ * Whether this treeitem is the initial roving-tabindex seed. Exactly one
269
+ * treeitem is seeded tabbable at mount; useTreeFocus (hasRovingTabIndex)
270
+ * then owns the tab stop dynamically.
271
+ */
272
+ isTabbable: boolean;
253
273
  }
254
274
 
255
275
  // =============================================================================
@@ -275,6 +295,9 @@ export function TreeListItem({
275
295
  onToggle,
276
296
  density,
277
297
  renderedChildren,
298
+ posInSet,
299
+ setSize,
300
+ isTabbable,
278
301
  }: TreeListItemInternalProps) {
279
302
  const labelId = useId();
280
303
  const descriptionId = useId();
@@ -342,18 +365,26 @@ export function TreeListItem({
342
365
  );
343
366
 
344
367
  const chevron = hasChildren ? (
345
- handleClick != null && onClick != null ? (
346
- // Separate toggle button when item has its own onClick
368
+ handleToggle != null ? (
369
+ // Real toggle button whenever expand/collapse is supported, so the row
370
+ // can be expanded from the keyboard even when the item has no onClick/href
371
+ // (row-level onClick is the only click path in that case, but there is no
372
+ // focusable element to receive Enter/Space). The row's handleClick ignores
373
+ // clicks originating inside a <button>, so this never double-toggles.
347
374
  <button
348
375
  type="button"
349
376
  aria-expanded={isExpanded}
350
377
  aria-label="Toggle children"
378
+ disabled={isDisabled}
379
+ // Roving tabindex lives on the treeitem row; the chevron toggle is not
380
+ // a separate tab stop. Row-level Enter/Space forwards to this button.
381
+ tabIndex={-1}
351
382
  onClick={handleToggle}
352
383
  {...stylex.props(styles.chevronButton)}>
353
384
  {chevronIcon}
354
385
  </button>
355
386
  ) : (
356
- // Non-interactive chevron when clicking the row toggles
387
+ // Non-interactive chevron only when toggling is not wired up at all
357
388
  <span {...stylex.props(styles.chevronContainer)}>{chevronIcon}</span>
358
389
  )
359
390
  ) : null;
@@ -371,7 +402,9 @@ export function TreeListItem({
371
402
  aria-disabled={isDisabled || undefined}
372
403
  aria-labelledby={labelId}
373
404
  aria-describedby={description != null ? descriptionId : undefined}
374
- tabIndex={isDisabled ? -1 : undefined}
405
+ // Roving tabindex lives on the treeitem row; inner action is not a
406
+ // separate tab stop. Activation is forwarded from the row.
407
+ tabIndex={-1}
375
408
  {...stylex.props(styles.invisibleAnchor)}>
376
409
  {labelAndDescription}
377
410
  </LinkComponent>
@@ -382,6 +415,9 @@ export function TreeListItem({
382
415
  disabled={isDisabled}
383
416
  aria-labelledby={labelId}
384
417
  aria-describedby={description != null ? descriptionId : undefined}
418
+ // Roving tabindex lives on the treeitem row; inner action is not a
419
+ // separate tab stop. Activation is forwarded from the row.
420
+ tabIndex={-1}
385
421
  {...stylex.props(styles.invisibleButton)}>
386
422
  {labelAndDescription}
387
423
  </button>
@@ -400,7 +436,17 @@ export function TreeListItem({
400
436
  aria-expanded={hasChildren ? isExpanded : undefined}
401
437
  aria-selected={isSelected || undefined}
402
438
  aria-disabled={isDisabled || undefined}
403
- {...stylex.props(styles.wrapper)}>
439
+ aria-level={nestedLevel + 1}
440
+ aria-posinset={posInSet}
441
+ aria-setsize={setSize}
442
+ // Roving tabindex: exactly one visible treeitem is tabbable at a time.
443
+ // Disabled items are skipped by the tree keyboard handler but remain
444
+ // in the accessibility tree.
445
+ tabIndex={isDisabled ? -1 : isTabbable ? 0 : -1}
446
+ data-tree-id={id}
447
+ data-tree-level={nestedLevel + 1}
448
+ data-tree-disabled={isDisabled || undefined}
449
+ {...stylex.props(styles.wrapper, treeItemScope)}>
404
450
  <div {...stylex.props(styles.treeBranches)}>
405
451
  <TreeListBranches
406
452
  ancestorsIsLast={ancestorsIsLast}
@@ -0,0 +1,20 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file treeListItem.markers.stylex.ts
5
+ * @input Uses StyleX defineMarker
6
+ * @output Exports treeItemScope marker
7
+ * @position Scoped marker; consumed by TreeListItem.tsx
8
+ *
9
+ * SYNC: When modified, update /packages/core/src/TreeList/TreeListItem.tsx
10
+ */
11
+
12
+ import * as stylex from '@stylexjs/stylex';
13
+
14
+ /**
15
+ * Scoped marker placed on each treeitem row (`<li role="treeitem">`).
16
+ * Binds the row's `:focus-visible` outline to its OWN treeitem, so focusing
17
+ * a parent treeitem does not leak the focus ring onto descendant rows.
18
+ */
19
+ export const treeItemScope: ReturnType<typeof stylex.defineMarker> =
20
+ stylex.defineMarker();
@@ -29,6 +29,7 @@ import React, {
29
29
  import * as stylex from '@stylexjs/stylex';
30
30
  import type {StyleXStyles} from '@stylexjs/stylex';
31
31
  import {usePopover} from '../Popover/usePopover';
32
+ import {useAnnounce} from '../hooks/useAnnounce';
32
33
  import {TypeaheadItem} from './TypeaheadItem';
33
34
  import {Icon} from '../Icon';
34
35
  import {
@@ -48,9 +49,10 @@ import {themeProps} from '../utils/themeProps';
48
49
  // Types
49
50
  // =============================================================================
50
51
 
51
- export interface BaseTypeaheadProps<
52
- T extends SearchableItem,
53
- > extends Omit<BaseProps<HTMLElement>, 'onChange'> {
52
+ export interface BaseTypeaheadProps<T extends SearchableItem> extends Omit<
53
+ BaseProps<HTMLElement>,
54
+ 'onChange'
55
+ > {
54
56
  ref?: React.Ref<HTMLInputElement>;
55
57
  /**
56
58
  * Search source providing items.
@@ -101,6 +103,16 @@ export interface BaseTypeaheadProps<
101
103
  */
102
104
  isDisabled?: boolean;
103
105
 
106
+ /**
107
+ * When disabled with a reason, keeps the input focusable via `aria-disabled`
108
+ * (instead of the native `disabled` attribute) and `readOnly` so an
109
+ * associated disabled-reason tooltip stays discoverable by keyboard and
110
+ * assistive technology. Value mutation is still blocked by the `isDisabled`
111
+ * guards. Consumers (Typeahead) own the tooltip and wrapper.
112
+ * @default false
113
+ */
114
+ isFocusableDisabled?: boolean;
115
+
104
116
  /**
105
117
  * Auto-focus on mount.
106
118
  * @default false
@@ -134,6 +146,11 @@ export interface BaseTypeaheadProps<
134
146
  */
135
147
  ariaDescribedBy?: string;
136
148
 
149
+ /**
150
+ * Additional aria-labelledby IDs.
151
+ */
152
+ ariaLabelledBy?: string;
153
+
137
154
  /**
138
155
  * Additional StyleX styles for the input element.
139
156
  */
@@ -280,9 +297,7 @@ const itemSizeStyles = stylex.create({
280
297
  * />
281
298
  * ```
282
299
  */
283
- export const BaseTypeahead = function BaseTypeahead<
284
- T extends SearchableItem,
285
- >({
300
+ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
286
301
  searchSource,
287
302
  value,
288
303
  onChange,
@@ -292,11 +307,13 @@ export const BaseTypeahead = function BaseTypeahead<
292
307
  maxMenuItems = 10,
293
308
  emptySearchResultsText = 'No results found',
294
309
  isDisabled = false,
310
+ isFocusableDisabled = false,
295
311
  hasAutoFocus = false,
296
312
  onChangeQuery,
297
313
  onOpenChange,
298
314
  inputId: externalInputId,
299
315
  ariaDescribedBy,
316
+ ariaLabelledBy,
300
317
  inputXStyle,
301
318
  anchorRef,
302
319
  onKeyDown: externalOnKeyDown,
@@ -311,6 +328,11 @@ export const BaseTypeahead = function BaseTypeahead<
311
328
  const inputRef = useRef<HTMLInputElement>(null);
312
329
  const fallbackAnchorRef = useRef<HTMLInputElement>(null);
313
330
 
331
+ // Announce result counts / "no results" to screen readers via a persistent
332
+ // live region (comboboxes-6). The combobox's own popup carries no working
333
+ // live region, so highlight/result changes were previously silent.
334
+ const announce = useAnnounce();
335
+
314
336
  const [query, setQuery] = useState('');
315
337
  const [results, setResults] = useState<T[]>([]);
316
338
  const [highlightedIndex, setHighlightedIndex] = useState(-1);
@@ -353,6 +375,9 @@ export const BaseTypeahead = function BaseTypeahead<
353
375
  hasLightDismiss: true,
354
376
  hasCloseButton: false,
355
377
  hasAutoFocus: false,
378
+ // The popup's own role="listbox" is the exposed semantics; the input keeps
379
+ // DOM focus, so wrapping it in a modal dialog would misrepresent it.
380
+ role: 'none',
356
381
  });
357
382
 
358
383
  // Show the layer, deferring past the active click if a pointer is down.
@@ -394,11 +419,21 @@ export const BaseTypeahead = function BaseTypeahead<
394
419
  return;
395
420
  }
396
421
  resultsGenRef.current = gen;
397
- setResults(searchResults.slice(0, maxMenuItems));
422
+ const shown = searchResults.slice(0, maxMenuItems);
423
+ setResults(shown);
398
424
  setHighlightedIndex(searchResults.length > 0 ? 0 : -1);
399
425
  if (searchResults.length > 0 || searchQuery.length > 0) {
400
426
  showLayer();
401
427
  }
428
+ // Announce the outcome only for an active query (not the initial
429
+ // focus-open), so screen-reader users hear result counts / no-results.
430
+ if (searchQuery.length > 0) {
431
+ announce(
432
+ shown.length === 0
433
+ ? emptySearchResultsText
434
+ : `${shown.length} ${shown.length === 1 ? 'result' : 'results'}`,
435
+ );
436
+ }
402
437
  } catch {
403
438
  if (searchGenRef.current !== gen) {
404
439
  return;
@@ -411,7 +446,7 @@ export const BaseTypeahead = function BaseTypeahead<
411
446
  }
412
447
  }
413
448
  },
414
- [searchSource, maxMenuItems, showLayer],
449
+ [searchSource, maxMenuItems, showLayer, announce, emptySearchResultsText],
415
450
  );
416
451
 
417
452
  // Perform bootstrap
@@ -456,6 +491,8 @@ export const BaseTypeahead = function BaseTypeahead<
456
491
  searchSource.cancel?.();
457
492
  setResults([]);
458
493
  setHasSearched(false);
494
+ // Clear any lingering result-count / no-results announcement.
495
+ announce('');
459
496
  popover.hide();
460
497
  return;
461
498
  }
@@ -482,6 +519,7 @@ export const BaseTypeahead = function BaseTypeahead<
482
519
  popover,
483
520
  debounceMs,
484
521
  searchSource,
522
+ announce,
485
523
  ],
486
524
  );
487
525
 
@@ -539,6 +577,32 @@ export const BaseTypeahead = function BaseTypeahead<
539
577
  showLayer,
540
578
  ]);
541
579
 
580
+ // Handle blur — close the dropdown when focus leaves the input for an
581
+ // element that is neither inside the field wrapper (anchor) nor inside the
582
+ // dropdown popover. The native popover="auto" light-dismiss only fires on
583
+ // outside pointer clicks and Escape; it does not close when focus moves away
584
+ // via the keyboard (Tab) or programmatically, which would otherwise leave an
585
+ // orphaned open menu. Clicking a result moves focus onto the option (it is
586
+ // tabIndex={-1}, so it lives inside the popover) and selection re-focuses the
587
+ // input, so this only closes on a genuine focus-out of the whole field.
588
+ const handleBlur = useCallback(
589
+ (e: React.FocusEvent<HTMLInputElement>) => {
590
+ if (!popover.isOpen) {
591
+ return;
592
+ }
593
+ const next = e.relatedTarget as Node | null;
594
+ if (next) {
595
+ const anchorEl = anchorRef?.current ?? fallbackAnchorRef.current;
596
+ const popoverEl = document.getElementById(popover.id);
597
+ if (anchorEl?.contains(next) || popoverEl?.contains(next)) {
598
+ return;
599
+ }
600
+ }
601
+ popover.hide();
602
+ },
603
+ [popover, anchorRef],
604
+ );
605
+
542
606
  // Keyboard navigation
543
607
  const handleKeyDown = useCallback(
544
608
  (e: React.KeyboardEvent<HTMLInputElement>) => {
@@ -615,6 +679,19 @@ export const BaseTypeahead = function BaseTypeahead<
615
679
  [listboxId],
616
680
  );
617
681
 
682
+ // Keep the highlighted option visible during keyboard navigation. The
683
+ // listbox is a fixed-height scroll container, so without this the virtual
684
+ // cursor walks off-screen once navigation passes the visible window. Mirrors
685
+ // CommandPaletteItem's scrollIntoView({block: 'nearest'}) behavior.
686
+ useEffect(() => {
687
+ if (!popover.isOpen || highlightedIndex < 0) {
688
+ return;
689
+ }
690
+ document
691
+ .getElementById(getItemId(highlightedIndex))
692
+ ?.scrollIntoView?.({block: 'nearest'});
693
+ }, [popover.isOpen, highlightedIndex, getItemId]);
694
+
618
695
  const selectedKey =
619
696
  value == null ? null : getKey(value.id, () => results.indexOf(value));
620
697
 
@@ -644,6 +721,8 @@ export const BaseTypeahead = function BaseTypeahead<
644
721
  }
645
722
  aria-autocomplete="list"
646
723
  aria-describedby={ariaDescribedBy}
724
+ aria-labelledby={ariaLabelledBy}
725
+ aria-disabled={isFocusableDisabled ? 'true' : undefined}
647
726
  value={query}
648
727
  onChange={handleInputChange}
649
728
  onPointerDown={() => {
@@ -657,9 +736,14 @@ export const BaseTypeahead = function BaseTypeahead<
657
736
  );
658
737
  }}
659
738
  onFocus={handleFocus}
739
+ onBlur={handleBlur}
660
740
  onKeyDown={handleKeyDown}
661
741
  placeholder={placeholder}
662
- disabled={isDisabled}
742
+ // When a disabled-reason tooltip is shown the input keeps focusability
743
+ // via aria-disabled + readOnly instead of the native disabled
744
+ // attribute; value mutation stays blocked by the isDisabled guards.
745
+ disabled={isDisabled && !isFocusableDisabled}
746
+ readOnly={isFocusableDisabled || undefined}
663
747
  autoFocus={hasAutoFocus}
664
748
  data-autofocus={hasAutoFocus || undefined}
665
749
  autoComplete="off"
@@ -7,8 +7,21 @@ export const docs = {
7
7
  displayName: 'Typeahead',
8
8
  group: 'Typeahead',
9
9
  category: 'Data Input',
10
- keywords: ["typeahead","autocomplete","combobox","searchbox","autosuggest","select","dropdown","lookup","searchable","suggestion","picker"],
11
- description: 'Styled typeahead with label, description, validation, and all field features. Wraps BaseTypeahead with Field for the primary use case.',
10
+ keywords: [
11
+ 'typeahead',
12
+ 'autocomplete',
13
+ 'combobox',
14
+ 'searchbox',
15
+ 'autosuggest',
16
+ 'select',
17
+ 'dropdown',
18
+ 'lookup',
19
+ 'searchable',
20
+ 'suggestion',
21
+ 'picker',
22
+ ],
23
+ description:
24
+ 'Styled typeahead with label, description, validation, and all field features. Wraps BaseTypeahead with Field for the primary use case.',
12
25
  props: [
13
26
  {
14
27
  name: 'label',
@@ -19,7 +32,8 @@ export const docs = {
19
32
  {
20
33
  name: 'searchSource',
21
34
  type: 'SearchSource<T>',
22
- description: 'Data source providing search and bootstrap methods for populating the dropdown.',
35
+ description:
36
+ 'Data source providing search and bootstrap methods for populating the dropdown.',
23
37
  required: true,
24
38
  },
25
39
  {
@@ -57,6 +71,12 @@ export const docs = {
57
71
  description: 'Disables the input.',
58
72
  default: 'false',
59
73
  },
74
+ {
75
+ name: 'disabledMessage',
76
+ type: 'string',
77
+ description:
78
+ 'Explains why the input is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the field focusable via aria-disabled (activation stays blocked). Use this instead of wrapping a disabled Typeahead in Tooltip — disabled controls swallow the hover events an external Tooltip needs.',
79
+ },
60
80
  {
61
81
  name: 'maxMenuItems',
62
82
  type: 'number',
@@ -66,12 +86,14 @@ export const docs = {
66
86
  {
67
87
  name: 'status',
68
88
  type: 'InputStatus',
69
- description: 'Validation status object with type and message for error/warning/success states.',
89
+ description:
90
+ 'Validation status object with type and message for error/warning/success states.',
70
91
  },
71
92
  {
72
93
  name: 'renderItem',
73
94
  type: '(item: T) => ReactNode',
74
- description: 'Custom render function for dropdown items. Default renders TypeaheadItem.',
95
+ description:
96
+ 'Custom render function for dropdown items. Default renders TypeaheadItem.',
75
97
  },
76
98
  {
77
99
  name: 'isLabelHidden',
@@ -122,7 +144,8 @@ export const docs = {
122
144
  {
123
145
  name: 'debounceMs',
124
146
  type: 'number',
125
- description: 'Debounce delay in ms before triggering search. Set to 0 for synchronous sources.',
147
+ description:
148
+ 'Debounce delay in ms before triggering search. Set to 0 for synchronous sources.',
126
149
  default: '150',
127
150
  },
128
151
  {
@@ -138,13 +161,11 @@ export const docs = {
138
161
  {
139
162
  name: 'xstyle',
140
163
  type: 'StyleXStyles',
141
- description: 'StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}.',
164
+ description:
165
+ 'StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}.',
142
166
  },
143
167
  ],
144
- components: [
145
- {name: 'BaseTypeahead'},
146
- {name: 'TypeaheadItem'},
147
- ],
168
+ components: [{name: 'BaseTypeahead'}, {name: 'TypeaheadItem'}],
148
169
  theming: {
149
170
  targets: [
150
171
  {className: 'astryx-typeahead', visualProps: ['status']},
@@ -156,12 +177,45 @@ export const docs = {
156
177
  description:
157
178
  'A searchable input for selecting a single item from a large or dynamic dataset. Results appear as the user types, with support for async data sources, debounced search, and custom item rendering. Use it when the option list is too large for a Selector dropdown.',
158
179
  bestPractices: [
159
- {guidance: true, description: 'Provide descriptive placeholder text that hints at what users can search for.'},
160
- {guidance: true, description: 'Show suggestions on focus when users benefit from seeing popular or recent options before typing.'},
161
- {guidance: true, description: 'Add a search delay for remote data sources to avoid excessive network requests.'},
162
- {guidance: false, description: 'Use for short, static option lists; use Selector for better discoverability.'},
163
- {guidance: false, description: 'Use for multi-selection; use Tokenizer instead.'},
164
- {guidance: false, description: 'Place multiple Typeaheads adjacent to each other without clear labels differentiating them.'},
180
+ {
181
+ guidance: true,
182
+ description:
183
+ 'Provide descriptive placeholder text that hints at what users can search for.',
184
+ },
185
+ {
186
+ guidance: true,
187
+ description:
188
+ 'Show suggestions on focus when users benefit from seeing popular or recent options before typing.',
189
+ },
190
+ {
191
+ guidance: true,
192
+ description:
193
+ 'Add a search delay for remote data sources to avoid excessive network requests.',
194
+ },
195
+ {
196
+ guidance: true,
197
+ description:
198
+ 'Use inside InputGroup when the typeahead needs a single-line prefix or suffix addon.',
199
+ },
200
+ {
201
+ guidance: false,
202
+ description:
203
+ 'Use for short, static option lists; use Selector for better discoverability.',
204
+ },
205
+ {
206
+ guidance: false,
207
+ description: 'Use for multi-selection; use Tokenizer instead.',
208
+ },
209
+ {
210
+ guidance: false,
211
+ description:
212
+ 'Place multiple Typeaheads adjacent to each other without clear labels differentiating them.',
213
+ },
214
+ {
215
+ guidance: false,
216
+ description:
217
+ 'Wrap a disabled Typeahead in Tooltip to explain why it is disabled; disabled triggers swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
218
+ },
165
219
  ],
166
220
  },
167
221
  };
@@ -172,29 +226,86 @@ export const docsZh = {
172
226
  description:
173
227
  'A searchable input for selecting a single item from a large or dynamic dataset. Results appear as the user types, with support for async data sources, debounced search, and custom item rendering. Use it when the option list is too large for a Selector dropdown.',
174
228
  bestPractices: [
175
- {guidance: true, description: 'Provide descriptive placeholder text that hints at what users can search for.'},
176
- {guidance: true, description: 'Show suggestions on focus when users benefit from seeing popular or recent options before typing.'},
177
- {guidance: true, description: 'Add a search delay for remote data sources to avoid excessive network requests.'},
178
- {guidance: false, description: 'Use for short, static option lists; use Selector for better discoverability.'},
179
- {guidance: false, description: 'Use for multi-selection; use Tokenizer instead.'},
180
- {guidance: false, description: 'Place multiple Typeaheads adjacent to each other without clear labels differentiating them.'},
229
+ {
230
+ guidance: true,
231
+ description:
232
+ 'Provide descriptive placeholder text that hints at what users can search for.',
233
+ },
234
+ {
235
+ guidance: true,
236
+ description:
237
+ 'Show suggestions on focus when users benefit from seeing popular or recent options before typing.',
238
+ },
239
+ {
240
+ guidance: true,
241
+ description:
242
+ 'Add a search delay for remote data sources to avoid excessive network requests.',
243
+ },
244
+ {
245
+ guidance: false,
246
+ description:
247
+ 'Use for short, static option lists; use Selector for better discoverability.',
248
+ },
249
+ {
250
+ guidance: false,
251
+ description: 'Use for multi-selection; use Tokenizer instead.',
252
+ },
253
+ {
254
+ guidance: false,
255
+ description:
256
+ 'Place multiple Typeaheads adjacent to each other without clear labels differentiating them.',
257
+ },
258
+ {
259
+ guidance: false,
260
+ description:
261
+ 'Wrap a disabled Typeahead in Tooltip to explain why it is disabled; disabled triggers swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
262
+ },
181
263
  ],
182
264
  },
183
265
  };
184
266
 
185
267
  /** @type {import('../docs-types').TranslationDoc} */
186
268
  export const docsDense = {
187
- description: 'Searchable dropdown for single-item selection w/ keyboard navigation. Supports async+sync search via searchSource interface.',
269
+ description:
270
+ 'Searchable dropdown for single-item selection w/ keyboard navigation. Supports async+sync search via searchSource interface.',
188
271
  usage: {
189
272
  description:
190
273
  'A searchable input for selecting a single item from a large or dynamic dataset. Results appear as the user types, with support for async data sources, debounced search, and custom item rendering. Use it when the option list is too large for a Selector dropdown.',
191
274
  bestPractices: [
192
- {guidance: true, description: 'Provide descriptive placeholder text that hints at what users can search for.'},
193
- {guidance: true, description: 'Show suggestions on focus when users benefit from seeing popular or recent options before typing.'},
194
- {guidance: true, description: 'Add a search delay for remote data sources to avoid excessive network requests.'},
195
- {guidance: false, description: 'Use for short, static option lists; use Selector for better discoverability.'},
196
- {guidance: false, description: 'Use for multi-selection; use Tokenizer instead.'},
197
- {guidance: false, description: 'Place multiple Typeaheads adjacent to each other without clear labels differentiating them.'},
275
+ {
276
+ guidance: true,
277
+ description:
278
+ 'Provide descriptive placeholder text that hints at what users can search for.',
279
+ },
280
+ {
281
+ guidance: true,
282
+ description:
283
+ 'Show suggestions on focus when users benefit from seeing popular or recent options before typing.',
284
+ },
285
+ {
286
+ guidance: true,
287
+ description:
288
+ 'Add a search delay for remote data sources to avoid excessive network requests.',
289
+ },
290
+ {
291
+ guidance: false,
292
+ description:
293
+ 'Use for short, static option lists; use Selector for better discoverability.',
294
+ },
295
+ {
296
+ guidance: false,
297
+ description: 'Use for multi-selection; use Tokenizer instead.',
298
+ },
299
+ {
300
+ guidance: false,
301
+ description:
302
+ 'Place multiple Typeaheads adjacent to each other without clear labels differentiating them.',
303
+ },
304
+ {
305
+ guidance: false,
306
+ description:
307
+ 'Wrap a disabled Typeahead in Tooltip to explain why it is disabled; disabled triggers swallow the hover events the wrapper needs. Use the disabledMessage prop instead.',
308
+ },
198
309
  ],
199
310
  },
200
311
  };