@astryxdesign/core 0.1.4 → 0.1.5-canary.76e6697

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 (635) hide show
  1. package/CHANGELOG.md +141 -0
  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 +20 -18
  5. package/dist/AlertDialog/useImperativeAlertDialog.d.ts +0 -2
  6. package/dist/AlertDialog/useImperativeAlertDialog.d.ts.map +1 -1
  7. package/dist/AlertDialog/useImperativeAlertDialog.js +3 -5
  8. package/dist/AppShell/AppShell.d.ts +1 -1
  9. package/dist/AppShell/AppShell.d.ts.map +1 -1
  10. package/dist/AppShell/AppShell.js +55 -53
  11. package/dist/AspectRatio/AspectRatio.d.ts +48 -10
  12. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  13. package/dist/AspectRatio/AspectRatio.js +33 -12
  14. package/dist/AspectRatio/index.d.ts +1 -1
  15. package/dist/AspectRatio/index.d.ts.map +1 -1
  16. package/dist/Avatar/Avatar.d.ts.map +1 -1
  17. package/dist/Avatar/Avatar.js +28 -26
  18. package/dist/Avatar/AvatarStatusDot.js +6 -6
  19. package/dist/AvatarGroup/AvatarGroup.js +6 -6
  20. package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -7
  21. package/dist/Badge/Badge.js +3 -3
  22. package/dist/Banner/Banner.d.ts.map +1 -1
  23. package/dist/Banner/Banner.js +32 -25
  24. package/dist/Blockquote/Blockquote.js +7 -7
  25. package/dist/Breadcrumbs/BreadcrumbItem.js +17 -17
  26. package/dist/Breadcrumbs/Breadcrumbs.js +7 -7
  27. package/dist/Button/Button.js +19 -19
  28. package/dist/ButtonGroup/ButtonGroup.js +7 -7
  29. package/dist/Calendar/Calendar.d.ts.map +1 -1
  30. package/dist/Calendar/Calendar.js +68 -48
  31. package/dist/Calendar/dayCellUtils.d.ts.map +1 -1
  32. package/dist/Calendar/styles.d.ts +2 -2
  33. package/dist/Calendar/styles.d.ts.map +1 -1
  34. package/dist/Calendar/styles.js +2 -2
  35. package/dist/Card/Card.d.ts +4 -2
  36. package/dist/Card/Card.d.ts.map +1 -1
  37. package/dist/Card/Card.js +18 -10
  38. package/dist/Carousel/Carousel.d.ts.map +1 -1
  39. package/dist/Carousel/Carousel.js +24 -21
  40. package/dist/Center/Center.js +3 -3
  41. package/dist/Chat/ChatComposer.js +23 -23
  42. package/dist/Chat/ChatComposerDrawer.js +14 -14
  43. package/dist/Chat/ChatComposerInput.d.ts +1 -1
  44. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  45. package/dist/Chat/ChatComposerInput.js +27 -15
  46. package/dist/Chat/ChatDictationButton.d.ts +1 -1
  47. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  48. package/dist/Chat/ChatDictationButton.js +13 -11
  49. package/dist/Chat/ChatLayout.js +17 -17
  50. package/dist/Chat/ChatLayoutScrollButton.d.ts +1 -1
  51. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  52. package/dist/Chat/ChatLayoutScrollButton.js +12 -10
  53. package/dist/Chat/ChatMessage.js +12 -12
  54. package/dist/Chat/ChatMessageBubble.js +7 -7
  55. package/dist/Chat/ChatMessageList.js +14 -14
  56. package/dist/Chat/ChatMessageMetadata.d.ts +1 -1
  57. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  58. package/dist/Chat/ChatMessageMetadata.js +14 -12
  59. package/dist/Chat/ChatPastedTextToken.js +13 -13
  60. package/dist/Chat/ChatSendButton.js +3 -3
  61. package/dist/Chat/ChatSystemMessage.d.ts +1 -1
  62. package/dist/Chat/ChatSystemMessage.d.ts.map +1 -1
  63. package/dist/Chat/ChatSystemMessage.js +17 -17
  64. package/dist/Chat/ChatTokenizedText.d.ts +1 -1
  65. package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
  66. package/dist/Chat/ChatTokenizedText.js +24 -15
  67. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  68. package/dist/Chat/ChatToolCalls.js +81 -74
  69. package/dist/Chat/index.d.ts +1 -1
  70. package/dist/Chat/index.d.ts.map +1 -1
  71. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  72. package/dist/Chat/useTriggerMenu.js +15 -15
  73. package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
  74. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  75. package/dist/CheckboxInput/CheckboxInput.js +25 -23
  76. package/dist/CheckboxList/CheckboxList.js +9 -9
  77. package/dist/CheckboxList/CheckboxListItem.d.ts +1 -1
  78. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  79. package/dist/CheckboxList/CheckboxListItem.js +8 -6
  80. package/dist/Citation/Citation.js +10 -10
  81. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  82. package/dist/ClickableCard/ClickableCard.js +32 -9
  83. package/dist/Code/Code.js +3 -3
  84. package/dist/CodeBlock/CodeBlock.d.ts +10 -1
  85. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  86. package/dist/CodeBlock/CodeBlock.js +88 -52
  87. package/dist/Collapsible/Collapsible.d.ts +9 -3
  88. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  89. package/dist/Collapsible/Collapsible.js +109 -22
  90. package/dist/Collapsible/CollapsibleGroup.d.ts +37 -7
  91. package/dist/Collapsible/CollapsibleGroup.d.ts.map +1 -1
  92. package/dist/Collapsible/CollapsibleGroup.js +64 -12
  93. package/dist/Collapsible/CollapsibleGroupContext.d.ts +24 -0
  94. package/dist/Collapsible/CollapsibleGroupContext.d.ts.map +1 -1
  95. package/dist/Collapsible/CollapsibleGroupContext.js +26 -3
  96. package/dist/Collapsible/index.d.ts +1 -0
  97. package/dist/Collapsible/index.d.ts.map +1 -1
  98. package/dist/Collapsible/useCollapsible.d.ts +4 -1
  99. package/dist/Collapsible/useCollapsible.d.ts.map +1 -1
  100. package/dist/Collapsible/useCollapsible.js +20 -6
  101. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  102. package/dist/CommandPalette/CommandPalette.js +36 -34
  103. package/dist/CommandPalette/CommandPaletteEmpty.js +3 -3
  104. package/dist/CommandPalette/CommandPaletteFooter.js +16 -16
  105. package/dist/CommandPalette/CommandPaletteGroup.js +5 -5
  106. package/dist/CommandPalette/CommandPaletteInput.js +13 -13
  107. package/dist/CommandPalette/CommandPaletteItem.js +3 -3
  108. package/dist/CommandPalette/CommandPaletteList.js +3 -3
  109. package/dist/ContextMenu/ContextMenu.d.ts +7 -2
  110. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  111. package/dist/ContextMenu/ContextMenu.js +76 -43
  112. package/dist/DateInput/DateInput.js +18 -18
  113. package/dist/DateRangeInput/DateRangeInput.js +21 -21
  114. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  115. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  116. package/dist/DateTimeInput/DateTimeInput.js +30 -26
  117. package/dist/DateTimeInput/index.d.ts +1 -1
  118. package/dist/DateTimeInput/index.d.ts.map +1 -1
  119. package/dist/Dialog/Dialog.js +9 -9
  120. package/dist/Dialog/DialogHeader.js +16 -16
  121. package/dist/Dialog/useImperativeDialog.js +3 -3
  122. package/dist/Divider/Divider.js +7 -7
  123. package/dist/DropdownMenu/DropdownMenu.js +10 -10
  124. package/dist/DropdownMenu/DropdownMenuItem.d.ts +2 -17
  125. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  126. package/dist/DropdownMenu/DropdownMenuItem.js +3 -3
  127. package/dist/DropdownMenu/renderDropdownItems.js +10 -10
  128. package/dist/EmptyState/EmptyState.js +9 -9
  129. package/dist/Field/Field.js +17 -17
  130. package/dist/Field/FieldLabel.js +15 -15
  131. package/dist/Field/InputClearButton.js +5 -5
  132. package/dist/FieldStatus/FieldStatus.js +3 -3
  133. package/dist/FileInput/FileInput.js +29 -29
  134. package/dist/FormLayout/FormLayout.js +5 -5
  135. package/dist/Grid/Grid.d.ts +4 -3
  136. package/dist/Grid/Grid.d.ts.map +1 -1
  137. package/dist/Grid/Grid.js +29 -12
  138. package/dist/Grid/GridSpan.js +3 -3
  139. package/dist/HStack/HStack.js +3 -3
  140. package/dist/Heading/Heading.js +10 -10
  141. package/dist/HoverCard/HoverCard.js +9 -9
  142. package/dist/HoverCard/useHoverCard.d.ts +5 -1
  143. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  144. package/dist/HoverCard/useHoverCard.js +3 -3
  145. package/dist/Icon/Icon.d.ts.map +1 -1
  146. package/dist/Icon/Icon.js +16 -12
  147. package/dist/Icon/defaultIcons.js +116 -116
  148. package/dist/IconButton/IconButton.js +3 -3
  149. package/dist/InputGroup/InputGroup.js +11 -11
  150. package/dist/InputGroup/InputGroupText.js +3 -3
  151. package/dist/Item/Item.js +18 -18
  152. package/dist/Kbd/Kbd.js +5 -5
  153. package/dist/Layer/LayerProvider.js +7 -7
  154. package/dist/Layer/useLayer.d.ts +29 -2
  155. package/dist/Layer/useLayer.d.ts.map +1 -1
  156. package/dist/Layer/useLayer.js +44 -31
  157. package/dist/Layout/Layout.js +21 -21
  158. package/dist/Layout/LayoutContent.js +3 -3
  159. package/dist/Layout/LayoutFooter.js +5 -5
  160. package/dist/Layout/LayoutHeader.js +5 -5
  161. package/dist/Layout/LayoutPanel.js +3 -3
  162. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  163. package/dist/Lightbox/Lightbox.js +55 -31
  164. package/dist/Lightbox/useLightbox.d.ts +0 -1
  165. package/dist/Lightbox/useLightbox.d.ts.map +1 -1
  166. package/dist/Lightbox/useLightbox.js +3 -4
  167. package/dist/Link/Link.d.ts +0 -2
  168. package/dist/Link/Link.d.ts.map +1 -1
  169. package/dist/Link/Link.js +15 -17
  170. package/dist/Link/LinkProvider.js +3 -3
  171. package/dist/Link/useLinkify.js +3 -3
  172. package/dist/List/List.js +11 -11
  173. package/dist/List/ListItem.js +11 -11
  174. package/dist/Markdown/Markdown.d.ts.map +1 -1
  175. package/dist/Markdown/Markdown.js +102 -102
  176. package/dist/MetadataList/MetadataList.js +10 -10
  177. package/dist/MetadataList/MetadataListItem.js +15 -15
  178. package/dist/MobileNav/MobileNav.d.ts +1 -1
  179. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  180. package/dist/MobileNav/MobileNav.js +26 -23
  181. package/dist/MobileNav/MobileNavToggle.js +5 -5
  182. package/dist/MoreMenu/MoreMenu.js +3 -3
  183. package/dist/MultiSelector/MultiSelector.js +56 -56
  184. package/dist/NavIcon/NavIcon.js +3 -3
  185. package/dist/NavMenu/NavHeadingMenu.js +5 -5
  186. package/dist/NavMenu/NavHeadingMenuItem.js +8 -8
  187. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  188. package/dist/NumberInput/NumberInput.js +48 -32
  189. package/dist/Outline/Outline.js +15 -15
  190. package/dist/OverflowList/OverflowList.js +8 -8
  191. package/dist/Overlay/Overlay.js +3 -3
  192. package/dist/Overlay/OverlayScrim.js +5 -5
  193. package/dist/Overlay/useOverlay.d.ts +0 -3
  194. package/dist/Overlay/useOverlay.d.ts.map +1 -1
  195. package/dist/Overlay/useOverlay.js +3 -6
  196. package/dist/Pagination/Pagination.d.ts +1 -1
  197. package/dist/Pagination/Pagination.d.ts.map +1 -1
  198. package/dist/Pagination/Pagination.js +125 -72
  199. package/dist/Popover/Popover.js +16 -16
  200. package/dist/Popover/usePopover.js +7 -7
  201. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  202. package/dist/PowerSearch/PowerSearch.js +110 -92
  203. package/dist/PowerSearch/PowerSearchEditPopover.js +84 -84
  204. package/dist/PowerSearch/PowerSearchFilterEditor.js +3 -3
  205. package/dist/PowerSearch/PowerSearchToken.js +5 -5
  206. package/dist/PowerSearch/PowerSearchValueEditor.js +54 -54
  207. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  208. package/dist/ProgressBar/ProgressBar.js +25 -18
  209. package/dist/RadioList/RadioList.js +7 -7
  210. package/dist/RadioList/RadioListItem.d.ts +1 -1
  211. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  212. package/dist/RadioList/RadioListItem.js +24 -21
  213. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  214. package/dist/Resizable/ResizeHandle.js +28 -10
  215. package/dist/Section/Section.js +5 -5
  216. package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
  217. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  218. package/dist/SegmentedControl/SegmentedControl.js +32 -10
  219. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  220. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  221. package/dist/SegmentedControl/SegmentedControlItem.js +18 -12
  222. package/dist/SelectableCard/SelectableCard.js +5 -5
  223. package/dist/Selector/Selector.js +46 -46
  224. package/dist/Selector/SelectorOption.js +3 -3
  225. package/dist/SideNav/SideNav.d.ts.map +1 -1
  226. package/dist/SideNav/SideNav.js +38 -34
  227. package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
  228. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  229. package/dist/SideNav/SideNavCollapseButton.js +8 -6
  230. package/dist/SideNav/SideNavHeading.js +87 -87
  231. package/dist/SideNav/SideNavItem.js +42 -42
  232. package/dist/SideNav/SideNavSection.d.ts +1 -1
  233. package/dist/SideNav/SideNavSection.d.ts.map +1 -1
  234. package/dist/SideNav/SideNavSection.js +18 -16
  235. package/dist/Skeleton/Skeleton.js +3 -3
  236. package/dist/Slider/Slider.js +23 -23
  237. package/dist/Spinner/Spinner.js +9 -9
  238. package/dist/StatusDot/StatusDot.js +5 -5
  239. package/dist/Switch/Switch.d.ts +8 -4
  240. package/dist/Switch/Switch.d.ts.map +1 -1
  241. package/dist/Switch/Switch.js +34 -29
  242. package/dist/TabList/Tab.js +18 -18
  243. package/dist/TabList/TabList.js +5 -5
  244. package/dist/TabList/TabMenu.d.ts.map +1 -1
  245. package/dist/TabList/TabMenu.js +57 -30
  246. package/dist/TabList/tab.markers.stylex.d.ts +1 -1
  247. package/dist/Table/BaseTable.d.ts.map +1 -1
  248. package/dist/Table/BaseTable.js +50 -39
  249. package/dist/Table/Table.js +7 -7
  250. package/dist/Table/TableBody.d.ts +1 -1
  251. package/dist/Table/TableBody.d.ts.map +1 -1
  252. package/dist/Table/TableBody.js +9 -5
  253. package/dist/Table/TableCell.js +3 -3
  254. package/dist/Table/TableFooter.d.ts +1 -1
  255. package/dist/Table/TableFooter.d.ts.map +1 -1
  256. package/dist/Table/TableFooter.js +9 -5
  257. package/dist/Table/TableHeader.d.ts +1 -1
  258. package/dist/Table/TableHeader.d.ts.map +1 -1
  259. package/dist/Table/TableHeader.js +9 -5
  260. package/dist/Table/TableHeaderCell.js +3 -3
  261. package/dist/Table/TableRow.js +5 -5
  262. package/dist/Table/index.d.ts +2 -0
  263. package/dist/Table/index.d.ts.map +1 -1
  264. package/dist/Table/index.js +1 -0
  265. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  266. package/dist/Table/plugins/columnResize/useTableColumnResize.js +14 -11
  267. package/dist/Table/plugins/filtering/useTableFiltering.js +71 -71
  268. package/dist/Table/plugins/groupedRows/index.d.ts +3 -0
  269. package/dist/Table/plugins/groupedRows/index.d.ts.map +1 -0
  270. package/dist/Table/plugins/groupedRows/index.js +3 -0
  271. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +78 -0
  272. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -0
  273. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +250 -0
  274. package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
  275. package/dist/Table/plugins/pagination/paginateData.js +5 -1
  276. package/dist/Table/plugins/pagination/useTablePagination.js +7 -7
  277. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +1 -1
  278. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +23 -23
  279. package/dist/Table/plugins/selection/useTableSelection.js +18 -18
  280. package/dist/Table/plugins/selection/useTableSelectionState.d.ts.map +1 -1
  281. package/dist/Table/plugins/selection/useTableSelectionState.js +11 -1
  282. package/dist/Table/plugins/sortable/useTableSortable.js +17 -17
  283. package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
  284. package/dist/Table/plugins/sortable/useTableSortableState.js +8 -4
  285. package/dist/Table/tableContextMenu.js +9 -9
  286. package/dist/Text/Text.js +10 -10
  287. package/dist/TextArea/TextArea.js +14 -14
  288. package/dist/TextInput/TextInput.js +15 -15
  289. package/dist/Thumbnail/Thumbnail.d.ts +3 -2
  290. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  291. package/dist/Thumbnail/Thumbnail.js +30 -29
  292. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  293. package/dist/TimeInput/TimeInput.js +26 -21
  294. package/dist/Timestamp/Timestamp.d.ts +1 -1
  295. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  296. package/dist/Timestamp/Timestamp.js +37 -26
  297. package/dist/Toast/Toast.d.ts.map +1 -1
  298. package/dist/Toast/Toast.js +25 -17
  299. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  300. package/dist/Toast/ToastViewport.js +23 -11
  301. package/dist/Toast/useToast.d.ts.map +1 -1
  302. package/dist/Toast/useToast.js +44 -4
  303. package/dist/ToggleButton/ToggleButton.js +12 -12
  304. package/dist/ToggleButton/ToggleButtonGroup.js +5 -5
  305. package/dist/Token/Token.js +21 -21
  306. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  307. package/dist/Tokenizer/Tokenizer.js +36 -34
  308. package/dist/Toolbar/Toolbar.js +18 -18
  309. package/dist/Tooltip/Tooltip.js +11 -11
  310. package/dist/Tooltip/useTooltip.d.ts +5 -1
  311. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  312. package/dist/Tooltip/useTooltip.js +3 -3
  313. package/dist/TopNav/TopNav.js +32 -32
  314. package/dist/TopNav/TopNavHeading.js +67 -67
  315. package/dist/TopNav/TopNavItem.js +5 -5
  316. package/dist/TopNav/TopNavMegaMenu.js +30 -30
  317. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +1 -1
  318. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  319. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +25 -14
  320. package/dist/TopNav/TopNavMegaMenuItem.js +16 -16
  321. package/dist/TopNav/TopNavMenu.js +32 -32
  322. package/dist/TreeList/TreeList.js +8 -8
  323. package/dist/TreeList/TreeListBranches.js +11 -11
  324. package/dist/TreeList/TreeListItem.js +30 -30
  325. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  326. package/dist/Typeahead/BaseTypeahead.js +23 -20
  327. package/dist/Typeahead/Typeahead.js +12 -12
  328. package/dist/Typeahead/TypeaheadItem.js +10 -10
  329. package/dist/VStack/VStack.js +3 -3
  330. package/dist/VisuallyHidden/VisuallyHidden.d.ts +0 -3
  331. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -1
  332. package/dist/VisuallyHidden/VisuallyHidden.js +0 -3
  333. package/dist/astryx.css +7 -0
  334. package/dist/astryx.umd.js +63 -63
  335. package/dist/astryx.umd.js.map +4 -4
  336. package/dist/docs-types.d.ts +8 -2
  337. package/dist/docs-types.d.ts.map +1 -1
  338. package/dist/hooks/focusableSelector.d.ts +1 -1
  339. package/dist/hooks/focusableSelector.d.ts.map +1 -1
  340. package/dist/hooks/focusableSelector.js +1 -1
  341. package/dist/hooks/index.d.ts +2 -0
  342. package/dist/hooks/index.d.ts.map +1 -1
  343. package/dist/hooks/index.js +1 -0
  344. package/dist/hooks/useFocusTrap.d.ts +3 -0
  345. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  346. package/dist/hooks/useFocusTrap.js +38 -1
  347. package/dist/hooks/useHotkeys.d.ts +51 -0
  348. package/dist/hooks/useHotkeys.d.ts.map +1 -0
  349. package/dist/hooks/useHotkeys.js +160 -0
  350. package/dist/hooks/useInteractiveRole.d.ts +6 -2
  351. package/dist/hooks/useInteractiveRole.d.ts.map +1 -1
  352. package/dist/hooks/useInteractiveRole.js +6 -2
  353. package/dist/hooks/useKeyboardHint.js +9 -9
  354. package/dist/hooks/useStreamingText.d.ts +3 -1
  355. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  356. package/dist/hooks/useStreamingText.js +14 -5
  357. package/dist/theme/MediaTheme.js +3 -3
  358. package/dist/theme/Theme.js +7 -7
  359. package/dist/theme/defineTheme.d.ts +1 -1
  360. package/dist/theme/defineTheme.d.ts.map +1 -1
  361. package/dist/theme/expandColorScale.d.ts.map +1 -1
  362. package/dist/theme/expandColorScale.js +10 -3
  363. package/dist/theme/hct.d.ts +0 -15
  364. package/dist/theme/hct.d.ts.map +1 -1
  365. package/dist/theme/hct.js +9 -9
  366. package/dist/theme/syntax/SyntaxTheme.js +5 -5
  367. package/dist/theme/tokens.d.ts +10 -2
  368. package/dist/theme/tokens.d.ts.map +1 -1
  369. package/dist/theme/tokens.js +220 -4
  370. package/dist/theme/useTheme.d.ts +3 -2
  371. package/dist/theme/useTheme.d.ts.map +1 -1
  372. package/dist/theme/useTheme.js +73 -6
  373. package/dist/utils/color.d.ts +42 -0
  374. package/dist/utils/color.d.ts.map +1 -0
  375. package/dist/utils/color.js +150 -0
  376. package/dist/utils/composeEventHandlers.d.ts +30 -0
  377. package/dist/utils/composeEventHandlers.d.ts.map +1 -0
  378. package/dist/utils/composeEventHandlers.js +40 -0
  379. package/dist/utils/index.d.ts +3 -0
  380. package/dist/utils/index.d.ts.map +1 -1
  381. package/dist/utils/index.js +3 -1
  382. package/dist/utils/timeParser.d.ts.map +1 -1
  383. package/dist/utils/timeParser.js +8 -5
  384. package/package.json +4 -4
  385. package/src/AlertDialog/AlertDialog.doc.mjs +4 -0
  386. package/src/AlertDialog/AlertDialog.tsx +2 -0
  387. package/src/AlertDialog/useImperativeAlertDialog.tsx +0 -2
  388. package/src/AppShell/AppShell.tsx +2 -0
  389. package/src/AspectRatio/AspectRatio.doc.mjs +28 -1
  390. package/src/AspectRatio/AspectRatio.test.tsx +142 -1
  391. package/src/AspectRatio/AspectRatio.tsx +70 -10
  392. package/src/AspectRatio/index.ts +5 -1
  393. package/src/Avatar/Avatar.doc.mjs +11 -0
  394. package/src/Avatar/Avatar.test.tsx +32 -1
  395. package/src/Avatar/Avatar.tsx +14 -22
  396. package/src/Avatar/AvatarStatusDot.tsx +2 -2
  397. package/src/AvatarGroup/AvatarGroup.doc.mjs +1 -0
  398. package/src/AvatarGroup/AvatarGroup.tsx +2 -2
  399. package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -2
  400. package/src/Banner/Banner.doc.mjs +8 -0
  401. package/src/Banner/Banner.test.tsx +38 -0
  402. package/src/Banner/Banner.tsx +8 -1
  403. package/src/Calendar/Calendar.doc.mjs +1 -1
  404. package/src/Calendar/Calendar.test.tsx +122 -17
  405. package/src/Calendar/Calendar.tsx +26 -5
  406. package/src/Calendar/dayCellUtils.ts +3 -1
  407. package/src/Calendar/styles.ts +12 -2
  408. package/src/Card/Card.doc.mjs +1 -1
  409. package/src/Card/Card.tsx +16 -6
  410. package/src/Carousel/Carousel.doc.mjs +12 -12
  411. package/src/Carousel/Carousel.test.tsx +13 -0
  412. package/src/Carousel/Carousel.tsx +4 -2
  413. package/src/Chat/Chat.doc.mjs +1 -1
  414. package/src/Chat/ChatComposerInput.test.tsx +27 -1
  415. package/src/Chat/ChatComposerInput.tsx +20 -15
  416. package/src/Chat/ChatDictationButton.test.tsx +43 -0
  417. package/src/Chat/ChatDictationButton.tsx +4 -4
  418. package/src/Chat/ChatLayoutScrollButton.test.tsx +33 -0
  419. package/src/Chat/ChatLayoutScrollButton.tsx +3 -1
  420. package/src/Chat/ChatMessageMetadata.test.tsx +32 -0
  421. package/src/Chat/ChatMessageMetadata.tsx +4 -6
  422. package/src/Chat/ChatSystemMessage.test.tsx +26 -11
  423. package/src/Chat/ChatSystemMessage.tsx +7 -7
  424. package/src/Chat/ChatTokenizedText.test.tsx +29 -16
  425. package/src/Chat/ChatTokenizedText.tsx +15 -8
  426. package/src/Chat/ChatToolCalls.test.tsx +55 -0
  427. package/src/Chat/ChatToolCalls.tsx +10 -12
  428. package/src/Chat/index.ts +1 -4
  429. package/src/Chat/useTriggerMenu.tsx +1 -4
  430. package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -3
  431. package/src/CheckboxInput/CheckboxInput.test.tsx +71 -4
  432. package/src/CheckboxInput/CheckboxInput.tsx +2 -0
  433. package/src/CheckboxList/CheckboxList.test.tsx +19 -0
  434. package/src/CheckboxList/CheckboxListItem.tsx +11 -2
  435. package/src/Citation/Citation.doc.mjs +5 -0
  436. package/src/ClickableCard/ClickableCard.tsx +45 -2
  437. package/src/CodeBlock/CodeBlock.doc.mjs +7 -2
  438. package/src/CodeBlock/CodeBlock.test.tsx +122 -3
  439. package/src/CodeBlock/CodeBlock.tsx +62 -4
  440. package/src/Collapsible/Collapsible.doc.mjs +8 -4
  441. package/src/Collapsible/Collapsible.test.tsx +403 -0
  442. package/src/Collapsible/Collapsible.tsx +85 -10
  443. package/src/Collapsible/CollapsibleGroup.doc.mjs +27 -3
  444. package/src/Collapsible/CollapsibleGroup.test.tsx +314 -0
  445. package/src/Collapsible/CollapsibleGroup.tsx +97 -9
  446. package/src/Collapsible/CollapsibleGroupContext.tsx +34 -2
  447. package/src/Collapsible/index.ts +1 -0
  448. package/src/Collapsible/useCollapsible.ts +20 -6
  449. package/src/CommandPalette/CommandPalette.doc.mjs +5 -0
  450. package/src/CommandPalette/CommandPalette.tsx +5 -3
  451. package/src/CommandPalette/CommandPaletteEmpty.doc.mjs +5 -0
  452. package/src/CommandPalette/CommandPaletteGroup.doc.mjs +10 -0
  453. package/src/CommandPalette/CommandPaletteInput.doc.mjs +6 -0
  454. package/src/CommandPalette/CommandPaletteItem.doc.mjs +6 -0
  455. package/src/CommandPalette/CommandPaletteList.doc.mjs +9 -0
  456. package/src/ContextMenu/ContextMenu.doc.mjs +15 -0
  457. package/src/ContextMenu/ContextMenu.test.tsx +87 -0
  458. package/src/ContextMenu/ContextMenu.tsx +87 -28
  459. package/src/ContextMenu/ContextMenuItem.doc.mjs +6 -0
  460. package/src/DateInput/DateInput.test.tsx +11 -20
  461. package/src/DateRangeInput/DateRangeInput.doc.mjs +9 -6
  462. package/src/DateRangeInput/DateRangeInput.test.tsx +31 -44
  463. package/src/DateTimeInput/DateTimeInput.doc.mjs +3 -2
  464. package/src/DateTimeInput/DateTimeInput.test.tsx +118 -16
  465. package/src/DateTimeInput/DateTimeInput.tsx +8 -2
  466. package/src/DateTimeInput/index.ts +1 -0
  467. package/src/Dialog/Dialog.doc.mjs +4 -0
  468. package/src/Dialog/DialogHeader.doc.mjs +45 -0
  469. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -1
  470. package/src/DropdownMenu/DropdownMenu.test.tsx +22 -2
  471. package/src/DropdownMenu/DropdownMenuItem.tsx +5 -17
  472. package/src/EmptyState/EmptyState.doc.mjs +1 -1
  473. package/src/Field/Field.test.tsx +1 -4
  474. package/src/Field/FieldLabel.test.tsx +2 -2
  475. package/src/FieldStatus/FieldStatus.test.tsx +282 -0
  476. package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +0 -3
  477. package/src/Grid/Grid.test.tsx +43 -18
  478. package/src/Grid/Grid.tsx +26 -9
  479. package/src/HoverCard/HoverCard.doc.mjs +6 -6
  480. package/src/HoverCard/useHoverCard.doc.mjs +5 -5
  481. package/src/HoverCard/useHoverCard.tsx +9 -2
  482. package/src/Icon/Icon.test.tsx +41 -29
  483. package/src/Icon/Icon.tsx +6 -2
  484. package/src/InputGroup/InputGroup.doc.mjs +1 -0
  485. package/src/InputGroup/InputGroup.tsx +2 -2
  486. package/src/InteractiveRoleContext/InteractiveRoleContext.test.tsx +185 -0
  487. package/src/Item/Item.tsx +1 -1
  488. package/src/Layer/useLayer.doc.mjs +2 -2
  489. package/src/Layer/useLayer.test.tsx +221 -2
  490. package/src/Layer/useLayer.tsx +69 -30
  491. package/src/Layout/Layout.test.tsx +285 -0
  492. package/src/Layout/LayoutContent.doc.mjs +12 -0
  493. package/src/Layout/LayoutPanel.doc.mjs +40 -0
  494. package/src/Layout/LayoutSlots.test.tsx +364 -0
  495. package/src/Lightbox/Lightbox.doc.mjs +5 -0
  496. package/src/Lightbox/Lightbox.test.tsx +123 -2
  497. package/src/Lightbox/Lightbox.tsx +29 -1
  498. package/src/Lightbox/useLightbox.tsx +0 -1
  499. package/src/Link/Link.tsx +0 -2
  500. package/src/Markdown/Markdown.tsx +9 -7
  501. package/src/Markdown/parser.perf.test.ts +34 -12
  502. package/src/MobileNav/MobileNav.test.tsx +56 -0
  503. package/src/MobileNav/MobileNav.tsx +13 -8
  504. package/src/NavMenu/NavMenu.doc.mjs +15 -0
  505. package/src/NumberInput/NumberInput.test.tsx +48 -3
  506. package/src/NumberInput/NumberInput.tsx +32 -15
  507. package/src/Outline/Outline.doc.mjs +2 -0
  508. package/src/Outline/parseOutlineFromMarkdown.test.ts +80 -0
  509. package/src/OverflowList/OverflowList.test.tsx +416 -0
  510. package/src/Overlay/Overlay.doc.mjs +6 -0
  511. package/src/Overlay/Overlay.test.tsx +356 -0
  512. package/src/Overlay/useOverlay.tsx +0 -3
  513. package/src/Pagination/Pagination.test.tsx +162 -0
  514. package/src/Pagination/Pagination.tsx +80 -26
  515. package/src/Popover/Popover.doc.mjs +6 -6
  516. package/src/Popover/Popover.test.tsx +65 -0
  517. package/src/Popover/usePopover.doc.mjs +1 -1
  518. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  519. package/src/PowerSearch/PowerSearch.test.tsx +109 -1
  520. package/src/PowerSearch/PowerSearch.tsx +37 -16
  521. package/src/ProgressBar/ProgressBar.doc.mjs +2 -0
  522. package/src/ProgressBar/ProgressBar.test.tsx +30 -0
  523. package/src/ProgressBar/ProgressBar.tsx +12 -5
  524. package/src/RadioList/RadioList.test.tsx +19 -0
  525. package/src/RadioList/RadioListItem.tsx +9 -4
  526. package/src/Resizable/ResizeHandle.test.tsx +218 -0
  527. package/src/Resizable/ResizeHandle.tsx +22 -4
  528. package/src/SegmentedControl/SegmentedControl.doc.mjs +1 -1
  529. package/src/SegmentedControl/SegmentedControl.test.tsx +192 -0
  530. package/src/SegmentedControl/SegmentedControl.tsx +27 -5
  531. package/src/SegmentedControl/SegmentedControlItem.tsx +9 -4
  532. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  533. package/src/Selector/Selector.test.tsx +27 -1
  534. package/src/SideNav/SideNav.doc.mjs +7 -1
  535. package/src/SideNav/SideNav.test.tsx +66 -0
  536. package/src/SideNav/SideNav.tsx +6 -2
  537. package/src/SideNav/SideNavCollapseButton.tsx +4 -3
  538. package/src/SideNav/SideNavSection.tsx +6 -4
  539. package/src/SizeContext/SizeContext.test.tsx +226 -0
  540. package/src/Switch/Switch.doc.mjs +7 -7
  541. package/src/Switch/Switch.test.tsx +102 -3
  542. package/src/Switch/Switch.tsx +20 -7
  543. package/src/TabList/TabList.test.tsx +185 -1
  544. package/src/TabList/TabMenu.tsx +45 -9
  545. package/src/Table/BaseTable.tsx +13 -2
  546. package/src/Table/Table.doc.mjs +6 -1
  547. package/src/Table/Table.test.tsx +87 -0
  548. package/src/Table/TableBody.tsx +15 -2
  549. package/src/Table/TableFooter.tsx +15 -2
  550. package/src/Table/TableHeader.tsx +15 -2
  551. package/src/Table/index.ts +5 -0
  552. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +13 -0
  553. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +3 -1
  554. package/src/Table/plugins/groupedRows/index.ts +7 -0
  555. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +231 -0
  556. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +349 -0
  557. package/src/Table/plugins/pagination/paginateData.ts +5 -1
  558. package/src/Table/plugins/pagination/useTablePagination.test.tsx +13 -0
  559. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +1 -1
  560. package/src/Table/plugins/selection/useTableSelectionState.test.tsx +23 -0
  561. package/src/Table/plugins/selection/useTableSelectionState.tsx +11 -6
  562. package/src/Table/plugins/sortable/useTableSortableState.test.tsx +35 -1
  563. package/src/Table/plugins/sortable/useTableSortableState.tsx +8 -4
  564. package/src/Table/useTableGroupedRows.doc.mjs +71 -0
  565. package/src/TextArea/TextArea.test.tsx +3 -3
  566. package/src/TextInput/TextInput.test.tsx +3 -3
  567. package/src/Thumbnail/Thumbnail.test.tsx +36 -2
  568. package/src/Thumbnail/Thumbnail.tsx +4 -2
  569. package/src/TimeInput/TimeInput.test.tsx +37 -0
  570. package/src/TimeInput/TimeInput.tsx +11 -1
  571. package/src/Timestamp/Timestamp.doc.mjs +1 -1
  572. package/src/Timestamp/Timestamp.test.tsx +52 -0
  573. package/src/Timestamp/Timestamp.tsx +30 -16
  574. package/src/Toast/Toast.tsx +11 -3
  575. package/src/Toast/ToastViewport.test.tsx +64 -0
  576. package/src/Toast/ToastViewport.tsx +12 -0
  577. package/src/Toast/useToast.test.tsx +258 -0
  578. package/src/Toast/useToast.tsx +41 -0
  579. package/src/ToggleButton/ToggleButton.doc.mjs +1 -0
  580. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  581. package/src/Tokenizer/Tokenizer.test.tsx +54 -0
  582. package/src/Tokenizer/Tokenizer.tsx +5 -4
  583. package/src/Tooltip/Tooltip.doc.mjs +6 -6
  584. package/src/Tooltip/useTooltip.doc.mjs +5 -5
  585. package/src/Tooltip/useTooltip.tsx +12 -2
  586. package/src/TopNav/TopNav.doc.mjs +1 -1
  587. package/src/TopNav/TopNav.test.tsx +23 -7
  588. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +9 -2
  589. package/src/TreeList/TreeList.doc.mjs +2 -2
  590. package/src/Typeahead/BaseTypeahead.doc.mjs +19 -0
  591. package/src/Typeahead/BaseTypeahead.tsx +5 -2
  592. package/src/Typeahead/Typeahead.doc.mjs +1 -1
  593. package/src/Typeahead/Typeahead.test.tsx +45 -1
  594. package/src/VisuallyHidden/VisuallyHidden.tsx +0 -3
  595. package/src/__tests__/TestIcon.tsx +26 -0
  596. package/src/__tests__/fastRoleQueries.ts +66 -0
  597. package/src/docPropReferences.test.ts +178 -0
  598. package/src/docs-types.ts +9 -1
  599. package/src/hooks/focusableSelector.ts +1 -1
  600. package/src/hooks/index.ts +3 -0
  601. package/src/hooks/useFocusTrap.doc.mjs +4 -2
  602. package/src/hooks/useFocusTrap.test.tsx +149 -1
  603. package/src/hooks/useFocusTrap.ts +50 -1
  604. package/src/hooks/useHotkeys.doc.mjs +52 -0
  605. package/src/hooks/useHotkeys.test.ts +245 -0
  606. package/src/hooks/useHotkeys.ts +203 -0
  607. package/src/hooks/useInteractiveRole.ts +12 -4
  608. package/src/hooks/useStreamingText.test.ts +54 -19
  609. package/src/hooks/useStreamingText.ts +16 -5
  610. package/src/hooks/useTreeFocus.test.tsx +1 -3
  611. package/src/reset.css +29 -0
  612. package/src/theme/SyntaxTheme.doc.mjs +4 -4
  613. package/src/theme/defineTheme.ts +4 -13
  614. package/src/theme/derivedVarRegistry.test.ts +2 -2
  615. package/src/theme/expandColorScale.test.ts +29 -0
  616. package/src/theme/expandColorScale.ts +11 -6
  617. package/src/theme/hct.ts +9 -17
  618. package/src/theme/themingTargets.test.ts +353 -0
  619. package/src/theme/tokens.test.ts +182 -9
  620. package/src/theme/tokens.ts +239 -4
  621. package/src/theme/useTheme.test.tsx +126 -2
  622. package/src/theme/useTheme.ts +87 -6
  623. package/src/utils/color.test.ts +133 -0
  624. package/src/utils/color.ts +148 -0
  625. package/src/utils/composeEventHandlers.test.ts +71 -0
  626. package/src/utils/composeEventHandlers.ts +44 -0
  627. package/src/utils/index.ts +4 -0
  628. package/src/utils/mergeProps.test.ts +166 -0
  629. package/src/utils/sharedResizeObserver.test.ts +2 -2
  630. package/src/utils/timeParser.test.ts +13 -0
  631. package/src/utils/timeParser.ts +8 -5
  632. package/dist/Carousel/carousel.markers.stylex.d.ts +0 -7
  633. package/dist/Carousel/carousel.markers.stylex.d.ts.map +0 -1
  634. package/dist/Carousel/carousel.markers.stylex.js +0 -12
  635. package/src/Carousel/carousel.markers.stylex.ts +0 -10
