@astryxdesign/core 0.3.0 → 0.4.0

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 (551) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +10 -2
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +22 -3
  5. package/dist/AppShell/AppShell.d.ts +2 -2
  6. package/dist/AppShell/AppShell.d.ts.map +1 -1
  7. package/dist/AppShell/AppShell.js +40 -9
  8. package/dist/AspectRatio/AspectRatio.d.ts +13 -0
  9. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  10. package/dist/AspectRatio/AspectRatio.js +9 -0
  11. package/dist/Avatar/Avatar.d.ts.map +1 -1
  12. package/dist/Avatar/Avatar.js +33 -20
  13. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroupOverflow.js +2 -3
  15. package/dist/Banner/Banner.d.ts.map +1 -1
  16. package/dist/Banner/Banner.js +15 -14
  17. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  18. package/dist/Breadcrumbs/BreadcrumbItem.js +21 -8
  19. package/dist/Breadcrumbs/index.d.ts +2 -1
  20. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  21. package/dist/Breadcrumbs/index.js +1 -0
  22. package/dist/Button/Button.d.ts.map +1 -1
  23. package/dist/Button/Button.js +11 -15
  24. package/dist/Calendar/Calendar.d.ts.map +1 -1
  25. package/dist/Calendar/Calendar.js +2 -1
  26. package/dist/Calendar/styles.d.ts +0 -2
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +0 -2
  29. package/dist/Carousel/Carousel.d.ts.map +1 -1
  30. package/dist/Carousel/Carousel.js +8 -12
  31. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  32. package/dist/Chat/ChatDictationButton.js +2 -1
  33. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  34. package/dist/Chat/ChatLayoutScrollButton.js +3 -1
  35. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  36. package/dist/Chat/ChatSendButton.js +4 -3
  37. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  38. package/dist/Chat/ChatToolCalls.js +17 -17
  39. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  40. package/dist/Chat/useTriggerMenu.js +2 -6
  41. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  42. package/dist/CheckboxInput/CheckboxInput.js +36 -125
  43. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  44. package/dist/ClickableCard/ClickableCard.js +3 -11
  45. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  46. package/dist/CodeBlock/CodeBlock.js +84 -67
  47. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  48. package/dist/Collapsible/Collapsible.js +35 -15
  49. package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -1
  50. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  51. package/dist/CommandPalette/CommandPaletteItem.js +6 -3
  52. package/dist/CommandPalette/CommandPaletteList.js +1 -1
  53. package/dist/ComplexSelector/ComplexSelector.d.ts +1 -1
  54. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  55. package/dist/ComplexSelector/ComplexSelector.js +35 -33
  56. package/dist/ContextMenu/ContextMenu.d.ts +2 -2
  57. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  58. package/dist/ContextMenu/ContextMenu.js +1 -1
  59. package/dist/ContextMenu/index.d.ts +2 -1
  60. package/dist/ContextMenu/index.d.ts.map +1 -1
  61. package/dist/ContextMenu/index.js +1 -0
  62. package/dist/DateInput/DateInput.d.ts +9 -2
  63. package/dist/DateInput/DateInput.d.ts.map +1 -1
  64. package/dist/DateInput/DateInput.js +24 -23
  65. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  66. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  67. package/dist/DateRangeInput/DateRangeInput.js +11 -16
  68. package/dist/DateTimeInput/DateTimeInput.d.ts +9 -1
  69. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  70. package/dist/DateTimeInput/DateTimeInput.js +22 -17
  71. package/dist/Dialog/Dialog.d.ts.map +1 -1
  72. package/dist/Dialog/Dialog.js +4 -4
  73. package/dist/DropdownMenu/DropdownMenu.d.ts +33 -8
  74. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  75. package/dist/DropdownMenu/DropdownMenu.js +62 -20
  76. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +8 -11
  77. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +32 -31
  79. package/dist/DropdownMenu/DropdownMenuDivider.d.ts +25 -0
  80. package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -0
  81. package/dist/DropdownMenu/DropdownMenuDivider.js +66 -0
  82. package/dist/DropdownMenu/DropdownMenuItem.d.ts +15 -2
  83. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuItem.js +20 -8
  85. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +5 -5
  86. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  87. package/dist/DropdownMenu/DropdownMenuRadioItem.js +24 -67
  88. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  89. package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -8
  90. package/dist/DropdownMenu/index.d.ts +2 -1
  91. package/dist/DropdownMenu/index.d.ts.map +1 -1
  92. package/dist/DropdownMenu/index.js +4 -0
  93. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  94. package/dist/DropdownMenu/renderDropdownItems.js +35 -27
  95. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  96. package/dist/EmptyState/EmptyState.js +9 -5
  97. package/dist/Field/InputClearButton.d.ts +16 -3
  98. package/dist/Field/InputClearButton.d.ts.map +1 -1
  99. package/dist/Field/InputClearButton.js +15 -4
  100. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  101. package/dist/HoverCard/useHoverCard.js +3 -19
  102. package/dist/Indicator/CheckIndicator.d.ts +25 -0
  103. package/dist/Indicator/CheckIndicator.d.ts.map +1 -0
  104. package/dist/Indicator/CheckIndicator.js +155 -0
  105. package/dist/Indicator/CheckboxIndicator.d.ts +22 -0
  106. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -0
  107. package/dist/Indicator/CheckboxIndicator.js +173 -0
  108. package/dist/Indicator/RadioIndicator.d.ts +23 -0
  109. package/dist/Indicator/RadioIndicator.d.ts.map +1 -0
  110. package/dist/Indicator/RadioIndicator.js +137 -0
  111. package/dist/Indicator/index.d.ts +24 -0
  112. package/dist/Indicator/index.d.ts.map +1 -0
  113. package/dist/Indicator/index.js +26 -0
  114. package/dist/Indicator/indicator.markers.stylex.d.ts +16 -0
  115. package/dist/Indicator/indicator.markers.stylex.d.ts.map +1 -0
  116. package/dist/Indicator/indicator.markers.stylex.js +21 -0
  117. package/dist/Indicator/indicatorRegistry.d.ts +71 -0
  118. package/dist/Indicator/indicatorRegistry.d.ts.map +1 -0
  119. package/dist/Indicator/indicatorRegistry.js +93 -0
  120. package/dist/Indicator/types.d.ts +167 -0
  121. package/dist/Indicator/types.d.ts.map +1 -0
  122. package/dist/Indicator/types.js +1 -0
  123. package/dist/Indicator/useIndicator.d.ts +18 -0
  124. package/dist/Indicator/useIndicator.d.ts.map +1 -0
  125. package/dist/Indicator/useIndicator.js +30 -0
  126. package/dist/Item/Item.d.ts.map +1 -1
  127. package/dist/Item/Item.js +4 -8
  128. package/dist/Layer/useLayer.d.ts +14 -0
  129. package/dist/Layer/useLayer.d.ts.map +1 -1
  130. package/dist/Layer/useLayer.js +25 -2
  131. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  132. package/dist/Lightbox/Lightbox.js +56 -53
  133. package/dist/Link/Link.d.ts.map +1 -1
  134. package/dist/Link/Link.js +4 -5
  135. package/dist/MobileNav/MobileNav.js +8 -8
  136. package/dist/MoreMenu/MoreMenu.d.ts +14 -1
  137. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  138. package/dist/MoreMenu/MoreMenu.js +4 -0
  139. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  140. package/dist/MultiSelector/MultiSelector.js +78 -75
  141. package/dist/NumberInput/NumberInput.d.ts +27 -1
  142. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  143. package/dist/NumberInput/NumberInput.js +230 -42
  144. package/dist/Outline/Outline.d.ts.map +1 -1
  145. package/dist/Outline/Outline.js +2 -3
  146. package/dist/Pagination/Pagination.d.ts.map +1 -1
  147. package/dist/Pagination/Pagination.js +61 -63
  148. package/dist/Popover/Popover.d.ts.map +1 -1
  149. package/dist/Popover/Popover.js +6 -8
  150. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  151. package/dist/PowerSearch/PowerSearch.js +1 -1
  152. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  153. package/dist/PowerSearch/PowerSearchEditPopover.js +7 -0
  154. package/dist/ProgressBar/ProgressBar.d.ts +11 -4
  155. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  156. package/dist/ProgressBar/ProgressBar.js +96 -6
  157. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  158. package/dist/RadioList/RadioListItem.js +29 -84
  159. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  160. package/dist/Resizable/ResizeHandle.js +2 -3
  161. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  162. package/dist/SegmentedControl/SegmentedControlItem.js +2 -3
  163. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  164. package/dist/SelectableCard/SelectableCard.js +3 -11
  165. package/dist/Selector/Selector.d.ts +2 -1
  166. package/dist/Selector/Selector.d.ts.map +1 -1
  167. package/dist/Selector/Selector.js +164 -94
  168. package/dist/Selector/hooks.d.ts +18 -6
  169. package/dist/Selector/hooks.d.ts.map +1 -1
  170. package/dist/Selector/hooks.js +57 -40
  171. package/dist/SideNav/SideNav.d.ts.map +1 -1
  172. package/dist/SideNav/SideNav.js +1 -1
  173. package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
  174. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  175. package/dist/SideNav/SideNavCollapseButton.js +29 -14
  176. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  177. package/dist/SideNav/SideNavHeading.js +56 -20
  178. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  179. package/dist/SideNav/SideNavItem.js +28 -22
  180. package/dist/Stack/stack.stylex.d.ts +3 -3
  181. package/dist/Switch/Switch.js +11 -10
  182. package/dist/TabList/Tab.d.ts.map +1 -1
  183. package/dist/TabList/Tab.js +2 -3
  184. package/dist/TabList/TabMenu.d.ts.map +1 -1
  185. package/dist/TabList/TabMenu.js +41 -19
  186. package/dist/Table/BaseTable.d.ts.map +1 -1
  187. package/dist/Table/BaseTable.js +8 -0
  188. package/dist/Table/index.d.ts +1 -1
  189. package/dist/Table/index.d.ts.map +1 -1
  190. package/dist/Table/index.js +1 -1
  191. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
  192. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  193. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +22 -18
  194. package/dist/Table/plugins/rowExpansion/index.d.ts +1 -1
  195. package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -1
  196. package/dist/Table/plugins/rowExpansion/index.js +1 -1
  197. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +41 -76
  198. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  199. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +94 -345
  200. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  201. package/dist/Table/plugins/sortable/useTableSortable.js +23 -4
  202. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  203. package/dist/Table/plugins/tree/useTableTreeData.js +29 -33
  204. package/dist/Table/tableContextMenu.d.ts.map +1 -1
  205. package/dist/Table/tableContextMenu.js +2 -1
  206. package/dist/Table/types.d.ts +11 -0
  207. package/dist/Table/types.d.ts.map +1 -1
  208. package/dist/TextArea/TextArea.d.ts +10 -1
  209. package/dist/TextArea/TextArea.d.ts.map +1 -1
  210. package/dist/TextArea/TextArea.js +16 -6
  211. package/dist/TextInput/TextInput.d.ts +10 -1
  212. package/dist/TextInput/TextInput.d.ts.map +1 -1
  213. package/dist/TextInput/TextInput.js +13 -19
  214. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  215. package/dist/Thumbnail/Thumbnail.js +32 -26
  216. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  217. package/dist/TimeInput/TimeInput.js +7 -15
  218. package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -1
  219. package/dist/Timestamp/TimestampHoverCard.js +16 -34
  220. package/dist/Token/Token.d.ts.map +1 -1
  221. package/dist/Token/Token.js +20 -11
  222. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  223. package/dist/Tokenizer/Tokenizer.js +4 -2
  224. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  225. package/dist/Tooltip/useTooltip.js +3 -19
  226. package/dist/TopNav/TopNav.d.ts.map +1 -1
  227. package/dist/TopNav/TopNav.js +6 -5
  228. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  229. package/dist/TopNav/TopNavHeading.js +54 -16
  230. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  231. package/dist/TopNav/TopNavItem.js +3 -9
  232. package/dist/TopNav/TopNavMegaMenu.d.ts +7 -0
  233. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  234. package/dist/TopNav/TopNavMegaMenu.js +146 -60
  235. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  236. package/dist/TopNav/TopNavMegaMenuItem.js +22 -3
  237. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  238. package/dist/TopNav/TopNavMenu.js +83 -38
  239. package/dist/TreeList/TreeList.d.ts.map +1 -1
  240. package/dist/TreeList/TreeList.js +13 -0
  241. package/dist/TreeList/TreeListBranches.d.ts +1 -1
  242. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  243. package/dist/TreeList/TreeListBranches.js +14 -4
  244. package/dist/TreeList/TreeListItem.d.ts +11 -1
  245. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  246. package/dist/TreeList/TreeListItem.js +57 -30
  247. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  248. package/dist/Typeahead/BaseTypeahead.js +16 -8
  249. package/dist/astryx.css +74 -85
  250. package/dist/astryx.umd.js +56 -56
  251. package/dist/astryx.umd.js.map +4 -4
  252. package/dist/hooks/containerReveal.stylex.d.ts +61 -0
  253. package/dist/hooks/containerReveal.stylex.d.ts.map +1 -0
  254. package/dist/hooks/containerReveal.stylex.js +63 -0
  255. package/dist/hooks/index.d.ts +3 -0
  256. package/dist/hooks/index.d.ts.map +1 -1
  257. package/dist/hooks/index.js +2 -0
  258. package/dist/hooks/useClipboard.d.ts +59 -0
  259. package/dist/hooks/useClipboard.d.ts.map +1 -0
  260. package/dist/hooks/useClipboard.js +106 -0
  261. package/dist/hooks/useContainerReveal.d.ts +14 -8
  262. package/dist/hooks/useContainerReveal.d.ts.map +1 -1
  263. package/dist/hooks/useContainerReveal.js +28 -69
  264. package/dist/hooks/useIndicatorFocusRing.d.ts +28 -0
  265. package/dist/hooks/useIndicatorFocusRing.d.ts.map +1 -0
  266. package/dist/hooks/useIndicatorFocusRing.js +96 -0
  267. package/dist/hooks/useLongPress.d.ts.map +1 -1
  268. package/dist/hooks/useLongPress.js +12 -2
  269. package/dist/hooks/useScrollLock.d.ts.map +1 -1
  270. package/dist/hooks/useScrollLock.js +33 -18
  271. package/dist/hooks/useStreamingText.d.ts +18 -3
  272. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  273. package/dist/hooks/useStreamingText.js +47 -7
  274. package/dist/hooks/useTreeFocus.d.ts.map +1 -1
  275. package/dist/hooks/useTreeFocus.js +9 -3
  276. package/dist/hooks/useTypeahead.d.ts +3 -2
  277. package/dist/hooks/useTypeahead.d.ts.map +1 -1
  278. package/dist/hooks/useTypeahead.js +19 -7
  279. package/dist/index.d.ts +1 -0
  280. package/dist/index.d.ts.map +1 -1
  281. package/dist/index.js +1 -0
  282. package/dist/theme/defineTheme.d.ts +16 -0
  283. package/dist/theme/defineTheme.d.ts.map +1 -1
  284. package/dist/theme/defineTheme.js +8 -0
  285. package/dist/theme/derivedVarRegistry.d.ts +8 -0
  286. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  287. package/dist/theme/derivedVarRegistry.js +14 -13
  288. package/dist/theme/expandColorScale.d.ts +3 -1
  289. package/dist/theme/expandColorScale.d.ts.map +1 -1
  290. package/dist/theme/expandColorScale.js +17 -7
  291. package/dist/theme/expandTypeScale.d.ts.map +1 -1
  292. package/dist/theme/expandTypeScale.js +17 -0
  293. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  294. package/dist/theme/generateThemeRules.js +11 -0
  295. package/dist/theme/index.d.ts +1 -0
  296. package/dist/theme/index.d.ts.map +1 -1
  297. package/dist/utils/focusOutline.stylex.d.ts +107 -0
  298. package/dist/utils/focusOutline.stylex.d.ts.map +1 -0
  299. package/dist/utils/focusOutline.stylex.js +130 -0
  300. package/dist/utils/focusReturn.d.ts +24 -0
  301. package/dist/utils/focusReturn.d.ts.map +1 -0
  302. package/dist/utils/focusReturn.js +29 -0
  303. package/dist/utils/index.d.ts +1 -0
  304. package/dist/utils/index.d.ts.map +1 -1
  305. package/dist/utils/index.js +1 -0
  306. package/dist/utils/mergeRefs.d.ts.map +1 -1
  307. package/dist/utils/mergeRefs.js +7 -5
  308. package/dist/utils/rtlStyles.d.ts +2 -2
  309. package/dist/utils/rtlStyles.js +2 -2
  310. package/dist/utils/themeProps.d.ts +20 -1
  311. package/dist/utils/themeProps.d.ts.map +1 -1
  312. package/dist/utils/themeProps.js +8 -2
  313. package/locales/en.json +12 -0
  314. package/locales/pseudo.json +9 -0
  315. package/package.json +7 -2
  316. package/src/AlertDialog/AlertDialog.doc.mjs +16 -3
  317. package/src/AlertDialog/AlertDialog.test.tsx +208 -1
  318. package/src/AlertDialog/AlertDialog.tsx +21 -3
  319. package/src/AppShell/AppShell.doc.mjs +11 -0
  320. package/src/AppShell/AppShell.test.tsx +139 -0
  321. package/src/AppShell/AppShell.tsx +32 -22
  322. package/src/AspectRatio/AspectRatio.doc.mjs +27 -3
  323. package/src/AspectRatio/AspectRatio.test.tsx +30 -0
  324. package/src/AspectRatio/AspectRatio.tsx +13 -0
  325. package/src/Avatar/Avatar.doc.mjs +2 -13
  326. package/src/Avatar/Avatar.test.tsx +33 -8
  327. package/src/Avatar/Avatar.tsx +52 -50
  328. package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -9
  329. package/src/Banner/Banner.tsx +9 -6
  330. package/src/Breadcrumbs/BreadcrumbItem.tsx +16 -6
  331. package/src/Breadcrumbs/index.ts +5 -1
  332. package/src/Button/Button.tsx +21 -41
  333. package/src/Calendar/Calendar.tsx +2 -1
  334. package/src/Calendar/styles.ts +0 -8
  335. package/src/Carousel/Carousel.doc.mjs +3 -0
  336. package/src/Carousel/Carousel.tsx +10 -6
  337. package/src/Chat/Chat.doc.mjs +2 -0
  338. package/src/Chat/ChatDictationButton.tsx +7 -1
  339. package/src/Chat/ChatLayoutScrollButton.test.tsx +22 -0
  340. package/src/Chat/ChatLayoutScrollButton.tsx +8 -1
  341. package/src/Chat/ChatSendButton.tsx +2 -3
  342. package/src/Chat/ChatToolCalls.test.tsx +35 -0
  343. package/src/Chat/ChatToolCalls.tsx +36 -16
  344. package/src/Chat/useTriggerMenu.tsx +2 -5
  345. package/src/CheckboxInput/CheckboxInput.doc.mjs +4 -2
  346. package/src/CheckboxInput/CheckboxInput.test.tsx +115 -0
  347. package/src/CheckboxInput/CheckboxInput.tsx +45 -202
  348. package/src/ClickableCard/ClickableCard.tsx +6 -11
  349. package/src/CodeBlock/CodeBlock.doc.mjs +3 -0
  350. package/src/CodeBlock/CodeBlock.test.tsx +91 -0
  351. package/src/CodeBlock/CodeBlock.tsx +57 -80
  352. package/src/Collapsible/Collapsible.tsx +22 -18
  353. package/src/CommandPalette/CommandPalette.test.tsx +29 -0
  354. package/src/CommandPalette/CommandPaletteItem.tsx +7 -4
  355. package/src/CommandPalette/CommandPaletteList.tsx +2 -2
  356. package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
  357. package/src/ComplexSelector/ComplexSelector.test.tsx +64 -0
  358. package/src/ComplexSelector/ComplexSelector.tsx +46 -29
  359. package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
  360. package/src/ContextMenu/ContextMenu.test.tsx +41 -0
  361. package/src/ContextMenu/ContextMenu.tsx +3 -3
  362. package/src/ContextMenu/index.ts +5 -1
  363. package/src/DateInput/DateInput.doc.mjs +18 -3
  364. package/src/DateInput/DateInput.test.tsx +93 -11
  365. package/src/DateInput/DateInput.tsx +41 -19
  366. package/src/DateRangeInput/DateRangeInput.doc.mjs +10 -2
  367. package/src/DateRangeInput/DateRangeInput.test.tsx +110 -14
  368. package/src/DateRangeInput/DateRangeInput.tsx +24 -12
  369. package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -2
  370. package/src/DateTimeInput/DateTimeInput.test.tsx +75 -0
  371. package/src/DateTimeInput/DateTimeInput.tsx +35 -8
  372. package/src/Dialog/Dialog.tsx +2 -9
  373. package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -9
  374. package/src/DropdownMenu/DropdownMenu.test.tsx +534 -4
  375. package/src/DropdownMenu/DropdownMenu.tsx +113 -52
  376. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +27 -30
  377. package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +34 -0
  378. package/src/DropdownMenu/DropdownMenuDivider.tsx +81 -0
  379. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +39 -4
  380. package/src/DropdownMenu/DropdownMenuItem.tsx +48 -10
  381. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +30 -76
  382. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +25 -19
  383. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +44 -14
  384. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +1 -5
  385. package/src/DropdownMenu/index.ts +8 -1
  386. package/src/DropdownMenu/renderDropdownItems.tsx +33 -34
  387. package/src/EmptyState/EmptyState.doc.mjs +4 -0
  388. package/src/EmptyState/EmptyState.test.tsx +62 -0
  389. package/src/EmptyState/EmptyState.tsx +16 -6
  390. package/src/Field/Field.doc.mjs +1 -0
  391. package/src/Field/InputClearButton.test.tsx +117 -0
  392. package/src/Field/InputClearButton.tsx +30 -3
  393. package/src/HoverCard/useHoverCard.tsx +2 -23
  394. package/src/Icon/Icon.doc.mjs +2 -1
  395. package/src/Indicator/CheckIndicator.tsx +174 -0
  396. package/src/Indicator/CheckboxIndicator.tsx +257 -0
  397. package/src/Indicator/Indicator.doc.mjs +344 -0
  398. package/src/Indicator/Indicator.test.tsx +393 -0
  399. package/src/Indicator/RadioIndicator.tsx +206 -0
  400. package/src/Indicator/index.ts +45 -0
  401. package/src/Indicator/indicator.markers.stylex.ts +19 -0
  402. package/src/Indicator/indicatorRegistry.test.tsx +106 -0
  403. package/src/Indicator/indicatorRegistry.ts +120 -0
  404. package/src/Indicator/types.ts +186 -0
  405. package/src/Indicator/useIndicator.ts +39 -0
  406. package/src/Item/Item.doc.mjs +1 -1
  407. package/src/Item/Item.tsx +7 -14
  408. package/src/Layer/useLayer.doc.mjs +2 -2
  409. package/src/Layer/useLayer.test.tsx +85 -0
  410. package/src/Layer/useLayer.tsx +39 -1
  411. package/src/Lightbox/Lightbox.doc.mjs +1 -1
  412. package/src/Lightbox/Lightbox.tsx +43 -38
  413. package/src/Link/Link.tsx +4 -11
  414. package/src/MobileNav/MobileNav.tsx +3 -3
  415. package/src/MoreMenu/MoreMenu.doc.mjs +31 -0
  416. package/src/MoreMenu/MoreMenu.test.tsx +68 -1
  417. package/src/MoreMenu/MoreMenu.tsx +19 -0
  418. package/src/MultiSelector/MultiSelector.doc.mjs +9 -1
  419. package/src/MultiSelector/MultiSelector.test.tsx +255 -16
  420. package/src/MultiSelector/MultiSelector.tsx +103 -99
  421. package/src/NumberInput/NumberInput.doc.mjs +265 -50
  422. package/src/NumberInput/NumberInput.test.tsx +726 -21
  423. package/src/NumberInput/NumberInput.tsx +353 -59
  424. package/src/Outline/Outline.tsx +2 -5
  425. package/src/Pagination/Pagination.doc.mjs +1 -1
  426. package/src/Pagination/Pagination.test.tsx +22 -7
  427. package/src/Pagination/Pagination.tsx +38 -35
  428. package/src/Popover/Popover.tsx +6 -7
  429. package/src/PowerSearch/PowerSearch.tsx +1 -1
  430. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +42 -0
  431. package/src/PowerSearch/PowerSearchEditPopover.tsx +7 -0
  432. package/src/ProgressBar/ProgressBar.doc.mjs +27 -5
  433. package/src/ProgressBar/ProgressBar.test.tsx +224 -1
  434. package/src/ProgressBar/ProgressBar.tsx +124 -22
  435. package/src/RadioList/RadioList.doc.mjs +4 -2
  436. package/src/RadioList/RadioListItem.tsx +31 -130
  437. package/src/Resizable/ResizeHandle.tsx +2 -9
  438. package/src/SegmentedControl/SegmentedControlItem.tsx +2 -9
  439. package/src/SelectableCard/SelectableCard.tsx +4 -9
  440. package/src/Selector/Selector.doc.mjs +7 -4
  441. package/src/Selector/Selector.test.tsx +935 -25
  442. package/src/Selector/Selector.tsx +189 -106
  443. package/src/Selector/hooks.ts +77 -50
  444. package/src/SideNav/SideNav.test.tsx +46 -0
  445. package/src/SideNav/SideNav.tsx +1 -0
  446. package/src/SideNav/SideNavCollapseButton.tsx +15 -10
  447. package/src/SideNav/SideNavHeading.tsx +48 -10
  448. package/src/SideNav/SideNavItem.tsx +20 -12
  449. package/src/Stack/Stack.doc.mjs +110 -0
  450. package/src/StatusDot/StatusDot.doc.mjs +12 -3
  451. package/src/Switch/Switch.test.tsx +32 -0
  452. package/src/Switch/Switch.tsx +8 -8
  453. package/src/TabList/Tab.tsx +2 -9
  454. package/src/TabList/TabMenu.tsx +14 -21
  455. package/src/Table/BaseTable.tsx +11 -0
  456. package/src/Table/index.ts +1 -4
  457. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +30 -14
  458. package/src/Table/plugins/rowExpansion/index.ts +1 -4
  459. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +125 -175
  460. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +115 -458
  461. package/src/Table/plugins/sortable/useTableSortable.tsx +2 -6
  462. package/src/Table/plugins/tree/useTableTreeData.tsx +43 -24
  463. package/src/Table/tableContextMenu.test.tsx +27 -0
  464. package/src/Table/tableContextMenu.tsx +1 -0
  465. package/src/Table/types.ts +11 -0
  466. package/src/Table/useTableGroupedRows.doc.mjs +1 -1
  467. package/src/Table/useTableRowExpansion.doc.mjs +43 -66
  468. package/src/TextArea/TextArea.doc.mjs +42 -2
  469. package/src/TextArea/TextArea.test.tsx +219 -0
  470. package/src/TextArea/TextArea.tsx +34 -7
  471. package/src/TextInput/TextInput.doc.mjs +18 -2
  472. package/src/TextInput/TextInput.test.tsx +189 -0
  473. package/src/TextInput/TextInput.tsx +25 -31
  474. package/src/Thumbnail/Thumbnail.tsx +2 -9
  475. package/src/TimeInput/TimeInput.doc.mjs +2 -2
  476. package/src/TimeInput/TimeInput.test.tsx +30 -3
  477. package/src/TimeInput/TimeInput.tsx +9 -26
  478. package/src/Timestamp/Timestamp.doc.mjs +4 -3
  479. package/src/Timestamp/TimestampHoverCard.tsx +13 -35
  480. package/src/Token/Token.tsx +5 -28
  481. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  482. package/src/Tokenizer/Tokenizer.test.tsx +45 -3
  483. package/src/Tokenizer/Tokenizer.tsx +10 -2
  484. package/src/Tooltip/useTooltip.tsx +2 -23
  485. package/src/TopNav/TopNav.tsx +1 -3
  486. package/src/TopNav/TopNavHeading.tsx +42 -13
  487. package/src/TopNav/TopNavItem.tsx +3 -21
  488. package/src/TopNav/TopNavMegaMenu.test.tsx +433 -33
  489. package/src/TopNav/TopNavMegaMenu.tsx +118 -53
  490. package/src/TopNav/TopNavMegaMenuItem.tsx +2 -9
  491. package/src/TopNav/TopNavMenu.tsx +34 -37
  492. package/src/TreeList/TreeList.doc.mjs +5 -0
  493. package/src/TreeList/TreeList.test.tsx +206 -7
  494. package/src/TreeList/TreeList.tsx +22 -0
  495. package/src/TreeList/TreeListBranches.tsx +25 -2
  496. package/src/TreeList/TreeListItem.tsx +89 -52
  497. package/src/Typeahead/BaseTypeahead.tsx +19 -6
  498. package/src/Typeahead/Typeahead.doc.mjs +1 -0
  499. package/src/Typeahead/Typeahead.test.tsx +76 -3
  500. package/src/hooks/containerReveal.stylex.ts +102 -0
  501. package/src/hooks/index.ts +4 -0
  502. package/src/hooks/useClipboard.doc.mjs +87 -0
  503. package/src/hooks/useClipboard.test.tsx +151 -0
  504. package/src/hooks/useClipboard.ts +135 -0
  505. package/src/hooks/useContainerReveal.doc.mjs +7 -7
  506. package/src/hooks/useContainerReveal.test.tsx +42 -62
  507. package/src/hooks/useContainerReveal.ts +36 -91
  508. package/src/hooks/useImageMode.test.ts +1 -1
  509. package/src/hooks/useIndicatorFocusRing.tsx +120 -0
  510. package/src/hooks/useLongPress.test.tsx +18 -0
  511. package/src/hooks/useLongPress.ts +12 -2
  512. package/src/hooks/useScrollLock.test.ts +72 -0
  513. package/src/hooks/useScrollLock.ts +51 -19
  514. package/src/hooks/useStreamingText.test.ts +46 -1
  515. package/src/hooks/useStreamingText.ts +49 -7
  516. package/src/hooks/useTreeFocus.test.tsx +50 -0
  517. package/src/hooks/useTreeFocus.ts +14 -3
  518. package/src/hooks/useTypeahead.test.tsx +150 -0
  519. package/src/hooks/useTypeahead.ts +24 -9
  520. package/src/i18n/InternationalizationProvider.doc.mjs +7 -2
  521. package/src/index.ts +1 -0
  522. package/src/theme/defineTheme.ts +24 -0
  523. package/src/theme/derivedVarRegistry.test.ts +21 -1
  524. package/src/theme/derivedVarRegistry.ts +19 -6
  525. package/src/theme/expandColorScale.test.ts +14 -0
  526. package/src/theme/expandColorScale.ts +24 -9
  527. package/src/theme/expandTypeScale.test.ts +43 -0
  528. package/src/theme/expandTypeScale.ts +17 -0
  529. package/src/theme/generateThemeRules.test.ts +61 -20
  530. package/src/theme/generateThemeRules.ts +11 -0
  531. package/src/theme/index.ts +13 -0
  532. package/src/utils/focusOutline.stylex.ts +163 -0
  533. package/src/utils/focusReturn.test.ts +42 -0
  534. package/src/utils/focusReturn.ts +31 -0
  535. package/src/utils/index.ts +1 -0
  536. package/src/utils/mergeRefs.test.ts +48 -0
  537. package/src/utils/mergeRefs.ts +12 -6
  538. package/src/utils/rtlStyles.ts +2 -2
  539. package/src/utils/themeProps.ts +26 -4
  540. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts +0 -9
  541. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts.map +0 -1
  542. package/dist/CheckboxInput/checkbox.markers.stylex.js +0 -14
  543. package/dist/RadioList/radio.markers.stylex.d.ts +0 -7
  544. package/dist/RadioList/radio.markers.stylex.d.ts.map +0 -1
  545. package/dist/RadioList/radio.markers.stylex.js +0 -12
  546. package/dist/hooks/containerReveal.pool.stylex.d.ts +0 -303
  547. package/dist/hooks/containerReveal.pool.stylex.d.ts.map +0 -1
  548. package/dist/hooks/containerReveal.pool.stylex.js +0 -292
  549. package/src/CheckboxInput/checkbox.markers.stylex.ts +0 -12
  550. package/src/RadioList/radio.markers.stylex.ts +0 -10
  551. package/src/hooks/containerReveal.pool.stylex.ts +0 -571
