@astryxdesign/core 0.1.8 → 0.1.9-canary.09e9ddd

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 (610) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/AppShell/AppShell.d.ts.map +1 -1
  3. package/dist/AppShell/AppShell.js +6 -2
  4. package/dist/AppShell/AppShellMobileContext.d.ts +8 -0
  5. package/dist/AppShell/AppShellMobileContext.d.ts.map +1 -1
  6. package/dist/Avatar/Avatar.d.ts +53 -3
  7. package/dist/Avatar/Avatar.d.ts.map +1 -1
  8. package/dist/Avatar/Avatar.js +203 -49
  9. package/dist/Avatar/AvatarStatusDot.d.ts +33 -5
  10. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  11. package/dist/Avatar/AvatarStatusDot.js +144 -19
  12. package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
  13. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroup.js +58 -6
  15. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  16. package/dist/AvatarGroup/AvatarGroupOverflow.js +1 -0
  17. package/dist/Banner/Banner.d.ts +9 -1
  18. package/dist/Banner/Banner.d.ts.map +1 -1
  19. package/dist/Banner/Banner.js +33 -4
  20. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +31 -2
  21. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  22. package/dist/Breadcrumbs/BreadcrumbItem.js +208 -6
  23. package/dist/Breadcrumbs/index.d.ts +5 -0
  24. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  25. package/dist/Breadcrumbs/index.js +9 -1
  26. package/dist/Button/Button.d.ts +8 -2
  27. package/dist/Button/Button.d.ts.map +1 -1
  28. package/dist/Button/Button.js +33 -4
  29. package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
  30. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  31. package/dist/ButtonGroup/ButtonGroup.js +30 -1
  32. package/dist/Calendar/Calendar.d.ts.map +1 -1
  33. package/dist/Calendar/Calendar.js +30 -2
  34. package/dist/Calendar/dayCellUtils.js +1 -1
  35. package/dist/Card/Card.d.ts +8 -2
  36. package/dist/Card/Card.d.ts.map +1 -1
  37. package/dist/Card/Card.js +28 -2
  38. package/dist/Carousel/Carousel.d.ts +4 -1
  39. package/dist/Carousel/Carousel.d.ts.map +1 -1
  40. package/dist/Carousel/Carousel.js +24 -4
  41. package/dist/Chat/ChatComposer.d.ts +8 -0
  42. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  43. package/dist/Chat/ChatComposer.js +46 -7
  44. package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
  45. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  46. package/dist/Chat/ChatComposerDrawer.js +11 -1
  47. package/dist/Chat/ChatComposerInput.d.ts +20 -3
  48. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  49. package/dist/Chat/ChatComposerInput.js +36 -4
  50. package/dist/Chat/ChatContext.d.ts +33 -0
  51. package/dist/Chat/ChatContext.d.ts.map +1 -1
  52. package/dist/Chat/ChatContext.js +16 -2
  53. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  54. package/dist/Chat/ChatDictationButton.js +1 -1
  55. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  56. package/dist/Chat/ChatLayout.js +4 -4
  57. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  58. package/dist/Chat/ChatLayoutScrollButton.js +4 -4
  59. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  60. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  61. package/dist/Chat/ChatSendButton.js +7 -1
  62. package/dist/Chat/ChatToolCalls.d.ts +5 -1
  63. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  64. package/dist/Chat/ChatToolCalls.js +18 -9
  65. package/dist/Chat/index.d.ts +2 -1
  66. package/dist/Chat/index.d.ts.map +1 -1
  67. package/dist/Chat/index.js +1 -1
  68. package/dist/Chat/useChatStreamScroll.d.ts +2 -1
  69. package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
  70. package/dist/Chat/useChatStreamScroll.js +22 -8
  71. package/dist/Chat/useSpeechRecognition.d.ts +0 -1
  72. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  73. package/dist/Chat/useSpeechRecognition.js +1 -1
  74. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  75. package/dist/Chat/useTriggerMenu.js +2 -2
  76. package/dist/CheckboxInput/CheckboxInput.js +1 -1
  77. package/dist/CheckboxList/CheckboxListItem.d.ts +20 -1
  78. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  79. package/dist/CheckboxList/CheckboxListItem.js +11 -1
  80. package/dist/Citation/Citation.d.ts +22 -1
  81. package/dist/Citation/Citation.d.ts.map +1 -1
  82. package/dist/Citation/Citation.js +20 -6
  83. package/dist/ClickableCard/ClickableCard.d.ts +9 -2
  84. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  85. package/dist/ClickableCard/ClickableCard.js +5 -2
  86. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  87. package/dist/CodeBlock/CodeBlock.js +9 -2
  88. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  89. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  90. package/dist/CommandPalette/CommandPalette.js +3 -1
  91. package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
  92. package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
  93. package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
  94. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  95. package/dist/CommandPalette/CommandPaletteInput.js +6 -1
  96. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  97. package/dist/DateInput/DateInput.d.ts +55 -2
  98. package/dist/DateInput/DateInput.d.ts.map +1 -1
  99. package/dist/DateInput/DateInput.js +28 -2
  100. package/dist/DateInput/index.d.ts +1 -1
  101. package/dist/DateInput/index.d.ts.map +1 -1
  102. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  103. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  104. package/dist/DateRangeInput/DateRangeInput.js +3 -1
  105. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  106. package/dist/DateTimeInput/DateTimeInput.js +18 -3
  107. package/dist/Dialog/Dialog.d.ts +3 -0
  108. package/dist/Dialog/Dialog.d.ts.map +1 -1
  109. package/dist/Dialog/Dialog.js +57 -6
  110. package/dist/Dialog/DialogContext.d.ts +7 -0
  111. package/dist/Dialog/DialogContext.d.ts.map +1 -1
  112. package/dist/Dialog/DialogContext.js +2 -2
  113. package/dist/Dialog/DialogHeader.d.ts +5 -2
  114. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  115. package/dist/Dialog/DialogHeader.js +6 -1
  116. package/dist/Divider/Divider.js +1 -1
  117. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
  118. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  119. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
  120. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  121. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
  122. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  123. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
  124. package/dist/Field/Field.d.ts.map +1 -1
  125. package/dist/Field/Field.js +2 -3
  126. package/dist/Field/FieldLabel.d.ts +1 -1
  127. package/dist/Field/FieldLabel.d.ts.map +1 -1
  128. package/dist/Field/FieldLabel.js +43 -16
  129. package/dist/FieldStatus/FieldStatus.d.ts +15 -0
  130. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  131. package/dist/FieldStatus/FieldStatus.js +58 -6
  132. package/dist/FileInput/FileInput.d.ts +9 -2
  133. package/dist/FileInput/FileInput.d.ts.map +1 -1
  134. package/dist/FileInput/FileInput.js +42 -20
  135. package/dist/HoverCard/HoverCard.d.ts +9 -1
  136. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  137. package/dist/HoverCard/HoverCard.js +2 -0
  138. package/dist/HoverCard/useHoverCard.d.ts +8 -0
  139. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  140. package/dist/HoverCard/useHoverCard.js +7 -2
  141. package/dist/Icon/Icon.d.ts +7 -2
  142. package/dist/Icon/Icon.d.ts.map +1 -1
  143. package/dist/Item/Item.d.ts +6 -1
  144. package/dist/Item/Item.d.ts.map +1 -1
  145. package/dist/Item/Item.js +22 -1
  146. package/dist/Layer/useLayer.d.ts +6 -0
  147. package/dist/Layer/useLayer.d.ts.map +1 -1
  148. package/dist/Layer/useLayer.js +2 -0
  149. package/dist/Lightbox/Lightbox.js +4 -4
  150. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  151. package/dist/MobileNav/MobileNav.js +6 -1
  152. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  153. package/dist/MobileNav/MobileNavToggle.js +4 -0
  154. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  155. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  156. package/dist/MultiSelector/MultiSelector.js +41 -12
  157. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  158. package/dist/MultiSelector/hooks.js +16 -0
  159. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  160. package/dist/NumberInput/NumberInput.d.ts +9 -2
  161. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  162. package/dist/NumberInput/NumberInput.js +8 -1
  163. package/dist/Outline/Outline.d.ts +0 -1
  164. package/dist/Outline/Outline.d.ts.map +1 -1
  165. package/dist/Outline/Outline.js +0 -1
  166. package/dist/OverflowList/OverflowList.d.ts +20 -3
  167. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  168. package/dist/OverflowList/OverflowList.js +29 -4
  169. package/dist/Pagination/Pagination.d.ts.map +1 -1
  170. package/dist/Pagination/Pagination.js +11 -3
  171. package/dist/Popover/Popover.d.ts.map +1 -1
  172. package/dist/Popover/Popover.js +3 -2
  173. package/dist/Popover/usePopover.d.ts.map +1 -1
  174. package/dist/Popover/usePopover.js +3 -9
  175. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  176. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  177. package/dist/PowerSearch/PowerSearch.js +2 -0
  178. package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
  179. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  180. package/dist/SelectableCard/SelectableCard.d.ts +9 -2
  181. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  182. package/dist/SelectableCard/SelectableCard.js +16 -13
  183. package/dist/Selector/Selector.d.ts +8 -0
  184. package/dist/Selector/Selector.d.ts.map +1 -1
  185. package/dist/Selector/Selector.js +7 -3
  186. package/dist/Selector/hooks.d.ts.map +1 -1
  187. package/dist/Selector/hooks.js +16 -0
  188. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  189. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  190. package/dist/SideNav/SideNavHeading.js +21 -8
  191. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  192. package/dist/Slider/Slider.d.ts.map +1 -1
  193. package/dist/Slider/Slider.js +19 -2
  194. package/dist/Stack/stack.stylex.d.ts +9 -9
  195. package/dist/TabList/Tab.js +2 -2
  196. package/dist/TabList/TabMenu.js +1 -1
  197. package/dist/Table/BaseTable.d.ts.map +1 -1
  198. package/dist/Table/BaseTable.js +3 -2
  199. package/dist/Table/TableCell.js +3 -3
  200. package/dist/Table/TableHeaderCell.js +3 -3
  201. package/dist/Table/index.d.ts +2 -0
  202. package/dist/Table/index.d.ts.map +1 -1
  203. package/dist/Table/index.js +1 -0
  204. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  205. package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
  206. package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
  207. package/dist/Table/plugins/rowStatus/index.js +3 -0
  208. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
  209. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
  210. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
  211. package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
  212. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  213. package/dist/Table/plugins/selection/useTableSelection.js +4 -1
  214. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +1 -1
  215. package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
  216. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  217. package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
  218. package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
  219. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
  220. package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
  221. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  222. package/dist/Table/useBaseTablePlugins.js +5 -3
  223. package/dist/TextArea/TextArea.d.ts +9 -1
  224. package/dist/TextArea/TextArea.d.ts.map +1 -1
  225. package/dist/TextArea/TextArea.js +2 -0
  226. package/dist/TextInput/TextInput.d.ts +9 -2
  227. package/dist/TextInput/TextInput.d.ts.map +1 -1
  228. package/dist/TextInput/TextInput.js +6 -1
  229. package/dist/Thumbnail/Thumbnail.d.ts +26 -5
  230. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  231. package/dist/Thumbnail/Thumbnail.js +97 -54
  232. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
  233. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
  234. package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
  235. package/dist/TimeInput/TimeInput.d.ts +9 -2
  236. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  237. package/dist/TimeInput/TimeInput.js +17 -4
  238. package/dist/Timestamp/Timestamp.d.ts +3 -1
  239. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  240. package/dist/Timestamp/Timestamp.js +8 -6
  241. package/dist/Toast/useToast.d.ts.map +1 -1
  242. package/dist/Toast/useToast.js +2 -5
  243. package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
  244. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  245. package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
  246. package/dist/Tokenizer/Tokenizer.d.ts +10 -3
  247. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  248. package/dist/Tokenizer/Tokenizer.js +18 -4
  249. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  250. package/dist/TopNav/TopNavHeading.js +18 -8
  251. package/dist/TopNav/TopNavMegaMenu.js +10 -4
  252. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
  253. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  254. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
  255. package/dist/TopNav/TopNavMenu.d.ts +2 -1
  256. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  257. package/dist/TopNav/TopNavMenu.js +68 -6
  258. package/dist/TreeList/TreeList.d.ts +12 -3
  259. package/dist/TreeList/TreeList.d.ts.map +1 -1
  260. package/dist/TreeList/TreeList.js +2 -0
  261. package/dist/TreeList/TreeListBranches.d.ts +5 -0
  262. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  263. package/dist/TreeList/TreeListBranches.js +10 -4
  264. package/dist/TreeList/TreeListItem.d.ts +8 -2
  265. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  266. package/dist/TreeList/TreeListItem.js +28 -8
  267. package/dist/TreeList/TreeListTypes.d.ts +25 -1
  268. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  269. package/dist/TreeList/index.d.ts +2 -2
  270. package/dist/TreeList/index.d.ts.map +1 -1
  271. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  272. package/dist/Typeahead/BaseTypeahead.js +20 -11
  273. package/dist/Typeahead/Typeahead.d.ts +9 -2
  274. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  275. package/dist/Typeahead/Typeahead.js +2 -0
  276. package/dist/astryx.css +41 -31
  277. package/dist/astryx.umd.js +51 -51
  278. package/dist/astryx.umd.js.map +4 -4
  279. package/dist/authoring/doc.d.ts.map +1 -1
  280. package/dist/docs-types.d.ts +8 -0
  281. package/dist/docs-types.d.ts.map +1 -1
  282. package/dist/hooks/computeOverflow.d.ts +47 -0
  283. package/dist/hooks/computeOverflow.d.ts.map +1 -0
  284. package/dist/hooks/computeOverflow.js +213 -0
  285. package/dist/hooks/index.d.ts +1 -0
  286. package/dist/hooks/index.d.ts.map +1 -1
  287. package/dist/hooks/index.js +2 -1
  288. package/dist/hooks/isRtlElement.d.ts +18 -0
  289. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  290. package/dist/hooks/isRtlElement.js +27 -0
  291. package/dist/hooks/useDevWarning.d.ts +18 -0
  292. package/dist/hooks/useDevWarning.d.ts.map +1 -0
  293. package/dist/hooks/useDevWarning.js +49 -0
  294. package/dist/hooks/useGridFocus.d.ts +6 -1
  295. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  296. package/dist/hooks/useGridFocus.js +12 -9
  297. package/dist/hooks/useListFocus.d.ts +6 -1
  298. package/dist/hooks/useListFocus.d.ts.map +1 -1
  299. package/dist/hooks/useListFocus.js +12 -4
  300. package/dist/hooks/useOverflow.d.ts +19 -0
  301. package/dist/hooks/useOverflow.d.ts.map +1 -1
  302. package/dist/hooks/useOverflow.js +36 -25
  303. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  304. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  305. package/dist/i18n/InternationalizationContext.js +3 -0
  306. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  307. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  308. package/dist/i18n/InternationalizationProvider.js +5 -1
  309. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  310. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  311. package/dist/i18n/getLocaleDirection.js +29 -0
  312. package/dist/i18n/index.d.ts +6 -0
  313. package/dist/i18n/index.d.ts.map +1 -1
  314. package/dist/i18n/index.js +7 -1
  315. package/dist/i18n/resolve.d.ts.map +1 -1
  316. package/dist/i18n/resolve.js +7 -18
  317. package/dist/i18n/useDirection.d.ts +2 -0
  318. package/dist/i18n/useDirection.d.ts.map +1 -0
  319. package/dist/i18n/useDirection.js +27 -0
  320. package/dist/theme/Theme.d.ts.map +1 -1
  321. package/dist/theme/Theme.js +2 -7
  322. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  323. package/dist/theme/derivedVarRegistry.js +13 -0
  324. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  325. package/dist/theme/generateThemeRules.js +51 -0
  326. package/dist/theme/hct.d.ts +0 -1
  327. package/dist/theme/hct.d.ts.map +1 -1
  328. package/dist/theme/hct.js +1 -1
  329. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  330. package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
  331. package/dist/utils/devWarning.d.ts +42 -0
  332. package/dist/utils/devWarning.d.ts.map +1 -0
  333. package/dist/utils/devWarning.js +88 -0
  334. package/dist/utils/index.d.ts +3 -1
  335. package/dist/utils/index.d.ts.map +1 -1
  336. package/dist/utils/index.js +3 -2
  337. package/dist/utils/plainDate.d.ts +30 -0
  338. package/dist/utils/plainDate.d.ts.map +1 -1
  339. package/dist/utils/plainDate.js +53 -0
  340. package/dist/utils/types.d.ts +13 -0
  341. package/dist/utils/types.d.ts.map +1 -1
  342. package/locales/en.json +32 -0
  343. package/locales/fr-FR.json +14 -0
  344. package/locales/pseudo.json +24 -0
  345. package/package.json +1 -1
  346. package/src/AppShell/AppShell.tsx +6 -0
  347. package/src/AppShell/AppShellMobileContext.tsx +8 -0
  348. package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
  349. package/src/Avatar/Avatar.doc.mjs +60 -3
  350. package/src/Avatar/Avatar.test.tsx +281 -1
  351. package/src/Avatar/Avatar.tsx +324 -64
  352. package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
  353. package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
  354. package/src/Avatar/AvatarStatusDot.tsx +178 -21
  355. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  356. package/src/AvatarGroup/AvatarGroup.test.tsx +125 -0
  357. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  358. package/src/AvatarGroup/AvatarGroupOverflow.tsx +1 -0
  359. package/src/Banner/Banner.doc.mjs +9 -0
  360. package/src/Banner/Banner.test.tsx +30 -0
  361. package/src/Banner/Banner.tsx +53 -9
  362. package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
  363. package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
  364. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
  365. package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
  366. package/src/Breadcrumbs/index.ts +27 -0
  367. package/src/Button/Button.doc.mjs +9 -4
  368. package/src/Button/Button.test.tsx +49 -0
  369. package/src/Button/Button.tsx +27 -3
  370. package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
  371. package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
  372. package/src/ButtonGroup/ButtonGroup.tsx +32 -0
  373. package/src/Calendar/Calendar.doc.mjs +12 -1
  374. package/src/Calendar/Calendar.test.tsx +193 -0
  375. package/src/Calendar/Calendar.tsx +38 -16
  376. package/src/Calendar/dayCellUtils.test.ts +5 -0
  377. package/src/Calendar/dayCellUtils.ts +1 -1
  378. package/src/Card/Card.doc.mjs +9 -0
  379. package/src/Card/Card.test.tsx +21 -3
  380. package/src/Card/Card.tsx +35 -2
  381. package/src/Carousel/Carousel.doc.mjs +1 -0
  382. package/src/Carousel/Carousel.test.tsx +53 -0
  383. package/src/Carousel/Carousel.tsx +34 -4
  384. package/src/Chat/ChatComposer.doc.mjs +12 -3
  385. package/src/Chat/ChatComposer.test.tsx +115 -0
  386. package/src/Chat/ChatComposer.tsx +73 -9
  387. package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
  388. package/src/Chat/ChatComposerDrawer.tsx +11 -1
  389. package/src/Chat/ChatComposerInput.doc.mjs +7 -0
  390. package/src/Chat/ChatComposerInput.test.tsx +103 -0
  391. package/src/Chat/ChatComposerInput.tsx +51 -5
  392. package/src/Chat/ChatContext.tsx +37 -10
  393. package/src/Chat/ChatDictationButton.tsx +4 -1
  394. package/src/Chat/ChatLayout.tsx +7 -5
  395. package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
  396. package/src/Chat/ChatMessageMetadata.tsx +1 -2
  397. package/src/Chat/ChatSendButton.tsx +11 -1
  398. package/src/Chat/ChatToolCalls.test.tsx +64 -0
  399. package/src/Chat/ChatToolCalls.tsx +25 -4
  400. package/src/Chat/index.ts +5 -1
  401. package/src/Chat/useChatStreamScroll.test.tsx +49 -0
  402. package/src/Chat/useChatStreamScroll.ts +27 -10
  403. package/src/Chat/useSpeechRecognition.ts +1 -1
  404. package/src/Chat/useTriggerMenu.tsx +4 -2
  405. package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
  406. package/src/CheckboxInput/CheckboxInput.tsx +1 -1
  407. package/src/CheckboxList/CheckboxList.test.tsx +81 -3
  408. package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
  409. package/src/CheckboxList/CheckboxListItem.tsx +41 -5
  410. package/src/Citation/Citation.doc.mjs +4 -3
  411. package/src/Citation/Citation.test.tsx +97 -0
  412. package/src/Citation/Citation.tsx +43 -11
  413. package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
  414. package/src/ClickableCard/ClickableCard.test.tsx +34 -0
  415. package/src/ClickableCard/ClickableCard.tsx +13 -3
  416. package/src/CodeBlock/CodeBlock.test.tsx +56 -0
  417. package/src/CodeBlock/CodeBlock.tsx +10 -2
  418. package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
  419. package/src/CommandPalette/CommandPalette.tsx +3 -1
  420. package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
  421. package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
  422. package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
  423. package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
  424. package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
  425. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  426. package/src/ContextMenu/ContextMenu.test.tsx +193 -0
  427. package/src/DateInput/DateInput.doc.mjs +31 -0
  428. package/src/DateInput/DateInput.test.tsx +131 -0
  429. package/src/DateInput/DateInput.tsx +78 -3
  430. package/src/DateInput/index.ts +1 -0
  431. package/src/DateRangeInput/DateRangeInput.doc.mjs +8 -0
  432. package/src/DateRangeInput/DateRangeInput.test.tsx +23 -0
  433. package/src/DateRangeInput/DateRangeInput.tsx +13 -3
  434. package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -1
  435. package/src/DateTimeInput/DateTimeInput.test.tsx +147 -0
  436. package/src/DateTimeInput/DateTimeInput.tsx +42 -18
  437. package/src/Dialog/Dialog.doc.mjs +2 -2
  438. package/src/Dialog/Dialog.test.tsx +77 -4
  439. package/src/Dialog/Dialog.tsx +89 -5
  440. package/src/Dialog/DialogContext.ts +9 -2
  441. package/src/Dialog/DialogHeader.doc.mjs +2 -2
  442. package/src/Dialog/DialogHeader.tsx +9 -2
  443. package/src/Divider/Divider.tsx +2 -2
  444. package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
  445. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
  446. package/src/DropdownMenu/DropdownMenuItem.tsx +1 -1
  447. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
  448. package/src/Field/Field.test.tsx +57 -12
  449. package/src/Field/Field.tsx +6 -5
  450. package/src/Field/FieldLabel.tsx +9 -1
  451. package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
  452. package/src/FieldStatus/FieldStatus.test.tsx +150 -40
  453. package/src/FieldStatus/FieldStatus.tsx +63 -5
  454. package/src/FileInput/FileInput.doc.mjs +17 -2
  455. package/src/FileInput/FileInput.test.tsx +135 -12
  456. package/src/FileInput/FileInput.tsx +53 -28
  457. package/src/HoverCard/HoverCard.doc.mjs +13 -0
  458. package/src/HoverCard/HoverCard.test.tsx +21 -2
  459. package/src/HoverCard/HoverCard.tsx +11 -0
  460. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  461. package/src/HoverCard/useHoverCard.tsx +24 -2
  462. package/src/Icon/Icon.doc.mjs +3 -2
  463. package/src/Icon/Icon.tsx +7 -2
  464. package/src/IconButton/IconButton.doc.mjs +8 -0
  465. package/src/IconButton/IconButton.test.tsx +15 -18
  466. package/src/Item/Item.test.tsx +40 -18
  467. package/src/Item/Item.tsx +38 -2
  468. package/src/Layer/useLayer.tsx +8 -0
  469. package/src/Lightbox/Lightbox.tsx +4 -4
  470. package/src/List/List.test.tsx +9 -8
  471. package/src/MobileNav/MobileNav.tsx +12 -1
  472. package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
  473. package/src/MobileNav/MobileNavToggle.tsx +9 -1
  474. package/src/MultiSelector/MultiSelector.doc.mjs +13 -2
  475. package/src/MultiSelector/MultiSelector.test.tsx +195 -3
  476. package/src/MultiSelector/MultiSelector.tsx +65 -12
  477. package/src/MultiSelector/hooks.ts +17 -0
  478. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  479. package/src/NumberInput/NumberInput.doc.mjs +15 -0
  480. package/src/NumberInput/NumberInput.test.tsx +82 -7
  481. package/src/NumberInput/NumberInput.tsx +21 -4
  482. package/src/Outline/Outline.tsx +0 -1
  483. package/src/OverflowList/OverflowList.doc.mjs +39 -6
  484. package/src/OverflowList/OverflowList.test.tsx +111 -0
  485. package/src/OverflowList/OverflowList.tsx +48 -8
  486. package/src/Pagination/Pagination.tsx +11 -3
  487. package/src/Popover/Popover.tsx +7 -4
  488. package/src/Popover/usePopover.tsx +9 -13
  489. package/src/PowerSearch/PowerSearch.doc.mjs +29 -0
  490. package/src/PowerSearch/PowerSearch.test.tsx +43 -0
  491. package/src/PowerSearch/PowerSearch.tsx +10 -1
  492. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
  493. package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
  494. package/src/PowerSearch/usePowerSearchSource.ts +1 -2
  495. package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
  496. package/src/SelectableCard/SelectableCard.test.tsx +46 -4
  497. package/src/SelectableCard/SelectableCard.tsx +29 -16
  498. package/src/Selector/Selector.doc.mjs +7 -0
  499. package/src/Selector/Selector.test.tsx +92 -0
  500. package/src/Selector/Selector.tsx +16 -2
  501. package/src/Selector/hooks.ts +17 -0
  502. package/src/SideNav/SideNav.test.tsx +119 -3
  503. package/src/SideNav/SideNavCollapseButton.tsx +6 -1
  504. package/src/SideNav/SideNavHeading.tsx +24 -8
  505. package/src/SideNav/SideNavItem.tsx +5 -1
  506. package/src/Slider/Slider.test.tsx +75 -2
  507. package/src/Slider/Slider.tsx +21 -5
  508. package/src/Switch/Switch.test.tsx +32 -1
  509. package/src/TabList/Tab.tsx +2 -2
  510. package/src/TabList/TabMenu.tsx +2 -2
  511. package/src/Table/BaseTable.tsx +3 -5
  512. package/src/Table/TableCell.tsx +3 -3
  513. package/src/Table/TableHeaderCell.tsx +3 -3
  514. package/src/Table/index.ts +5 -0
  515. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
  516. package/src/Table/plugins/rowStatus/index.ts +7 -0
  517. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
  518. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
  519. package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
  520. package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
  521. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -1
  522. package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
  523. package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
  524. package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
  525. package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
  526. package/src/Table/useBaseTablePlugins.ts +10 -6
  527. package/src/Table/useTableRowStatus.doc.mjs +30 -0
  528. package/src/Table/useTableSelection.doc.mjs +65 -14
  529. package/src/Table/useTableTreeData.doc.mjs +29 -0
  530. package/src/Table/useTableTreeState.doc.mjs +2 -2
  531. package/src/TextArea/TextArea.doc.mjs +15 -0
  532. package/src/TextArea/TextArea.test.tsx +32 -1
  533. package/src/TextArea/TextArea.tsx +10 -0
  534. package/src/TextInput/TextInput.doc.mjs +15 -0
  535. package/src/TextInput/TextInput.test.tsx +44 -0
  536. package/src/TextInput/TextInput.tsx +13 -1
  537. package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
  538. package/src/Thumbnail/Thumbnail.test.tsx +98 -7
  539. package/src/Thumbnail/Thumbnail.tsx +142 -42
  540. package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
  541. package/src/TimeInput/TimeInput.doc.mjs +15 -0
  542. package/src/TimeInput/TimeInput.test.tsx +99 -1
  543. package/src/TimeInput/TimeInput.tsx +29 -6
  544. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  545. package/src/Timestamp/Timestamp.test.tsx +32 -0
  546. package/src/Timestamp/Timestamp.tsx +28 -8
  547. package/src/Toast/useToast.tsx +7 -8
  548. package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
  549. package/src/Tokenizer/Tokenizer.doc.mjs +30 -1
  550. package/src/Tokenizer/Tokenizer.test.tsx +206 -2
  551. package/src/Tokenizer/Tokenizer.tsx +26 -4
  552. package/src/TopNav/TopNav.test.tsx +125 -1
  553. package/src/TopNav/TopNavHeading.tsx +24 -8
  554. package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
  555. package/src/TopNav/TopNavMegaMenu.tsx +10 -4
  556. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
  557. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
  558. package/src/TopNav/TopNavMenu.test.tsx +118 -4
  559. package/src/TopNav/TopNavMenu.tsx +83 -5
  560. package/src/TreeList/TreeList.doc.mjs +22 -0
  561. package/src/TreeList/TreeList.test.tsx +232 -0
  562. package/src/TreeList/TreeList.tsx +18 -2
  563. package/src/TreeList/TreeListBranches.tsx +16 -2
  564. package/src/TreeList/TreeListItem.tsx +52 -12
  565. package/src/TreeList/TreeListTypes.ts +27 -1
  566. package/src/TreeList/index.ts +2 -2
  567. package/src/Typeahead/BaseTypeahead.tsx +30 -15
  568. package/src/Typeahead/Typeahead.doc.mjs +7 -0
  569. package/src/Typeahead/Typeahead.test.tsx +50 -0
  570. package/src/Typeahead/Typeahead.tsx +10 -0
  571. package/src/authoring/doc.ts +1 -3
  572. package/src/docs-types.ts +5 -0
  573. package/src/hooks/computeOverflow.test.ts +422 -0
  574. package/src/hooks/computeOverflow.ts +290 -0
  575. package/src/hooks/index.ts +2 -0
  576. package/src/hooks/isRtlElement.ts +27 -0
  577. package/src/hooks/useDevWarning.test.tsx +45 -0
  578. package/src/hooks/useDevWarning.ts +54 -0
  579. package/src/hooks/useGridFocus.doc.mjs +3 -3
  580. package/src/hooks/useGridFocus.test.tsx +41 -0
  581. package/src/hooks/useGridFocus.ts +21 -10
  582. package/src/hooks/useListFocus.doc.mjs +3 -3
  583. package/src/hooks/useListFocus.test.tsx +67 -1
  584. package/src/hooks/useListFocus.ts +21 -5
  585. package/src/hooks/useOverflow.test.ts +96 -4
  586. package/src/hooks/useOverflow.ts +74 -33
  587. package/src/i18n/InternationalizationContext.ts +4 -0
  588. package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
  589. package/src/i18n/InternationalizationProvider.tsx +12 -2
  590. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  591. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  592. package/src/i18n/getLocaleDirection.ts +29 -0
  593. package/src/i18n/index.ts +6 -0
  594. package/src/i18n/resolve.ts +9 -21
  595. package/src/i18n/useDirection.ts +29 -0
  596. package/src/reset.css +0 -26
  597. package/src/reset.test.ts +60 -0
  598. package/src/theme/Theme.tsx +11 -14
  599. package/src/theme/derivedVarRegistry.test.ts +1 -0
  600. package/src/theme/derivedVarRegistry.ts +6 -0
  601. package/src/theme/generateThemeRules.test.ts +107 -0
  602. package/src/theme/generateThemeRules.ts +56 -0
  603. package/src/theme/hct.ts +1 -1
  604. package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
  605. package/src/utils/devWarning.test.ts +56 -0
  606. package/src/utils/devWarning.ts +102 -0
  607. package/src/utils/index.ts +6 -0
  608. package/src/utils/plainDate.test.ts +22 -0
  609. package/src/utils/plainDate.ts +61 -0
  610. package/src/utils/types.ts +14 -0