@@ -10,6 +10,11 @@
10
10
  * build-time theme adapters, chart configuration, canvas/SVG rendering, tests,
11
11
  * or plain JS theme objects for other styling libraries.
12
12
  *
13
+ * Derived tokens can reference other tokens (`var(--color-accent)`) and use CSS
14
+ * color functions (`color-mix`). The resolver follows those references through
15
+ * the theme iteratively and evaluates the supported color functions so callers
16
+ * receive concrete raw values, not CSS expressions.
17
+ *
13
18
  * SYNC: When modified, update:
14
19
  * - /packages/core/src/theme/useTheme.ts
15
20
  * - /packages/core/src/theme/index.ts
@@ -21,6 +26,7 @@ import {
21
26
  type TokenName,
22
27
  type TokenValue,
23
28
  } from './defineTheme';
29
+ import {parseColor, formatColor} from '../utils/color';
24
30
 
25
31
  /** Resolved color mode used when choosing the side of light/dark token values. */
26
32
  export type ResolvedThemeMode = 'light' | 'dark';
@@ -144,14 +150,243 @@ function resolveXDSTokenValue(
144
150
  return value;
145
151
  }
146
152
 
153
+ // =============================================================================
154
+ // Reference resolution — turn token expressions into concrete raw values
155
+ // =============================================================================
156
+ //
157
+ // Generated themes emit derived tokens as references to other tokens rather
158
+ // than baked-in values, so a scoped CSS override of a base token re-themes the
159
+ // subtree that references it. The CSS cascade resolves those references, but
160
+ // non-CSS consumers (canvas, SVG, data-viz) need the concrete value. These
161
+ // helpers replay the same resolution in JS: follow `var()` references through
162
+ // the resolved token map (iteratively, guarding against cycles) and evaluate
163
+ // the CSS color functions used by the theme generator against those values.
164
+
165
+ /** Index of the `)` matching the `(` at `openIndex`, or -1 when unbalanced. */
166
+ function findMatchingParen(input: string, openIndex: number): number {
167
+ let depth = 0;
168
+ for (let i = openIndex; i < input.length; i++) {
169
+ const char = input[i];
170
+ if (char === '(') {
171
+ depth++;
172
+ } else if (char === ')') {
173
+ depth--;
174
+ if (depth === 0) {
175
+ return i;
176
+ }
177
+ }
178
+ }
179
+ return -1;
180
+ }
181
+
182
+ /** Split a color-mix component into its color and optional percentage. */
183
+ function parseMixComponent(
184
+ part: string,
185
+ ): {color: string; percentage: number | null} | null {
186
+ const trimmed = part.trim();
187
+ const match = trimmed.match(/\s+([\d.]+)%$/);
188
+ if (match) {
189
+ return {
190
+ color: trimmed.slice(0, match.index).trim(),
191
+ percentage: parseFloat(match[1]),
192
+ };
193
+ }
194
+ return {color: trimmed, percentage: null};
195
+ }
196
+
197
+ /**
198
+ * Evaluate `color-mix(in <space>, c1 [p1], c2 [p2])` to a concrete color.
199
+ *
200
+ * Supports the `srgb` color space (the one the theme generator emits) using
201
+ * the CSS Color 5 algorithm: normalize the percentages, interpolate the
202
+ * premultiplied channels, then apply the alpha multiplier when the mix weights
203
+ * sum to less than 100%. Returns null for anything it can't evaluate so the
204
+ * original expression is preserved rather than guessed.
205
+ */
206
+ function evaluateColorMix(body: string): string | null {
207
+ const spaceMatch = body.match(/^in\s+([\w-]+)\s*,\s*(.+)$/s);
208
+ if (!spaceMatch) {
209
+ return null;
210
+ }
211
+ const [, colorSpace, rest] = spaceMatch;
212
+ if (colorSpace.toLowerCase() !== 'srgb') {
213
+ return null;
214
+ }
215
+
216
+ const split = splitTopLevelComma(rest);
217
+ if (split === null) {
218
+ return null;
219
+ }
220
+ const first = parseMixComponent(split[0]);
221
+ const second = parseMixComponent(split[1]);
222
+ if (first === null || second === null) {
223
+ return null;
224
+ }
225
+
226
+ const c1 = parseColor(first.color);
227
+ const c2 = parseColor(second.color);
228
+ if (c1 === null || c2 === null) {
229
+ return null;
230
+ }
231
+
232
+ // Fill in omitted percentages, then normalize so they sum to 100%.
233
+ let p1: number;
234
+ let p2: number;
235
+ if (first.percentage !== null && second.percentage !== null) {
236
+ p1 = first.percentage;
237
+ p2 = second.percentage;
238
+ } else if (first.percentage !== null) {
239
+ p1 = first.percentage;
240
+ p2 = 100 - p1;
241
+ } else if (second.percentage !== null) {
242
+ p2 = second.percentage;
243
+ p1 = 100 - p2;
244
+ } else {
245
+ p1 = 50;
246
+ p2 = 50;
247
+ }
248
+ const sum = p1 + p2;
249
+ if (sum <= 0) {
250
+ return null;
251
+ }
252
+ const w1 = p1 / sum;
253
+ const w2 = p2 / sum;
254
+ const alphaMultiplier = sum < 100 ? sum / 100 : 1;
255
+
256
+ // Interpolate in premultiplied sRGB, then un-premultiply.
257
+ const mixedA = w1 * c1.a + w2 * c2.a;
258
+ const premix = (k1: number, k2: number): number =>
259
+ w1 * k1 * c1.a + w2 * k2 * c2.a;
260
+ const rp = premix(c1.r, c2.r);
261
+ const gp = premix(c1.g, c2.g);
262
+ const bp = premix(c1.b, c2.b);
263
+ const rgb =
264
+ mixedA === 0
265
+ ? {r: 0, g: 0, b: 0}
266
+ : {r: rp / mixedA, g: gp / mixedA, b: bp / mixedA};
267
+
268
+ return formatColor({...rgb, a: mixedA * alphaMultiplier});
269
+ }
270
+
271
+ /** Evaluate every supported color function in an expression, innermost first. */
272
+ function evaluateColorFunctions(expr: string): string {
273
+ const idx = expr.indexOf('color-mix(');
274
+ if (idx === -1) {
275
+ return expr;
276
+ }
277
+ const openIndex = idx + 'color-mix'.length;
278
+ const closeIndex = findMatchingParen(expr, openIndex);
279
+ if (closeIndex === -1) {
280
+ return expr;
281
+ }
282
+ const body = evaluateColorFunctions(expr.slice(openIndex + 1, closeIndex));
283
+ const evaluated = evaluateColorMix(body);
284
+ const replacement = evaluated ?? `color-mix(${body})`;
285
+ return (
286
+ expr.slice(0, idx) +
287
+ replacement +
288
+ evaluateColorFunctions(expr.slice(closeIndex + 1))
289
+ );
290
+ }
291
+
292
+ /**
293
+ * Substitute `var(--name[, fallback])` references with their resolved values.
294
+ * `seen` tracks the reference chain so cycles resolve to the literal reference
295
+ * instead of recursing forever.
296
+ */
297
+ function substituteVars(
298
+ expr: string,
299
+ raw: Record<string, string>,
300
+ cache: Record<string, string>,
301
+ seen: Set<string>,
302
+ ): string {
303
+ const start = expr.indexOf('var(');
304
+ if (start === -1) {
305
+ return expr;
306
+ }
307
+ const openIndex = start + 'var'.length;
308
+ const closeIndex = findMatchingParen(expr, openIndex);
309
+ if (closeIndex === -1) {
310
+ return expr;
311
+ }
312
+
313
+ const inner = expr.slice(openIndex + 1, closeIndex);
314
+ const commaSplit = splitTopLevelComma(inner);
315
+ const name = (commaSplit ? commaSplit[0] : inner).trim();
316
+ const fallback = commaSplit ? commaSplit[1] : null;
317
+
318
+ let replacement: string;
319
+ if (seen.has(name)) {
320
+ replacement = expr.slice(start, closeIndex + 1);
321
+ } else if (name in raw) {
322
+ seen.add(name);
323
+ replacement = resolveReference(name, raw, cache, seen);
324
+ seen.delete(name);
325
+ } else if (fallback !== null) {
326
+ replacement = substituteVars(fallback.trim(), raw, cache, seen);
327
+ } else {
328
+ replacement = expr.slice(start, closeIndex + 1);
329
+ }
330
+
331
+ const rest = substituteVars(expr.slice(closeIndex + 1), raw, cache, seen);
332
+ return expr.slice(0, start) + replacement + rest;
333
+ }
334
+
335
+ /** Fully resolve a single expression: substitute references, then evaluate colors. */
336
+ function resolveExpression(
337
+ expr: string,
338
+ raw: Record<string, string>,
339
+ cache: Record<string, string>,
340
+ seen: Set<string>,
341
+ ): string {
342
+ if (!expr.includes('var(') && !expr.includes('color-mix(')) {
343
+ return expr;
344
+ }
345
+ const substituted = substituteVars(expr, raw, cache, seen);
346
+ return evaluateColorFunctions(substituted);
347
+ }
348
+
349
+ /** Resolve one token by name, memoizing the result in `cache`. */
350
+ function resolveReference(
351
+ name: string,
352
+ raw: Record<string, string>,
353
+ cache: Record<string, string>,
354
+ seen: Set<string>,
355
+ ): string {
356
+ if (name in cache) {
357
+ return cache[name];
358
+ }
359
+ const value = raw[name];
360
+ if (value === undefined) {
361
+ return '';
362
+ }
363
+ const resolved = resolveExpression(value, raw, cache, seen);
364
+ cache[name] = resolved;
365
+ return resolved;
366
+ }
367
+
368
+ /** Resolve every reference/color function in a raw token map to concrete values. */
369
+ function resolveReferences(
370
+ raw: Record<string, string>,
371
+ ): Record<string, string> {
372
+ const cache: Record<string, string> = {};
373
+ for (const name of Object.keys(raw)) {
374
+ resolveReference(name, raw, cache, new Set<string>());
375
+ }
376
+ return cache;
377
+ }
378
+
147
379
  /**
148
380
  * Resolve all Astryx token values for a theme and effective color mode.
149
381
  *
150
382
  * The result starts with `tokenDefaults`, applies `theme.tokens`, then
151
383
  * reapplies `theme.__inputTokens` when available so explicit tuple overrides
152
384
  * retain their original light/dark sides instead of relying on CSS parsing.
153
- * This mirrors the token resolution used by `useTheme()` but does not need
154
- * React context or media queries.
385
+ * A final pass resolves any `var()` references between tokens and evaluates
386
+ * the CSS color functions the theme generator emits (e.g. `color-mix`), so
387
+ * derived tokens like `--color-text-accent` return concrete values rather than
388
+ * `var(--color-accent)`. This mirrors the token resolution used by
389
+ * `useTheme()` but does not need React context or media queries.
155
390
  *
156
391
  * Pass `theme` as null/undefined to resolve defaults only.
157
392
  */
