@astryxdesign/core 0.2.0 → 0.3.0-canary.041a0ef

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 (1168) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/README.md +5 -3
  3. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +1 -1
  5. package/dist/AppShell/AppShell.d.ts +2 -20
  6. package/dist/AppShell/AppShell.d.ts.map +1 -1
  7. package/dist/AppShell/AppShell.js +25 -18
  8. package/dist/AppShell/index.d.ts +20 -1
  9. package/dist/AppShell/index.d.ts.map +1 -1
  10. package/dist/AppShell/index.js +14 -0
  11. package/dist/AspectRatio/AspectRatio.d.ts +1 -1
  12. package/dist/AspectRatio/AspectRatio.js +1 -1
  13. package/dist/Avatar/Avatar.d.ts +1 -1
  14. package/dist/Avatar/Avatar.d.ts.map +1 -1
  15. package/dist/Avatar/Avatar.js +37 -24
  16. package/dist/Avatar/AvatarStatusDot.d.ts +2 -26
  17. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  18. package/dist/Avatar/AvatarStatusDot.js +1 -22
  19. package/dist/Avatar/index.d.ts +26 -1
  20. package/dist/Avatar/index.d.ts.map +1 -1
  21. package/dist/Avatar/index.js +21 -0
  22. package/dist/AvatarGroup/AvatarGroup.d.ts +1 -1
  23. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  24. package/dist/AvatarGroup/AvatarGroup.js +4 -8
  25. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +2 -2
  26. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  27. package/dist/AvatarGroup/AvatarGroupOverflow.js +9 -6
  28. package/dist/Badge/Badge.d.ts +2 -30
  29. package/dist/Badge/Badge.d.ts.map +1 -1
  30. package/dist/Badge/Badge.js +2 -17
  31. package/dist/Badge/index.d.ts +31 -2
  32. package/dist/Badge/index.d.ts.map +1 -1
  33. package/dist/Badge/index.js +15 -1
  34. package/dist/Banner/Banner.d.ts +2 -37
  35. package/dist/Banner/Banner.d.ts.map +1 -1
  36. package/dist/Banner/Banner.js +21 -48
  37. package/dist/Banner/index.d.ts +37 -1
  38. package/dist/Banner/index.d.ts.map +1 -1
  39. package/dist/Banner/index.js +27 -0
  40. package/dist/Blockquote/Blockquote.d.ts +1 -1
  41. package/dist/Blockquote/Blockquote.js +1 -1
  42. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +1 -1
  43. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  44. package/dist/Breadcrumbs/BreadcrumbItem.js +22 -8
  45. package/dist/Breadcrumbs/Breadcrumbs.d.ts +2 -18
  46. package/dist/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
  47. package/dist/Breadcrumbs/Breadcrumbs.js +1 -15
  48. package/dist/Breadcrumbs/index.d.ts +18 -1
  49. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  50. package/dist/Breadcrumbs/index.js +14 -0
  51. package/dist/Button/Button.d.ts +3 -21
  52. package/dist/Button/Button.d.ts.map +1 -1
  53. package/dist/Button/Button.js +17 -34
  54. package/dist/Button/index.d.ts +21 -3
  55. package/dist/Button/index.d.ts.map +1 -1
  56. package/dist/Button/index.js +15 -1
  57. package/dist/ButtonGroup/ButtonGroup.d.ts +1 -1
  58. package/dist/ButtonGroup/ButtonGroup.js +1 -1
  59. package/dist/Calendar/Calendar.d.ts.map +1 -1
  60. package/dist/Calendar/Calendar.js +3 -2
  61. package/dist/Calendar/index.d.ts +1 -1
  62. package/dist/Calendar/index.d.ts.map +1 -1
  63. package/dist/Calendar/index.js +1 -1
  64. package/dist/Calendar/styles.d.ts +2 -4
  65. package/dist/Calendar/styles.d.ts.map +1 -1
  66. package/dist/Calendar/styles.js +2 -4
  67. package/dist/Calendar/utils.d.ts +0 -4
  68. package/dist/Calendar/utils.d.ts.map +1 -1
  69. package/dist/Calendar/utils.js +1 -8
  70. package/dist/Card/Card.d.ts +1 -1
  71. package/dist/Card/Card.js +1 -1
  72. package/dist/Carousel/Carousel.d.ts +54 -3
  73. package/dist/Carousel/Carousel.d.ts.map +1 -1
  74. package/dist/Carousel/Carousel.js +90 -27
  75. package/dist/Carousel/index.d.ts +1 -1
  76. package/dist/Carousel/index.d.ts.map +1 -1
  77. package/dist/Center/Center.d.ts +21 -4
  78. package/dist/Center/Center.d.ts.map +1 -1
  79. package/dist/Center/Center.js +11 -3
  80. package/dist/Chat/ChatComposer.d.ts +1 -1
  81. package/dist/Chat/ChatComposer.js +9 -9
  82. package/dist/Chat/ChatComposerDrawer.d.ts +1 -1
  83. package/dist/Chat/ChatComposerDrawer.js +5 -5
  84. package/dist/Chat/ChatComposerInput.d.ts +1 -1
  85. package/dist/Chat/ChatComposerInput.js +1 -1
  86. package/dist/Chat/ChatDictationButton.d.ts +1 -1
  87. package/dist/Chat/ChatDictationButton.js +1 -1
  88. package/dist/Chat/ChatLayout.d.ts +8 -1
  89. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  90. package/dist/Chat/ChatLayout.js +15 -4
  91. package/dist/Chat/ChatLayoutScrollButton.d.ts +1 -1
  92. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  93. package/dist/Chat/ChatLayoutScrollButton.js +2 -1
  94. package/dist/Chat/ChatMessage.d.ts +1 -1
  95. package/dist/Chat/ChatMessage.js +1 -1
  96. package/dist/Chat/ChatMessageBubble.d.ts +1 -1
  97. package/dist/Chat/ChatMessageBubble.js +1 -1
  98. package/dist/Chat/ChatMessageList.d.ts +1 -1
  99. package/dist/Chat/ChatMessageList.js +1 -1
  100. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  101. package/dist/Chat/ChatSendButton.js +4 -2
  102. package/dist/Chat/ChatSystemMessage.d.ts +1 -1
  103. package/dist/Chat/ChatSystemMessage.js +1 -1
  104. package/dist/Chat/ChatTokenizedText.d.ts +1 -1
  105. package/dist/Chat/ChatTokenizedText.js +1 -1
  106. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  107. package/dist/Chat/ChatToolCalls.js +17 -17
  108. package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
  109. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  110. package/dist/CheckboxInput/CheckboxInput.js +3 -3
  111. package/dist/CheckboxList/CheckboxList.d.ts +1 -1
  112. package/dist/CheckboxList/CheckboxList.js +1 -1
  113. package/dist/CheckboxList/CheckboxListItem.d.ts +1 -1
  114. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  115. package/dist/CheckboxList/CheckboxListItem.js +20 -5
  116. package/dist/Citation/Citation.d.ts +1 -1
  117. package/dist/Citation/Citation.js +1 -1
  118. package/dist/ClickableCard/ClickableCard.d.ts +3 -3
  119. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  120. package/dist/ClickableCard/ClickableCard.js +6 -14
  121. package/dist/Code/Code.d.ts +2 -2
  122. package/dist/Code/Code.js +2 -2
  123. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  124. package/dist/CodeBlock/CodeBlock.js +35 -18
  125. package/dist/Collapsible/Collapsible.d.ts +1 -1
  126. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  127. package/dist/Collapsible/Collapsible.js +36 -16
  128. package/dist/Collapsible/CollapsibleGroup.d.ts +1 -1
  129. package/dist/Collapsible/CollapsibleGroup.js +1 -1
  130. package/dist/Collapsible/CollapsibleGroupContext.js +1 -1
  131. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  132. package/dist/CommandPalette/CommandPalette.js +1 -1
  133. package/dist/CommandPalette/CommandPaletteEmpty.js +1 -1
  134. package/dist/CommandPalette/CommandPaletteFooter.js +1 -1
  135. package/dist/CommandPalette/CommandPaletteGroup.js +1 -1
  136. package/dist/CommandPalette/CommandPaletteInput.d.ts +2 -2
  137. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  138. package/dist/CommandPalette/CommandPaletteInput.js +4 -2
  139. package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -1
  140. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  141. package/dist/CommandPalette/CommandPaletteList.js +1 -1
  142. package/dist/ComplexSelector/ComplexSelector.d.ts +108 -0
  143. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -0
  144. package/dist/ComplexSelector/ComplexSelector.js +310 -0
  145. package/dist/ComplexSelector/index.d.ts +7 -0
  146. package/dist/ComplexSelector/index.d.ts.map +1 -0
  147. package/dist/ComplexSelector/index.js +10 -0
  148. package/dist/ContextMenu/ContextMenu.d.ts +2 -2
  149. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  150. package/dist/ContextMenu/ContextMenu.js +24 -6
  151. package/dist/DateInput/DateInput.d.ts +9 -2
  152. package/dist/DateInput/DateInput.d.ts.map +1 -1
  153. package/dist/DateInput/DateInput.js +6 -3
  154. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  155. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  156. package/dist/DateRangeInput/DateRangeInput.js +6 -3
  157. package/dist/DateTimeInput/DateTimeInput.d.ts +9 -1
  158. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  159. package/dist/DateTimeInput/DateTimeInput.js +6 -3
  160. package/dist/Dialog/Dialog.d.ts +33 -24
  161. package/dist/Dialog/Dialog.d.ts.map +1 -1
  162. package/dist/Dialog/Dialog.js +47 -31
  163. package/dist/Dialog/DialogHeader.d.ts +1 -1
  164. package/dist/Dialog/DialogHeader.js +1 -1
  165. package/dist/Dialog/index.d.ts +18 -1
  166. package/dist/Dialog/index.d.ts.map +1 -1
  167. package/dist/Dialog/index.js +14 -0
  168. package/dist/Divider/Divider.d.ts +2 -18
  169. package/dist/Divider/Divider.d.ts.map +1 -1
  170. package/dist/Divider/Divider.js +1 -15
  171. package/dist/Divider/index.d.ts +18 -1
  172. package/dist/Divider/index.d.ts.map +1 -1
  173. package/dist/Divider/index.js +14 -0
  174. package/dist/DropdownMenu/DropdownMenu.d.ts +28 -8
  175. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  176. package/dist/DropdownMenu/DropdownMenu.js +75 -23
  177. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +18 -12
  178. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  179. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +38 -63
  180. package/dist/DropdownMenu/DropdownMenuItem.d.ts +8 -3
  181. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  182. package/dist/DropdownMenu/DropdownMenuItem.js +14 -5
  183. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
  184. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  185. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
  186. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  187. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  188. package/dist/DropdownMenu/DropdownMenuRadioItem.js +6 -2
  189. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +1 -1
  190. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  191. package/dist/DropdownMenu/DropdownMenuSubMenu.js +14 -6
  192. package/dist/DropdownMenu/menuItemHover.d.ts +1 -0
  193. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -1
  194. package/dist/DropdownMenu/menuItemHover.js +1 -0
  195. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  196. package/dist/DropdownMenu/renderDropdownItems.js +27 -16
  197. package/dist/EmptyState/EmptyState.d.ts +1 -1
  198. package/dist/EmptyState/EmptyState.js +1 -1
  199. package/dist/Field/Field.d.ts +1 -1
  200. package/dist/Field/Field.js +1 -1
  201. package/dist/Field/FieldLabel.d.ts +4 -3
  202. package/dist/Field/FieldLabel.d.ts.map +1 -1
  203. package/dist/Field/FieldLabel.js +48 -5
  204. package/dist/FieldStatus/FieldStatus.d.ts +1 -18
  205. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  206. package/dist/FieldStatus/FieldStatus.js +13 -17
  207. package/dist/FieldStatus/index.d.ts +19 -1
  208. package/dist/FieldStatus/index.d.ts.map +1 -1
  209. package/dist/FieldStatus/index.js +14 -0
  210. package/dist/FileInput/FileInput.js +1 -1
  211. package/dist/FormLayout/FormLayout.d.ts +1 -1
  212. package/dist/FormLayout/FormLayout.d.ts.map +1 -1
  213. package/dist/FormLayout/FormLayout.js +1 -1
  214. package/dist/Grid/Grid.d.ts +2 -10
  215. package/dist/Grid/Grid.d.ts.map +1 -1
  216. package/dist/Grid/Grid.js +1 -10
  217. package/dist/Grid/GridSpan.d.ts +1 -1
  218. package/dist/Grid/GridSpan.js +1 -1
  219. package/dist/HStack/HStack.d.ts +1 -1
  220. package/dist/HStack/HStack.js +1 -1
  221. package/dist/Heading/Heading.d.ts +2 -2
  222. package/dist/Heading/Heading.d.ts.map +1 -1
  223. package/dist/Heading/Heading.js +5 -4
  224. package/dist/HoverCard/HoverCard.d.ts +1 -1
  225. package/dist/HoverCard/HoverCard.js +1 -1
  226. package/dist/Icon/Icon.d.ts +1 -1
  227. package/dist/Icon/Icon.d.ts.map +1 -1
  228. package/dist/Icon/Icon.js +4 -2
  229. package/dist/Icon/defaultIcons.d.ts.map +1 -1
  230. package/dist/Icon/defaultIcons.js +14 -0
  231. package/dist/Icon/globalIconRegistry.d.ts +48 -6
  232. package/dist/Icon/globalIconRegistry.d.ts.map +1 -1
  233. package/dist/Icon/globalIconRegistry.js +74 -7
  234. package/dist/Icon/index.d.ts +4 -3
  235. package/dist/Icon/index.d.ts.map +1 -1
  236. package/dist/Icon/index.js +2 -1
  237. package/dist/Icon/useIcon.d.ts +14 -0
  238. package/dist/Icon/useIcon.d.ts.map +1 -0
  239. package/dist/Icon/useIcon.js +21 -0
  240. package/dist/IconButton/IconButton.d.ts +1 -1
  241. package/dist/IconButton/IconButton.js +1 -1
  242. package/dist/InputGroup/InputGroup.d.ts +1 -1
  243. package/dist/InputGroup/InputGroup.js +1 -1
  244. package/dist/InputGroup/InputGroupText.d.ts +1 -1
  245. package/dist/InputGroup/InputGroupText.js +1 -1
  246. package/dist/Item/Item.d.ts +17 -4
  247. package/dist/Item/Item.d.ts.map +1 -1
  248. package/dist/Item/Item.js +36 -15
  249. package/dist/Kbd/Kbd.d.ts +1 -1
  250. package/dist/Kbd/Kbd.js +1 -1
  251. package/dist/Layout/Layout.d.ts +1 -1
  252. package/dist/Layout/Layout.js +1 -1
  253. package/dist/Layout/LayoutContent.d.ts +1 -1
  254. package/dist/Layout/LayoutContent.js +1 -1
  255. package/dist/Layout/LayoutFooter.d.ts +1 -1
  256. package/dist/Layout/LayoutFooter.js +1 -1
  257. package/dist/Layout/LayoutHeader.d.ts +1 -1
  258. package/dist/Layout/LayoutHeader.js +1 -1
  259. package/dist/Layout/LayoutPanel.d.ts +1 -1
  260. package/dist/Layout/LayoutPanel.js +1 -1
  261. package/dist/Lightbox/Lightbox.d.ts +6 -4
  262. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  263. package/dist/Lightbox/Lightbox.js +173 -79
  264. package/dist/Link/Link.d.ts +1 -1
  265. package/dist/Link/Link.d.ts.map +1 -1
  266. package/dist/Link/Link.js +5 -6
  267. package/dist/Link/LinkProvider.d.ts +2 -2
  268. package/dist/Link/LinkProvider.js +2 -2
  269. package/dist/List/List.d.ts +1 -1
  270. package/dist/List/List.js +1 -1
  271. package/dist/List/ListItem.d.ts +12 -2
  272. package/dist/List/ListItem.d.ts.map +1 -1
  273. package/dist/List/ListItem.js +3 -1
  274. package/dist/Markdown/Markdown.d.ts.map +1 -1
  275. package/dist/Markdown/Markdown.js +35 -13
  276. package/dist/MetadataList/MetadataList.d.ts +2 -2
  277. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  278. package/dist/MetadataList/MetadataList.js +38 -12
  279. package/dist/MetadataList/MetadataListItem.d.ts +1 -1
  280. package/dist/MetadataList/MetadataListItem.js +1 -1
  281. package/dist/MobileNav/MobileNav.d.ts +1 -1
  282. package/dist/MobileNav/MobileNav.js +9 -9
  283. package/dist/MoreMenu/MoreMenu.d.ts +1 -1
  284. package/dist/MoreMenu/MoreMenu.js +3 -3
  285. package/dist/MultiSelector/MultiSelector.d.ts +13 -4
  286. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  287. package/dist/MultiSelector/MultiSelector.js +155 -54
  288. package/dist/NavIcon/NavIcon.d.ts +1 -1
  289. package/dist/NavIcon/NavIcon.js +1 -1
  290. package/dist/NavMenu/index.d.ts +0 -2
  291. package/dist/NavMenu/index.d.ts.map +1 -1
  292. package/dist/NavMenu/index.js +1 -3
  293. package/dist/NumberInput/NumberInput.d.ts +1 -1
  294. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  295. package/dist/NumberInput/NumberInput.js +19 -7
  296. package/dist/Outline/Outline.d.ts.map +1 -1
  297. package/dist/Outline/Outline.js +3 -4
  298. package/dist/OverflowList/OverflowList.d.ts +1 -1
  299. package/dist/OverflowList/OverflowList.js +1 -1
  300. package/dist/Pagination/Pagination.d.ts +26 -21
  301. package/dist/Pagination/Pagination.d.ts.map +1 -1
  302. package/dist/Pagination/Pagination.js +204 -78
  303. package/dist/Pagination/index.d.ts +22 -1
  304. package/dist/Pagination/index.d.ts.map +1 -1
  305. package/dist/Pagination/index.js +14 -0
  306. package/dist/Popover/Popover.d.ts +20 -3
  307. package/dist/Popover/Popover.d.ts.map +1 -1
  308. package/dist/Popover/Popover.js +5 -1
  309. package/dist/Popover/usePopover.d.ts.map +1 -1
  310. package/dist/Popover/usePopover.js +14 -3
  311. package/dist/PowerSearch/PowerSearch.d.ts +1 -1
  312. package/dist/PowerSearch/PowerSearch.js +1 -1
  313. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  314. package/dist/PowerSearch/PowerSearchEditPopover.js +7 -0
  315. package/dist/ProgressBar/ProgressBar.d.ts +56 -22
  316. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  317. package/dist/ProgressBar/ProgressBar.js +169 -22
  318. package/dist/ProgressBar/ProgressBarMarkTooltip.d.ts +27 -0
  319. package/dist/ProgressBar/ProgressBarMarkTooltip.d.ts.map +1 -0
  320. package/dist/ProgressBar/ProgressBarMarkTooltip.js +35 -0
  321. package/dist/ProgressBar/index.d.ts +21 -1
  322. package/dist/ProgressBar/index.d.ts.map +1 -1
  323. package/dist/ProgressBar/index.js +14 -0
  324. package/dist/RadioList/RadioList.d.ts +1 -1
  325. package/dist/RadioList/RadioList.js +1 -1
  326. package/dist/RadioList/RadioListItem.d.ts +1 -1
  327. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  328. package/dist/RadioList/RadioListItem.js +2 -2
  329. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  330. package/dist/Resizable/ResizeHandle.js +17 -14
  331. package/dist/Section/Section.d.ts +2 -19
  332. package/dist/Section/Section.d.ts.map +1 -1
  333. package/dist/Section/Section.js +1 -15
  334. package/dist/Section/index.d.ts +19 -1
  335. package/dist/Section/index.d.ts.map +1 -1
  336. package/dist/Section/index.js +14 -0
  337. package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
  338. package/dist/SegmentedControl/SegmentedControl.js +1 -1
  339. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  340. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  341. package/dist/SegmentedControl/SegmentedControlItem.js +6 -6
  342. package/dist/SelectableCard/SelectableCard.d.ts +4 -3
  343. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  344. package/dist/SelectableCard/SelectableCard.js +18 -14
  345. package/dist/Selector/Selector.d.ts +14 -4
  346. package/dist/Selector/Selector.d.ts.map +1 -1
  347. package/dist/Selector/Selector.js +247 -77
  348. package/dist/Selector/hooks.d.ts +18 -6
  349. package/dist/Selector/hooks.d.ts.map +1 -1
  350. package/dist/Selector/hooks.js +57 -40
  351. package/dist/SideNav/SideNav.d.ts +1 -1
  352. package/dist/SideNav/SideNav.d.ts.map +1 -1
  353. package/dist/SideNav/SideNav.js +2 -2
  354. package/dist/SideNav/SideNavCollapseButton.d.ts +2 -2
  355. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  356. package/dist/SideNav/SideNavCollapseButton.js +30 -14
  357. package/dist/SideNav/SideNavHeading.d.ts +1 -1
  358. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  359. package/dist/SideNav/SideNavHeading.js +57 -20
  360. package/dist/SideNav/SideNavItem.d.ts +2 -2
  361. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  362. package/dist/SideNav/SideNavItem.js +30 -25
  363. package/dist/SideNav/SideNavSection.d.ts +1 -1
  364. package/dist/SideNav/SideNavSection.js +1 -1
  365. package/dist/Skeleton/Skeleton.d.ts +1 -1
  366. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  367. package/dist/Skeleton/Skeleton.js +3 -3
  368. package/dist/Slider/Slider.d.ts.map +1 -1
  369. package/dist/Slider/Slider.js +78 -68
  370. package/dist/Spinner/Spinner.d.ts +1 -1
  371. package/dist/Spinner/Spinner.js +1 -1
  372. package/dist/Stack/Stack.d.ts +1 -1
  373. package/dist/Stack/Stack.js +1 -1
  374. package/dist/Stack/StackItem.d.ts +1 -1
  375. package/dist/Stack/StackItem.js +1 -1
  376. package/dist/Stack/stack.stylex.d.ts +3 -3
  377. package/dist/StatusDot/StatusDot.d.ts +1 -20
  378. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  379. package/dist/StatusDot/StatusDot.js +2 -17
  380. package/dist/StatusDot/index.d.ts +21 -1
  381. package/dist/StatusDot/index.d.ts.map +1 -1
  382. package/dist/StatusDot/index.js +14 -0
  383. package/dist/Switch/Switch.d.ts +2 -6
  384. package/dist/Switch/Switch.d.ts.map +1 -1
  385. package/dist/Switch/Switch.js +28 -20
  386. package/dist/TabList/Tab.d.ts +1 -1
  387. package/dist/TabList/Tab.d.ts.map +1 -1
  388. package/dist/TabList/Tab.js +3 -4
  389. package/dist/TabList/TabList.d.ts +1 -1
  390. package/dist/TabList/TabList.js +1 -1
  391. package/dist/TabList/TabMenu.d.ts +1 -1
  392. package/dist/TabList/TabMenu.d.ts.map +1 -1
  393. package/dist/TabList/TabMenu.js +52 -22
  394. package/dist/Table/BaseTable.d.ts +1 -1
  395. package/dist/Table/BaseTable.d.ts.map +1 -1
  396. package/dist/Table/BaseTable.js +4 -7
  397. package/dist/Table/Table.d.ts +1 -1
  398. package/dist/Table/Table.js +1 -1
  399. package/dist/Table/TableCell.d.ts +1 -1
  400. package/dist/Table/TableCell.js +4 -2
  401. package/dist/Table/TableHeaderCell.d.ts +1 -1
  402. package/dist/Table/TableHeaderCell.js +4 -2
  403. package/dist/Table/TableRow.d.ts +1 -1
  404. package/dist/Table/TableRow.js +1 -1
  405. package/dist/Table/index.d.ts +1 -1
  406. package/dist/Table/index.d.ts.map +1 -1
  407. package/dist/Table/index.js +1 -1
  408. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
  409. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  410. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +22 -18
  411. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +18 -3
  412. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  413. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +55 -43
  414. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  415. package/dist/Table/plugins/sortable/useTableSortable.js +23 -4
  416. package/dist/Table/plugins/tree/useTableTreeData.d.ts +11 -0
  417. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  418. package/dist/Table/plugins/tree/useTableTreeData.js +65 -35
  419. package/dist/Table/tableContextMenu.d.ts.map +1 -1
  420. package/dist/Table/tableContextMenu.js +2 -1
  421. package/dist/Table/types.d.ts +5 -9
  422. package/dist/Table/types.d.ts.map +1 -1
  423. package/dist/Text/Text.d.ts +11 -2
  424. package/dist/Text/Text.d.ts.map +1 -1
  425. package/dist/Text/Text.js +26 -3
  426. package/dist/Text/index.d.ts +31 -1
  427. package/dist/Text/index.d.ts.map +1 -1
  428. package/dist/Text/index.js +23 -0
  429. package/dist/TextArea/TextArea.d.ts +1 -1
  430. package/dist/TextArea/TextArea.d.ts.map +1 -1
  431. package/dist/TextArea/TextArea.js +111 -41
  432. package/dist/TextInput/TextInput.d.ts +1 -1
  433. package/dist/TextInput/TextInput.d.ts.map +1 -1
  434. package/dist/TextInput/TextInput.js +4 -3
  435. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  436. package/dist/Thumbnail/Thumbnail.js +28 -16
  437. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  438. package/dist/TimeInput/TimeInput.js +3 -2
  439. package/dist/Timestamp/Timestamp.d.ts +26 -12
  440. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  441. package/dist/Timestamp/Timestamp.js +128 -65
  442. package/dist/Timestamp/TimestampHoverCard.d.ts +45 -0
  443. package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -0
  444. package/dist/Timestamp/TimestampHoverCard.js +228 -0
  445. package/dist/Timestamp/formatInstant.d.ts +3 -3
  446. package/dist/Timestamp/formatInstant.d.ts.map +1 -1
  447. package/dist/Timestamp/formatInstant.js +7 -2
  448. package/dist/Timestamp/tooltipEntries.d.ts +17 -2
  449. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -1
  450. package/dist/Timestamp/tooltipEntries.js +4 -2
  451. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  452. package/dist/Toast/ToastViewport.js +61 -9
  453. package/dist/ToggleButton/ToggleButton.d.ts +1 -1
  454. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  455. package/dist/ToggleButton/ToggleButton.js +4 -2
  456. package/dist/ToggleButton/ToggleButtonGroup.d.ts +1 -1
  457. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  458. package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
  459. package/dist/Token/Token.d.ts +6 -28
  460. package/dist/Token/Token.d.ts.map +1 -1
  461. package/dist/Token/Token.js +84 -64
  462. package/dist/Token/TokenLink.d.ts +62 -0
  463. package/dist/Token/TokenLink.d.ts.map +1 -0
  464. package/dist/Token/TokenLink.js +76 -0
  465. package/dist/Token/index.d.ts +27 -1
  466. package/dist/Token/index.d.ts.map +1 -1
  467. package/dist/Token/index.js +14 -0
  468. package/dist/Tokenizer/Tokenizer.d.ts +1 -1
  469. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  470. package/dist/Tokenizer/Tokenizer.js +5 -3
  471. package/dist/Toolbar/Toolbar.d.ts +1 -1
  472. package/dist/Toolbar/Toolbar.js +1 -1
  473. package/dist/Tooltip/Tooltip.d.ts +1 -1
  474. package/dist/Tooltip/Tooltip.js +1 -1
  475. package/dist/TopNav/TopNav.d.ts +1 -1
  476. package/dist/TopNav/TopNav.d.ts.map +1 -1
  477. package/dist/TopNav/TopNav.js +7 -6
  478. package/dist/TopNav/TopNavHeading.d.ts +2 -8
  479. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  480. package/dist/TopNav/TopNavHeading.js +56 -20
  481. package/dist/TopNav/TopNavItem.d.ts +1 -1
  482. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  483. package/dist/TopNav/TopNavItem.js +4 -10
  484. package/dist/TopNav/TopNavMegaMenu.d.ts +1 -1
  485. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  486. package/dist/TopNav/TopNavMegaMenu.js +89 -42
  487. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +1 -1
  488. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +1 -1
  489. package/dist/TopNav/TopNavMegaMenuItem.d.ts +1 -1
  490. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  491. package/dist/TopNav/TopNavMegaMenuItem.js +23 -4
  492. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  493. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  494. package/dist/TopNav/TopNavMenu.js +84 -33
  495. package/dist/TreeList/TreeList.d.ts +1 -1
  496. package/dist/TreeList/TreeList.d.ts.map +1 -1
  497. package/dist/TreeList/TreeList.js +14 -1
  498. package/dist/TreeList/TreeListBranches.d.ts +1 -1
  499. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  500. package/dist/TreeList/TreeListBranches.js +15 -5
  501. package/dist/TreeList/TreeListItem.d.ts +12 -2
  502. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  503. package/dist/TreeList/TreeListItem.js +58 -30
  504. package/dist/TreeList/TreeListTypes.d.ts +1 -17
  505. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  506. package/dist/TreeList/index.d.ts +18 -1
  507. package/dist/TreeList/index.d.ts.map +1 -1
  508. package/dist/TreeList/index.js +14 -0
  509. package/dist/Typeahead/BaseTypeahead.d.ts +10 -1
  510. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  511. package/dist/Typeahead/BaseTypeahead.js +17 -3
  512. package/dist/Typeahead/Typeahead.d.ts +1 -1
  513. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  514. package/dist/Typeahead/Typeahead.js +9 -2
  515. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  516. package/dist/Typeahead/TypeaheadItem.js +1 -1
  517. package/dist/VStack/VStack.d.ts +1 -1
  518. package/dist/VStack/VStack.js +1 -1
  519. package/dist/VisuallyHidden/VisuallyHidden.d.ts +1 -1
  520. package/dist/VisuallyHidden/VisuallyHidden.js +1 -1
  521. package/dist/astryx.css +143 -46
  522. package/dist/astryx.umd.js +52 -56
  523. package/dist/astryx.umd.js.map +4 -4
  524. package/dist/hooks/containerReveal.pool.stylex.d.ts +303 -0
  525. package/dist/hooks/containerReveal.pool.stylex.d.ts.map +1 -0
  526. package/dist/hooks/containerReveal.pool.stylex.js +292 -0
  527. package/dist/hooks/index.d.ts +2 -0
  528. package/dist/hooks/index.d.ts.map +1 -1
  529. package/dist/hooks/index.js +2 -1
  530. package/dist/hooks/useContainerReveal.d.ts +83 -0
  531. package/dist/hooks/useContainerReveal.d.ts.map +1 -0
  532. package/dist/hooks/useContainerReveal.js +123 -0
  533. package/dist/hooks/useGridFocus.d.ts +8 -6
  534. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  535. package/dist/hooks/useInputContainer.d.ts.map +1 -1
  536. package/dist/hooks/useInputContainer.js +29 -1
  537. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
  538. package/dist/hooks/useInputStatusIcon.js +11 -0
  539. package/dist/hooks/useKeyboardHint.d.ts +2 -2
  540. package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
  541. package/dist/hooks/useKeyboardHint.js +5 -3
  542. package/dist/hooks/useListFocus.d.ts +8 -7
  543. package/dist/hooks/useListFocus.d.ts.map +1 -1
  544. package/dist/hooks/useLongPress.d.ts.map +1 -1
  545. package/dist/hooks/useLongPress.js +12 -2
  546. package/dist/hooks/useStreamingText.d.ts +18 -3
  547. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  548. package/dist/hooks/useStreamingText.js +47 -7
  549. package/dist/hooks/useTreeFocus.d.ts.map +1 -1
  550. package/dist/hooks/useTreeFocus.js +13 -2
  551. package/dist/hooks/useTypeahead.d.ts +3 -2
  552. package/dist/hooks/useTypeahead.d.ts.map +1 -1
  553. package/dist/hooks/useTypeahead.js +19 -7
  554. package/dist/i18n/InternationalizationProvider.d.ts +6 -0
  555. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  556. package/dist/i18n/useDirection.d.ts.map +1 -1
  557. package/dist/i18n/useDirection.js +6 -3
  558. package/dist/index.d.ts +2 -1
  559. package/dist/index.d.ts.map +1 -1
  560. package/dist/index.js +3 -3
  561. package/dist/theme/Theme.d.ts.map +1 -1
  562. package/dist/theme/Theme.js +2 -7
  563. package/dist/theme/contrast.d.ts +45 -0
  564. package/dist/theme/contrast.d.ts.map +1 -0
  565. package/dist/theme/contrast.js +88 -0
  566. package/dist/theme/defineTheme.d.ts +9 -3
  567. package/dist/theme/defineTheme.d.ts.map +1 -1
  568. package/dist/theme/defineTheme.js +6 -4
  569. package/dist/theme/derivedVarRegistry.d.ts +8 -0
  570. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  571. package/dist/theme/derivedVarRegistry.js +5 -13
  572. package/dist/theme/expandColorScale.d.ts +32 -3
  573. package/dist/theme/expandColorScale.d.ts.map +1 -1
  574. package/dist/theme/expandColorScale.js +102 -13
  575. package/dist/theme/expandTypeScale.d.ts.map +1 -1
  576. package/dist/theme/expandTypeScale.js +17 -0
  577. package/dist/theme/generateThemeRules.d.ts +0 -6
  578. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  579. package/dist/theme/generateThemeRules.js +11 -15
  580. package/dist/theme/index.d.ts +9 -7
  581. package/dist/theme/index.d.ts.map +1 -1
  582. package/dist/theme/index.js +4 -3
  583. package/dist/theme/themeRegistry.d.ts +32 -0
  584. package/dist/theme/themeRegistry.d.ts.map +1 -0
  585. package/dist/theme/themeRegistry.js +49 -0
  586. package/dist/theme/tokens.stylex.d.ts +0 -17
  587. package/dist/theme/tokens.stylex.d.ts.map +1 -1
  588. package/dist/theme/tokens.stylex.js +0 -22
  589. package/dist/theme/types.d.ts +10 -2
  590. package/dist/theme/types.d.ts.map +1 -1
  591. package/dist/theme/useTheme.d.ts +9 -0
  592. package/dist/theme/useTheme.d.ts.map +1 -1
  593. package/dist/theme/useTheme.js +82 -27
  594. package/dist/utils/focusOutline.stylex.d.ts +74 -0
  595. package/dist/utils/focusOutline.stylex.d.ts.map +1 -0
  596. package/dist/utils/focusOutline.stylex.js +95 -0
  597. package/dist/utils/rtlStyles.d.ts +23 -2
  598. package/dist/utils/rtlStyles.d.ts.map +1 -1
  599. package/dist/utils/rtlStyles.js +28 -3
  600. package/groups.doc.mjs +2 -2
  601. package/locales/en.json +128 -0
  602. package/locales/pseudo.json +96 -0
  603. package/package.json +9 -13
  604. package/src/AlertDialog/AlertDialog.doc.mjs +3 -3
  605. package/src/AlertDialog/AlertDialog.tsx +1 -1
  606. package/src/AlertDialog/useImperativeAlertDialog.doc.mjs +1 -1
  607. package/src/AppShell/AppShell.doc.mjs +3 -3
  608. package/src/AppShell/AppShell.test.tsx +55 -0
  609. package/src/AppShell/AppShell.tsx +27 -22
  610. package/src/AppShell/index.ts +20 -1
  611. package/src/AppShell/useAppShellMobile.doc.mjs +2 -2
  612. package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
  613. package/src/AspectRatio/AspectRatio.tsx +1 -1
  614. package/src/Avatar/Avatar.doc.mjs +5 -16
  615. package/src/Avatar/Avatar.test.tsx +33 -8
  616. package/src/Avatar/Avatar.tsx +60 -53
  617. package/src/Avatar/AvatarStatusDot.doc.mjs +1 -1
  618. package/src/Avatar/AvatarStatusDot.tsx +2 -27
  619. package/src/Avatar/index.ts +26 -1
  620. package/src/AvatarGroup/AvatarGroup.doc.mjs +3 -3
  621. package/src/AvatarGroup/AvatarGroup.test.tsx +21 -1
  622. package/src/AvatarGroup/AvatarGroup.tsx +3 -7
  623. package/src/AvatarGroup/AvatarGroupOverflow.doc.mjs +1 -1
  624. package/src/AvatarGroup/AvatarGroupOverflow.tsx +7 -12
  625. package/src/Badge/Badge.doc.mjs +3 -3
  626. package/src/Badge/Badge.tsx +2 -31
  627. package/src/Badge/index.ts +32 -6
  628. package/src/Banner/Banner.doc.mjs +3 -3
  629. package/src/Banner/Banner.tsx +17 -51
  630. package/src/Banner/index.ts +39 -7
  631. package/src/Blockquote/Blockquote.doc.mjs +3 -3
  632. package/src/Blockquote/Blockquote.tsx +1 -1
  633. package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +1 -1
  634. package/src/Breadcrumbs/BreadcrumbItem.tsx +17 -5
  635. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +3 -3
  636. package/src/Breadcrumbs/Breadcrumbs.test.tsx +1 -1
  637. package/src/Breadcrumbs/Breadcrumbs.tsx +2 -19
  638. package/src/Breadcrumbs/index.ts +19 -5
  639. package/src/Button/Button.doc.mjs +3 -3
  640. package/src/Button/Button.test.tsx +16 -0
  641. package/src/Button/Button.tsx +27 -64
  642. package/src/Button/index.ts +22 -7
  643. package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -3
  644. package/src/ButtonGroup/ButtonGroup.tsx +1 -1
  645. package/src/Calendar/Calendar.doc.mjs +3 -3
  646. package/src/Calendar/Calendar.test.tsx +22 -6
  647. package/src/Calendar/Calendar.tsx +3 -2
  648. package/src/Calendar/index.ts +1 -6
  649. package/src/Calendar/styles.ts +2 -10
  650. package/src/Calendar/utils.ts +0 -11
  651. package/src/Card/Card.doc.mjs +3 -3
  652. package/src/Card/Card.tsx +1 -1
  653. package/src/Carousel/Carousel.doc.mjs +13 -3
  654. package/src/Carousel/Carousel.test.tsx +232 -1
  655. package/src/Carousel/Carousel.tsx +154 -27
  656. package/src/Carousel/index.ts +1 -1
  657. package/src/Center/Center.doc.mjs +41 -3
  658. package/src/Center/Center.test.tsx +75 -0
  659. package/src/Center/Center.tsx +38 -3
  660. package/src/Chat/Chat.doc.mjs +3 -3
  661. package/src/Chat/ChatComposer.doc.mjs +1 -1
  662. package/src/Chat/ChatComposer.tsx +5 -5
  663. package/src/Chat/ChatComposerDrawer.doc.mjs +1 -1
  664. package/src/Chat/ChatComposerDrawer.tsx +5 -5
  665. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  666. package/src/Chat/ChatComposerInput.tsx +1 -1
  667. package/src/Chat/ChatComposerTokenElement.doc.mjs +1 -1
  668. package/src/Chat/ChatDictationButton.doc.mjs +3 -3
  669. package/src/Chat/ChatDictationButton.tsx +1 -1
  670. package/src/Chat/ChatLayout.doc.mjs +1 -1
  671. package/src/Chat/ChatLayout.test.tsx +57 -0
  672. package/src/Chat/ChatLayout.tsx +23 -2
  673. package/src/Chat/ChatLayoutScrollButton.doc.mjs +1 -1
  674. package/src/Chat/ChatLayoutScrollButton.test.tsx +22 -0
  675. package/src/Chat/ChatLayoutScrollButton.tsx +2 -1
  676. package/src/Chat/ChatMessage.doc.mjs +1 -1
  677. package/src/Chat/ChatMessage.tsx +1 -1
  678. package/src/Chat/ChatMessageBubble.doc.mjs +1 -1
  679. package/src/Chat/ChatMessageBubble.tsx +1 -1
  680. package/src/Chat/ChatMessageList.doc.mjs +1 -1
  681. package/src/Chat/ChatMessageList.tsx +1 -1
  682. package/src/Chat/ChatMessageMetadata.doc.mjs +1 -1
  683. package/src/Chat/ChatSendButton.doc.mjs +1 -1
  684. package/src/Chat/ChatSendButton.tsx +5 -3
  685. package/src/Chat/ChatSystemMessage.doc.mjs +1 -1
  686. package/src/Chat/ChatSystemMessage.tsx +1 -1
  687. package/src/Chat/ChatTokenizedText.doc.mjs +1 -1
  688. package/src/Chat/ChatTokenizedText.tsx +1 -1
  689. package/src/Chat/ChatToolCalls.doc.mjs +3 -3
  690. package/src/Chat/ChatToolCalls.test.tsx +35 -0
  691. package/src/Chat/ChatToolCalls.tsx +36 -16
  692. package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -3
  693. package/src/CheckboxInput/CheckboxInput.test.tsx +56 -0
  694. package/src/CheckboxInput/CheckboxInput.tsx +18 -3
  695. package/src/CheckboxList/CheckboxList.doc.mjs +3 -3
  696. package/src/CheckboxList/CheckboxList.test.tsx +94 -3
  697. package/src/CheckboxList/CheckboxList.tsx +1 -1
  698. package/src/CheckboxList/CheckboxListItem.doc.mjs +1 -1
  699. package/src/CheckboxList/CheckboxListItem.tsx +18 -11
  700. package/src/Citation/Citation.doc.mjs +2 -2
  701. package/src/Citation/Citation.tsx +1 -1
  702. package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
  703. package/src/ClickableCard/ClickableCard.tsx +9 -14
  704. package/src/Code/Code.tsx +2 -2
  705. package/src/CodeBlock/Code.doc.mjs +1 -1
  706. package/src/CodeBlock/CodeBlock.doc.mjs +3 -3
  707. package/src/CodeBlock/CodeBlock.test.tsx +17 -0
  708. package/src/CodeBlock/CodeBlock.tsx +18 -17
  709. package/src/Collapsible/Collapsible.doc.mjs +3 -3
  710. package/src/Collapsible/Collapsible.tsx +23 -19
  711. package/src/Collapsible/CollapsibleGroup.doc.mjs +1 -1
  712. package/src/Collapsible/CollapsibleGroup.tsx +1 -1
  713. package/src/Collapsible/CollapsibleGroupContext.tsx +1 -1
  714. package/src/Collapsible/useCollapsible.doc.mjs +2 -2
  715. package/src/CommandPalette/CommandPalette.doc.mjs +4 -4
  716. package/src/CommandPalette/CommandPalette.test.tsx +29 -0
  717. package/src/CommandPalette/CommandPalette.tsx +1 -1
  718. package/src/CommandPalette/CommandPaletteEmpty.doc.mjs +1 -1
  719. package/src/CommandPalette/CommandPaletteEmpty.tsx +1 -1
  720. package/src/CommandPalette/CommandPaletteFooter.doc.mjs +1 -1
  721. package/src/CommandPalette/CommandPaletteFooter.tsx +1 -1
  722. package/src/CommandPalette/CommandPaletteGroup.doc.mjs +1 -1
  723. package/src/CommandPalette/CommandPaletteGroup.test.tsx +6 -2
  724. package/src/CommandPalette/CommandPaletteGroup.tsx +1 -1
  725. package/src/CommandPalette/CommandPaletteInput.doc.mjs +1 -1
  726. package/src/CommandPalette/CommandPaletteInput.tsx +5 -1
  727. package/src/CommandPalette/CommandPaletteItem.doc.mjs +1 -1
  728. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  729. package/src/CommandPalette/CommandPaletteList.doc.mjs +1 -1
  730. package/src/CommandPalette/CommandPaletteList.tsx +1 -1
  731. package/src/ComplexSelector/ComplexSelector.doc.mjs +220 -0
  732. package/src/ComplexSelector/ComplexSelector.test.tsx +181 -0
  733. package/src/ComplexSelector/ComplexSelector.tsx +443 -0
  734. package/src/ComplexSelector/index.ts +17 -0
  735. package/src/ContextMenu/ContextMenu.doc.mjs +4 -4
  736. package/src/ContextMenu/ContextMenu.test.tsx +38 -2
  737. package/src/ContextMenu/ContextMenu.tsx +27 -6
  738. package/src/ContextMenu/ContextMenuItem.doc.mjs +1 -1
  739. package/src/DateInput/DateInput.doc.mjs +19 -4
  740. package/src/DateInput/DateInput.test.tsx +79 -3
  741. package/src/DateInput/DateInput.tsx +23 -3
  742. package/src/DateRangeInput/DateRangeInput.doc.mjs +11 -3
  743. package/src/DateRangeInput/DateRangeInput.test.tsx +97 -2
  744. package/src/DateRangeInput/DateRangeInput.tsx +19 -2
  745. package/src/DateTimeInput/DateTimeInput.doc.mjs +19 -5
  746. package/src/DateTimeInput/DateTimeInput.test.tsx +81 -2
  747. package/src/DateTimeInput/DateTimeInput.tsx +19 -2
  748. package/src/Dialog/Dialog.doc.mjs +7 -5
  749. package/src/Dialog/Dialog.test.tsx +46 -3
  750. package/src/Dialog/Dialog.tsx +63 -53
  751. package/src/Dialog/DialogHeader.doc.mjs +1 -1
  752. package/src/Dialog/DialogHeader.tsx +1 -1
  753. package/src/Dialog/index.ts +18 -1
  754. package/src/Dialog/useImperativeDialog.doc.mjs +1 -1
  755. package/src/Divider/Divider.doc.mjs +3 -3
  756. package/src/Divider/Divider.tsx +2 -19
  757. package/src/Divider/index.ts +19 -5
  758. package/src/DropdownMenu/DropdownMenu.doc.mjs +22 -7
  759. package/src/DropdownMenu/DropdownMenu.test.tsx +405 -1
  760. package/src/DropdownMenu/DropdownMenu.tsx +117 -50
  761. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +1 -1
  762. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +41 -64
  763. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +25 -5
  764. package/src/DropdownMenu/DropdownMenuItem.tsx +34 -7
  765. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +5 -13
  766. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
  767. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +1 -1
  768. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +11 -2
  769. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +84 -2
  770. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +1 -1
  771. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +90 -15
  772. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +24 -8
  773. package/src/DropdownMenu/menuItemHover.ts +1 -0
  774. package/src/DropdownMenu/renderDropdownItems.tsx +31 -21
  775. package/src/EmptyState/EmptyState.doc.mjs +3 -3
  776. package/src/EmptyState/EmptyState.tsx +1 -1
  777. package/src/Field/Field.doc.mjs +7 -3
  778. package/src/Field/Field.tsx +1 -1
  779. package/src/Field/FieldLabel.doc.mjs +1 -1
  780. package/src/Field/FieldLabel.test.tsx +103 -0
  781. package/src/Field/FieldLabel.tsx +61 -5
  782. package/src/FieldStatus/FieldStatus.doc.mjs +3 -2
  783. package/src/FieldStatus/FieldStatus.test.tsx +61 -0
  784. package/src/FieldStatus/FieldStatus.tsx +16 -23
  785. package/src/FieldStatus/index.ts +20 -5
  786. package/src/FileInput/FileInput.doc.mjs +3 -3
  787. package/src/FileInput/FileInput.tsx +1 -1
  788. package/src/FormLayout/FormLayout.doc.mjs +3 -3
  789. package/src/FormLayout/FormLayout.tsx +2 -5
  790. package/src/Grid/Grid.doc.mjs +3 -8
  791. package/src/Grid/Grid.tsx +1 -25
  792. package/src/Grid/GridSpan.doc.mjs +1 -1
  793. package/src/Grid/GridSpan.tsx +1 -1
  794. package/src/HStack/HStack.tsx +1 -1
  795. package/src/Heading/Heading.tsx +4 -3
  796. package/src/HoverCard/HoverCard.doc.mjs +3 -3
  797. package/src/HoverCard/HoverCard.tsx +1 -1
  798. package/src/HoverCard/useHoverCard.doc.mjs +2 -2
  799. package/src/Icon/Icon.doc.mjs +8 -6
  800. package/src/Icon/Icon.test.tsx +23 -0
  801. package/src/Icon/Icon.tsx +4 -2
  802. package/src/Icon/defaultIcons.tsx +14 -0
  803. package/src/Icon/globalIconRegistry.test.tsx +87 -1
  804. package/src/Icon/globalIconRegistry.tsx +111 -9
  805. package/src/Icon/index.ts +9 -7
  806. package/src/Icon/useIcon.ts +23 -0
  807. package/src/IconButton/IconButton.doc.mjs +2 -2
  808. package/src/IconButton/IconButton.tsx +1 -1
  809. package/src/InputGroup/InputGroup.doc.mjs +2 -2
  810. package/src/InputGroup/InputGroup.tsx +1 -1
  811. package/src/InputGroup/InputGroupText.doc.mjs +1 -1
  812. package/src/InputGroup/InputGroupText.tsx +1 -1
  813. package/src/Item/Item.doc.mjs +8 -3
  814. package/src/Item/Item.test.tsx +88 -0
  815. package/src/Item/Item.tsx +65 -26
  816. package/src/Kbd/Kbd.doc.mjs +3 -3
  817. package/src/Kbd/Kbd.tsx +1 -1
  818. package/src/Layer/Layer.doc.mjs +2 -2
  819. package/src/Layer/useLayer.doc.mjs +2 -2
  820. package/src/Layout/Layout.doc.mjs +3 -3
  821. package/src/Layout/Layout.tsx +1 -1
  822. package/src/Layout/LayoutContent.doc.mjs +1 -1
  823. package/src/Layout/LayoutContent.tsx +1 -1
  824. package/src/Layout/LayoutFooter.doc.mjs +1 -1
  825. package/src/Layout/LayoutFooter.tsx +1 -1
  826. package/src/Layout/LayoutHeader.doc.mjs +1 -1
  827. package/src/Layout/LayoutHeader.tsx +1 -1
  828. package/src/Layout/LayoutPanel.doc.mjs +1 -1
  829. package/src/Layout/LayoutPanel.tsx +1 -1
  830. package/src/Lightbox/Lightbox.doc.mjs +6 -6
  831. package/src/Lightbox/Lightbox.test.tsx +211 -0
  832. package/src/Lightbox/Lightbox.tsx +152 -60
  833. package/src/Link/Link.doc.mjs +3 -3
  834. package/src/Link/Link.tsx +5 -12
  835. package/src/Link/LinkProvider.doc.mjs +2 -2
  836. package/src/Link/LinkProvider.tsx +2 -2
  837. package/src/List/List.doc.mjs +3 -3
  838. package/src/List/List.tsx +1 -1
  839. package/src/List/ListItem.doc.mjs +13 -1
  840. package/src/List/ListItem.tsx +14 -1
  841. package/src/Markdown/Markdown.doc.mjs +81 -1
  842. package/src/Markdown/Markdown.test.tsx +92 -0
  843. package/src/Markdown/Markdown.tsx +96 -68
  844. package/src/Markdown/parser.perf.test.ts +47 -35
  845. package/src/MetadataList/MetadataList.doc.mjs +3 -3
  846. package/src/MetadataList/MetadataList.test.tsx +82 -0
  847. package/src/MetadataList/MetadataList.tsx +45 -20
  848. package/src/MetadataList/MetadataListItem.doc.mjs +1 -1
  849. package/src/MetadataList/MetadataListItem.tsx +1 -1
  850. package/src/MobileNav/MobileNav.doc.mjs +3 -3
  851. package/src/MobileNav/MobileNav.tsx +4 -4
  852. package/src/MoreMenu/MoreMenu.doc.mjs +3 -3
  853. package/src/MoreMenu/MoreMenu.test.tsx +28 -1
  854. package/src/MoreMenu/MoreMenu.tsx +3 -3
  855. package/src/MultiSelector/MultiSelector.doc.mjs +37 -10
  856. package/src/MultiSelector/MultiSelector.test.tsx +396 -8
  857. package/src/MultiSelector/MultiSelector.tsx +254 -74
  858. package/src/NavIcon/NavIcon.doc.mjs +3 -3
  859. package/src/NavIcon/NavIcon.tsx +1 -1
  860. package/src/NavMenu/NavHeadingMenu.test.tsx +0 -16
  861. package/src/NavMenu/NavMenu.doc.mjs +2 -2
  862. package/src/NavMenu/index.ts +0 -4
  863. package/src/NumberInput/NumberInput.doc.mjs +5 -8
  864. package/src/NumberInput/NumberInput.test.tsx +117 -3
  865. package/src/NumberInput/NumberInput.tsx +30 -3
  866. package/src/Outline/Outline.doc.mjs +3 -3
  867. package/src/Outline/Outline.tsx +3 -6
  868. package/src/OverflowList/OverflowList.doc.mjs +3 -3
  869. package/src/OverflowList/OverflowList.tsx +1 -1
  870. package/src/Overlay/Overlay.doc.mjs +2 -2
  871. package/src/Pagination/Pagination.doc.mjs +55 -8
  872. package/src/Pagination/Pagination.test.tsx +582 -0
  873. package/src/Pagination/Pagination.tsx +249 -64
  874. package/src/Pagination/index.ts +22 -1
  875. package/src/Popover/Popover.doc.mjs +31 -3
  876. package/src/Popover/Popover.test.tsx +41 -0
  877. package/src/Popover/Popover.tsx +25 -2
  878. package/src/Popover/usePopover.doc.mjs +2 -2
  879. package/src/Popover/usePopover.tsx +10 -4
  880. package/src/PowerSearch/PowerSearch.doc.mjs +3 -3
  881. package/src/PowerSearch/PowerSearch.tsx +1 -1
  882. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +42 -0
  883. package/src/PowerSearch/PowerSearchEditPopover.tsx +7 -0
  884. package/src/ProgressBar/ProgressBar.doc.mjs +24 -3
  885. package/src/ProgressBar/ProgressBar.test.tsx +523 -2
  886. package/src/ProgressBar/ProgressBar.tsx +250 -25
  887. package/src/ProgressBar/ProgressBarMarkTooltip.tsx +43 -0
  888. package/src/ProgressBar/index.ts +22 -1
  889. package/src/RadioList/RadioList.doc.mjs +3 -3
  890. package/src/RadioList/RadioList.test.tsx +26 -4
  891. package/src/RadioList/RadioList.tsx +1 -1
  892. package/src/RadioList/RadioListItem.doc.mjs +1 -1
  893. package/src/RadioList/RadioListItem.tsx +9 -2
  894. package/src/Resizable/Resizable.doc.mjs +2 -2
  895. package/src/Resizable/ResizeHandle.test.tsx +52 -3
  896. package/src/Resizable/ResizeHandle.tsx +27 -22
  897. package/src/Resizable/useResizable.doc.mjs +2 -2
  898. package/src/Section/Section.doc.mjs +3 -3
  899. package/src/Section/Section.tsx +2 -20
  900. package/src/Section/index.ts +20 -5
  901. package/src/SegmentedControl/SegmentedControl.doc.mjs +3 -3
  902. package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
  903. package/src/SegmentedControl/SegmentedControl.tsx +1 -1
  904. package/src/SegmentedControl/SegmentedControlItem.doc.mjs +1 -1
  905. package/src/SegmentedControl/SegmentedControlItem.tsx +23 -12
  906. package/src/SelectableCard/SelectableCard.doc.mjs +4 -2
  907. package/src/SelectableCard/SelectableCard.test.tsx +55 -0
  908. package/src/SelectableCard/SelectableCard.tsx +23 -12
  909. package/src/Selector/Selector.doc.mjs +34 -11
  910. package/src/Selector/Selector.test.tsx +1176 -118
  911. package/src/Selector/Selector.tsx +345 -96
  912. package/src/Selector/SelectorOption.doc.mjs +1 -1
  913. package/src/Selector/hooks.ts +77 -50
  914. package/src/SideNav/SideNav.doc.mjs +3 -3
  915. package/src/SideNav/SideNav.test.tsx +46 -0
  916. package/src/SideNav/SideNav.tsx +2 -1
  917. package/src/SideNav/SideNavCollapseButton.doc.mjs +1 -1
  918. package/src/SideNav/SideNavCollapseButton.tsx +16 -10
  919. package/src/SideNav/SideNavHeading.doc.mjs +1 -1
  920. package/src/SideNav/SideNavHeading.tsx +49 -12
  921. package/src/SideNav/SideNavItem.doc.mjs +1 -1
  922. package/src/SideNav/SideNavItem.tsx +21 -14
  923. package/src/SideNav/SideNavSection.doc.mjs +1 -1
  924. package/src/SideNav/SideNavSection.tsx +1 -1
  925. package/src/Skeleton/Skeleton.doc.mjs +3 -3
  926. package/src/Skeleton/Skeleton.test.tsx +16 -0
  927. package/src/Skeleton/Skeleton.tsx +14 -2
  928. package/src/Slider/Slider.doc.mjs +3 -3
  929. package/src/Slider/Slider.tsx +9 -13
  930. package/src/Spinner/Spinner.doc.mjs +3 -3
  931. package/src/Spinner/Spinner.tsx +1 -1
  932. package/src/Stack/Stack.doc.mjs +113 -3
  933. package/src/Stack/Stack.tsx +1 -1
  934. package/src/Stack/StackItem.tsx +1 -1
  935. package/src/StatusDot/StatusDot.doc.mjs +15 -6
  936. package/src/StatusDot/StatusDot.tsx +2 -22
  937. package/src/StatusDot/index.ts +22 -5
  938. package/src/Switch/Switch.doc.mjs +5 -5
  939. package/src/Switch/Switch.test.tsx +71 -25
  940. package/src/Switch/Switch.tsx +63 -26
  941. package/src/TabList/Tab.doc.mjs +1 -1
  942. package/src/TabList/Tab.tsx +3 -10
  943. package/src/TabList/TabList.doc.mjs +3 -3
  944. package/src/TabList/TabList.test.tsx +21 -18
  945. package/src/TabList/TabList.tsx +1 -1
  946. package/src/TabList/TabMenu.doc.mjs +1 -1
  947. package/src/TabList/TabMenu.tsx +25 -24
  948. package/src/Table/BaseTable.tsx +4 -5
  949. package/src/Table/Table.doc.mjs +5 -5
  950. package/src/Table/Table.test.tsx +27 -49
  951. package/src/Table/Table.tsx +1 -1
  952. package/src/Table/TableCell.doc.mjs +1 -1
  953. package/src/Table/TableCell.tsx +2 -2
  954. package/src/Table/TableHeaderCell.doc.mjs +1 -1
  955. package/src/Table/TableHeaderCell.tsx +2 -2
  956. package/src/Table/TableRow.doc.mjs +1 -1
  957. package/src/Table/TableRow.tsx +1 -1
  958. package/src/Table/index.ts +1 -1
  959. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +30 -14
  960. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
  961. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +72 -33
  962. package/src/Table/plugins/sortable/useTableSortable.tsx +2 -6
  963. package/src/Table/plugins/tree/useTableTreeData.test.tsx +161 -2
  964. package/src/Table/plugins/tree/useTableTreeData.tsx +97 -25
  965. package/src/Table/tableContextMenu.test.tsx +27 -0
  966. package/src/Table/tableContextMenu.tsx +1 -0
  967. package/src/Table/types.ts +5 -9
  968. package/src/Table/useTableColumnResize.doc.mjs +1 -1
  969. package/src/Table/useTableColumnSettings.doc.mjs +1 -1
  970. package/src/Table/useTableFilterState.doc.mjs +1 -1
  971. package/src/Table/useTableFiltering.doc.mjs +1 -1
  972. package/src/Table/useTableGroupedRows.doc.mjs +2 -2
  973. package/src/Table/useTablePagination.doc.mjs +1 -1
  974. package/src/Table/useTableRowExpansion.doc.mjs +57 -4
  975. package/src/Table/useTableRowIndex.doc.mjs +2 -2
  976. package/src/Table/useTableRowStatus.doc.mjs +3 -3
  977. package/src/Table/useTableSelection.doc.mjs +1 -1
  978. package/src/Table/useTableSelectionState.doc.mjs +1 -1
  979. package/src/Table/useTableSortable.doc.mjs +1 -1
  980. package/src/Table/useTableStickyColumns.doc.mjs +1 -1
  981. package/src/Table/useTableTreeData.doc.mjs +10 -1
  982. package/src/Table/useTableTreeState.doc.mjs +1 -1
  983. package/src/Text/Heading.doc.mjs +4 -4
  984. package/src/Text/Text.doc.mjs +4 -4
  985. package/src/Text/Text.test.tsx +42 -0
  986. package/src/Text/Text.tsx +26 -2
  987. package/src/Text/index.ts +32 -6
  988. package/src/TextArea/TextArea.doc.mjs +31 -7
  989. package/src/TextArea/TextArea.test.tsx +186 -7
  990. package/src/TextArea/TextArea.tsx +156 -52
  991. package/src/TextInput/TextInput.doc.mjs +5 -5
  992. package/src/TextInput/TextInput.test.tsx +77 -0
  993. package/src/TextInput/TextInput.tsx +7 -3
  994. package/src/Thumbnail/Thumbnail.doc.mjs +2 -2
  995. package/src/Thumbnail/Thumbnail.test.tsx +24 -1
  996. package/src/Thumbnail/Thumbnail.tsx +29 -43
  997. package/src/TimeInput/TimeInput.doc.mjs +5 -5
  998. package/src/TimeInput/TimeInput.test.tsx +30 -3
  999. package/src/TimeInput/TimeInput.tsx +6 -2
  1000. package/src/Timestamp/Timestamp.doc.mjs +30 -24
  1001. package/src/Timestamp/Timestamp.test.tsx +438 -107
  1002. package/src/Timestamp/Timestamp.tsx +167 -103
  1003. package/src/Timestamp/TimestampHoverCard.tsx +283 -0
  1004. package/src/Timestamp/formatInstant.ts +9 -4
  1005. package/src/Timestamp/tooltipEntries.test.ts +9 -0
  1006. package/src/Timestamp/tooltipEntries.ts +18 -2
  1007. package/src/Toast/Toast.doc.mjs +3 -3
  1008. package/src/Toast/ToastViewport.test.tsx +218 -8
  1009. package/src/Toast/ToastViewport.tsx +71 -12
  1010. package/src/Toast/useToast.doc.mjs +2 -2
  1011. package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
  1012. package/src/ToggleButton/ToggleButton.test.tsx +24 -0
  1013. package/src/ToggleButton/ToggleButton.tsx +20 -2
  1014. package/src/ToggleButton/ToggleButtonGroup.doc.mjs +1 -1
  1015. package/src/ToggleButton/ToggleButtonGroup.tsx +3 -6
  1016. package/src/Token/Token.doc.mjs +3 -3
  1017. package/src/Token/Token.test.tsx +145 -0
  1018. package/src/Token/Token.tsx +77 -86
  1019. package/src/Token/TokenLink.tsx +107 -0
  1020. package/src/Token/index.ts +28 -1
  1021. package/src/Tokenizer/Tokenizer.doc.mjs +5 -5
  1022. package/src/Tokenizer/Tokenizer.test.tsx +45 -3
  1023. package/src/Tokenizer/Tokenizer.tsx +11 -3
  1024. package/src/Toolbar/Toolbar.doc.mjs +3 -3
  1025. package/src/Toolbar/Toolbar.tsx +1 -1
  1026. package/src/Tooltip/Tooltip.doc.mjs +3 -3
  1027. package/src/Tooltip/Tooltip.tsx +1 -1
  1028. package/src/Tooltip/useTooltip.doc.mjs +2 -2
  1029. package/src/TopNav/TopNav.doc.mjs +3 -3
  1030. package/src/TopNav/TopNav.test.tsx +2 -2
  1031. package/src/TopNav/TopNav.tsx +2 -4
  1032. package/src/TopNav/TopNavHeading.doc.mjs +1 -12
  1033. package/src/TopNav/TopNavHeading.tsx +44 -25
  1034. package/src/TopNav/TopNavItem.doc.mjs +1 -1
  1035. package/src/TopNav/TopNavItem.tsx +4 -22
  1036. package/src/TopNav/TopNavMegaMenu.doc.mjs +1 -1
  1037. package/src/TopNav/TopNavMegaMenu.tsx +62 -30
  1038. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
  1039. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +1 -1
  1040. package/src/TopNav/TopNavMegaMenuItem.doc.mjs +1 -1
  1041. package/src/TopNav/TopNavMegaMenuItem.tsx +3 -10
  1042. package/src/TopNav/TopNavMenu.doc.mjs +1 -1
  1043. package/src/TopNav/TopNavMenu.tsx +34 -32
  1044. package/src/TreeList/TreeList.doc.mjs +8 -3
  1045. package/src/TreeList/TreeList.test.tsx +216 -13
  1046. package/src/TreeList/TreeList.tsx +23 -1
  1047. package/src/TreeList/TreeListBranches.tsx +26 -3
  1048. package/src/TreeList/TreeListItem.tsx +90 -52
  1049. package/src/TreeList/TreeListTypes.ts +1 -18
  1050. package/src/TreeList/index.ts +19 -1
  1051. package/src/Typeahead/BaseTypeahead.doc.mjs +1 -1
  1052. package/src/Typeahead/BaseTypeahead.tsx +30 -2
  1053. package/src/Typeahead/Typeahead.doc.mjs +4 -3
  1054. package/src/Typeahead/Typeahead.test.tsx +138 -3
  1055. package/src/Typeahead/Typeahead.tsx +7 -1
  1056. package/src/Typeahead/TypeaheadItem.doc.mjs +1 -1
  1057. package/src/Typeahead/TypeaheadItem.tsx +1 -1
  1058. package/src/VStack/VStack.tsx +1 -1
  1059. package/src/VisuallyHidden/VisuallyHidden.doc.mjs +3 -3
  1060. package/src/VisuallyHidden/VisuallyHidden.tsx +1 -1
  1061. package/src/__tests__/babelPluginAddExtensions.test.ts +190 -0
  1062. package/src/__tests__/forcedColors.ts +60 -0
  1063. package/src/__tests__/inputWidthContract.test.tsx +8 -1
  1064. package/src/doc-mjs.d.ts +5 -2
  1065. package/src/docPropLiterals.test.ts +1 -1
  1066. package/src/docPropReferences.test.ts +1 -1
  1067. package/src/hooks/containerReveal.pool.stylex.ts +571 -0
  1068. package/src/hooks/index.ts +7 -0
  1069. package/src/hooks/useClickableContainer.doc.mjs +2 -2
  1070. package/src/hooks/useContainerReveal.doc.mjs +75 -0
  1071. package/src/hooks/useContainerReveal.test.tsx +116 -0
  1072. package/src/hooks/useContainerReveal.ts +181 -0
  1073. package/src/hooks/useEntryAnimation.doc.mjs +2 -2
  1074. package/src/hooks/useFocusTrap.doc.mjs +2 -2
  1075. package/src/hooks/useGridFocus.doc.mjs +2 -2
  1076. package/src/hooks/useGridFocus.ts +8 -6
  1077. package/src/hooks/useHotkeys.doc.mjs +2 -2
  1078. package/src/hooks/useImageMode.doc.mjs +2 -2
  1079. package/src/hooks/useImageMode.test.ts +1 -1
  1080. package/src/hooks/useInputContainer.doc.mjs +2 -2
  1081. package/src/hooks/useInputContainer.test.tsx +180 -0
  1082. package/src/hooks/useInputContainer.ts +36 -1
  1083. package/src/hooks/useInputStatusIcon.test.tsx +59 -0
  1084. package/src/hooks/useInputStatusIcon.tsx +12 -1
  1085. package/src/hooks/useKeyboardHint.doc.mjs +2 -2
  1086. package/src/hooks/useKeyboardHint.test.tsx +22 -0
  1087. package/src/hooks/useKeyboardHint.tsx +7 -3
  1088. package/src/hooks/useListFocus.doc.mjs +2 -2
  1089. package/src/hooks/useListFocus.ts +8 -7
  1090. package/src/hooks/useLongPress.test.tsx +18 -0
  1091. package/src/hooks/useLongPress.ts +12 -2
  1092. package/src/hooks/useMediaQuery.doc.mjs +2 -2
  1093. package/src/hooks/useOverflow.doc.mjs +2 -2
  1094. package/src/hooks/useScrollLock.doc.mjs +2 -2
  1095. package/src/hooks/useScrollOverflow.doc.mjs +2 -2
  1096. package/src/hooks/useStreamingText.doc.mjs +2 -2
  1097. package/src/hooks/useStreamingText.test.ts +46 -1
  1098. package/src/hooks/useStreamingText.ts +49 -7
  1099. package/src/hooks/useTreeFocus.doc.mjs +2 -2
  1100. package/src/hooks/useTreeFocus.test.tsx +53 -1
  1101. package/src/hooks/useTreeFocus.ts +13 -2
  1102. package/src/hooks/useTypeahead.test.tsx +150 -0
  1103. package/src/hooks/useTypeahead.ts +24 -9
  1104. package/src/i18n/InternationalizationProvider.doc.mjs +14 -2
  1105. package/src/i18n/InternationalizationProvider.tsx +6 -0
  1106. package/src/i18n/useDirection.ts +6 -3
  1107. package/src/i18n/useTranslator.doc.mjs +2 -2
  1108. package/src/index.ts +2 -18
  1109. package/src/theme/MediaTheme.doc.mjs +2 -2
  1110. package/src/theme/SyntaxTheme.doc.mjs +2 -2
  1111. package/src/theme/Theme.doc.mjs +2 -2
  1112. package/src/theme/Theme.tsx +3 -7
  1113. package/src/theme/contrast.test.ts +94 -0
  1114. package/src/theme/contrast.ts +99 -0
  1115. package/src/theme/defineTheme.test.ts +29 -30
  1116. package/src/theme/defineTheme.ts +11 -5
  1117. package/src/theme/derivedVarRegistry.test.ts +8 -1
  1118. package/src/theme/derivedVarRegistry.ts +15 -6
  1119. package/src/theme/expandColorScale.test.ts +401 -1
  1120. package/src/theme/expandColorScale.ts +143 -19
  1121. package/src/theme/expandTypeScale.test.ts +43 -0
  1122. package/src/theme/expandTypeScale.ts +17 -0
  1123. package/src/theme/generateThemeRules.test.ts +41 -20
  1124. package/src/theme/generateThemeRules.ts +11 -15
  1125. package/src/theme/index.ts +11 -13
  1126. package/src/theme/themeRegistry.test.ts +59 -0
  1127. package/src/theme/themeRegistry.ts +53 -0
  1128. package/src/theme/tokens.stylex.ts +0 -19
  1129. package/src/theme/types.ts +14 -13
  1130. package/src/theme/useTheme.doc.mjs +2 -2
  1131. package/src/theme/useTheme.test.tsx +48 -3
  1132. package/src/theme/useTheme.ts +100 -29
  1133. package/src/utils/focusOutline.stylex.ts +128 -0
  1134. package/src/utils/rtlStyles.ts +24 -2
  1135. package/dist/NavMenu/NavMenuItem.d.ts +0 -13
  1136. package/dist/NavMenu/NavMenuItem.d.ts.map +0 -1
  1137. package/dist/NavMenu/NavMenuItem.js +0 -16
  1138. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +0 -9
  1139. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +0 -1
  1140. package/dist/Thumbnail/thumbnail.markers.stylex.js +0 -14
  1141. package/dist/authoring/doc.d.ts +0 -145
  1142. package/dist/authoring/doc.d.ts.map +0 -1
  1143. package/dist/authoring/doc.js +0 -100
  1144. package/dist/authoring/index.d.ts +0 -29
  1145. package/dist/authoring/index.d.ts.map +0 -1
  1146. package/dist/authoring/index.js +0 -28
  1147. package/dist/authoring/integration.d.ts +0 -35
  1148. package/dist/authoring/integration.d.ts.map +0 -1
  1149. package/dist/authoring/integration.js +0 -30
  1150. package/dist/authoring/template.d.ts +0 -66
  1151. package/dist/authoring/template.d.ts.map +0 -1
  1152. package/dist/authoring/template.js +0 -55
  1153. package/dist/config.d.ts +0 -80
  1154. package/dist/config.d.ts.map +0 -1
  1155. package/dist/config.js +0 -40
  1156. package/dist/docs-types.d.ts +0 -969
  1157. package/dist/docs-types.d.ts.map +0 -1
  1158. package/dist/docs-types.js +0 -1
  1159. package/src/NavMenu/NavMenuItem.tsx +0 -19
  1160. package/src/Thumbnail/thumbnail.markers.stylex.ts +0 -12
  1161. package/src/authoring/doc.ts +0 -164
  1162. package/src/authoring/index.test.ts +0 -52
  1163. package/src/authoring/index.ts +0 -50
  1164. package/src/authoring/integration.ts +0 -42
  1165. package/src/authoring/template.ts +0 -74
  1166. package/src/config.test.ts +0 -16
  1167. package/src/config.ts +0 -92
  1168. package/src/docs-types.ts +0 -1108