@@ -9,11 +9,17 @@
9
9
  * SYNC: When Tokenizer.tsx changes, update tests to match
10
10
  */
11
11
 
12
- import {describe, it, expect, vi, beforeAll, afterAll} from 'vitest';
12
+ import {describe, it, expect, vi, beforeAll, afterAll, afterEach} from 'vitest';
13
13
  import {render, screen, fireEvent, act, waitFor} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
15
  import {Tokenizer} from './Tokenizer';
16
+ import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
16
17
  import type {SearchSource, SearchableItem} from '../Typeahead/types';
18
+ import {TestIcon} from '../__tests__/TestIcon';
19
+
20
+ function politeRegion(): HTMLElement | null {
21
+ return document.querySelector('[data-astryx-live-region="polite"]');
22
+ }
17
23
 
18
24
  // Store original matches to restore later
19
25
  const originalMatches = HTMLElement.prototype.matches;
@@ -60,6 +66,10 @@ afterAll(() => {
60
66
  (HTMLElement.prototype as any).matches = originalMatches;
61
67
  });
62
68
 
69
+ afterEach(() => {
70
+ __resetLiveRegionsForTest();
71
+ });
72
+
63
73
  // Test data
64
74
  const users: SearchableItem[] = [
65
75
  {id: '1', label: 'Alice'},
@@ -818,6 +828,51 @@ describe('Tokenizer', () => {
818
828
  });
819
829
  });
