@astryxdesign/core 0.4.7 → 0.5.0-canary.009bcb3

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 (730) hide show
  1. package/CHANGELOG.md +161 -1
  2. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +45 -20
  5. package/dist/AppShell/AppShell.d.ts.map +1 -1
  6. package/dist/AppShell/AppShell.js +3 -2
  7. package/dist/AspectRatio/AspectRatio.d.ts +24 -0
  8. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  9. package/dist/AspectRatio/AspectRatio.js +23 -4
  10. package/dist/Avatar/Avatar.d.ts +25 -1
  11. package/dist/Avatar/Avatar.d.ts.map +1 -1
  12. package/dist/Avatar/Avatar.js +58 -19
  13. package/dist/Avatar/index.d.ts +2 -2
  14. package/dist/Avatar/index.d.ts.map +1 -1
  15. package/dist/Avatar/index.js +1 -1
  16. package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
  17. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  18. package/dist/AvatarGroup/AvatarGroup.js +8 -4
  19. package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
  20. package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
  21. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  22. package/dist/AvatarGroup/AvatarGroupOverflow.js +10 -6
  23. package/dist/Banner/Banner.d.ts +49 -15
  24. package/dist/Banner/Banner.d.ts.map +1 -1
  25. package/dist/Banner/Banner.js +62 -20
  26. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  27. package/dist/BottomSheet/BottomSheet.js +17 -4
  28. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  29. package/dist/BottomSheet/BottomSheetSwitcher.js +3 -2
  30. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  31. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -10
  32. package/dist/Button/Button.d.ts.map +1 -1
  33. package/dist/Button/Button.js +11 -6
  34. package/dist/ButtonGroup/ButtonGroup.d.ts +5 -1
  35. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  36. package/dist/ButtonGroup/ButtonGroup.js +26 -7
  37. package/dist/Calendar/Calendar.d.ts +7 -3
  38. package/dist/Calendar/Calendar.d.ts.map +1 -1
  39. package/dist/Calendar/Calendar.js +21 -23
  40. package/dist/Calendar/getInitialFocusDate.d.ts +46 -0
  41. package/dist/Calendar/getInitialFocusDate.d.ts.map +1 -0
  42. package/dist/Calendar/getInitialFocusDate.js +62 -0
  43. package/dist/Calendar/styles.d.ts +5 -14
  44. package/dist/Calendar/styles.d.ts.map +1 -1
  45. package/dist/Calendar/styles.js +15 -15
  46. package/dist/Card/Card.d.ts +12 -12
  47. package/dist/Card/Card.d.ts.map +1 -1
  48. package/dist/Card/Card.js +17 -9
  49. package/dist/Card/index.d.ts +35 -1
  50. package/dist/Card/index.d.ts.map +1 -1
  51. package/dist/Card/index.js +21 -1
  52. package/dist/Carousel/Carousel.d.ts.map +1 -1
  53. package/dist/Carousel/Carousel.js +3 -3
  54. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  55. package/dist/Chat/ChatComposerInput.js +2 -3
  56. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  57. package/dist/Chat/ChatLayout.js +3 -3
  58. package/dist/Chat/ChatMessageList.d.ts +22 -3
  59. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  60. package/dist/Chat/ChatMessageList.js +6 -3
  61. package/dist/Chat/ChatTokenizedText.d.ts +2 -0
  62. package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
  63. package/dist/Chat/ChatTokenizedText.js +11 -6
  64. package/dist/Chat/useChatComposerTokens.js +1 -1
  65. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  66. package/dist/CheckboxInput/CheckboxInput.js +10 -3
  67. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  68. package/dist/ClickableCard/ClickableCard.js +3 -3
  69. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  70. package/dist/CodeBlock/CodeBlock.js +15 -4
  71. package/dist/CodeBlock/highlightRanges.js +1 -1
  72. package/dist/CodeBlock/highlightStyles.js +13 -13
  73. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  74. package/dist/CommandPalette/CommandPaletteInput.js +3 -2
  75. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  76. package/dist/CommandPalette/CommandPaletteItem.js +3 -2
  77. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  78. package/dist/ComplexSelector/ComplexSelector.js +1 -3
  79. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  80. package/dist/ContextMenu/ContextMenu.js +4 -3
  81. package/dist/DateInput/DateInput.d.ts +43 -0
  82. package/dist/DateInput/DateInput.d.ts.map +1 -1
  83. package/dist/DateInput/DateInput.js +22 -2
  84. package/dist/DateInput/NativeDateField.d.ts +10 -0
  85. package/dist/DateInput/NativeDateField.d.ts.map +1 -0
  86. package/dist/DateInput/NativeDateField.js +494 -0
  87. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  88. package/dist/DateInput/TouchDateField.js +82 -23
  89. package/dist/DateInput/index.d.ts +1 -1
  90. package/dist/DateInput/index.d.ts.map +1 -1
  91. package/dist/DateInput/nativeDateSegments.d.ts +22 -0
  92. package/dist/DateInput/nativeDateSegments.d.ts.map +1 -0
  93. package/dist/DateInput/nativeDateSegments.js +111 -0
  94. package/dist/DateRangeInput/DateRangeInput.d.ts +4 -2
  95. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  96. package/dist/DateTimeInput/DateTimeInput.d.ts +21 -1
  97. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  98. package/dist/DateTimeInput/DateTimeInput.js +406 -12
  99. package/dist/DateTimeInput/index.d.ts +1 -1
  100. package/dist/DateTimeInput/index.d.ts.map +1 -1
  101. package/dist/Dialog/Dialog.d.ts +21 -1
  102. package/dist/Dialog/Dialog.d.ts.map +1 -1
  103. package/dist/Dialog/Dialog.js +110 -58
  104. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  105. package/dist/DropdownMenu/DropdownMenu.js +4 -13
  106. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  107. package/dist/DropdownMenu/DropdownMenuSubMenu.js +6 -5
  108. package/dist/Field/FieldLabel.d.ts.map +1 -1
  109. package/dist/Field/FieldLabel.js +9 -1
  110. package/dist/Field/InputClearButton.d.ts +9 -3
  111. package/dist/Field/InputClearButton.d.ts.map +1 -1
  112. package/dist/Field/InputClearButton.js +14 -3
  113. package/dist/FileInput/FileInput.d.ts.map +1 -1
  114. package/dist/FileInput/FileInput.js +3 -2
  115. package/dist/Heading/Heading.d.ts.map +1 -1
  116. package/dist/Heading/Heading.js +6 -3
  117. package/dist/HoverCard/HoverCard.d.ts +6 -0
  118. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  119. package/dist/HoverCard/HoverCard.js +104 -3
  120. package/dist/HoverCard/useHoverCard.d.ts +19 -2
  121. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  122. package/dist/HoverCard/useHoverCard.js +74 -26
  123. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  124. package/dist/Indicator/CheckboxIndicator.js +6 -2
  125. package/dist/Item/Item.d.ts.map +1 -1
  126. package/dist/Item/Item.js +4 -2
  127. package/dist/Kbd/Kbd.d.ts.map +1 -1
  128. package/dist/Kbd/Kbd.js +2 -19
  129. package/dist/Layer/LayerDepthContext.d.ts +52 -0
  130. package/dist/Layer/LayerDepthContext.d.ts.map +1 -0
  131. package/dist/Layer/LayerDepthContext.js +66 -0
  132. package/dist/Layer/gestureCounter.d.ts +8 -0
  133. package/dist/Layer/gestureCounter.d.ts.map +1 -0
  134. package/dist/Layer/gestureCounter.js +53 -0
  135. package/dist/Layer/index.d.ts +3 -0
  136. package/dist/Layer/index.d.ts.map +1 -1
  137. package/dist/Layer/index.js +4 -0
  138. package/dist/Layer/layerStack.d.ts +98 -0
  139. package/dist/Layer/layerStack.d.ts.map +1 -0
  140. package/dist/Layer/layerStack.js +306 -0
  141. package/dist/Layer/useLayer.d.ts +23 -13
  142. package/dist/Layer/useLayer.d.ts.map +1 -1
  143. package/dist/Layer/useLayer.js +128 -8
  144. package/dist/Layer/useLayerDismissal.d.ts +93 -0
  145. package/dist/Layer/useLayerDismissal.d.ts.map +1 -0
  146. package/dist/Layer/useLayerDismissal.js +91 -0
  147. package/dist/Lightbox/Lightbox.d.ts +1 -0
  148. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  149. package/dist/Lightbox/Lightbox.js +103 -81
  150. package/dist/List/List.d.ts +1 -1
  151. package/dist/List/List.d.ts.map +1 -1
  152. package/dist/List/List.js +15 -4
  153. package/dist/Markdown/Markdown.d.ts +1 -1
  154. package/dist/Markdown/Markdown.d.ts.map +1 -1
  155. package/dist/Markdown/Markdown.js +20 -7
  156. package/dist/Markdown/index.d.ts +1 -1
  157. package/dist/Markdown/index.d.ts.map +1 -1
  158. package/dist/Markdown/parser.d.ts +38 -1
  159. package/dist/Markdown/parser.d.ts.map +1 -1
  160. package/dist/Markdown/parser.js +182 -32
  161. package/dist/MetadataList/MetadataListItem.d.ts +1 -1
  162. package/dist/MetadataList/MetadataListItem.d.ts.map +1 -1
  163. package/dist/MetadataList/MetadataListItem.js +4 -1
  164. package/dist/MobileNav/MobileNav.d.ts +6 -1
  165. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  166. package/dist/MobileNav/MobileNav.js +61 -36
  167. package/dist/MultiSelector/MultiSelector.d.ts +32 -1
  168. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  169. package/dist/MultiSelector/MultiSelector.js +73 -15
  170. package/dist/MultiSelector/hooks.d.ts +7 -1
  171. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  172. package/dist/MultiSelector/hooks.js +3 -2
  173. package/dist/MultiSelector/index.d.ts +1 -1
  174. package/dist/MultiSelector/index.d.ts.map +1 -1
  175. package/dist/NavIcon/NavIcon.d.ts.map +1 -1
  176. package/dist/NavIcon/NavIcon.js +5 -1
  177. package/dist/NavMenu/NavHeadingMenu.d.ts +1 -1
  178. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  179. package/dist/NavMenu/NavHeadingMenu.js +9 -5
  180. package/dist/NumberInput/NumberInput.d.ts +6 -1
  181. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  182. package/dist/NumberInput/NumberInput.js +54 -104
  183. package/dist/NumberInput/numberInputCommit.d.ts +34 -0
  184. package/dist/NumberInput/numberInputCommit.d.ts.map +1 -0
  185. package/dist/NumberInput/numberInputCommit.js +71 -0
  186. package/dist/NumberInput/numberParser.d.ts +64 -0
  187. package/dist/NumberInput/numberParser.d.ts.map +1 -0
  188. package/dist/NumberInput/numberParser.js +350 -0
  189. package/dist/Outline/Outline.d.ts.map +1 -1
  190. package/dist/Outline/Outline.js +3 -2
  191. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  192. package/dist/OverflowList/OverflowList.js +3 -2
  193. package/dist/Overlay/Overlay.d.ts.map +1 -1
  194. package/dist/Overlay/Overlay.js +3 -2
  195. package/dist/Popover/Popover.d.ts.map +1 -1
  196. package/dist/Popover/Popover.js +1 -9
  197. package/dist/Popover/usePopover.d.ts +7 -41
  198. package/dist/Popover/usePopover.d.ts.map +1 -1
  199. package/dist/Popover/usePopover.js +40 -21
  200. package/dist/PowerSearch/PowerSearch.d.ts +8 -2
  201. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  202. package/dist/PowerSearch/PowerSearch.js +19 -6
  203. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +3 -1
  204. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  205. package/dist/PowerSearch/PowerSearchEditPopover.js +28 -6
  206. package/dist/PowerSearch/PowerSearchValueEditor.d.ts +3 -1
  207. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  208. package/dist/PowerSearch/PowerSearchValueEditor.js +110 -27
  209. package/dist/PowerSearch/types.d.ts +2 -0
  210. package/dist/PowerSearch/types.d.ts.map +1 -1
  211. package/dist/PowerSearch/usePowerSearchSource.d.ts +6 -1
  212. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  213. package/dist/PowerSearch/usePowerSearchSource.js +14 -5
  214. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  215. package/dist/ProgressBar/ProgressBar.js +18 -5
  216. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  217. package/dist/Resizable/ResizeHandle.js +3 -2
  218. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  219. package/dist/SegmentedControl/SegmentedControl.js +3 -2
  220. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  221. package/dist/SelectableCard/SelectableCard.js +12 -3
  222. package/dist/Selector/Selector.d.ts +18 -1
  223. package/dist/Selector/Selector.d.ts.map +1 -1
  224. package/dist/Selector/Selector.js +91 -18
  225. package/dist/Selector/hooks.d.ts +7 -1
  226. package/dist/Selector/hooks.d.ts.map +1 -1
  227. package/dist/Selector/hooks.js +3 -2
  228. package/dist/SideNav/SideNav.d.ts.map +1 -1
  229. package/dist/SideNav/SideNav.js +4 -3
  230. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  231. package/dist/SideNav/SideNavHeading.js +8 -7
  232. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  233. package/dist/SideNav/SideNavItem.js +4 -3
  234. package/dist/Slider/Slider.d.ts.map +1 -1
  235. package/dist/Slider/Slider.js +37 -5
  236. package/dist/Spinner/Spinner.d.ts +3 -3
  237. package/dist/Spinner/Spinner.d.ts.map +1 -1
  238. package/dist/Spinner/Spinner.js +130 -78
  239. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  240. package/dist/StatusDot/StatusDot.js +6 -1
  241. package/dist/Stepper/Step.d.ts +140 -0
  242. package/dist/Stepper/Step.d.ts.map +1 -0
  243. package/dist/Stepper/Step.js +1045 -0
  244. package/dist/Stepper/StepStatus.d.ts +24 -0
  245. package/dist/Stepper/StepStatus.d.ts.map +1 -0
  246. package/dist/Stepper/StepStatus.js +1 -0
  247. package/dist/Stepper/Stepper.d.ts +93 -0
  248. package/dist/Stepper/Stepper.d.ts.map +1 -0
  249. package/dist/Stepper/Stepper.js +184 -0
  250. package/dist/Stepper/StepperContext.d.ts +41 -0
  251. package/dist/Stepper/StepperContext.d.ts.map +1 -0
  252. package/dist/Stepper/StepperContext.js +34 -0
  253. package/dist/Stepper/index.d.ts +8 -0
  254. package/dist/Stepper/index.d.ts.map +1 -0
  255. package/dist/Stepper/index.js +7 -0
  256. package/dist/Stepper/stepper.stylex.d.ts +15 -0
  257. package/dist/Stepper/stepper.stylex.d.ts.map +1 -0
  258. package/dist/Stepper/stepper.stylex.js +20 -0
  259. package/dist/Switch/Switch.d.ts.map +1 -1
  260. package/dist/Switch/Switch.js +8 -3
  261. package/dist/TabList/Tab.d.ts +15 -2
  262. package/dist/TabList/Tab.d.ts.map +1 -1
  263. package/dist/TabList/Tab.js +32 -7
  264. package/dist/TabList/TabList.d.ts +46 -7
  265. package/dist/TabList/TabList.d.ts.map +1 -1
  266. package/dist/TabList/TabList.js +353 -23
  267. package/dist/TabList/TabListContext.d.ts +11 -1
  268. package/dist/TabList/TabListContext.d.ts.map +1 -1
  269. package/dist/TabList/TabListContext.js +11 -2
  270. package/dist/TabList/TabMenu.d.ts.map +1 -1
  271. package/dist/TabList/TabMenu.js +3 -2
  272. package/dist/TabList/index.d.ts +2 -2
  273. package/dist/TabList/index.d.ts.map +1 -1
  274. package/dist/Table/BaseTable.d.ts.map +1 -1
  275. package/dist/Table/BaseTable.js +10 -2
  276. package/dist/Table/Table.d.ts.map +1 -1
  277. package/dist/Table/Table.js +3 -6
  278. package/dist/Table/TableRow.d.ts +16 -5
  279. package/dist/Table/TableRow.d.ts.map +1 -1
  280. package/dist/Table/TableRow.js +16 -5
  281. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  282. package/dist/Table/plugins/filtering/useTableFiltering.js +73 -4
  283. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +26 -0
  284. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  285. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +54 -11
  286. package/dist/Table/plugins/pagination/useTablePagination.d.ts +3 -0
  287. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  288. package/dist/Table/plugins/pagination/useTablePagination.js +21 -4
  289. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  290. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
  291. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -1
  292. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +10 -3
  293. package/dist/Table/plugins/selection/useTableSelection.d.ts +16 -0
  294. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  295. package/dist/Table/plugins/selection/useTableSelection.js +43 -5
  296. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  297. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
  298. package/dist/Table/types.d.ts +22 -4
  299. package/dist/Table/types.d.ts.map +1 -1
  300. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  301. package/dist/Table/useBaseTablePlugins.js +5 -0
  302. package/dist/Text/Text.d.ts.map +1 -1
  303. package/dist/Text/Text.js +6 -3
  304. package/dist/TextArea/TextArea.d.ts.map +1 -1
  305. package/dist/TextArea/TextArea.js +16 -10
  306. package/dist/TextInput/TextInput.d.ts.map +1 -1
  307. package/dist/TextInput/TextInput.js +3 -2
  308. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  309. package/dist/TimeInput/TimeInput.js +3 -2
  310. package/dist/Timestamp/Timestamp.d.ts +1 -1
  311. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  312. package/dist/Timestamp/Timestamp.js +15 -21
  313. package/dist/Toast/Toast.d.ts.map +1 -1
  314. package/dist/Toast/Toast.js +22 -7
  315. package/dist/Toast/ToastViewport.d.ts +1 -0
  316. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  317. package/dist/Toast/ToastViewport.js +71 -18
  318. package/dist/Token/Token.d.ts +1 -1
  319. package/dist/Token/Token.d.ts.map +1 -1
  320. package/dist/Token/Token.js +20 -9
  321. package/dist/Token/TokenLink.d.ts +1 -1
  322. package/dist/Token/TokenLink.d.ts.map +1 -1
  323. package/dist/Token/TokenLink.js +7 -4
  324. package/dist/Tokenizer/Tokenizer.d.ts +14 -1
  325. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  326. package/dist/Tokenizer/Tokenizer.js +33 -21
  327. package/dist/Tooltip/Tooltip.d.ts +5 -0
  328. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  329. package/dist/Tooltip/useTooltip.d.ts +5 -0
  330. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  331. package/dist/Tooltip/useTooltip.js +39 -24
  332. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  333. package/dist/TopNav/TopNavHeading.js +5 -4
  334. package/dist/TopNav/TopNavMegaMenu.d.ts +1 -1
  335. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  336. package/dist/TopNav/TopNavMegaMenu.js +31 -11
  337. package/dist/TopNav/TopNavMenu.d.ts +1 -1
  338. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  339. package/dist/TopNav/TopNavMenu.js +22 -7
  340. package/dist/TreeList/TreeList.d.ts +1 -1
  341. package/dist/TreeList/TreeList.d.ts.map +1 -1
  342. package/dist/TreeList/TreeList.js +7 -2
  343. package/dist/Typeahead/BaseTypeahead.d.ts +35 -0
  344. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  345. package/dist/Typeahead/BaseTypeahead.js +119 -37
  346. package/dist/Typeahead/Typeahead.d.ts +8 -1
  347. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  348. package/dist/Typeahead/Typeahead.js +5 -2
  349. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  350. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  351. package/dist/Typeahead/TypeaheadItem.js +7 -2
  352. package/dist/astryx.css +113 -11
  353. package/dist/hooks/index.d.ts +1 -0
  354. package/dist/hooks/index.d.ts.map +1 -1
  355. package/dist/hooks/index.js +1 -0
  356. package/dist/hooks/useFocusTrap.d.ts +7 -4
  357. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  358. package/dist/hooks/useFocusTrap.js +60 -95
  359. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  360. package/dist/hooks/useHotkeys.js +3 -18
  361. package/dist/hooks/useMergedRefs.d.ts +18 -0
  362. package/dist/hooks/useMergedRefs.d.ts.map +1 -0
  363. package/dist/hooks/useMergedRefs.js +25 -0
  364. package/dist/index.d.ts +1 -0
  365. package/dist/index.d.ts.map +1 -1
  366. package/dist/index.js +1 -0
  367. package/dist/theme/Theme.d.ts.map +1 -1
  368. package/dist/theme/Theme.js +46 -10
  369. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  370. package/dist/theme/derivedVarRegistry.js +24 -4
  371. package/dist/theme/generateThemeRules.d.ts +21 -0
  372. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  373. package/dist/theme/generateThemeRules.js +26 -0
  374. package/dist/theme/syntax/tokens.d.ts +1 -1
  375. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  376. package/dist/theme/syntax/tokens.js +5 -2
  377. package/dist/utils/groupItems.d.ts +5 -1
  378. package/dist/utils/groupItems.d.ts.map +1 -1
  379. package/dist/utils/groupItems.js +9 -9
  380. package/dist/utils/index.d.ts +1 -1
  381. package/dist/utils/index.d.ts.map +1 -1
  382. package/dist/utils/isApplePlatform.d.ts +18 -0
  383. package/dist/utils/isApplePlatform.d.ts.map +1 -0
  384. package/dist/utils/isApplePlatform.js +37 -0
  385. package/dist/utils/sharedResizeObserver.d.ts.map +1 -1
  386. package/dist/utils/sharedResizeObserver.js +10 -1
  387. package/dist/utils/timeParser.d.ts +1 -1
  388. package/dist/utils/timeParser.d.ts.map +1 -1
  389. package/dist/utils/timeParser.js +26 -12
  390. package/locales/af-ZA.json +6 -6
  391. package/locales/ar-SA.json +6 -6
  392. package/locales/ca-ES.json +5 -5
  393. package/locales/cs-CZ.json +6 -6
  394. package/locales/da-DK.json +6 -6
  395. package/locales/de-DE.json +6 -6
  396. package/locales/el-GR.json +6 -6
  397. package/locales/en.json +163 -11
  398. package/locales/es-ES.json +5 -5
  399. package/locales/fi-FI.json +6 -6
  400. package/locales/fr-FR.json +6 -6
  401. package/locales/he-IL.json +6 -6
  402. package/locales/hu-HU.json +6 -6
  403. package/locales/it-IT.json +6 -6
  404. package/locales/ja-JP.json +6 -6
  405. package/locales/ko-KR.json +6 -6
  406. package/locales/nl-NL.json +6 -6
  407. package/locales/no-NO.json +6 -6
  408. package/locales/pl-PL.json +6 -6
  409. package/locales/pseudo.json +114 -0
  410. package/locales/pt-BR.json +6 -6
  411. package/locales/pt-PT.json +6 -6
  412. package/locales/ro-RO.json +6 -6
  413. package/locales/ru-RU.json +6 -6
  414. package/locales/sr-SP.json +6 -6
  415. package/locales/sv-SE.json +6 -6
  416. package/locales/tr-TR.json +6 -6
  417. package/locales/uk-UA.json +6 -6
  418. package/locales/vi-VN.json +6 -6
  419. package/locales/zh-CN.json +6 -6
  420. package/locales/zh-TW.json +6 -6
  421. package/package.json +8 -3
  422. package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
  423. package/src/AlertDialog/AlertDialog.test.tsx +211 -2
  424. package/src/AlertDialog/AlertDialog.tsx +62 -20
  425. package/src/AppShell/AppShell.tsx +3 -2
  426. package/src/AspectRatio/AspectRatio.doc.mjs +6 -3
  427. package/src/AspectRatio/AspectRatio.test.tsx +57 -10
  428. package/src/AspectRatio/AspectRatio.tsx +40 -1
  429. package/src/Avatar/Avatar.doc.mjs +14 -3
  430. package/src/Avatar/Avatar.test.tsx +97 -0
  431. package/src/Avatar/Avatar.tsx +125 -52
  432. package/src/Avatar/index.ts +2 -2
  433. package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
  434. package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
  435. package/src/AvatarGroup/AvatarGroup.tsx +15 -6
  436. package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
  437. package/src/AvatarGroup/AvatarGroupOverflow.tsx +10 -4
  438. package/src/Banner/Banner.doc.mjs +22 -11
  439. package/src/Banner/Banner.test.tsx +177 -25
  440. package/src/Banner/Banner.tsx +93 -27
  441. package/src/BottomSheet/BottomSheet.test.tsx +123 -0
  442. package/src/BottomSheet/BottomSheet.tsx +17 -4
  443. package/src/BottomSheet/BottomSheetSwitcher.tsx +3 -2
  444. package/src/Breadcrumbs/BreadcrumbItem.tsx +9 -5
  445. package/src/Button/Button.doc.mjs +24 -1
  446. package/src/Button/Button.test.tsx +32 -4
  447. package/src/Button/Button.tsx +12 -5
  448. package/src/ButtonGroup/ButtonGroup.doc.mjs +10 -1
  449. package/src/ButtonGroup/ButtonGroup.test.tsx +404 -1
  450. package/src/ButtonGroup/ButtonGroup.tsx +23 -5
  451. package/src/Calendar/Calendar.doc.mjs +7 -6
  452. package/src/Calendar/Calendar.test.tsx +143 -0
  453. package/src/Calendar/Calendar.tsx +30 -26
  454. package/src/Calendar/getInitialFocusDate.test.ts +94 -0
  455. package/src/Calendar/getInitialFocusDate.ts +93 -0
  456. package/src/Calendar/styles.ts +49 -31
  457. package/src/Card/Card.doc.mjs +10 -7
  458. package/src/Card/Card.test.tsx +113 -19
  459. package/src/Card/Card.tsx +67 -89
  460. package/src/Card/index.ts +36 -1
  461. package/src/Carousel/Carousel.tsx +3 -2
  462. package/src/Chat/ChatComposerInput.tsx +5 -1
  463. package/src/Chat/ChatLayout.tsx +3 -2
  464. package/src/Chat/ChatMessageList.doc.mjs +9 -1
  465. package/src/Chat/ChatMessageList.test.tsx +46 -0
  466. package/src/Chat/ChatMessageList.tsx +28 -4
  467. package/src/Chat/ChatTokenizedText.tsx +17 -10
  468. package/src/Chat/useChatComposerTokens.ts +1 -1
  469. package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
  470. package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
  471. package/src/CheckboxInput/CheckboxInput.tsx +8 -2
  472. package/src/ClickableCard/ClickableCard.tsx +3 -2
  473. package/src/CodeBlock/CodeBlock.doc.mjs +16 -4
  474. package/src/CodeBlock/CodeBlock.test.tsx +37 -0
  475. package/src/CodeBlock/CodeBlock.tsx +20 -4
  476. package/src/CodeBlock/highlightRanges.ts +1 -1
  477. package/src/CodeBlock/highlightStyles.ts +13 -13
  478. package/src/CommandPalette/CommandPaletteInput.tsx +3 -2
  479. package/src/CommandPalette/CommandPaletteItem.tsx +3 -2
  480. package/src/ComplexSelector/ComplexSelector.test.tsx +32 -0
  481. package/src/ComplexSelector/ComplexSelector.tsx +1 -3
  482. package/src/ContextMenu/ContextMenu.doc.mjs +5 -0
  483. package/src/ContextMenu/ContextMenu.tsx +4 -3
  484. package/src/DateInput/DateInput.doc.mjs +16 -0
  485. package/src/DateInput/DateInput.tsx +55 -2
  486. package/src/DateInput/DateInputTouch.test.tsx +146 -32
  487. package/src/DateInput/NativeDateField.test.tsx +635 -0
  488. package/src/DateInput/NativeDateField.tsx +641 -0
  489. package/src/DateInput/TouchDateField.tsx +108 -24
  490. package/src/DateInput/index.ts +1 -0
  491. package/src/DateInput/nativeDateSegments.ts +127 -0
  492. package/src/DateRangeInput/DateRangeInput.doc.mjs +2 -2
  493. package/src/DateRangeInput/DateRangeInput.test.tsx +22 -0
  494. package/src/DateRangeInput/DateRangeInput.tsx +4 -2
  495. package/src/DateTimeInput/DateTimeInput.doc.mjs +18 -0
  496. package/src/DateTimeInput/DateTimeInput.test.tsx +1088 -0
  497. package/src/DateTimeInput/DateTimeInput.tsx +556 -24
  498. package/src/DateTimeInput/index.ts +1 -0
  499. package/src/Dialog/Dialog.doc.mjs +8 -3
  500. package/src/Dialog/Dialog.test.tsx +429 -2
  501. package/src/Dialog/Dialog.tsx +133 -58
  502. package/src/DropdownMenu/DropdownMenu.doc.mjs +6 -0
  503. package/src/DropdownMenu/DropdownMenu.test.tsx +44 -10
  504. package/src/DropdownMenu/DropdownMenu.tsx +4 -13
  505. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +8 -5
  506. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +8 -11
  507. package/src/Field/Field.doc.mjs +13 -2
  508. package/src/Field/FieldLabel.test.tsx +29 -0
  509. package/src/Field/FieldLabel.tsx +7 -0
  510. package/src/Field/InputClearButton.test.tsx +15 -1
  511. package/src/Field/InputClearButton.tsx +28 -4
  512. package/src/FileInput/FileInput.tsx +3 -2
  513. package/src/Heading/Heading.test.tsx +23 -1
  514. package/src/Heading/Heading.tsx +6 -3
  515. package/src/HoverCard/HoverCard.doc.mjs +13 -2
  516. package/src/HoverCard/HoverCard.test.tsx +154 -4
  517. package/src/HoverCard/HoverCard.tsx +143 -3
  518. package/src/HoverCard/useHoverCard.tsx +104 -33
  519. package/src/Indicator/CheckboxIndicator.tsx +14 -8
  520. package/src/Indicator/Indicator.doc.mjs +2 -0
  521. package/src/Item/Item.tsx +5 -4
  522. package/src/Kbd/Kbd.tsx +2 -19
  523. package/src/Layer/LayerDepthContext.tsx +62 -0
  524. package/src/Layer/gestureCounter.ts +57 -0
  525. package/src/Layer/index.ts +9 -0
  526. package/src/Layer/layerDismissalFamilies.test.tsx +359 -0
  527. package/src/Layer/layerDismissalInvariants.test.tsx +417 -0
  528. package/src/Layer/layerStack.ts +362 -0
  529. package/src/Layer/useLayer.test.tsx +324 -15
  530. package/src/Layer/useLayer.tsx +164 -8
  531. package/src/Layer/useLayerDismissal.test.tsx +469 -0
  532. package/src/Layer/useLayerDismissal.ts +173 -0
  533. package/src/Layout/Layout.doc.mjs +2 -2
  534. package/src/Layout/__tests__/edgeCompensation.test.tsx +1 -1
  535. package/src/Lightbox/Lightbox.doc.mjs +12 -0
  536. package/src/Lightbox/Lightbox.tsx +124 -102
  537. package/src/Link/Link.doc.mjs +39 -0
  538. package/src/List/List.test.tsx +38 -0
  539. package/src/List/List.tsx +8 -1
  540. package/src/Markdown/Markdown.doc.mjs +5 -0
  541. package/src/Markdown/Markdown.test.tsx +37 -0
  542. package/src/Markdown/Markdown.tsx +16 -5
  543. package/src/Markdown/incremental.test.ts +16 -2
  544. package/src/Markdown/index.ts +1 -0
  545. package/src/Markdown/parser.perf.test.ts +96 -1
  546. package/src/Markdown/parser.test.ts +178 -2
  547. package/src/Markdown/parser.ts +253 -32
  548. package/src/MetadataList/MetadataList.test.tsx +75 -2
  549. package/src/MetadataList/MetadataListItem.tsx +5 -2
  550. package/src/MobileNav/MobileNav.tsx +62 -36
  551. package/src/MoreMenu/MoreMenu.doc.mjs +7 -1
  552. package/src/MultiSelector/MultiSelector.doc.mjs +49 -1
  553. package/src/MultiSelector/MultiSelector.test.tsx +311 -0
  554. package/src/MultiSelector/MultiSelector.tsx +151 -15
  555. package/src/MultiSelector/hooks.ts +9 -2
  556. package/src/MultiSelector/index.ts +1 -0
  557. package/src/NavIcon/NavIcon.doc.mjs +8 -2
  558. package/src/NavIcon/NavIcon.test.tsx +9 -0
  559. package/src/NavIcon/NavIcon.tsx +5 -1
  560. package/src/NavMenu/NavHeadingMenu.test.tsx +30 -0
  561. package/src/NavMenu/NavHeadingMenu.tsx +9 -5
  562. package/src/NumberInput/NumberInput.doc.mjs +31 -7
  563. package/src/NumberInput/NumberInput.test.tsx +436 -8
  564. package/src/NumberInput/NumberInput.tsx +62 -114
  565. package/src/NumberInput/numberInputCommit.test.ts +72 -0
  566. package/src/NumberInput/numberInputCommit.ts +103 -0
  567. package/src/NumberInput/numberParser.docblock.test.ts +234 -0
  568. package/src/NumberInput/numberParser.test.ts +222 -0
  569. package/src/NumberInput/numberParser.ts +403 -0
  570. package/src/Outline/Outline.tsx +3 -2
  571. package/src/OverflowList/OverflowList.tsx +3 -2
  572. package/src/Overlay/Overlay.tsx +3 -2
  573. package/src/Pagination/Pagination.test.tsx +3 -2
  574. package/src/Popover/Popover.test.tsx +14 -0
  575. package/src/Popover/Popover.tsx +1 -9
  576. package/src/Popover/usePopover.tsx +57 -32
  577. package/src/PowerSearch/PowerSearch.doc.mjs +160 -28
  578. package/src/PowerSearch/PowerSearch.test.tsx +240 -1
  579. package/src/PowerSearch/PowerSearch.tsx +34 -5
  580. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +288 -0
  581. package/src/PowerSearch/PowerSearchEditPopover.tsx +29 -2
  582. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +111 -1
  583. package/src/PowerSearch/PowerSearchValueEditor.tsx +124 -10
  584. package/src/PowerSearch/types.ts +2 -0
  585. package/src/PowerSearch/usePowerSearchSource.test.ts +82 -2
  586. package/src/PowerSearch/usePowerSearchSource.ts +13 -3
  587. package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
  588. package/src/ProgressBar/ProgressBar.test.tsx +24 -0
  589. package/src/ProgressBar/ProgressBar.tsx +28 -8
  590. package/src/Resizable/ResizeHandle.tsx +3 -2
  591. package/src/SegmentedControl/SegmentedControl.tsx +3 -2
  592. package/src/SelectableCard/SelectableCard.doc.mjs +3 -0
  593. package/src/SelectableCard/SelectableCard.tsx +19 -2
  594. package/src/Selector/Selector.doc.mjs +26 -1
  595. package/src/Selector/Selector.test.tsx +346 -1
  596. package/src/Selector/Selector.tsx +148 -21
  597. package/src/Selector/hooks.ts +17 -2
  598. package/src/SideNav/SideNav.doc.mjs +6 -6
  599. package/src/SideNav/SideNav.tsx +4 -2
  600. package/src/SideNav/SideNavHeading.tsx +12 -12
  601. package/src/SideNav/SideNavItem.tsx +4 -2
  602. package/src/Slider/Slider.test.tsx +106 -1
  603. package/src/Slider/Slider.tsx +55 -3
  604. package/src/Spinner/Spinner.test.tsx +147 -1
  605. package/src/Spinner/Spinner.tsx +120 -101
  606. package/src/StatusDot/StatusDot.doc.mjs +8 -2
  607. package/src/StatusDot/StatusDot.test.tsx +9 -0
  608. package/src/StatusDot/StatusDot.tsx +7 -1
  609. package/src/Stepper/Step.doc.mjs +98 -0
  610. package/src/Stepper/Step.tsx +1638 -0
  611. package/src/Stepper/StepStatus.ts +26 -0
  612. package/src/Stepper/Stepper.doc.mjs +370 -0
  613. package/src/Stepper/Stepper.test.tsx +1024 -0
  614. package/src/Stepper/Stepper.tsx +258 -0
  615. package/src/Stepper/StepperContext.ts +71 -0
  616. package/src/Stepper/index.ts +18 -0
  617. package/src/Stepper/stepper.stylex.ts +19 -0
  618. package/src/Switch/Switch.doc.mjs +2 -0
  619. package/src/Switch/Switch.test.tsx +10 -0
  620. package/src/Switch/Switch.tsx +6 -2
  621. package/src/TabList/Tab.doc.mjs +13 -1
  622. package/src/TabList/Tab.tsx +67 -7
  623. package/src/TabList/TabList.doc.mjs +22 -6
  624. package/src/TabList/TabList.test.tsx +559 -0
  625. package/src/TabList/TabList.tsx +490 -22
  626. package/src/TabList/TabListContext.ts +13 -2
  627. package/src/TabList/TabMenu.tsx +3 -2
  628. package/src/TabList/index.ts +6 -2
  629. package/src/Table/BaseTable.tsx +12 -4
  630. package/src/Table/Table.doc.mjs +9 -2
  631. package/src/Table/Table.test.tsx +132 -14
  632. package/src/Table/Table.tsx +3 -8
  633. package/src/Table/TableBody.doc.mjs +40 -0
  634. package/src/Table/TableFooter.doc.mjs +40 -0
  635. package/src/Table/TableHeader.doc.mjs +40 -0
  636. package/src/Table/TableRow.tsx +16 -5
  637. package/src/Table/plugins/filtering/useTableFiltering.test.tsx +44 -6
  638. package/src/Table/plugins/filtering/useTableFiltering.tsx +100 -4
  639. package/src/Table/plugins/groupedRows/useTableGroupedRows-perf.test.tsx +112 -0
  640. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +100 -0
  641. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +67 -12
  642. package/src/Table/plugins/pagination/useTablePagination.test.tsx +34 -4
  643. package/src/Table/plugins/pagination/useTablePagination.tsx +35 -3
  644. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +9 -2
  645. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +13 -7
  646. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +12 -3
  647. package/src/Table/plugins/selection/useTableSelection.test.tsx +138 -0
  648. package/src/Table/plugins/selection/useTableSelection.tsx +63 -7
  649. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
  650. package/src/Table/types.ts +22 -4
  651. package/src/Table/useBaseTablePlugins.ts +5 -0
  652. package/src/Table/useTableGroupedRows.doc.mjs +5 -4
  653. package/src/Table/useTablePagination.doc.mjs +7 -0
  654. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  655. package/src/Table/useTableSelection.doc.mjs +31 -0
  656. package/src/Text/Text.test.tsx +67 -1
  657. package/src/Text/Text.tsx +6 -3
  658. package/src/TextArea/TextArea.doc.mjs +12 -2
  659. package/src/TextArea/TextArea.test.tsx +11 -0
  660. package/src/TextArea/TextArea.tsx +37 -24
  661. package/src/TextInput/TextInput.doc.mjs +10 -0
  662. package/src/TextInput/TextInput.tsx +3 -2
  663. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  664. package/src/TimeInput/TimeInput.tsx +2 -2
  665. package/src/Timestamp/Timestamp.test.tsx +58 -0
  666. package/src/Timestamp/Timestamp.tsx +12 -10
  667. package/src/Toast/Toast.doc.mjs +26 -12
  668. package/src/Toast/Toast.tsx +28 -4
  669. package/src/Toast/ToastViewport.test.tsx +536 -8
  670. package/src/Toast/ToastViewport.tsx +81 -12
  671. package/src/Token/Token.test.tsx +95 -0
  672. package/src/Token/Token.tsx +15 -10
  673. package/src/Token/TokenLink.tsx +14 -5
  674. package/src/Tokenizer/Tokenizer.doc.mjs +43 -3
  675. package/src/Tokenizer/Tokenizer.test.tsx +161 -0
  676. package/src/Tokenizer/Tokenizer.tsx +53 -24
  677. package/src/Toolbar/Toolbar.doc.mjs +5 -0
  678. package/src/Tooltip/Tooltip.doc.mjs +5 -0
  679. package/src/Tooltip/Tooltip.test.tsx +32 -0
  680. package/src/Tooltip/Tooltip.tsx +5 -0
  681. package/src/Tooltip/useTooltip.tsx +47 -24
  682. package/src/TopNav/TopNavHeading.tsx +5 -4
  683. package/src/TopNav/TopNavMegaMenu.test.tsx +104 -0
  684. package/src/TopNav/TopNavMegaMenu.tsx +47 -5
  685. package/src/TopNav/TopNavMenu.test.tsx +133 -1
  686. package/src/TopNav/TopNavMenu.tsx +38 -7
  687. package/src/TreeList/TreeList.test.tsx +49 -0
  688. package/src/TreeList/TreeList.tsx +7 -2
  689. package/src/Typeahead/BaseTypeahead.doc.mjs +24 -0
  690. package/src/Typeahead/BaseTypeahead.tsx +181 -39
  691. package/src/Typeahead/Typeahead.doc.mjs +11 -0
  692. package/src/Typeahead/Typeahead.test.tsx +203 -0
  693. package/src/Typeahead/Typeahead.tsx +12 -2
  694. package/src/Typeahead/TypeaheadItem.test.tsx +43 -0
  695. package/src/Typeahead/TypeaheadItem.tsx +8 -1
  696. package/src/hooks/index.ts +2 -0
  697. package/src/hooks/useAnnounce.doc.mjs +96 -0
  698. package/src/hooks/useContainerReveal.doc.mjs +2 -2
  699. package/src/hooks/useDevWarning.doc.mjs +96 -0
  700. package/src/hooks/useFocusTrap.test.tsx +14 -0
  701. package/src/hooks/useFocusTrap.ts +62 -111
  702. package/src/hooks/useFocusTrapEscapeShim.test.tsx +165 -0
  703. package/src/hooks/useHotkeys.ts +3 -18
  704. package/src/hooks/useIndicatorFocusRing.doc.mjs +104 -0
  705. package/src/hooks/useInputStatusIcon.doc.mjs +142 -0
  706. package/src/hooks/useInteractiveRole.doc.mjs +119 -0
  707. package/src/hooks/useLongPress.doc.mjs +123 -0
  708. package/src/hooks/useMergedRefs.doc.mjs +79 -0
  709. package/src/hooks/useMergedRefs.test.tsx +62 -0
  710. package/src/hooks/useMergedRefs.ts +36 -0
  711. package/src/hooks/useTypeahead.doc.mjs +153 -0
  712. package/src/index.ts +1 -0
  713. package/src/raw-import.d.ts +14 -0
  714. package/src/theme/MediaTheme.doc.mjs +5 -5
  715. package/src/theme/Theme.test.tsx +104 -2
  716. package/src/theme/Theme.tsx +49 -14
  717. package/src/theme/defineTheme.test.ts +23 -0
  718. package/src/theme/derivedVarRegistry.test.ts +26 -3
  719. package/src/theme/derivedVarRegistry.ts +23 -4
  720. package/src/theme/generateThemeRules.test.ts +99 -1
  721. package/src/theme/generateThemeRules.ts +28 -0
  722. package/src/theme/syntax/tokens.ts +5 -2
  723. package/src/utils/groupItems.ts +12 -6
  724. package/src/utils/index.ts +1 -1
  725. package/src/utils/isApplePlatform.test.ts +61 -0
  726. package/src/utils/isApplePlatform.ts +37 -0
  727. package/src/utils/sharedResizeObserver.ts +10 -2
  728. package/src/utils/timeParser.test.ts +6 -1
  729. package/src/utils/timeParser.ts +35 -13
  730. package/src/__tests__/inputWidthContract.test.tsx +0 -69
