@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
@@ -0,0 +1,1024 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {StrictMode} from 'react';
4
+ import {describe, it, expect, vi} from 'vitest';
5
+ import {render, screen, within} from '@testing-library/react';
6
+ import userEvent from '@testing-library/user-event';
7
+ import {Stepper} from './Stepper';
8
+ import {Step} from './Step';
9
+
10
+ describe('Stepper', () => {
11
+ it('renders an ordered list of steps (not a nav landmark)', () => {
12
+ render(
13
+ <Stepper activeStep={0}>
14
+ <Step step={0} label="Step 1" />
15
+ <Step step={1} label="Step 2" />
16
+ <Step step={2} label="Step 3" />
17
+ </Stepper>,
18
+ );
19
+ // A stepper is a sequence/progress list, not a navigation landmark.
20
+ expect(screen.queryByRole('navigation')).not.toBeInTheDocument();
21
+ const list = screen.getByRole('list', {name: 'Progress'});
22
+ expect(list.tagName).toBe('OL');
23
+ expect(screen.getByText('Step 1')).toBeInTheDocument();
24
+ expect(screen.getByText('Step 2')).toBeInTheDocument();
25
+ expect(screen.getByText('Step 3')).toBeInTheDocument();
26
+ });
27
+
28
+ it('renders step numbers', () => {
29
+ render(
30
+ <Stepper activeStep={0}>
31
+ <Step step={0} label="First" indicator="number" />
32
+ <Step step={1} label="Second" indicator="number" />
33
+ </Stepper>,
34
+ );
35
+ expect(screen.getByText('1')).toBeInTheDocument();
36
+ expect(screen.getByText('2')).toBeInTheDocument();
37
+ });
38
+
39
+ it('marks the active step with aria-current', () => {
40
+ render(
41
+ <Stepper activeStep={1}>
42
+ <Step step={0} label="Step 1" data-testid="step-0" />
43
+ <Step step={1} label="Step 2" data-testid="step-1" />
44
+ <Step step={2} label="Step 3" data-testid="step-2" />
45
+ </Stepper>,
46
+ );
47
+ expect(screen.getByTestId('step-0')).not.toHaveAttribute('aria-current');
48
+ expect(screen.getByTestId('step-1')).toHaveAttribute(
49
+ 'aria-current',
50
+ 'step',
51
+ );
52
+ expect(screen.getByTestId('step-2')).not.toHaveAttribute('aria-current');
53
+ });
54
+
55
+ it('renders descriptions when provided', () => {
56
+ render(
57
+ <Stepper activeStep={0}>
58
+ <Step step={0} label="Account" description="Create your account" />
59
+ <Step step={1} label="Profile" />
60
+ </Stepper>,
61
+ );
62
+ expect(screen.getByText('Create your account')).toBeInTheDocument();
63
+ });
64
+
65
+ it('supports custom accessible label', () => {
66
+ render(
67
+ <Stepper activeStep={0} label="Checkout progress">
68
+ <Step step={0} label="Cart" />
69
+ <Step step={1} label="Payment" />
70
+ </Stepper>,
71
+ );
72
+ expect(
73
+ screen.getByRole('list', {name: 'Checkout progress'}),
74
+ ).toBeInTheDocument();
75
+ });
76
+
77
+ it('supports vertical orientation', () => {
78
+ render(
79
+ <Stepper activeStep={0} orientation="vertical">
80
+ <Step step={0} label="Step 1" />
81
+ <Step step={1} label="Step 2" />
82
+ </Stepper>,
83
+ );
84
+ const list = screen.getByRole('list');
85
+ expect(list).toHaveAttribute('data-orientation', 'vertical');
86
+ });
87
+
88
+ it('calls onStepClick when a completed step is clicked', async () => {
89
+ const user = userEvent.setup();
90
+ const handleClick = vi.fn();
91
+ render(
92
+ <Stepper activeStep={2} onStepClick={handleClick}>
93
+ <Step step={0} label="Step 1" />
94
+ <Step step={1} label="Step 2" />
95
+ <Step step={2} label="Step 3" />
96
+ </Stepper>,
97
+ );
98
+ await user.click(
99
+ screen.getByRole('button', {name: 'Go to step 1: Step 1, completed'}),
100
+ );
101
+ expect(handleClick).toHaveBeenCalledWith(0);
102
+ });
103
+
104
+ it('calls onStepClick when the active step is clicked', async () => {
105
+ const user = userEvent.setup();
106
+ const handleClick = vi.fn();
107
+ render(
108
+ <Stepper activeStep={1} onStepClick={handleClick}>
109
+ <Step step={0} label="Step 1" />
110
+ <Step step={1} label="Step 2" />
111
+ <Step step={2} label="Step 3" />
112
+ </Stepper>,
113
+ );
114
+ await user.click(
115
+ screen.getByRole('button', {name: 'Go to step 2: Step 2'}),
116
+ );
117
+ expect(handleClick).toHaveBeenCalledWith(1);
118
+ });
119
+
120
+ it('renders buttons for upcoming steps in non-linear mode', () => {
121
+ render(
122
+ <Stepper activeStep={0} onStepClick={() => {}}>
123
+ <Step step={0} label="Step 1" />
124
+ <Step step={1} label="Step 2" />
125
+ </Stepper>,
126
+ );
127
+ expect(
128
+ screen.getByRole('button', {name: 'Go to step 1: Step 1'}),
129
+ ).toBeInTheDocument();
130
+ expect(
131
+ screen.getByRole('button', {name: 'Go to step 2: Step 2'}),
132
+ ).toBeInTheDocument();
133
+ });
134
+
135
+ it('calls onStepClick when an upcoming step is clicked', async () => {
136
+ const user = userEvent.setup();
137
+ const handleClick = vi.fn();
138
+ render(
139
+ <Stepper activeStep={0} onStepClick={handleClick}>
140
+ <Step step={0} label="Step 1" />
141
+ <Step step={1} label="Step 2" />
142
+ <Step step={2} label="Step 3" />
143
+ </Stepper>,
144
+ );
145
+ await user.click(
146
+ screen.getByRole('button', {name: 'Go to step 3: Step 3'}),
147
+ );
148
+ expect(handleClick).toHaveBeenCalledWith(2);
149
+ });
150
+
151
+ it('does not render buttons for disabled steps', () => {
152
+ render(
153
+ <Stepper activeStep={2} onStepClick={() => {}}>
154
+ <Step step={0} label="Step 1" isDisabled />
155
+ <Step step={1} label="Step 2" />
156
+ <Step step={2} label="Step 3" />
157
+ </Stepper>,
158
+ );
159
+ expect(
160
+ screen.queryByRole('button', {name: /Go to step 1: Step 1/}),
161
+ ).not.toBeInTheDocument();
162
+ });
163
+
164
+ it('does not render buttons when onStepClick is not provided', () => {
165
+ render(
166
+ <Stepper activeStep={2}>
167
+ <Step step={0} label="Step 1" />
168
+ <Step step={1} label="Step 2" />
169
+ <Step step={2} label="Step 3" />
170
+ </Stepper>,
171
+ );
172
+ expect(screen.queryAllByRole('button')).toHaveLength(0);
173
+ });
174
+
175
+ it('applies a semantic color status (color only) via data attribute', () => {
176
+ render(
177
+ <Stepper activeStep={1}>
178
+ <Step step={0} label="Step 1" data-testid="step-0" />
179
+ <Step step={1} label="Step 2" status="error" data-testid="step-1" />
180
+ </Stepper>,
181
+ );
182
+ expect(screen.getByTestId('step-1')).toHaveAttribute(
183
+ 'data-status',
184
+ 'error',
185
+ );
186
+ // status is color-only — it must not change progress semantics.
187
+ expect(screen.getByTestId('step-1')).toHaveAttribute(
188
+ 'aria-current',
189
+ 'step',
190
+ );
191
+ });
192
+
193
+ it('reflects each global semantic status on the data attribute', () => {
194
+ render(
195
+ <Stepper activeStep={0}>
196
+ <Step step={0} label="A" status="accent" data-testid="s-accent" />
197
+ <Step step={1} label="B" status="success" data-testid="s-success" />
198
+ <Step step={2} label="C" status="warning" data-testid="s-warning" />
199
+ <Step step={3} label="D" status="error" data-testid="s-error" />
200
+ </Stepper>,
201
+ );
202
+ expect(screen.getByTestId('s-accent')).toHaveAttribute(
203
+ 'data-status',
204
+ 'accent',
205
+ );
206
+ expect(screen.getByTestId('s-success')).toHaveAttribute(
207
+ 'data-status',
208
+ 'success',
209
+ );
210
+ expect(screen.getByTestId('s-warning')).toHaveAttribute(
211
+ 'data-status',
212
+ 'warning',
213
+ );
214
+ expect(screen.getByTestId('s-error')).toHaveAttribute(
215
+ 'data-status',
216
+ 'error',
217
+ );
218
+ });
219
+
220
+ it('keeps the progress bar progress-colored regardless of status, recoloring only the indicator', () => {
221
+ // Baseline: a completed step with no status.
222
+ const baseline = render(
223
+ <Stepper activeStep={1}>
224
+ <Step step={0} label="A" data-testid="base" />
225
+ </Stepper>,
226
+ );
227
+ const baseStep = baseline.getByTestId('base');
228
+ const baseBar = baseStep.querySelector('.astryx-step-bar') as HTMLElement;
229
+ const baseIndicator = baseStep.querySelector('svg')
230
+ ?.parentElement as HTMLElement;
231
+
232
+ // Same completed step, now with a semantic status.
233
+ const themed = render(
234
+ <Stepper activeStep={1}>
235
+ <Step step={0} label="A" status="error" data-testid="themed" />
236
+ </Stepper>,
237
+ );
238
+ const themedStep = themed.getByTestId('themed');
239
+ const themedBar = themedStep.querySelector(
240
+ '.astryx-step-bar',
241
+ ) as HTMLElement;
242
+ const themedIndicator = themedStep.querySelector('svg')
243
+ ?.parentElement as HTMLElement;
244
+
245
+ // Bar coloring must be identical — status must NOT recolor the bar
246
+ // (always --color-accent when filled / --color-border when incomplete).
247
+ expect(themedBar.className).toBe(baseBar.className);
248
+
249
+ // The indicator, however, must pick up the status color.
250
+ expect(themedIndicator.className).not.toBe(baseIndicator.className);
251
+ });
252
+
253
+ it('keeps an incomplete step bar border-colored regardless of status', () => {
254
+ // Baseline: a not-started step with no status.
255
+ const baseline = render(
256
+ <Stepper activeStep={0}>
257
+ <Step step={0} label="A" data-testid="base-active" />
258
+ <Step step={1} label="B" data-testid="base" />
259
+ </Stepper>,
260
+ );
261
+ const baseBar = baseline
262
+ .getByTestId('base')
263
+ .querySelector('.astryx-step-bar') as HTMLElement;
264
+
265
+ // Same not-started step, now with a semantic status.
266
+ const themed = render(
267
+ <Stepper activeStep={0}>
268
+ <Step step={0} label="A" data-testid="themed-active" />
269
+ <Step step={1} label="B" status="warning" data-testid="themed" />
270
+ </Stepper>,
271
+ );
272
+ const themedBar = themed
273
+ .getByTestId('themed')
274
+ .querySelector('.astryx-step-bar') as HTMLElement;
275
+
276
+ // Incomplete bar stays border-colored — status must not recolor it.
277
+ expect(themedBar.className).toBe(baseBar.className);
278
+ });
279
+
280
+ it('does not set a status data attribute when status is unset', () => {
281
+ render(
282
+ <Stepper activeStep={0}>
283
+ <Step step={0} label="Step 1" data-testid="step-0" />
284
+ </Stepper>,
285
+ );
286
+ expect(screen.getByTestId('step-0')).not.toHaveAttribute('data-status');
287
+ });
288
+
289
+ it('handles zero active step correctly', () => {
290
+ render(
291
+ <Stepper activeStep={0}>
292
+ <Step step={0} label="Step 1" data-testid="step-0" />
293
+ <Step step={1} label="Step 2" data-testid="step-1" />
294
+ </Stepper>,
295
+ );
296
+ expect(screen.getByTestId('step-0')).toHaveAttribute(
297
+ 'aria-current',
298
+ 'step',
299
+ );
300
+ expect(screen.getByTestId('step-1')).not.toHaveAttribute('aria-current');
301
+ });
302
+
303
+ it('renders each step as a list item', () => {
304
+ render(
305
+ <Stepper activeStep={0}>
306
+ <Step step={0} label="Step 1" />
307
+ <Step step={1} label="Step 2" />
308
+ <Step step={2} label="Step 3" />
309
+ </Stepper>,
310
+ );
311
+ const items = screen.getAllByRole('listitem');
312
+ expect(items).toHaveLength(3);
313
+ expect(items[0].tagName).toBe('LI');
314
+ });
315
+
316
+ it('accepts a custom ReactNode as indicator', () => {
317
+ render(
318
+ <Stepper activeStep={0}>
319
+ <Step
320
+ step={0}
321
+ label="Step 1"
322
+ indicator={<span data-testid="custom-icon">★</span>}
323
+ />
324
+ </Stepper>,
325
+ );
326
+ expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
327
+ expect(screen.getByText('★')).toBeInTheDocument();
328
+ });
329
+
330
+ it('accepts a ReactNode as indicator', () => {
331
+ render(
332
+ <Stepper activeStep={1}>
333
+ <Step
334
+ step={1}
335
+ label="Payment"
336
+ indicator={<span data-testid="pay-icon">$</span>}
337
+ />
338
+ </Stepper>,
339
+ );
340
+ expect(screen.getByTestId('pay-icon')).toBeInTheDocument();
341
+ });
342
+
343
+ it('renders a distinct indicator glyph per status on non-current steps', () => {
344
+ // All steps completed (activeStep past them) so none is the current step.
345
+ render(
346
+ <Stepper activeStep={4}>
347
+ <Step step={0} label="A" status="success" data-testid="s-success" />
348
+ <Step step={1} label="B" status="warning" data-testid="s-warning" />
349
+ <Step step={2} label="C" status="error" data-testid="s-error" />
350
+ <Step step={3} label="D" data-testid="s-plain" />
351
+ </Stepper>,
352
+ );
353
+
354
+ const indicatorClass = (testid: string) =>
355
+ (
356
+ screen.getByTestId(testid).querySelector('svg')
357
+ ?.parentElement as HTMLElement
358
+ ).className;
359
+
360
+ // Each status renders an svg indicator (no number badge)...
361
+ expect(screen.getByTestId('s-success').querySelector('svg')).toBeTruthy();
362
+ expect(screen.getByTestId('s-warning').querySelector('svg')).toBeTruthy();
363
+ expect(screen.getByTestId('s-error').querySelector('svg')).toBeTruthy();
364
+
365
+ // ...and each status tints the indicator differently from the others and
366
+ // from the plain completed (accent) step.
367
+ const classes = new Set([
368
+ indicatorClass('s-success'),
369
+ indicatorClass('s-warning'),
370
+ indicatorClass('s-error'),
371
+ indicatorClass('s-plain'),
372
+ ]);
373
+ expect(classes.size).toBe(4);
374
+ });
375
+
376
+ it('lets the current step keep its ring indicator regardless of status', () => {
377
+ // The current-step ring's painted color is driven by the StyleX
378
+ // `iconInProgress` class (accent), never a status color — the ring replaces
379
+ // any status glyph. The `astryx-step-indicator` theme target reflects
380
+ // `status` as a data attribute so a theme can still reach it, which is
381
+ // orthogonal to the painted color, so assert the StyleX color class here.
382
+ const stylexColorClasses = (el: HTMLElement) =>
383
+ el.className
384
+ .split(/\s+/)
385
+ // Keep StyleX classes (debug `Step__styles.*` names + `x*` atomic
386
+ // hashes); drop the themeProps data reflections (`in-progress`,
387
+ // `success`, `astryx-*`) which are orthogonal to the painted color.
388
+ .filter(c => c.startsWith('Step__styles.') || /^x[a-z0-9]+$/.test(c))
389
+ .sort()
390
+ .join(' ');
391
+
392
+ const plain = render(
393
+ <Stepper activeStep={0}>
394
+ <Step step={0} label="A" data-testid="plain" />
395
+ </Stepper>,
396
+ );
397
+ const plainIndicator = stylexColorClasses(
398
+ plain.getByTestId('plain').querySelector('svg')
399
+ ?.parentElement as HTMLElement,
400
+ );
401
+
402
+ // The same current step, now with status="success": the painted ring must
403
+ // be unchanged (the current-step ring replaces any status glyph).
404
+ const themed = render(
405
+ <Stepper activeStep={0}>
406
+ <Step step={0} label="A" status="success" data-testid="themed" />
407
+ </Stepper>,
408
+ );
409
+ const themedIndicator = stylexColorClasses(
410
+ themed.getByTestId('themed').querySelector('svg')
411
+ ?.parentElement as HTMLElement,
412
+ );
413
+
414
+ expect(themedIndicator).toBe(plainIndicator);
415
+ // And it is the in-progress (accent) color, not a status color.
416
+ expect(plainIndicator).toContain('Step__styles.iconInProgress');
417
+ });
418
+
419
+ it('replaces the number badge with a status glyph on not-started steps', () => {
420
+ render(
421
+ <Stepper activeStep={0}>
422
+ <Step step={0} label="A" data-testid="current" />
423
+ <Step step={1} label="B" status="error" data-testid="future" />
424
+ </Stepper>,
425
+ );
426
+ const future = screen.getByTestId('future');
427
+ // The not-started step would normally show its number ("2"); with a status
428
+ // glyph it shows an icon instead.
429
+ expect(future.textContent).not.toContain('2');
430
+ expect(future.querySelector('svg')).toBeTruthy();
431
+ });
432
+
433
+ it('exposes progress/status as visually hidden text (indicators are aria-hidden)', () => {
434
+ render(
435
+ <Stepper activeStep={2}>
436
+ <Step step={0} label="Account" data-testid="done" />
437
+ <Step step={1} label="Payment" status="error" data-testid="failed" />
438
+ <Step step={2} label="Review" data-testid="current" />
439
+ <Step step={3} label="Confirm" data-testid="upcoming" />
440
+ </Stepper>,
441
+ );
442
+ // Completed step announces "completed"; error status wins over completion.
443
+ expect(
444
+ within(screen.getByTestId('done')).getByText('completed'),
445
+ ).toBeInTheDocument();
446
+ expect(
447
+ within(screen.getByTestId('failed')).getByText('error'),
448
+ ).toBeInTheDocument();
449
+ expect(
450
+ within(screen.getByTestId('failed')).queryByText('completed'),
451
+ ).not.toBeInTheDocument();
452
+ // Current step is announced via aria-current, not hidden text; upcoming
453
+ // steps stay silent.
454
+ expect(
455
+ within(screen.getByTestId('current')).queryByText('completed'),
456
+ ).not.toBeInTheDocument();
457
+ expect(
458
+ within(screen.getByTestId('upcoming')).queryByText(
459
+ /completed|error|warning/,
460
+ ),
461
+ ).not.toBeInTheDocument();
462
+ });
463
+
464
+ it('exposes warning and success statuses as visually hidden text', () => {
465
+ render(
466
+ <Stepper activeStep={2}>
467
+ <Step step={0} label="Build" status="warning" data-testid="warned" />
468
+ <Step step={1} label="Deploy" status="success" data-testid="passed" />
469
+ </Stepper>,
470
+ );
471
+ expect(
472
+ within(screen.getByTestId('warned')).getByText('warning'),
473
+ ).toBeInTheDocument();
474
+ expect(
475
+ within(screen.getByTestId('passed')).getByText('completed'),
476
+ ).toBeInTheDocument();
477
+ });
478
+
479
+ it('composes status into the accessible name of clickable steps', () => {
480
+ render(
481
+ <Stepper activeStep={2} onStepClick={() => {}}>
482
+ <Step step={0} label="Account" />
483
+ <Step step={1} label="Payment" status="error" />
484
+ <Step step={2} label="Review" />
485
+ </Stepper>,
486
+ );
487
+ expect(
488
+ screen.getByRole('button', {name: 'Go to step 1: Account, completed'}),
489
+ ).toBeInTheDocument();
490
+ expect(
491
+ screen.getByRole('button', {name: 'Go to step 2: Payment, error'}),
492
+ ).toBeInTheDocument();
493
+ // The current step gets no status suffix (aria-current covers it).
494
+ expect(
495
+ screen.getByRole('button', {name: 'Go to step 3: Review'}),
496
+ ).toBeInTheDocument();
497
+ });
498
+
499
+ it('exposes hidden status text in the on-track layout too', () => {
500
+ render(
501
+ <Stepper activeStep={1} indicatorPosition="on-track">
502
+ <Step step={0} label="Account" data-testid="ot-done" />
503
+ <Step step={1} label="Payment" data-testid="ot-current" />
504
+ </Stepper>,
505
+ );
506
+ expect(
507
+ within(screen.getByTestId('ot-done')).getByText('completed'),
508
+ ).toBeInTheDocument();
509
+ expect(
510
+ within(screen.getByTestId('ot-current')).queryByText('completed'),
511
+ ).not.toBeInTheDocument();
512
+ });
513
+
514
+ // A vertical on-track step's content slot renders outside the row that draws
515
+ // the connector, so without its own segment the track breaks open around any
516
+ // step carrying content. jsdom can't measure the line, so assert the wiring:
517
+ // the slot carries a segment, and it hides on the last step like the row's
518
+ // trailing one does.
519
+ it('continues the on-track connector past a step content slot', () => {
520
+ render(
521
+ <Stepper
522
+ activeStep={1}
523
+ orientation="vertical"
524
+ indicatorPosition="on-track">
525
+ <Step step={0} label="Account" data-testid="ot-plain" />
526
+ <Step step={1} label="Payment" data-testid="ot-content">
527
+ <button type="button">Pay now</button>
528
+ </Step>
529
+ </Stepper>,
530
+ );
531
+ expect(
532
+ screen
533
+ .getByTestId('ot-content')
534
+ .querySelector('[class*="otContentSegV"][class*="otSegHiddenIfLast"]'),
535
+ ).toBeInTheDocument();
536
+ // A step without content has no slot, so no extra segment.
537
+ expect(
538
+ screen.getByTestId('ot-plain').querySelector('[class*="otContentSegV"]'),
539
+ ).not.toBeInTheDocument();
540
+ });
541
+
542
+ describe('keyboard interaction', () => {
543
+ it('activates a step with Enter', async () => {
544
+ const user = userEvent.setup();
545
+ const handleClick = vi.fn();
546
+ render(
547
+ <Stepper activeStep={2} onStepClick={handleClick}>
548
+ <Step step={0} label="Step 1" />
549
+ <Step step={1} label="Step 2" />
550
+ <Step step={2} label="Step 3" />
551
+ </Stepper>,
552
+ );
553
+ await user.tab();
554
+ expect(
555
+ screen.getByRole('button', {name: 'Go to step 1: Step 1, completed'}),
556
+ ).toHaveFocus();
557
+ await user.keyboard('{Enter}');
558
+ expect(handleClick).toHaveBeenCalledWith(0);
559
+ });
560
+
561
+ it('activates a step with Space', async () => {
562
+ const user = userEvent.setup();
563
+ const handleClick = vi.fn();
564
+ render(
565
+ <Stepper activeStep={2} onStepClick={handleClick}>
566
+ <Step step={0} label="Step 1" />
567
+ <Step step={1} label="Step 2" />
568
+ <Step step={2} label="Step 3" />
569
+ </Stepper>,
570
+ );
571
+ await user.tab();
572
+ await user.keyboard(' ');
573
+ expect(handleClick).toHaveBeenCalledWith(0);
574
+ });
575
+
576
+ it('tabs through steps in document order, skipping disabled ones', async () => {
577
+ const user = userEvent.setup();
578
+ render(
579
+ <Stepper activeStep={3} onStepClick={() => {}}>
580
+ <Step step={0} label="One" />
581
+ <Step step={1} label="Two" isDisabled />
582
+ <Step step={2} label="Three" />
583
+ </Stepper>,
584
+ );
585
+ await user.tab();
586
+ expect(
587
+ screen.getByRole('button', {name: 'Go to step 1: One, completed'}),
588
+ ).toHaveFocus();
589
+ // The disabled step renders no button, so Tab lands on step 3 next.
590
+ await user.tab();
591
+ expect(
592
+ screen.getByRole('button', {name: 'Go to step 3: Three, completed'}),
593
+ ).toHaveFocus();
594
+ });
595
+
596
+ it('supports keyboard activation in the on-track layout', async () => {
597
+ const user = userEvent.setup();
598
+ const handleClick = vi.fn();
599
+ render(
600
+ <Stepper
601
+ activeStep={2}
602
+ indicatorPosition="on-track"
603
+ onStepClick={handleClick}>
604
+ <Step step={0} label="Cart" />
605
+ <Step step={1} label="Shipping" />
606
+ <Step step={2} label="Payment" />
607
+ </Stepper>,
608
+ );
609
+ await user.tab();
610
+ await user.keyboard('{Enter}');
611
+ expect(handleClick).toHaveBeenCalledWith(0);
612
+ });
613
+ });
614
+
615
+ describe('fragment-grouped steps', () => {
616
+ const onTrackSteps = (
617
+ <>
618
+ <Step step={0} label="Cart" />
619
+ <Step step={1} label="Shipping" />
620
+ <Step step={2} label="Payment" />
621
+ </>
622
+ );
623
+
624
+ it('renders on-track steps identically whether they are flat or grouped in a fragment', () => {
625
+ const flat = render(
626
+ <Stepper activeStep={1} indicatorPosition="on-track">
627
+ <Step step={0} label="Cart" />
628
+ <Step step={1} label="Shipping" />
629
+ <Step step={2} label="Payment" />
630
+ </Stepper>,
631
+ );
632
+ const flatHtml = flat.container.innerHTML;
633
+ flat.unmount();
634
+
635
+ const grouped = render(
636
+ <Stepper activeStep={1} indicatorPosition="on-track">
637
+ {onTrackSteps}
638
+ </Stepper>,
639
+ );
640
+ expect(grouped.container.innerHTML).toBe(flatHtml);
641
+ });
642
+
643
+ // The connector's end segments are hidden by CSS keyed to the step's own
644
+ // <li> position, which jsdom can't evaluate — assert the wiring instead:
645
+ // every step carries the same hide-if-first/hide-if-last classes, so no
646
+ // step is singled out by counting children.
647
+ it('gives every grouped step the same structural connector classes', () => {
648
+ render(
649
+ <Stepper activeStep={1} indicatorPosition="on-track">
650
+ {onTrackSteps}
651
+ </Stepper>,
652
+ );
653
+ const items = screen.getAllByRole('listitem');
654
+ expect(items).toHaveLength(3);
655
+ for (const item of items) {
656
+ expect(
657
+ item.querySelector('[class*="otSegHiddenIfFirst"]'),
658
+ ).toBeInTheDocument();
659
+ expect(
660
+ item.querySelector('[class*="otSegHiddenIfLast"]'),
661
+ ).toBeInTheDocument();
662
+ }
663
+ });
664
+
665
+ it('keeps every grouped step keyboard-activatable', async () => {
666
+ const user = userEvent.setup();
667
+ const handleClick = vi.fn();
668
+ render(
669
+ <Stepper
670
+ activeStep={2}
671
+ indicatorPosition="on-track"
672
+ onStepClick={handleClick}>
673
+ {onTrackSteps}
674
+ </Stepper>,
675
+ );
676
+ screen
677
+ .getByRole('button', {name: 'Go to step 2: Shipping, completed'})
678
+ .focus();
679
+ await user.keyboard('{Enter}');
680
+ expect(handleClick).toHaveBeenCalledWith(1);
681
+ });
682
+ });
683
+
684
+ // The connector fill animates a ::before scaled along the track axis, which
685
+ // jsdom neither renders nor times — so assert the wiring the animation hangs
686
+ // off: every connector carries the shared track style (the element that owns
687
+ // the fill layer and its transition), and the fill/empty pair it gets is the
688
+ // one for its axis, since the wrong axis would scale the line's thickness
689
+ // away instead of its length.
690
+ describe('connector fill', () => {
691
+ const barEl = (testId: string) =>
692
+ screen
693
+ .getByTestId(testId)
694
+ .querySelector('[class*="connectorTrack"]') as HTMLElement;
695
+
696
+ it('scales the separated bar along the inline axis when horizontal', () => {
697
+ render(
698
+ <Stepper activeStep={1} orientation="horizontal">
699
+ <Step step={0} label="A" data-testid="a" />
700
+ <Step step={1} label="B" data-testid="b" />
701
+ <Step step={2} label="C" data-testid="c" />
702
+ </Stepper>,
703
+ );
704
+ // Reached steps are filled, upcoming ones empty — both on the H pair.
705
+ expect(barEl('a').className).toContain('connectorFillH');
706
+ expect(barEl('b').className).toContain('connectorFillH');
707
+ expect(barEl('c').className).toContain('connectorEmptyH');
708
+ expect(barEl('c').className).not.toContain('connectorEmptyV');
709
+ });
710
+
711
+ it('scales the separated bar along the block axis when vertical', () => {
712
+ render(
713
+ <Stepper activeStep={1} orientation="vertical">
714
+ <Step step={0} label="A" data-testid="a" />
715
+ <Step step={1} label="B" data-testid="b" />
716
+ <Step step={2} label="C" data-testid="c" />
717
+ </Stepper>,
718
+ );
719
+ expect(barEl('a').className).toContain('connectorFillV');
720
+ expect(barEl('c').className).toContain('connectorEmptyV');
721
+ expect(barEl('c').className).not.toContain('connectorEmptyH');
722
+ });
723
+
724
+ it('gives every on-track segment the track style and its axis pair', () => {
725
+ render(
726
+ <Stepper activeStep={1} indicatorPosition="on-track">
727
+ <Step step={0} label="A" data-testid="a" />
728
+ <Step step={1} label="B" data-testid="b" />
729
+ <Step step={2} label="C" data-testid="c" />
730
+ </Stepper>,
731
+ );
732
+ // A step draws the segments flanking its own indicator, so each carries
733
+ // the track style; none may fall back to the vertical axis pair here.
734
+ for (const id of ['a', 'b', 'c']) {
735
+ const segs = Array.from(
736
+ screen.getByTestId(id).querySelectorAll('[class*="connectorTrack"]'),
737
+ );
738
+ expect(segs).toHaveLength(2);
739
+ for (const seg of segs) {
740
+ expect(seg.className).toMatch(/connector(Fill|Empty)H/);
741
+ expect(seg.className).not.toMatch(/connector(Fill|Empty)V/);
742
+ }
743
+ }
744
+ // Progress splits at the current step: the segment arriving at it is
745
+ // filled, the one leaving it is not.
746
+ const current = Array.from(
747
+ screen.getByTestId('b').querySelectorAll('[class*="connectorTrack"]'),
748
+ );
749
+ expect(current[0].className).toContain('connectorFillH');
750
+ expect(current[1].className).toContain('connectorEmptyH');
751
+ });
752
+ });
753
+
754
+ // One change animates the connector: advancing a single step. jsdom runs no
755
+ // transitions, so what is asserted here is the schedule one would run on.
756
+ // Every segment's slice is expressed in one unit — the node-to-node span —
757
+ // so a slice reads as `{start, length}` in spans, a segment that lands at
758
+ // once reads as a pair of zeros, and a span stitched from several segments
759
+ // is contiguous when its slices abut in track order.
760
+ describe('connector fill motion', () => {
761
+ const separated = (activeStep: number) => (
762
+ <Stepper activeStep={activeStep} orientation="horizontal">
763
+ <Step step={0} label="A" data-testid="a" />
764
+ <Step step={1} label="B" data-testid="b" />
765
+ <Step step={2} label="C" data-testid="c" />
766
+ <Step step={3} label="D" data-testid="d" />
767
+ <Step step={4} label="E" data-testid="e" />
768
+ </Stepper>
769
+ );
770
+
771
+ // StyleX routes dynamic values through hashed custom properties, whose
772
+ // names are not readable by hand. Recover the mapping from the one change
773
+ // that animates — the only one where the two carry different values. The
774
+ // probe mounts alongside whatever the calling test rendered, so it needs a
775
+ // test id of its own to be found.
776
+ const timingVarNames = (() => {
777
+ let cached: {duration: string; delay: string} | null = null;
778
+ return () => {
779
+ if (cached) {
780
+ return cached;
781
+ }
782
+ const steps = (
783
+ <>
784
+ <Step step={0} label="A" />
785
+ <Step step={1} label="B" data-testid="timing-probe" />
786
+ </>
787
+ );
788
+ const probe = render(<Stepper activeStep={0}>{steps}</Stepper>);
789
+ probe.rerender(<Stepper activeStep={1}>{steps}</Stepper>);
790
+ const el = probe
791
+ .getByTestId('timing-probe')
792
+ .querySelector('[class*="connectorTiming"]') as HTMLElement;
793
+ const found: Record<string, string> = {};
794
+ for (const name of Array.from(el.style)) {
795
+ const value = el.style.getPropertyValue(name).trim();
796
+ if (value === 'var(--duration-medium)') {
797
+ found.duration = name;
798
+ } else if (value === '0s') {
799
+ found.delay = name;
800
+ }
801
+ }
802
+ probe.unmount();
803
+ cached = found as {duration: string; delay: string};
804
+ return cached;
805
+ };
806
+ })();
807
+
808
+ /**
809
+ * A slice as a multiple of one span: `0s` is none of a span, a bare span
810
+ * expression is all of one, and `calc(<span> * n)` is n of them.
811
+ */
812
+ const spans = (value: string): number => {
813
+ if (value === '0s') {
814
+ return 0;
815
+ }
816
+ const scaled = value.match(/\* ([\d.]+)\)$/);
817
+ return scaled ? Number(scaled[1]) : 1;
818
+ };
819
+
820
+ /** Every connector in track order, as `{start, length}` in spans. */
821
+ const schedule = (el: HTMLElement) =>
822
+ Array.from(
823
+ el.querySelectorAll<HTMLElement>('[class*="connectorTiming"]'),
824
+ ).map(seg => {
825
+ const names = timingVarNames();
826
+ return {
827
+ start: spans(seg.style.getPropertyValue(names.delay).trim()),
828
+ length: spans(seg.style.getPropertyValue(names.duration).trim()),
829
+ };
830
+ });
831
+
832
+ /** Nothing in this subtree moves over time. */
833
+ const isInstant = (el: HTMLElement) =>
834
+ schedule(el).every(slice => slice.start === 0 && slice.length === 0);
835
+
836
+ /** The span expression itself, which carries the fill's duration. */
837
+ const spanExpression = (el: HTMLElement) => {
838
+ const raw = (
839
+ el.querySelector('[class*="connectorTiming"]') as HTMLElement
840
+ ).style
841
+ .getPropertyValue(timingVarNames().duration)
842
+ .trim();
843
+ return raw.replace(/^calc\((.*) \* [\d.]+\)$/, '$1');
844
+ };
845
+
846
+ /**
847
+ * The timing functions the fills in this subtree run on. Unlike the
848
+ * duration and the delay this is a static style, so it lives in the
849
+ * injected stylesheet under one of each segment's atomic classes rather
850
+ * than in an inline custom property.
851
+ */
852
+ const fillEasings = (el: HTMLElement) => {
853
+ const found = new Set<string>();
854
+ for (const seg of Array.from(
855
+ el.querySelectorAll<HTMLElement>('[class*="connectorTrack"]'),
856
+ )) {
857
+ const classes = new Set(seg.className.split(/\s+/));
858
+ for (const sheet of Array.from(document.styleSheets)) {
859
+ for (const rule of Array.from(sheet.cssRules)) {
860
+ if (!('selectorText' in rule)) {
861
+ continue;
862
+ }
863
+ const {selectorText, style} = rule as CSSStyleRule;
864
+ const owner = selectorText.match(/^\.([\w-]+)/);
865
+ if (
866
+ owner == null ||
867
+ !classes.has(owner[1]) ||
868
+ !selectorText.endsWith('::before')
869
+ ) {
870
+ continue;
871
+ }
872
+ const value = style
873
+ .getPropertyValue('transition-timing-function')
874
+ .trim();
875
+ if (value !== '') {
876
+ found.add(value);
877
+ }
878
+ }
879
+ }
880
+ }
881
+ return [...found];
882
+ };
883
+
884
+ it('animates the one span a single forward step crosses', () => {
885
+ const {rerender, getByTestId} = render(separated(0));
886
+ rerender(separated(1));
887
+ // The bar arriving at the new step fills across the whole span.
888
+ expect(schedule(getByTestId('b'))).toEqual([{start: 0, length: 1}]);
889
+ // Every other bar is untouched, so it is handed no timing that a later
890
+ // change could inherit as a stale delay.
891
+ for (const id of ['a', 'c', 'd', 'e']) {
892
+ expect(isInstant(getByTestId(id))).toBe(true);
893
+ }
894
+ });
895
+
896
+ it('fills that span over the medium duration', () => {
897
+ // A fill crossing a whole segment is a spatial change, not a
898
+ // micro-interaction, so it sits above the fast band.
899
+ const {rerender, getByTestId} = render(separated(0));
900
+ rerender(separated(1));
901
+ expect(spanExpression(getByTestId('b'))).toBe('var(--duration-medium)');
902
+ });
903
+
904
+ it('fills linearly so a stitched span reads as one front', () => {
905
+ // An on-track span is drawn by two segments, three where a content slot
906
+ // splits it. A curve applied per segment restarts its deceleration at
907
+ // every seam, and the seam becomes the most visible part of the result.
908
+ const {container} = render(separated(0));
909
+ expect(fillEasings(container.firstElementChild as HTMLElement)).toEqual([
910
+ 'linear',
911
+ ]);
912
+ });
913
+
914
+ it('lands a forward jump of more than one step at once', () => {
915
+ // A jump is a navigation rather than a progression: sweeping a front
916
+ // across the crossed segments makes the user sit out a journey they
917
+ // asked to skip.
918
+ const {rerender, getByTestId} = render(separated(0));
919
+ rerender(separated(3));
920
+ for (const id of ['a', 'b', 'c', 'd', 'e']) {
921
+ expect(isInstant(getByTestId(id))).toBe(true);
922
+ }
923
+ });
924
+
925
+ it('lands a backward change at once, one step or several', () => {
926
+ // Retracting is the same arithmetic as filling, but it ends on a
927
+ // shrinking stub of accent rather than a nearly-full bar, and a remnant
928
+ // still on the track reads as unfinished however briefly it is there.
929
+ for (const to of [2, 0]) {
930
+ const view = render(separated(3));
931
+ view.rerender(separated(to));
932
+ for (const id of ['a', 'b', 'c', 'd', 'e']) {
933
+ expect(isInstant(view.getByTestId(id))).toBe(true);
934
+ }
935
+ view.unmount();
936
+ }
937
+ });
938
+
939
+ it('leaves every segment instant on mount', () => {
940
+ // A stepper opening mid-flow has no previous step to have travelled
941
+ // from, so its completed segments must paint filled at once rather than
942
+ // replaying the history that would have produced them.
943
+ const {getByTestId} = render(separated(3));
944
+ for (const id of ['a', 'b', 'c', 'd', 'e']) {
945
+ expect(isInstant(getByTestId(id))).toBe(true);
946
+ }
947
+ });
948
+
949
+ const onTrack = (activeStep: number) => (
950
+ <Stepper
951
+ activeStep={activeStep}
952
+ orientation="horizontal"
953
+ indicatorPosition="on-track">
954
+ <Step step={0} label="A" data-testid="a" />
955
+ <Step step={1} label="B" data-testid="b" />
956
+ <Step step={2} label="C" data-testid="c" />
957
+ </Stepper>
958
+ );
959
+
960
+ it('runs the leaving half of an on-track span before the arriving half', () => {
961
+ const {rerender, getByTestId} = render(onTrack(0));
962
+ rerender(onTrack(1));
963
+ // The span is drawn by two steps. Left alone both halves flip together
964
+ // and the gap between two nodes reads as two dashes converging on the
965
+ // space between them; split, the one leaving the near node runs first
966
+ // and the pair reads as one stretch of track filling.
967
+ const [aCap, aRail] = schedule(getByTestId('a'));
968
+ const [bCap, bRail] = schedule(getByTestId('b'));
969
+ expect(aRail).toEqual({start: 0, length: 0.5});
970
+ expect(bCap).toEqual({start: 0.5, length: 0.5});
971
+ // The segments either side of the span are not part of it.
972
+ expect(aCap).toEqual({start: 0, length: 0});
973
+ expect(bRail).toEqual({start: 0, length: 0});
974
+ expect(isInstant(getByTestId('c'))).toBe(true);
975
+ });
976
+
977
+ const verticalWithContent = (activeStep: number) => (
978
+ <Stepper
979
+ activeStep={activeStep}
980
+ orientation="vertical"
981
+ indicatorPosition="on-track">
982
+ <Step step={0} label="A" data-testid="a" />
983
+ <Step step={1} label="B" data-testid="b">
984
+ <button type="button">Do it</button>
985
+ </Step>
986
+ <Step step={2} label="C" data-testid="c" />
987
+ </Stepper>
988
+ );
989
+
990
+ it('threads a content slot segment into its span between rail and cap', () => {
991
+ const {rerender, getByTestId} = render(verticalWithContent(1));
992
+ rerender(verticalWithContent(2));
993
+ // A vertical step with content draws a third segment down the side of
994
+ // the slot, so the span leaving it is stitched from three pieces and all
995
+ // three have to fall in track order. The rail and cap are unequal
996
+ // lengths, so the slices are unequal too.
997
+ const [bCap, bRail, bContent] = schedule(getByTestId('b'));
998
+ const [cCap] = schedule(getByTestId('c'));
999
+ expect(bRail).toEqual({start: 0, length: 0.175});
1000
+ expect(bContent).toEqual({start: 0.175, length: 0.525});
1001
+ expect(cCap).toEqual({start: 0.7, length: 0.3});
1002
+ // The span arriving at this step belongs to the previous change.
1003
+ expect(bCap).toEqual({start: 0, length: 0});
1004
+ expect(isInstant(getByTestId('a'))).toBe(true);
1005
+ });
1006
+
1007
+ it('tracks the previous step correctly under StrictMode double rendering', () => {
1008
+ // The previous step is derived during render from state, so StrictMode
1009
+ // invoking the render twice must queue the same successor both times
1010
+ // rather than losing a step or advancing two — which would turn a single
1011
+ // forward step into a two-step jump and stop it animating.
1012
+ const {rerender, getByTestId} = render(
1013
+ <StrictMode>{separated(0)}</StrictMode>,
1014
+ );
1015
+ rerender(<StrictMode>{separated(1)}</StrictMode>);
1016
+ expect(schedule(getByTestId('b'))).toEqual([{start: 0, length: 1}]);
1017
+ // A second step measures from step 1, not from the original mount, so
1018
+ // the next span animates and the one behind it stops.
1019
+ rerender(<StrictMode>{separated(2)}</StrictMode>);
1020
+ expect(schedule(getByTestId('c'))).toEqual([{start: 0, length: 1}]);
1021
+ expect(isInstant(getByTestId('b'))).toBe(true);
1022
+ });
1023
+ });
1024
+ });