820
830
 
831
+ describe('startIcon', () => {
832
+ it('does not render a start icon when omitted', () => {
833
+ render(
834
+ <Tokenizer
835
+ label="Members"
836
+ searchSource={userSource}
837
+ value={[]}
838
+ onChange={() => {}}
839
+ />,
840
+ );
841
+ expect(document.querySelector('svg')).not.toBeInTheDocument();
842
+ });
843
+
844
+ it('renders a ReactNode start icon before the tokens', () => {
845
+ render(
846
+ <Tokenizer
847
+ label="Members"
848
+ searchSource={userSource}
849
+ value={[{id: '1', label: 'Alice'}]}
850
+ onChange={() => {}}
851
+ startIcon={<TestIcon data-testid="start-icon" />}
852
+ />,
853
+ );
854
+ const icon = screen.getByTestId('start-icon');
855
+ const token = screen.getByText('Alice');
856
+ expect(icon).toBeInTheDocument();
857
+ expect(
858
+ icon.compareDocumentPosition(token) & Node.DOCUMENT_POSITION_FOLLOWING,
859
+ ).toBeTruthy();
860
+ });
861
+
862
+ it('renders an IconType (SVG component) start icon', () => {
863
+ render(
864
+ <Tokenizer
865
+ label="Members"
866
+ searchSource={userSource}
867
+ value={[]}
868
+ onChange={() => {}}
869
+ startIcon={TestIcon}
870
+ />,
871
+ );
872
+ expect(document.querySelector('svg')).toBeInTheDocument();
873
+ });
874
+ });
875
+
821
876
  describe('disabledMessage', () => {
822
877
  const h = {hidden: true} as const;
823
878
  const isOpen = (el: Element) => el.matches(':popover-open');
@@ -921,6 +976,130 @@ describe('Tokenizer', () => {
921
976
  expect(screen.getByRole('combobox')).toBeDisabled();
922
977
  });
923
978
  });
