@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
@@ -21,7 +21,7 @@ export const docs = {
21
21
  anatomy: [
22
22
  {name: 'Scroll container', required: true, description: 'The horizontal overflow area that holds all items.'},
23
23
  {name: 'Items', required: true, description: 'The children rendered in a row. Each item is animated with a scroll-driven scale effect.'},
24
- {name: 'Fade edges', required: true, description: 'Gradient fades on the left and right edges that indicate more content is available.'},
24
+ {name: 'Fade edges', required: false, description: 'Gradient fades on the left and right edges that indicate more content is available. Enabled by default, disable with hasEdgeFade={false}.'},
25
25
  {name: 'Navigation buttons', required: false, description: 'Prev/next buttons that appear on hover. Enabled by default, disable with hasButtons={false}.'},
26
26
  ],
27
27
  },
@@ -29,7 +29,9 @@ export const docs = {
29
29
  {name: 'children', type: 'ReactNode', description: 'Carousel items rendered in a horizontal scroll container.', required: true},
30
30
  {name: 'gap', type: "0 | 0.5 | 1 | 1.5 | 2 | 3 | 4", description: 'Gap between items using the spacing token scale.', default: '1'},
31
31
  {name: 'hasButtons', type: 'boolean', description: 'Show prev/next navigation buttons on hover (desktop only).', default: 'true'},
32
+ {name: 'hasEdgeFade', type: 'boolean', description: 'Show a gradient edge-fade mask when content overflows, signalling that more items exist off-screen.', default: 'true'},
32
33
  {name: 'hasSnap', type: 'boolean', description: 'Enable scroll-snap so each child snaps to the start edge.', default: 'false'},
34
+ {name: 'padding', type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10', description: 'Inline padding inside the scroll container, with matching scroll-padding so snap points align to the content edge.'},
33
35
  {name: 'aria-label', type: 'string', description: 'Accessible label for the carousel region.', default: "\'Carousel\'"},
34
36
  {name: 'ref', type: 'React.Ref<HTMLDivElement>', description: 'Ref forwarded to the root element.'},
35
37
  {name: 'xstyle', type: 'StyleXStyles', description: 'StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value.'},
@@ -71,7 +73,9 @@ export const docsZh = {
71
73
  children: '在水平滚动容器中渲染的轮播项目。',
72
74
  gap: '使用间距令牌比例的项目间距。',
73
75
  hasButtons: '悬停时显示上一个/下一个导航按钮(仅桌面端)。',
76
+ hasEdgeFade: '内容溢出时显示渐变边缘遮罩,提示屏幕外还有更多项目。',
74
77
  hasSnap: '启用滚动吸附,使每个子元素吸附到起始边缘。',
78
+ padding: '滚动容器内的内联内边距,并设置匹配的 scroll-padding,使吸附点与内容边缘对齐。',
75
79
  'aria-label': '轮播区域的无障碍标签。',
76
80
  },
77
81
  };
@@ -95,7 +99,9 @@ export const docsDense = {
95
99
  children: 'carousel items in horizontal scroll',
96
100
  gap: 'item spacing via spacing token scale',
97
101
  hasButtons: 'prev/next buttons on hover (desktop)',
102
+ hasEdgeFade: 'gradient edge-fade mask on overflow',
98
103
  hasSnap: 'scroll-snap; children snap to start edge',
104
+ padding: 'inline padding; scroll-padding keeps snap points on content edge',
99
105
  'aria-label': 'accessible label for carousel region',
100
106
  'data-testid': 'test selector for automated testing frameworks',
101
107
  },
@@ -78,4 +78,24 @@ describe('Carousel', () => {
78
78
  expect(screen.getByLabelText('Scroll left')).toBeInTheDocument();
79
79
  expect(screen.getByLabelText('Scroll right')).toBeInTheDocument();
80
80
  });
81
+
82
+ it('disables edge scroll buttons instead of removing them from the tab order', () => {
83
+ // In jsdom there is no measurable overflow, so both edges are at rest and
84
+ // the scroll buttons are in their hidden/inert state. They must stay
85
+ // mounted but be disabled — a disabled <button> is skipped by the tab
86
+ // order and hidden from the a11y tree, so keyboard users don't focus an
87
+ // invisible control (WCAG 2.4.7).
88
+ render(
89
+ <Carousel aria-label="Edge state">
90
+ <div>Item 1</div>
91
+ <div>Item 2</div>
92
+ </Carousel>,
93
+ );
94
+ const left = screen.getByLabelText('Scroll left');
95
+ const right = screen.getByLabelText('Scroll right');
96
+ expect(left).toBeInTheDocument();
97
+ expect(right).toBeInTheDocument();
98
+ expect(left).toBeDisabled();
99
+ expect(right).toBeDisabled();
100
+ });
81
101
  });