@@ -29,7 +29,7 @@ import React, {
29
29
  type ReactNode,
30
30
  } from 'react';
31
31
  import * as stylex from '@stylexjs/stylex';
32
- import {usePopover} from '../Popover/usePopover';
32
+ import {usePopoverInternal} from '../Popover/usePopover';
33
33
  import {useTooltip} from '../Tooltip';
34
34
  import {Icon, renderIconSlot, type IconType} from '../Icon';
35
35
  import {useIndicator} from '../Indicator';
@@ -37,7 +37,6 @@ import type {IndicatorPosition} from '../Indicator';
37
37
  import type {IconName} from '../Icon';
38
38
  import {
39
39
  Field,
40
- InputClearButton,
41
40
  inputStatusBorderStyles,
42
41
  inputStatusHoverShadowStyles,
43
42
  inputWrapperStyles,
@@ -45,7 +44,8 @@ import {
45
44
  } from '../Field';
46
45
  import {Divider} from '../Divider';
47
46
  import {layerAnimations} from '../Layer/layerAnimations.stylex';
48
- import type {LayerPlacement} from '../Layer/useLayer';
47
+ import {useKeepLayerOpenProps, type LayerPlacement} from '../Layer/useLayer';
48
+ import {InternalInputClearButton} from '../Field/InputClearButton';
49
49
  import {Spinner} from '../Spinner';
50
50
  import {PanelSearchInput} from '../Field/PanelSearchInput';
51
51
  import {useAnnounce} from '../hooks/useAnnounce';
@@ -648,6 +648,25 @@ interface SelectorPropsBase<
648
648
  */
649
649
  searchPlaceholder?: string;
650
650
 
651
+ /**
652
+ * Content shown in the panel when there are no options to show, and
653
+ * announced in a polite live region when the panel opens. Not shown while
654
+ * `isLoading` — the options have not arrived yet.
655
+ * @default 'No options'
656
+ */
657
+ emptyText?: ReactNode;
658
+
659
+ /**
660
+ * Content shown in the panel when a search query matches no options, and
661
+ * announced in a polite live region at the same time.
662
+ *
663
+ * The panel message is `role="presentation"`, so the live region is the only
664
+ * route to assistive tech: a string is announced verbatim, a richer node
665
+ * falls back to the default text since it cannot be spoken.
666
+ * @default 'No results found'
667
+ */
668
+ emptySearchText?: ReactNode;
669
+
651
670
  /**
652
671
  * Position placement relative to the trigger.
653
672
  *
@@ -794,6 +813,8 @@ export function Selector<T extends SelectorOptionType>(
794
813
  indicatorPosition = 'end',
795
814
  hasSearch = false,
796
815
  searchPlaceholder: searchPlaceholderFromProps,
816
+ emptyText: emptyTextFromProps,
817
+ emptySearchText: emptySearchTextFromProps,
797
818
  placement,
798
819
  isDefaultOpen = false,
799
820
  'data-testid': testId,
@@ -802,12 +823,16 @@ export function Selector<T extends SelectorOptionType>(
802
823
  className,
803
824
  style,
804
825
  hasClear: hasClearProp,
826
+ id,
805
827
  ...rest
806
828
  } = props as SelectorPropsClearable<T>;
807
829
  const isEffectivelyRequired = useResolvedRequired({isRequired, isOptional});
808
830
  const placeholder = placeholderFromProps ?? t('@astryx.selector.placeholder');
809
831
  const searchPlaceholder =
810
832
  searchPlaceholderFromProps ?? t('@astryx.selector.searchPlaceholder');
833
+ const emptyText = emptyTextFromProps ?? t('@astryx.selector.empty');
834
+ const emptySearchText =
835
+ emptySearchTextFromProps ?? t('@astryx.selector.emptySearchResults');
811
836
  const hasClear = hasClearProp === true;
812
837
  const size = useSize(sizeProp, 'md');
813
838
  const effectiveStatusVariant =
@@ -817,7 +842,10 @@ export function Selector<T extends SelectorOptionType>(
817
842
 
818
843
  // Normalize null to undefined for internal use (null is the clear sentinel)
819
844
  const normalizedValue = value === null ? undefined : value;
820
- const triggerId = useId();
845
+ const generatedTriggerId = useId();
846
+ // A caller's `id` lands on the trigger either way, so the internal identity
847
+ // has to be that same value or the label and listbox point at nothing.
848
+ const triggerId = id ?? generatedTriggerId;
821
849
  const listboxId = useId();
822
850
  const descriptionId = useId();
823
851
  const statusMessageId = useId();
@@ -831,6 +859,9 @@ export function Selector<T extends SelectorOptionType>(
831
859
  const inputGroup = useInputGroup();
832
860
 
833
861
  const [searchQuery, setSearchQuery] = useState('');
862
+ // Mirrors searchQuery for the seed path, which runs before focus reaches the
863
+ // input and so cannot read the rendered state.
864
+ const searchQueryRef = useRef('');
834
865
  // A typed query shows the search row's clear (✕) button, which becomes
835
866
  // the next tab stop after the search input.
836
867
  const hasQuery = searchQuery.length > 0;
@@ -840,6 +871,17 @@ export function Selector<T extends SelectorOptionType>(
840
871
  const isBusy = isLoading || optimisticValue !== normalizedValue;
841
872
  const announce = useAnnounce();
842
873
 
874
+ // The panel's empty message is role="presentation" and reaches assistive tech
875
+ // only through this live region, so the region has to speak whatever the
876
+ // panel shows. A ReactNode override cannot be spoken; fall back to the
877
+ // catalog copy for that case rather than announcing nothing.
878
+ const emptyAnnouncement =
879
+ typeof emptyText === 'string' ? emptyText : t('@astryx.selector.empty');
880
+ const emptySearchAnnouncement =
881
+ typeof emptySearchText === 'string'
882
+ ? emptySearchText
883
+ : t('@astryx.selector.emptySearchResults');
884
+
843
885
  // Disabled-reason tooltip. Disabled controls swallow pointer events, so the
844
886
  // tooltip listeners attach to the trigger container (which already exists)
845
887
  // and the trigger button stays perceivable via aria-disabled instead of the
@@ -907,6 +949,7 @@ export function Selector<T extends SelectorOptionType>(
907
949
  // Layer for dropdown positioning
908
950
  const handleLayerHide = useCallback(() => {
909
951
  setSearchQuery('');
952
+ searchQueryRef.current = '';
910
953
  resetTypeaheadRef.current();
911
954
  // Clear any lingering result count when the popover closes so stale status
912
955
  // text does not linger in the a11y tree.
@@ -914,7 +957,7 @@ export function Selector<T extends SelectorOptionType>(
914
957
  triggerRef.current?.focus();
915
958
  }, [announce]);
916
959
 
917
- const popover = usePopover({
960
+ const popover = usePopoverInternal({
918
961
  onHide: handleLayerHide,
919
962
  hasLightDismiss: true,
920
963
  hasCloseButton: false,
@@ -926,6 +969,7 @@ export function Selector<T extends SelectorOptionType>(
926
969
  // `usePopover` owns — not on the scrolling list inside it.
927
970
  surfaceTarget: 'selector-popup',
928
971
  });
972
+ const keepOpenProps = useKeepLayerOpenProps(popover.id, popover.isOpen);
929
973
 
930
974
  // Open dropdown on mount when isDefaultOpen is true
931
975
  useEffect(() => {
@@ -935,28 +979,76 @@ export function Selector<T extends SelectorOptionType>(
935
979
  // eslint-disable-next-line @eslint-react/exhaustive-deps -- mount-only: isDefaultOpen is not reactive
936
980
  }, []);
937
981
 
938
- // Announce the filtered result count from the query-change handler (matching
982
+ // Announce the filtered result count from the query-change handlers (matching
939
983
  // BaseTypeahead) rather than a reactive effect: computing the count for the
940
984
  // next query here fires the announcement exactly once per keystroke and does
941
- // not re-speak on unrelated re-renders.
942
- const handleSearchChange = useCallback(
985
+ // not re-speak on unrelated re-renders. Split out from handleSearchChange so
986
+ // the type-to-open seed below reaches the same live region — a query the user
987
+ // typed is a query however it arrived.
988
+ const announceSearchResults = useCallback(
943
989
  (nextQuery: string) => {
944
- setSearchQuery(nextQuery);
945
990
  if (nextQuery.length === 0) {
946
991
  // Emptying the query clears the region rather than announcing a count.
947
992
  announce('');
948
993
  return;
949
994
  }
995
+ // While isLoading the panel deliberately shows nothing, so announcing a
996
+ // result would put a claim in the one channel the screen has gone quiet
997
+ // for.
998
+ if (isLoading) {
999
+ announce('');
1000
+ return;
1001
+ }
950
1002
  const count = filterOptionsByQuery(selectableItems, nextQuery).length;
951
1003
  announce(
952
1004
  count === 0
953
- ? t('@astryx.selector.emptySearchResults')
1005
+ ? emptySearchAnnouncement
954
1006
  : t('@astryx.selector.resultCount', {count}),
955
1007
  );
956
1008
  },
957
- [announce, selectableItems, t],
1009
+ [announce, isLoading, selectableItems, emptySearchAnnouncement, t],
1010
+ );
1011
+
1012
+ const handleSearchChange = useCallback(
1013
+ (nextQuery: string) => {
1014
+ setSearchQuery(nextQuery);
1015
+ searchQueryRef.current = nextQuery;
1016
+ announceSearchResults(nextQuery);
1017
+ },
1018
+ [announceSearchResults],
958
1019
  );
959
1020
 
1021
+ // The panel's empty message is role="presentation", so this region is the
1022
+ // only route to assistive tech. It has to watch the STATE rather than the
1023
+ // open event: the panel can become empty either on open or when a fetch
1024
+ // lands with nothing in it, and an open-only announcement leaves the second
1025
+ // case silent while the message sits on screen. The ref makes it fire once
1026
+ // per arrival at that state rather than on every re-render.
1027
+ const announcedEmptyRef = useRef<string | null>(null);
1028
+ useEffect(() => {
1029
+ const isPanelEmpty =
1030
+ popover.isOpen &&
1031
+ !isLoading &&
1032
+ searchQuery === '' &&
1033
+ selectableItems.length === 0;
1034
+ if (!isPanelEmpty) {
1035
+ announcedEmptyRef.current = null;
1036
+ return;
1037
+ }
1038
+ if (announcedEmptyRef.current === emptyAnnouncement) {
1039
+ return;
1040
+ }
1041
+ announcedEmptyRef.current = emptyAnnouncement;
1042
+ announce(emptyAnnouncement);
1043
+ }, [
1044
+ popover.isOpen,
1045
+ isLoading,
1046
+ searchQuery,
1047
+ selectableItems.length,
1048
+ emptyAnnouncement,
1049
+ announce,
1050
+ ]);
1051
+
960
1052
  // Calculate offset to position selected item over trigger. Explicit
961
1053
  // placement opts out of the selector-specific overlay behavior and uses the
962
1054
  // standard layer positioning API instead.
@@ -992,10 +1084,20 @@ export function Selector<T extends SelectorOptionType>(
992
1084
  }, [onChange, changeAction, startTransition, setOptimisticValue]);
993
1085
 
994
1086
  // Type-to-find appends to the query rather than replacing it: characters
995
- // typed before focus reaches the search input must not be dropped.
996
- const appendSearchQuery = useCallback((char: string) => {
997
- setSearchQuery(query => query + char);
998
- }, []);
1087
+ // typed before focus reaches the search input must not be dropped. The ref
1088
+ // is what makes that safe without a state updater — it advances
1089
+ // synchronously, so a second character seeded in the same tick still sees
1090
+ // the first, and the announcement can be computed here rather than inside a
1091
+ // setState callback.
1092
+ const appendSearchQuery = useCallback(
1093
+ (char: string) => {
1094
+ const nextQuery = searchQueryRef.current + char;
1095
+ searchQueryRef.current = nextQuery;
1096
+ setSearchQuery(nextQuery);
1097
+ announceSearchResults(nextQuery);
1098
+ },
1099
+ [announceSearchResults],
1100
+ );
999
1101
 
1000
1102
  const commitValue = useCallback(
1001
1103
  (newValue: string) => {
@@ -1021,6 +1123,7 @@ export function Selector<T extends SelectorOptionType>(
1021
1123
  onItemMouseEnter,
1022
1124
  } = useCombobox({
1023
1125
  selectableItems: filteredItems,
1126
+ wasJustDismissed: popover.wasJustDismissed,
1024
1127
  // The optimistic value, not the raw prop: with a pending changeAction the
1025
1128
  // prop still holds the old selection, so the popup would open with the
1026
1129
  // highlight on it and Delete/Backspace could clear a value the action has
@@ -1313,8 +1416,11 @@ export function Selector<T extends SelectorOptionType>(
1313
1416
  const renderOptions = useCallback(() => {
1314
1417
  const isSearching = hasSearch && Boolean(searchQuery);
1315
1418
 
1316
- // Nothing matched across every group/option: show the empty state.
1317
- if (isSearching && filteredItems.length === 0) {
1419
+ // Nothing to show — either the query matched nothing, or no options were
1420
+ // given at all. Both render the same slot with different copy. While
1421
+ // isLoading the options have not arrived yet, so asserting either would be
1422
+ // a claim the component cannot make; the trigger's spinner covers it.
1423
+ if (filteredItems.length === 0 && !isLoading) {
1318
1424
  // role="presentation" keeps the message out of the listbox's
1319
1425
  // accessibility tree (role="listbox" only permits option/group
1320
1426
  // children); the no-results outcome is announced via the
@@ -1327,7 +1433,7 @@ export function Selector<T extends SelectorOptionType>(
1327
1433
  themeProps('selector-empty-state'),
1328
1434
  stylex.props(styles.emptyState),
1329
1435
  )}>
1330
- No results found
1436
+ {isSearching ? emptySearchText : emptyText}
1331
1437
  </div>,
1332
1438
  ];
1333
1439
  }
@@ -1344,7 +1450,17 @@ export function Selector<T extends SelectorOptionType>(
1344
1450
  if (isSearching) {
1345
1451
  continue;
1346
1452
  }
1347
- elements.push(<Divider key={`divider-${i}`} xstyle={styles.divider} />);
1453
+ // role="listbox" only permits option/group children; the divider
1454
+ // carries no information the options don't, so it's hidden from the
1455
+ // accessibility tree entirely rather than exposing role="separator"
1456
+ // as a disallowed listbox child (axe aria-required-children).
1457
+ elements.push(
1458
+ <Divider
1459
+ key={`divider-${i}`}
1460
+ aria-hidden="true"
1461
+ xstyle={styles.divider}
1462
+ />,
1463
+ );
1348
1464
  } else if (isSection(option)) {
1349
1465
  const sectionItems: ReactNode[] = [];
1350
1466
  for (const opt of option.options) {
@@ -1391,7 +1507,16 @@ export function Selector<T extends SelectorOptionType>(
1391
1507
  }
1392
1508
 
1393
1509
  return elements;
1394
- }, [options, renderItem, hasSearch, searchQuery, filteredItems]);
1510
+ }, [
1511
+ options,
1512
+ renderItem,
1513
+ hasSearch,
1514
+ searchQuery,
1515
+ filteredItems,
1516
+ isLoading,
1517
+ emptyText,
1518
+ emptySearchText,
1519
+ ]);
1395
1520
 
1396
1521
  // The detached message box renders its own leading status icon, so the
1397
1522
  // on-field icon would duplicate it — keep the chevron indicator instead.
@@ -1529,7 +1654,8 @@ export function Selector<T extends SelectorOptionType>(
1529
1654
  )}
1530
1655
  {isBusy && <Spinner size="sm" />}
1531
1656
  {hasClear && value != null && !isDisabled && (
1532
- <InputClearButton
1657
+ <InternalInputClearButton
1658
+ {...keepOpenProps}
1533
1659
  label={t('@astryx.selector.clearLabel', {label})}
1534
1660
  onClick={handleClear}
1535
1661
  iconClassName={stableClassName('selector-clear-icon')}
@@ -1548,6 +1674,7 @@ export function Selector<T extends SelectorOptionType>(
1548
1674
  type="button"
1549
1675
  aria-label={t(STATUS_BUTTON_LABEL_KEY[status.type])}
1550
1676
  aria-describedby={statusTooltip.describedBy}
1677
+ {...keepOpenProps}
1551
1678
  onClick={e => e.stopPropagation()}
1552
1679
  {...stylex.props(
1553
1680
  focusOutlineStyles.focusVisible,
@@ -176,6 +176,12 @@ interface UseComboboxOptions {
176
176
  * lands in the search input, which then owns its own typing.
177
177
  */
178
178
  onSearchSeed?: (char: string) => void;
179
+ /**
180
+ * Whether the browser's light dismiss just closed the popup. The trigger
181
+ * click that follows belongs to that same press, so acting on it would
182
+ * reopen the popup the user just closed.
183
+ */
184
+ wasJustDismissed?: () => boolean;
179
185
  listboxId: string;
180
186
  }