979
+ describe('announcements', () => {
980
+ it('announces removal politely on Backspace with an empty input', async () => {
981
+ const onChange = vi.fn();
982
+ render(
983
+ <Tokenizer
984
+ label="Members"
985
+ searchSource={userSource}
986
+ value={[users[0], users[1]]}
987
+ onChange={onChange}
988
+ />,
989
+ );
990
+ const input = screen.getByRole('combobox');
991
+ fireEvent.keyDown(input, {key: 'Backspace'});
992
+ expect(onChange).toHaveBeenCalledWith([users[0]], {
993
+ item: users[1],
994
+ type: 'remove',
995
+ });
996
+ await waitFor(() => {
997
+ expect(politeRegion()).toHaveTextContent('Removed Bob');
998
+ });
999
+ });
1000
+
1001
+ it("announces removal politely when clicking a token's remove button", async () => {
1002
+ render(
1003
+ <Tokenizer
1004
+ label="Members"
1005
+ searchSource={userSource}
1006
+ value={[users[0], users[1]]}
1007
+ onChange={() => {}}
1008
+ />,
1009
+ );
1010
+ fireEvent.click(screen.getByRole('button', {name: 'Remove Alice'}));
1011
+ await waitFor(() => {
1012
+ expect(politeRegion()).toHaveTextContent('Removed Alice');
1013
+ });
1014
+ });
1015
+
1016
+ it('announces addition politely when selecting a search result', async () => {
1017
+ render(
1018
+ <Tokenizer
1019
+ label="Members"
1020
+ searchSource={userSource}
1021
+ value={[]}
1022
+ onChange={() => {}}
1023
+ hasEntriesOnFocus
1024
+ debounceMs={0}
1025
+ />,
1026
+ );
1027
+ const input = screen.getByRole('combobox');
1028
+ fireEvent.focus(input);
1029
+ await act(async () => {
1030
+ await new Promise(r => setTimeout(r, 50));
1031
+ });
1032
+ fireEvent.click(screen.getByText('Alice'));
1033
+ await waitFor(() => {
1034
+ expect(politeRegion()).toHaveTextContent('Added Alice');
1035
+ });
1036
+ });
1037
+
1038
+ it('announces addition politely when creating a token with hasCreate', async () => {
1039
+ const emptySource: SearchSource = {
1040
+ search: () => [],
1041
+ bootstrap: () => [],
1042
+ };
1043
+ render(
1044
+ <Tokenizer
1045
+ label="Tags"
1046
+ searchSource={emptySource}
1047
+ value={[]}
1048
+ onChange={() => {}}
1049
+ hasCreate
1050
+ debounceMs={0}
1051
+ />,
1052
+ );
1053
+ const input = screen.getByRole('combobox');
1054
+ await act(async () => {
1055
+ fireEvent.change(input, {target: {value: 'new-tag'}});
1056
+ });
1057
+ await act(async () => {
1058
+ await new Promise(r => setTimeout(r, 50));
1059
+ });
1060
+ fireEvent.click(screen.getByText('Create "new-tag"'));
1061
+ await waitFor(() => {
1062
+ expect(politeRegion()).toHaveTextContent('Added new-tag');
1063
+ });
1064
+ });
1065
+
1066
+ it('does not announce on mount', () => {
1067
+ render(
1068
+ <Tokenizer
1069
+ label="Members"
1070
+ searchSource={userSource}
1071
+ value={[users[0]]}
1072
+ onChange={() => {}}
1073
+ />,
1074
+ );
1075
+ // The live regions are created lazily on first announce, so a mount
1076
+ // with pre-selected tokens must not create (or speak through) one.
1077
+ expect(politeRegion()).toBeNull();
1078
+ });
1079
+
1080
+ it('does not announce add/remove while typing', async () => {
1081
+ render(
1082
+ <Tokenizer
1083
+ label="Members"
1084
+ searchSource={userSource}
1085
+ value={[]}
1086
+ onChange={() => {}}
1087
+ debounceMs={0}
1088
+ />,
1089
+ );
1090
+ const input = screen.getByRole('combobox');
1091
+ await act(async () => {
1092
+ fireEvent.change(input, {target: {value: 'Ali'}});
1093
+ });
1094
+ await act(async () => {
1095
+ await new Promise(r => setTimeout(r, 50));
1096
+ });
1097
+ // BaseTypeahead announces result counts while typing (existing
1098
+ // behavior); typing alone must not produce add/remove announcements.
1099
+ expect(politeRegion()?.textContent ?? '').not.toMatch(/Added|Removed/);
1100
+ });
1101
+ });
1102
+
924
1103
  describe('form participation', () => {
925
1104
  it('submits one entry per token id under htmlName', () => {
926
1105
  const {container} = render(
@@ -951,7 +1130,32 @@ describe('Tokenizer', () => {
951
1130
  />
952
1131
  </form>,
953
1132
  );
954
- expect([...new FormData(container.querySelector('form')!).keys()]).toEqual([]);
1133
+ expect([
1134
+ ...new FormData(container.querySelector('form')!).keys(),
1135
+ ]).toEqual([]);
955
1136
  });
956
1137
  });
957
1138
  });
