@astryxdesign/core 0.1.9 → 0.2.0-canary.0f56f82

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 (565) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/dist/Avatar/Avatar.d.ts +42 -3
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +190 -59
  5. package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
  6. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  7. package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
  8. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  9. package/dist/AvatarGroup/AvatarGroup.js +58 -6
  10. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  11. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  12. package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -2
  13. package/dist/Banner/Banner.js +2 -2
  14. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  15. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
  16. package/dist/Breadcrumbs/index.d.ts +1 -0
  17. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  18. package/dist/Breadcrumbs/index.js +2 -1
  19. package/dist/Button/Button.d.ts +1 -1
  20. package/dist/Button/Button.d.ts.map +1 -1
  21. package/dist/Button/Button.js +6 -4
  22. package/dist/Calendar/Calendar.d.ts.map +1 -1
  23. package/dist/Calendar/Calendar.js +50 -9
  24. package/dist/Calendar/dayCellUtils.d.ts +4 -4
  25. package/dist/Calendar/dayCellUtils.js +2 -2
  26. package/dist/Calendar/styles.d.ts +30 -31
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +30 -31
  29. package/dist/Card/Card.js +1 -1
  30. package/dist/Carousel/Carousel.d.ts.map +1 -1
  31. package/dist/Carousel/Carousel.js +22 -12
  32. package/dist/Chat/ChatComposerInput.js +1 -1
  33. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  34. package/dist/Chat/ChatDictationButton.js +3 -1
  35. package/dist/Chat/ChatLayout.js +4 -4
  36. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  37. package/dist/Chat/ChatMessageBubble.js +8 -8
  38. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  39. package/dist/Chat/ChatToolCalls.js +10 -3
  40. package/dist/Chat/useTriggerMenu.js +2 -2
  41. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  42. package/dist/CheckboxInput/CheckboxInput.js +6 -6
  43. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  44. package/dist/CheckboxList/CheckboxListItem.js +19 -4
  45. package/dist/Citation/Citation.d.ts +22 -1
  46. package/dist/Citation/Citation.d.ts.map +1 -1
  47. package/dist/Citation/Citation.js +20 -6
  48. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  49. package/dist/CodeBlock/CodeBlock.js +16 -10
  50. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  51. package/dist/Collapsible/Collapsible.js +3 -1
  52. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  53. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  54. package/dist/CommandPalette/CommandPalette.js +42 -3
  55. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  56. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  57. package/dist/ContextMenu/ContextMenu.js +23 -5
  58. package/dist/ContextMenu/index.d.ts +1 -0
  59. package/dist/ContextMenu/index.d.ts.map +1 -1
  60. package/dist/ContextMenu/index.js +3 -1
  61. package/dist/DateInput/DateInput.d.ts +10 -2
  62. package/dist/DateInput/DateInput.d.ts.map +1 -1
  63. package/dist/DateInput/DateInput.js +33 -19
  64. package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
  65. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  66. package/dist/DateRangeInput/DateRangeInput.js +23 -20
  67. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  68. package/dist/DateTimeInput/DateTimeInput.js +23 -18
  69. package/dist/Divider/Divider.d.ts +2 -2
  70. package/dist/Divider/Divider.d.ts.map +1 -1
  71. package/dist/Divider/Divider.js +13 -0
  72. package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
  73. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  74. package/dist/DropdownMenu/DropdownMenu.js +22 -5
  75. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  76. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
  77. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
  79. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
  80. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  81. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
  82. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  83. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuRadioItem.js +5 -2
  85. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
  86. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
  87. package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
  88. package/dist/DropdownMenu/index.d.ts +10 -0
  89. package/dist/DropdownMenu/index.d.ts.map +1 -1
  90. package/dist/DropdownMenu/index.js +13 -0
  91. package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
  92. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
  93. package/dist/DropdownMenu/menuItemHover.js +33 -0
  94. package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
  95. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
  96. package/dist/DropdownMenu/menuItemRoles.js +10 -1
  97. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  98. package/dist/DropdownMenu/renderDropdownItems.js +21 -6
  99. package/dist/Field/Field.d.ts +3 -1
  100. package/dist/Field/Field.d.ts.map +1 -1
  101. package/dist/Field/Field.js +4 -1
  102. package/dist/Field/FieldLabel.d.ts +2 -1
  103. package/dist/Field/FieldLabel.d.ts.map +1 -1
  104. package/dist/Field/FieldLabel.js +9 -5
  105. package/dist/Field/inputStyles.stylex.d.ts +1 -0
  106. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  107. package/dist/Field/inputStyles.stylex.js +1 -0
  108. package/dist/FieldStatus/FieldStatus.d.ts +10 -0
  109. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  110. package/dist/FieldStatus/FieldStatus.js +51 -5
  111. package/dist/FileInput/FileInput.d.ts +10 -2
  112. package/dist/FileInput/FileInput.d.ts.map +1 -1
  113. package/dist/FileInput/FileInput.js +93 -65
  114. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  115. package/dist/HoverCard/useHoverCard.js +10 -4
  116. package/dist/Icon/Icon.d.ts +15 -1
  117. package/dist/Icon/Icon.d.ts.map +1 -1
  118. package/dist/Icon/Icon.js +19 -3
  119. package/dist/Item/Item.d.ts +16 -3
  120. package/dist/Item/Item.d.ts.map +1 -1
  121. package/dist/Item/Item.js +31 -6
  122. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  123. package/dist/Layer/layerAnimations.stylex.js +10 -2
  124. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  125. package/dist/Lightbox/Lightbox.js +19 -13
  126. package/dist/List/List.d.ts.map +1 -1
  127. package/dist/List/List.js +6 -3
  128. package/dist/List/ListItem.d.ts +11 -1
  129. package/dist/List/ListItem.d.ts.map +1 -1
  130. package/dist/List/ListItem.js +2 -0
  131. package/dist/Markdown/Markdown.d.ts.map +1 -1
  132. package/dist/Markdown/Markdown.js +7 -0
  133. package/dist/MetadataList/MetadataList.d.ts +1 -1
  134. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  135. package/dist/MetadataList/MetadataList.js +4 -2
  136. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  137. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  138. package/dist/MultiSelector/MultiSelector.js +80 -42
  139. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  140. package/dist/NumberInput/NumberInput.d.ts +10 -2
  141. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  142. package/dist/NumberInput/NumberInput.js +22 -17
  143. package/dist/Outline/Outline.js +2 -2
  144. package/dist/Pagination/Pagination.d.ts.map +1 -1
  145. package/dist/Pagination/Pagination.js +11 -3
  146. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  147. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  148. package/dist/PowerSearch/PowerSearch.js +2 -0
  149. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  150. package/dist/ProgressBar/ProgressBar.js +6 -1
  151. package/dist/RadioList/RadioList.d.ts +2 -2
  152. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  153. package/dist/RadioList/RadioListItem.js +5 -5
  154. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  155. package/dist/Resizable/ResizeHandle.js +49 -19
  156. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  157. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  158. package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
  159. package/dist/Selector/Selector.d.ts +8 -0
  160. package/dist/Selector/Selector.d.ts.map +1 -1
  161. package/dist/Selector/Selector.js +66 -17
  162. package/dist/SideNav/SideNav.d.ts.map +1 -1
  163. package/dist/SideNav/SideNav.js +5 -5
  164. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  165. package/dist/SideNav/SideNavCollapseButton.js +13 -10
  166. package/dist/SideNav/SideNavItem.d.ts +1 -1
  167. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  168. package/dist/SideNav/SideNavItem.js +12 -10
  169. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  170. package/dist/Skeleton/Skeleton.js +2 -2
  171. package/dist/Slider/Slider.d.ts.map +1 -1
  172. package/dist/Slider/Slider.js +87 -34
  173. package/dist/Spinner/Spinner.d.ts +3 -2
  174. package/dist/Spinner/Spinner.d.ts.map +1 -1
  175. package/dist/Spinner/Spinner.js +11 -2
  176. package/dist/Switch/Switch.d.ts +8 -1
  177. package/dist/Switch/Switch.d.ts.map +1 -1
  178. package/dist/Switch/Switch.js +171 -91
  179. package/dist/TabList/Tab.js +2 -2
  180. package/dist/TabList/TabList.d.ts +2 -11
  181. package/dist/TabList/TabList.d.ts.map +1 -1
  182. package/dist/TabList/TabList.js +5 -9
  183. package/dist/TabList/TabListContext.d.ts +0 -5
  184. package/dist/TabList/TabListContext.d.ts.map +1 -1
  185. package/dist/TabList/TabListContext.js +0 -5
  186. package/dist/TabList/TabMenu.js +1 -1
  187. package/dist/Table/BaseTable.d.ts.map +1 -1
  188. package/dist/Table/BaseTable.js +30 -4
  189. package/dist/Table/TableCell.js +3 -3
  190. package/dist/Table/TableHeaderCell.js +3 -3
  191. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  192. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
  193. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  194. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +37 -27
  195. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  196. package/dist/Table/plugins/selection/useTableSelection.js +3 -0
  197. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  198. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
  199. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  200. package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
  201. package/dist/Table/types.d.ts +32 -0
  202. package/dist/Table/types.d.ts.map +1 -1
  203. package/dist/TextArea/TextArea.d.ts +10 -1
  204. package/dist/TextArea/TextArea.d.ts.map +1 -1
  205. package/dist/TextArea/TextArea.js +18 -19
  206. package/dist/TextInput/TextInput.d.ts +10 -2
  207. package/dist/TextInput/TextInput.d.ts.map +1 -1
  208. package/dist/TextInput/TextInput.js +20 -17
  209. package/dist/Thumbnail/Thumbnail.js +2 -2
  210. package/dist/TimeInput/TimeInput.d.ts +10 -2
  211. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  212. package/dist/TimeInput/TimeInput.js +17 -17
  213. package/dist/Timestamp/Timestamp.d.ts +31 -3
  214. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  215. package/dist/Timestamp/Timestamp.js +47 -76
  216. package/dist/Timestamp/formatInstant.d.ts +41 -0
  217. package/dist/Timestamp/formatInstant.d.ts.map +1 -0
  218. package/dist/Timestamp/formatInstant.js +177 -0
  219. package/dist/Timestamp/index.d.ts +1 -0
  220. package/dist/Timestamp/index.d.ts.map +1 -1
  221. package/dist/Timestamp/tooltipEntries.d.ts +56 -0
  222. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
  223. package/dist/Timestamp/tooltipEntries.js +163 -0
  224. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  225. package/dist/Toast/ToastViewport.js +61 -9
  226. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  227. package/dist/ToggleButton/ToggleButton.js +3 -1
  228. package/dist/Token/Token.d.ts +34 -4
  229. package/dist/Token/Token.d.ts.map +1 -1
  230. package/dist/Token/Token.js +85 -45
  231. package/dist/Token/TokenLink.d.ts +62 -0
  232. package/dist/Token/TokenLink.d.ts.map +1 -0
  233. package/dist/Token/TokenLink.js +76 -0
  234. package/dist/Token/index.d.ts +1 -1
  235. package/dist/Token/index.d.ts.map +1 -1
  236. package/dist/Tokenizer/Tokenizer.d.ts +9 -2
  237. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  238. package/dist/Tokenizer/Tokenizer.js +4 -2
  239. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  240. package/dist/Tooltip/useTooltip.js +17 -1
  241. package/dist/TopNav/TopNavItem.d.ts +3 -1
  242. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  243. package/dist/TopNav/TopNavItem.js +30 -3
  244. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  245. package/dist/TopNav/TopNavMegaMenu.js +9 -3
  246. package/dist/TreeList/TreeList.d.ts.map +1 -1
  247. package/dist/TreeList/TreeList.js +1 -0
  248. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  249. package/dist/TreeList/TreeListBranches.js +8 -6
  250. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  251. package/dist/TreeList/TreeListItem.js +32 -14
  252. package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
  253. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  254. package/dist/Typeahead/BaseTypeahead.js +22 -11
  255. package/dist/Typeahead/Typeahead.d.ts +9 -2
  256. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  257. package/dist/Typeahead/Typeahead.js +11 -2
  258. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  259. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  260. package/dist/Typeahead/TypeaheadItem.js +20 -10
  261. package/dist/astryx.css +74 -33
  262. package/dist/astryx.umd.js +51 -51
  263. package/dist/astryx.umd.js.map +4 -4
  264. package/dist/hooks/index.d.ts +2 -0
  265. package/dist/hooks/index.d.ts.map +1 -1
  266. package/dist/hooks/index.js +1 -0
  267. package/dist/hooks/isRtlElement.d.ts +18 -0
  268. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  269. package/dist/hooks/isRtlElement.js +27 -0
  270. package/dist/hooks/useAnnounce.d.ts +3 -0
  271. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  272. package/dist/hooks/useAnnounce.js +39 -1
  273. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  274. package/dist/hooks/useFocusTrap.js +52 -11
  275. package/dist/hooks/useGridFocus.d.ts +6 -1
  276. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  277. package/dist/hooks/useGridFocus.js +12 -9
  278. package/dist/hooks/useHotkeys.d.ts +9 -0
  279. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  280. package/dist/hooks/useHotkeys.js +9 -0
  281. package/dist/hooks/useInputStatusIcon.d.ts +38 -0
  282. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
  283. package/dist/hooks/useInputStatusIcon.js +169 -0
  284. package/dist/hooks/useKeyboardHint.d.ts +1 -1
  285. package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
  286. package/dist/hooks/useKeyboardHint.js +4 -2
  287. package/dist/hooks/useListFocus.d.ts +39 -1
  288. package/dist/hooks/useListFocus.d.ts.map +1 -1
  289. package/dist/hooks/useListFocus.js +54 -9
  290. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  291. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  292. package/dist/i18n/InternationalizationContext.js +3 -0
  293. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  294. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  295. package/dist/i18n/InternationalizationProvider.js +5 -1
  296. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  297. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  298. package/dist/i18n/getLocaleDirection.js +29 -0
  299. package/dist/i18n/index.d.ts +6 -0
  300. package/dist/i18n/index.d.ts.map +1 -1
  301. package/dist/i18n/index.js +7 -1
  302. package/dist/i18n/useDirection.d.ts +2 -0
  303. package/dist/i18n/useDirection.d.ts.map +1 -0
  304. package/dist/i18n/useDirection.js +27 -0
  305. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  306. package/dist/theme/derivedVarRegistry.js +13 -0
  307. package/dist/utils/index.d.ts +1 -0
  308. package/dist/utils/index.d.ts.map +1 -1
  309. package/dist/utils/index.js +2 -1
  310. package/dist/utils/plainDate.d.ts +17 -0
  311. package/dist/utils/plainDate.d.ts.map +1 -1
  312. package/dist/utils/plainDate.js +23 -4
  313. package/dist/utils/rtlStyles.d.ts +24 -0
  314. package/dist/utils/rtlStyles.d.ts.map +1 -0
  315. package/dist/utils/rtlStyles.js +27 -0
  316. package/locales/en.json +112 -0
  317. package/locales/pseudo.json +84 -0
  318. package/package.json +6 -1
  319. package/src/Avatar/Avatar.doc.mjs +50 -3
  320. package/src/Avatar/Avatar.test.tsx +218 -0
  321. package/src/Avatar/Avatar.tsx +285 -79
  322. package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
  323. package/src/Avatar/AvatarStatusDot.tsx +6 -4
  324. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  325. package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
  326. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  327. package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
  328. package/src/Banner/Banner.tsx +6 -6
  329. package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
  330. package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
  331. package/src/Breadcrumbs/index.ts +4 -0
  332. package/src/Button/Button.doc.mjs +0 -4
  333. package/src/Button/Button.test.tsx +16 -0
  334. package/src/Button/Button.tsx +6 -4
  335. package/src/Calendar/Calendar.test.tsx +170 -20
  336. package/src/Calendar/Calendar.tsx +73 -16
  337. package/src/Calendar/dayCellUtils.test.ts +18 -18
  338. package/src/Calendar/dayCellUtils.ts +2 -2
  339. package/src/Calendar/styles.ts +33 -39
  340. package/src/Card/Card.tsx +1 -1
  341. package/src/Carousel/Carousel.tsx +25 -6
  342. package/src/Chat/ChatComposer.doc.mjs +2 -2
  343. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  344. package/src/Chat/ChatComposerInput.tsx +2 -2
  345. package/src/Chat/ChatDictationButton.tsx +7 -1
  346. package/src/Chat/ChatLayout.tsx +4 -4
  347. package/src/Chat/ChatMessageBubble.tsx +15 -10
  348. package/src/Chat/ChatSystemMessage.test.tsx +5 -0
  349. package/src/Chat/ChatToolCalls.tsx +9 -2
  350. package/src/Chat/useTriggerMenu.tsx +1 -1
  351. package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
  352. package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
  353. package/src/CheckboxInput/CheckboxInput.tsx +21 -6
  354. package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
  355. package/src/CheckboxList/CheckboxList.test.tsx +94 -3
  356. package/src/CheckboxList/CheckboxListItem.tsx +17 -10
  357. package/src/Citation/Citation.doc.mjs +4 -3
  358. package/src/Citation/Citation.test.tsx +97 -0
  359. package/src/Citation/Citation.tsx +43 -11
  360. package/src/CodeBlock/CodeBlock.test.tsx +17 -0
  361. package/src/CodeBlock/CodeBlock.tsx +38 -11
  362. package/src/Collapsible/Collapsible.doc.mjs +1 -0
  363. package/src/Collapsible/Collapsible.test.tsx +7 -0
  364. package/src/Collapsible/Collapsible.tsx +16 -6
  365. package/src/CommandPalette/CommandPalette.test.tsx +95 -1
  366. package/src/CommandPalette/CommandPalette.tsx +41 -2
  367. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  368. package/src/ContextMenu/ContextMenu.test.tsx +59 -2
  369. package/src/ContextMenu/ContextMenu.tsx +22 -11
  370. package/src/ContextMenu/index.ts +5 -0
  371. package/src/DateInput/DateInput.doc.mjs +25 -0
  372. package/src/DateInput/DateInput.test.tsx +230 -0
  373. package/src/DateInput/DateInput.tsx +51 -29
  374. package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
  375. package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
  376. package/src/DateRangeInput/DateRangeInput.tsx +42 -30
  377. package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
  378. package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
  379. package/src/DateTimeInput/DateTimeInput.tsx +44 -39
  380. package/src/Divider/Divider.test.tsx +32 -8
  381. package/src/Divider/Divider.tsx +14 -1
  382. package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
  383. package/src/DropdownMenu/DropdownMenu.tsx +31 -12
  384. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
  385. package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
  386. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
  387. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
  388. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +9 -3
  389. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +20 -2
  390. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
  391. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
  392. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
  393. package/src/DropdownMenu/index.ts +16 -0
  394. package/src/DropdownMenu/menuItemHover.ts +39 -0
  395. package/src/DropdownMenu/menuItemRoles.ts +9 -0
  396. package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
  397. package/src/Field/Field.doc.mjs +4 -0
  398. package/src/Field/Field.tsx +14 -9
  399. package/src/Field/FieldLabel.test.tsx +25 -0
  400. package/src/Field/FieldLabel.tsx +12 -3
  401. package/src/Field/inputStyles.stylex.ts +2 -0
  402. package/src/FieldStatus/FieldStatus.doc.mjs +1 -0
  403. package/src/FieldStatus/FieldStatus.test.tsx +133 -0
  404. package/src/FieldStatus/FieldStatus.tsx +61 -4
  405. package/src/FileInput/FileInput.doc.mjs +23 -2
  406. package/src/FileInput/FileInput.test.tsx +104 -13
  407. package/src/FileInput/FileInput.tsx +106 -79
  408. package/src/HoverCard/useHoverCard.tsx +15 -3
  409. package/src/Icon/Icon.doc.mjs +13 -0
  410. package/src/Icon/Icon.test.tsx +89 -0
  411. package/src/Icon/Icon.tsx +51 -3
  412. package/src/Item/Item.doc.mjs +5 -0
  413. package/src/Item/Item.test.tsx +88 -0
  414. package/src/Item/Item.tsx +57 -11
  415. package/src/Layer/layerAnimations.stylex.ts +23 -0
  416. package/src/Lightbox/Lightbox.tsx +15 -7
  417. package/src/List/List.test.tsx +17 -29
  418. package/src/List/List.tsx +6 -1
  419. package/src/List/ListItem.doc.mjs +12 -0
  420. package/src/List/ListItem.tsx +13 -0
  421. package/src/Markdown/Markdown.test.tsx +21 -0
  422. package/src/Markdown/Markdown.tsx +4 -0
  423. package/src/MetadataList/MetadataList.test.tsx +24 -0
  424. package/src/MetadataList/MetadataList.tsx +6 -2
  425. package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
  426. package/src/MultiSelector/MultiSelector.test.tsx +402 -0
  427. package/src/MultiSelector/MultiSelector.tsx +120 -59
  428. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  429. package/src/NumberInput/NumberInput.doc.mjs +21 -0
  430. package/src/NumberInput/NumberInput.test.tsx +71 -0
  431. package/src/NumberInput/NumberInput.tsx +35 -26
  432. package/src/Outline/Outline.test.tsx +12 -12
  433. package/src/Outline/Outline.tsx +2 -2
  434. package/src/Pagination/Pagination.tsx +11 -3
  435. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  436. package/src/PowerSearch/PowerSearch.test.tsx +23 -0
  437. package/src/PowerSearch/PowerSearch.tsx +10 -1
  438. package/src/ProgressBar/ProgressBar.test.tsx +34 -0
  439. package/src/ProgressBar/ProgressBar.tsx +16 -1
  440. package/src/RadioList/RadioList.doc.mjs +6 -0
  441. package/src/RadioList/RadioList.test.tsx +26 -4
  442. package/src/RadioList/RadioList.tsx +2 -2
  443. package/src/RadioList/RadioListItem.tsx +12 -5
  444. package/src/Resizable/ResizeHandle.test.tsx +94 -0
  445. package/src/Resizable/ResizeHandle.tsx +70 -20
  446. package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
  447. package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
  448. package/src/Selector/Selector.doc.mjs +15 -0
  449. package/src/Selector/Selector.test.tsx +370 -0
  450. package/src/Selector/Selector.tsx +88 -20
  451. package/src/SideNav/SideNav.tsx +1 -8
  452. package/src/SideNav/SideNavCollapseButton.tsx +9 -7
  453. package/src/SideNav/SideNavItem.tsx +5 -3
  454. package/src/Skeleton/Skeleton.test.tsx +16 -0
  455. package/src/Skeleton/Skeleton.tsx +13 -1
  456. package/src/Slider/Slider.doc.mjs +6 -0
  457. package/src/Slider/Slider.test.tsx +240 -12
  458. package/src/Slider/Slider.tsx +96 -23
  459. package/src/Spinner/Spinner.test.tsx +10 -8
  460. package/src/Spinner/Spinner.tsx +15 -5
  461. package/src/Switch/Switch.doc.mjs +142 -42
  462. package/src/Switch/Switch.test.tsx +111 -0
  463. package/src/Switch/Switch.tsx +149 -32
  464. package/src/TabList/Tab.tsx +2 -2
  465. package/src/TabList/TabList.doc.mjs +0 -6
  466. package/src/TabList/TabList.test.tsx +3 -15
  467. package/src/TabList/TabList.tsx +6 -17
  468. package/src/TabList/TabListContext.ts +0 -6
  469. package/src/TabList/TabMenu.tsx +2 -2
  470. package/src/Table/BaseTable.tsx +34 -2
  471. package/src/Table/Table.doc.mjs +11 -0
  472. package/src/Table/Table.test.tsx +85 -0
  473. package/src/Table/TableCell.tsx +3 -3
  474. package/src/Table/TableHeaderCell.tsx +3 -3
  475. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
  476. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
  477. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +27 -18
  478. package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
  479. package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
  480. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
  481. package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
  482. package/src/Table/types.ts +33 -0
  483. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  484. package/src/TextArea/TextArea.doc.mjs +21 -0
  485. package/src/TextArea/TextArea.test.tsx +23 -0
  486. package/src/TextArea/TextArea.tsx +27 -26
  487. package/src/TextInput/TextInput.doc.mjs +21 -0
  488. package/src/TextInput/TextInput.test.tsx +150 -0
  489. package/src/TextInput/TextInput.tsx +28 -25
  490. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  491. package/src/Thumbnail/Thumbnail.tsx +1 -1
  492. package/src/TimeInput/TimeInput.doc.mjs +21 -0
  493. package/src/TimeInput/TimeInput.test.tsx +23 -0
  494. package/src/TimeInput/TimeInput.tsx +24 -25
  495. package/src/Timestamp/Timestamp.doc.mjs +32 -6
  496. package/src/Timestamp/Timestamp.test.tsx +371 -0
  497. package/src/Timestamp/Timestamp.tsx +96 -93
  498. package/src/Timestamp/formatInstant.ts +218 -0
  499. package/src/Timestamp/index.ts +4 -0
  500. package/src/Timestamp/tooltipEntries.test.ts +552 -0
  501. package/src/Timestamp/tooltipEntries.ts +210 -0
  502. package/src/Toast/ToastViewport.test.tsx +218 -8
  503. package/src/Toast/ToastViewport.tsx +71 -12
  504. package/src/ToggleButton/ToggleButton.test.tsx +24 -0
  505. package/src/ToggleButton/ToggleButton.tsx +19 -1
  506. package/src/Token/Token.test.tsx +166 -15
  507. package/src/Token/Token.tsx +104 -47
  508. package/src/Token/TokenLink.tsx +107 -0
  509. package/src/Token/index.ts +1 -1
  510. package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
  511. package/src/Tokenizer/Tokenizer.test.tsx +23 -0
  512. package/src/Tokenizer/Tokenizer.tsx +14 -2
  513. package/src/Tooltip/Tooltip.test.tsx +46 -0
  514. package/src/Tooltip/useTooltip.tsx +20 -0
  515. package/src/TopNav/TopNav.test.tsx +93 -2
  516. package/src/TopNav/TopNavItem.doc.mjs +3 -3
  517. package/src/TopNav/TopNavItem.tsx +35 -6
  518. package/src/TopNav/TopNavMegaMenu.tsx +26 -2
  519. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
  520. package/src/TreeList/TreeList.doc.mjs +6 -0
  521. package/src/TreeList/TreeList.test.tsx +50 -10
  522. package/src/TreeList/TreeList.tsx +5 -0
  523. package/src/TreeList/TreeListBranches.tsx +8 -6
  524. package/src/TreeList/TreeListItem.tsx +33 -11
  525. package/src/Typeahead/BaseTypeahead.tsx +42 -15
  526. package/src/Typeahead/Typeahead.doc.mjs +13 -0
  527. package/src/Typeahead/Typeahead.test.tsx +112 -0
  528. package/src/Typeahead/Typeahead.tsx +17 -1
  529. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  530. package/src/__tests__/forcedColors.ts +60 -0
  531. package/src/__tests__/inputWidthContract.test.tsx +62 -0
  532. package/src/doc-mjs.d.ts +19 -0
  533. package/src/hooks/index.ts +6 -0
  534. package/src/hooks/isRtlElement.ts +27 -0
  535. package/src/hooks/useAnnounce.test.tsx +75 -2
  536. package/src/hooks/useAnnounce.ts +47 -1
  537. package/src/hooks/useFocusTrap.test.tsx +104 -0
  538. package/src/hooks/useFocusTrap.ts +61 -12
  539. package/src/hooks/useGridFocus.doc.mjs +3 -3
  540. package/src/hooks/useGridFocus.test.tsx +41 -0
  541. package/src/hooks/useGridFocus.ts +21 -10
  542. package/src/hooks/useHotkeys.ts +9 -0
  543. package/src/hooks/useInputStatusIcon.test.tsx +221 -0
  544. package/src/hooks/useInputStatusIcon.tsx +235 -0
  545. package/src/hooks/useKeyboardHint.test.tsx +22 -0
  546. package/src/hooks/useKeyboardHint.tsx +6 -2
  547. package/src/hooks/useListFocus.doc.mjs +25 -3
  548. package/src/hooks/useListFocus.test.tsx +153 -1
  549. package/src/hooks/useListFocus.ts +102 -9
  550. package/src/i18n/InternationalizationContext.ts +4 -0
  551. package/src/i18n/InternationalizationProvider.tsx +12 -2
  552. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  553. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  554. package/src/i18n/getLocaleDirection.ts +29 -0
  555. package/src/i18n/index.ts +6 -0
  556. package/src/i18n/useDirection.ts +29 -0
  557. package/src/reset.css +0 -26
  558. package/src/reset.test.ts +60 -0
  559. package/src/theme/derivedVarRegistry.test.ts +1 -0
  560. package/src/theme/derivedVarRegistry.ts +6 -0
  561. package/src/theme/generateThemeRules.test.ts +42 -0
  562. package/src/utils/index.ts +2 -0
  563. package/src/utils/plainDate.test.ts +24 -6
  564. package/src/utils/plainDate.ts +18 -4
  565. package/src/utils/rtlStyles.ts +27 -0