@@ -3,7 +3,7 @@
3
3
  /**
4
4
  * @file Selector.test.tsx
5
5
  * @input Uses vitest, @testing-library/react, @testing-library/user-event
6
- * @output Unit tests for Selector
6
+ * @output Unit tests for Selector behavior and selected-item geometry
7
7
  * @position Tests; validates Selector behavior
8
8
  *
9
9
  * SYNC: When Selector.tsx API changes, update these tests.
@@ -18,20 +18,24 @@ import {
18
18
  within,
19
19
  } from '@testing-library/react';
20
20
  import userEvent from '@testing-library/user-event';
21
+ import {useState} from 'react';
21
22
  import {Selector} from './Selector';
22
23
  import {SelectorOption} from './SelectorOption';
23
24
  import {Icon} from '../Icon';
24
25
  import {InputGroup, InputGroupText} from '../InputGroup';
25
26
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
26
27
  import {defineTheme} from '../theme/defineTheme';
27
- import {generateThemeCSSFlat} from '../theme/generateThemeRules';
28
+ import {generateThemeCSS} from '../theme/generateThemeRules';
28
29
 
29
- function politeRegion(): HTMLElement | null {
30
- return document.querySelector('[data-astryx-live-region="polite"]');
30
+ function generateThemeTestCSS(theme: Parameters<typeof generateThemeCSS>[0]) {
31
+ const {prose, component} = generateThemeCSS(theme);
32
+ return [prose, component].filter(Boolean).join('\n\n');
31
33
  }
32
34
 
33
35
  // Mock showPopover and hidePopover methods since they're not implemented in jsdom
34
36
  beforeEach(() => {
37
+ // The live regions are a document-level singleton; start each test clean.
38
+ __resetLiveRegionsForTest();
35
39
  HTMLElement.prototype.showPopover = vi.fn(function (this: HTMLElement) {
36
40
  this.setAttribute('popover-open', '');
37
41
  const event = new Event('toggle', {bubbles: false});
@@ -66,6 +70,23 @@ const h = {hidden: true} as const;
66
70
 
67
71
  const OPTIONS = ['Apple', 'Banana', 'Cherry'];
68
72
 
73
+ // Mirrors useTypeahead's default resetMs — how long the typed buffer survives.
74
+ const TYPEAHEAD_RESET_MS = 750;
75
+
76
+ const politeRegion = () =>
77
+ document.querySelector('[data-astryx-live-region="polite"]');
78
+
79
+ /**
80
+ * Type onto an element with no awaits between keystrokes. Typeahead only
81
+ * accumulates while keys land inside the reset window, so an awaited
82
+ * `user.keyboard` per character would put CI stalls on the critical path.
83
+ */
84
+ function type(text: string, element: HTMLElement) {
85
+ for (const key of text) {
86
+ fireEvent.keyDown(element, {key});
87
+ }
88
+ }
89
+
69
90
  function rect({
70
91
  top,
71
92
  bottom,
@@ -94,36 +115,103 @@ function rect({
94
115
  };
95
116
  }
96
117
 
97
- function mockSelectorRects() {
118
+ function mockSelectorRects({
119
+ anchor = rect({top: 160, bottom: 190, height: 30}),
120
+ trigger = rect({top: 160, bottom: 190, height: 30}),
121
+ listbox = rect({top: 190, bottom: 310, height: 120}),
122
+ selectedItem = rect({top: 220, bottom: 250, height: 30}),
123
+ listboxLayoutHeight = listbox.height,
124
+ selectedItemLayoutTop = selectedItem.top - listbox.top,
125
+ selectedItemLayoutHeight = selectedItem.height,
126
+ viewportHeight = 200,
127
+ }: {
128
+ anchor?: DOMRect;
129
+ trigger?: DOMRect;
130
+ listbox?: DOMRect;
131
+ selectedItem?: DOMRect;
132
+ listboxLayoutHeight?: number;
133
+ selectedItemLayoutTop?: number;
134
+ selectedItemLayoutHeight?: number;
135
+ viewportHeight?: number;
136
+ } = {}) {
98
137
  const originalGetBoundingClientRect =
99
138
  HTMLElement.prototype.getBoundingClientRect;
100
139
  const originalInnerHeight = Object.getOwnPropertyDescriptor(
101
140
  window,
102
141
  'innerHeight',
103
142
  );
143
+ const originalOffsetTop = Object.getOwnPropertyDescriptor(
144
+ HTMLElement.prototype,
145
+ 'offsetTop',
146
+ );
147
+ const originalOffsetHeight = Object.getOwnPropertyDescriptor(
148
+ HTMLElement.prototype,
149
+ 'offsetHeight',
150
+ );
104
151
  HTMLElement.prototype.getBoundingClientRect = function () {
152
+ if (this.classList.contains('astryx-selector')) {
153
+ return anchor;
154
+ }
105
155
  // The trigger is role="combobox" by default, or a plain button with
106
156
  // aria-haspopup="listbox" in hasSearch mode — match either.
107
157
  if (
108
158
  this.getAttribute('role') === 'combobox' ||
109
159
  this.getAttribute('aria-haspopup') === 'listbox'
110
160
  ) {
111
- return rect({top: 160, bottom: 190, height: 30});
161
+ return trigger;
112
162
  }
113
163
  if (this.getAttribute('role') === 'listbox') {
114
- return rect({top: 190, bottom: 310, height: 120});
164
+ return listbox;
115
165
  }
116
166
  if (this.id.endsWith('-item-1')) {
117
- return rect({top: 220, bottom: 250, height: 30});
167
+ return selectedItem;
118
168
  }
119
169
  return originalGetBoundingClientRect.call(this);
120
170
  };
171
+ Object.defineProperty(HTMLElement.prototype, 'offsetTop', {
172
+ configurable: true,
173
+ get() {
174
+ if (this.getAttribute('role') === 'listbox') {
175
+ return 0;
176
+ }
177
+ if (this.id.endsWith('-item-1')) {
178
+ return selectedItemLayoutTop;
179
+ }
180
+ return 0;
181
+ },
182
+ });
183
+ Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
184
+ configurable: true,
185
+ get() {
186
+ if (this.getAttribute('role') === 'listbox') {
187
+ return listboxLayoutHeight;
188
+ }
189
+ if (this.id.endsWith('-item-1')) {
190
+ return selectedItemLayoutHeight;
191
+ }
192
+ return 0;
193
+ },
194
+ });
121
195
  Object.defineProperty(window, 'innerHeight', {
122
- value: 200,
196
+ value: viewportHeight,
123
197
  configurable: true,
124
198
  });
125
199
  return () => {
126
200
  HTMLElement.prototype.getBoundingClientRect = originalGetBoundingClientRect;
201
+ if (originalOffsetTop) {
202
+ Object.defineProperty(
203
+ HTMLElement.prototype,
204
+ 'offsetTop',
205
+ originalOffsetTop,
206
+ );
207
+ }
208
+ if (originalOffsetHeight) {
209
+ Object.defineProperty(
210
+ HTMLElement.prototype,
211
+ 'offsetHeight',
212
+ originalOffsetHeight,
213
+ );
214
+ }
127
215
  if (originalInnerHeight) {
128
216
  Object.defineProperty(window, 'innerHeight', originalInnerHeight);
129
217
  }
@@ -261,6 +349,81 @@ describe('Selector', () => {
261
349
  }
262
350
  });
263
351
 
352
+ it('aligns the selected item using untransformed layout geometry', async () => {
353
+ const restoreRects = mockSelectorRects({
354
+ anchor: rect({top: 160, bottom: 192, height: 32}),
355
+ trigger: rect({top: 166, bottom: 186, height: 20}),
356
+ // Simulate the 0.95 entry scale in visual rects while retaining the
357
+ // untransformed 120px list / 36px item offset used for positioning.
358
+ listbox: rect({top: 190, bottom: 304, height: 114}),
359
+ selectedItem: rect({
360
+ top: 224.2,
361
+ bottom: 254.6,
362
+ height: 30.4,
363
+ }),
364
+ listboxLayoutHeight: 120,
365
+ selectedItemLayoutTop: 36,
366
+ selectedItemLayoutHeight: 32,
367
+ viewportHeight: 900,
368
+ });
369
+ const user = userEvent.setup();
370
+ try {
371
+ render(
372
+ <Selector
373
+ label="Fruit"
374
+ options={OPTIONS}
375
+ value="Banana"
376
+ onChange={() => {}}
377
+ />,
378
+ );
379
+
380
+ await user.click(screen.getByRole('combobox'));
381
+ const popover = screen
382
+ .getByRole('listbox', {hidden: true})
383
+ .closest('[popover]');
384
+ await waitFor(() => {
385
+ // 68px geometric alignment plus the 1px optical correction.
386
+ expect(popover?.getAttribute('style')).toContain(
387
+ 'margin-block-start: -69px',
388
+ );
389
+ });
390
+ } finally {
391
+ restoreRects();
392
+ }
393
+ });
394
+
395
+ it('adds the border inset only to input-variant dropdowns', async () => {
396
+ const user = userEvent.setup();
397
+ const {unmount} = render(
398
+ <Selector
399
+ label="Input fruit"
400
+ options={OPTIONS}
401
+ value="Banana"
402
+ onChange={() => {}}
403
+ />,
404
+ );
405
+
406
+ await user.click(screen.getByRole('combobox'));
407
+ const inputDropdownClass = screen.getByRole('listbox', h).className;
408
+ unmount();
409
+
410
+ render(
411
+ <Selector
412
+ label="Ghost fruit"
413
+ options={OPTIONS}
414
+ value="Banana"
415
+ variant="ghost"
416
+ onChange={() => {}}
417
+ />,
418
+ );
419
+ await user.click(screen.getByRole('combobox'));
420
+ const ghostDropdownClass = screen.getByRole('listbox', h).className;
421
+
422
+ // The bordered input gets one extra StyleX rule for its border-width
423
+ // correction; the borderless ghost keeps the base menu inset.
424
+ expect(inputDropdownClass).not.toBe(ghostDropdownClass);
425
+ });
426
+
264
427
  it('does not apply selected-item overlay offset when placement is explicit', async () => {
265
428
  const restoreRects = mockSelectorRects();
266
429
  const user = userEvent.setup();
@@ -613,6 +776,28 @@ describe('Selector', () => {
613
776
  expect(within(listbox).getByText('No results found')).toBeInTheDocument();
614
777
  });
615
778
 
779
+ it('empty-state message is not exposed as a listbox child', async () => {
780
+ const user = userEvent.setup();
781
+ render(
782
+ <Selector
783
+ label="Fruit"
784
+ options={OPTIONS}
785
+ value="Apple"
786
+ onChange={() => {}}
787
+ hasSearch
788
+ />,
789
+ );
790
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
791
+ await user.type(screen.getByRole('combobox', h), 'xyz');
792
+
793
+ // role="listbox" only permits option/group children — the visual
794
+ // empty-state message must be presentational (it is announced through
795
+ // the result-count live region instead).
796
+ const listbox = screen.getByRole('listbox', h);
797
+ const empty = within(listbox).getByText('No results found');
798
+ expect(empty).toHaveAttribute('role', 'presentation');
799
+ });
800
+
616
801
  it('calls onChange when selecting a filtered option', async () => {
617
802
  const user = userEvent.setup();
618
803
  const onChange = vi.fn();
@@ -962,152 +1147,678 @@ describe('Selector', () => {
962
1147
  });
963
1148
  });
964
1149
 
965
- describe('InputGroup integration', () => {
966
- it('uses the group Field chrome and composes group and selector labels', () => {
967
- render(
968
- <InputGroup
969
- label="Destination"
970
- description="Where the alert should route"
971
- status={{type: 'error', message: 'Destination is required'}}>
972
- <InputGroupText>#</InputGroupText>
973
- <Selector
974
- label="Channel"
975
- isLabelHidden
976
- options={OPTIONS}
977
- placeholder="Choose a channel"
978
- />
979
- </InputGroup>,
980
- );
1150
+ describe('typeahead', () => {
1151
+ it('selects the matching option by typing on the closed trigger', async () => {
1152
+ const user = userEvent.setup();
1153
+ const onChange = vi.fn();
1154
+ render(<Selector label="Fruit" options={OPTIONS} onChange={onChange} />);
981
1155
 
982
- const group = screen.getByRole('group', {name: 'Destination'});
983
- const groupLabelID = group.getAttribute('aria-labelledby');
984
- const trigger = screen.getByRole('combobox', {
985
- name: 'Destination Channel',
986
- });
987
- const labelledByIDs =
988
- trigger.getAttribute('aria-labelledby')?.split(' ') ?? [];
1156
+ await user.tab();
1157
+ await user.keyboard('c');
989
1158
 
990
- expect(labelledByIDs).toHaveLength(2);
991
- expect(labelledByIDs[0]).toBe(groupLabelID);
992
- expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
993
- 'Channel',
994
- );
995
- expect(trigger).toHaveAttribute(
996
- 'aria-describedby',
997
- group.getAttribute('aria-describedby'),
1159
+ expect(onChange).toHaveBeenCalledWith('Cherry');
1160
+ // Native select parity: the value changes without opening the menu.
1161
+ expect(screen.getByRole('combobox')).toHaveAttribute(
1162
+ 'aria-expanded',
1163
+ 'false',
998
1164
  );
999
- expect(screen.getByText('#')).toBeInTheDocument();
1000
1165
  });
1001
1166
 
1002
- it('keeps disabled reasons described when grouped', () => {
1003
- render(
1004
- <InputGroup label="Destination">
1005
- <InputGroupText>#</InputGroupText>
1167
+ it('cycles through options sharing a first letter on repeated presses', async () => {
1168
+ const user = userEvent.setup();
1169
+ function Harness() {
1170
+ const [value, setValue] = useState<string | undefined>(undefined);
1171
+ return (
1006
1172
  <Selector
1007
- label="Channel"
1008
- isLabelHidden
1009
- options={OPTIONS}
1010
- isDisabled
1011
- disabledMessage="Choose a project first"
1173
+ label="City"
1174
+ options={['Austin', 'Chicago', 'Cleveland', 'Columbus']}
1175
+ value={value}
1176
+ onChange={setValue}
1012
1177
  />
1013
- </InputGroup>,
1014
- );
1178
+ );
1179
+ }
1180
+ render(<Harness />);
1015
1181
 
1016
- const trigger = screen.getByRole('combobox', {
1017
- name: 'Destination Channel',
1018
- });
1019
- const tooltip = screen.getByRole('tooltip', h);
1182
+ await user.tab();
1183
+ await user.keyboard('c');
1184
+ expect(screen.getByRole('combobox')).toHaveTextContent('Chicago');
1185
+ await user.keyboard('c');
1186
+ expect(screen.getByRole('combobox')).toHaveTextContent('Cleveland');
1187
+ await user.keyboard('c');
1188
+ expect(screen.getByRole('combobox')).toHaveTextContent('Columbus');
1189
+ // Wraps back around past non-matching options.
1190
+ await user.keyboard('c');
1191
+ expect(screen.getByRole('combobox')).toHaveTextContent('Chicago');
1192
+ });
1020
1193
 
1021
- expect(trigger).not.toBeDisabled();
1022
- expect(trigger).toHaveAttribute('aria-disabled', 'true');
1023
- expect(trigger.getAttribute('aria-describedby')).toContain(tooltip.id);
1194
+ it('advances past the current selection on a fresh single-letter press', async () => {
1195
+ const user = userEvent.setup();
1196
+ function Harness() {
1197
+ const [value, setValue] = useState<string | undefined>('Chicago');
1198
+ return (
1199
+ <Selector
1200
+ label="City"
1201
+ options={['Austin', 'Chicago', 'Cleveland', 'Columbus']}
1202
+ value={value}
1203
+ onChange={setValue}
1204
+ />
1205
+ );
1206
+ }
1207
+ render(<Harness />);
1208
+
1209
+ const trigger = screen.getByRole('combobox');
1210
+ await user.tab();
1211
+ // Native select parity: the selected option's own initial moves on to
1212
+ // the next match. Anchoring the search AT the selection instead of after
1213
+ // it re-matches the current value, and the duplicate-select guard then
1214
+ // swallows the keystroke entirely.
1215
+ type('c', trigger);
1216
+
1217
+ expect(trigger).toHaveTextContent('Cleveland');
1024
1218
  });
1025
- });
1026
1219
 
1027
- describe('disabledMessage', () => {
1028
- it('shows the reason tooltip on hover when disabled with a reason', async () => {
1220
+ it('advances the highlight past the current one with the menu open', async () => {
1221
+ const user = userEvent.setup();
1029
1222
  render(
1030
1223
  <Selector
1031
- label="Fruit"
1032
- options={OPTIONS}
1033
- isDisabled
1034
- disabledMessage="You need the Editor role"
1035
- data-testid="fruit-selector"
1224
+ label="City"
1225
+ options={['Austin', 'Chicago', 'Cleveland', 'Columbus']}
1226
+ value="Chicago"
1227
+ onChange={() => {}}
1036
1228
  />,
1037
1229
  );
1038
1230
 
1039
- const container = screen.getByTestId('fruit-selector');
1040
- const tooltip = screen.getByRole('tooltip', h);
1041
- expect(tooltip).toHaveTextContent('You need the Editor role');
1042
-
1043
- fireEvent.mouseEnter(container);
1044
- await waitFor(() => {
1045
- expect(tooltip).toHaveAttribute('popover-open');
1046
- });
1231
+ const trigger = screen.getByRole('combobox');
1232
+ await user.tab();
1233
+ await user.keyboard('{Enter}'); // opens with the highlight on Chicago
1234
+ type('c', trigger);
1047
1235
 
1048
- fireEvent.mouseLeave(container);
1049
- await waitFor(() => {
1050
- expect(tooltip).not.toHaveAttribute('popover-open');
1051
- });
1236
+ const activeId = trigger.getAttribute('aria-activedescendant');
1237
+ expect(document.getElementById(activeId ?? '')).toHaveTextContent(
1238
+ 'Cleveland',
1239
+ );
1052
1240
  });
1053
1241
 
1054
- it('shows the reason tooltip on keyboard focus', async () => {
1242
+ it('treats a space mid-buffer as part of the match, not as open', async () => {
1055
1243
  const user = userEvent.setup();
1244
+ const onChange = vi.fn();
1056
1245
  render(
1057
1246
  <Selector
1058
- label="Fruit"
1059
- options={OPTIONS}
1060
- isDisabled
1061
- disabledMessage="You need the Editor role"
1247
+ label="State"
1248
+ options={['New Jersey', 'New York']}
1249
+ onChange={onChange}
1062
1250
  />,
1063
1251
  );
1064
1252
 
1065
- const tooltip = screen.getByRole('tooltip', h);
1253
+ const trigger = screen.getByRole('combobox');
1066
1254
  await user.tab();
1067
- expect(screen.getByRole('combobox')).toHaveFocus();
1068
- await waitFor(() => {
1069
- expect(tooltip).toHaveAttribute('popover-open');
1070
- });
1255
+ // Synchronous keydowns: the buffer only accumulates while keystrokes
1256
+ // land inside the TYPEAHEAD_RESET_MS window, and awaiting between them
1257
+ // would put a CI stall on the critical path.
1258
+ type('new y', trigger);
1259
+
1260
+ expect(onChange).toHaveBeenLastCalledWith('New York');
1261
+ expect(trigger).toHaveAttribute('aria-expanded', 'false');
1071
1262
  });
1072
1263
 
1073
- it('does not render a tooltip when not disabled', () => {
1074
- render(
1075
- <Selector
1076
- label="Fruit"
1077
- options={OPTIONS}
1078
- disabledMessage="You need the Editor role"
1079
- />,
1264
+ it('opens and seeds the search input when typing on a closed hasSearch trigger', async () => {
1265
+ const user = userEvent.setup();
1266
+ render(<Selector label="Fruit" options={OPTIONS} hasSearch />);
1267
+
1268
+ await user.tab();
1269
+ await user.keyboard('c');
1270
+
1271
+ const search = screen.getByPlaceholderText('Search…');
1272
+ expect(search).toHaveValue('c');
1273
+ await waitFor(() => expect(search).toHaveFocus());
1274
+ });
1275
+
1276
+ it('accumulates a multi-character prefix and resets it after the timeout', async () => {
1277
+ const user = userEvent.setup();
1278
+ const onChange = vi.fn();
1279
+ // Controlled: the committed value has to feed back in, or the match
1280
+ // anchor stays -1 for the whole test and never gets exercised.
1281
+ function Harness() {
1282
+ const [value, setValue] = useState<string | undefined>(undefined);
1283
+ return (
1284
+ <Selector
1285
+ label="Fruit"
1286
+ options={['Apple', 'Banana', 'Blueberry']}
1287
+ value={value}
1288
+ onChange={next => {
1289
+ setValue(next);
1290
+ onChange(next);
1291
+ }}
1292
+ />
1293
+ );
1294
+ }
1295
+ render(<Harness />);
1296
+
1297
+ const trigger = screen.getByRole('combobox');
1298
+ await user.tab();
1299
+ type('b', trigger);
1300
+ expect(trigger).toHaveTextContent('Banana');
1301
+ // Within the window the buffer accumulates: "bl" → Blueberry. A
1302
+ // multi-character buffer refines, so it may keep the current match.
1303
+ type('l', trigger);
1304
+ expect(trigger).toHaveTextContent('Blueberry');
1305
+
1306
+ // Past the window the buffer starts fresh: "a" → Apple. A surviving
1307
+ // buffer would search "bla" and match nothing, so only a real reset
1308
+ // gets here — worth the one real wait in the suite.
1309
+ await new Promise(resolve =>
1310
+ setTimeout(resolve, TYPEAHEAD_RESET_MS + 100),
1080
1311
  );
1081
- expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
1312
+ type('a', trigger);
1313
+ expect(trigger).toHaveTextContent('Apple');
1082
1314
  });
1083
1315
 
1084
- it('does not render a tooltip when disabled without a reason', () => {
1085
- render(<Selector label="Fruit" options={OPTIONS} isDisabled />);
1086
- expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
1316
+ it('skips disabled options when matching', async () => {
1317
+ const user = userEvent.setup();
1318
+ function Harness() {
1319
+ const [value, setValue] = useState<string | undefined>(undefined);
1320
+ return (
1321
+ <Selector
1322
+ label="Fruit"
1323
+ options={[{value: 'Cherry', disabled: true}, 'Coconut']}
1324
+ value={value}
1325
+ onChange={setValue}
1326
+ />
1327
+ );
1328
+ }
1329
+ render(<Harness />);
1330
+
1331
+ const trigger = screen.getByRole('combobox');
1332
+ await user.tab();
1333
+ type('c', trigger);
1334
+ expect(trigger).toHaveTextContent('Coconut');
1335
+
1336
+ // The skip has to survive cycling too: with Coconut current, the next
1337
+ // press wraps onto the disabled Cherry and must pass over it.
1338
+ type('c', trigger);
1339
+ expect(trigger).toHaveTextContent('Coconut');
1340
+ expect(trigger).not.toHaveTextContent('Cherry');
1087
1341
  });
1088
1342
 
1089
- it('keeps the trigger focusable via aria-disabled when a reason is provided', () => {
1343
+ it('moves the highlight without committing when typing with the menu open', async () => {
1344
+ const user = userEvent.setup();
1345
+ const onChange = vi.fn();
1090
1346
  render(
1091
1347
  <Selector
1092
- label="Fruit"
1093
- options={OPTIONS}
1094
- isDisabled
1095
- disabledMessage="You need the Editor role"
1348
+ label="City"
1349
+ options={['Austin', 'Chicago', 'Cleveland']}
1350
+ onChange={onChange}
1096
1351
  />,
1097
1352
  );
1353
+
1354
+ await user.tab();
1355
+ await user.keyboard('{Enter}'); // open
1098
1356
  const trigger = screen.getByRole('combobox');
1099
- expect(trigger).not.toBeDisabled();
1100
- expect(trigger).toHaveAttribute('aria-disabled', 'true');
1101
- expect(trigger).toHaveAttribute('tabIndex', '0');
1357
+
1358
+ await user.keyboard('c');
1359
+ let activeId = trigger.getAttribute('aria-activedescendant');
1360
+ expect(document.getElementById(activeId ?? '')).toHaveTextContent(
1361
+ 'Chicago',
1362
+ );
1363
+
1364
+ // Repeated press cycles the highlight, still without committing.
1365
+ await user.keyboard('c');
1366
+ activeId = trigger.getAttribute('aria-activedescendant');
1367
+ expect(document.getElementById(activeId ?? '')).toHaveTextContent(
1368
+ 'Cleveland',
1369
+ );
1370
+ expect(onChange).not.toHaveBeenCalled();
1371
+ // aria-activedescendant already announces each match, so announcing
1372
+ // again here would make a screen reader say every match twice.
1373
+ // useAnnounce writes its text in a rAF callback, so let a frame pass —
1374
+ // asserting before it runs would pass no matter what the code does.
1375
+ await new Promise(resolve => requestAnimationFrame(() => resolve(null)));
1376
+ expect(politeRegion()?.textContent ?? '').toBe('');
1377
+
1378
+ await user.keyboard('{Enter}');
1379
+ expect(onChange).toHaveBeenCalledWith('Cleveland');
1102
1380
  });
1103
1381
 
1104
- it('links the reason tooltip from the trigger via aria-describedby', () => {
1382
+ it('does not fire onChange when the only match is already selected', async () => {
1383
+ const user = userEvent.setup();
1384
+ const onChange = vi.fn();
1105
1385
  render(
1106
1386
  <Selector
1107
1387
  label="Fruit"
1108
1388
  options={OPTIONS}
1109
- isDisabled
1110
- disabledMessage="You need the Editor role"
1389
+ value="Cherry"
1390
+ onChange={onChange}
1391
+ />,
1392
+ );
1393
+
1394
+ await user.tab();
1395
+ await user.keyboard('c');
1396
+
1397
+ expect(onChange).not.toHaveBeenCalled();
1398
+ });
1399
+
1400
+ it('ignores printable keys pressed with ctrl or meta modifiers', async () => {
1401
+ const user = userEvent.setup();
1402
+ const onChange = vi.fn();
1403
+ render(<Selector label="Fruit" options={OPTIONS} onChange={onChange} />);
1404
+
1405
+ await user.tab();
1406
+ await user.keyboard('{Control>}c{/Control}{Meta>}b{/Meta}');
1407
+
1408
+ expect(onChange).not.toHaveBeenCalled();
1409
+ });
1410
+
1411
+ it('announces the committed option to screen readers', async () => {
1412
+ const user = userEvent.setup();
1413
+ render(<Selector label="Fruit" options={OPTIONS} onChange={() => {}} />);
1414
+
1415
+ await user.tab();
1416
+ await user.keyboard('c');
1417
+
1418
+ // The trigger keeps focus and the menu never opens, so nothing else
1419
+ // prompts a re-read. The polite live region carries the new value.
1420
+ await waitFor(() => {
1421
+ expect(politeRegion()).toHaveTextContent('Cherry');
1422
+ });
1423
+ });
1424
+
1425
+ it('does not select while focusable-disabled', async () => {
1426
+ const user = userEvent.setup();
1427
+ const onChange = vi.fn();
1428
+ render(
1429
+ <Selector
1430
+ label="Fruit"
1431
+ options={OPTIONS}
1432
+ onChange={onChange}
1433
+ isDisabled
1434
+ disabledMessage="Ask an admin"
1435
+ />,
1436
+ );
1437
+
1438
+ // aria-disabled keeps the trigger focusable, so keydowns still arrive.
1439
+ screen.getByRole('combobox').focus();
1440
+ await user.keyboard('c');
1441
+
1442
+ expect(onChange).not.toHaveBeenCalled();
1443
+ });
1444
+
1445
+ it('cycles without duplicating changeAction while an action is pending', async () => {
1446
+ const user = userEvent.setup();
1447
+ const calls: string[] = [];
1448
+ render(
1449
+ <Selector
1450
+ label="City"
1451
+ options={['Chicago', 'Cleveland', 'Columbus']}
1452
+ value={undefined}
1453
+ changeAction={async value => {
1454
+ calls.push(value);
1455
+ // Never settles, so the value prop never catches up to what the
1456
+ // trigger already shows.
1457
+ await new Promise<void>(() => {});
1458
+ }}
1459
+ />,
1460
+ );
1461
+
1462
+ const trigger = screen.getByRole('combobox');
1463
+ await user.tab();
1464
+ type('ccc', trigger);
1465
+
1466
+ // The anchor must come from the optimistic value, not the stale prop.
1467
+ // Three options make that observable: with a stale anchor every press
1468
+ // re-matches Chicago, which the duplicate guard then swallows.
1469
+ expect(calls).toEqual(['Chicago', 'Cleveland', 'Columbus']);
1470
+ });
1471
+
1472
+ it('starts a fresh buffer after selecting from the open menu', async () => {
1473
+ const user = userEvent.setup();
1474
+ const onChange = vi.fn();
1475
+ render(
1476
+ <Selector
1477
+ label="Animal"
1478
+ options={['Cat', 'Dog']}
1479
+ onChange={onChange}
1480
+ />,
1481
+ );
1482
+
1483
+ await user.tab();
1484
+ await user.keyboard('{Enter}'); // open
1485
+ await user.keyboard('d'); // highlight Dog
1486
+ await user.keyboard('{Enter}'); // commit Dog, closes
1487
+ onChange.mockClear();
1488
+
1489
+ // The stale 'd' must not linger: 'c' is a fresh buffer, not "dc".
1490
+ await user.keyboard('c');
1491
+ expect(onChange).toHaveBeenCalledWith('Cat');
1492
+ });
1493
+
1494
+ it('starts a fresh buffer after the value is cleared', async () => {
1495
+ const user = userEvent.setup();
1496
+ const onChange = vi.fn();
1497
+ function Harness() {
1498
+ const [value, setValue] = useState<string | null>('Dog');
1499
+ return (
1500
+ <Selector
1501
+ label="Animal"
1502
+ options={['Cat', 'Dog']}
1503
+ hasClear
1504
+ value={value}
1505
+ onChange={next => {
1506
+ setValue(next);
1507
+ onChange(next);
1508
+ }}
1509
+ />
1510
+ );
1511
+ }
1512
+ render(<Harness />);
1513
+
1514
+ const trigger = screen.getByRole('combobox');
1515
+ await user.tab();
1516
+ // Fills the buffer with 'd' without committing — Dog is already current.
1517
+ type('d', trigger);
1518
+ fireEvent.keyDown(trigger, {key: 'Delete'});
1519
+ expect(onChange).toHaveBeenLastCalledWith(null);
1520
+
1521
+ // The stale 'd' must not survive the clear: 'c' is a fresh buffer, not
1522
+ // "dc", which would match nothing and leave the value cleared.
1523
+ type('c', trigger);
1524
+ expect(onChange).toHaveBeenLastCalledWith('Cat');
1525
+ });
1526
+
1527
+ it('matches on the label and commits the value', async () => {
1528
+ const user = userEvent.setup();
1529
+ const onChange = vi.fn();
1530
+ // Values deliberately crossed against labels: a native select matches
1531
+ // the rendered text and reports the value.
1532
+ function Harness() {
1533
+ const [value, setValue] = useState<string | undefined>(undefined);
1534
+ return (
1535
+ <Selector
1536
+ label="Fruit"
1537
+ options={[
1538
+ {value: 'zzz', label: 'Apple'},
1539
+ {value: 'apple', label: 'Zebra'},
1540
+ ]}
1541
+ value={value}
1542
+ onChange={next => {
1543
+ setValue(next);
1544
+ onChange(next);
1545
+ }}
1546
+ />
1547
+ );
1548
+ }
1549
+ render(<Harness />);
1550
+
1551
+ const trigger = screen.getByRole('combobox');
1552
+ await user.tab();
1553
+ type('a', trigger);
1554
+
1555
+ expect(onChange).toHaveBeenCalledWith('zzz');
1556
+ expect(trigger).toHaveTextContent('Apple');
1557
+
1558
+ // No other label starts with "a" — the option whose *value* is 'apple'
1559
+ // is labelled Zebra — so a second press stays put and commits nothing.
1560
+ type('a', trigger);
1561
+ expect(onChange).toHaveBeenCalledTimes(1);
1562
+ });
1563
+
1564
+ it('matches across sections, ignoring dividers and group titles', async () => {
1565
+ const user = userEvent.setup();
1566
+ const onChange = vi.fn();
1567
+ render(
1568
+ <Selector
1569
+ label="Fruit"
1570
+ options={[
1571
+ 'Almond',
1572
+ {type: 'divider'},
1573
+ {
1574
+ type: 'section',
1575
+ title: 'Tropical',
1576
+ options: [
1577
+ {value: 'mango', label: 'Mango'},
1578
+ {value: 'papaya', label: 'Papaya'},
1579
+ ],
1580
+ },
1581
+ ]}
1582
+ onChange={onChange}
1583
+ />,
1584
+ );
1585
+
1586
+ const trigger = screen.getByRole('combobox');
1587
+ await user.tab();
1588
+ type('p', trigger);
1589
+ expect(onChange).toHaveBeenCalledWith('papaya');
1590
+
1591
+ // The section title "Tropical" is decoration, not an option.
1592
+ onChange.mockClear();
1593
+ type('t', trigger);
1594
+ expect(onChange).not.toHaveBeenCalled();
1595
+ });
1596
+
1597
+ it('keeps aria-activedescendant on the matched option across a section', async () => {
1598
+ const user = userEvent.setup();
1599
+ render(
1600
+ <Selector
1601
+ label="Fruit"
1602
+ options={[
1603
+ 'Almond',
1604
+ {type: 'divider'},
1605
+ {
1606
+ type: 'section',
1607
+ title: 'Berries',
1608
+ options: [{value: 'blueberry', label: 'Blueberry'}],
1609
+ },
1610
+ ]}
1611
+ value="Almond"
1612
+ onChange={() => {}}
1613
+ />,
1614
+ );
1615
+
1616
+ const trigger = screen.getByRole('combobox');
1617
+ await user.tab();
1618
+ await user.keyboard('{Enter}'); // opens on Almond
1619
+ type('b', trigger);
1620
+
1621
+ const activeId = trigger.getAttribute('aria-activedescendant');
1622
+ expect(document.getElementById(activeId ?? '')).toHaveTextContent(
1623
+ 'Blueberry',
1624
+ );
1625
+ });
1626
+
1627
+ it('anchors at the top when the value matches no option', async () => {
1628
+ const user = userEvent.setup();
1629
+ const onChange = vi.fn();
1630
+ render(
1631
+ <Selector
1632
+ label="Fruit"
1633
+ options={['Apple', 'Apricot']}
1634
+ value="Durian"
1635
+ onChange={onChange}
1636
+ />,
1637
+ );
1638
+
1639
+ const trigger = screen.getByRole('combobox');
1640
+ await user.tab();
1641
+ type('a', trigger);
1642
+
1643
+ // Nothing is really selected, so the first match must stay reachable.
1644
+ expect(onChange).toHaveBeenCalledWith('Apple');
1645
+ });
1646
+
1647
+ it('lets Space open the menu after an abandoned typeahead', async () => {
1648
+ const user = userEvent.setup();
1649
+ render(<Selector label="Fruit" options={OPTIONS} />);
1650
+
1651
+ const trigger = screen.getByRole('combobox');
1652
+ await user.tab();
1653
+ await user.keyboard('{Enter}'); // open
1654
+ await user.keyboard('z'); // no match; buffer holds "z"
1655
+ await user.keyboard('{Escape}'); // close, abandoning the buffer
1656
+
1657
+ // A live "z" buffer would swallow Space as a match character.
1658
+ await user.keyboard(' ');
1659
+ expect(trigger).toHaveAttribute('aria-expanded', 'true');
1660
+ });
1661
+
1662
+ it('seeds every character typed before the search input takes focus', async () => {
1663
+ const user = userEvent.setup();
1664
+ render(<Selector label="Fruit" options={OPTIONS} hasSearch />);
1665
+
1666
+ await user.tab();
1667
+ // The popup opens on the first key, but focus only moves to the search
1668
+ // input on the next frame — the second key still lands on the trigger.
1669
+ await user.keyboard('ch');
1670
+
1671
+ const search = screen.getByPlaceholderText('Search…');
1672
+ await waitFor(() => expect(search).toHaveValue('ch'));
1673
+ });
1674
+ });
1675
+
1676
+ describe('InputGroup integration', () => {
1677
+ it('uses the group Field chrome and composes group and selector labels', () => {
1678
+ render(
1679
+ <InputGroup
1680
+ label="Destination"
1681
+ description="Where the alert should route"
1682
+ status={{type: 'error', message: 'Destination is required'}}>
1683
+ <InputGroupText>#</InputGroupText>
1684
+ <Selector
1685
+ label="Channel"
1686
+ isLabelHidden
1687
+ options={OPTIONS}
1688
+ placeholder="Choose a channel"
1689
+ />
1690
+ </InputGroup>,
1691
+ );
1692
+
1693
+ const group = screen.getByRole('group', {name: 'Destination'});
1694
+ const groupLabelID = group.getAttribute('aria-labelledby');
1695
+ const trigger = screen.getByRole('combobox', {
1696
+ name: 'Destination Channel',
1697
+ });
1698
+ const labelledByIDs =
1699
+ trigger.getAttribute('aria-labelledby')?.split(' ') ?? [];
1700
+
1701
+ expect(labelledByIDs).toHaveLength(2);
1702
+ expect(labelledByIDs[0]).toBe(groupLabelID);
1703
+ expect(document.getElementById(labelledByIDs[1])).toHaveTextContent(
1704
+ 'Channel',
1705
+ );
1706
+ expect(trigger).toHaveAttribute(
1707
+ 'aria-describedby',
1708
+ group.getAttribute('aria-describedby'),
1709
+ );
1710
+ expect(screen.getByText('#')).toBeInTheDocument();
1711
+ });
1712
+
1713
+ it('keeps disabled reasons described when grouped', () => {
1714
+ render(
1715
+ <InputGroup label="Destination">
1716
+ <InputGroupText>#</InputGroupText>
1717
+ <Selector
1718
+ label="Channel"
1719
+ isLabelHidden
1720
+ options={OPTIONS}
1721
+ isDisabled
1722
+ disabledMessage="Choose a project first"
1723
+ />
1724
+ </InputGroup>,
1725
+ );
1726
+
1727
+ const trigger = screen.getByRole('combobox', {
1728
+ name: 'Destination Channel',
1729
+ });
1730
+ const tooltip = screen.getByRole('tooltip', h);
1731
+
1732
+ expect(trigger).not.toBeDisabled();
1733
+ expect(trigger).toHaveAttribute('aria-disabled', 'true');
1734
+ expect(trigger.getAttribute('aria-describedby')).toContain(tooltip.id);
1735
+ });
1736
+ });
1737
+
1738
+ describe('disabledMessage', () => {
1739
+ it('shows the reason tooltip on hover when disabled with a reason', async () => {
1740
+ render(
1741
+ <Selector
1742
+ label="Fruit"
1743
+ options={OPTIONS}
1744
+ isDisabled
1745
+ disabledMessage="You need the Editor role"
1746
+ data-testid="fruit-selector"
1747
+ />,
1748
+ );
1749
+
1750
+ const container = screen.getByTestId('fruit-selector');
1751
+ const tooltip = screen.getByRole('tooltip', h);
1752
+ expect(tooltip).toHaveTextContent('You need the Editor role');
1753
+
1754
+ fireEvent.mouseEnter(container);
1755
+ await waitFor(() => {
1756
+ expect(tooltip).toHaveAttribute('popover-open');
1757
+ });
1758
+
1759
+ fireEvent.mouseLeave(container);
1760
+ await waitFor(() => {
1761
+ expect(tooltip).not.toHaveAttribute('popover-open');
1762
+ });
1763
+ });
1764
+
1765
+ it('shows the reason tooltip on keyboard focus', async () => {
1766
+ const user = userEvent.setup();
1767
+ render(
1768
+ <Selector
1769
+ label="Fruit"
1770
+ options={OPTIONS}
1771
+ isDisabled
1772
+ disabledMessage="You need the Editor role"
1773
+ />,
1774
+ );
1775
+
1776
+ const tooltip = screen.getByRole('tooltip', h);
1777
+ await user.tab();
1778
+ expect(screen.getByRole('combobox')).toHaveFocus();
1779
+ await waitFor(() => {
1780
+ expect(tooltip).toHaveAttribute('popover-open');
1781
+ });
1782
+ });
1783
+
1784
+ it('does not render a tooltip when not disabled', () => {
1785
+ render(
1786
+ <Selector
1787
+ label="Fruit"
1788
+ options={OPTIONS}
1789
+ disabledMessage="You need the Editor role"
1790
+ />,
1791
+ );
1792
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
1793
+ });
1794
+
1795
+ it('does not render a tooltip when disabled without a reason', () => {
1796
+ render(<Selector label="Fruit" options={OPTIONS} isDisabled />);
1797
+ expect(screen.queryByRole('tooltip', h)).not.toBeInTheDocument();
1798
+ });
1799
+
1800
+ it('keeps the trigger focusable via aria-disabled when a reason is provided', () => {
1801
+ render(
1802
+ <Selector
1803
+ label="Fruit"
1804
+ options={OPTIONS}
1805
+ isDisabled
1806
+ disabledMessage="You need the Editor role"
1807
+ />,
1808
+ );
1809
+ const trigger = screen.getByRole('combobox');
1810
+ expect(trigger).not.toBeDisabled();
1811
+ expect(trigger).toHaveAttribute('aria-disabled', 'true');
1812
+ expect(trigger).toHaveAttribute('tabIndex', '0');
1813
+ });
1814
+
1815
+ it('links the reason tooltip from the trigger via aria-describedby', () => {
1816
+ render(
1817
+ <Selector
1818
+ label="Fruit"
1819
+ options={OPTIONS}
1820
+ isDisabled
1821
+ disabledMessage="You need the Editor role"
1111
1822
  />,
1112
1823
  );
1113
1824
  const trigger = screen.getByRole('combobox');
@@ -1219,6 +1930,99 @@ describe('Selector statusVariant forwarding', () => {
1219
1930
  'detached',
1220
1931
  );
1221
1932
  });
1933
+
1934
+ it('keeps the on-field status icon for the attached variant', () => {
1935
+ const {container} = render(
1936
+ <Selector
1937
+ label="Fruit"
1938
+ options={['Apple', 'Banana']}
1939
+ status={{type: 'error', message: 'Required'}}
1940
+ />,
1941
+ );
1942
+ // Attached: the status glyph replaces the chevron indicator on the field.
1943
+ expect(
1944
+ container.querySelector('.astryx-selector-indicator-icon'),
1945
+ ).toBeNull();
1946
+ });
1947
+
1948
+ it('suppresses the on-field status icon for the detached variant', () => {
1949
+ const {container} = render(
1950
+ <Selector
1951
+ label="Fruit"
1952
+ options={['Apple', 'Banana']}
1953
+ status={{type: 'error', message: 'Required'}}
1954
+ statusVariant="detached"
1955
+ />,
1956
+ );
1957
+ // Detached: the message box below carries its own leading icon, so the
1958
+ // field keeps its chevron indicator rather than duplicating the glyph.
1959
+ expect(
1960
+ container.querySelector('.astryx-selector-indicator-icon'),
1961
+ ).not.toBeNull();
1962
+ });
1963
+
1964
+ it('detaches attached status by default for the ghost variant', () => {
1965
+ const {container} = render(
1966
+ <Selector
1967
+ label="Fruit"
1968
+ options={['Apple', 'Banana']}
1969
+ variant="ghost"
1970
+ status={{type: 'error', message: 'Required'}}
1971
+ />,
1972
+ );
1973
+ expect(container.querySelector('.astryx-selector')).toHaveAttribute(
1974
+ 'data-variant',
1975
+ 'ghost',
1976
+ );
1977
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1978
+ 'data-variant',
1979
+ 'detached',
1980
+ );
1981
+ });
1982
+
1983
+ it('uses a status tooltip for ghost selectors when requested', () => {
1984
+ const {container} = render(
1985
+ <Selector
1986
+ label="Fruit"
1987
+ options={['Apple', 'Banana']}
1988
+ variant="ghost"
1989
+ status={{type: 'warning', message: 'Visible to all users'}}
1990
+ statusVariant="tooltip"
1991
+ />,
1992
+ );
1993
+ expect(container.querySelector('.astryx-field-status')).toBeNull();
1994
+ const statusButton = screen.getByRole('button', {
1995
+ name: /warning details/i,
1996
+ });
1997
+ const tooltip = screen.getByRole('tooltip', h);
1998
+ expect(tooltip).toHaveTextContent('Visible to all users');
1999
+ expect(statusButton.getAttribute('aria-describedby')).toContain(tooltip.id);
2000
+ expect(
2001
+ screen.getByRole('combobox').getAttribute('aria-describedby'),
2002
+ ).toContain(tooltip.id);
2003
+ });
2004
+ });
2005
+
2006
+ describe('Selector empty-state theme target', () => {
2007
+ const OPTIONS = ['Apple', 'Banana', 'Cherry'];
2008
+
2009
+ it('renders the astryx-selector-empty-state target on the "No results found" element', async () => {
2010
+ const user = userEvent.setup();
2011
+ const {container} = render(
2012
+ <Selector
2013
+ label="Fruit"
2014
+ options={OPTIONS}
2015
+ onChange={() => {}}
2016
+ hasSearch
2017
+ />,
2018
+ );
2019
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
2020
+ await user.type(screen.getByRole('combobox', h), 'xyz');
2021
+
2022
+ const empty = container.querySelector('.astryx-selector-empty-state');
2023
+ expect(empty).not.toBeNull();
2024
+ expect(empty).toHaveTextContent('No results found');
2025
+ });
1222
2026
  });
1223
2027
 
1224
2028
  describe('Selector clear icon theme target', () => {
@@ -1319,7 +2123,7 @@ describe('Selector clear icon theme target', () => {
1319
2123
  },
1320
2124
  },
1321
2125
  });
1322
- const css = generateThemeCSSFlat(theme);
2126
+ const css = generateThemeTestCSS(theme);
1323
2127
  expect(css).toContain('.astryx-selector-clear-icon {');
1324
2128
  expect(css).toContain('width: 12px');
1325
2129
  expect(css).toContain('height: 12px');
@@ -1367,9 +2171,12 @@ describe('Selector indicator (chevron) icon theme target', () => {
1367
2171
  });
1368
2172
  });
1369
2173
 
1370
- it('renders the default icon (inherit color, sm size) byte-identically', () => {
2174
+ it('renders the default icon (secondary color, sm size) byte-identically', () => {
1371
2175
  // Pixel-identical default guard: the chevron glyph must carry the exact
1372
- // same StyleX color/size classes as a standalone inherit/sm icon. The added
2176
+ // same StyleX color/size classes as a standalone secondary/sm icon. The
2177
+ // glyph now sets --color-icon-secondary itself rather than inheriting it
2178
+ // from a wrapper span that set the same token, so the rendered color is
2179
+ // unchanged. The added
1373
2180
  // target class + data-state are purely additive — they change nothing until
1374
2181
  // a theme targets them.
1375
2182
  const {container} = render(
@@ -1378,12 +2185,12 @@ describe('Selector indicator (chevron) icon theme target', () => {
1378
2185
  const icon = getIndicatorIcon(container);
1379
2186
 
1380
2187
  const {container: refContainer} = render(
1381
- <Icon icon="chevronDown" size="sm" color="inherit" />,
2188
+ <Icon icon="chevronDown" size="sm" color="secondary" />,
1382
2189
  );
1383
2190
  const refIcon = refContainer.querySelector('.astryx-icon') as HTMLElement;
1384
2191
 
1385
2192
  // Exclude the additive theme-target classes (the stable target + its
1386
- // reflected state class) so only the StyleX color/size classes remain.
2193
+ // reflected state class) so only StyleX classes remain.
1387
2194
  const themeTargetClasses = new Set([
1388
2195
  'astryx-selector-indicator-icon',
1389
2196
  'collapsed',
@@ -1395,7 +2202,14 @@ describe('Selector indicator (chevron) icon theme target', () => {
1395
2202
  .filter(c => !themeTargetClasses.has(c))
1396
2203
  .sort();
1397
2204
 
1398
- expect(styleClasses(icon)).toEqual(styleClasses(refIcon));
2205
+ // A superset, not an exact match: the chevron additionally carries the
2206
+ // rotation styles, which live on the glyph precisely so a theme can reach
2207
+ // the transform through the same selector as the color. The guard that
2208
+ // matters is that every color/size class of a standalone icon is still
2209
+ // present — i.e. the default look has not drifted.
2210
+ expect(styleClasses(icon)).toEqual(
2211
+ expect.arrayContaining(styleClasses(refIcon)),
2212
+ );
1399
2213
  });
1400
2214
 
1401
2215
  it('exposes selector-indicator-icon so a theme reaches the icon size and per-state color', () => {
@@ -1413,7 +2227,7 @@ describe('Selector indicator (chevron) icon theme target', () => {
1413
2227
  },
1414
2228
  },
1415
2229
  });
1416
- const css = generateThemeCSSFlat(theme);
2230
+ const css = generateThemeTestCSS(theme);
1417
2231
  expect(css).toContain('.astryx-selector-indicator-icon {');
1418
2232
  expect(css).toContain('width: 14px');
1419
2233
  expect(css).toContain('height: 14px');
@@ -1421,3 +2235,247 @@ describe('Selector indicator (chevron) icon theme target', () => {
1421
2235
  expect(css).toContain('color: var(--color-icon-primary)');
1422
2236
  });
1423
2237
  });
2238
+
2239
+ describe('Selector search affordances', () => {
2240
+ it('renders a decorative (aria-hidden) magnifier icon whenever hasSearch is on', async () => {
2241
+ const user = userEvent.setup();
2242
+ render(
2243
+ <Selector
2244
+ label="Fruit"
2245
+ options={OPTIONS}
2246
+ value="Apple"
2247
+ onChange={() => {}}
2248
+ hasSearch
2249
+ />,
2250
+ );
2251
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
2252
+ const search = screen.getByRole('combobox', {hidden: true});
2253
+ // The search field is a TextInput; the magnifier is its startIcon, so it
2254
+ // sits inside the input container as a sibling of the <input>.
2255
+ const container = search.parentElement;
2256
+ const magnifier = container?.querySelector('.astryx-icon');
2257
+ expect(magnifier).toBeTruthy();
2258
+ // Decorative: the icon is hidden from assistive tech and carries no name.
2259
+ expect(magnifier?.getAttribute('aria-hidden')).toBe('true');
2260
+ expect(magnifier?.getAttribute('aria-label')).toBeNull();
2261
+ });
2262
+
2263
+ it('renders the clear button once a query is typed and clears + refocuses on click', async () => {
2264
+ const user = userEvent.setup();
2265
+ render(
2266
+ <Selector
2267
+ label="Fruit"
2268
+ options={OPTIONS}
2269
+ value="Apple"
2270
+ onChange={() => {}}
2271
+ hasSearch
2272
+ />,
2273
+ );
2274
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
2275
+ const search = screen.getByRole('combobox', {hidden: true});
2276
+ await user.type(search, 'ap');
2277
+ expect(search).toHaveValue('ap');
2278
+
2279
+ // The clear button is TextInput's built-in hasClear affordance; its name is
2280
+ // derived from the field label ("Search options").
2281
+ const clear = screen.getByRole('button', {
2282
+ name: 'Clear Search options',
2283
+ hidden: true,
2284
+ });
2285
+
2286
+ await user.click(clear);
2287
+ expect(search).toHaveValue('');
2288
+ expect(search).toHaveFocus();
2289
+ });
2290
+
2291
+ it('does not render the clear button when the query is empty', async () => {
2292
+ const user = userEvent.setup();
2293
+ render(
2294
+ <Selector
2295
+ label="Fruit"
2296
+ options={OPTIONS}
2297
+ value="Apple"
2298
+ onChange={() => {}}
2299
+ hasSearch
2300
+ />,
2301
+ );
2302
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
2303
+ expect(
2304
+ screen.queryByRole('button', {
2305
+ name: 'Clear Search options',
2306
+ hidden: true,
2307
+ }),
2308
+ ).not.toBeInTheDocument();
2309
+ });
2310
+
2311
+ it('keeps the combobox contract on the input, not the affordances', async () => {
2312
+ const user = userEvent.setup();
2313
+ render(
2314
+ <Selector
2315
+ label="Fruit"
2316
+ options={OPTIONS}
2317
+ value="Apple"
2318
+ onChange={() => {}}
2319
+ hasSearch
2320
+ />,
2321
+ );
2322
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
2323
+ // Exactly one combobox — the input. The magnifier and clear button are not
2324
+ // part of the combobox contract.
2325
+ const comboboxes = screen.getAllByRole('combobox', {hidden: true});
2326
+ expect(comboboxes).toHaveLength(1);
2327
+ expect(comboboxes[0].tagName).toBe('INPUT');
2328
+ expect(comboboxes[0]).toHaveAttribute('aria-autocomplete', 'list');
2329
+ });
2330
+
2331
+ it('tabs from the search input to the clear button (keeping the popup open) when a query is showing it', async () => {
2332
+ const user = userEvent.setup();
2333
+ render(
2334
+ <Selector
2335
+ label="Fruit"
2336
+ options={OPTIONS}
2337
+ value="Apple"
2338
+ onChange={() => {}}
2339
+ hasSearch
2340
+ />,
2341
+ );
2342
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
2343
+ const trigger = screen.getByRole('button', {name: 'Fruit'});
2344
+ const search = screen.getByRole('combobox', {hidden: true});
2345
+ await user.type(search, 'ap');
2346
+ expect(search).toHaveFocus();
2347
+
2348
+ // Forward-tab lands on the clear (✕) button and the popup stays open, so
2349
+ // the affordance is keyboard-reachable rather than being skipped when the
2350
+ // input's Tab dismisses the popup.
2351
+ await user.tab();
2352
+ const clear = screen.getByRole('button', {
2353
+ name: 'Clear Search options',
2354
+ hidden: true,
2355
+ });
2356
+ expect(clear).toHaveFocus();
2357
+ expect(trigger).toHaveAttribute('aria-expanded', 'true');
2358
+ });
2359
+ });
2360
+
2361
+ describe('Selector selected-marker theme target (selector-check)', () => {
2362
+ const openOptions = (): HTMLElement[] => screen.getAllByRole('option', h);
2363
+
2364
+ it('renders the astryx-selector-check target on the selected row only', () => {
2365
+ render(
2366
+ <Selector
2367
+ label="Fruit"
2368
+ options={OPTIONS}
2369
+ value="Banana"
2370
+ onChange={() => {}}
2371
+ isDefaultOpen
2372
+ />,
2373
+ );
2374
+ const options = openOptions();
2375
+ const selected = options.find(
2376
+ o => o.getAttribute('aria-selected') === 'true',
2377
+ )!;
2378
+ const check = selected.querySelector('.astryx-selector-check');
2379
+ expect(check).toBeInTheDocument();
2380
+ // The target lands on the checkmark glyph itself, so a theme can restyle or
2381
+ // hide it (e.g. to compose its own selected indicator via renderOption).
2382
+ expect(check).toHaveClass('astryx-icon');
2383
+
2384
+ const unselected = options.filter(
2385
+ o => o.getAttribute('aria-selected') !== 'true',
2386
+ );
2387
+ for (const row of unselected) {
2388
+ expect(row.querySelector('.astryx-selector-check')).not.toBeInTheDocument();
2389
+ }
2390
+ });
2391
+
2392
+ it('renders the default checkmark byte-identically aside from the target class', () => {
2393
+ // The added target class is purely additive — it changes nothing about the
2394
+ // glyph's own color/size until a theme targets it.
2395
+ render(
2396
+ <Selector
2397
+ label="Fruit"
2398
+ options={OPTIONS}
2399
+ value="Banana"
2400
+ onChange={() => {}}
2401
+ isDefaultOpen
2402
+ />,
2403
+ );
2404
+ const selected = screen
2405
+ .getAllByRole('option', h)
2406
+ .find(o => o.getAttribute('aria-selected') === 'true')!;
2407
+ const check = selected.querySelector(
2408
+ '.astryx-selector-check',
2409
+ ) as HTMLElement;
2410
+
2411
+ const {container: refContainer} = render(
2412
+ <Icon icon="check" size="sm" color="accent" />,
2413
+ );
2414
+ const refIcon = refContainer.querySelector('.astryx-icon') as HTMLElement;
2415
+ const styleClasses = (el: HTMLElement) =>
2416
+ el.className
2417
+ .split(' ')
2418
+ .filter(c => c !== 'astryx-selector-check')
2419
+ .sort();
2420
+ expect(styleClasses(check)).toEqual(styleClasses(refIcon));
2421
+ });
2422
+
2423
+ it('exposes selector-check so a theme can hide or restyle the marker', () => {
2424
+ const theme = defineTheme({
2425
+ name: 'selector-check-test',
2426
+ components: {
2427
+ 'selector-check': {
2428
+ base: {display: 'none'},
2429
+ },
2430
+ },
2431
+ });
2432
+ const css = generateThemeTestCSS(theme);
2433
+ expect(css).toContain('.astryx-selector-check {');
2434
+ expect(css).toContain('display: none');
2435
+ });
2436
+ });
2437
+
2438
+ describe('Selector disabled state theme target', () => {
2439
+ const getSelectorRoot = (container: HTMLElement): HTMLElement => {
2440
+ const root = container.querySelector('.astryx-selector');
2441
+ if (root == null) {
2442
+ throw new Error('selector root not found');
2443
+ }
2444
+ return root as HTMLElement;
2445
+ };
2446
+
2447
+ it('reflects data-disabled="disabled" on the root when disabled', () => {
2448
+ const {container} = render(
2449
+ <Selector label="Fruit" options={OPTIONS} onChange={() => {}} isDisabled />,
2450
+ );
2451
+ expect(getSelectorRoot(container)).toHaveAttribute(
2452
+ 'data-disabled',
2453
+ 'disabled',
2454
+ );
2455
+ });
2456
+
2457
+ it('omits the disabled class/attribute when enabled', () => {
2458
+ const {container} = render(
2459
+ <Selector label="Fruit" options={OPTIONS} onChange={() => {}} />,
2460
+ );
2461
+ const root = getSelectorRoot(container);
2462
+ expect(root).not.toHaveAttribute('data-disabled');
2463
+ expect(root).not.toHaveClass('disabled');
2464
+ });
2465
+
2466
+ it('exposes the disabled state so a theme can key on it', () => {
2467
+ const theme = defineTheme({
2468
+ name: 'selector-disabled-state-test',
2469
+ components: {
2470
+ selector: {
2471
+ 'disabled:disabled': {opacity: '0.4'},
2472
+ },
2473
+ },
2474
+ });
2475
+ const css = generateThemeTestCSS(theme);
2476
+ expect(css).toContain('.astryx-selector.disabled');
2477
+ expect(css).toContain('opacity: 0.4');
2478
+ });
2479
+ });
2480
+
2481
+