1139
+
1140
+
1141
+ describe('Tokenizer statusVariant forwarding', () => {
1142
+ it('defaults to attached (status renders with data-variant="attached")', () => {
1143
+ const {container} = render(
1144
+ <Tokenizer label="Members" searchSource={userSource} value={[]} onChange={() => {}} status={{type: 'error', message: 'Required'}} />,
1145
+ );
1146
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1147
+ 'data-variant',
1148
+ 'attached',
1149
+ );
1150
+ });
1151
+
1152
+ it('forwards statusVariant="detached" to the underlying Field status', () => {
1153
+ const {container} = render(
1154
+ <Tokenizer label="Members" searchSource={userSource} value={[]} onChange={() => {}} status={{type: 'error', message: 'Required'}} statusVariant="detached" />,
1155
+ );
1156
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1157
+ 'data-variant',
1158
+ 'detached',
1159
+ );
1160
+ });
1161
+ });
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file Tokenizer.tsx
7
- * @input Uses React, BaseTypeahead, Field, Token
7
+ * @input Uses React, BaseTypeahead, Field, Token, useAnnounce
8
8
  * @output Exports Tokenizer multi-select typeahead component
9
9
  * @position Composed component; forwards DOM ref and exposes focus control via
10
10
  * handleRef
@@ -37,12 +37,14 @@ import {
37
37
  inputStatusBorderStyles,
38
38
  inputStatusHoverShadowStyles,
39
39
  inputStatusFocusWithinStyles,
40
+ type FieldStatusVariant,
40
41
  } from '../Field';