@@ -167,7 +402,7 @@ export function resolveThemeTokens(
167
402
  }
168
403
 
169
404
  if (theme == null) {
170
- return resolved;
405
+ return resolveReferences(resolved);
171
406
  }
172
407
 
173
408
  for (const [key, value] of Object.entries(theme.tokens)) {
@@ -182,7 +417,7 @@ export function resolveThemeTokens(
182
417
  }
183
418
  }
184
419
 
185
- return resolved;
420
+ return resolveReferences(resolved);
186
421
  }
187
422
 
188
423
  /** Resolve one Astryx token value for a theme and effective color mode. */
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
- import {describe, it, expect, vi} from 'vitest';
4
- import {renderHook} from '@testing-library/react';
3
+ import {describe, it, expect, vi, afterEach} from 'vitest';
4
+ import {render, renderHook, act, waitFor} from '@testing-library/react';
5
5
  import React from 'react';
6
6
  import {Theme} from './Theme';
7
7
  import {defineTheme} from './defineTheme';
@@ -122,4 +122,128 @@ describe('useTheme', () => {
122
122
  resolveThemeTokens(testTheme, {mode: 'dark'}),
123
123
  );
124
124
  });
125
+
126
+ it('resolves derived accent tokens to raw values, not var()/color-mix', () => {
127
+ const brandTheme = defineTheme({name: 'brand', color: {accent: '#0064E0'}});
128
+ const {result} = renderHook(() => useTheme(), {
129
+ wrapper: ({children}) => (
130
+ <Theme theme={brandTheme} mode="light">
131
+ {children}
132
+ </Theme>
133
+ ),
134
+ });
135
+
136
+ const accent = result.current.token('--color-accent');
137
+ expect(result.current.token('--color-text-accent')).toBe(accent);
138
+ expect(result.current.token('--color-icon-accent')).toBe(accent);
139
+ expect(result.current.token('--color-accent-muted')).toMatch(/^(#|rgb)/);
140
+ expect(result.current.token('--color-accent-muted')).not.toContain('var(');
141
+ expect(result.current.token('--color-accent-muted')).not.toContain(
142
+ 'color-mix',
143
+ );
144
+ });
145
+ });
146
+
147
+ // Covers the fallback used when a component calls useTheme() with no
148
+ // ThemeContext ancestor reachable — e.g. a detached tree (useToast's
149
+ // fallback viewport, other portals appended straight to document.body).
150
+ // Root Theme instances sync their mode to <html data-theme> specifically so
151
+ // this fallback can resolve the app's actual mode instead of jumping
152
+ // straight to OS preference (see Theme.tsx's useRootThemeSync).
153
+ describe('useTheme mode resolution without a ThemeContext ancestor', () => {
154
+ afterEach(async () => {
155
+ // The hook from each `it` below is still mounted and subscribed to the
156
+ // shared MutationObserver when this runs (RTL's own cleanup — which
157
+ // unmounts it — is registered after this file's afterEach), so removing
158
+ // the attribute here triggers a live state update; flush it inside act
159
+ // so React doesn't warn about an update outside one.
160
+ await act(async () => {
161
+ document.documentElement.removeAttribute('data-theme');
162
+ });
163
+ });
164
+
165
+ it('resolves mode from <html data-theme> when set', () => {
166
+ document.documentElement.setAttribute('data-theme', 'dark');
167
+ const {result} = renderHook(() => useTheme());
168
+ expect(result.current.mode).toBe('dark');
169
+ });
170
+
171
+ it('falls back to OS preference when <html data-theme> is absent', () => {
172
+ // useMediaQuery is mocked to false (light) at the top of this file.
173
+ const {result} = renderHook(() => useTheme());
174
+ expect(result.current.mode).toBe('light');
175
+ });
176
+
177
+ it('stays live when <html data-theme> changes after mount', async () => {
178
+ const {result} = renderHook(() => useTheme());
179
+ expect(result.current.mode).toBe('light');
180
+
181
+ act(() => {
182
+ document.documentElement.setAttribute('data-theme', 'dark');
183
+ });
184
+
185
+ await waitFor(() => expect(result.current.mode).toBe('dark'));
186
+ });
187
+ });
188
+
189
+ // Covers the singleton MutationObserver + no-op gating in useRootThemeModeAttr:
190
+ // provider-path consumers (a ThemeContext ancestor is reachable) must not
191
+ // create an observer or react to <html data-theme> at all, and every
192
+ // no-context consumer must share exactly one observer, refcounted down to
193
+ // zero as they unmount.
194
+ describe('useTheme root-attribute observer lifecycle', () => {
195
+ afterEach(() => {
196
+ document.documentElement.removeAttribute('data-theme');
197
+ // vi.stubGlobal'd MutationObserver stubs below are torn down here even if
198
+ // a test fails partway through, instead of relying on a manual restore
199
+ // line at the end of each test that a mid-test throw would skip.
200
+ vi.unstubAllGlobals();
201
+ });
202
+
203
+ it('creates no observer and does not re-render provider-path consumers when <html data-theme> changes', () => {
204
+ const ObserverSpy = vi.fn();
205
+ vi.stubGlobal('MutationObserver', ObserverSpy);
206
+
207
+ const renders = {count: 0};
208
+ function Consumer() {
209
+ useTheme();
210
+ renders.count++;
211
+ return null;
212
+ }
213
+
214
+ render(
215
+ <Theme theme={testTheme} mode="light">
216
+ <Consumer />
217
+ </Theme>,
218
+ );
219
+
220
+ expect(ObserverSpy).not.toHaveBeenCalled();
221
+
222
+ const before = renders.count;
223
+ act(() => {
224
+ document.documentElement.setAttribute('data-theme', 'dark');
225
+ });
226
+ expect(renders.count).toBe(before);
227
+ });
228
+
229
+ it('shares one observer across multiple no-context consumers and disconnects once all unmount', () => {
230
+ const observe = vi.fn();
231
+ const disconnect = vi.fn();
232
+ const ObserverSpy = vi.fn().mockImplementation(function () {
233
+ return {observe, disconnect};
234
+ });
235
+ vi.stubGlobal('MutationObserver', ObserverSpy);
236
+
237
+ const first = renderHook(() => useTheme());
238
+ const second = renderHook(() => useTheme());
239
+
240
+ expect(ObserverSpy).toHaveBeenCalledTimes(1);
241
+ expect(observe).toHaveBeenCalledTimes(1);
242
+
243
+ first.unmount();
244
+ expect(disconnect).not.toHaveBeenCalled();
245
+
246
+ second.unmount();
247
+ expect(disconnect).toHaveBeenCalledTimes(1);
248
+ });
125
249
  });