@@ -295,9 +295,16 @@ export function Carousel({
295
295
  const firstChild = el.firstElementChild as HTMLElement | null;
296
296
  const itemWidth = firstChild ? firstChild.offsetWidth : 0;
297
297
  const amount = el.clientWidth - itemWidth * 0.5;
298
+ // Respect the user's reduced-motion preference — mirrors the CSS
299
+ // scroll-behavior override so button-driven scrolling doesn't animate
300
+ // for users who opted out of motion.
301
+ const prefersReducedMotion =
302
+ typeof window !== 'undefined' &&
303
+ typeof window.matchMedia === 'function' &&
304
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches;
298
305
  el.scrollBy({
299
306
  left: direction * Math.max(amount, itemWidth),
300
- behavior: 'smooth',
307
+ behavior: prefersReducedMotion ? 'auto' : 'smooth',
301
308
  });
302
309
  }, []);
303
310
 
@@ -360,6 +367,11 @@ export function Carousel({
360
367
  variant="ghost"
361
368
  size="sm"
362
369
  isIconOnly
370
+ // Disabled when there's nothing to scroll toward. Keeps the
371
+ // button mounted (stable layout/focus) but removes it from the
372
+ // tab order and a11y tree while it's visually hidden, so
373
+ // keyboard users don't land on an invisible control.
374
+ isDisabled={!overflowStart}
363
375
  onClick={() => scrollBy(-1)}
364
376
  xstyle={styles.buttonRadiusOverride}
365
377
  />
@@ -376,6 +388,9 @@ export function Carousel({
376
388
  variant="ghost"
377
389
  size="sm"
378
390
  isIconOnly
391
+ // See "Scroll left" — disabled while visually hidden so the
392
+ // button stays mounted but out of the tab order / a11y tree.
393
+ isDisabled={!overflowEnd}
379
394
  onClick={() => scrollBy(1)}
380
395
  xstyle={styles.buttonRadiusOverride}
381
396
  />
@@ -18,14 +18,24 @@ export const docs = {
18
18
  },
19
19
  {
20
20
  name: 'width',
21
- type: 'number | string',
21
+ type: 'SizeValue',
22
22
  description: 'Container width (px or CSS value).',
23
23
  },
24
24
  {
25
25
  name: 'height',
26
- type: 'number | string',
26
+ type: 'SizeValue',
27
27
  description: 'Container height (px or CSS value).',
28
28
  },
29
+ {
30
+ name: 'maxWidth',
31
+ type: 'SizeValue',
32
+ description: 'Maximum container width (px or CSS value).',
33
+ },
34
+ {
35
+ name: 'minHeight',
36
+ type: 'SizeValue',
37
+ description: 'Minimum container height (px or CSS value).',
38
+ },
29
39
  {
30
40
  name: 'isInline',
31
41
  type: 'boolean',
@@ -39,15 +39,21 @@ const styles = stylex.create({
39
39
 
40
40
  // Dynamic styles for sizing props
41
41
  const dynamicStyles = stylex.create({
42
- sizing: (width: SizeValue | null, height: SizeValue | null) => ({
42
+ sizing: (
43
+ width: SizeValue | null,
44
+ height: SizeValue | null,
45
+ maxWidth: SizeValue | null,
46
+ minHeight: SizeValue | null,
47
+ ) => ({
43
48
  width,
44
49
  height,
50
+ maxWidth,
51
+ minHeight,
45
52
  }),
46
53
  });
47
54
 
48
55
  export type CenterAxis = 'both' | 'horizontal' | 'vertical';
49
56
 
50
-
51
57
  export interface CenterProps extends BaseProps<HTMLDivElement> {
52
58
  /** Ref forwarded to the root element */
53
59
  ref?: React.Ref<HTMLDivElement>;
@@ -72,6 +78,18 @@ export interface CenterProps extends BaseProps<HTMLDivElement> {
72
78
  */
73
79
  height?: SizeValue;
74
80
 
81
+ /**
82
+ * Maximum width of the container.
83
+ * Numbers are treated as pixels, strings are used as-is (e.g., '100%').
84
+ */
85
+ maxWidth?: SizeValue;
86
+
87
+ /**
88
+ * Minimum height of the container.
89
+ * Numbers are treated as pixels, strings are used as-is (e.g., '100%').
90
+ */
91
+ minHeight?: SizeValue;
92
+
75
93
  /**
76
94
  * Whether to make the container inline-flex (useful for text/icons).
77
95
  * @default false
@@ -101,6 +119,8 @@ export function Center({
101
119
  axis = 'both',
102
120
  width,
103
121
  height,
122
+ maxWidth,
123
+ minHeight,
104
124
  isInline = false,
105
125
  children,
106
126
  xstyle,
@@ -115,7 +135,12 @@ export function Center({
115
135
  isInline ? styles.inline : styles.base,
116
136
  (axis === 'both' || axis === 'vertical') && styles.alignItemsCenter,
117
137
  (axis === 'both' || axis === 'horizontal') && styles.justifyContentCenter,
118
- dynamicStyles.sizing(width ?? null, height ?? null),
138
+ dynamicStyles.sizing(
139
+ width ?? null,
140
+ height ?? null,
141
+ maxWidth ?? null,
142
+ minHeight ?? null,
143
+ ),
119
144
  xstyle,
120
145
  ),
121
146
  className,
@@ -409,18 +409,36 @@ describe('ChatComposerInput', () => {
409
409
  });
410
410
 
411
411
  describe('accessibility', () => {
412
- it('has aria-haspopup on the textbox', () => {
412
+ it('exposes role=combobox when triggers are configured', () => {
413
413
  const triggers = [createMentionTrigger()];
414
414
  render(<ChatComposerInput triggers={triggers} />);
415
- const textbox = screen.getByRole('textbox');
416
- expect(textbox).toHaveAttribute('aria-haspopup', 'listbox');
415
+ // aria-expanded/haspopup/controls/activedescendant are only valid on
416
+ // role="combobox", so the editable element must be a combobox (not a
417
+ // plain textbox) whenever trigger-menu behavior is wired.
418
+ expect(screen.getByRole('combobox')).toBeInTheDocument();
419
+ expect(screen.queryByRole('textbox')).not.toBeInTheDocument();
420
+ });
421
+
422
+ it('has aria-haspopup on the combobox', () => {
423
+ const triggers = [createMentionTrigger()];
424
+ render(<ChatComposerInput triggers={triggers} />);
425
+ const combobox = screen.getByRole('combobox');
426
+ expect(combobox).toHaveAttribute('aria-haspopup', 'listbox');
417
427
  });
418
428
 
419
429
  it('has aria-expanded=false when menu is closed', () => {
420
430
  const triggers = [createMentionTrigger()];
421
431
  render(<ChatComposerInput triggers={triggers} />);
422
- const textbox = screen.getByRole('textbox');
423
- expect(textbox).toHaveAttribute('aria-expanded', 'false');
432
+ const combobox = screen.getByRole('combobox');
433
+ expect(combobox).toHaveAttribute('aria-expanded', 'false');
434
+ });
435
+
436
+ it('stays role=textbox with no combobox attributes when no triggers are configured', () => {
437
+ render(<ChatComposerInput label="Message" />);
438
+ const textbox = screen.getByRole('textbox', {name: 'Message'});
439
+ // A plain textbox must not carry combobox-only ARIA (axe: aria-allowed-attr).
440
+ expect(textbox).not.toHaveAttribute('aria-expanded');
441
+ expect(textbox).not.toHaveAttribute('aria-haspopup');
424
442
  });
425
443
  });
426
444
 
@@ -590,7 +608,8 @@ describe('ChatComposerInput', () => {
590
608
  const result = render(
591
609
  <ChatComposerInput triggers={triggers} onChange={onChange} />,
592
610
  );
593
- const textbox = screen.getByRole('textbox');
611
+ // With triggers configured the editable is a combobox, not a textbox.
612
+ const textbox = screen.getByRole('combobox');
594
613
  textbox.focus();
595
614
  return {...result, textbox, onChange};
596
615
  }
@@ -684,7 +703,7 @@ describe('ChatComposerInput', () => {
684
703
  onChange={onChange}
685
704
  />,
686
705
  );
687
- const textbox = screen.getByRole('textbox');
706
+ const textbox = screen.getByRole('combobox');
688
707
  textbox.focus();
689
708
 
690
709
  setCursorAfterText(textbox, 'hello @');
@@ -632,7 +632,6 @@ export function ChatComposerInput(props: ChatComposerInputProps) {
632
632
  )}
633
633
  <div
634
634
  ref={editableRef}
635
- role="textbox"
636
635
  aria-multiline="true"
637
636
  aria-label={label}
638
637
  contentEditable={!isDisabled}
@@ -34,7 +34,7 @@ export const docs = {
34
34
  name: 'dictation',
35
35
  type: 'UseSpeechRecognitionReturn',
36
36
  description:
37
- 'The return value from useChatDictation or useSpeechRecognition. Controls all button state \u2014 listening, volume, bands, and toggle.',
37
+ 'The return value from useChatDictation or useSpeechRecognition. Controls all button state: listening, volume, bands, and toggle.',
38
38
  required: true,
39
39
  },
40
40
  {
@@ -45,6 +45,12 @@ export const docs = {
45
45
  type: 'SpacingStep',
46
46
  description: 'Gap between top-level message rows. Defaults to the selected density; override for LLM event streams or independent rows that need different spacing from density.',
47
47
  },
48
+ {
49
+ name: 'isStreaming',
50
+ type: 'boolean',
51
+ description: 'Whether an assistant message is actively streaming. Marks the log aria-busy so screen readers wait and announce the completed message once instead of re-announcing partial text on every token.',
52
+ default: 'false',
53
+ },
48
54
  ],
49
55
  };
50
56
 
@@ -59,6 +65,7 @@ export const docsZh = {
59
65
  scrollToTopAction: '用户滚动到顶部时触发的异步操作。用于加载更早的消息。',
60
66
  density: '视觉密度,通过上下文传递给子消息。',
61
67
  gap: '顶层消息行之间的间距。默认跟随密度;当 LLM 事件流等独立行需要不同间距时可覆盖。',
68
+ isStreaming: '是否有助手消息正在流式输出。标记日志为 aria-busy,让屏幕阅读器等待并在完成后一次性播报,而不是每个 token 都重复播报。',
62
69
  },
63
70
  };
64
71
 
@@ -73,5 +80,6 @@ export const docsDense = {
73
80
  scrollToTopAction: 'async action at scroll top; load older msgs',
74
81
  density: 'visual density; flows to children via context',
75
82
  gap: 'top-level row gap; defaults to density spacing; override for independent LLM/tool rows',
83
+ isStreaming: 'assistant streaming? marks log aria-busy so SR announces the completed msg once',
76
84
  },
77
85
  };
@@ -28,6 +28,24 @@ describe('ChatMessageList', () => {
28
28
  expect(el.getAttribute('role')).toBe('log');
29
29
  });
30
30
 
31
+ it('is not aria-busy by default', () => {
32
+ render(
33
+ <ChatMessageList data-testid="list">
34
+ <div>msg</div>
35
+ </ChatMessageList>,
36
+ );
37
+ expect(screen.getByTestId('list')).not.toHaveAttribute('aria-busy');
38
+ });
39
+
40
+ it('marks the log aria-busy while streaming', () => {
41
+ render(
42
+ <ChatMessageList data-testid="list" isStreaming>
43
+ <div>msg</div>
44
+ </ChatMessageList>,
45
+ );
46
+ expect(screen.getByTestId('list')).toHaveAttribute('aria-busy', 'true');
47
+ });
48
+
31
49
  it('renders empty state when no children', () => {
32
50
  render(
33
51
  <ChatMessageList emptyState={<div>No messages yet</div>}>
@@ -72,6 +72,20 @@ export interface ChatMessageListProps extends BaseProps<HTMLDivElement> {
72
72
  * be grouped) and row spacing should be tuned separately from density.
73
73
  */
74
74
  gap?: SpacingStep;
75
+
76
+ /**
77
+ * Whether an assistant message is actively streaming into the list.
78
+ *
79
+ * The list is a `role="log"` / `aria-live="polite"` region, so while a
80
+ * message streams in token-by-token, screen readers would otherwise
81
+ * re-announce the accumulating partial text on every mutation. Set
82
+ * `isStreaming` to `true` for the duration of a stream: it marks the log
83
+ * `aria-busy="true"` so assistive tech waits and announces the completed
84
+ * message once, when `isStreaming` returns to `false`.
85
+ *
86
+ * @default false
87
+ */
88
+ isStreaming?: boolean;
75
89
  }
76
90
 
77
91
  // =============================================================================
@@ -190,6 +204,7 @@ export function ChatMessageList({
190
204
  scrollToTopAction,
191
205
  density = 'balanced',
192
206
  gap,
207
+ isStreaming = false,
193
208
  xstyle,
194
209
  className,
195
210
  style,
@@ -252,6 +267,7 @@ export function ChatMessageList({
252
267
  ref={ref}
253
268
  role="log"
254
269
  aria-live="polite"
270
+ aria-busy={isStreaming || undefined}
255
271
  tabIndex={0}
256
272
  data-testid={testId}
257
273
  {...mergeProps(
@@ -81,8 +81,15 @@ export interface UseTriggerMenuReturn {
81
81
  renderMenu: () => ReactNode;
82
82
  /** Reset/close the trigger menu */
83
83
  reset: () => void;
84
- /** ARIA props to spread onto the textbox element */
84
+ /**
85
+ * ARIA props to spread onto the editable element. When triggers are
86
+ * configured the element becomes a `combobox` (which is the only role that
87
+ * permits `aria-expanded`/`aria-haspopup`/`aria-controls`/
88
+ * `aria-activedescendant`); otherwise it stays a plain `textbox` and no
89
+ * combobox attributes are emitted.
90
+ */
85
91
  ariaProps: {
92
+ role: 'combobox' | 'textbox';
86
93
  'aria-expanded'?: boolean;
87
94
  'aria-controls'?: string;
88
95
  'aria-activedescendant'?: string;
@@ -296,6 +303,9 @@ export function useTriggerMenu(
296
303
  hasLightDismiss: true,
297
304
  hasCloseButton: false,
298
305
  hasAutoFocus: false,
306
+ // The popup's own role="listbox" is the exposed semantics; focus stays in
307
+ // the contenteditable composer, so a modal dialog wrapper is incorrect.
308
+ role: 'none',
299
309
  });
300
310
 
301
311
  // Cleanup on unmount
@@ -598,10 +608,17 @@ export function useTriggerMenu(
598
608
  el?.scrollIntoView({block: 'nearest'});
599
609
  }, [state.highlightedIndex, popover.isOpen, getItemId]);
600
610
 
601
- // ARIA props for the textbox element
602
- const ariaProps =
603
- state.isActive && popover.isOpen
611
+ // ARIA props for the editable element. Combobox attributes
612
+ // (aria-expanded/haspopup/controls/activedescendant) are only valid on
613
+ // role="combobox", so we only switch to that role — and only emit those
614
+ // attributes — when triggers are actually configured. With no triggers the
615
+ // element stays a plain role="textbox".
616
+ const hasTriggers = (triggers?.length ?? 0) > 0;
617
+ const ariaProps: UseTriggerMenuReturn['ariaProps'] = !hasTriggers
618
+ ? {role: 'textbox'}
619
+ : state.isActive && popover.isOpen
604
620
  ? {
621
+ role: 'combobox',
605
622
  'aria-expanded': true as const,
606
623
  'aria-controls': listboxId,
607
624
  'aria-activedescendant':
@@ -611,6 +628,7 @@ export function useTriggerMenu(
611
628
  'aria-haspopup': 'listbox' as const,
612
629
  }
613
630
  : {
631
+ role: 'combobox',
614
632
  'aria-expanded': false as const,
615
633
  'aria-haspopup': 'listbox' as const,
616
634
  };
@@ -63,6 +63,12 @@ export const docs = {
63
63
  description: 'Whether the checkbox is disabled.',
64
64
  default: 'false',
65
65
  },
66
+ {
67
+ name: 'disabledMessage',
68
+ type: 'string',
69
+ description:
70
+ 'Explains why the checkbox is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the checkbox focusable via aria-disabled (toggling stays blocked). Use this instead of wrapping a disabled CheckboxInput in Tooltip — disabled controls swallow the hover events an external Tooltip needs.',
71
+ },
66
72
  {
67
73
  name: 'isReadOnly',
68
74
  type: 'boolean',
@@ -124,6 +130,7 @@ export const docs = {
124
130
  { guidance: true, description: 'Use the indeterminate state for "select all" checkboxes when only some items in a group are selected.' },
125
131
  { guidance: false, description: 'Use a checkbox for mutually exclusive choices; use RadioList when only one option can be selected.' },
126
132
  { guidance: false, description: 'Use a checkbox for actions that take effect immediately; use a toggle switch or button instead.' },
133
+ { guidance: false, description: 'Wrap a disabled checkbox in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.' },
127
134
  ],
128
135
  anatomy: [
129
136
  { name: 'Checkbox', required: true, description: 'The check box itself: unchecked, checked, or indeterminate.' },
@@ -146,6 +153,7 @@ export const docsZh = {
146
153
  { guidance: true, description: 'Use the indeterminate state for "select all" checkboxes when only some items in a group are selected.' },
147
154
  { guidance: false, description: 'Use a checkbox for mutually exclusive choices; use RadioList when only one option can be selected.' },
148
155
  { guidance: false, description: 'Use a checkbox for actions that take effect immediately; use a toggle switch or button instead.' },
156
+ { guidance: false, description: 'Wrap a disabled checkbox in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.' },
149
157
  ],
150
158
  },
151
159
  props: [
@@ -163,6 +171,7 @@ export const docsZh = {
163
171
  },
164
172
  {name: 'isLoading', type: 'boolean', description: '复选框是否处于加载状态。显示旋转器并阻止交互。', default: 'false'},
165
173
  {name: 'isDisabled', type: 'boolean', description: '复选框是否禁用。', default: 'false'},
174
+ {name: 'disabledMessage', type: 'string', description: 'Explains why the checkbox is disabled. With isDisabled, shows a tooltip on hover/keyboard focus and keeps the checkbox focusable via aria-disabled (toggling stays blocked). Use this instead of wrapping a disabled CheckboxInput in Tooltip — disabled controls swallow the hover events an external Tooltip needs.'},
166
175
  {name: 'isReadOnly', type: 'boolean', description: '复选框是否为只读。以完整不透明度显示当前状态但阻止交互。与 isDisabled 不同,只读复选框不会变暗。', default: 'false'},
167
176
  {name: 'isOptional', type: 'boolean', description: '字段是否可选。与 isRequired 互斥。', default: 'false'},
168
177
  {name: 'isRequired', type: 'boolean', description: '复选框是否必填。与 isOptional 互斥。', default: 'false'},
@@ -200,6 +209,7 @@ export const docsDense = {
200
209
  { guidance: true, description: 'Use the indeterminate state for "select all" checkboxes when only some items in a group are selected.' },
201
210
  { guidance: false, description: 'Use a checkbox for mutually exclusive choices; use RadioList when only one option can be selected.' },
202
211
  { guidance: false, description: 'Use a checkbox for actions that take effect immediately; use a toggle switch or button instead.' },
212
+ { guidance: false, description: 'Wrap a disabled checkbox in Tooltip to explain why it is disabled; disabled controls swallow the hover events the wrapper needs. Use the disabledMessage prop instead.' },
203
213
  ],
204
214
  },
205
215
  propDescriptions: {