41
42
  import {Token} from '../Token';
42
43
  import {renderIconSlot, type IconType} from '../Icon';
43
44
  import {OverflowList} from '../OverflowList';
44
45
  import {useLayer} from '../Layer/useLayer';
45
46
  import {useTooltip} from '../Tooltip';
47
+ import {useAnnounce} from '../hooks/useAnnounce';
46
48
  import {
47
49
  colorVars,
48
50
  spacingVars,
@@ -110,6 +112,13 @@ export interface TokenizerProps<T extends SearchableItem> extends Omit<
110
112
  isOptional?: boolean;
111
113
  /** Validation status. */
112
114
  status?: InputStatus;
115
+ /**
116
+ * How the status message is placed relative to the input.
117
+ * - 'attached': message overlaps directly below the input (bordered treatment)
118
+ * - 'detached': message floats below as a separate element with spacing
119
+ * @default 'attached'
120
+ */
121
+ statusVariant?: FieldStatusVariant;
113
122
  /**
114
123
  * Icon to display at the start of the input.
115
124
  * Accepts a ReactNode (e.g. `<Icon icon={SearchIcon} />`) or an SVG icon component directly.
@@ -369,6 +378,7 @@ export function Tokenizer<T extends SearchableItem>({
369
378
  isRequired = false,
370
379
  isOptional = false,
371
380
  status,
381
+ statusVariant = 'attached',
372
382
  startIcon,
373
383
  labelTooltip,
374
384
  searchSource,
@@ -560,6 +570,12 @@ export function Tokenizer<T extends SearchableItem>({
560
570
  [],
561
571
  );
562
572
 
573
+ // Announce token add/remove politely via the persistent live region.
574
+ // Tokens previously appeared and disappeared silently — Backspace on an
575
+ // empty input removes the trailing token, and the per-token remove buttons
576
+ // gave no audible feedback either.
577
+ const announce = useAnnounce();
578
+
563
579
  // Handle adding an item — detect creatable synthetic items
564
580
  const handleAdd = useCallback(
565
581
  (item: T | null) => {
@@ -584,6 +600,7 @@ export function Tokenizer<T extends SearchableItem>({
584
600
  const realItem = base as T;
585
601
  const newItems = [...value, realItem];
586
602
  onChange(newItems, {item: realItem, type: 'create'});
603
+ announce(`Added ${createdValue}`);
587
604
  return;
588
605
  }
589
606
 
@@ -592,18 +609,22 @@ export function Tokenizer<T extends SearchableItem>({
592
609
  }
593
610
  const newItems = [...value, item];
594
611
  onChange(newItems, {item, type: 'add'});
612
+ announce(`Added ${item.label}`);
595
613
  },
596
- [value, onChange, isAtMax, selectedIds, hasCreate],
614
+ [value, onChange, isAtMax, selectedIds, hasCreate, announce],
597
615
  );
598
616
 
599
- // Handle removing an item
617
+ // Handle removing an item. Single removal path: both Backspace on an empty
618
+ // input and the per-token remove buttons route through here, so the
619
+ // announcement covers both.
600
620
  const handleRemove = useCallback(
601
621
  (item: T) => {
602
622
  const newItems = value.filter(v => v.id !== item.id);
603
623
  onChange(newItems, {item, type: 'remove'});
624
+ announce(`Removed ${item.label}`);
604
625
  inputRef.current?.focus();
605
626
  },
606
- [value, onChange],
627
+ [value, onChange, announce],
607
628
  );
608
629
 
609
630
  // Handle clearing all items
@@ -879,6 +900,7 @@ export function Tokenizer<T extends SearchableItem>({
879
900
  }
880
901
  : undefined
881
902
  }
903
+ statusVariant={statusVariant}
882
904
  labelTooltip={labelTooltip}
883
905
  width={width}
884
906
  xstyle={xstyle}
@@ -10,7 +10,7 @@
10
10
  */
11
11
 
12
12
  import {describe, it, expect, vi} from 'vitest';
13
- import {render, screen} from '@testing-library/react';
13
+ import {fireEvent, render, screen} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
15
  import {TopNav} from './TopNav';
16
16
  import {TopNavRenderContext} from './TopNavRenderContext';
@@ -297,6 +297,85 @@ describe('TopNavHeading', () => {
297
297
  render(<TopNavHeading heading="Test" ref={ref} />);
298
298
  expect(ref).toHaveBeenCalledWith(expect.any(HTMLElement));
299
299
  });
300
+
301
+ // ===========================================================================
302
+ // Menu popover semantics — the popup must not be announced as a modal
303
+ // dialog, and role="menu" must be scoped to the actual menu items so the
304
+ // heading button is not an invalid child of the menu.
305
+ // ===========================================================================
306
+
307
+ // The popover layer keeps `popover` content display:none in jsdom even
308
+ // when open, hiding it from role queries — so these tests assert the
309
+ // popup's ARIA semantics at the DOM level instead.
310
+ describe('menu popover semantics', () => {
311
+ const menuItems = (
312
+ <>
313
+ <div role="menuitem">Alpha</div>
314
+ <div role="menuitem">Beta</div>
315
+ </>
316
+ );
317
+
318
+ it('does not wrap the heading menu popup in a modal dialog', async () => {
319
+ const user = userEvent.setup();
320
+ render(<TopNavHeading heading="My App" menu={menuItems} />);
321
+ await user.click(screen.getByRole('button', {name: 'Open menu'}));
322
+ expect(document.querySelector('[role="dialog"]')).toBeNull();
323
+ expect(document.querySelector('[aria-modal="true"]')).toBeNull();
324
+ });
325
+
326
+ it('scopes role="menu" to only menuitem children with an accessible name', async () => {
327
+ const user = userEvent.setup();
328
+ render(<TopNavHeading heading="My App" menu={menuItems} />);
329
+ await user.click(screen.getByRole('button', {name: 'Open menu'}));
330
+ const menu = document.querySelector('[role="menu"]');
331
+ expect(menu).not.toBeNull();
332
+ expect(menu).toHaveAttribute('aria-label', 'My App');
333
+ const children = Array.from(menu!.children);
334
+ expect(children.length).toBeGreaterThan(0);
335
+ for (const child of children) {
336
+ expect(child).toHaveAttribute('role', 'menuitem');
337
+ }
338
+ });
339
+
340
+ it('keeps the popup heading button outside the menu and closes on click', async () => {
341
+ const user = userEvent.setup();
342
+ render(<TopNavHeading heading="My App" menu={menuItems} />);
343
+ const trigger = screen.getByRole('button', {name: 'Open menu'});
344
+ await user.click(trigger);
345
+ expect(trigger).toHaveAttribute('aria-expanded', 'true');
346
+ const menu = document.querySelector('[role="menu"]');
347
+ expect(menu).not.toBeNull();
348
+ // The heading replica button in the popup is a sibling of the menu,
349
+ // not an invalid menu child.
350
+ const headingButton = Array.from(
351
+ document.querySelectorAll('button'),
352
+ ).find(b => b !== trigger && b.textContent?.includes('My App'));
353
+ expect(headingButton).toBeDefined();
354
+ expect(menu!.contains(headingButton!)).toBe(false);
355
+ // Clicking it still closes the popup.
356
+ fireEvent.click(headingButton!);
357
+ expect(trigger).toHaveAttribute('aria-expanded', 'false');
358
+ });
359
+
360
+ it('applies the same semantics in mixed mode (menu + hrefs)', async () => {
361
+ const user = userEvent.setup();
362
+ render(
363
+ <TopNavHeading
364
+ heading="Product"
365
+ headingHref="/product"
366
+ menu={menuItems}
367
+ />,
368
+ );
369
+ await user.click(screen.getByRole('button', {name: 'Open menu'}));
370
+ expect(document.querySelector('[role="dialog"]')).toBeNull();
371
+ const menu = document.querySelector('[role="menu"]');
372
+ expect(menu).not.toBeNull();
373
+ expect(menu).toHaveAttribute('aria-label', 'Product');
374
+ for (const child of Array.from(menu!.children)) {
375
+ expect(child).toHaveAttribute('role', 'menuitem');
376
+ }
377
+ });
378
+ });
300
379
  });