@@ -9,14 +9,19 @@
9
9
  * @position Theme hook; used by data viz, canvas, and non-CSS consumers
10
10
  *
11
11
  * Provides synchronous access to theme token values resolved for the
12
- * current color mode — no DOM reads, no double render. Token resolution
13
- * is shared with the server-safe helpers in ./tokens.ts.
12
+ * current color mode — no DOM reads on the provider path, no double render.
13
+ * Without a reachable ThemeContext it consults `<html data-theme>` (kept in
14
+ * sync by Theme) via a single shared, refcounted MutationObserver before
15
+ * assuming OS preference; provider-path consumers subscribe to a no-op
16
+ * store instead (the same args-switch technique useMediaQuery uses), so
17
+ * mounting under a Theme never creates an observer. Token resolution is
18
+ * shared with the server-safe helpers in ./tokens.ts.
14
19
  *
15
20
  * SYNC: When modified, update:
16
21
  * - /packages/core/src/theme/index.ts
17
22
  */
18
23
 
19
- import {createContext, use, useMemo} from 'react';
24
+ import {createContext, use, useMemo, useSyncExternalStore} from 'react';
20
25
  import type {ThemeMode} from './types';
21
26
  import type {DefinedTheme} from './defineTheme';
22
27
  import {resolveThemeTokens} from './tokens';