181
187
 
@@ -208,6 +214,7 @@ export function useCombobox({
208
214
  onSelect,
209
215
  onClear,
210
216
  onSearchSeed,
217
+ wasJustDismissed,
211
218
  listboxId,
212
219
  }: UseComboboxOptions): UseComboboxResult {
213
220
  const [highlightedIndex, setHighlightedIndex] = useState<number>(-1);
@@ -244,7 +251,7 @@ export function useCombobox({
244
251
  );
245
252
 
246
253
  const onTriggerClick = useCallback(() => {
247
- if (isDisabled) {
254
+ if (isDisabled || wasJustDismissed?.()) {
248
255
  return;
249
256
  }
250
257
  if (isOpen) {
@@ -256,7 +263,15 @@ export function useCombobox({
256
263
  setHighlightedIndex(selectedIndex >= 0 ? selectedIndex : 0);
257
264
  }
258
265
  }
259
- }, [isDisabled, isOpen, onOpen, closeAndReset, findSelectedIndex, hasSearch]);
266
+ }, [
267
+ isDisabled,
268
+ wasJustDismissed,
269
+ isOpen,
270
+ onOpen,
271
+ closeAndReset,
272
+ findSelectedIndex,
273
+ hasSearch,
274
+ ]);
260
275
 
261
276
  const onItemMouseEnter = useCallback(
262
277
  (item: SelectorOptionData, index: number) => {
@@ -131,8 +131,8 @@ export const docs = {
131
131
  bestPractices: [
132
132
  {guidance: true, description: 'Use sections to group related navigation items and help users scan for their destination.'},
133
133
  {guidance: true, description: 'Pair outline and filled icon variants so the selected state is visually distinct.'},
134
- {guidance: true, description: 'Mark the current page with isSelected — it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
135
- {guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short — they are the accessible name in both expanded and icon-only modes.'},
134
+ {guidance: true, description: 'Mark the current page with isSelected: it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
135
+ {guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short; they are the accessible name in both expanded and icon-only modes.'},
136
136
  {guidance: true, description: 'While the nav is collapsed, an item with children shows them in a submenu flyout. On a device that can hover, pointing at the item opens it after a short delay and moving away closes it; a flyout opened by clicking stays open until it is dismissed. On touch, it opens on tap. Do not put an action in there that has no other route to it.'},
137
137
  {guidance: false, description: 'Include a SideNavHeading when a TopNav is already providing app identity; this duplicates branding.'},
138
138
  {guidance: false, description: 'Use for filtering content; use tabs or filter buttons instead.'},
@@ -153,8 +153,8 @@ export const docsZh = {
153
153
  bestPractices: [
154
154
  {guidance: true, description: 'Use sections to group related navigation items and help users scan for their destination.'},
155
155
  {guidance: true, description: 'Pair outline and filled icon variants so the selected state is visually distinct.'},
156
- {guidance: true, description: 'Mark the current page with isSelected — it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
157
- {guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short — they are the accessible name in both expanded and icon-only modes.'},
156
+ {guidance: true, description: 'Mark the current page with isSelected: it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
157
+ {guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short; they are the accessible name in both expanded and icon-only modes.'},
158
158
  {guidance: true, description: 'While the nav is collapsed, an item with children shows them in a submenu flyout. On a device that can hover, pointing at the item opens it after a short delay and moving away closes it; a flyout opened by clicking stays open until it is dismissed. On touch, it opens on tap. Do not put an action in there that has no other route to it.'},
159
159
  {guidance: false, description: 'Include a SideNavHeading when a TopNav is already providing app identity; this duplicates branding.'},
160
160
  {guidance: false, description: 'Use for filtering content; use tabs or filter buttons instead.'},
@@ -175,8 +175,8 @@ export const docsDense = {
175
175
  bestPractices: [
176
176
  {guidance: true, description: 'Use sections to group related navigation items and help users scan for their destination.'},
177
177
  {guidance: true, description: 'Pair outline and filled icon variants so the selected state is visually distinct.'},
178
- {guidance: true, description: 'Mark the current page with isSelected — it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
179
- {guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short — they are the accessible name in both expanded and icon-only modes.'},
178
+ {guidance: true, description: 'Mark the current page with isSelected: it sets aria-current="page", so the current destination is announced rather than carried by color alone.'},
179
+ {guidance: true, description: 'SideNav renders a navigation landmark, and a collapsible item follows the WAI-ARIA APG Disclosure pattern (https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/): the toggle carries aria-expanded and aria-controls, and the group it owns is inert while collapsed. Keep item labels short; they are the accessible name in both expanded and icon-only modes.'},
180
180
  {guidance: true, description: 'While the nav is collapsed, an item with children shows them in a submenu flyout. On a device that can hover, pointing at the item opens it after a short delay and moving away closes it; a flyout opened by clicking stays open until it is dismissed. On touch, it opens on tap. Do not put an action in there that has no other route to it.'},
181
181
  {guidance: false, description: 'Include a SideNavHeading when a TopNav is already providing app identity; this duplicates branding.'},
182
182
  {guidance: false, description: 'Use for filtering content; use tabs or filter buttons instead.'},
@@ -32,7 +32,7 @@ import type {BaseProps} from '../BaseProps';
32
32
  import * as stylex from '@stylexjs/stylex';
33
33
  import type {StyleXStyles} from '@stylexjs/stylex';
34
34
  import {spacingVars} from '../theme/tokens.stylex';
35
- import {mergeProps, mergeRefs} from '../utils';
35
+ import {mergeProps} from '../utils';
36
36
  import {
37
37
  SideNavCollapseContext,
38
38
  type SideNavCollapseState,
@@ -49,6 +49,7 @@ import {themeProps} from '../utils/themeProps';
49
49
  import {SizeProvider} from '../SizeContext/SizeContext';
50
50
  import {useTranslator} from '../i18n';
51
51
 
52
+ import {useMergedRefs} from '../hooks/useMergedRefs';
52
53
  // =============================================================================
53
54
  // Constants
54
55
  // =============================================================================
@@ -349,6 +350,7 @@ export function SideNav({
349
350
  useState(defaultIsCollapsed);
350
351
  const collapsed = isControlled ? controlledCollapsed : uncontrolledCollapsed;
351
352
  const navRef = useRef<HTMLElement>(null);
353
+ const mergedNavRef = useMergedRefs(ref, navRef);
352
354
  const collapseStateRef = useRef<SideNavCollapseState>({
353
355
  isCollapsed: collapsed,
354
356
  toggle: () => {},
@@ -517,7 +519,7 @@ export function SideNav({
517
519
 
518
520
  const navElement = (
519
521
  <nav
520
- ref={mergeRefs(ref, navRef)}
522
+ ref={mergedNavRef}
521
523
  role="navigation"
522
524
  aria-label={t('@astryx.sideNav.label')}
523
525
  data-testid={testId}
@@ -40,7 +40,8 @@ import {focusOutlineProps} from '../utils/focusOutline.stylex';
40
40
  import {useSideNavCollapse} from './SideNavCollapseContext';
41
41
  import {useLinkComponent} from '../Link/useLinkComponent';
42
42
  import type {LinkComponentType} from '../Link/types';
43
- import {mergeProps, mergeRefs} from '../utils';
43
+ import {mergeProps} from '../utils';
44
+ import {useMergedRefs} from '../hooks/useMergedRefs';
44
45
  import type {BaseProps} from '../BaseProps';
45
46
  import {useMenuHover} from '../hooks/useMenuHover';
46
47
  import {NavHeadingCloseContext} from '../NavMenu/NavMenuContext';
@@ -59,7 +60,7 @@ const styles = stylex.create({
59
60
  minHeight: spacingVars['--spacing-8'],
60
61
  paddingInlineStart: {
61
62
  default: spacingVars['--spacing-2'],
62
- ':has(.astryx-navicon)': 0,
63
+ ':has(.astryx-nav-icon)': 0,
63
64
  },
64
65
  paddingInlineEnd: spacingVars['--spacing-2'],
65
66
  paddingBlock: 0,
@@ -211,7 +212,7 @@ const styles = stylex.create({
211
212
  minHeight: spacingVars['--spacing-8'],
212
213
  paddingInlineStart: {
213
214
  default: spacingVars['--spacing-2'],
214
- ':has(.astryx-navicon)': 0,
215
+ ':has(.astryx-nav-icon)': 0,
215
216
  },
216
217
  paddingInlineEnd: spacingVars['--spacing-2'],
217
218
  paddingBlock: 0,
@@ -399,11 +400,18 @@ export function SideNavHeading({
399
400
  // setTriggerEl belongs on the chevron button, not this root: it is the
400
401
  // focus-restore target and a <div> cannot take focus. triggerRef stays here
401
402
  // because the panel anchors to the whole heading.
402
- const setRef = mergeRefs<HTMLDivElement>(
403
+ const setRef = useMergedRefs<HTMLDivElement>(
403
404
  rootRef,
404
405
  ref,
405
406
  menu ? popover.triggerRef : undefined,
406
407
  );
408
+ const collapsedSetRef = useMergedRefs<HTMLElement>(
409
+ collapsedItemRef,
410
+ ref,
411
+ // Collapsed, this button is the trigger, so it takes both roles.
412
+ menu ? popover.triggerRef : undefined,
413
+ menu ? setTriggerEl : undefined,
414
+ );
407
415
 
408
416
  // In collapsed mode: hide if no icon, show icon-only if has icon
409
417
  if (isCollapsed && !icon) {
@@ -412,14 +420,6 @@ export function SideNavHeading({
412
420
  if (isCollapsed && icon) {
413
421
  const collapsedIcon = <span {...stylex.props(styles.icon)}>{icon}</span>;
414
422
 
415
- const collapsedSetRef = mergeRefs<HTMLElement>(
416
- collapsedItemRef,
417
- ref,
418
- // Collapsed, this button is the trigger, so it takes both roles.
419
- menu ? popover.triggerRef : undefined,
420
- menu ? setTriggerEl : undefined,
421
- );
422
-
423
423
  let collapsedElement: ReactNode;
424
424
 
425
425
  if (headingHref) {
@@ -47,7 +47,7 @@ import {useLinkComponent} from '../Link/useLinkComponent';
47
47
  import type {LinkComponentType} from '../Link/types';
48
48
  import {usePopover} from '../Popover/usePopover';
49
49
  import {useMenuHover} from '../hooks/useMenuHover';
50
- import {mergeProps, mergeRefs} from '../utils';
50
+ import {mergeProps} from '../utils';
51
51
  import type {BaseProps} from '../BaseProps';
52
52
  import {Tooltip} from '../Tooltip';
53
53
  import {navItemStyles, type NavItemSize} from '../NavItem/navItemStyles.stylex';
@@ -61,6 +61,7 @@ import {useAppShellMobile} from '../AppShell/AppShellMobileContext';
61
61
  import {themeProps} from '../utils/themeProps';
62
62
  import {useTranslator} from '../i18n';
63
63
 
64
+ import {useMergedRefs} from '../hooks/useMergedRefs';
64
65
  // =============================================================================
65
66
  // Styles
66
67
  // =============================================================================
@@ -408,6 +409,7 @@ export function SideNavItem({
408
409
  hasCloseButton: false,
409
410
  dialogLabel: t('@astryx.sideNavItem.submenuLabel', {label}),
410
411
  });
412
+ const mergedTriggerRef = useMergedRefs(ref, popover.triggerRef);
411
413
 
412
414
  // Collapse state for items with children
413
415
  const itemCollapsibleConfig = useMemo(
@@ -524,7 +526,7 @@ export function SideNavItem({
524
526
  return (
525
527
  <div {...stylex.props(styles.root, xstyle)}>
526
528
  <button
527
- ref={mergeRefs(ref, popover.triggerRef)}
529
+ ref={mergedTriggerRef}
528
530
  type="button"
529
531
  {...rest}
530
532
  {...hoverTriggerProps}
@@ -13,7 +13,10 @@ import {useState} from 'react';
13
13
  import {describe, it, expect, vi, beforeEach} from 'vitest';
14
14
  import {render, screen, act, fireEvent, waitFor} from '@testing-library/react';
15
15
  import userEvent from '@testing-library/user-event';
16
+ import * as stylex from '@stylexjs/stylex';
16
17
  import {Slider} from './Slider';
18
+ import {focusOutlineStyles} from '../utils/focusOutline.stylex';
19
+ import {__resetInteractionModalityForTest} from '../utils/interactionModality';
17
20
 
18
21
  // Mock showPopover/hidePopover (not implemented in jsdom) so the tooltip layer
19
22
  // reflects its open state via a `popover-open` attribute the tests can assert.
@@ -854,7 +857,7 @@ describe('Slider', () => {
854
857
  />,
855
858
  );
856
859
  const thumb = screen.getByRole('slider');
857
- thumb.focus();
860
+ act(() => thumb.focus());
858
861
  await user.keyboard('{ArrowRight}');
859
862
  expect(onChange).not.toHaveBeenCalled();
860
863
  });
@@ -902,4 +905,106 @@ describe('Slider', () => {
902
905
  ]).toEqual([]);
903
906
  });
904
907
  });
908
+
909
+ describe('focus ring modality', () => {
910
+ beforeEach(() => {
911
+ __resetInteractionModalityForTest();
912
+ });
913
+
914
+ // The ring is a stylex class, so derive it from the same source the
915
+ // component applies rather than hardcoding a hash.
916
+ const RING = stylex
917
+ .props(focusOutlineStyles.focusVisible)
918
+ .className!.split(' ');
919
+ const isRinged = (el: HTMLElement) =>
920
+ RING.every(c => el.classList.contains(c));
921
+
922
+ // The track has no layout in jsdom; pointer maths needs a real rect.
923
+ const grabTrack = (thumb: HTMLElement) => {
924
+ const track = thumb.parentElement!;
925
+ track.getBoundingClientRect = () => ({
926
+ left: 0,
927
+ top: 0,
928
+ right: 200,
929
+ bottom: 20,
930
+ width: 200,
931
+ height: 20,
932
+ x: 0,
933
+ y: 0,
934
+ toJSON: () => {},
935
+ });
936
+ fireEvent.pointerDown(track, {clientX: 100, clientY: 10, pointerId: 1});
937
+ };
938
+
939
+ it('rings when the thumb is reached with the keyboard', async () => {
940
+ const user = userEvent.setup();
941
+ render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
942
+ await user.tab();
943
+ expect(isRinged(screen.getByRole('slider'))).toBe(true);
944
+ });
945
+
946
+ it('does not ring when the thumb is grabbed with the mouse', () => {
947
+ render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
948
+ const thumb = screen.getByRole('slider');
949
+ grabTrack(thumb);
950
+ expect(thumb).toHaveFocus();
951
+ expect(isRinged(thumb)).toBe(false);
952
+ });
953
+
954
+ it('drops the ring when the mouse grabs a thumb that already had it', async () => {
955
+ const user = userEvent.setup();
956
+ render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
957
+ await user.tab();
958
+ const thumb = screen.getByRole('slider');
959
+ expect(isRinged(thumb)).toBe(true);
960
+ // Already focused, so focus() fires no focus event.
961
+ grabTrack(thumb);
962
+ expect(isRinged(thumb)).toBe(false);
963
+ });
964
+
965
+ it('brings the ring back when an arrow key follows a mouse drag', () => {
966
+ render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
967
+ const thumb = screen.getByRole('slider');
968
+ grabTrack(thumb);
969
+ expect(isRinged(thumb)).toBe(false);
970
+ fireEvent.keyDown(thumb, {key: 'ArrowRight'});
971
+ expect(isRinged(thumb)).toBe(true);
972
+ });
973
+
974
+ it('leaves the ring off for a modifier chord after a mouse drag', () => {
975
+ render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
976
+ const thumb = screen.getByRole('slider');
977
+ grabTrack(thumb);
978
+ // Copying or reloading is not navigation, and the mouse is still on it.
979
+ fireEvent.keyDown(thumb, {key: 'c', metaKey: true});
980
+ expect(isRinged(thumb)).toBe(false);
981
+ });
982
+
983
+ it('drops the ring on blur', async () => {
984
+ const user = userEvent.setup();
985
+ render(<Slider label="Volume" value={50} onChange={vi.fn()} />);
986
+ await user.tab();
987
+ const thumb = screen.getByRole('slider');
988
+ expect(isRinged(thumb)).toBe(true);
989
+ act(() => thumb.blur());
990
+ expect(isRinged(thumb)).toBe(false);
991
+ });
992
+
993
+ it('rings the range thumb the keyboard reached, not its sibling', async () => {
994
+ const user = userEvent.setup();
995
+ render(
996
+ <Slider
997
+ label="Price"
998
+ value={[20, 80] as [number, number]}
999
+ onChange={vi.fn()}
1000
+ />,
1001
+ );
1002
+ await user.tab();
1003
+ await user.tab();
1004
+ const thumbs = screen.getAllByRole('slider');
1005
+ expect(thumbs[1]).toHaveFocus();
1006
+ expect(isRinged(thumbs[1])).toBe(true);
1007
+ expect(isRinged(thumbs[0])).toBe(false);
1008
+ });
1009
+ });
905
1010
  });