301
380
 
302
381
  describe('NavIcon', () => {
@@ -444,4 +523,49 @@ describe('TopNavItem', () => {
444
523
  expect(card).toHaveAttribute('aria-label', 'Featured');
445
524
  });
446
525
  });
526
+
527
+ describe('TopNavMegaMenuFeaturedCard image alt handling', () => {
528
+ it('marks the image as explicitly decorative when imageAlt is omitted', () => {
529
+ render(
530
+ <TopNavMegaMenuFeaturedCard
531
+ title="What's new"
532
+ image="/promo.jpg"
533
+ data-testid="featured-card"
534
+ />,
535
+ );
536
+ const img = screen.getByTestId('featured-card').querySelector('img');
537
+ expect(img).toHaveAttribute('alt', '');
538
+ expect(img).toHaveAttribute('role', 'presentation');
539
+ expect(img).toHaveAttribute('aria-hidden', 'true');
540
+ // The image must not be exposed to assistive technology as a nameless img.
541
+ expect(screen.queryByRole('img')).toBeNull();
542
+ });
543
+
544
+ it('exposes the image with normal img semantics when imageAlt is provided', () => {
545
+ render(
546
+ <TopNavMegaMenuFeaturedCard
547
+ title="What's new"
548
+ image="/promo.jpg"
549
+ imageAlt="Team collaboration"
550
+ />,
551
+ );
552
+ const img = screen.getByRole('img', {name: 'Team collaboration'});
553
+ expect(img).not.toHaveAttribute('role');
554
+ expect(img).not.toHaveAttribute('aria-hidden');
555
+ });
556
+
557
+ it('keeps title and link semantics unchanged with a decorative image', () => {
558
+ render(
559
+ <TopNavMegaMenuFeaturedCard
560
+ title="What's new"
561
+ image="/promo.jpg"
562
+ linkLabel="Read the announcement"
563
+ linkHref="/blog/v4"
564
+ />,
565
+ );
566
+ expect(screen.getByText("What's new")).toBeInTheDocument();
567
+ const link = screen.getByRole('link', {name: /Read the announcement/});
568
+ expect(link).toHaveAttribute('href', '/blog/v4');
569
+ });
570
+ });
447
571
  });