@@ -5,6 +5,7 @@ import {render, screen} from '@testing-library/react';
5
5
  import userEvent from '@testing-library/user-event';
6
6
  import {MetadataList} from './MetadataList';
7
7
  import {MetadataListItem} from './MetadataListItem';
8
+ import {InternationalizationProvider} from '../i18n';
8
9
 
9
10
  describe('MetadataList', () => {
10
11
  it('renders a description list with items', () => {
@@ -87,6 +88,29 @@ describe('MetadataList', () => {
87
88
  expect(screen.queryByText('B')).not.toBeInTheDocument();
88
89
  });
89
90
 
91
+ it('localizes the show more / show less labels through the i18n catalog', async () => {
92
+ const user = userEvent.setup();
93
+
94
+ render(
95
+ <InternationalizationProvider
96
+ locale="fr"
97
+ overrides={{
98
+ fr: {
99
+ '@astryx.metadataList.showMore': 'Afficher plus',
100
+ '@astryx.metadataList.showLess': 'Afficher moins',
101
+ },
102
+ }}>
103
+ <MetadataList maxNumOfItems={1}>
104
+ <MetadataListItem label="A">1</MetadataListItem>
105
+ <MetadataListItem label="B">2</MetadataListItem>
106
+ </MetadataList>
107
+ </InternationalizationProvider>,
108
+ );
109
+
110
+ await user.click(screen.getByText('Afficher plus'));
111
+ expect(screen.getByText('Afficher moins')).toBeInTheDocument();
112
+ });
113
+
90
114
  it('does not show toggle in horizontal mode even with maxNumOfItems', () => {
91
115
  render(
92
116
  <MetadataList orientation="horizontal" maxNumOfItems={1}>
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file MetadataList.tsx
7
- * @input Uses React, ReactNode, StyleXStyles, theme tokens, MetadataListContext
7
+ * @input Uses React, ReactNode, StyleXStyles, theme tokens, MetadataListContext, i18n (useTranslator)
8
8
  * @output Exports MetadataList component, MetadataListProps, MetadataListColumns types
9
9
  * @position Core implementation; consumed by index.ts, tested by MetadataList.test.tsx
10
10
  *
@@ -31,6 +31,7 @@ import {
31
31
  import type {BaseProps} from '../BaseProps';
32
32
  import {mergeProps} from '../utils';
33
33
  import {themeProps} from '../utils/themeProps';
34
+ import {useTranslator} from '../i18n';
34
35
 
35
36
  // =============================================================================
36
37
  // Types
@@ -197,6 +198,7 @@ export function MetadataList({
197
198
  const labelConfig = label ?? (isMultiColumn ? LABEL_TOP : LABEL_START);
198
199
  const [isShowAll, setIsShowAll] = useState(false);
199
200
  const contentId = useId();
201
+ const t = useTranslator();
200
202
 
201
203
  const contextValue = useMemo(
202
204
  () => ({
@@ -283,7 +285,9 @@ export function MetadataList({
283
285
  aria-expanded={isShowAll}
284
286
  onClick={() => setIsShowAll(prev => !prev)}
285
287
  {...stylex.props(styles.toggleButton)}>
286
- {isShowAll ? 'Show less' : 'Show more'}
288
+ {isShowAll
289
+ ? t('@astryx.metadataList.showLess')
290
+ : t('@astryx.metadataList.showMore')}
287
291
  </button>
288
292
  )}
289
293
  </div>
@@ -21,6 +21,11 @@ export const docs = {
21
21
  theming: {
22
22
  targets: [
23
23
  {className: 'astryx-multi-selector', visualProps: ['size', 'status']},
24
+ {className: 'astryx-multi-selector-clear-icon'},
25
+ {
26
+ className: 'astryx-multi-selector-indicator-icon',
27
+ states: ['state'],
28
+ },
24
29
  ],
25
30
  },
26
31
  components: [
@@ -155,12 +160,25 @@ export const docs = {
155
160
  type: "{type: 'error' | 'warning' | 'success', message?: string}",
156
161
  description: 'Validation status with an optional message.',
157
162
  },
163
+ {
164
+ name: 'statusVariant',
165
+ type: "'attached' | 'detached'",
166
+ description:
167
+ 'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing.',
168
+ default: "'attached'",
169
+ },
158
170
  {
159
171
  name: 'renderOption',
160
172
  type: '(option: MultiSelectorOptionData) => ReactNode',
161
173
  description:
162
174
  'Custom render function for each selectable option in the dropdown. Not called for dividers, sections, or the select-all row.',
163
175
  },
176
+ {
177
+ name: 'width',
178
+ type: 'SizeValue',
179
+ description:
180
+ 'Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.',
181
+ },
164
182
  {
165
183
  name: 'xstyle',
166
184
  type: 'StyleXStyles',
@@ -250,6 +268,7 @@ export const docsZh = {
250
268
  isRequired: '将字段标记为必填。',
251
269
  isLoading: '在触发器中显示加载旋转器。',
252
270
  status: '带可选消息的验证状态。',
271
+ statusVariant: '状态消息的放置方式:attached 直接叠加在输入框下方;detached 作为独立元素浮于下方并留有间距。',
253
272
  renderOption:
254
273
  '每个可选选项的自定义渲染函数。不会用于分隔线、分组或全选行。',
255
274
  xstyle: '布局自定义的 StyleX 样式,必须是 stylex.create() 值。',
@@ -375,6 +394,7 @@ export const docsDense = {
375
394
  isRequired: 'marks required',
376
395
  isLoading: 'spinner in trigger',
377
396
  status: 'validation status w/ optional message',
397
+ statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing.',
378
398
  renderOption:
379
399
  'custom render fn per selectable option; not dividers/sections/select-all',
380
400
  xstyle: 'StyleX layout styles; stylex.create() only',
@@ -19,7 +19,10 @@ import {
19
19
  } from '@testing-library/react';
20
20
  import userEvent from '@testing-library/user-event';
21
21
  import {MultiSelector} from './MultiSelector';
22
+ import {Icon} from '../Icon';
22
23
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
24
+ import {defineTheme} from '../theme/defineTheme';
25
+ import {generateThemeCSSFlat} from '../theme/generateThemeRules';
23
26
 
24
27
  // Module-level constants to satisfy @eslint-react/no-unstable-default-props.
25
28
  const ANNOUNCE_OPTIONS = ['Apple', 'Banana', 'Orange'] as const;
@@ -507,6 +510,59 @@ describe('MultiSelector', () => {
507
510
  expect(options[0]).toHaveTextContent('Select all');
508
511
  });
509
512
 
513
+ it('select-all accessible name reflects none/partial/all selection', async () => {
514
+ const user = userEvent.setup();
515
+ const options = [
516
+ {value: 'apple', label: 'Apple'},
517
+ {value: 'banana', label: 'Banana'},
518
+ ];
519
+ const {rerender} = render(
520
+ <MultiSelector
521
+ label="Fruit"
522
+ options={options}
523
+ value={[]}
524
+ onChange={() => {}}
525
+ hasSelectAll
526
+ />,
527
+ );
528
+
529
+ await user.click(screen.getByRole('combobox'));
530
+
531
+ // None selected: plain name, not selected
532
+ let selectAll = screen.getAllByRole('option', h)[0];
533
+ expect(selectAll).not.toHaveAccessibleName(/partially selected/);
534
+ expect(selectAll).toHaveAttribute('aria-selected', 'false');
535
+
536
+ // Partial: aria-selected="mixed" is invalid on role="option", so the
537
+ // indeterminate state must be conveyed through the accessible name.
538
+ rerender(
539
+ <MultiSelector
540
+ label="Fruit"
541
+ options={options}
542
+ value={['apple']}
543
+ onChange={() => {}}
544
+ hasSelectAll
545
+ />,
546
+ );
547
+ selectAll = screen.getAllByRole('option', h)[0];
548
+ expect(selectAll).toHaveAccessibleName('Select all, partially selected');
549
+ expect(selectAll).toHaveAttribute('aria-selected', 'false');
550
+
551
+ // All selected: plain name again, selected
552
+ rerender(
553
+ <MultiSelector
554
+ label="Fruit"
555
+ options={options}
556
+ value={['apple', 'banana']}
557
+ onChange={() => {}}
558
+ hasSelectAll
559
+ />,
560
+ );
561
+ selectAll = screen.getAllByRole('option', h)[0];
562
+ expect(selectAll).not.toHaveAccessibleName(/partially selected/);
563
+ expect(selectAll).toHaveAttribute('aria-selected', 'true');
564
+ });
565
+
510
566
  it('select-all toggles via keyboard Enter', async () => {
511
567
  const user = userEvent.setup();
512
568
  const onChange = vi.fn();
@@ -565,6 +621,72 @@ describe('MultiSelector', () => {
565
621
  expect(options).toHaveLength(1);
566
622
  });
567
623
 
624
+ describe('grouped search', () => {
625
+ const GROUPED = [
626
+ {
627
+ type: 'section' as const,
628
+ title: 'Citrus',
629
+ options: [
630
+ {value: 'orange', label: 'Orange'},
631
+ {value: 'lemon', label: 'Lemon'},
632
+ ],
633
+ },
634
+ {
635
+ type: 'section' as const,
636
+ title: 'Berries',
637
+ options: [
638
+ {value: 'strawberry', label: 'Strawberry'},
639
+ {value: 'blueberry', label: 'Blueberry'},
640
+ ],
641
+ },
642
+ ];
643
+
644
+ it('keeps the group header above matching items while searching', async () => {
645
+ const user = userEvent.setup();
646
+ render(
647
+ <MultiSelector
648
+ label="Fruit"
649
+ options={GROUPED}
650
+ value={[]}
651
+ onChange={() => {}}
652
+ hasSearch
653
+ />,
654
+ );
655
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
656
+ await user.type(screen.getByRole('combobox', h), 'orange');
657
+
658
+ expect(
659
+ screen.getByRole('group', {name: 'Citrus', ...h}),
660
+ ).toBeInTheDocument();
661
+ const options = screen.getAllByRole('option', h);
662
+ expect(options).toHaveLength(1);
663
+ expect(options[0]).toHaveTextContent('Orange');
664
+ });
665
+
666
+ it('hides a group whose items have no match', async () => {
667
+ const user = userEvent.setup();
668
+ render(
669
+ <MultiSelector
670
+ label="Fruit"
671
+ options={GROUPED}
672
+ value={[]}
673
+ onChange={() => {}}
674
+ hasSearch
675
+ />,
676
+ );
677
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
678
+ await user.type(screen.getByRole('combobox', h), 'berry');
679
+
680
+ expect(
681
+ screen.getByRole('group', {name: 'Berries', ...h}),
682
+ ).toBeInTheDocument();
683
+ expect(
684
+ screen.queryByRole('group', {name: 'Citrus', ...h}),
685
+ ).not.toBeInTheDocument();
686
+ expect(screen.getAllByRole('option', h)).toHaveLength(2);
687
+ });
688
+ });
689
+
568
690
  it('PageDown/PageUp jump the highlight to the last/first filtered option', async () => {
569
691
  const user = userEvent.setup();
570
692
  render(
@@ -645,6 +767,29 @@ describe('MultiSelector', () => {
645
767
  ).toBeInTheDocument();
646
768
  });
647
769
 
770
+ it('empty-state message is not exposed as a listbox child', async () => {
771
+ const user = userEvent.setup();
772
+ render(
773
+ <MultiSelector
774
+ label="Fruit"
775
+ options={defaultOptions}
776
+ value={[]}
777
+ onChange={() => {}}
778
+ hasSearch
779
+ />,
780
+ );
781
+
782
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
783
+ await user.type(screen.getByRole('combobox', h), 'xyz');
784
+
785
+ // role="listbox" only permits option/group children — the visual
786
+ // empty-state message must be presentational (it is announced through
787
+ // the result-count live region instead).
788
+ const listbox = screen.getByRole('listbox', h);
789
+ const empty = within(listbox).getByText('No results found');
790
+ expect(empty).toHaveAttribute('role', 'presentation');
791
+ });
792
+
648
793
  describe('result announcements', () => {
649
794
  it('announces the match count politely while searching', async () => {
650
795
  const user = userEvent.setup();
@@ -1245,3 +1390,260 @@ describe('MultiSelector', () => {
1245
1390
  });
1246
1391
  });
1247
1392
  });
1393
+
1394
+ describe('MultiSelector statusVariant forwarding', () => {
1395
+ it('defaults to attached (status renders with data-variant="attached")', () => {
1396
+ const {container} = render(
1397
+ <MultiSelector
1398
+ label="Fruit"
1399
+ options={['Apple', 'Banana']}
1400
+ value={[]}
1401
+ onChange={() => {}}
1402
+ status={{type: 'error', message: 'Required'}}
1403
+ />,
1404
+ );
1405
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1406
+ 'data-variant',
1407
+ 'attached',
1408
+ );
1409
+ });
1410
+
1411
+ it('forwards statusVariant="detached" to the underlying Field status', () => {
1412
+ const {container} = render(
1413
+ <MultiSelector
1414
+ label="Fruit"
1415
+ options={['Apple', 'Banana']}
1416
+ value={[]}
1417
+ onChange={() => {}}
1418
+ status={{type: 'error', message: 'Required'}}
1419
+ statusVariant="detached"
1420
+ />,
1421
+ );
1422
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1423
+ 'data-variant',
1424
+ 'detached',
1425
+ );
1426
+ });
1427
+ });
1428
+
1429
+ describe('MultiSelector clear icon theme target', () => {
1430
+ const ICON_OPTIONS = ['Apple', 'Banana', 'Orange'];
1431
+
1432
+ // Resolve the clear glyph span (the astryx-icon element inside the clear
1433
+ // button), independent of the theme target class.
1434
+ const getClearIcon = (): HTMLElement => {
1435
+ const button = screen.getByRole('button', {name: 'Clear all Fruit'});
1436
+ const icon = button.querySelector('.astryx-icon');
1437
+ if (icon == null) {
1438
+ throw new Error('clear icon not found');
1439
+ }
1440
+ return icon as HTMLElement;
1441
+ };
1442
+
1443
+ it('renders the astryx-multi-selector-clear-icon target on the clear glyph', () => {
1444
+ render(
1445
+ <MultiSelector
1446
+ label="Fruit"
1447
+ options={ICON_OPTIONS}
1448
+ value={['Banana']}
1449
+ onChange={() => {}}
1450
+ hasClear
1451
+ />,
1452
+ );
1453
+ // The stable theme target lands on the icon element itself (not the
1454
+ // button), so a theme can restyle just this glyph (color, size, hover)
1455
+ // via `defineTheme` — a button-level target could not reach the icon's
1456
+ // own color/size.
1457
+ const icon = getClearIcon();
1458
+ expect(icon).toHaveClass('astryx-multi-selector-clear-icon');
1459
+ expect(icon).toHaveClass('astryx-icon');
1460
+ });
1461
+
1462
+ it('keeps the clear button functional alongside the target', () => {
1463
+ const onChange = vi.fn();
1464
+ render(
1465
+ <MultiSelector
1466
+ label="Fruit"
1467
+ options={ICON_OPTIONS}
1468
+ value={['Banana']}
1469
+ onChange={onChange}
1470
+ hasClear
1471
+ />,
1472
+ );
1473
+ const clear = screen.getByRole('button', {name: 'Clear all Fruit'});
1474
+ expect(clear.tagName).toBe('BUTTON');
1475
+ fireEvent.click(clear);
1476
+ expect(onChange).toHaveBeenCalledWith([]);
1477
+ });
1478
+
1479
+ it('renders the default icon (secondary color, sm size) byte-identically', () => {
1480
+ // Pixel-identical default guard: the clear glyph must carry the exact same
1481
+ // StyleX color/size classes as a standalone secondary/sm icon. The added
1482
+ // target class is purely additive — it changes nothing until a theme
1483
+ // targets it.
1484
+ render(
1485
+ <MultiSelector
1486
+ label="Fruit"
1487
+ options={ICON_OPTIONS}
1488
+ value={['Banana']}
1489
+ onChange={() => {}}
1490
+ hasClear
1491
+ />,
1492
+ );
1493
+ const icon = getClearIcon();
1494
+
1495
+ const {container: refContainer} = render(
1496
+ <Icon icon="close" size="sm" color="secondary" />,
1497
+ );
1498
+ const refIcon = refContainer.querySelector('.astryx-icon') as HTMLElement;
1499
+
1500
+ const styleClasses = (el: HTMLElement) =>
1501
+ el.className
1502
+ .split(' ')
1503
+ .filter(c => c !== 'astryx-multi-selector-clear-icon')
1504
+ .sort();
1505
+
1506
+ expect(styleClasses(icon)).toEqual(styleClasses(refIcon));
1507
+ });
1508
+
1509
+ it('exposes multi-selector-clear-icon so a theme reaches the icon color, size, and hover', () => {
1510
+ // jsdom cannot resolve the @layer cascade, so the DOM-class assertion above
1511
+ // (target lands on the icon element) plus this generation assertion (the
1512
+ // theme emits same-element icon rules in @layer astryx-theme) together
1513
+ // prove the seam: a same-element theme rule wins over the icon's own
1514
+ // base-layer color/size.
1515
+ const theme = defineTheme({
1516
+ name: 'multi-selector-clear-icon-test',
1517
+ components: {
1518
+ 'multi-selector-clear-icon': {
1519
+ base: {
1520
+ width: '12px',
1521
+ height: '12px',
1522
+ fontSize: '12px',
1523
+ color: 'var(--color-icon-secondary)',
1524
+ ':hover': {color: 'var(--color-icon-primary)'},
1525
+ },
1526
+ },
1527
+ },
1528
+ });
1529
+ const css = generateThemeCSSFlat(theme);
1530
+ expect(css).toContain('.astryx-multi-selector-clear-icon {');
1531
+ expect(css).toContain('width: 12px');
1532
+ expect(css).toContain('height: 12px');
1533
+ expect(css).toContain('.astryx-multi-selector-clear-icon:hover {');
1534
+ expect(css).toContain('color: var(--color-icon-primary)');
1535
+ });
1536
+ });
1537
+
1538
+ describe('MultiSelector indicator (chevron) icon theme target', () => {
1539
+ const ICON_OPTIONS = ['Apple', 'Banana', 'Orange'];
1540
+
1541
+ const getIndicatorIcon = (container: HTMLElement): HTMLElement => {
1542
+ // The chevron is the only glyph carrying the indicator target class.
1543
+ const icon = container.querySelector(
1544
+ '.astryx-multi-selector-indicator-icon',
1545
+ );
1546
+ if (icon == null) {
1547
+ throw new Error('indicator icon not found');
1548
+ }
1549
+ return icon as HTMLElement;
1550
+ };
1551
+
1552
+ it('renders the astryx-multi-selector-indicator-icon target on the chevron glyph', () => {
1553
+ const {container} = render(
1554
+ <MultiSelector
1555
+ label="Fruit"
1556
+ options={ICON_OPTIONS}
1557
+ value={[]}
1558
+ onChange={() => {}}
1559
+ />,
1560
+ );
1561
+ // The stable theme target lands on the icon element itself (not the trigger
1562
+ // button), so a theme can restyle just this glyph (color, size, hover) —
1563
+ // and each open/closed state — via `defineTheme`. A button-level target
1564
+ // could not reach the icon's own color/size.
1565
+ const icon = getIndicatorIcon(container);
1566
+ expect(icon).toHaveClass('astryx-multi-selector-indicator-icon');
1567
+ expect(icon).toHaveClass('astryx-icon');
1568
+ // Open/closed state is reflected so a theme can target each state alone.
1569
+ expect(icon).toHaveAttribute('data-state', 'collapsed');
1570
+ });
1571
+
1572
+ it('reflects the expanded state on the chevron when the popover is open', async () => {
1573
+ const user = userEvent.setup();
1574
+ const {container} = render(
1575
+ <MultiSelector
1576
+ label="Fruit"
1577
+ options={ICON_OPTIONS}
1578
+ value={[]}
1579
+ onChange={() => {}}
1580
+ />,
1581
+ );
1582
+ await user.click(screen.getByRole('combobox'));
1583
+ await waitFor(() => {
1584
+ expect(getIndicatorIcon(container)).toHaveAttribute(
1585
+ 'data-state',
1586
+ 'expanded',
1587
+ );
1588
+ });
1589
+ });
1590
+
1591
+ it('renders the default icon (inherit color, sm size) byte-identically', () => {
1592
+ // Pixel-identical default guard: the chevron glyph must carry the exact
1593
+ // same StyleX color/size classes as a standalone inherit/sm icon. The added
1594
+ // target class + data-state are purely additive — they change nothing until
1595
+ // a theme targets them.
1596
+ const {container} = render(
1597
+ <MultiSelector
1598
+ label="Fruit"
1599
+ options={ICON_OPTIONS}
1600
+ value={[]}
1601
+ onChange={() => {}}
1602
+ />,
1603
+ );
1604
+ const icon = getIndicatorIcon(container);
1605
+
1606
+ const {container: refContainer} = render(
1607
+ <Icon icon="chevronDown" size="sm" color="inherit" />,
1608
+ );
1609
+ const refIcon = refContainer.querySelector('.astryx-icon') as HTMLElement;
1610
+
1611
+ // Exclude the additive theme-target classes (the stable target + its
1612
+ // reflected state class) so only the StyleX color/size classes remain.
1613
+ const themeTargetClasses = new Set([
1614
+ 'astryx-multi-selector-indicator-icon',
1615
+ 'collapsed',
1616
+ 'expanded',
1617
+ ]);
1618
+ const styleClasses = (el: HTMLElement) =>
1619
+ el.className
1620
+ .split(' ')
1621
+ .filter(c => !themeTargetClasses.has(c))
1622
+ .sort();
1623
+
1624
+ expect(styleClasses(icon)).toEqual(styleClasses(refIcon));
1625
+ });
1626
+
1627
+ it('exposes multi-selector-indicator-icon so a theme reaches the icon size and per-state color', () => {
1628
+ // jsdom cannot resolve the @layer cascade, so the DOM-class assertions
1629
+ // above (target lands on the icon element) plus this generation assertion
1630
+ // (the theme emits same-element icon rules in @layer astryx-theme) together
1631
+ // prove the seam: a same-element theme rule wins over the icon's own
1632
+ // base-layer color/size.
1633
+ const theme = defineTheme({
1634
+ name: 'multi-selector-indicator-icon-test',
1635
+ components: {
1636
+ 'multi-selector-indicator-icon': {
1637
+ base: {width: '14px', height: '14px', fontSize: '14px'},
1638
+ 'state:expanded': {color: 'var(--color-icon-primary)'},
1639
+ },
1640
+ },
1641
+ });
1642
+ const css = generateThemeCSSFlat(theme);
1643
+ expect(css).toContain('.astryx-multi-selector-indicator-icon {');
1644
+ expect(css).toContain('width: 14px');
1645
+ expect(css).toContain('height: 14px');
1646
+ expect(css).toContain('.astryx-multi-selector-indicator-icon.expanded');
1647
+ expect(css).toContain('color: var(--color-icon-primary)');
1648
+ });
1649
+ });