@astryxdesign/core 0.4.7 → 0.5.0-canary.32a62fd

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 (554) hide show
  1. package/CHANGELOG.md +161 -1
  2. package/dist/AppShell/AppShell.d.ts.map +1 -1
  3. package/dist/AppShell/AppShell.js +3 -2
  4. package/dist/AspectRatio/AspectRatio.d.ts +24 -0
  5. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  6. package/dist/AspectRatio/AspectRatio.js +23 -4
  7. package/dist/Avatar/Avatar.d.ts +25 -1
  8. package/dist/Avatar/Avatar.d.ts.map +1 -1
  9. package/dist/Avatar/Avatar.js +58 -19
  10. package/dist/Avatar/index.d.ts +2 -2
  11. package/dist/Avatar/index.d.ts.map +1 -1
  12. package/dist/Avatar/index.js +1 -1
  13. package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
  14. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  15. package/dist/AvatarGroup/AvatarGroup.js +8 -4
  16. package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
  17. package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
  18. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  19. package/dist/AvatarGroup/AvatarGroupOverflow.js +10 -6
  20. package/dist/Banner/Banner.d.ts +40 -15
  21. package/dist/Banner/Banner.d.ts.map +1 -1
  22. package/dist/Banner/Banner.js +51 -18
  23. package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
  24. package/dist/BottomSheet/BottomSheet.js +17 -4
  25. package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
  26. package/dist/BottomSheet/BottomSheetSwitcher.js +3 -2
  27. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  28. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -10
  29. package/dist/Button/Button.d.ts.map +1 -1
  30. package/dist/Button/Button.js +5 -4
  31. package/dist/ButtonGroup/ButtonGroup.d.ts +5 -1
  32. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  33. package/dist/ButtonGroup/ButtonGroup.js +26 -7
  34. package/dist/Calendar/Calendar.d.ts +3 -1
  35. package/dist/Calendar/Calendar.d.ts.map +1 -1
  36. package/dist/Calendar/Calendar.js +13 -14
  37. package/dist/Calendar/getInitialFocusDate.d.ts +46 -0
  38. package/dist/Calendar/getInitialFocusDate.d.ts.map +1 -0
  39. package/dist/Calendar/getInitialFocusDate.js +62 -0
  40. package/dist/Carousel/Carousel.d.ts.map +1 -1
  41. package/dist/Carousel/Carousel.js +3 -3
  42. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  43. package/dist/Chat/ChatComposerInput.js +2 -3
  44. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  45. package/dist/Chat/ChatLayout.js +3 -3
  46. package/dist/Chat/ChatMessageList.d.ts +22 -3
  47. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  48. package/dist/Chat/ChatMessageList.js +6 -3
  49. package/dist/Chat/ChatTokenizedText.d.ts +2 -0
  50. package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
  51. package/dist/Chat/ChatTokenizedText.js +11 -6
  52. package/dist/Chat/useChatComposerTokens.js +1 -1
  53. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  54. package/dist/CheckboxInput/CheckboxInput.js +10 -3
  55. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  56. package/dist/ClickableCard/ClickableCard.js +3 -3
  57. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  58. package/dist/CodeBlock/CodeBlock.js +15 -4
  59. package/dist/CodeBlock/highlightRanges.js +1 -1
  60. package/dist/CodeBlock/highlightStyles.js +13 -13
  61. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  62. package/dist/CommandPalette/CommandPaletteInput.js +3 -2
  63. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  64. package/dist/CommandPalette/CommandPaletteItem.js +3 -2
  65. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  66. package/dist/ContextMenu/ContextMenu.js +4 -3
  67. package/dist/DateInput/DateInput.d.ts +43 -0
  68. package/dist/DateInput/DateInput.d.ts.map +1 -1
  69. package/dist/DateInput/DateInput.js +22 -2
  70. package/dist/DateInput/NativeDateField.d.ts +10 -0
  71. package/dist/DateInput/NativeDateField.d.ts.map +1 -0
  72. package/dist/DateInput/NativeDateField.js +477 -0
  73. package/dist/DateInput/TouchDateField.d.ts.map +1 -1
  74. package/dist/DateInput/TouchDateField.js +38 -4
  75. package/dist/DateInput/index.d.ts +1 -1
  76. package/dist/DateInput/index.d.ts.map +1 -1
  77. package/dist/DateTimeInput/DateTimeInput.d.ts +21 -1
  78. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  79. package/dist/DateTimeInput/DateTimeInput.js +406 -12
  80. package/dist/DateTimeInput/index.d.ts +1 -1
  81. package/dist/DateTimeInput/index.d.ts.map +1 -1
  82. package/dist/Dialog/Dialog.d.ts +7 -1
  83. package/dist/Dialog/Dialog.d.ts.map +1 -1
  84. package/dist/Dialog/Dialog.js +89 -58
  85. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  86. package/dist/DropdownMenu/DropdownMenuSubMenu.js +6 -5
  87. package/dist/Field/FieldLabel.d.ts.map +1 -1
  88. package/dist/Field/FieldLabel.js +9 -1
  89. package/dist/FileInput/FileInput.d.ts.map +1 -1
  90. package/dist/FileInput/FileInput.js +3 -2
  91. package/dist/Heading/Heading.d.ts.map +1 -1
  92. package/dist/Heading/Heading.js +6 -2
  93. package/dist/HoverCard/HoverCard.d.ts +6 -0
  94. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  95. package/dist/HoverCard/HoverCard.js +52 -3
  96. package/dist/HoverCard/useHoverCard.d.ts +16 -2
  97. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  98. package/dist/HoverCard/useHoverCard.js +74 -26
  99. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
  100. package/dist/Indicator/CheckboxIndicator.js +6 -2
  101. package/dist/Item/Item.d.ts.map +1 -1
  102. package/dist/Item/Item.js +4 -2
  103. package/dist/Kbd/Kbd.d.ts.map +1 -1
  104. package/dist/Kbd/Kbd.js +2 -19
  105. package/dist/Layer/LayerDepthContext.d.ts +52 -0
  106. package/dist/Layer/LayerDepthContext.d.ts.map +1 -0
  107. package/dist/Layer/LayerDepthContext.js +66 -0
  108. package/dist/Layer/index.d.ts +3 -0
  109. package/dist/Layer/index.d.ts.map +1 -1
  110. package/dist/Layer/index.js +4 -0
  111. package/dist/Layer/layerStack.d.ts +98 -0
  112. package/dist/Layer/layerStack.d.ts.map +1 -0
  113. package/dist/Layer/layerStack.js +306 -0
  114. package/dist/Layer/useLayerDismissal.d.ts +93 -0
  115. package/dist/Layer/useLayerDismissal.d.ts.map +1 -0
  116. package/dist/Layer/useLayerDismissal.js +91 -0
  117. package/dist/Lightbox/Lightbox.d.ts +1 -0
  118. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  119. package/dist/Lightbox/Lightbox.js +103 -81
  120. package/dist/Markdown/index.d.ts +1 -1
  121. package/dist/Markdown/index.d.ts.map +1 -1
  122. package/dist/Markdown/parser.d.ts +38 -1
  123. package/dist/Markdown/parser.d.ts.map +1 -1
  124. package/dist/Markdown/parser.js +177 -29
  125. package/dist/MobileNav/MobileNav.d.ts +6 -1
  126. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  127. package/dist/MobileNav/MobileNav.js +61 -36
  128. package/dist/MultiSelector/MultiSelector.d.ts +15 -1
  129. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  130. package/dist/MultiSelector/MultiSelector.js +17 -6
  131. package/dist/MultiSelector/index.d.ts +1 -1
  132. package/dist/MultiSelector/index.d.ts.map +1 -1
  133. package/dist/NavIcon/NavIcon.d.ts.map +1 -1
  134. package/dist/NavIcon/NavIcon.js +5 -1
  135. package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
  136. package/dist/NavMenu/NavHeadingMenu.js +3 -2
  137. package/dist/NumberInput/NumberInput.d.ts +1 -0
  138. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  139. package/dist/NumberInput/NumberInput.js +27 -37
  140. package/dist/NumberInput/numberParser.d.ts +43 -0
  141. package/dist/NumberInput/numberParser.d.ts.map +1 -0
  142. package/dist/NumberInput/numberParser.js +293 -0
  143. package/dist/Outline/Outline.d.ts.map +1 -1
  144. package/dist/Outline/Outline.js +3 -2
  145. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  146. package/dist/OverflowList/OverflowList.js +3 -2
  147. package/dist/Overlay/Overlay.d.ts.map +1 -1
  148. package/dist/Overlay/Overlay.js +3 -2
  149. package/dist/Popover/usePopover.d.ts.map +1 -1
  150. package/dist/Popover/usePopover.js +20 -17
  151. package/dist/PowerSearch/PowerSearch.d.ts +8 -2
  152. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  153. package/dist/PowerSearch/PowerSearch.js +19 -6
  154. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +3 -1
  155. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  156. package/dist/PowerSearch/PowerSearchEditPopover.js +28 -6
  157. package/dist/PowerSearch/PowerSearchValueEditor.d.ts +3 -1
  158. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  159. package/dist/PowerSearch/PowerSearchValueEditor.js +19 -9
  160. package/dist/PowerSearch/types.d.ts +2 -0
  161. package/dist/PowerSearch/types.d.ts.map +1 -1
  162. package/dist/PowerSearch/usePowerSearchSource.d.ts +6 -1
  163. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  164. package/dist/PowerSearch/usePowerSearchSource.js +14 -5
  165. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  166. package/dist/ProgressBar/ProgressBar.js +18 -5
  167. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  168. package/dist/Resizable/ResizeHandle.js +3 -2
  169. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  170. package/dist/SegmentedControl/SegmentedControl.js +3 -2
  171. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  172. package/dist/SelectableCard/SelectableCard.js +3 -3
  173. package/dist/Selector/Selector.d.ts.map +1 -1
  174. package/dist/Selector/Selector.js +5 -0
  175. package/dist/SideNav/SideNav.d.ts.map +1 -1
  176. package/dist/SideNav/SideNav.js +4 -3
  177. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  178. package/dist/SideNav/SideNavHeading.js +8 -7
  179. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  180. package/dist/SideNav/SideNavItem.js +4 -3
  181. package/dist/Slider/Slider.d.ts.map +1 -1
  182. package/dist/Slider/Slider.js +3 -3
  183. package/dist/Spinner/Spinner.d.ts +3 -3
  184. package/dist/Spinner/Spinner.d.ts.map +1 -1
  185. package/dist/Spinner/Spinner.js +130 -78
  186. package/dist/StatusDot/StatusDot.d.ts.map +1 -1
  187. package/dist/StatusDot/StatusDot.js +6 -1
  188. package/dist/Stepper/Step.d.ts +140 -0
  189. package/dist/Stepper/Step.d.ts.map +1 -0
  190. package/dist/Stepper/Step.js +1045 -0
  191. package/dist/Stepper/StepStatus.d.ts +24 -0
  192. package/dist/Stepper/StepStatus.d.ts.map +1 -0
  193. package/dist/Stepper/StepStatus.js +1 -0
  194. package/dist/Stepper/Stepper.d.ts +93 -0
  195. package/dist/Stepper/Stepper.d.ts.map +1 -0
  196. package/dist/Stepper/Stepper.js +184 -0
  197. package/dist/Stepper/StepperContext.d.ts +41 -0
  198. package/dist/Stepper/StepperContext.d.ts.map +1 -0
  199. package/dist/Stepper/StepperContext.js +34 -0
  200. package/dist/Stepper/index.d.ts +8 -0
  201. package/dist/Stepper/index.d.ts.map +1 -0
  202. package/dist/Stepper/index.js +7 -0
  203. package/dist/Stepper/stepper.stylex.d.ts +15 -0
  204. package/dist/Stepper/stepper.stylex.d.ts.map +1 -0
  205. package/dist/Stepper/stepper.stylex.js +20 -0
  206. package/dist/Switch/Switch.d.ts.map +1 -1
  207. package/dist/Switch/Switch.js +8 -3
  208. package/dist/TabList/Tab.d.ts +15 -2
  209. package/dist/TabList/Tab.d.ts.map +1 -1
  210. package/dist/TabList/Tab.js +32 -7
  211. package/dist/TabList/TabList.d.ts +46 -7
  212. package/dist/TabList/TabList.d.ts.map +1 -1
  213. package/dist/TabList/TabList.js +353 -23
  214. package/dist/TabList/TabListContext.d.ts +11 -1
  215. package/dist/TabList/TabListContext.d.ts.map +1 -1
  216. package/dist/TabList/TabListContext.js +11 -2
  217. package/dist/TabList/TabMenu.d.ts.map +1 -1
  218. package/dist/TabList/TabMenu.js +3 -2
  219. package/dist/TabList/index.d.ts +2 -2
  220. package/dist/TabList/index.d.ts.map +1 -1
  221. package/dist/Table/BaseTable.d.ts.map +1 -1
  222. package/dist/Table/BaseTable.js +10 -2
  223. package/dist/Table/Table.d.ts.map +1 -1
  224. package/dist/Table/Table.js +3 -6
  225. package/dist/Table/TableRow.d.ts +16 -5
  226. package/dist/Table/TableRow.d.ts.map +1 -1
  227. package/dist/Table/TableRow.js +16 -5
  228. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  229. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +20 -8
  230. package/dist/Table/plugins/pagination/useTablePagination.d.ts +3 -0
  231. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  232. package/dist/Table/plugins/pagination/useTablePagination.js +21 -4
  233. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  234. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +7 -2
  235. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -1
  236. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +10 -3
  237. package/dist/Table/plugins/selection/useTableSelection.d.ts +16 -0
  238. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  239. package/dist/Table/plugins/selection/useTableSelection.js +19 -5
  240. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  241. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
  242. package/dist/Table/types.d.ts +22 -4
  243. package/dist/Table/types.d.ts.map +1 -1
  244. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  245. package/dist/Table/useBaseTablePlugins.js +5 -0
  246. package/dist/Text/Text.d.ts.map +1 -1
  247. package/dist/Text/Text.js +6 -2
  248. package/dist/TextArea/TextArea.d.ts.map +1 -1
  249. package/dist/TextArea/TextArea.js +9 -3
  250. package/dist/TextInput/TextInput.d.ts.map +1 -1
  251. package/dist/TextInput/TextInput.js +3 -2
  252. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  253. package/dist/TimeInput/TimeInput.js +3 -2
  254. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  255. package/dist/Timestamp/Timestamp.js +5 -3
  256. package/dist/Token/TokenLink.d.ts.map +1 -1
  257. package/dist/Token/TokenLink.js +2 -2
  258. package/dist/Tokenizer/Tokenizer.d.ts +3 -1
  259. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  260. package/dist/Tokenizer/Tokenizer.js +2 -0
  261. package/dist/Tooltip/Tooltip.d.ts +5 -0
  262. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  263. package/dist/Tooltip/useTooltip.d.ts +5 -0
  264. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  265. package/dist/Tooltip/useTooltip.js +39 -24
  266. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  267. package/dist/TopNav/TopNavHeading.js +5 -4
  268. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  269. package/dist/TopNav/TopNavMegaMenu.js +3 -3
  270. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  271. package/dist/TopNav/TopNavMenu.js +4 -3
  272. package/dist/Typeahead/BaseTypeahead.d.ts +2 -0
  273. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  274. package/dist/Typeahead/BaseTypeahead.js +68 -29
  275. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  276. package/dist/Typeahead/Typeahead.js +3 -2
  277. package/dist/astryx.css +94 -7
  278. package/dist/hooks/index.d.ts +1 -0
  279. package/dist/hooks/index.d.ts.map +1 -1
  280. package/dist/hooks/index.js +1 -0
  281. package/dist/hooks/useFocusTrap.d.ts +7 -4
  282. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  283. package/dist/hooks/useFocusTrap.js +60 -95
  284. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  285. package/dist/hooks/useHotkeys.js +3 -18
  286. package/dist/hooks/useMergedRefs.d.ts +18 -0
  287. package/dist/hooks/useMergedRefs.d.ts.map +1 -0
  288. package/dist/hooks/useMergedRefs.js +25 -0
  289. package/dist/index.d.ts +1 -0
  290. package/dist/index.d.ts.map +1 -1
  291. package/dist/index.js +1 -0
  292. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  293. package/dist/theme/derivedVarRegistry.js +24 -4
  294. package/dist/theme/syntax/tokens.d.ts +1 -1
  295. package/dist/theme/syntax/tokens.d.ts.map +1 -1
  296. package/dist/theme/syntax/tokens.js +5 -2
  297. package/dist/utils/groupItems.d.ts +5 -1
  298. package/dist/utils/groupItems.d.ts.map +1 -1
  299. package/dist/utils/groupItems.js +9 -9
  300. package/dist/utils/index.d.ts +1 -1
  301. package/dist/utils/index.d.ts.map +1 -1
  302. package/dist/utils/isApplePlatform.d.ts +18 -0
  303. package/dist/utils/isApplePlatform.d.ts.map +1 -0
  304. package/dist/utils/isApplePlatform.js +37 -0
  305. package/dist/utils/sharedResizeObserver.d.ts.map +1 -1
  306. package/dist/utils/sharedResizeObserver.js +10 -1
  307. package/dist/utils/timeParser.d.ts +1 -1
  308. package/dist/utils/timeParser.d.ts.map +1 -1
  309. package/dist/utils/timeParser.js +26 -12
  310. package/locales/en.json +31 -7
  311. package/locales/pseudo.json +18 -0
  312. package/package.json +8 -3
  313. package/src/AppShell/AppShell.tsx +3 -2
  314. package/src/AspectRatio/AspectRatio.doc.mjs +6 -3
  315. package/src/AspectRatio/AspectRatio.test.tsx +57 -10
  316. package/src/AspectRatio/AspectRatio.tsx +40 -1
  317. package/src/Avatar/Avatar.doc.mjs +14 -3
  318. package/src/Avatar/Avatar.test.tsx +97 -0
  319. package/src/Avatar/Avatar.tsx +125 -52
  320. package/src/Avatar/index.ts +2 -2
  321. package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
  322. package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
  323. package/src/AvatarGroup/AvatarGroup.tsx +15 -6
  324. package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
  325. package/src/AvatarGroup/AvatarGroupOverflow.tsx +10 -4
  326. package/src/Banner/Banner.doc.mjs +13 -11
  327. package/src/Banner/Banner.test.tsx +102 -15
  328. package/src/Banner/Banner.tsx +72 -25
  329. package/src/BottomSheet/BottomSheet.test.tsx +123 -0
  330. package/src/BottomSheet/BottomSheet.tsx +17 -4
  331. package/src/BottomSheet/BottomSheetSwitcher.tsx +3 -2
  332. package/src/Breadcrumbs/BreadcrumbItem.tsx +9 -5
  333. package/src/Button/Button.doc.mjs +22 -0
  334. package/src/Button/Button.test.tsx +13 -0
  335. package/src/Button/Button.tsx +5 -4
  336. package/src/ButtonGroup/ButtonGroup.doc.mjs +10 -1
  337. package/src/ButtonGroup/ButtonGroup.test.tsx +391 -1
  338. package/src/ButtonGroup/ButtonGroup.tsx +23 -5
  339. package/src/Calendar/Calendar.doc.mjs +4 -3
  340. package/src/Calendar/Calendar.test.tsx +52 -0
  341. package/src/Calendar/Calendar.tsx +18 -15
  342. package/src/Calendar/getInitialFocusDate.test.ts +94 -0
  343. package/src/Calendar/getInitialFocusDate.ts +93 -0
  344. package/src/Carousel/Carousel.tsx +3 -2
  345. package/src/Chat/ChatComposerInput.tsx +5 -1
  346. package/src/Chat/ChatLayout.tsx +3 -2
  347. package/src/Chat/ChatMessageList.doc.mjs +9 -1
  348. package/src/Chat/ChatMessageList.test.tsx +46 -0
  349. package/src/Chat/ChatMessageList.tsx +28 -4
  350. package/src/Chat/ChatTokenizedText.tsx +17 -10
  351. package/src/Chat/useChatComposerTokens.ts +1 -1
  352. package/src/CheckboxInput/CheckboxInput.doc.mjs +2 -0
  353. package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
  354. package/src/CheckboxInput/CheckboxInput.tsx +8 -2
  355. package/src/ClickableCard/ClickableCard.tsx +3 -2
  356. package/src/CodeBlock/CodeBlock.doc.mjs +16 -4
  357. package/src/CodeBlock/CodeBlock.test.tsx +37 -0
  358. package/src/CodeBlock/CodeBlock.tsx +20 -4
  359. package/src/CodeBlock/highlightRanges.ts +1 -1
  360. package/src/CodeBlock/highlightStyles.ts +13 -13
  361. package/src/CommandPalette/CommandPaletteInput.tsx +3 -2
  362. package/src/CommandPalette/CommandPaletteItem.tsx +3 -2
  363. package/src/ContextMenu/ContextMenu.doc.mjs +5 -0
  364. package/src/ContextMenu/ContextMenu.tsx +4 -3
  365. package/src/DateInput/DateInput.doc.mjs +16 -0
  366. package/src/DateInput/DateInput.tsx +55 -2
  367. package/src/DateInput/DateInputTouch.test.tsx +68 -9
  368. package/src/DateInput/NativeDateField.test.tsx +565 -0
  369. package/src/DateInput/NativeDateField.tsx +623 -0
  370. package/src/DateInput/TouchDateField.tsx +38 -4
  371. package/src/DateInput/index.ts +1 -0
  372. package/src/DateTimeInput/DateTimeInput.doc.mjs +18 -0
  373. package/src/DateTimeInput/DateTimeInput.test.tsx +1088 -0
  374. package/src/DateTimeInput/DateTimeInput.tsx +556 -24
  375. package/src/DateTimeInput/index.ts +1 -0
  376. package/src/Dialog/Dialog.doc.mjs +8 -3
  377. package/src/Dialog/Dialog.test.tsx +261 -1
  378. package/src/Dialog/Dialog.tsx +109 -58
  379. package/src/DropdownMenu/DropdownMenu.doc.mjs +6 -0
  380. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +8 -5
  381. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +8 -11
  382. package/src/Field/Field.doc.mjs +13 -2
  383. package/src/Field/FieldLabel.test.tsx +29 -0
  384. package/src/Field/FieldLabel.tsx +7 -0
  385. package/src/FileInput/FileInput.tsx +3 -2
  386. package/src/Heading/Heading.test.tsx +23 -1
  387. package/src/Heading/Heading.tsx +6 -2
  388. package/src/HoverCard/HoverCard.doc.mjs +13 -2
  389. package/src/HoverCard/HoverCard.test.tsx +101 -4
  390. package/src/HoverCard/HoverCard.tsx +71 -3
  391. package/src/HoverCard/useHoverCard.tsx +101 -33
  392. package/src/Indicator/CheckboxIndicator.tsx +14 -8
  393. package/src/Indicator/Indicator.doc.mjs +2 -0
  394. package/src/Item/Item.tsx +5 -4
  395. package/src/Kbd/Kbd.tsx +2 -19
  396. package/src/Layer/LayerDepthContext.tsx +62 -0
  397. package/src/Layer/index.ts +9 -0
  398. package/src/Layer/layerDismissalFamilies.test.tsx +359 -0
  399. package/src/Layer/layerDismissalInvariants.test.tsx +417 -0
  400. package/src/Layer/layerStack.ts +362 -0
  401. package/src/Layer/useLayerDismissal.test.tsx +469 -0
  402. package/src/Layer/useLayerDismissal.ts +173 -0
  403. package/src/Layout/Layout.doc.mjs +2 -2
  404. package/src/Lightbox/Lightbox.doc.mjs +12 -0
  405. package/src/Lightbox/Lightbox.tsx +124 -102
  406. package/src/Link/Link.doc.mjs +39 -0
  407. package/src/Markdown/Markdown.doc.mjs +5 -0
  408. package/src/Markdown/incremental.test.ts +16 -2
  409. package/src/Markdown/index.ts +1 -0
  410. package/src/Markdown/parser.perf.test.ts +96 -1
  411. package/src/Markdown/parser.test.ts +145 -2
  412. package/src/Markdown/parser.ts +244 -29
  413. package/src/MobileNav/MobileNav.tsx +62 -36
  414. package/src/MoreMenu/MoreMenu.doc.mjs +7 -1
  415. package/src/MultiSelector/MultiSelector.doc.mjs +27 -0
  416. package/src/MultiSelector/MultiSelector.test.tsx +106 -0
  417. package/src/MultiSelector/MultiSelector.tsx +50 -6
  418. package/src/MultiSelector/index.ts +1 -0
  419. package/src/NavIcon/NavIcon.doc.mjs +8 -2
  420. package/src/NavIcon/NavIcon.test.tsx +9 -0
  421. package/src/NavIcon/NavIcon.tsx +5 -1
  422. package/src/NavMenu/NavHeadingMenu.tsx +3 -2
  423. package/src/NumberInput/NumberInput.doc.mjs +20 -0
  424. package/src/NumberInput/NumberInput.tsx +28 -29
  425. package/src/NumberInput/numberParser.test.ts +137 -0
  426. package/src/NumberInput/numberParser.ts +346 -0
  427. package/src/Outline/Outline.tsx +3 -2
  428. package/src/OverflowList/OverflowList.tsx +3 -2
  429. package/src/Overlay/Overlay.tsx +3 -2
  430. package/src/Popover/usePopover.tsx +31 -28
  431. package/src/PowerSearch/PowerSearch.doc.mjs +160 -28
  432. package/src/PowerSearch/PowerSearch.test.tsx +240 -1
  433. package/src/PowerSearch/PowerSearch.tsx +34 -5
  434. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +201 -0
  435. package/src/PowerSearch/PowerSearchEditPopover.tsx +29 -2
  436. package/src/PowerSearch/PowerSearchValueEditor.test.tsx +47 -1
  437. package/src/PowerSearch/PowerSearchValueEditor.tsx +15 -0
  438. package/src/PowerSearch/types.ts +2 -0
  439. package/src/PowerSearch/usePowerSearchSource.test.ts +82 -2
  440. package/src/PowerSearch/usePowerSearchSource.ts +13 -3
  441. package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
  442. package/src/ProgressBar/ProgressBar.test.tsx +24 -0
  443. package/src/ProgressBar/ProgressBar.tsx +28 -8
  444. package/src/Resizable/ResizeHandle.tsx +3 -2
  445. package/src/SegmentedControl/SegmentedControl.tsx +3 -2
  446. package/src/SelectableCard/SelectableCard.tsx +3 -2
  447. package/src/Selector/Selector.doc.mjs +12 -1
  448. package/src/Selector/Selector.test.tsx +45 -1
  449. package/src/Selector/Selector.tsx +11 -1
  450. package/src/SideNav/SideNav.doc.mjs +6 -6
  451. package/src/SideNav/SideNav.tsx +4 -2
  452. package/src/SideNav/SideNavHeading.tsx +12 -12
  453. package/src/SideNav/SideNavItem.tsx +4 -2
  454. package/src/Slider/Slider.tsx +3 -2
  455. package/src/Spinner/Spinner.test.tsx +147 -1
  456. package/src/Spinner/Spinner.tsx +120 -101
  457. package/src/StatusDot/StatusDot.doc.mjs +8 -2
  458. package/src/StatusDot/StatusDot.test.tsx +9 -0
  459. package/src/StatusDot/StatusDot.tsx +7 -1
  460. package/src/Stepper/Step.doc.mjs +98 -0
  461. package/src/Stepper/Step.tsx +1638 -0
  462. package/src/Stepper/StepStatus.ts +26 -0
  463. package/src/Stepper/Stepper.doc.mjs +370 -0
  464. package/src/Stepper/Stepper.test.tsx +1024 -0
  465. package/src/Stepper/Stepper.tsx +258 -0
  466. package/src/Stepper/StepperContext.ts +71 -0
  467. package/src/Stepper/index.ts +18 -0
  468. package/src/Stepper/stepper.stylex.ts +19 -0
  469. package/src/Switch/Switch.doc.mjs +2 -0
  470. package/src/Switch/Switch.test.tsx +10 -0
  471. package/src/Switch/Switch.tsx +6 -2
  472. package/src/TabList/Tab.doc.mjs +13 -1
  473. package/src/TabList/Tab.tsx +67 -7
  474. package/src/TabList/TabList.doc.mjs +22 -6
  475. package/src/TabList/TabList.test.tsx +559 -0
  476. package/src/TabList/TabList.tsx +490 -22
  477. package/src/TabList/TabListContext.ts +13 -2
  478. package/src/TabList/TabMenu.tsx +3 -2
  479. package/src/TabList/index.ts +6 -2
  480. package/src/Table/BaseTable.tsx +12 -4
  481. package/src/Table/Table.doc.mjs +9 -2
  482. package/src/Table/Table.test.tsx +132 -14
  483. package/src/Table/Table.tsx +3 -8
  484. package/src/Table/TableBody.doc.mjs +40 -0
  485. package/src/Table/TableFooter.doc.mjs +40 -0
  486. package/src/Table/TableHeader.doc.mjs +40 -0
  487. package/src/Table/TableRow.tsx +16 -5
  488. package/src/Table/plugins/groupedRows/useTableGroupedRows-perf.test.tsx +112 -0
  489. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +100 -0
  490. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +17 -8
  491. package/src/Table/plugins/pagination/useTablePagination.test.tsx +34 -4
  492. package/src/Table/plugins/pagination/useTablePagination.tsx +35 -3
  493. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +9 -2
  494. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +13 -7
  495. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +12 -3
  496. package/src/Table/plugins/selection/useTableSelection.test.tsx +76 -0
  497. package/src/Table/plugins/selection/useTableSelection.tsx +40 -7
  498. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
  499. package/src/Table/types.ts +22 -4
  500. package/src/Table/useBaseTablePlugins.ts +5 -0
  501. package/src/Table/useTableGroupedRows.doc.mjs +5 -4
  502. package/src/Table/useTablePagination.doc.mjs +7 -0
  503. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  504. package/src/Table/useTableSelection.doc.mjs +31 -0
  505. package/src/Text/Text.test.tsx +23 -1
  506. package/src/Text/Text.tsx +6 -2
  507. package/src/TextArea/TextArea.doc.mjs +8 -2
  508. package/src/TextArea/TextArea.test.tsx +11 -0
  509. package/src/TextArea/TextArea.tsx +15 -8
  510. package/src/TextInput/TextInput.doc.mjs +10 -0
  511. package/src/TextInput/TextInput.tsx +3 -2
  512. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  513. package/src/TimeInput/TimeInput.tsx +2 -2
  514. package/src/Timestamp/Timestamp.tsx +4 -2
  515. package/src/Toast/Toast.doc.mjs +6 -0
  516. package/src/Token/TokenLink.tsx +2 -2
  517. package/src/Tokenizer/Tokenizer.doc.mjs +27 -0
  518. package/src/Tokenizer/Tokenizer.tsx +4 -0
  519. package/src/Toolbar/Toolbar.doc.mjs +5 -0
  520. package/src/Tooltip/Tooltip.doc.mjs +5 -0
  521. package/src/Tooltip/Tooltip.test.tsx +32 -0
  522. package/src/Tooltip/Tooltip.tsx +5 -0
  523. package/src/Tooltip/useTooltip.tsx +47 -24
  524. package/src/TopNav/TopNavHeading.tsx +5 -4
  525. package/src/TopNav/TopNavMegaMenu.tsx +3 -2
  526. package/src/TopNav/TopNavMenu.tsx +4 -3
  527. package/src/Typeahead/BaseTypeahead.doc.mjs +11 -0
  528. package/src/Typeahead/BaseTypeahead.tsx +85 -33
  529. package/src/Typeahead/Typeahead.doc.mjs +5 -0
  530. package/src/Typeahead/Typeahead.test.tsx +49 -0
  531. package/src/Typeahead/Typeahead.tsx +3 -2
  532. package/src/hooks/index.ts +2 -0
  533. package/src/hooks/useContainerReveal.doc.mjs +2 -2
  534. package/src/hooks/useFocusTrap.test.tsx +14 -0
  535. package/src/hooks/useFocusTrap.ts +62 -111
  536. package/src/hooks/useFocusTrapEscapeShim.test.tsx +165 -0
  537. package/src/hooks/useHotkeys.ts +3 -18
  538. package/src/hooks/useMergedRefs.doc.mjs +79 -0
  539. package/src/hooks/useMergedRefs.test.tsx +62 -0
  540. package/src/hooks/useMergedRefs.ts +36 -0
  541. package/src/index.ts +1 -0
  542. package/src/theme/MediaTheme.doc.mjs +5 -5
  543. package/src/theme/derivedVarRegistry.test.ts +19 -3
  544. package/src/theme/derivedVarRegistry.ts +23 -4
  545. package/src/theme/generateThemeRules.test.ts +37 -0
  546. package/src/theme/syntax/tokens.ts +5 -2
  547. package/src/utils/groupItems.ts +12 -6
  548. package/src/utils/index.ts +1 -1
  549. package/src/utils/isApplePlatform.test.ts +61 -0
  550. package/src/utils/isApplePlatform.ts +37 -0
  551. package/src/utils/sharedResizeObserver.ts +10 -2
  552. package/src/utils/timeParser.test.ts +6 -1
  553. package/src/utils/timeParser.ts +35 -13
  554. package/src/__tests__/inputWidthContract.test.tsx +0 -69