@@ -87,6 +92,76 @@ export interface UseThemeReturn {
87
92
  // Hook
88
93
  // =============================================================================
89
94
 
95
+ function getRootThemeAttrSnapshot(): 'light' | 'dark' | null {
96
+ if (typeof document === 'undefined') {
97
+ return null;
98
+ }
99
+ const attr = document.documentElement.getAttribute('data-theme');
100
+ return attr === 'light' || attr === 'dark' ? attr : null;
101
+ }
102
+
103
+ function getRootThemeAttrServerSnapshot(): 'light' | 'dark' | null {
104
+ return null;
105
+ }
106
+
107
+ function getNullThemeMode(): null {
108
+ return null;
109
+ }
110
+
111
+ // Every no-context consumer wants the same <html data-theme> attribute, so
112
+ // one MutationObserver — refcounted via this listener set — serves all of
113
+ // them instead of one per consumer.
114
+ const rootThemeAttrListeners = new Set<() => void>();
115
+ let rootThemeAttrObserver: MutationObserver | null = null;
116
+
117
+ function notifyRootThemeAttrListeners(): void {
118
+ for (const listener of rootThemeAttrListeners) {
119
+ listener();
120
+ }
121
+ }
122
+
123
+ function subscribeRootThemeAttr(onStoreChange: () => void): () => void {
124
+ rootThemeAttrListeners.add(onStoreChange);
125
+
126
+ if (
127
+ rootThemeAttrListeners.size === 1 &&
128
+ typeof MutationObserver !== 'undefined'
129
+ ) {
130
+ rootThemeAttrObserver = new MutationObserver(notifyRootThemeAttrListeners);
131
+ rootThemeAttrObserver.observe(document.documentElement, {
132
+ attributes: true,
133
+ attributeFilter: ['data-theme'],
134
+ });
135
+ }
136
+
137
+ return () => {
138
+ rootThemeAttrListeners.delete(onStoreChange);
139
+ if (rootThemeAttrListeners.size === 0 && rootThemeAttrObserver) {
140
+ rootThemeAttrObserver.disconnect();
141
+ rootThemeAttrObserver = null;
142
+ }
143
+ };
144
+ }
145
+
146
+ function subscribeNoop(): () => void {
147
+ return () => {};
148
+ }
149
+
150
+ /**
151
+ * Reads the root Theme's mode off `<html data-theme>`, live via the shared
152
+ * MutationObserver. Null means no root Theme has synced it (none present,
153
+ * or mode is 'system'). `hasCtx` switches which store this subscribes to —
154
+ * a no-op store when a ThemeContext exists — instead of skipping the hook
155
+ * call, so provider-path consumers never touch the DOM or the observer.
156
+ */
157
+ function useRootThemeModeAttr(hasCtx: boolean): 'light' | 'dark' | null {
158
+ return useSyncExternalStore(
159
+ hasCtx ? subscribeNoop : subscribeRootThemeAttr,
160
+ hasCtx ? getNullThemeMode : getRootThemeAttrSnapshot,
161
+ getRootThemeAttrServerSnapshot,
162
+ );
163
+ }
164
+
90
165
  /**
91
166
  * Access the current Astryx theme's token values, resolved for the active color mode.
92
167
  *
@@ -95,8 +170,9 @@ export interface UseThemeReturn {
95
170
  * (e.g. Vega, D3, Chart.js) that need concrete values rather than
96
171
  * CSS custom property references.
97
172
  *
98
- * When called outside an <Theme> provider, returns the default theme
99
- * tokens resolved against the current system color mode.
173
+ * When called outside a <Theme> provider, resolves mode from the root
174
+ * Theme's `<html data-theme>` when one is present, falling back to the
175
+ * current system color mode otherwise.
100
176
  *
101
177
  * @example
102
178
  * ```
@@ -114,10 +190,15 @@ export interface UseThemeReturn {
114
190
  export function useTheme(): UseThemeReturn {
115
191
  const ctx = use(ThemeContext);
116
192
 
193
+ // Falls back to the root Theme's mode via <html data-theme> when there's
194
+ // no ThemeContext ancestor (e.g. useToast's detached fallback viewport).
195
+ // Resolves to null when `ctx` is present, so it has no effect there.
196
+ const rootAttrMode = useRootThemeModeAttr(ctx != null);
197
+
117
198
  // Resolve 'system' to 'light' | 'dark' using the OS preference
118
199
  const prefersDark = useMediaQuery('(prefers-color-scheme: dark)');
119
200
 
120
- const mode = ctx?.mode ?? 'system';
201
+ const mode = ctx?.mode ?? rootAttrMode ?? 'system';
121
202
  const theme = ctx?.theme ?? null;
122
203
 
123
204
  const effectiveMode: 'light' | 'dark' =
@@ -0,0 +1,133 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, expect, it} from 'vitest';
4
+ import {parseHex, parseRgb, parseColor, formatHex, formatColor} from './color';
5
+
6
+ describe('parseHex', () => {
7
+ it('parses #rrggbb', () => {
8
+ expect(parseHex('#0064E0')).toEqual({r: 0, g: 100, b: 224, a: 1});
9
+ });
10
+
11
+ it('parses without a leading #', () => {
12
+ expect(parseHex('0064E0')).toEqual({r: 0, g: 100, b: 224, a: 1});
13
+ });
14
+
15
+ it('expands #rgb shorthand', () => {
16
+ expect(parseHex('#abc')).toEqual({r: 0xaa, g: 0xbb, b: 0xcc, a: 1});
17
+ });
18
+
19
+ it('parses #rrggbbaa alpha', () => {
20
+ expect(parseHex('#00000080')).toEqual({r: 0, g: 0, b: 0, a: 128 / 255});
21
+ });
22
+
23
+ it('expands #rgba shorthand alpha', () => {
24
+ expect(parseHex('#f008')).toEqual({
25
+ r: 0xff,
26
+ g: 0,
27
+ b: 0,
28
+ a: 0x88 / 255,
29
+ });
30
+ });
31
+
32
+ it('returns null for non-hex input', () => {
33
+ expect(parseHex('rgb(0,0,0)')).toBeNull();
34
+ expect(parseHex('#12')).toBeNull();
35
+ expect(parseHex('#zzzzzz')).toBeNull();
36
+ // @ts-expect-error runtime guard for non-string input
37
+ expect(parseHex(null)).toBeNull();
38
+ });
39
+ });
40
+
41
+ describe('parseRgb', () => {
42
+ it('parses comma-separated rgb()', () => {
43
+ expect(parseRgb('rgb(0, 100, 224)')).toEqual({
44
+ r: 0,
45
+ g: 100,
46
+ b: 224,
47
+ a: 1,
48
+ });
49
+ });
50
+
51
+ it('parses rgba() with alpha', () => {
52
+ expect(parseRgb('rgba(0, 0, 0, 0.5)')).toEqual({r: 0, g: 0, b: 0, a: 0.5});
53
+ });
54
+
55
+ it('parses space-separated with slash alpha', () => {
56
+ expect(parseRgb('rgb(0 100 224 / 0.25)')).toEqual({
57
+ r: 0,
58
+ g: 100,
59
+ b: 224,
60
+ a: 0.25,
61
+ });
62
+ });
63
+
64
+ it('parses percentage channels', () => {
65
+ expect(parseRgb('rgb(100%, 0%, 0%)')).toEqual({
66
+ r: 255,
67
+ g: 0,
68
+ b: 0,
69
+ a: 1,
70
+ });
71
+ });
72
+
73
+ it('clamps alpha and channels into range', () => {
74
+ expect(parseRgb('rgba(300, -20, 10, 2)')).toEqual({
75
+ r: 255,
76
+ g: 0,
77
+ b: 10,
78
+ a: 1,
79
+ });
80
+ });
81
+
82
+ it('returns null when it cannot parse', () => {
83
+ expect(parseRgb('rgb(0, 0)')).toBeNull();
84
+ expect(parseRgb('#000000')).toBeNull();
85
+ });
86
+ });
87
+
88
+ describe('parseColor', () => {
89
+ it('routes hex and rgb strings to the right parser', () => {
90
+ expect(parseColor('#FFFFFF')).toEqual({r: 255, g: 255, b: 255, a: 1});
91
+ expect(parseColor('rgb(1, 2, 3)')).toEqual({r: 1, g: 2, b: 3, a: 1});
92
+ });
93
+
94
+ it('resolves the named colors used in token expressions', () => {
95
+ expect(parseColor('transparent')).toEqual({r: 0, g: 0, b: 0, a: 0});
96
+ expect(parseColor('BLACK')).toEqual({r: 0, g: 0, b: 0, a: 1});
97
+ expect(parseColor('white')).toEqual({r: 255, g: 255, b: 255, a: 1});
98
+ });
99
+
100
+ it('returns null for unsupported colors so callers can preserve them', () => {
101
+ expect(parseColor('var(--color-accent)')).toBeNull();
102
+ expect(parseColor('oklch(0.5 0.1 200)')).toBeNull();
103
+ expect(parseColor('rebeccapurple')).toBeNull();
104
+ });
105
+ });
106
+
107
+ describe('formatHex', () => {
108
+ it('formats channels as uppercase #RRGGBB', () => {
109
+ expect(formatHex(0, 100, 224)).toBe('#0064E0');
110
+ });
111
+
112
+ it('rounds and clamps out-of-range channels', () => {
113
+ expect(formatHex(-5, 300, 127.6)).toBe('#00FF80');
114
+ });
115
+ });
116
+
117
+ describe('formatColor', () => {
118
+ it('formats opaque colors as hex', () => {
119
+ expect(formatColor({r: 0, g: 100, b: 224, a: 1})).toBe('#0064E0');
120
+ });
121
+
122
+ it('formats translucent colors as rgba()', () => {
123
+ expect(formatColor({r: 0, g: 100, b: 224, a: 0.2})).toBe(
124
+ 'rgba(0, 100, 224, 0.2)',
125
+ );
126
+ });
127
+
128
+ it('round-trips through parseColor', () => {
129
+ const parsed = parseColor('rgba(10, 20, 30, 0.5)');
130
+ expect(parsed).not.toBeNull();
131
+ expect(formatColor(parsed!)).toBe('rgba(10, 20, 30, 0.5)');
132
+ });
133
+ });