@astryxdesign/core 0.1.6 → 0.1.7-canary.0a6de96

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 (521) hide show
  1. package/CHANGELOG.md +68 -0
  2. package/README.md +2 -0
  3. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  4. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  5. package/dist/AlertDialog/AlertDialog.js +4 -1
  6. package/dist/AppShell/AppShell.d.ts.map +1 -1
  7. package/dist/AppShell/AppShell.js +3 -1
  8. package/dist/AvatarGroup/AvatarGroup.d.ts +1 -1
  9. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  10. package/dist/AvatarGroup/AvatarGroup.js +4 -1
  11. package/dist/Banner/Banner.d.ts.map +1 -1
  12. package/dist/Banner/Banner.js +8 -6
  13. package/dist/Breadcrumbs/Breadcrumbs.d.ts +1 -1
  14. package/dist/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
  15. package/dist/Breadcrumbs/Breadcrumbs.js +4 -1
  16. package/dist/Button/Button.d.ts +10 -2
  17. package/dist/Button/Button.d.ts.map +1 -1
  18. package/dist/Button/Button.js +49 -6
  19. package/dist/ButtonGroup/ButtonGroup.d.ts +20 -5
  20. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  21. package/dist/ButtonGroup/ButtonGroup.js +27 -11
  22. package/dist/Calendar/Calendar.d.ts.map +1 -1
  23. package/dist/Calendar/Calendar.js +29 -7
  24. package/dist/Carousel/Carousel.d.ts +1 -1
  25. package/dist/Carousel/Carousel.d.ts.map +1 -1
  26. package/dist/Carousel/Carousel.js +8 -5
  27. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  28. package/dist/Chat/ChatComposer.js +4 -1
  29. package/dist/Chat/ChatComposerDrawer.d.ts +1 -1
  30. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  31. package/dist/Chat/ChatComposerDrawer.js +9 -2
  32. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  33. package/dist/Chat/ChatComposerInput.js +6 -2
  34. package/dist/Chat/ChatLayout.d.ts +1 -11
  35. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  36. package/dist/Chat/ChatLayout.js +6 -4
  37. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  38. package/dist/Chat/ChatLayoutScrollButton.js +4 -2
  39. package/dist/Chat/ChatMessage.d.ts +1 -1
  40. package/dist/Chat/ChatMessage.d.ts.map +1 -1
  41. package/dist/Chat/ChatMessage.js +8 -2
  42. package/dist/Chat/ChatMessageBubble.d.ts +1 -1
  43. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  44. package/dist/Chat/ChatMessageBubble.js +3 -1
  45. package/dist/Chat/ChatMessageList.d.ts +1 -1
  46. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  47. package/dist/Chat/ChatMessageList.js +3 -1
  48. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  49. package/dist/Chat/ChatMessageMetadata.js +13 -8
  50. package/dist/Chat/ChatPastedTextToken.d.ts.map +1 -1
  51. package/dist/Chat/ChatPastedTextToken.js +3 -1
  52. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  53. package/dist/Chat/ChatSendButton.js +3 -1
  54. package/dist/Chat/index.d.ts +1 -1
  55. package/dist/Chat/index.d.ts.map +1 -1
  56. package/dist/Chat/useChatStreamScroll.d.ts +12 -1
  57. package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
  58. package/dist/Chat/useChatStreamScroll.js +43 -6
  59. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  60. package/dist/Chat/useSpeechRecognition.js +4 -2
  61. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  62. package/dist/Chat/useTriggerMenu.js +4 -2
  63. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  64. package/dist/CheckboxInput/CheckboxInput.js +4 -2
  65. package/dist/CheckboxList/CheckboxList.d.ts +1 -1
  66. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  67. package/dist/CheckboxList/CheckboxList.js +3 -1
  68. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  69. package/dist/CheckboxList/CheckboxListItem.js +3 -1
  70. package/dist/Citation/Citation.d.ts.map +1 -1
  71. package/dist/Citation/Citation.js +10 -2
  72. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  73. package/dist/CodeBlock/CodeBlock.js +71 -53
  74. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  75. package/dist/Collapsible/Collapsible.js +8 -1
  76. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  77. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  78. package/dist/CommandPalette/CommandPalette.js +8 -3
  79. package/dist/CommandPalette/CommandPaletteInput.d.ts +1 -1
  80. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  81. package/dist/CommandPalette/CommandPaletteInput.js +4 -1
  82. package/dist/CommandPalette/CommandPaletteList.d.ts +1 -1
  83. package/dist/CommandPalette/CommandPaletteList.d.ts.map +1 -1
  84. package/dist/CommandPalette/CommandPaletteList.js +4 -1
  85. package/dist/ContextMenu/ContextMenu.d.ts +1 -1
  86. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  87. package/dist/ContextMenu/ContextMenu.js +8 -4
  88. package/dist/ContextMenu/index.d.ts +3 -0
  89. package/dist/ContextMenu/index.d.ts.map +1 -1
  90. package/dist/ContextMenu/index.js +7 -1
  91. package/dist/DateInput/DateInput.d.ts +1 -1
  92. package/dist/DateInput/DateInput.d.ts.map +1 -1
  93. package/dist/DateInput/DateInput.js +10 -5
  94. package/dist/DateRangeInput/DateRangeInput.d.ts +1 -1
  95. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  96. package/dist/DateRangeInput/DateRangeInput.js +11 -6
  97. package/dist/DateTimeInput/DateTimeInput.d.ts +1 -1
  98. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  99. package/dist/DateTimeInput/DateTimeInput.js +15 -7
  100. package/dist/Dialog/Dialog.d.ts.map +1 -1
  101. package/dist/Dialog/Dialog.js +15 -12
  102. package/dist/Dialog/DialogHeader.d.ts +1 -1
  103. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  104. package/dist/Dialog/DialogHeader.js +7 -3
  105. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
  106. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  107. package/dist/DropdownMenu/DropdownMenu.js +19 -9
  108. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +89 -0
  109. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -0
  110. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +170 -0
  111. package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -1
  112. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  113. package/dist/DropdownMenu/DropdownMenuContext.js +18 -0
  114. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +69 -0
  115. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -0
  116. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +70 -0
  117. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +69 -0
  118. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -0
  119. package/dist/DropdownMenu/DropdownMenuRadioItem.js +178 -0
  120. package/dist/DropdownMenu/index.d.ts +5 -1
  121. package/dist/DropdownMenu/index.d.ts.map +1 -1
  122. package/dist/DropdownMenu/index.js +10 -1
  123. package/dist/DropdownMenu/menuItemRoles.d.ts +13 -0
  124. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -0
  125. package/dist/DropdownMenu/menuItemRoles.js +15 -0
  126. package/dist/EmptyState/EmptyState.d.ts +4 -1
  127. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  128. package/dist/FileInput/FileInput.d.ts.map +1 -1
  129. package/dist/FileInput/FileInput.js +11 -1
  130. package/dist/Icon/Icon.d.ts +17 -12
  131. package/dist/Icon/Icon.d.ts.map +1 -1
  132. package/dist/Icon/Icon.js +28 -20
  133. package/dist/Kbd/Kbd.js +1 -1
  134. package/dist/Layer/useLayer.d.ts +10 -0
  135. package/dist/Layer/useLayer.d.ts.map +1 -1
  136. package/dist/Layer/useLayer.js +23 -1
  137. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  138. package/dist/Lightbox/Lightbox.js +6 -4
  139. package/dist/Link/Link.d.ts +5 -1
  140. package/dist/Link/Link.d.ts.map +1 -1
  141. package/dist/Link/Link.js +32 -1
  142. package/dist/Markdown/Markdown.d.ts.map +1 -1
  143. package/dist/Markdown/Markdown.js +10 -8
  144. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  145. package/dist/MobileNav/MobileNav.js +4 -2
  146. package/dist/MobileNav/MobileNavToggle.d.ts +1 -1
  147. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  148. package/dist/MobileNav/MobileNavToggle.js +4 -1
  149. package/dist/MoreMenu/MoreMenu.d.ts +1 -1
  150. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  151. package/dist/MoreMenu/MoreMenu.js +4 -1
  152. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  153. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  154. package/dist/MultiSelector/MultiSelector.js +13 -6
  155. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  156. package/dist/NumberInput/NumberInput.js +5 -1
  157. package/dist/Outline/Outline.d.ts +1 -1
  158. package/dist/Outline/Outline.d.ts.map +1 -1
  159. package/dist/Outline/Outline.js +4 -1
  160. package/dist/Pagination/Pagination.d.ts +1 -1
  161. package/dist/Pagination/Pagination.d.ts.map +1 -1
  162. package/dist/Pagination/Pagination.js +38 -11
  163. package/dist/Popover/usePopover.d.ts.map +1 -1
  164. package/dist/Popover/usePopover.js +4 -1
  165. package/dist/PowerSearch/PowerSearch.d.ts +1 -1
  166. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  167. package/dist/PowerSearch/PowerSearch.js +22 -12
  168. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +1 -1
  169. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  170. package/dist/PowerSearch/PowerSearchEditPopover.js +26 -20
  171. package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
  172. package/dist/PowerSearch/PowerSearchToken.js +7 -3
  173. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  174. package/dist/PowerSearch/PowerSearchValueEditor.js +34 -21
  175. package/dist/PowerSearch/formatFilterValue.d.ts +2 -1
  176. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  177. package/dist/PowerSearch/formatFilterValue.js +19 -9
  178. package/dist/PowerSearch/index.d.ts +2 -1
  179. package/dist/PowerSearch/index.d.ts.map +1 -1
  180. package/dist/PowerSearch/index.js +1 -0
  181. package/dist/PowerSearch/resolveOperatorLabel.d.ts +23 -0
  182. package/dist/PowerSearch/resolveOperatorLabel.d.ts.map +1 -0
  183. package/dist/PowerSearch/resolveOperatorLabel.js +28 -0
  184. package/dist/PowerSearch/types.d.ts +28 -2
  185. package/dist/PowerSearch/types.d.ts.map +1 -1
  186. package/dist/PowerSearch/usePowerSearchConfig.d.ts.map +1 -1
  187. package/dist/PowerSearch/usePowerSearchConfig.js +27 -27
  188. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  189. package/dist/PowerSearch/usePowerSearchSource.js +15 -8
  190. package/dist/Resizable/ResizeHandle.d.ts +1 -1
  191. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  192. package/dist/Resizable/ResizeHandle.js +4 -1
  193. package/dist/Selector/Selector.d.ts.map +1 -1
  194. package/dist/Selector/Selector.js +52 -14
  195. package/dist/SideNav/SideNav.d.ts.map +1 -1
  196. package/dist/SideNav/SideNav.js +4 -2
  197. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  198. package/dist/SideNav/SideNavCollapseButton.js +3 -1
  199. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  200. package/dist/SideNav/SideNavHeading.js +5 -3
  201. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  202. package/dist/SideNav/SideNavItem.js +7 -1
  203. package/dist/Switch/Switch.d.ts.map +1 -1
  204. package/dist/Switch/Switch.js +4 -2
  205. package/dist/TabList/TabList.d.ts +1 -1
  206. package/dist/TabList/TabList.d.ts.map +1 -1
  207. package/dist/TabList/TabList.js +4 -1
  208. package/dist/Table/BaseTable.d.ts.map +1 -1
  209. package/dist/Table/BaseTable.js +29 -16
  210. package/dist/Table/Table.d.ts.map +1 -1
  211. package/dist/Table/Table.js +5 -3
  212. package/dist/Table/plugins/columnResize/useTableColumnResize.js +1 -1
  213. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  214. package/dist/Table/plugins/filtering/useTableFiltering.js +56 -19
  215. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
  216. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  217. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +12 -5
  218. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  219. package/dist/Table/plugins/pagination/useTablePagination.js +6 -3
  220. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  221. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +8 -6
  222. package/dist/Table/plugins/rowIndex/useTableRowIndex.d.ts +1 -1
  223. package/dist/Table/plugins/rowIndex/useTableRowIndex.js +1 -1
  224. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  225. package/dist/Table/plugins/selection/useTableSelection.js +5 -2
  226. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  227. package/dist/Table/plugins/sortable/useTableSortable.js +6 -4
  228. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +2 -2
  229. package/dist/Table/types.d.ts +17 -10
  230. package/dist/Table/types.d.ts.map +1 -1
  231. package/dist/TextInput/TextInput.d.ts.map +1 -1
  232. package/dist/TextInput/TextInput.js +5 -1
  233. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  234. package/dist/Thumbnail/Thumbnail.js +8 -2
  235. package/dist/TimeInput/TimeInput.d.ts +1 -1
  236. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  237. package/dist/TimeInput/TimeInput.js +7 -2
  238. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  239. package/dist/Timestamp/Timestamp.js +18 -3
  240. package/dist/Toast/Toast.d.ts.map +1 -1
  241. package/dist/Toast/Toast.js +3 -1
  242. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  243. package/dist/Toast/ToastViewport.js +3 -1
  244. package/dist/Token/Token.d.ts.map +1 -1
  245. package/dist/Token/Token.js +8 -2
  246. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  247. package/dist/Tokenizer/Tokenizer.js +3 -1
  248. package/dist/TopNav/TopNav.d.ts +2 -1
  249. package/dist/TopNav/TopNav.d.ts.map +1 -1
  250. package/dist/TopNav/TopNav.js +4 -1
  251. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  252. package/dist/TopNav/TopNavHeading.js +5 -3
  253. package/dist/TreeList/TreeList.d.ts.map +1 -1
  254. package/dist/TreeList/TreeList.js +5 -1
  255. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  256. package/dist/TreeList/TreeListItem.js +7 -1
  257. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  258. package/dist/Typeahead/BaseTypeahead.js +8 -4
  259. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  260. package/dist/Typeahead/Typeahead.js +3 -1
  261. package/dist/VisuallyHidden/VisuallyHidden.d.ts +1 -0
  262. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -1
  263. package/dist/VisuallyHidden/VisuallyHidden.js +1 -0
  264. package/dist/astryx.css +35 -3
  265. package/dist/astryx.umd.js +62 -60
  266. package/dist/astryx.umd.js.map +4 -4
  267. package/dist/authoring/doc.d.ts +145 -0
  268. package/dist/authoring/doc.d.ts.map +1 -0
  269. package/dist/authoring/doc.js +100 -0
  270. package/dist/authoring/index.d.ts +29 -0
  271. package/dist/authoring/index.d.ts.map +1 -0
  272. package/dist/authoring/index.js +28 -0
  273. package/dist/authoring/integration.d.ts +35 -0
  274. package/dist/authoring/integration.d.ts.map +1 -0
  275. package/dist/authoring/integration.js +30 -0
  276. package/dist/authoring/template.d.ts +66 -0
  277. package/dist/authoring/template.d.ts.map +1 -0
  278. package/dist/authoring/template.js +55 -0
  279. package/dist/config.d.ts +80 -0
  280. package/dist/config.d.ts.map +1 -0
  281. package/dist/config.js +40 -0
  282. package/dist/docs-types.d.ts +13 -4
  283. package/dist/docs-types.d.ts.map +1 -1
  284. package/dist/i18n/InternationalizationContext.d.ts +12 -0
  285. package/dist/i18n/InternationalizationContext.d.ts.map +1 -0
  286. package/dist/i18n/InternationalizationContext.js +29 -0
  287. package/dist/i18n/InternationalizationProvider.d.ts +61 -0
  288. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -0
  289. package/dist/i18n/InternationalizationProvider.js +44 -0
  290. package/dist/i18n/index.d.ts +24 -0
  291. package/dist/i18n/index.d.ts.map +1 -0
  292. package/dist/i18n/index.js +21 -0
  293. package/dist/i18n/resolve.d.ts +22 -0
  294. package/dist/i18n/resolve.d.ts.map +1 -0
  295. package/dist/i18n/resolve.js +141 -0
  296. package/dist/i18n/translator.d.ts +25 -0
  297. package/dist/i18n/translator.d.ts.map +1 -0
  298. package/dist/i18n/translator.js +1 -0
  299. package/dist/i18n/types.d.ts +47 -0
  300. package/dist/i18n/types.d.ts.map +1 -0
  301. package/dist/i18n/types.js +1 -0
  302. package/dist/i18n/useTranslator.d.ts +15 -0
  303. package/dist/i18n/useTranslator.d.ts.map +1 -0
  304. package/dist/i18n/useTranslator.js +39 -0
  305. package/dist/index.d.ts +1 -0
  306. package/dist/index.d.ts.map +1 -1
  307. package/dist/index.js +3 -0
  308. package/dist/theme/hct.d.ts +0 -1
  309. package/dist/theme/hct.d.ts.map +1 -1
  310. package/dist/theme/hct.js +0 -3
  311. package/dist/utils/color.d.ts +13 -1
  312. package/dist/utils/color.d.ts.map +1 -1
  313. package/dist/utils/color.js +23 -1
  314. package/dist/utils/index.d.ts +1 -1
  315. package/dist/utils/index.d.ts.map +1 -1
  316. package/dist/utils/index.js +1 -1
  317. package/locales/en.json +746 -0
  318. package/locales/pseudo.json +560 -0
  319. package/package.json +23 -2
  320. package/src/AlertDialog/AlertDialog.doc.mjs +5 -0
  321. package/src/AlertDialog/AlertDialog.tsx +4 -1
  322. package/src/AppShell/AppShell.doc.mjs +8 -2
  323. package/src/AppShell/AppShell.tsx +3 -1
  324. package/src/AvatarGroup/AvatarGroup.tsx +4 -1
  325. package/src/Banner/Banner.tsx +10 -5
  326. package/src/Breadcrumbs/Breadcrumbs.tsx +4 -1
  327. package/src/Button/Button.doc.mjs +8 -0
  328. package/src/Button/Button.test.tsx +27 -0
  329. package/src/Button/Button.tsx +51 -5
  330. package/src/ButtonGroup/ButtonGroup.test.tsx +386 -2
  331. package/src/ButtonGroup/ButtonGroup.tsx +27 -11
  332. package/src/Calendar/Calendar.test.tsx +103 -2
  333. package/src/Calendar/Calendar.tsx +29 -6
  334. package/src/Card/Card.doc.mjs +3 -3
  335. package/src/Carousel/Carousel.tsx +10 -7
  336. package/src/Chat/ChatComposer.tsx +5 -1
  337. package/src/Chat/ChatComposerDrawer.tsx +9 -2
  338. package/src/Chat/ChatComposerInput.tsx +10 -4
  339. package/src/Chat/ChatLayout.test.tsx +127 -2
  340. package/src/Chat/ChatLayout.tsx +5 -12
  341. package/src/Chat/ChatLayoutScrollButton.tsx +4 -2
  342. package/src/Chat/ChatMessage.tsx +5 -1
  343. package/src/Chat/ChatMessageBubble.tsx +2 -0
  344. package/src/Chat/ChatMessageList.doc.mjs +1 -1
  345. package/src/Chat/ChatMessageList.tsx +2 -0
  346. package/src/Chat/ChatMessageMetadata.tsx +15 -9
  347. package/src/Chat/ChatPastedTextToken.tsx +3 -1
  348. package/src/Chat/ChatSendButton.tsx +3 -1
  349. package/src/Chat/ChatToolCalls.doc.mjs +1 -1
  350. package/src/Chat/index.ts +1 -0
  351. package/src/Chat/useChatStreamScroll.test.tsx +168 -0
  352. package/src/Chat/useChatStreamScroll.ts +67 -11
  353. package/src/Chat/useSpeechRecognition.ts +11 -2
  354. package/src/Chat/useTriggerMenu.tsx +4 -2
  355. package/src/CheckboxInput/CheckboxInput.test.tsx +16 -0
  356. package/src/CheckboxInput/CheckboxInput.tsx +4 -2
  357. package/src/CheckboxList/CheckboxList.doc.mjs +6 -1
  358. package/src/CheckboxList/CheckboxList.tsx +2 -0
  359. package/src/CheckboxList/CheckboxListItem.tsx +7 -1
  360. package/src/Citation/Citation.tsx +4 -2
  361. package/src/ClickableCard/ClickableCard.doc.mjs +1 -1
  362. package/src/CodeBlock/CodeBlock.tsx +91 -40
  363. package/src/Collapsible/Collapsible.doc.mjs +1 -0
  364. package/src/Collapsible/Collapsible.test.tsx +6 -0
  365. package/src/Collapsible/Collapsible.tsx +19 -4
  366. package/src/CommandPalette/CommandPalette.tsx +10 -3
  367. package/src/CommandPalette/CommandPaletteInput.test.tsx +1 -1
  368. package/src/CommandPalette/CommandPaletteInput.tsx +5 -1
  369. package/src/CommandPalette/CommandPaletteList.tsx +4 -1
  370. package/src/ContextMenu/ContextMenu.test.tsx +75 -1
  371. package/src/ContextMenu/ContextMenu.tsx +14 -6
  372. package/src/ContextMenu/index.ts +15 -0
  373. package/src/DateInput/DateInput.doc.mjs +2 -2
  374. package/src/DateInput/DateInput.test.tsx +17 -5
  375. package/src/DateInput/DateInput.tsx +13 -5
  376. package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
  377. package/src/DateRangeInput/DateRangeInput.tsx +14 -6
  378. package/src/DateTimeInput/DateTimeInput.doc.mjs +2 -2
  379. package/src/DateTimeInput/DateTimeInput.tsx +17 -7
  380. package/src/Dialog/Dialog.tsx +11 -15
  381. package/src/Dialog/DialogHeader.tsx +7 -3
  382. package/src/DropdownMenu/DropdownMenu.doc.mjs +23 -0
  383. package/src/DropdownMenu/DropdownMenu.tsx +23 -14
  384. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +95 -0
  385. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +237 -0
  386. package/src/DropdownMenu/DropdownMenuContext.tsx +29 -1
  387. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +6 -0
  388. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +80 -0
  389. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +119 -0
  390. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +80 -0
  391. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +232 -0
  392. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +163 -0
  393. package/src/DropdownMenu/index.ts +23 -3
  394. package/src/DropdownMenu/menuItemRoles.ts +22 -0
  395. package/src/EmptyState/EmptyState.doc.mjs +3 -3
  396. package/src/EmptyState/EmptyState.tsx +4 -1
  397. package/src/Field/Field.doc.mjs +2 -2
  398. package/src/FileInput/FileInput.test.tsx +40 -1
  399. package/src/FileInput/FileInput.tsx +12 -1
  400. package/src/Grid/Grid.doc.mjs +5 -5
  401. package/src/Icon/Icon.test.tsx +46 -0
  402. package/src/Icon/Icon.tsx +37 -24
  403. package/src/InputGroup/InputGroup.doc.mjs +1 -1
  404. package/src/Kbd/Kbd.test.tsx +26 -0
  405. package/src/Kbd/Kbd.tsx +1 -1
  406. package/src/Layer/useLayer.doc.mjs +8 -5
  407. package/src/Layer/useLayer.test.tsx +136 -1
  408. package/src/Layer/useLayer.tsx +34 -2
  409. package/src/Lightbox/Lightbox.doc.mjs +7 -2
  410. package/src/Lightbox/Lightbox.tsx +6 -4
  411. package/src/Link/Link.test.tsx +74 -2
  412. package/src/Link/Link.tsx +48 -1
  413. package/src/Markdown/Markdown.tsx +12 -4
  414. package/src/MobileNav/MobileNav.tsx +4 -2
  415. package/src/MobileNav/MobileNavToggle.tsx +5 -3
  416. package/src/MoreMenu/MoreMenu.tsx +4 -1
  417. package/src/MultiSelector/MultiSelector.tsx +14 -5
  418. package/src/NumberInput/NumberInput.tsx +3 -1
  419. package/src/Outline/Outline.tsx +4 -1
  420. package/src/OverflowList/OverflowList.doc.mjs +2 -2
  421. package/src/Pagination/Pagination.tsx +35 -12
  422. package/src/Popover/usePopover.tsx +6 -1
  423. package/src/PowerSearch/PowerSearch.doc.mjs +9 -4
  424. package/src/PowerSearch/PowerSearch.tsx +22 -10
  425. package/src/PowerSearch/PowerSearchEditPopover.tsx +27 -20
  426. package/src/PowerSearch/PowerSearchToken.tsx +17 -6
  427. package/src/PowerSearch/PowerSearchValueEditor.tsx +34 -21
  428. package/src/PowerSearch/formatFilterValue.test.ts +282 -0
  429. package/src/PowerSearch/formatFilterValue.ts +21 -8
  430. package/src/PowerSearch/index.ts +5 -0
  431. package/src/PowerSearch/resolveOperatorLabel.ts +34 -0
  432. package/src/PowerSearch/types.ts +33 -9
  433. package/src/PowerSearch/usePowerSearchConfig.ts +59 -27
  434. package/src/PowerSearch/usePowerSearchSource.ts +17 -8
  435. package/src/RadioList/RadioList.doc.mjs +1 -1
  436. package/src/Resizable/ResizeHandle.tsx +4 -1
  437. package/src/Section/Section.doc.mjs +4 -4
  438. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  439. package/src/Selector/Selector.doc.mjs +6 -3
  440. package/src/Selector/Selector.test.tsx +114 -6
  441. package/src/Selector/Selector.tsx +68 -17
  442. package/src/SideNav/SideNav.tsx +4 -2
  443. package/src/SideNav/SideNavCollapseButton.tsx +3 -1
  444. package/src/SideNav/SideNavHeading.tsx +5 -3
  445. package/src/SideNav/SideNavItem.tsx +3 -1
  446. package/src/Slider/Slider.doc.mjs +2 -2
  447. package/src/Stack/Stack.doc.mjs +10 -10
  448. package/src/Switch/Switch.doc.mjs +2 -2
  449. package/src/Switch/Switch.test.tsx +16 -0
  450. package/src/Switch/Switch.tsx +4 -2
  451. package/src/TabList/TabList.tsx +4 -1
  452. package/src/Table/BaseTable.tsx +36 -19
  453. package/src/Table/Table.test.tsx +132 -1
  454. package/src/Table/Table.tsx +6 -4
  455. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +1 -1
  456. package/src/Table/plugins/filtering/useTableFiltering.tsx +31 -30
  457. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +7 -5
  458. package/src/Table/plugins/pagination/useTablePagination.tsx +4 -1
  459. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +9 -8
  460. package/src/Table/plugins/rowIndex/useTableRowIndex.tsx +1 -1
  461. package/src/Table/plugins/selection/useTableSelection.tsx +6 -7
  462. package/src/Table/plugins/sortable/useTableSortable.tsx +8 -5
  463. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +4 -4
  464. package/src/Table/types.ts +18 -12
  465. package/src/Table/useTableFiltering.doc.mjs +2 -2
  466. package/src/Table/useTableGroupedRows.doc.mjs +3 -3
  467. package/src/Table/useTableSortable.doc.mjs +11 -11
  468. package/src/Text/Text.doc.mjs +2 -2
  469. package/src/TextInput/TextInput.tsx +3 -1
  470. package/src/Thumbnail/Thumbnail.tsx +4 -2
  471. package/src/TimeInput/TimeInput.doc.mjs +2 -2
  472. package/src/TimeInput/TimeInput.tsx +6 -2
  473. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  474. package/src/Timestamp/Timestamp.test.tsx +120 -7
  475. package/src/Timestamp/Timestamp.tsx +21 -1
  476. package/src/Toast/Toast.tsx +3 -1
  477. package/src/Toast/ToastViewport.tsx +3 -1
  478. package/src/Token/Token.tsx +4 -2
  479. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  480. package/src/Tokenizer/Tokenizer.tsx +4 -4
  481. package/src/Toolbar/Toolbar.doc.mjs +1 -1
  482. package/src/TopNav/TopNav.doc.mjs +1 -0
  483. package/src/TopNav/TopNav.test.tsx +30 -0
  484. package/src/TopNav/TopNav.tsx +6 -4
  485. package/src/TopNav/TopNavHeading.tsx +5 -3
  486. package/src/TreeList/TreeList.tsx +5 -1
  487. package/src/TreeList/TreeListItem.tsx +6 -1
  488. package/src/Typeahead/BaseTypeahead.tsx +11 -4
  489. package/src/Typeahead/Typeahead.doc.mjs +1 -1
  490. package/src/Typeahead/Typeahead.tsx +3 -1
  491. package/src/VisuallyHidden/VisuallyHidden.tsx +1 -0
  492. package/src/authoring/doc.ts +166 -0
  493. package/src/authoring/index.test.ts +52 -0
  494. package/src/authoring/index.ts +50 -0
  495. package/src/authoring/integration.ts +42 -0
  496. package/src/authoring/template.ts +74 -0
  497. package/src/config.test.ts +16 -0
  498. package/src/config.ts +92 -0
  499. package/src/docPropLiterals.test.ts +938 -0
  500. package/src/docs-types.ts +15 -10
  501. package/src/i18n/InternationalizationContext.ts +39 -0
  502. package/src/i18n/InternationalizationProvider.doc.mjs +72 -0
  503. package/src/i18n/InternationalizationProvider.tsx +82 -0
  504. package/src/i18n/__tests__/e2e-pagination.test.tsx +172 -0
  505. package/src/i18n/__tests__/e2e-powersearch.test.tsx +130 -0
  506. package/src/i18n/__tests__/resolve.test.ts +284 -0
  507. package/src/i18n/index.ts +32 -0
  508. package/src/i18n/resolve.ts +165 -0
  509. package/src/i18n/translator.ts +31 -0
  510. package/src/i18n/types.ts +53 -0
  511. package/src/i18n/useTranslator.doc.mjs +46 -0
  512. package/src/i18n/useTranslator.ts +50 -0
  513. package/src/index.ts +3 -0
  514. package/src/theme/hct.ts +0 -4
  515. package/src/utils/color.test.ts +101 -1
  516. package/src/utils/color.ts +23 -1
  517. package/src/utils/index.ts +8 -1
  518. package/dist/NavItem/index.d.ts +0 -9
  519. package/dist/NavItem/index.d.ts.map +0 -1
  520. package/dist/NavItem/index.js +0 -10
  521. package/src/NavItem/index.ts +0 -11