@@ -332,6 +332,10 @@ export function TopNavHeading({
332
332
 
333
333
  const popover = usePopover({
334
334
  dialogLabel: t('@astryx.topNav.heading.dialogLabel'),
335
+ // The popup exposes its own role="menu" semantics; a role="dialog"
336
+ // aria-modal wrapper would announce "dialog, Navigation menu" around a
337
+ // menu (the anti-pattern removed in a478a3dcf).
338
+ role: 'none',
335
339
  hasCloseButton: false,
336
340
  });
337
341
 
@@ -511,13 +515,19 @@ export function TopNavHeading({
511
515
  {popover.render(
512
516
  <div
513
517
  ref={menuRef}
514
- role="menu"
515
518
  {...stylex.props(styles.popoverContent)}
516
519
  {...contentProps}>
517
520
  {popoverHeadingContent}
518
- <NavHeadingCloseContext value={closeMenuCtx}>
519
- {menu}
520
- </NavHeadingCloseContext>
521
+ {/* The menu role is scoped to the actual menu items so the
522
+ heading button above stays a valid sibling, not an invalid
523
+ child of a role="menu" element. */}
524
+ <div
525
+ role="menu"
526
+ aria-label={heading ?? t('@astryx.topNav.heading.dialogLabel')}>
527
+ <NavHeadingCloseContext value={closeMenuCtx}>
528
+ {menu}
529
+ </NavHeadingCloseContext>
530
+ </div>
521
531
  </div>,
522
532
  {
523
533
  placement: 'below',
@@ -575,13 +585,19 @@ export function TopNavHeading({
575
585
  {popover.render(
576
586
  <div
577
587
  ref={menuRef}
578
- role="menu"
579
588
  {...stylex.props(styles.popoverContent)}
580
589
  {...contentProps}>
581
590
  {popoverHeadingContent}
582
- <NavHeadingCloseContext value={closeMenuCtx}>
583
- {menu}
584
- </NavHeadingCloseContext>
591
+ {/* The menu role is scoped to the actual menu items so the
592
+ heading button above stays a valid sibling, not an invalid
593
+ child of a role="menu" element. */}
594
+ <div
595
+ role="menu"
596
+ aria-label={heading ?? t('@astryx.topNav.heading.dialogLabel')}>
597
+ <NavHeadingCloseContext value={closeMenuCtx}>
598
+ {menu}
599
+ </NavHeadingCloseContext>
600
+ </div>
585
601
  </div>,
586
602
  {
587
603
  placement: 'below',