@@ -1509,6 +1509,29 @@ describe('MultiSelector statusVariant forwarding', () => {
1509
1509
  });
1510
1510
  });
1511
1511
 
1512
+ describe('MultiSelector empty-state theme target', () => {
1513
+ const OPTIONS = ['Apple', 'Banana', 'Cherry'];
1514
+
1515
+ it('renders the astryx-multi-selector-empty-state target on the "No results found" element', async () => {
1516
+ const user = userEvent.setup();
1517
+ const {container} = render(
1518
+ <MultiSelector
1519
+ label="Fruit"
1520
+ options={OPTIONS}
1521
+ value={[]}
1522
+ onChange={() => {}}
1523
+ hasSearch
1524
+ />,
1525
+ );
1526
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
1527
+ await user.type(screen.getByRole('combobox', h), 'xyz');
1528
+
1529
+ const empty = container.querySelector('.astryx-multi-selector-empty-state');
1530
+ expect(empty).not.toBeNull();
1531
+ expect(empty).toHaveTextContent('No results found');
1532
+ });
1533
+ });
1534
+
1512
1535
  describe('MultiSelector clear icon theme target', () => {
1513
1536
  const ICON_OPTIONS = ['Apple', 'Banana', 'Orange'];
1514
1537
 
@@ -1523,7 +1546,7 @@ describe('MultiSelector clear icon theme target', () => {
1523
1546
  return icon as HTMLElement;
1524
1547
  };
1525
1548
 
1526
- it('renders the astryx-multi-selector-clear-icon target on the clear glyph', () => {
1549
+ it('renders the astryx-input-clear-icon target (plus the legacy alias) on the clear glyph', () => {
1527
1550
  render(
1528
1551
  <MultiSelector
1529
1552
  label="Fruit"
@@ -1533,11 +1556,13 @@ describe('MultiSelector clear icon theme target', () => {
1533
1556
  hasClear
1534
1557
  />,
1535
1558
  );
1536
- // The stable theme target lands on the icon element itself (not the
1537
- // button), so a theme can restyle just this glyph (color, size, hover)
1538
- // via `defineTheme` — a button-level target could not reach the icon's
1539
- // own color/size.
1559
+ // The canonical target lands on the icon element itself (not the button),
1560
+ // so a theme can restyle just this glyph (color, size, hover) via
1561
+ // `defineTheme` — a button-level target could not reach the icon's own
1562
+ // color/size. The original per-component name rides along for a
1563
+ // deprecation window.
1540
1564
  const icon = getClearIcon();
1565
+ expect(icon).toHaveClass('astryx-input-clear-icon');
1541
1566
  expect(icon).toHaveClass('astryx-multi-selector-clear-icon');
1542
1567
  expect(icon).toHaveClass('astryx-icon');
1543
1568
  });
@@ -1559,11 +1584,13 @@ describe('MultiSelector clear icon theme target', () => {
1559
1584
  expect(onChange).toHaveBeenCalledWith([]);
1560
1585
  });
1561
1586
 
1562
- it('renders the default icon (secondary color, sm size) byte-identically', () => {
1563
- // Pixel-identical default guard: the clear glyph must carry the exact same
1564
- // StyleX color/size classes as a standalone secondary/sm icon. The added
1565
- // target class is purely additive it changes nothing until a theme
1566
- // targets it.
1587
+ it('routes the clear glyph through the shared clear button, keeping the legacy target', () => {
1588
+ // The clear affordance now composes the shared InputClearButton (a ghost
1589
+ // Button with a secondary/sm glyph), so the icon carries the canonical
1590
+ // `astryx-input-clear-icon` target andfor a deprecation window the
1591
+ // original `astryx-multi-selector-clear-icon`. Aside from those target
1592
+ // classes it matches the shared button's own `close`/`sm`/`secondary`
1593
+ // glyph exactly, so the default look is defined in one place.
1567
1594
  render(
1568
1595
  <MultiSelector
1569
1596
  label="Fruit"
@@ -1574,6 +1601,8 @@ describe('MultiSelector clear icon theme target', () => {
1574
1601
  />,
1575
1602
  );
1576
1603
  const icon = getClearIcon();
1604
+ expect(icon).toHaveClass('astryx-input-clear-icon');
1605
+ expect(icon).toHaveClass('astryx-multi-selector-clear-icon');
1577
1606
 
1578
1607
  const {container: refContainer} = render(
1579
1608
  <Icon icon="close" size="sm" color="secondary" />,
@@ -1583,7 +1612,11 @@ describe('MultiSelector clear icon theme target', () => {
1583
1612
  const styleClasses = (el: HTMLElement) =>
1584
1613
  el.className
1585
1614
  .split(' ')
1586
- .filter(c => c !== 'astryx-multi-selector-clear-icon')
1615
+ .filter(
1616
+ c =>
1617
+ c !== 'astryx-input-clear-icon' &&
1618
+ c !== 'astryx-multi-selector-clear-icon',
1619
+ )
1587
1620
  .sort();
1588
1621
 
1589
1622
  expect(styleClasses(icon)).toEqual(styleClasses(refIcon));
@@ -1671,9 +1704,12 @@ describe('MultiSelector indicator (chevron) icon theme target', () => {
1671
1704
  });
1672
1705
  });
1673
1706
 
1674
- it('renders the default icon (inherit color, sm size) byte-identically', () => {
1707
+ it('renders the default icon (secondary color, sm size) byte-identically', () => {
1675
1708
  // Pixel-identical default guard: the chevron glyph must carry the exact
1676
- // same StyleX color/size classes as a standalone inherit/sm icon. The added
1709
+ // same StyleX color/size classes as a standalone secondary/sm icon. The
1710
+ // glyph now sets --color-icon-secondary itself rather than inheriting it
1711
+ // from a wrapper span that set the same token, so the rendered color is
1712
+ // unchanged. The added
1677
1713
  // target class + data-state are purely additive — they change nothing until
1678
1714
  // a theme targets them.
1679
1715
  const {container} = render(
@@ -1687,12 +1723,12 @@ describe('MultiSelector indicator (chevron) icon theme target', () => {
1687
1723
  const icon = getIndicatorIcon(container);
1688
1724
 
1689
1725
  const {container: refContainer} = render(
1690
- <Icon icon="chevronDown" size="sm" color="inherit" />,
1726
+ <Icon icon="chevronDown" size="sm" color="secondary" />,
1691
1727
  );
1692
1728
  const refIcon = refContainer.querySelector('.astryx-icon') as HTMLElement;
1693
1729
 
1694
1730
  // Exclude the additive theme-target classes (the stable target + its
1695
- // reflected state class) so only the StyleX color/size classes remain.
1731
+ // reflected state class) so only StyleX classes remain.
1696
1732
  const themeTargetClasses = new Set([
1697
1733
  'astryx-multi-selector-indicator-icon',
1698
1734
  'collapsed',
@@ -1704,7 +1740,14 @@ describe('MultiSelector indicator (chevron) icon theme target', () => {
1704
1740
  .filter(c => !themeTargetClasses.has(c))
1705
1741
  .sort();
1706
1742
 
1707
- expect(styleClasses(icon)).toEqual(styleClasses(refIcon));
1743
+ // A superset, not an exact match: the chevron additionally carries the
1744
+ // rotation styles, which live on the glyph precisely so a theme can reach
1745
+ // the transform through the same selector as the color. The guard that
1746
+ // matters is that every color/size class of a standalone icon is still
1747
+ // present — i.e. the default look has not drifted.
1748
+ expect(styleClasses(icon)).toEqual(
1749
+ expect.arrayContaining(styleClasses(refIcon)),
1750
+ );
1708
1751
  });
1709
1752
 
1710
1753
  it('exposes multi-selector-indicator-icon so a theme reaches the icon size and per-state color', () => {
@@ -1871,3 +1914,199 @@ describe('MultiSelector search affordances', () => {
1871
1914
  expect(trigger).toHaveAttribute('aria-expanded', 'false');
1872
1915
  });
1873
1916
  });
1917
+
1918
+ describe('MultiSelector disabled state theme target', () => {
1919
+ const getSelectorRoot = (container: HTMLElement): HTMLElement => {
1920
+ const root = container.querySelector('.astryx-multi-selector');
1921
+ if (root == null) {
1922
+ throw new Error('multi-selector root not found');
1923
+ }
1924
+ return root as HTMLElement;
1925
+ };
1926
+
1927
+ it('reflects data-state="disabled" on the root when disabled', () => {
1928
+ const {container} = render(
1929
+ <MultiSelector
1930
+ label="Fruit"
1931
+ options={['Apple', 'Banana', 'Orange']}
1932
+ value={[]}
1933
+ onChange={() => {}}
1934
+ isDisabled
1935
+ />,
1936
+ );
1937
+ expect(getSelectorRoot(container)).toHaveAttribute(
1938
+ 'data-disabled',
1939
+ 'disabled',
1940
+ );
1941
+ });
1942
+
1943
+ it('omits the disabled class/attribute when enabled', () => {
1944
+ const {container} = render(
1945
+ <MultiSelector
1946
+ label="Fruit"
1947
+ options={['Apple', 'Banana', 'Orange']}
1948
+ value={[]}
1949
+ onChange={() => {}}
1950
+ />,
1951
+ );
1952
+ const root = getSelectorRoot(container);
1953
+ expect(root).not.toHaveAttribute('data-disabled');
1954
+ expect(root).not.toHaveClass('disabled');
1955
+ });
1956
+
1957
+ it('exposes the disabled state so a theme can key on it', () => {
1958
+ const theme = defineTheme({
1959
+ name: 'multi-selector-disabled-state-test',
1960
+ components: {
1961
+ 'multi-selector': {
1962
+ 'disabled:disabled': {opacity: '0.4'},
1963
+ },
1964
+ },
1965
+ });
1966
+ const css = generateThemeTestCSS(theme);
1967
+ expect(css).toContain('.astryx-multi-selector.disabled');
1968
+ expect(css).toContain('opacity: 0.4');
1969
+ });
1970
+ });
1971
+
1972
+ describe('MultiSelector dropdown option theme target', () => {
1973
+ const ROW_OPTIONS = ['Apple', 'Banana', 'Orange'];
1974
+
1975
+ it('renders astryx-multi-selector-option, with its size, on every dropdown row', async () => {
1976
+ const user = userEvent.setup();
1977
+ render(
1978
+ <MultiSelector
1979
+ label="Fruit"
1980
+ options={ROW_OPTIONS}
1981
+ value={[]}
1982
+ onChange={() => {}}
1983
+ size="lg"
1984
+ />,
1985
+ );
1986
+ await user.click(screen.getByRole('combobox'));
1987
+ const options = screen.getAllByRole('option', h);
1988
+ expect(options).toHaveLength(3);
1989
+ for (const option of options) {
1990
+ expect(option).toHaveClass('astryx-multi-selector-option');
1991
+ expect(option).toHaveClass('lg');
1992
+ expect(option).toHaveAttribute('data-size', 'lg');
1993
+ }
1994
+ });
1995
+
1996
+ it('carries the selected and disabled states a theme keys on', async () => {
1997
+ const user = userEvent.setup();
1998
+ render(
1999
+ <MultiSelector
2000
+ label="Fruit"
2001
+ options={[
2002
+ {value: 'apple', label: 'Apple'},
2003
+ {value: 'banana', label: 'Banana'},
2004
+ {value: 'orange', label: 'Orange', disabled: true},
2005
+ ]}
2006
+ value={['apple']}
2007
+ onChange={() => {}}
2008
+ />,
2009
+ );
2010
+ await user.click(screen.getByRole('combobox'));
2011
+ const [selected, plain, disabled] = screen.getAllByRole('option', h);
2012
+
2013
+ expect(selected).toHaveClass('selected');
2014
+ expect(selected).toHaveAttribute('data-selected', 'selected');
2015
+ expect(plain).not.toHaveClass('selected');
2016
+ expect(plain).not.toHaveAttribute('data-selected');
2017
+
2018
+ expect(disabled).toHaveClass('disabled');
2019
+ expect(disabled).toHaveAttribute('data-disabled', 'disabled');
2020
+ expect(plain).not.toHaveAttribute('data-disabled');
2021
+ });
2022
+
2023
+ it('marks the Select All row with the select-all state, not a separate target', async () => {
2024
+ const user = userEvent.setup();
2025
+ render(
2026
+ <MultiSelector
2027
+ label="Fruit"
2028
+ options={ROW_OPTIONS}
2029
+ value={[]}
2030
+ onChange={() => {}}
2031
+ hasSelectAll
2032
+ />,
2033
+ );
2034
+ await user.click(screen.getByRole('combobox'));
2035
+
2036
+ const [selectAllRow, ...regularRows] = screen.getAllByRole('option', h);
2037
+ expect(selectAllRow).toHaveTextContent('Select all');
2038
+ expect(selectAllRow).toHaveClass('astryx-multi-selector-option');
2039
+ expect(selectAllRow).toHaveClass('select-all');
2040
+ expect(selectAllRow).toHaveAttribute('data-select-all', 'select-all');
2041
+
2042
+ for (const row of regularRows) {
2043
+ expect(row).toHaveClass('astryx-multi-selector-option');
2044
+ expect(row).not.toHaveClass('select-all');
2045
+ expect(row).not.toHaveAttribute('data-select-all');
2046
+ }
2047
+ });
2048
+
2049
+ it('keeps the row targetable when renderOption replaces the label', async () => {
2050
+ const user = userEvent.setup();
2051
+ render(
2052
+ <MultiSelector
2053
+ label="Fruit"
2054
+ options={[{value: 'apple', label: 'Apple'}]}
2055
+ value={[]}
2056
+ onChange={() => {}}
2057
+ renderOption={option => (
2058
+ <span data-testid="custom-row">{option.label}</span>
2059
+ )}
2060
+ />,
2061
+ );
2062
+ await user.click(screen.getByRole('combobox'));
2063
+ const option = screen.getAllByRole('option', h)[0];
2064
+ // The row owns the typography, so custom content inherits the same
2065
+ // treatment the fallback label gets — and one row override reaches both.
2066
+ expect(option).toHaveClass('astryx-multi-selector-option');
2067
+ expect(within(option).getByTestId('custom-row')).toHaveTextContent('Apple');
2068
+ });
2069
+
2070
+ it('exposes the row target, its states and its size to defineTheme', () => {
2071
+ const theme = defineTheme({
2072
+ name: 'multi-selector-option-target-test',
2073
+ components: {
2074
+ 'multi-selector-option': {
2075
+ base: {borderRadius: '8px', fontWeight: '600'},
2076
+ selected: {backgroundColor: 'var(--color-background-muted)'},
2077
+ 'select-all': {fontWeight: '700'},
2078
+ 'size:lg': {borderRadius: '12px'},
2079
+ },
2080
+ },
2081
+ });
2082
+ const css = generateThemeTestCSS(theme);
2083
+ expect(css).toContain('.astryx-multi-selector-option {');
2084
+ expect(css).toContain('.astryx-multi-selector-option.selected');
2085
+ expect(css).toContain('.astryx-multi-selector-option.select-all');
2086
+ expect(css).toContain('.astryx-multi-selector-option.lg');
2087
+ });
2088
+ });
2089
+
2090
+ describe('MultiSelector popup theme target', () => {
2091
+ it('puts astryx-multi-selector-popup on the dropdown box inside the layer', async () => {
2092
+ const user = userEvent.setup();
2093
+ render(
2094
+ <MultiSelector
2095
+ label="Fruit"
2096
+ options={['Apple', 'Banana']}
2097
+ value={[]}
2098
+ onChange={() => {}}
2099
+ />,
2100
+ );
2101
+ await user.click(screen.getByRole('combobox', {name: /Fruit/}));
2102
+
2103
+ const layer = document.querySelector('[popover]') as HTMLElement;
2104
+ const popup = document.querySelector(
2105
+ '.astryx-multi-selector-popup',
2106
+ ) as HTMLElement;
2107
+ expect(popup).not.toBeNull();
2108
+ expect(popup).not.toBe(layer);
2109
+ expect(layer.contains(popup)).toBe(true);
2110
+ expect(popup.querySelector('[role="listbox"]')).not.toBeNull();
2111
+ });
2112
+ });
@@ -34,6 +34,7 @@ import {Icon, renderIconSlot, type IconType} from '../Icon';
34
34
  import type {IconName} from '../Icon';
35
35
  import {
36
36
  Field,
37
+ InputClearButton,
37
38
  inputStatusBorderStyles,
38
39
  inputStatusHoverShadowStyles,
39
40
  inputWrapperStyles,
@@ -75,6 +76,7 @@ import type {BaseProps} from '../BaseProps';
75
76
  import type {SizeValue} from '../utils/types';
76
77
  import {useSize} from '../SizeContext/SizeContext';
77
78
  import {themeProps} from '../utils/themeProps';
79
+ import {stableClassName} from '../naming';
78
80
  import {groupStyles} from '../InputGroup/groupStyles';
79
81
  import {useInputGroup} from '../InputGroup/InputGroupContext';
80
82
  import {VisuallyHidden} from '../VisuallyHidden';
@@ -158,25 +160,27 @@ const styles = stylex.create({
158
160
  color: colorVars['--color-text-secondary'],
159
161
  fontWeight: fontWeightVars['--font-weight-medium'],
160
162
  },
163
+ // Only what Icon does not already provide: `size="sm"` gives the 16px box
164
+ // and `color` the token, but the glyph still must not shrink inside the flex
165
+ // trigger.
161
166
  triggerIcon: {
162
167
  flexShrink: 0,
163
- display: 'flex',
164
- alignItems: 'center',
165
- justifyContent: 'center',
166
- width: 16,
167
- height: 16,
168
+ },
169
+ // Rotation lives on the chevron glyph itself (passed through `xstyle`), not
170
+ // on the layout wrapper above, so the icon's `multi-selector-indicator-icon`
171
+ // theme target and the open/closed transform sit on one element — a theme can
172
+ // restyle the mark and its rotation through a single selector. The wrapper
173
+ // keeps only layout. The status branch renders a different icon, so it never
174
+ // picks these up and needs no transition opt-out.
175
+ triggerIconRotation: {
168
176
  transitionProperty: 'transform',
169
177
  transitionDuration: durationVars['--duration-fast'],
170
178
  transitionTimingFunction: easeVars['--ease-standard'],
171
179
  transformOrigin: 'center',
172
- color: colorVars['--color-icon-secondary'],
173
180
  },
174
181
  triggerIconOpen: {
175
182
  transform: 'rotate(180deg)',
176
183
  },
177
- triggerIconStatus: {
178
- transition: 'none',
179
- },
180
184
  triggerGhost: {
181
185
  width: 'auto',
182
186
  borderWidth: 0,
@@ -220,23 +224,6 @@ const styles = stylex.create({
220
224
  },
221
225
 
222
226
  // Clear button
223
- clearButton: {
224
- display: 'flex',
225
- alignItems: 'center',
226
- justifyContent: 'center',
227
- padding: 0,
228
- margin: 0,
229
- borderWidth: 0,
230
- borderStyle: 'none',
231
- backgroundColor: 'transparent',
232
- cursor: 'pointer',
233
- borderRadius: radiusVars['--radius-element'],
234
- outline: {
235
- default: 'none',
236
- ':focus-visible': `${borderVars['--border-width']} solid ${colorVars['--color-accent']}`,
237
- },
238
- outlineOffset: 1,
239
- },
240
227
  statusButton: {
241
228
  display: 'flex',
242
229
  alignItems: 'center',
@@ -267,7 +254,6 @@ const styles = stylex.create({
267
254
  // Popover container (for anchor positioning)
268
255
  popover: {
269
256
  minWidth: 'anchor-size(width)',
270
- marginBlockStart: spacingVars['--spacing-1'],
271
257
  },
272
258
 
273
259
  // Search field. The inner TextInput owns the border, focus ring, magnifier
@@ -307,6 +293,14 @@ const styles = stylex.create({
307
293
  width: '100%',
308
294
  borderRadius: radiusVars['--radius-element'],
309
295
  cursor: 'pointer',
296
+ // Row typography lives here, not on the label span, so a theme override on
297
+ // the row target reaches both the fallback label and renderOption output
298
+ // (a declaration on the span would win over the inherited row value).
299
+ // Matches Selector, whose option row owns its typography the same way.
300
+ fontFamily: typographyVars['--font-family-body'],
301
+ fontSize: typeScaleVars['--text-label-size'],
302
+ fontWeight: fontWeightVars['--font-weight-medium'],
303
+ color: colorVars['--color-text-primary'],
310
304
  backgroundColor: 'transparent',
311
305
  border: 'none',
312
306
  outline: 'none',
@@ -316,6 +310,7 @@ const styles = stylex.create({
316
310
  },
317
311
  itemDisabled: {
318
312
  opacity: 0.5,
313
+ color: colorVars['--color-text-disabled'],
319
314
  cursor: 'not-allowed',
320
315
  },
321
316
 
@@ -326,20 +321,15 @@ const styles = stylex.create({
326
321
  flexShrink: 0,
327
322
  },
328
323
 
329
- // Label text for items (rendered outside checkbox for correct click behavior)
324
+ // Label text for items (rendered outside checkbox for correct click
325
+ // behavior). Typography is inherited from the row; this only handles
326
+ // truncation.
330
327
  itemLabel: {
331
- fontFamily: typographyVars['--font-family-body'],
332
- fontSize: typeScaleVars['--text-label-size'],
333
- fontWeight: fontWeightVars['--font-weight-medium'],
334
- color: colorVars['--color-text-primary'],
335
328
  minWidth: 0,
336
329
  overflow: 'hidden',
337
330
  textOverflow: 'ellipsis',
338
331
  whiteSpace: 'nowrap',
339
332
  },
340
- itemLabelDisabled: {
341
- color: colorVars['--color-text-disabled'],
342
- },
343
333
 
344
334
  // Empty state
345
335
  emptyState: {
@@ -1264,12 +1254,24 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1264
1254
  }
1265
1255
  }}
1266
1256
  onMouseEnter={() => onItemMouseEnter(item, flatIndex)}
1267
- {...stylex.props(
1268
- styles.item,
1269
- isSelectAll ? selectAllSizeStyles[size] : itemSizeStyles[size],
1270
- isSelectAll && styles.selectAllWrapper,
1271
- isHighlighted && styles.itemHighlighted,
1272
- item.disabled && styles.itemDisabled,
1257
+ {...mergeProps(
1258
+ // One target for every dropdown row, carrying the row's size and
1259
+ // runtime state so a theme can express "selected option at large"
1260
+ // or restyle just the Select All row (`.select-all`) without
1261
+ // reaching for structural selectors.
1262
+ themeProps('multi-selector-option', {
1263
+ size,
1264
+ 'select-all': isSelectAll ? 'select-all' : null,
1265
+ selected: isSelected ? 'selected' : null,
1266
+ disabled: item.disabled ? 'disabled' : null,
1267
+ }),
1268
+ stylex.props(
1269
+ styles.item,
1270
+ isSelectAll ? selectAllSizeStyles[size] : itemSizeStyles[size],
1271
+ isSelectAll && styles.selectAllWrapper,
1272
+ isHighlighted && styles.itemHighlighted,
1273
+ item.disabled && styles.itemDisabled,
1274
+ ),
1273
1275
  )}>
1274
1276
  <div inert {...stylex.props(styles.checkboxDecorative)}>
1275
1277
  <CheckboxInput
@@ -1284,11 +1286,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1284
1286
  {renderOption && !isSelectAll ? (
1285
1287
  renderOption(item)
1286
1288
  ) : (
1287
- <span
1288
- {...stylex.props(
1289
- styles.itemLabel,
1290
- item.disabled && styles.itemLabelDisabled,
1291
- )}>
1289
+ <span {...stylex.props(styles.itemLabel)}>
1292
1290
  {item.label ?? item.value}
1293
1291
  </span>
1294
1292
  )}
@@ -1343,7 +1341,10 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1343
1341
  <div
1344
1342
  key="empty"
1345
1343
  role="presentation"
1346
- {...stylex.props(styles.emptyState)}>
1344
+ {...mergeProps(
1345
+ themeProps('multi-selector-empty-state'),
1346
+ stylex.props(styles.emptyState),
1347
+ )}>
1347
1348
  No results found
1348
1349
  </div>,
1349
1350
  );
@@ -1445,6 +1446,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1445
1446
  variant,
1446
1447
  size,
1447
1448
  status: status?.type ?? null,
1449
+ disabled: isDisabled ? 'disabled' : null,
1448
1450
  }),
1449
1451
  stylex.props(
1450
1452
  inputWrapperStyles.base,
@@ -1519,72 +1521,73 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1519
1521
  ))}
1520
1522
  {isBusy && <Spinner size="sm" />}
1521
1523
  {hasClear && value.length > 0 && !isDisabled && (
1522
- <button
1523
- type="button"
1524
+ <InputClearButton
1525
+ label={t('@astryx.multiSelector.clearAll', {label})}
1524
1526
  onClick={handleClear}
1525
- aria-label={t('@astryx.multiSelector.clearAll', {label})}
1526
- {...stylex.props(styles.clearButton)}>
1527
- <Icon
1528
- icon="close"
1529
- size="sm"
1530
- color="secondary"
1531
- // Stable theme target on the clear glyph itself, so a theme can
1532
- // restyle just this icon (color, size, hover) via `defineTheme`.
1533
- // Same-element rules in @layer astryx-theme win over the icon's
1534
- // own base color/size, which a button-level target could not
1535
- // reach.
1536
- {...themeProps('multi-selector-clear-icon')}
1537
- />
1538
- </button>
1527
+ iconClassName={stableClassName('multi-selector-clear-icon')}
1528
+ />
1539
1529
  )}
1540
- <span
1541
- {...stylex.props(
1542
- styles.triggerIcon,
1543
- !showStatusIcon && popover.isOpen && styles.triggerIconOpen,
1544
- showStatusIcon && styles.triggerIconStatus,
1545
- )}>
1546
- {showStatusIcon ? (
1547
- showStatusTooltip ? (
1548
- <button
1549
- ref={statusTooltip.ref}
1550
- type="button"
1551
- aria-label={t(STATUS_BUTTON_LABEL_KEY[status.type])}
1552
- aria-describedby={statusTooltip.describedBy}
1553
- onClick={e => e.stopPropagation()}
1554
- {...stylex.props(styles.statusButton)}>
1555
- <Icon
1556
- icon={STATUS_ICON_MAP[status.type]}
1557
- size="sm"
1558
- color={STATUS_ICON_COLOR_MAP[status.type]}
1559
- />
1560
- </button>
1561
- ) : (
1530
+ {/*
1531
+ No wrapper span: Icon's own span already provides the 16px box (`sm`)
1532
+ and the icon color, so the status glyph and the chevron are each
1533
+ directly targetable instead of sharing one untargetable parent — and
1534
+ the two affordances stop sharing a node.
1535
+ */}
1536
+ {showStatusIcon ? (
1537
+ showStatusTooltip ? (
1538
+ <button
1539
+ ref={statusTooltip.ref}
1540
+ type="button"
1541
+ aria-label={t(STATUS_BUTTON_LABEL_KEY[status.type])}
1542
+ aria-describedby={statusTooltip.describedBy}
1543
+ onClick={e => e.stopPropagation()}
1544
+ {...stylex.props(styles.statusButton)}>
1562
1545
  <Icon
1563
1546
  icon={STATUS_ICON_MAP[status.type]}
1564
1547
  size="sm"
1565
1548
  color={STATUS_ICON_COLOR_MAP[status.type]}
1549
+ xstyle={styles.triggerIcon}
1566
1550
  />
1567
- )
1551
+ </button>
1568
1552
  ) : (
1569
1553
  <Icon
1570
- icon="chevronDown"
1554
+ icon={STATUS_ICON_MAP[status.type]}
1571
1555
  size="sm"
1572
- color="inherit"
1573
- // Stable theme target on the chevron glyph itself, so a theme can
1574
- // restyle just this icon (color, size, hover) — and its
1575
- // open/closed state — via `defineTheme`. Same-element rules in
1576
- // @layer astryx-theme win over the icon's own base color/size,
1577
- // which a button-level target could not reach.
1578
- {...themeProps('multi-selector-indicator-icon', {
1579
- state: popover.isOpen ? 'expanded' : 'collapsed',
1580
- })}
1556
+ color={STATUS_ICON_COLOR_MAP[status.type]}
1557
+ xstyle={styles.triggerIcon}
1581
1558
  />
1582
- )}
1583
- </span>
1559
+ )
1560
+ ) : (
1561
+ <Icon
1562
+ icon="chevronDown"
1563
+ size="sm"
1564
+ color="secondary"
1565
+ // The rotation rides on the glyph, alongside the box and color
1566
+ // the wrapper used to provide, so one element carries the mark,
1567
+ // its open/closed transform, and the theme target.
1568
+ xstyle={[
1569
+ styles.triggerIcon,
1570
+ styles.triggerIconRotation,
1571
+ popover.isOpen && styles.triggerIconOpen,
1572
+ ]}
1573
+ // Stable theme target on the chevron glyph itself, so a theme can
1574
+ // restyle just this icon (color, size, hover) — and its
1575
+ // open/closed state — via `defineTheme`. Same-element rules in
1576
+ // @layer astryx-theme win over the icon's own base color/size,
1577
+ // which a button-level target could not reach.
1578
+ {...themeProps('multi-selector-indicator-icon', {
1579
+ state: popover.isOpen ? 'expanded' : 'collapsed',
1580
+ })}
1581
+ />
1582
+ )}
1584
1583
  </div>
1585
1584
 
1586
1585
  {popover.render(
1587
- <div {...stylex.props(styles.dropdown)}>
1586
+ <div
1587
+ {...mergeProps(
1588
+ themeProps('multi-selector-popup'),
1589
+ stylex.props(styles.dropdown),
1590
+ )}>
1588
1591
  {renderSearch()}
1589
1592
  <div
1590
1593
  id={listboxId}
@@ -1597,6 +1600,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1597
1600
  {
1598
1601
  placement: 'below',
1599
1602
  alignment: 'start',
1603
+ offset: spacingVars['--spacing-1'],
1600
1604
  xstyle: styles.popover,
1601
1605
  },
1602
1606
  )}