@@ -14,14 +14,22 @@
14
14
 
15
15
  import {useMemo} from 'react';
16
16
  import type {SearchSource} from '../Typeahead/types';
17
+ import {useTranslator} from '../i18n';
18
+ import {resolveOperatorLabel} from './resolveOperatorLabel';
17
19
  import type {InternalConfig} from './useInternalConfig';
18
20
  import type {PowerSearchItem, PowerSearchOperator, FilterValue} from './types';
19
21
 
20
22
  export function usePowerSearchSource(
21
23
  config: InternalConfig,
22
24
  ): SearchSource<PowerSearchItem> {
25
+ const t = useTranslator();
23
26
  return useMemo(() => {
24
27
  const allItems = buildFieldItems(config);
28
+ // Resolver stays inline — `t()` internally memoizes both catalog
29
+ // lookups and parsed IntlMessageFormat instances, so calling it
30
+ // per keystroke is already O(1).
31
+ const opLabel = (op: PowerSearchOperator): string =>
32
+ resolveOperatorLabel(op, t);
25
33
 
26
34
  return {
27
35
  search(query: string): PowerSearchItem[] {
@@ -68,14 +76,15 @@ export function usePowerSearchSource(
68
76
 
69
77
  // Check each field+operator combo against the query
70
78
  for (const op of field.operators) {
71
- const combinedLabel = `${field.label} ${op.label}`.toLowerCase();
79
+ const combinedLabel =
80
+ `${field.label} ${opLabel(op)}`.toLowerCase();
72
81
  if (combinedLabel.includes(lower)) {
73
82
  const id = `${field.key}:${op.key}`;
74
83
  if (!seen.has(id)) {
75
84
  seen.add(id);
76
85
  results.push({
77
86
  id,
78
- label: `${field.label} ${op.label}`,
87
+ label: `${field.label} ${opLabel(op)}`,
79
88
  auxiliaryData: {
80
89
  fieldKey: field.key,
81
90
  operatorKey: op.key,
@@ -100,7 +109,7 @@ export function usePowerSearchSource(
100
109
  // Try "<field> <operator> <value>" first (longer match wins)
101
110
  let hasExactOperatorMatch = false;
102
111
  for (const op of field.operators) {
103
- const prefix = `${fieldLabel} ${op.label.toLowerCase()} `;
112
+ const prefix = `${fieldLabel} ${opLabel(op).toLowerCase()} `;
104
113
  if (lower.startsWith(prefix) && lower.length > prefix.length) {
105
114
  const rawValue = query.slice(prefix.length);
106
115
  const matches = resolveValueMatches(op, rawValue);
@@ -113,7 +122,7 @@ export function usePowerSearchSource(
113
122
  seen.add(id);
114
123
  results.push({
115
124
  id,
116
- label: `${field.label} ${op.label} ${match.quoted ? `"${match.displayValue}"` : match.displayValue}`,
125
+ label: `${field.label} ${opLabel(op)} ${match.quoted ? `"${match.displayValue}"` : match.displayValue}`,
117
126
  auxiliaryData: {
118
127
  fieldKey: field.key,
119
128
  operatorKey: op.key,
@@ -136,7 +145,7 @@ export function usePowerSearchSource(
136
145
  // Check the remainder isn't the start of an operator name
137
146
  const remainder = lower.slice(fieldPrefix.length);
138
147
  const isOperatorPrefix = field.operators.some(op =>
139
- op.label.toLowerCase().startsWith(remainder),
148
+ opLabel(op).toLowerCase().startsWith(remainder),
140
149
  );
141
150
  if (!isOperatorPrefix) {
142
151
  const rawValue = query.slice(fieldPrefix.length);
@@ -148,7 +157,7 @@ export function usePowerSearchSource(
148
157
  seen.add(id);
149
158
  results.push({
150
159
  id,
151
- label: `${field.label} ${op.label} ${match.quoted ? `"${match.displayValue}"` : match.displayValue}`,
160
+ label: `${field.label} ${opLabel(op)} ${match.quoted ? `"${match.displayValue}"` : match.displayValue}`,
152
161
  auxiliaryData: {
153
162
  fieldKey: field.key,
154
163
  operatorKey: op.key,
@@ -171,7 +180,7 @@ export function usePowerSearchSource(
171
180
  f =>
172
181
  f.label.toLowerCase() === lower ||
173
182
  f.operators.some(
174
- op => `${f.label} ${op.label}`.toLowerCase() === lower,
183
+ op => `${f.label} ${opLabel(op)}`.toLowerCase() === lower,
175
184
  ),
176
185
  );
177
186
  if (contentFieldKey && !hasExactMatch) {
@@ -197,7 +206,7 @@ export function usePowerSearchSource(
197
206
  return allItems;
198
207
  },
199
208
  };
200
- }, [config]);
209
+ }, [config, t]);
201
210
  }
202
211
 
203
212
  interface ValueMatch {
@@ -100,7 +100,7 @@ export const docs = {
100
100
  },
101
101
  {
102
102
  name: 'status',
103
- type: 'InputStatus',
103
+ type: "{type: 'warning' | 'error' | 'success', message?: string}",
104
104
  description: 'Status indicator ({ type, message }).',
105
105
  },
106
106
  {
@@ -33,6 +33,7 @@ import {
33
33
  import {mergeProps, mergeRefs} from '../utils';
34
34
  import type {ResizableProps} from './useResizable';
35
35
  import {themeProps} from '../utils/themeProps';
36
+ import {useTranslator} from '../i18n';
36
37
 
37
38
  const KEYBOARD_STEP = 10;
38
39
  const KEYBOARD_LARGE_STEP = 50;
@@ -307,7 +308,7 @@ export function ResizeHandle({
307
308
  hasDivider = false,
308
309
  isAlwaysVisible = true,
309
310
  pillPlacement = 'auto',
310
- label = 'Resize handle',
311
+ label: labelFromProps,
311
312
  resizable,
312
313
  children,
313
314
  xstyle,
@@ -315,6 +316,8 @@ export function ResizeHandle({
315
316
  ref,
316
317
  ...props
317
318
  }: ResizeHandleProps) {
319
+ const t = useTranslator();
320
+ const label = labelFromProps ?? t('@astryx.resizable.handle.label');
318
321
  const handleRef = useRef<HTMLDivElement>(null);
319
322
  // Removes the in-flight drag's window listeners (and resets body styles).
320
323
  // Held in a ref so unmount can tear down a drag that never got a pointerup.
@@ -49,13 +49,13 @@ export const docs = {
49
49
  },
50
50
  {
51
51
  name: 'padding',
52
- type: 'SpacingStep',
52
+ type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
53
53
  description: 'Internal padding using the spacing scale (0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10). Use padding={0} for edge-to-edge content.',
54
54
  default: '4',
55
55
  },
56
56
  {
57
57
  name: 'paddingBlock',
58
- type: 'SpacingStep',
58
+ type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
59
59
  description: 'Block (vertical) padding override. Overrides only the block-axis padding while preserving inline padding from `padding` or the container theme default. Accepts the spacing scale (0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10).',
60
60
  },
61
61
  {
@@ -131,13 +131,13 @@ export const docsZh = {
131
131
  },
132
132
  {
133
133
  name: 'padding',
134
- type: 'SpacingStep',
134
+ type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
135
135
  description: '使用间距比例的内部内边距(0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10)。使用 padding={0} 实现全宽内容。',
136
136
  default: '4',
137
137
  },
138
138
  {
139
139
  name: 'paddingBlock',
140
- type: 'SpacingStep',
140
+ type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
141
141
  description: '块(垂直)方向内边距覆盖。仅覆盖块轴内边距,同时保留来自 padding 或容器主题默认值的行内内边距。使用间距比例(0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10)。',
142
142
  },
143
143
  {
@@ -25,7 +25,7 @@ export const docs = {
25
25
  {name: 'onChange', type: '(isSelected: boolean) => void', description: 'Called when toggled.', required: true},
26
26
  {name: 'isDisabled', type: 'boolean', description: 'Disables the card.', default: 'false'},
27
27
  {name: 'children', type: 'ReactNode', description: 'Card content.'},
28
- {name: 'padding', type: "SpacingStep", description: 'Inner padding.', default: '4'},
28
+ {name: 'padding', type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10', description: 'Inner padding.', default: '4'},
29
29
  {name: 'variant', type: "'default' | 'transparent' | 'muted' | 'blue' | 'cyan' | 'gray' | 'green' | 'orange' | 'pink' | 'purple' | 'red' | 'teal' | 'yellow'", description: 'Background color variant.', default: "'default'"},
30
30
  {name: 'width', type: 'SizeValue', description: 'Card width.'},
31
31
  {name: 'height', type: 'SizeValue', description: 'Card height.'},
@@ -36,7 +36,8 @@ export const docs = {
36
36
  {
37
37
  name: 'options',
38
38
  type: 'SelectorOption[]',
39
- description: 'Array of items: strings, objects with value/label/icon/disabled, dividers ({type: "divider"}), or sections ({type: "section", title, items}).',
39
+ description:
40
+ 'Array of items: strings, objects with value/label/icon/disabled, dividers ({type: "divider"}), or sections ({type: "section", title, items}).',
40
41
  required: true,
41
42
  },
42
43
  {
@@ -59,7 +60,8 @@ export const docs = {
59
60
  {
60
61
  name: 'hasSearch',
61
62
  type: 'boolean',
62
- description: 'Whether to show a search input for filtering options.',
63
+ description:
64
+ 'Whether to show a search input for filtering options. As the user types, the match count (or "No results found") is announced to screen readers via a polite live region.',
63
65
  default: 'false',
64
66
  },
65
67
  {
@@ -135,7 +137,8 @@ export const docs = {
135
137
  {
136
138
  name: 'xstyle',
137
139
  type: 'StyleXStyles',
138
- description: 'StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}.',
140
+ description:
141
+ 'StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}.',
139
142
  },
140
143
  ],
141
144
  components: [{name: 'SelectorOption'}],
@@ -9,12 +9,23 @@
9
9
  * SYNC: When Selector.tsx API changes, update these tests.
10
10
  */
11
11
 
12
- import {describe, it, expect, vi, beforeEach} from 'vitest';
13
- import {render, screen, fireEvent, waitFor} from '@testing-library/react';
12
+ import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
13
+ import {
14
+ render,
15
+ screen,
16
+ fireEvent,
17
+ waitFor,
18
+ within,
19
+ } from '@testing-library/react';
14
20
  import userEvent from '@testing-library/user-event';
15
21
  import {Selector} from './Selector';
16
22
  import {SelectorOption} from './SelectorOption';
17
23
  import {InputGroup, InputGroupText} from '../InputGroup';
24
+ import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
25
+
26
+ function politeRegion(): HTMLElement | null {
27
+ return document.querySelector('[data-astryx-live-region="polite"]');
28
+ }
18
29
 
19
30
  // Mock showPopover and hidePopover methods since they're not implemented in jsdom
20
31
  beforeEach(() => {
@@ -42,6 +53,10 @@ beforeEach(() => {
42
53
  };
43
54
  });
44
55
 
56
+ afterEach(() => {
57
+ __resetLiveRegionsForTest();
58
+ });
59
+
45
60
  // Helper: jsdom popover content is in the DOM but may not be
46
61
  // "visible" in the accessibility tree. Use hidden: true to find it.
47
62
  const h = {hidden: true} as const;
@@ -536,7 +551,11 @@ describe('Selector', () => {
536
551
  await user.click(screen.getByRole('button', {name: 'Fruit'}));
537
552
  await user.type(screen.getByRole('combobox', h), 'xyz');
538
553
  expect(screen.queryAllByRole('option', h)).toHaveLength(0);
539
- expect(screen.getByText('No results found')).toBeInTheDocument();
554
+ // Scope to the listbox: the polite live region also announces "No results
555
+ // found", so an unscoped query matches both the visible empty state and
556
+ // the a11y announcement.
557
+ const listbox = screen.getByRole('listbox', h);
558
+ expect(within(listbox).getByText('No results found')).toBeInTheDocument();
540
559
  });
541
560
 
542
561
  it('calls onChange when selecting a filtered option', async () => {
@@ -599,6 +618,82 @@ describe('Selector', () => {
599
618
  screen.getByPlaceholderText('Find a fruit...'),
600
619
  ).toBeInTheDocument();
601
620
  });
621
+
622
+ describe('result announcements', () => {
623
+ it('announces the match count politely while searching', async () => {
624
+ const user = userEvent.setup();
625
+ render(
626
+ <Selector
627
+ label="Fruit"
628
+ options={OPTIONS}
629
+ value="Apple"
630
+ onChange={() => {}}
631
+ hasSearch
632
+ />,
633
+ );
634
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
635
+ // "a" matches Apple and Banana.
636
+ await user.type(screen.getByRole('combobox', h), 'a');
637
+ await waitFor(() => {
638
+ expect(politeRegion()).toHaveTextContent('2 results');
639
+ });
640
+ });
641
+
642
+ it('announces the singular form when one option matches', async () => {
643
+ const user = userEvent.setup();
644
+ render(
645
+ <Selector
646
+ label="Fruit"
647
+ options={OPTIONS}
648
+ value="Apple"
649
+ onChange={() => {}}
650
+ hasSearch
651
+ />,
652
+ );
653
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
654
+ // "ban" matches only Banana. Anchored so it cannot pass on "1 results".
655
+ await user.type(screen.getByRole('combobox', h), 'ban');
656
+ await waitFor(() => {
657
+ expect(politeRegion()).toHaveTextContent(/^1 result$/);
658
+ });
659
+ });
660
+
661
+ it('announces "No results found" when nothing matches', async () => {
662
+ const user = userEvent.setup();
663
+ render(
664
+ <Selector
665
+ label="Fruit"
666
+ options={OPTIONS}
667
+ value="Apple"
668
+ onChange={() => {}}
669
+ hasSearch
670
+ />,
671
+ );
672
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
673
+ await user.type(screen.getByRole('combobox', h), 'xyz');
674
+ await waitFor(() => {
675
+ expect(politeRegion()).toHaveTextContent('No results found');
676
+ });
677
+ });
678
+
679
+ it('does not announce results until the user searches', async () => {
680
+ const user = userEvent.setup();
681
+ render(
682
+ <Selector
683
+ label="Fruit"
684
+ options={OPTIONS}
685
+ value="Apple"
686
+ onChange={() => {}}
687
+ hasSearch
688
+ />,
689
+ );
690
+ // Popover closed: nothing announced.
691
+ expect(politeRegion()?.textContent ?? '').toBe('');
692
+ // Open with an empty query: still nothing announced.
693
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
694
+ expect(politeRegion()?.textContent ?? '').toBe('');
695
+ });
696
+ });
602
697
  });
603
698
 
604
699
  describe('keyboard accessibility', () => {
@@ -869,7 +964,12 @@ describe('Selector', () => {
869
964
  it('submits the selected value under htmlName', () => {
870
965
  const {container} = render(
871
966
  <form>
872
- <Selector label="Fruit" htmlName="fruit" options={OPTIONS} value="Banana" />
967
+ <Selector
968
+ label="Fruit"
969
+ htmlName="fruit"
970
+ options={OPTIONS}
971
+ value="Banana"
972
+ />
873
973
  </form>,
874
974
  );
875
975
  const data = new FormData(container.querySelector('form')!);
@@ -889,10 +989,18 @@ describe('Selector', () => {
889
989
  it('is excluded from form data when disabled', () => {
890
990
  const {container} = render(
891
991
  <form>
892
- <Selector label="Fruit" htmlName="fruit" options={OPTIONS} value="Banana" isDisabled />
992
+ <Selector
993
+ label="Fruit"
994
+ htmlName="fruit"
995
+ options={OPTIONS}
996
+ value="Banana"
997
+ isDisabled
998
+ />
893
999
  </form>,
894
1000
  );
895
- expect([...new FormData(container.querySelector('form')!).keys()]).toEqual([]);
1001
+ expect([
1002
+ ...new FormData(container.querySelector('form')!).keys(),
1003
+ ]).toEqual([]);
896
1004
  });
897
1005
  });
898
1006
  });
@@ -42,6 +42,7 @@ import {Divider} from '../Divider';
42
42
  import {layerAnimations} from '../Layer/layerAnimations.stylex';
43
43
  import type {LayerPlacement} from '../Layer/useLayer';
44
44
  import {Spinner} from '../Spinner';
45
+ import {useAnnounce} from '../hooks/useAnnounce';
45
46
  import {
46
47
  colorVars,
47
48
  sizeVars,
@@ -72,6 +73,7 @@ import {themeProps} from '../utils/themeProps';
72
73
  import {groupStyles} from '../InputGroup/groupStyles';
73
74
  import {useInputGroup} from '../InputGroup/InputGroupContext';
74
75
  import {VisuallyHidden} from '../VisuallyHidden';
76
+ import {useTranslator} from '../i18n';
75
77
 
76
78
  const styles = stylex.create({
77
79
  // Trigger container — the enhanced click target wrapping the combobox button and clear button as siblings
@@ -524,8 +526,7 @@ type SelectorPropsClearable<T extends SelectorOptionType = SelectorOptionType> =
524
526
  };
525
527
 
526
528
  export type SelectorProps<T extends SelectorOptionType = SelectorOptionType> =
527
- | SelectorPropsNonClearable<T>
528
- | SelectorPropsClearable<T>;
529
+ SelectorPropsNonClearable<T> | SelectorPropsClearable<T>;
529
530
 
530
531
  /**
531
532
  * Default option renderer
@@ -536,6 +537,23 @@ function DefaultOption({option}: {option: SelectorOptionData}) {
536
537
  );
537
538
  }
538
539
 
540
+ // Case-insensitive substring filter over the selectable options. Shared by the
541
+ // `filteredItems` memo (rendering) and the search-change handler, which needs
542
+ // the count for the *next* query synchronously to announce it exactly once per
543
+ // keystroke rather than reacting to state in an effect.
544
+ function filterOptionsByQuery(
545
+ items: SelectorOptionData[],
546
+ query: string,
547
+ ): SelectorOptionData[] {
548
+ if (!query) {
549
+ return items;
550
+ }
551
+ const q = query.toLowerCase();
552
+ return items.filter(item =>
553
+ (item.label ?? item.value).toLowerCase().includes(q),
554
+ );
555
+ }
556
+
539
557
  /**
540
558
  * A selector/dropdown component for choosing from a list of options.
541
559
  *
@@ -553,6 +571,7 @@ function DefaultOption({option}: {option: SelectorOptionData}) {
553
571
  export function Selector<T extends SelectorOptionType>(
554
572
  props: SelectorProps<T>,
555
573
  ) {
574
+ const t = useTranslator();
556
575
  const {
557
576
  label,
558
577
  isLabelHidden = false,
@@ -566,7 +585,7 @@ export function Selector<T extends SelectorOptionType>(
566
585
  onChange,
567
586
  changeAction,
568
587
  isLoading = false,
569
- placeholder = 'Select...',
588
+ placeholder: placeholderFromProps,
570
589
  size: sizeProp,
571
590
  status,
572
591
  labelTooltip,
@@ -574,7 +593,7 @@ export function Selector<T extends SelectorOptionType>(
574
593
  htmlName,
575
594
  renderOption,
576
595
  hasSearch = false,
577
- searchPlaceholder = 'Search...',
596
+ searchPlaceholder: searchPlaceholderFromProps,
578
597
  placement,
579
598
  isDefaultOpen = false,
580
599
  'data-testid': testId,
@@ -585,6 +604,9 @@ export function Selector<T extends SelectorOptionType>(
585
604
  hasClear: hasClearProp,
586
605
  ...rest
587
606
  } = props as SelectorPropsClearable<T>;
607
+ const placeholder = placeholderFromProps ?? t('@astryx.selector.placeholder');
608
+ const searchPlaceholder =
609
+ searchPlaceholderFromProps ?? t('@astryx.selector.searchPlaceholder');
588
610
  const hasClear = hasClearProp === true;
589
611
  const size = useSize(sizeProp, 'md');
590
612
 
@@ -637,15 +659,10 @@ export function Selector<T extends SelectorOptionType>(
637
659
  );
638
660
 
639
661
  // Filter items by search query
640
- const filteredItems = useMemo(() => {
641
- if (!searchQuery) {
642
- return selectableItems;
643
- }
644
- const query = searchQuery.toLowerCase();
645
- return selectableItems.filter(item =>
646
- (item.label ?? item.value).toLowerCase().includes(query),
647
- );
648
- }, [selectableItems, searchQuery]);
662
+ const filteredItems = useMemo(
663
+ () => filterOptionsByQuery(selectableItems, searchQuery),
664
+ [selectableItems, searchQuery],
665
+ );
649
666
 
650
667
  // Find selected item and its index for positioning
651
668
  const selectedItemIndex = useMemo(() => {
@@ -661,11 +678,20 @@ export function Selector<T extends SelectorOptionType>(
661
678
  // Ref for listbox to measure selected item position
662
679
  const listboxRef = useRef<HTMLDivElement>(null);
663
680
 
681
+ // Announce match counts / "No results found" politely as the user types, so
682
+ // screen-reader users hear how many options remain. Filtering was previously
683
+ // silent (comboboxes-7). Mirrors BaseTypeahead, which announces from its
684
+ // query-change callback (not a reactive effect) via the same useAnnounce hook.
685
+ const announce = useAnnounce();
686
+
664
687
  // Layer for dropdown positioning
665
688
  const handleLayerHide = useCallback(() => {
666
689
  setSearchQuery('');
690
+ // Clear any lingering result count when the popover closes so stale status
691
+ // text does not linger in the a11y tree.
692
+ announce('');
667
693
  triggerRef.current?.focus();
668
- }, []);
694
+ }, [announce]);
669
695
 
670
696
  const popover = usePopover({
671
697
  onHide: handleLayerHide,
@@ -685,6 +711,29 @@ export function Selector<T extends SelectorOptionType>(
685
711
  // eslint-disable-next-line @eslint-react/exhaustive-deps -- mount-only: isDefaultOpen is not reactive
686
712
  }, []);
687
713
 
714
+ // Announce the filtered result count from the query-change handler (matching
715
+ // BaseTypeahead) rather than a reactive effect: computing the count for the
716
+ // next query here fires the announcement exactly once per keystroke and does
717
+ // not re-speak on unrelated re-renders.
718
+ const handleSearchChange = useCallback(
719
+ (event: React.ChangeEvent<HTMLInputElement>) => {
720
+ const nextQuery = event.target.value;
721
+ setSearchQuery(nextQuery);
722
+ if (nextQuery.length === 0) {
723
+ // Emptying the query clears the region rather than announcing a count.
724
+ announce('');
725
+ return;
726
+ }
727
+ const count = filterOptionsByQuery(selectableItems, nextQuery).length;
728
+ announce(
729
+ count === 0
730
+ ? 'No results found'
731
+ : `${count} result${count === 1 ? '' : 's'}`,
732
+ );
733
+ },
734
+ [announce, selectableItems],
735
+ );
736
+
688
737
  // Calculate offset to position selected item over trigger. Explicit
689
738
  // placement opts out of the selector-specific overlay behavior and uses the
690
739
  // standard layer positioning API instead.
@@ -803,10 +852,10 @@ export function Selector<T extends SelectorOptionType>(
803
852
  ? getItemId(highlightedIndex)
804
853
  : undefined
805
854
  }
806
- aria-label="Search options"
855
+ aria-label={t('@astryx.selector.searchOptions')}
807
856
  type="text"
808
857
  value={searchQuery}
809
- onChange={e => setSearchQuery(e.target.value)}
858
+ onChange={handleSearchChange}
810
859
  onKeyDown={e => {
811
860
  // Arrow keys navigate options; Enter selects; Escape/Tab close.
812
861
  // Home/End are left to the input for caret movement.
@@ -831,10 +880,12 @@ export function Selector<T extends SelectorOptionType>(
831
880
  listboxId,
832
881
  searchQuery,
833
882
  searchPlaceholder,
883
+ handleSearchChange,
834
884
  onKeyDown,
835
885
  popover.isOpen,
836
886
  highlightedIndex,
837
887
  getItemId,
888
+ t,
838
889
  ]);
839
890
 
840
891
  // Render an individual item
@@ -1014,7 +1065,7 @@ export function Selector<T extends SelectorOptionType>(
1014
1065
  <button
1015
1066
  type="button"
1016
1067
  onClick={handleClear}
1017
- aria-label={`Clear ${label}`}
1068
+ aria-label={t('@astryx.selector.clearLabel', {label})}
1018
1069
  {...stylex.props(styles.clearButton)}>
1019
1070
  <Icon icon="close" size="sm" color="secondary" />
1020
1071
  </button>
@@ -45,6 +45,7 @@ import {useResizable} from '../Resizable/useResizable';
45
45
  import type {ResizableConfig} from '../Resizable/useResizable';
46
46
  import {ResizeHandle} from '../Resizable/ResizeHandle';
47
47
  import {themeProps} from '../utils/themeProps';
48
+ import {useTranslator} from '../i18n';
48
49
 
49
50
  // =============================================================================
50
51
  // Constants
@@ -330,6 +331,7 @@ export function SideNav({
330
331
  handleRef,
331
332
  ...props
332
333
  }: SideNavProps) {
334
+ const t = useTranslator();
333
335
  // Parse collapsible prop
334
336
  const collapsibleConfig = typeof collapsible === 'object' ? collapsible : {};
335
337
  const isCollapsible = !!collapsible;
@@ -504,7 +506,7 @@ export function SideNav({
504
506
  <nav
505
507
  ref={mergeRefs(ref, navRef)}
506
508
  role="navigation"
507
- aria-label="Side navigation"
509
+ aria-label={t('@astryx.sideNav.label')}
508
510
  data-testid={testId}
509
511
  {...mergeProps(
510
512
  themeProps('side-nav'),
@@ -569,7 +571,7 @@ export function SideNav({
569
571
  pillPlacement="end"
570
572
  isAlwaysVisible={false}
571
573
  resizable={resizableHook.props}
572
- label="Resize sidebar"
574
+ label={t('@astryx.sideNav.resizeSidebar')}
573
575
  />
574
576
  </div>
575
577
  ) : (
@@ -30,6 +30,7 @@ import {
30
30
  type SideNavImperativeCollapseHandle,
31
31
  } from './SideNavCollapseContext';
32
32
  import {useAppShellMobile} from '../AppShell/AppShellMobileContext';
33
+ import {useTranslator} from '../i18n';
33
34
 
34
35
  // =============================================================================
35
36
  // Styles
@@ -105,6 +106,7 @@ export function SideNavCollapseButton({
105
106
  onClick: onClickProp,
106
107
  ...props
107
108
  }: SideNavCollapseButtonProps) {
109
+ const t = useTranslator();
108
110
  const {isCollapsed, toggle, isCollapsible} =
109
111
  useSideNavCollapseState(handleRef);
110
112
  const {isMobile} = useAppShellMobile();
@@ -118,7 +120,7 @@ export function SideNavCollapseButton({
118
120
  return (
119
121
  <Button
120
122
  ref={ref}
121
- label={label ?? (isCollapsed ? 'Expand sidebar' : 'Collapse sidebar')}
123
+ label={label ?? (isCollapsed ? t('@astryx.sideNavCollapseButton.expandSidebar') : t('@astryx.sideNavCollapseButton.collapseSidebar'))}
122
124
  variant="ghost"
123
125
  {...props}
124
126
  onClick={composeEventHandlers(onClickProp, toggle)}
@@ -44,6 +44,7 @@ import type {BaseProps} from '../BaseProps';
44
44
  import {useMenuHover} from '../hooks/useMenuHover';
45
45
  import {NavHeadingCloseContext} from '../NavMenu/NavMenuContext';
46
46
  import {themeProps} from '../utils/themeProps';
47
+ import {useTranslator} from '../i18n';
47
48
 
48
49
  // =============================================================================
49
50
  // Styles
@@ -342,13 +343,14 @@ export function SideNavHeading({
342
343
  ref,
343
344
  ...props
344
345
  }: SideNavHeadingProps) {
346
+ const t = useTranslator();
345
347
  const LinkComponent = useLinkComponent(as);
346
348
  const {isCollapsed} = useSideNavCollapse();
347
349
  const rootRef = useRef<HTMLDivElement>(null);
348
350
  const collapsedItemRef = useRef<HTMLElement>(null);
349
351
 
350
352
  const popover = usePopover({
351
- dialogLabel: 'Navigation menu',
353
+ dialogLabel: t('@astryx.sideNav.heading.dialogLabel'),
352
354
  hasCloseButton: false,
353
355
  });
354
356
 
@@ -603,7 +605,7 @@ export function SideNavHeading({
603
605
  {renderTextContent(
604
606
  <button
605
607
  type="button"
606
- aria-label="Open menu"
608
+ aria-label={t('@astryx.sideNav.heading.openMenu')}
607
609
  onClick={e => {
608
610
  e.stopPropagation();
609
611
  triggerProps.onClick();
@@ -665,7 +667,7 @@ export function SideNavHeading({
665
667
  showChevron ? (
666
668
  <button
667
669
  type="button"
668
- aria-label="Open menu"
670
+ aria-label={t('@astryx.sideNav.heading.openMenu')}
669
671
  onClick={e => {
670
672
  e.stopPropagation();
671
673
  triggerProps.onClick();