@@ -9,10 +9,29 @@
9
9
  * SYNC: When Spinner.tsx changes, update tests to match new behavior
10
10
  */
11
11
 
12
- import {describe, it, expect} from 'vitest';
12
+ import {describe, it, expect, vi, afterEach} from 'vitest';
13
13
  import {render, screen} from '@testing-library/react';
14
14
  import {Spinner} from './Spinner';
15
15
 
16
+ /** sm/md/lg/xl, as Spinner.tsx defines them. */
17
+ const SIZES = {
18
+ sm: {diameter: 10, border: 2},
19
+ md: {diameter: 14, border: 3},
20
+ lg: {diameter: 18, border: 3},
21
+ xl: {diameter: 28, border: 4},
22
+ } as const;
23
+
24
+ const ring = (testId = 'spinner') =>
25
+ screen.getByTestId(testId).querySelector('svg') as SVGSVGElement;
26
+
27
+ const circles = (testId = 'spinner') => {
28
+ const [track, arc] = [...ring(testId).querySelectorAll('circle')];
29
+ return {track, arc};
30
+ };
31
+
32
+ const dashOf = (el: SVGCircleElement) =>
33
+ (el.getAttribute('stroke-dasharray') ?? '').split(/[\s,]+/).map(Number);
34
+
16
35
  describe('Spinner', () => {
17
36
  it('renders with default props', () => {
18
37
  render(<Spinner data-testid="spinner" />);
@@ -122,3 +141,130 @@ describe('Spinner', () => {
122
141
  expect(spinner.tagName.toLowerCase()).toBe('span');
123
142
  });
124
143
  });
144
+
145
+ describe('Spinner ring', () => {
146
+ afterEach(() => {
147
+ vi.restoreAllMocks();
148
+ });
149
+
150
+ it('draws the ring in SVG', () => {
151
+ render(<Spinner data-testid="spinner" />);
152
+ const svg = ring();
153
+ expect(svg).not.toBeNull();
154
+ expect(svg.querySelectorAll('circle')).toHaveLength(2);
155
+ expect(screen.getByTestId('spinner').querySelector('canvas')).toBeNull();
156
+ });
157
+
158
+ it.each(Object.entries(SIZES))(
159
+ 'sizes the %s ring from its size token',
160
+ (size, {diameter, border}) => {
161
+ render(
162
+ <Spinner size={size as keyof typeof SIZES} data-testid="spinner" />,
163
+ );
164
+ const frame = diameter + border * 2;
165
+ const svg = ring();
166
+ expect(svg.getAttribute('viewBox')).toBe(`0 0 ${frame} ${frame}`);
167
+ for (const c of [circles().track, circles().arc]) {
168
+ expect(Number(c.getAttribute('cx'))).toBe(frame / 2);
169
+ expect(Number(c.getAttribute('cy'))).toBe(frame / 2);
170
+ expect(Number(c.getAttribute('r'))).toBe(diameter / 2);
171
+ expect(Number(c.getAttribute('stroke-width'))).toBe(border);
172
+ }
173
+ },
174
+ );
175
+
176
+ // The canvas ring swept 135deg, not the 270deg its SPREAD comment claimed.
177
+ it.each(Object.entries(SIZES))(
178
+ 'sweeps 135 degrees at %s',
179
+ (size, {diameter}) => {
180
+ render(
181
+ <Spinner size={size as keyof typeof SIZES} data-testid="spinner" />,
182
+ );
183
+ const {track, arc} = circles();
184
+ const [on, off] = dashOf(arc);
185
+ expect(on + off).toBeCloseTo(Math.PI * diameter, 6);
186
+ expect((on / (on + off)) * 360).toBeCloseTo(135, 6);
187
+ expect(track.getAttribute('stroke-dasharray')).toBeNull();
188
+ },
189
+ );
190
+
191
+ it('starts the arc at twelve o’clock', () => {
192
+ render(<Spinner data-testid="spinner" />);
193
+ const frame = SIZES.md.diameter + SIZES.md.border * 2;
194
+ expect(circles().arc.getAttribute('transform')).toBe(
195
+ `rotate(-90 ${frame / 2} ${frame / 2})`,
196
+ );
197
+ });
198
+
199
+ // The whole point of the SVG ring: the colours come off the cascade, so
200
+ // nothing has to resolve them in JS. A read reaching the paint path again
201
+ // fails here.
202
+ it.each(['default', 'subtle', 'onMedia', 'inherit'] as const)(
203
+ 'reads no computed style to paint the %s shade',
204
+ shade => {
205
+ const spy = vi.spyOn(window, 'getComputedStyle');
206
+ render(<Spinner shade={shade} data-testid="spinner" />);
207
+ const spinner = screen.getByTestId('spinner');
208
+ const onSpinner = spy.mock.calls.filter(
209
+ ([el]) => el instanceof Element && spinner.contains(el),
210
+ );
211
+ expect(onSpinner).toEqual([]);
212
+ },
213
+ );
214
+
215
+ it('schedules no frame where the Web Animations API is absent', () => {
216
+ expect(SVGElement.prototype).not.toHaveProperty('getAnimations');
217
+ const raf = vi.spyOn(window, 'requestAnimationFrame');
218
+ render(<Spinner data-testid="spinner" />);
219
+ expect(ring()).not.toBeNull();
220
+ expect(raf).not.toHaveBeenCalled();
221
+ });
222
+
223
+ it('pins every ring to the timeline origin in a single frame', () => {
224
+ const animations: {startTime: number | null}[] = [];
225
+ const getAnimations = vi.fn(function (this: SVGElement) {
226
+ const a = {startTime: null as number | null};
227
+ animations.push(a);
228
+ return [a];
229
+ });
230
+ Object.defineProperty(SVGElement.prototype, 'getAnimations', {
231
+ value: getAnimations,
232
+ configurable: true,
233
+ writable: true,
234
+ });
235
+ const frames: FrameRequestCallback[] = [];
236
+ const raf = vi
237
+ .spyOn(window, 'requestAnimationFrame')
238
+ .mockImplementation(cb => {
239
+ frames.push(cb);
240
+ return frames.length;
241
+ });
242
+ const computed = vi.spyOn(window, 'getComputedStyle');
243
+
244
+ try {
245
+ const {container} = render(
246
+ <>
247
+ {Array.from({length: 5}, (_, i) => (
248
+ <Spinner key={i} />
249
+ ))}
250
+ </>,
251
+ );
252
+ // One frame for five spinners: the reads are batched, so no mount
253
+ // re-forces what the previous mount invalidated.
254
+ expect(raf).toHaveBeenCalledTimes(1);
255
+ frames.forEach(cb => cb(0));
256
+ expect(animations).toHaveLength(5);
257
+ expect(animations.every(a => a.startTime === 0)).toBe(true);
258
+ // The pin runs on the branch the other shade cases cannot reach, so the
259
+ // no-read assertion is made here too.
260
+ expect(
261
+ computed.mock.calls.filter(
262
+ ([el]) => el instanceof Element && container.contains(el),
263
+ ),
264
+ ).toEqual([]);
265
+ } finally {
266
+ // @ts-expect-error — removing the stub restores jsdom's real surface
267
+ delete SVGElement.prototype.getAnimations;
268
+ }
269
+ });
270
+ });
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file Spinner.tsx
7
- * @input Uses React, StyleX, canvas rendering
7
+ * @input Uses React, StyleX, SVG rendering
8
8
  * @output Exports Spinner component, SpinnerProps, SpinnerSize, SpinnerShade types
9
9
  * @position Core implementation of spinner loading indicator
10
10
  *
@@ -16,10 +16,9 @@
16
16
  * - /packages/cli/assets/templates/blocks/components/Spinner/ (showcase blocks)
17
17
  */
18
18
 
19
- import {useEffect, useId, useRef, type ReactNode} from 'react';
19
+ import {useId, type ReactNode} from 'react';
20
20
  import * as stylex from '@stylexjs/stylex';
21
- import {durationVars, spacingVars} from '../theme/tokens.stylex';
22
- import {useTheme} from '../theme/useTheme';
21
+ import {colorVars, durationVars, spacingVars} from '../theme/tokens.stylex';
23
22
  import type {BaseProps} from '../BaseProps';
24
23
  import {Text} from '../Text/Text';
25
24
  import {mergeProps} from '../utils';
@@ -29,10 +28,11 @@ import {themeProps} from '../utils/themeProps';
29
28
  // Constants
30
29
  // =============================================================================
31
30
 
32
- /** How much of the circle the active arc covers (as a fraction of 2π) */
33
- const SPREAD = 0.75;
34
- /** Where the active arc starts (as a fraction of 2π) */
35
- const START_POINT = 1.5;
31
+ /**
32
+ * Fraction of the ring the moving arc covers. The canvas ring this replaces
33
+ * swept 135deg, not the 270deg its constant's comment claimed.
34
+ */
35
+ const ARC_FRACTION = 0.375;
36
36
 
37
37
  const SIZES = {
38
38
  sm: {diameter: 10, border: 2},
@@ -41,6 +41,61 @@ const SIZES = {
41
41
  xl: {diameter: 28, border: 4},
42
42
  };
43
43
 
44
+ /** `onMedia` keeps the 77/255 its token's `4D` hex suffix used to encode. */
45
+ const TRACK_OPACITY = {
46
+ default: 1,
47
+ subtle: 1,
48
+ onMedia: 77 / 255,
49
+ inherit: 0.3,
50
+ };
51
+
52
+ /**
53
+ * Pin every ring's rotation to the document timeline's origin instead of its
54
+ * own start time, so spinners mounted seconds apart turn in phase.
55
+ *
56
+ * Setting `startTime` is exact where arithmetic on a clock read is not: a
57
+ * negative `animation-delay` computed at mount is only as good as the gap
58
+ * between reading the clock and the frame the animation starts in, which at
59
+ * 10x CPU throttling measured 116deg of drift.
60
+ *
61
+ * Rings are collected and pinned in one frame because `getAnimations()`
62
+ * resolves style and `startTime` dirties it again, so pinning them one at a
63
+ * time makes each mount re-force what the previous one invalidated — 53 style
64
+ * recalcs for 38 spinners against 19 batched.
65
+ */
66
+ const pendingRings = new Set<SVGSVGElement>();
67
+ let flushScheduled = false;
68
+
69
+ function pinRingsToTimelineOrigin(): void {
70
+ flushScheduled = false;
71
+ const animations: Animation[] = [];
72
+ for (const svg of pendingRings) {
73
+ animations.push(...svg.getAnimations());
74
+ }
75
+ pendingRings.clear();
76
+ for (const animation of animations) {
77
+ animation.startTime = 0;
78
+ }
79
+ }
80
+
81
+ function syncRotationPhase(
82
+ svg: SVGSVGElement | null,
83
+ ): (() => void) | undefined {
84
+ // jsdom implements no Web Animations, and this runs in every consumer's
85
+ // component tests.
86
+ if (svg == null || typeof svg.getAnimations !== 'function') {
87
+ return undefined;
88
+ }
89
+ pendingRings.add(svg);
90
+ if (!flushScheduled) {
91
+ flushScheduled = true;
92
+ requestAnimationFrame(pinRingsToTimelineOrigin);
93
+ }
94
+ return () => {
95
+ pendingRings.delete(svg);
96
+ };
97
+ }
98
+
44
99
  // =============================================================================
45
100
  // Animation
46
101
  // =============================================================================
@@ -67,7 +122,7 @@ const styles = stylex.create({
67
122
  overflow: 'hidden',
68
123
  verticalAlign: 'middle',
69
124
  },
70
- canvas: {
125
+ ring: {
71
126
  backfaceVisibility: 'hidden',
72
127
  display: 'block',
73
128
  willChange: 'transform',
@@ -82,6 +137,33 @@ const styles = stylex.create({
82
137
  animationName: rotation,
83
138
  animationTimingFunction: 'linear',
84
139
  },
140
+ circle: {
141
+ fill: 'none',
142
+ strokeLinecap: 'round',
143
+ },
144
+ });
145
+
146
+ const arcStyles = stylex.create({
147
+ default: {stroke: colorVars['--color-accent']},
148
+ subtle: {stroke: colorVars['--color-text-secondary']},
149
+ onMedia: {stroke: colorVars['--color-on-dark']},
150
+ inherit: {stroke: 'currentColor'},
151
+ });
152
+
153
+ const trackStyles = stylex.create({
154
+ default: {
155
+ stroke: colorVars['--color-track'],
156
+ strokeOpacity: TRACK_OPACITY.default,
157
+ },
158
+ subtle: {
159
+ stroke: colorVars['--color-track'],
160
+ strokeOpacity: TRACK_OPACITY.subtle,
161
+ },
162
+ onMedia: {
163
+ stroke: colorVars['--color-on-dark'],
164
+ strokeOpacity: TRACK_OPACITY.onMedia,
165
+ },
166
+ inherit: {stroke: 'currentColor', strokeOpacity: TRACK_OPACITY.inherit},
85
167
  });
86
168
 
87
169
  // =============================================================================
@@ -100,7 +182,7 @@ export interface SpinnerProps extends BaseProps<HTMLSpanElement> {
100
182
  * - 'sm': 10px diameter
101
183
  * - 'md': 14px diameter
102
184
  * - 'lg': 18px diameter
103
- * - 'xl': 36px diameter
185
+ * - 'xl': 28px diameter
104
186
  * @default 'md'
105
187
  */
106
188
  size?: SpinnerSize;
@@ -141,7 +223,7 @@ export interface SpinnerProps extends BaseProps<HTMLSpanElement> {
141
223
  // =============================================================================
142
224
 
143
225
  /**
144
- * An animated loading indicator. Available in three sizes and two color shades.
226
+ * An animated loading indicator. Available in four sizes and four color shades.
145
227
  *
146
228
  * @example
147
229
  * ```
@@ -164,97 +246,11 @@ export function Spinner({
164
246
  ref,
165
247
  ...restProps
166
248
  }: SpinnerProps) {
167
- const canvasRef = useRef<HTMLCanvasElement>(null);
168
- const {tokens: themeTokens} = useTheme();
169
-
170
- useEffect(() => {
171
- const canvas = canvasRef.current;
172
- if (canvas == null) {
173
- return;
174
- }
175
-
176
- const context = canvas.getContext('2d');
177
- if (!context) {
178
- return;
179
- }
180
-
181
- const {border, diameter} = SIZES[size];
182
- const pixelRatio = window.devicePixelRatio || 1;
183
-
184
- // Resolve colors from theme tokens (useTheme handles light/dark resolution).
185
- // - default → accent ring on a track tuned to body luminance
186
- // - subtle → secondary text color, less prominent
187
- // - onMedia → on-dark color, with a translucent track for photos/video
188
- // - inherit → the inherited currentColor, so the ring matches the parent's
189
- // resolved foreground (e.g. a button's variant text color)
190
- const inheritedColor =
191
- shade === 'inherit' ? getComputedStyle(canvas).color : null;
192
- const activeColor =
193
- shade === 'inherit'
194
- ? (inheritedColor as string)
195
- : shade === 'onMedia'
196
- ? themeTokens['--color-on-dark']
197
- : shade === 'subtle'
198
- ? themeTokens['--color-text-secondary']
199
- : themeTokens['--color-accent'];
200
- // Track derives from --color-on-dark for onMedia (with a 30% alpha so the
201
- // ring reads against arbitrary backgrounds) and from --color-track for the
202
- // body-luminance shades. For inherit, the track is the same currentColor
203
- // drawn at reduced alpha via globalAlpha (see below). All branches are
204
- // fully theme-driven.
205
- const backgroundColor =
206
- shade === 'inherit'
207
- ? (inheritedColor as string)
208
- : shade === 'onMedia'
209
- ? `${themeTokens['--color-on-dark']}4D`
210
- : themeTokens['--color-track'];
211
-
212
- const cssSize = diameter + border * 2;
213
-
214
- // Round to an even number of device pixels so the center stays on a whole
215
- // pixel (avoids rotation jitter); keep CSS size pinned to cssSize (#2732).
216
- const rawFrameSize = Math.round(cssSize * pixelRatio);
217
- const frameSize = rawFrameSize + (rawFrameSize % 2);
218
-
219
- const scale = frameSize / cssSize;
220
- const radius = (diameter / 2) * scale;
221
- const lineWidth = border * scale;
222
-
223
- canvas.height = canvas.width = frameSize;
224
- canvas.style.width = canvas.style.height = cssSize + 'px';
225
-
226
- context.lineCap = 'round';
227
- context.lineWidth = lineWidth;
228
-
229
- const center = frameSize / 2;
230
-
231
- // Background circle (full ring, faded). For the inherit shade the track is
232
- // the same currentColor as the arc, so fade it via globalAlpha (the
233
- // computed color is an opaque rgb() string with no alpha channel to tweak).
234
- context.beginPath();
235
- context.arc(center, center, radius, 0, 2 * Math.PI);
236
- context.strokeStyle = backgroundColor;
237
- if (shade === 'inherit') {
238
- context.globalAlpha = 0.3;
239
- }
240
- context.stroke();
241
- context.globalAlpha = 1;
242
-
243
- // Active arc (partial ring, colored)
244
- context.beginPath();
245
- context.arc(
246
- center,
247
- center,
248
- radius,
249
- START_POINT * Math.PI,
250
- ((START_POINT + SPREAD) % 2) * Math.PI,
251
- );
252
- context.strokeStyle = activeColor;
253
- context.stroke();
254
- }, [shade, size, themeTokens]);
255
-
256
249
  const {border, diameter} = SIZES[size];
257
250
  const frameSize = diameter + border * 2;
251
+ const center = frameSize / 2;
252
+ const circumference = Math.PI * diameter;
253
+ const arcLength = circumference * ARC_FRACTION;
258
254
  const hasLabel = label != null;
259
255
  const labelId = useId();
260
256
 
@@ -283,7 +279,30 @@ export function Spinner({
283
279
  hasLabel ? undefined : className,
284
280
  {...(hasLabel ? {} : style), width: frameSize, height: frameSize},
285
281
  )}>
286
- <canvas ref={canvasRef} {...stylex.props(styles.canvas)} />
282
+ <svg
283
+ ref={syncRotationPhase}
284
+ width={frameSize}
285
+ height={frameSize}
286
+ viewBox={`0 0 ${frameSize} ${frameSize}`}
287
+ aria-hidden="true"
288
+ {...stylex.props(styles.ring)}>
289
+ <circle
290
+ cx={center}
291
+ cy={center}
292
+ r={diameter / 2}
293
+ strokeWidth={border}
294
+ {...stylex.props(styles.circle, trackStyles[shade])}
295
+ />
296
+ <circle
297
+ cx={center}
298
+ cy={center}
299
+ r={diameter / 2}
300
+ strokeWidth={border}
301
+ strokeDasharray={`${arcLength} ${circumference - arcLength}`}
302
+ transform={`rotate(-90 ${center} ${center})`}
303
+ {...stylex.props(styles.circle, arcStyles[shade])}
304
+ />
305
+ </svg>
287
306
  </span>
288
307
  );
289
308
 
@@ -48,7 +48,10 @@ export const docs = {
48
48
  ],
49
49
  theming: {
50
50
  targets: [
51
- {className: 'astryx-statusdot', visualProps: ['variant']},
51
+ {className: 'astryx-status-dot', visualProps: ['variant']},
52
+ // Still emitted beside the names above, so themes written against
53
+ // them keep working. Drop in the next major.
54
+ {className: 'astryx-statusdot', visualProps: ['variant'], deprecatedFor: 'status-dot'},
52
55
  ],
53
56
  },
54
57
  usage: {
@@ -105,7 +108,10 @@ export const docsZh = {
105
108
  ],
106
109
  theming: {
107
110
  targets: [
108
- {className: 'astryx-statusdot', visualProps: ['variant']},
111
+ {className: 'astryx-status-dot', visualProps: ['variant']},
112
+ // Still emitted beside the names above, so themes written against
113
+ // them keep working. Drop in the next major.
114
+ {className: 'astryx-statusdot', visualProps: ['variant'], deprecatedFor: 'status-dot'},
109
115
  ],
110
116
  },
111
117
  usage: {
@@ -189,3 +189,12 @@ describe('StatusDot', () => {
189
189
  });
190
190
  });
191
191
  });
192
+
193
+ describe('StatusDot theme target names', () => {
194
+ it('renders the deprecated class beside the current one', () => {
195
+ render(<StatusDot variant="success" label="Online" />);
196
+ const dot = screen.getByRole('img', {name: 'Online'});
197
+ expect(dot).toHaveClass('astryx-status-dot');
198
+ expect(dot).toHaveClass('astryx-statusdot');
199
+ });
200
+ });
@@ -200,7 +200,13 @@ export function StatusDot({
200
200
  role="img"
201
201
  aria-label={label}
202
202
  {...mergeProps(
203
- themeProps('statusdot', {variant}),
203
+ themeProps(
204
+ 'status-dot',
205
+ {variant},
206
+ // `statusdot` ran the compound name together; themes styling it keep
207
+ // working until the next major.
208
+ {legacyNames: ['statusdot']},
209
+ ),
204
210
  stylex.props(
205
211
  styles.base,
206
212
  variants[variant],
@@ -0,0 +1,98 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
+
5
+ export const docs = {
6
+ name: 'Step',
7
+ subComponentOf: 'Stepper',
8
+ displayName: 'Step',
9
+ group: 'Stepper',
10
+ category: 'Navigation',
11
+ isHiddenFromOverview: true,
12
+ description:
13
+ 'Individual step within a Stepper. Renders a progress-bar segment, an indicator, and a label with optional description. Progress (completed/active/not-started) is derived from the parent Stepper\u2019s activeStep and this step\u2019s step index.',
14
+ props: [
15
+ {
16
+ name: 'step',
17
+ type: 'number',
18
+ description:
19
+ 'Zero-based index of this step. Used to derive progress (completed/active/not-started) relative to the parent activeStep.',
20
+ required: true,
21
+ },
22
+ {
23
+ name: 'label',
24
+ type: 'string',
25
+ description: 'Step label text.',
26
+ required: true,
27
+ },
28
+ {
29
+ name: 'description',
30
+ type: 'string',
31
+ description:
32
+ 'Optional description shown below the label for additional context.',
33
+ },
34
+ {
35
+ name: 'children',
36
+ type: 'ReactNode',
37
+ description:
38
+ 'Content rendered below the label and description. Useful in vertical steppers for form fields or detailed step content.',
39
+ },
40
+ {
41
+ name: 'status',
42
+ type: "'accent' | 'success' | 'warning' | 'error'",
43
+ description:
44
+ 'Semantic color for the step. Controls color only and maps to the global Astryx semantic tokens. Leave unset for the progress-derived default coloring.',
45
+ },
46
+ {
47
+ name: 'indicator',
48
+ type: "'auto' | 'number' | 'none' | ReactNode",
49
+ description:
50
+ "What to show as the step indicator. 'auto' shows a number until completed then a check, 'number' always shows a numbered badge, 'none' hides it, or pass any ReactNode (e.g. an Icon) for a fully custom indicator.",
51
+ slotElements: [{__element: 'Icon', props: {icon: 'check', size: 'sm'}}],
52
+ default: "'auto'",
53
+ },
54
+ {
55
+ name: 'isDisabled',
56
+ type: 'boolean',
57
+ description:
58
+ 'Disables interaction and dims the step indicator and label.',
59
+ default: 'false',
60
+ },
61
+ {
62
+ name: 'isOptional',
63
+ type: 'boolean',
64
+ description:
65
+ 'Marks the step as optional, appending an "Optional" affordance after the label.',
66
+ default: 'false',
67
+ },
68
+ {
69
+ name: 'endContent',
70
+ type: 'ReactNode',
71
+ description: 'Trailing content rendered at the end of the label row.',
72
+ },
73
+ {
74
+ name: 'density',
75
+ type: "'compact' | 'balanced' | 'spacious'",
76
+ description:
77
+ 'Controls vertical padding of the step. Falls back to the stepper-level density when unset.',
78
+ },
79
+ ],
80
+ // A Step reads its progress from the parent Stepper's context and throws
81
+ // without one, so the preview needs a real Stepper around it. Without this
82
+ // block Step inherits Stepper's playground, which renders it bare and hands
83
+ // it the parent's `activeStep`. The wrapper is vertical because that is the
84
+ // orientation where one step shows its whole anatomy — indicator, label, and
85
+ // description stacked — and `step` matches the wrapper's `activeStep` so the
86
+ // preview opens on the current step rather than an inert upcoming one.
87
+ playground: {
88
+ wrapper: {
89
+ component: 'Stepper',
90
+ props: {activeStep: 1, orientation: 'vertical'},
91
+ },
92
+ defaults: {
93
+ step: 1,
94
+ label: 'Billing address',
95
+ description: 'Used for invoices and tax',
96
+ },
97
+ },
98
+ };