@astryxdesign/core 0.3.0 → 0.4.0

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 (551) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +10 -2
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +22 -3
  5. package/dist/AppShell/AppShell.d.ts +2 -2
  6. package/dist/AppShell/AppShell.d.ts.map +1 -1
  7. package/dist/AppShell/AppShell.js +40 -9
  8. package/dist/AspectRatio/AspectRatio.d.ts +13 -0
  9. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  10. package/dist/AspectRatio/AspectRatio.js +9 -0
  11. package/dist/Avatar/Avatar.d.ts.map +1 -1
  12. package/dist/Avatar/Avatar.js +33 -20
  13. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroupOverflow.js +2 -3
  15. package/dist/Banner/Banner.d.ts.map +1 -1
  16. package/dist/Banner/Banner.js +15 -14
  17. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  18. package/dist/Breadcrumbs/BreadcrumbItem.js +21 -8
  19. package/dist/Breadcrumbs/index.d.ts +2 -1
  20. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  21. package/dist/Breadcrumbs/index.js +1 -0
  22. package/dist/Button/Button.d.ts.map +1 -1
  23. package/dist/Button/Button.js +11 -15
  24. package/dist/Calendar/Calendar.d.ts.map +1 -1
  25. package/dist/Calendar/Calendar.js +2 -1
  26. package/dist/Calendar/styles.d.ts +0 -2
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +0 -2
  29. package/dist/Carousel/Carousel.d.ts.map +1 -1
  30. package/dist/Carousel/Carousel.js +8 -12
  31. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  32. package/dist/Chat/ChatDictationButton.js +2 -1
  33. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  34. package/dist/Chat/ChatLayoutScrollButton.js +3 -1
  35. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  36. package/dist/Chat/ChatSendButton.js +4 -3
  37. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  38. package/dist/Chat/ChatToolCalls.js +17 -17
  39. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  40. package/dist/Chat/useTriggerMenu.js +2 -6
  41. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  42. package/dist/CheckboxInput/CheckboxInput.js +36 -125
  43. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  44. package/dist/ClickableCard/ClickableCard.js +3 -11
  45. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  46. package/dist/CodeBlock/CodeBlock.js +84 -67
  47. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  48. package/dist/Collapsible/Collapsible.js +35 -15
  49. package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -1
  50. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  51. package/dist/CommandPalette/CommandPaletteItem.js +6 -3
  52. package/dist/CommandPalette/CommandPaletteList.js +1 -1
  53. package/dist/ComplexSelector/ComplexSelector.d.ts +1 -1
  54. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  55. package/dist/ComplexSelector/ComplexSelector.js +35 -33
  56. package/dist/ContextMenu/ContextMenu.d.ts +2 -2
  57. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  58. package/dist/ContextMenu/ContextMenu.js +1 -1
  59. package/dist/ContextMenu/index.d.ts +2 -1
  60. package/dist/ContextMenu/index.d.ts.map +1 -1
  61. package/dist/ContextMenu/index.js +1 -0
  62. package/dist/DateInput/DateInput.d.ts +9 -2
  63. package/dist/DateInput/DateInput.d.ts.map +1 -1
  64. package/dist/DateInput/DateInput.js +24 -23
  65. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  66. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  67. package/dist/DateRangeInput/DateRangeInput.js +11 -16
  68. package/dist/DateTimeInput/DateTimeInput.d.ts +9 -1
  69. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  70. package/dist/DateTimeInput/DateTimeInput.js +22 -17
  71. package/dist/Dialog/Dialog.d.ts.map +1 -1
  72. package/dist/Dialog/Dialog.js +4 -4
  73. package/dist/DropdownMenu/DropdownMenu.d.ts +33 -8
  74. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  75. package/dist/DropdownMenu/DropdownMenu.js +62 -20
  76. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +8 -11
  77. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +32 -31
  79. package/dist/DropdownMenu/DropdownMenuDivider.d.ts +25 -0
  80. package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -0
  81. package/dist/DropdownMenu/DropdownMenuDivider.js +66 -0
  82. package/dist/DropdownMenu/DropdownMenuItem.d.ts +15 -2
  83. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuItem.js +20 -8
  85. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +5 -5
  86. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  87. package/dist/DropdownMenu/DropdownMenuRadioItem.js +24 -67
  88. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  89. package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -8
  90. package/dist/DropdownMenu/index.d.ts +2 -1
  91. package/dist/DropdownMenu/index.d.ts.map +1 -1
  92. package/dist/DropdownMenu/index.js +4 -0
  93. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  94. package/dist/DropdownMenu/renderDropdownItems.js +35 -27
  95. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  96. package/dist/EmptyState/EmptyState.js +9 -5
  97. package/dist/Field/InputClearButton.d.ts +16 -3
  98. package/dist/Field/InputClearButton.d.ts.map +1 -1
  99. package/dist/Field/InputClearButton.js +15 -4
  100. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  101. package/dist/HoverCard/useHoverCard.js +3 -19
  102. package/dist/Indicator/CheckIndicator.d.ts +25 -0
  103. package/dist/Indicator/CheckIndicator.d.ts.map +1 -0
  104. package/dist/Indicator/CheckIndicator.js +155 -0
  105. package/dist/Indicator/CheckboxIndicator.d.ts +22 -0
  106. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -0
  107. package/dist/Indicator/CheckboxIndicator.js +173 -0
  108. package/dist/Indicator/RadioIndicator.d.ts +23 -0
  109. package/dist/Indicator/RadioIndicator.d.ts.map +1 -0
  110. package/dist/Indicator/RadioIndicator.js +137 -0
  111. package/dist/Indicator/index.d.ts +24 -0
  112. package/dist/Indicator/index.d.ts.map +1 -0
  113. package/dist/Indicator/index.js +26 -0
  114. package/dist/Indicator/indicator.markers.stylex.d.ts +16 -0
  115. package/dist/Indicator/indicator.markers.stylex.d.ts.map +1 -0
  116. package/dist/Indicator/indicator.markers.stylex.js +21 -0
  117. package/dist/Indicator/indicatorRegistry.d.ts +71 -0
  118. package/dist/Indicator/indicatorRegistry.d.ts.map +1 -0
  119. package/dist/Indicator/indicatorRegistry.js +93 -0
  120. package/dist/Indicator/types.d.ts +167 -0
  121. package/dist/Indicator/types.d.ts.map +1 -0
  122. package/dist/Indicator/types.js +1 -0
  123. package/dist/Indicator/useIndicator.d.ts +18 -0
  124. package/dist/Indicator/useIndicator.d.ts.map +1 -0
  125. package/dist/Indicator/useIndicator.js +30 -0
  126. package/dist/Item/Item.d.ts.map +1 -1
  127. package/dist/Item/Item.js +4 -8
  128. package/dist/Layer/useLayer.d.ts +14 -0
  129. package/dist/Layer/useLayer.d.ts.map +1 -1
  130. package/dist/Layer/useLayer.js +25 -2
  131. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  132. package/dist/Lightbox/Lightbox.js +56 -53
  133. package/dist/Link/Link.d.ts.map +1 -1
  134. package/dist/Link/Link.js +4 -5
  135. package/dist/MobileNav/MobileNav.js +8 -8
  136. package/dist/MoreMenu/MoreMenu.d.ts +14 -1
  137. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  138. package/dist/MoreMenu/MoreMenu.js +4 -0
  139. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  140. package/dist/MultiSelector/MultiSelector.js +78 -75
  141. package/dist/NumberInput/NumberInput.d.ts +27 -1
  142. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  143. package/dist/NumberInput/NumberInput.js +230 -42
  144. package/dist/Outline/Outline.d.ts.map +1 -1
  145. package/dist/Outline/Outline.js +2 -3
  146. package/dist/Pagination/Pagination.d.ts.map +1 -1
  147. package/dist/Pagination/Pagination.js +61 -63
  148. package/dist/Popover/Popover.d.ts.map +1 -1
  149. package/dist/Popover/Popover.js +6 -8
  150. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  151. package/dist/PowerSearch/PowerSearch.js +1 -1
  152. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  153. package/dist/PowerSearch/PowerSearchEditPopover.js +7 -0
  154. package/dist/ProgressBar/ProgressBar.d.ts +11 -4
  155. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  156. package/dist/ProgressBar/ProgressBar.js +96 -6
  157. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  158. package/dist/RadioList/RadioListItem.js +29 -84
  159. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  160. package/dist/Resizable/ResizeHandle.js +2 -3
  161. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  162. package/dist/SegmentedControl/SegmentedControlItem.js +2 -3
  163. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  164. package/dist/SelectableCard/SelectableCard.js +3 -11
  165. package/dist/Selector/Selector.d.ts +2 -1
  166. package/dist/Selector/Selector.d.ts.map +1 -1
  167. package/dist/Selector/Selector.js +164 -94
  168. package/dist/Selector/hooks.d.ts +18 -6
  169. package/dist/Selector/hooks.d.ts.map +1 -1
  170. package/dist/Selector/hooks.js +57 -40
  171. package/dist/SideNav/SideNav.d.ts.map +1 -1
  172. package/dist/SideNav/SideNav.js +1 -1
  173. package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
  174. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  175. package/dist/SideNav/SideNavCollapseButton.js +29 -14
  176. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  177. package/dist/SideNav/SideNavHeading.js +56 -20
  178. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  179. package/dist/SideNav/SideNavItem.js +28 -22
  180. package/dist/Stack/stack.stylex.d.ts +3 -3
  181. package/dist/Switch/Switch.js +11 -10
  182. package/dist/TabList/Tab.d.ts.map +1 -1
  183. package/dist/TabList/Tab.js +2 -3
  184. package/dist/TabList/TabMenu.d.ts.map +1 -1
  185. package/dist/TabList/TabMenu.js +41 -19
  186. package/dist/Table/BaseTable.d.ts.map +1 -1
  187. package/dist/Table/BaseTable.js +8 -0
  188. package/dist/Table/index.d.ts +1 -1
  189. package/dist/Table/index.d.ts.map +1 -1
  190. package/dist/Table/index.js +1 -1
  191. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
  192. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  193. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +22 -18
  194. package/dist/Table/plugins/rowExpansion/index.d.ts +1 -1
  195. package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -1
  196. package/dist/Table/plugins/rowExpansion/index.js +1 -1
  197. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +41 -76
  198. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  199. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +94 -345
  200. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  201. package/dist/Table/plugins/sortable/useTableSortable.js +23 -4
  202. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  203. package/dist/Table/plugins/tree/useTableTreeData.js +29 -33
  204. package/dist/Table/tableContextMenu.d.ts.map +1 -1
  205. package/dist/Table/tableContextMenu.js +2 -1
  206. package/dist/Table/types.d.ts +11 -0
  207. package/dist/Table/types.d.ts.map +1 -1
  208. package/dist/TextArea/TextArea.d.ts +10 -1
  209. package/dist/TextArea/TextArea.d.ts.map +1 -1
  210. package/dist/TextArea/TextArea.js +16 -6
  211. package/dist/TextInput/TextInput.d.ts +10 -1
  212. package/dist/TextInput/TextInput.d.ts.map +1 -1
  213. package/dist/TextInput/TextInput.js +13 -19
  214. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  215. package/dist/Thumbnail/Thumbnail.js +32 -26
  216. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  217. package/dist/TimeInput/TimeInput.js +7 -15
  218. package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -1
  219. package/dist/Timestamp/TimestampHoverCard.js +16 -34
  220. package/dist/Token/Token.d.ts.map +1 -1
  221. package/dist/Token/Token.js +20 -11
  222. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  223. package/dist/Tokenizer/Tokenizer.js +4 -2
  224. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  225. package/dist/Tooltip/useTooltip.js +3 -19
  226. package/dist/TopNav/TopNav.d.ts.map +1 -1
  227. package/dist/TopNav/TopNav.js +6 -5
  228. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  229. package/dist/TopNav/TopNavHeading.js +54 -16
  230. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  231. package/dist/TopNav/TopNavItem.js +3 -9
  232. package/dist/TopNav/TopNavMegaMenu.d.ts +7 -0
  233. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  234. package/dist/TopNav/TopNavMegaMenu.js +146 -60
  235. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  236. package/dist/TopNav/TopNavMegaMenuItem.js +22 -3
  237. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  238. package/dist/TopNav/TopNavMenu.js +83 -38
  239. package/dist/TreeList/TreeList.d.ts.map +1 -1
  240. package/dist/TreeList/TreeList.js +13 -0
  241. package/dist/TreeList/TreeListBranches.d.ts +1 -1
  242. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  243. package/dist/TreeList/TreeListBranches.js +14 -4
  244. package/dist/TreeList/TreeListItem.d.ts +11 -1
  245. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  246. package/dist/TreeList/TreeListItem.js +57 -30
  247. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  248. package/dist/Typeahead/BaseTypeahead.js +16 -8
  249. package/dist/astryx.css +74 -85
  250. package/dist/astryx.umd.js +56 -56
  251. package/dist/astryx.umd.js.map +4 -4
  252. package/dist/hooks/containerReveal.stylex.d.ts +61 -0
  253. package/dist/hooks/containerReveal.stylex.d.ts.map +1 -0
  254. package/dist/hooks/containerReveal.stylex.js +63 -0
  255. package/dist/hooks/index.d.ts +3 -0
  256. package/dist/hooks/index.d.ts.map +1 -1
  257. package/dist/hooks/index.js +2 -0
  258. package/dist/hooks/useClipboard.d.ts +59 -0
  259. package/dist/hooks/useClipboard.d.ts.map +1 -0
  260. package/dist/hooks/useClipboard.js +106 -0
  261. package/dist/hooks/useContainerReveal.d.ts +14 -8
  262. package/dist/hooks/useContainerReveal.d.ts.map +1 -1
  263. package/dist/hooks/useContainerReveal.js +28 -69
  264. package/dist/hooks/useIndicatorFocusRing.d.ts +28 -0
  265. package/dist/hooks/useIndicatorFocusRing.d.ts.map +1 -0
  266. package/dist/hooks/useIndicatorFocusRing.js +96 -0
  267. package/dist/hooks/useLongPress.d.ts.map +1 -1
  268. package/dist/hooks/useLongPress.js +12 -2
  269. package/dist/hooks/useScrollLock.d.ts.map +1 -1
  270. package/dist/hooks/useScrollLock.js +33 -18
  271. package/dist/hooks/useStreamingText.d.ts +18 -3
  272. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  273. package/dist/hooks/useStreamingText.js +47 -7
  274. package/dist/hooks/useTreeFocus.d.ts.map +1 -1
  275. package/dist/hooks/useTreeFocus.js +9 -3
  276. package/dist/hooks/useTypeahead.d.ts +3 -2
  277. package/dist/hooks/useTypeahead.d.ts.map +1 -1
  278. package/dist/hooks/useTypeahead.js +19 -7
  279. package/dist/index.d.ts +1 -0
  280. package/dist/index.d.ts.map +1 -1
  281. package/dist/index.js +1 -0
  282. package/dist/theme/defineTheme.d.ts +16 -0
  283. package/dist/theme/defineTheme.d.ts.map +1 -1
  284. package/dist/theme/defineTheme.js +8 -0
  285. package/dist/theme/derivedVarRegistry.d.ts +8 -0
  286. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  287. package/dist/theme/derivedVarRegistry.js +14 -13
  288. package/dist/theme/expandColorScale.d.ts +3 -1
  289. package/dist/theme/expandColorScale.d.ts.map +1 -1
  290. package/dist/theme/expandColorScale.js +17 -7
  291. package/dist/theme/expandTypeScale.d.ts.map +1 -1
  292. package/dist/theme/expandTypeScale.js +17 -0
  293. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  294. package/dist/theme/generateThemeRules.js +11 -0
  295. package/dist/theme/index.d.ts +1 -0
  296. package/dist/theme/index.d.ts.map +1 -1
  297. package/dist/utils/focusOutline.stylex.d.ts +107 -0
  298. package/dist/utils/focusOutline.stylex.d.ts.map +1 -0
  299. package/dist/utils/focusOutline.stylex.js +130 -0
  300. package/dist/utils/focusReturn.d.ts +24 -0
  301. package/dist/utils/focusReturn.d.ts.map +1 -0
  302. package/dist/utils/focusReturn.js +29 -0
  303. package/dist/utils/index.d.ts +1 -0
  304. package/dist/utils/index.d.ts.map +1 -1
  305. package/dist/utils/index.js +1 -0
  306. package/dist/utils/mergeRefs.d.ts.map +1 -1
  307. package/dist/utils/mergeRefs.js +7 -5
  308. package/dist/utils/rtlStyles.d.ts +2 -2
  309. package/dist/utils/rtlStyles.js +2 -2
  310. package/dist/utils/themeProps.d.ts +20 -1
  311. package/dist/utils/themeProps.d.ts.map +1 -1
  312. package/dist/utils/themeProps.js +8 -2
  313. package/locales/en.json +12 -0
  314. package/locales/pseudo.json +9 -0
  315. package/package.json +7 -2
  316. package/src/AlertDialog/AlertDialog.doc.mjs +16 -3
  317. package/src/AlertDialog/AlertDialog.test.tsx +208 -1
  318. package/src/AlertDialog/AlertDialog.tsx +21 -3
  319. package/src/AppShell/AppShell.doc.mjs +11 -0
  320. package/src/AppShell/AppShell.test.tsx +139 -0
  321. package/src/AppShell/AppShell.tsx +32 -22
  322. package/src/AspectRatio/AspectRatio.doc.mjs +27 -3
  323. package/src/AspectRatio/AspectRatio.test.tsx +30 -0
  324. package/src/AspectRatio/AspectRatio.tsx +13 -0
  325. package/src/Avatar/Avatar.doc.mjs +2 -13
  326. package/src/Avatar/Avatar.test.tsx +33 -8
  327. package/src/Avatar/Avatar.tsx +52 -50
  328. package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -9
  329. package/src/Banner/Banner.tsx +9 -6
  330. package/src/Breadcrumbs/BreadcrumbItem.tsx +16 -6
  331. package/src/Breadcrumbs/index.ts +5 -1
  332. package/src/Button/Button.tsx +21 -41
  333. package/src/Calendar/Calendar.tsx +2 -1
  334. package/src/Calendar/styles.ts +0 -8
  335. package/src/Carousel/Carousel.doc.mjs +3 -0
  336. package/src/Carousel/Carousel.tsx +10 -6
  337. package/src/Chat/Chat.doc.mjs +2 -0
  338. package/src/Chat/ChatDictationButton.tsx +7 -1
  339. package/src/Chat/ChatLayoutScrollButton.test.tsx +22 -0
  340. package/src/Chat/ChatLayoutScrollButton.tsx +8 -1
  341. package/src/Chat/ChatSendButton.tsx +2 -3
  342. package/src/Chat/ChatToolCalls.test.tsx +35 -0
  343. package/src/Chat/ChatToolCalls.tsx +36 -16
  344. package/src/Chat/useTriggerMenu.tsx +2 -5
  345. package/src/CheckboxInput/CheckboxInput.doc.mjs +4 -2
  346. package/src/CheckboxInput/CheckboxInput.test.tsx +115 -0
  347. package/src/CheckboxInput/CheckboxInput.tsx +45 -202
  348. package/src/ClickableCard/ClickableCard.tsx +6 -11
  349. package/src/CodeBlock/CodeBlock.doc.mjs +3 -0
  350. package/src/CodeBlock/CodeBlock.test.tsx +91 -0
  351. package/src/CodeBlock/CodeBlock.tsx +57 -80
  352. package/src/Collapsible/Collapsible.tsx +22 -18
  353. package/src/CommandPalette/CommandPalette.test.tsx +29 -0
  354. package/src/CommandPalette/CommandPaletteItem.tsx +7 -4
  355. package/src/CommandPalette/CommandPaletteList.tsx +2 -2
  356. package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
  357. package/src/ComplexSelector/ComplexSelector.test.tsx +64 -0
  358. package/src/ComplexSelector/ComplexSelector.tsx +46 -29
  359. package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
  360. package/src/ContextMenu/ContextMenu.test.tsx +41 -0
  361. package/src/ContextMenu/ContextMenu.tsx +3 -3
  362. package/src/ContextMenu/index.ts +5 -1
  363. package/src/DateInput/DateInput.doc.mjs +18 -3
  364. package/src/DateInput/DateInput.test.tsx +93 -11
  365. package/src/DateInput/DateInput.tsx +41 -19
  366. package/src/DateRangeInput/DateRangeInput.doc.mjs +10 -2
  367. package/src/DateRangeInput/DateRangeInput.test.tsx +110 -14
  368. package/src/DateRangeInput/DateRangeInput.tsx +24 -12
  369. package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -2
  370. package/src/DateTimeInput/DateTimeInput.test.tsx +75 -0
  371. package/src/DateTimeInput/DateTimeInput.tsx +35 -8
  372. package/src/Dialog/Dialog.tsx +2 -9
  373. package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -9
  374. package/src/DropdownMenu/DropdownMenu.test.tsx +534 -4
  375. package/src/DropdownMenu/DropdownMenu.tsx +113 -52
  376. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +27 -30
  377. package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +34 -0
  378. package/src/DropdownMenu/DropdownMenuDivider.tsx +81 -0
  379. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +39 -4
  380. package/src/DropdownMenu/DropdownMenuItem.tsx +48 -10
  381. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +30 -76
  382. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +25 -19
  383. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +44 -14
  384. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +1 -5
  385. package/src/DropdownMenu/index.ts +8 -1
  386. package/src/DropdownMenu/renderDropdownItems.tsx +33 -34
  387. package/src/EmptyState/EmptyState.doc.mjs +4 -0
  388. package/src/EmptyState/EmptyState.test.tsx +62 -0
  389. package/src/EmptyState/EmptyState.tsx +16 -6
  390. package/src/Field/Field.doc.mjs +1 -0
  391. package/src/Field/InputClearButton.test.tsx +117 -0
  392. package/src/Field/InputClearButton.tsx +30 -3
  393. package/src/HoverCard/useHoverCard.tsx +2 -23
  394. package/src/Icon/Icon.doc.mjs +2 -1
  395. package/src/Indicator/CheckIndicator.tsx +174 -0
  396. package/src/Indicator/CheckboxIndicator.tsx +257 -0
  397. package/src/Indicator/Indicator.doc.mjs +344 -0
  398. package/src/Indicator/Indicator.test.tsx +393 -0
  399. package/src/Indicator/RadioIndicator.tsx +206 -0
  400. package/src/Indicator/index.ts +45 -0
  401. package/src/Indicator/indicator.markers.stylex.ts +19 -0
  402. package/src/Indicator/indicatorRegistry.test.tsx +106 -0
  403. package/src/Indicator/indicatorRegistry.ts +120 -0
  404. package/src/Indicator/types.ts +186 -0
  405. package/src/Indicator/useIndicator.ts +39 -0
  406. package/src/Item/Item.doc.mjs +1 -1
  407. package/src/Item/Item.tsx +7 -14
  408. package/src/Layer/useLayer.doc.mjs +2 -2
  409. package/src/Layer/useLayer.test.tsx +85 -0
  410. package/src/Layer/useLayer.tsx +39 -1
  411. package/src/Lightbox/Lightbox.doc.mjs +1 -1
  412. package/src/Lightbox/Lightbox.tsx +43 -38
  413. package/src/Link/Link.tsx +4 -11
  414. package/src/MobileNav/MobileNav.tsx +3 -3
  415. package/src/MoreMenu/MoreMenu.doc.mjs +31 -0
  416. package/src/MoreMenu/MoreMenu.test.tsx +68 -1
  417. package/src/MoreMenu/MoreMenu.tsx +19 -0
  418. package/src/MultiSelector/MultiSelector.doc.mjs +9 -1
  419. package/src/MultiSelector/MultiSelector.test.tsx +255 -16
  420. package/src/MultiSelector/MultiSelector.tsx +103 -99
  421. package/src/NumberInput/NumberInput.doc.mjs +265 -50
  422. package/src/NumberInput/NumberInput.test.tsx +726 -21
  423. package/src/NumberInput/NumberInput.tsx +353 -59
  424. package/src/Outline/Outline.tsx +2 -5
  425. package/src/Pagination/Pagination.doc.mjs +1 -1
  426. package/src/Pagination/Pagination.test.tsx +22 -7
  427. package/src/Pagination/Pagination.tsx +38 -35
  428. package/src/Popover/Popover.tsx +6 -7
  429. package/src/PowerSearch/PowerSearch.tsx +1 -1
  430. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +42 -0
  431. package/src/PowerSearch/PowerSearchEditPopover.tsx +7 -0
  432. package/src/ProgressBar/ProgressBar.doc.mjs +27 -5
  433. package/src/ProgressBar/ProgressBar.test.tsx +224 -1
  434. package/src/ProgressBar/ProgressBar.tsx +124 -22
  435. package/src/RadioList/RadioList.doc.mjs +4 -2
  436. package/src/RadioList/RadioListItem.tsx +31 -130
  437. package/src/Resizable/ResizeHandle.tsx +2 -9
  438. package/src/SegmentedControl/SegmentedControlItem.tsx +2 -9
  439. package/src/SelectableCard/SelectableCard.tsx +4 -9
  440. package/src/Selector/Selector.doc.mjs +7 -4
  441. package/src/Selector/Selector.test.tsx +935 -25
  442. package/src/Selector/Selector.tsx +189 -106
  443. package/src/Selector/hooks.ts +77 -50
  444. package/src/SideNav/SideNav.test.tsx +46 -0
  445. package/src/SideNav/SideNav.tsx +1 -0
  446. package/src/SideNav/SideNavCollapseButton.tsx +15 -10
  447. package/src/SideNav/SideNavHeading.tsx +48 -10
  448. package/src/SideNav/SideNavItem.tsx +20 -12
  449. package/src/Stack/Stack.doc.mjs +110 -0
  450. package/src/StatusDot/StatusDot.doc.mjs +12 -3
  451. package/src/Switch/Switch.test.tsx +32 -0
  452. package/src/Switch/Switch.tsx +8 -8
  453. package/src/TabList/Tab.tsx +2 -9
  454. package/src/TabList/TabMenu.tsx +14 -21
  455. package/src/Table/BaseTable.tsx +11 -0
  456. package/src/Table/index.ts +1 -4
  457. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +30 -14
  458. package/src/Table/plugins/rowExpansion/index.ts +1 -4
  459. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +125 -175
  460. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +115 -458
  461. package/src/Table/plugins/sortable/useTableSortable.tsx +2 -6
  462. package/src/Table/plugins/tree/useTableTreeData.tsx +43 -24
  463. package/src/Table/tableContextMenu.test.tsx +27 -0
  464. package/src/Table/tableContextMenu.tsx +1 -0
  465. package/src/Table/types.ts +11 -0
  466. package/src/Table/useTableGroupedRows.doc.mjs +1 -1
  467. package/src/Table/useTableRowExpansion.doc.mjs +43 -66
  468. package/src/TextArea/TextArea.doc.mjs +42 -2
  469. package/src/TextArea/TextArea.test.tsx +219 -0
  470. package/src/TextArea/TextArea.tsx +34 -7
  471. package/src/TextInput/TextInput.doc.mjs +18 -2
  472. package/src/TextInput/TextInput.test.tsx +189 -0
  473. package/src/TextInput/TextInput.tsx +25 -31
  474. package/src/Thumbnail/Thumbnail.tsx +2 -9
  475. package/src/TimeInput/TimeInput.doc.mjs +2 -2
  476. package/src/TimeInput/TimeInput.test.tsx +30 -3
  477. package/src/TimeInput/TimeInput.tsx +9 -26
  478. package/src/Timestamp/Timestamp.doc.mjs +4 -3
  479. package/src/Timestamp/TimestampHoverCard.tsx +13 -35
  480. package/src/Token/Token.tsx +5 -28
  481. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  482. package/src/Tokenizer/Tokenizer.test.tsx +45 -3
  483. package/src/Tokenizer/Tokenizer.tsx +10 -2
  484. package/src/Tooltip/useTooltip.tsx +2 -23
  485. package/src/TopNav/TopNav.tsx +1 -3
  486. package/src/TopNav/TopNavHeading.tsx +42 -13
  487. package/src/TopNav/TopNavItem.tsx +3 -21
  488. package/src/TopNav/TopNavMegaMenu.test.tsx +433 -33
  489. package/src/TopNav/TopNavMegaMenu.tsx +118 -53
  490. package/src/TopNav/TopNavMegaMenuItem.tsx +2 -9
  491. package/src/TopNav/TopNavMenu.tsx +34 -37
  492. package/src/TreeList/TreeList.doc.mjs +5 -0
  493. package/src/TreeList/TreeList.test.tsx +206 -7
  494. package/src/TreeList/TreeList.tsx +22 -0
  495. package/src/TreeList/TreeListBranches.tsx +25 -2
  496. package/src/TreeList/TreeListItem.tsx +89 -52
  497. package/src/Typeahead/BaseTypeahead.tsx +19 -6
  498. package/src/Typeahead/Typeahead.doc.mjs +1 -0
  499. package/src/Typeahead/Typeahead.test.tsx +76 -3
  500. package/src/hooks/containerReveal.stylex.ts +102 -0
  501. package/src/hooks/index.ts +4 -0
  502. package/src/hooks/useClipboard.doc.mjs +87 -0
  503. package/src/hooks/useClipboard.test.tsx +151 -0
  504. package/src/hooks/useClipboard.ts +135 -0
  505. package/src/hooks/useContainerReveal.doc.mjs +7 -7
  506. package/src/hooks/useContainerReveal.test.tsx +42 -62
  507. package/src/hooks/useContainerReveal.ts +36 -91
  508. package/src/hooks/useImageMode.test.ts +1 -1
  509. package/src/hooks/useIndicatorFocusRing.tsx +120 -0
  510. package/src/hooks/useLongPress.test.tsx +18 -0
  511. package/src/hooks/useLongPress.ts +12 -2
  512. package/src/hooks/useScrollLock.test.ts +72 -0
  513. package/src/hooks/useScrollLock.ts +51 -19
  514. package/src/hooks/useStreamingText.test.ts +46 -1
  515. package/src/hooks/useStreamingText.ts +49 -7
  516. package/src/hooks/useTreeFocus.test.tsx +50 -0
  517. package/src/hooks/useTreeFocus.ts +14 -3
  518. package/src/hooks/useTypeahead.test.tsx +150 -0
  519. package/src/hooks/useTypeahead.ts +24 -9
  520. package/src/i18n/InternationalizationProvider.doc.mjs +7 -2
  521. package/src/index.ts +1 -0
  522. package/src/theme/defineTheme.ts +24 -0
  523. package/src/theme/derivedVarRegistry.test.ts +21 -1
  524. package/src/theme/derivedVarRegistry.ts +19 -6
  525. package/src/theme/expandColorScale.test.ts +14 -0
  526. package/src/theme/expandColorScale.ts +24 -9
  527. package/src/theme/expandTypeScale.test.ts +43 -0
  528. package/src/theme/expandTypeScale.ts +17 -0
  529. package/src/theme/generateThemeRules.test.ts +61 -20
  530. package/src/theme/generateThemeRules.ts +11 -0
  531. package/src/theme/index.ts +13 -0
  532. package/src/utils/focusOutline.stylex.ts +163 -0
  533. package/src/utils/focusReturn.test.ts +42 -0
  534. package/src/utils/focusReturn.ts +31 -0
  535. package/src/utils/index.ts +1 -0
  536. package/src/utils/mergeRefs.test.ts +48 -0
  537. package/src/utils/mergeRefs.ts +12 -6
  538. package/src/utils/rtlStyles.ts +2 -2
  539. package/src/utils/themeProps.ts +26 -4
  540. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts +0 -9
  541. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts.map +0 -1
  542. package/dist/CheckboxInput/checkbox.markers.stylex.js +0 -14
  543. package/dist/RadioList/radio.markers.stylex.d.ts +0 -7
  544. package/dist/RadioList/radio.markers.stylex.d.ts.map +0 -1
  545. package/dist/RadioList/radio.markers.stylex.js +0 -12
  546. package/dist/hooks/containerReveal.pool.stylex.d.ts +0 -303
  547. package/dist/hooks/containerReveal.pool.stylex.d.ts.map +0 -1
  548. package/dist/hooks/containerReveal.pool.stylex.js +0 -292
  549. package/src/CheckboxInput/checkbox.markers.stylex.ts +0 -12
  550. package/src/RadioList/radio.markers.stylex.ts +0 -10
  551. package/src/hooks/containerReveal.pool.stylex.ts +0 -571
@@ -71,7 +71,9 @@ export interface ColorScaleConfig {
71
71
  neutralStyle?: 'warm' | 'cool' | 'neutral';
72
72
 
73
73
  /**
74
- * Contrast level. Affects tone assignments for text and UI elements.
74
+ * Contrast level. `'high'` pulls text, icons, and borders toward stronger
75
+ * tones (and thickens the subtle border's alpha) so structural and textual
76
+ * boundaries stay perceivable.
75
77
  * @default 'standard'
76
78
  */
77
79
  contrast?: 'standard' | 'high';
@@ -190,17 +192,25 @@ export function expandColorScale(config: ColorScaleConfig): ColorScaleTokens {
190
192
  const textSecondaryLightTone = isHigh ? 20 : 30;
191
193
  const textSecondaryDarkTone = isHigh ? 80 : 70;
192
194
 
195
+ // Borders track contrast the same way text does: high contrast pulls the
196
+ // emphasized border tone toward mid-scale (stronger against both the near-
197
+ // white light surface and the near-black dark surface) and thickens the
198
+ // otherwise-decorative subtle hairline by doubling its alpha, so structural
199
+ // boundaries stay perceivable for users who opt into high contrast.
200
+ const borderSubtleAlpha = isHigh ? 0.2 : 0.1;
201
+
193
202
  // Emphasized borders outline form controls (CheckboxInput, Selector), so
194
203
  // they are non-text UI boundaries under WCAG 1.4.11 and must reach 3:1
195
- // against the surface they sit on. The preferred tones (70 light /
196
- // 30 dark) land around 2.2:1 / 1.8:1, so bump the tone toward the
197
- // opposing extreme until the ratio passes. Text tones need no such loop:
198
- // their spacing guarantees >= 4.5:1 for any hue/chroma (see file header).
204
+ // against the surface they sit on. High contrast starts at a more
205
+ // aggressive tone (50 vs 70/30), guaranteeing a stronger result; standard
206
+ // contrast starts at 70/30 and walks toward mid-scale only as far as needed.
207
+ const borderEmphasizedStartLight = isHigh ? 50 : 70;
208
+ const borderEmphasizedStartDark = isHigh ? 50 : 30;
199
209
  const borderEmphasized = ld(
200
210
  ensureContrastTone(
201
211
  seedHue,
202
212
  neutralVariantChroma,
203
- 70,
213
+ borderEmphasizedStartLight,
204
214
  -1,
205
215
  N[99],
206
216
  NON_TEXT_MIN_CONTRAST,
@@ -208,7 +218,7 @@ export function expandColorScale(config: ColorScaleConfig): ColorScaleTokens {
208
218
  ensureContrastTone(
209
219
  seedHue,
210
220
  neutralVariantChroma,
211
- 30,
221
+ borderEmphasizedStartDark,
212
222
  1,
213
223
  N[10],
214
224
  NON_TEXT_MIN_CONTRAST,
@@ -276,8 +286,13 @@ export function expandColorScale(config: ColorScaleConfig): ColorScaleTokens {
276
286
  '--color-background-inverted': ld(N[10], N[99]),
277
287
 
278
288
  // Border
279
- // Decorative hairline (~1.1:1 by design) — not a WCAG 1.4.11 boundary.
280
- '--color-border': ld(hexWithAlpha(N[10], 0.1), hexWithAlpha(N[95], 0.1)),
289
+ // Border
290
+ // Decorative hairline — not a WCAG 1.4.11 boundary. High contrast
291
+ // doubles the alpha so structural boundaries stay perceivable.
292
+ '--color-border': ld(
293
+ hexWithAlpha(N[10], borderSubtleAlpha),
294
+ hexWithAlpha(N[95], borderSubtleAlpha),
295
+ ),
281
296
  '--color-border-emphasized': borderEmphasized,
282
297
 
283
298
  // Effects
@@ -305,4 +305,47 @@ describe('generateTypeScaleComponents', () => {
305
305
  'var(--text-body-leading)',
306
306
  );
307
307
  });
308
+
309
+ it('generates rules for all 3 heading display types', () => {
310
+ const components = generateTypeScaleComponents({base: 14, ratio: 1.2});
311
+ for (const type of ['display-1', 'display-2', 'display-3']) {
312
+ expect(components.heading).toHaveProperty(`type:${type}`);
313
+ }
314
+ });
315
+
316
+ it('heading display-type rules reference the display semantic tokens', () => {
317
+ const components = generateTypeScaleComponents({base: 14, ratio: 1.2});
318
+ const display1 = components.heading['type:display-1'];
319
+ expect(display1.fontFamily).toBe('var(--font-family-heading)');
320
+ expect(display1.fontSize).toBe('var(--text-display-1-size)');
321
+ expect(display1.lineHeight).toBe('var(--text-display-1-leading)');
322
+ // fontWeight is intentionally omitted here, matching the `text` branch's
323
+ // type-keyed rules — see defaultWeightByTypeStyles for how weight is
324
+ // applied instead.
325
+ expect(display1.fontWeight).toBeUndefined();
326
+ });
327
+
328
+ it('emits heading type:display-N rules after level:N rules, so type wins at equal specificity', () => {
329
+ // Heading renders both a `level:N` and a `type:display-N` class on the
330
+ // same element simultaneously when `type` is set (see Heading.tsx).
331
+ // Both produce single-class-selector CSS rules of equal specificity, so
332
+ // CSS's own "last rule wins" tiebreak is what makes `type` take
333
+ // precedence over `level` -- which only holds if type rules are emitted
334
+ // strictly after all level rules in this object's (and therefore the
335
+ // generated stylesheet's) key order. This regression-tests #4829,
336
+ // where type-keyed heading rules didn't exist at all and level always
337
+ // won by default, silently discarding the `type` prop under any theme
338
+ // with a typography.scale.
339
+ const components = generateTypeScaleComponents({base: 14, ratio: 1.2});
340
+ const keys = Object.keys(components.heading);
341
+ const lastLevelIndex = Math.max(
342
+ ...[1, 2, 3, 4, 5, 6].map(level => keys.indexOf(`level:${level}`)),
343
+ );
344
+ const firstTypeIndex = Math.min(
345
+ ...['display-1', 'display-2', 'display-3'].map(type =>
346
+ keys.indexOf(`type:${type}`),
347
+ ),
348
+ );
349
+ expect(firstTypeIndex).toBeGreaterThan(lastLevelIndex);
350
+ });
308
351
  });
@@ -368,6 +368,23 @@ export function generateTypeScaleComponents(
368
368
  lineHeight: `var(--text-heading-${level}-leading)`,
369
369
  };
370
370
  }
371
+ // `Heading` renders both a `level:N` and, when set, a `type:display-N`
372
+ // visual-prop class simultaneously (type sizing takes precedence over
373
+ // level sizing — see Heading.tsx's own `type ? sizeByTypeStyles[type] :
374
+ // sizeByLevelStyles[level]`). Without a `type:display-N` rule here, the
375
+ // `level:N` rule is the only one that matches, so it silently wins
376
+ // regardless of `type` once a theme supplies a type scale. Emitting these
377
+ // after the level rules keeps them later in source order, so they take
378
+ // precedence at equal specificity, matching the component's own logic.
379
+ // fontWeight is intentionally omitted, mirroring the `text` branch below
380
+ // and preserving `defaultWeightByTypeStyles`.
381
+ for (const type of ['display-1', 'display-2', 'display-3']) {
382
+ headingRules[`type:${type}`] = {
383
+ fontFamily: 'var(--font-family-heading)',
384
+ fontSize: `var(--text-${type}-size)`,
385
+ lineHeight: `var(--text-${type}-leading)`,
386
+ };
387
+ }
371
388
  components.heading = headingRules;
372
389
 
373
390
  const textRules: Record<string, Record<string, string>> = {};
@@ -385,46 +385,46 @@ describe('derived var expansion', () => {
385
385
  expect(rule).toContain('--_button-radius: 8px');
386
386
  });
387
387
 
388
- it('emits internal vars for avatar fallback typography (base)', () => {
388
+ it('emits direct rules for avatar fallback background, color, and weight', () => {
389
389
  const theme = defineTheme({
390
- name: 'test-derived-avatar',
390
+ name: 'test-avatar-fallback',
391
391
  components: {
392
- avatar: {
392
+ 'avatar-fallback': {
393
393
  base: {
394
- fontWeight: 'var(--font-weight-normal)',
395
- color: 'var(--color-text-secondary)',
396
394
  backgroundColor: 'var(--color-accent-muted)',
395
+ color: 'var(--color-text-secondary)',
396
+ fontWeight: 'var(--font-weight-normal)',
397
397
  },
398
398
  },
399
399
  },
400
400
  });
401
401
  const rules = generateThemeRules(theme);
402
- const rule = rules.find(r => r.includes('.astryx-avatar'));
402
+ const rule = rules.find(r => r.includes('.astryx-avatar-fallback'));
403
403
  expect(rule).toBeDefined();
404
- expect(rule).toContain(
405
- '--_avatar-fallback-font-weight: var(--font-weight-normal)',
406
- );
407
- expect(rule).toContain(
408
- '--_avatar-fallback-color: var(--color-text-secondary)',
409
- );
410
- expect(rule).toContain(
411
- '--_avatar-fallback-background: var(--color-accent-muted)',
412
- );
404
+ expect(rule).toContain('background-color: var(--color-accent-muted)');
405
+ expect(rule).toContain('color: var(--color-text-secondary)');
406
+ expect(rule).toContain('font-weight: var(--font-weight-normal)');
407
+ // These are direct class targets now, not internal derived vars.
408
+ expect(rule).not.toContain('--_avatar-fallback-background');
409
+ expect(rule).not.toContain('--_avatar-fallback-color');
410
+ expect(rule).not.toContain('--_avatar-fallback-font-weight');
413
411
  });
414
412
 
415
- it('emits a per-size fallback font-size for avatar (size:sm)', () => {
413
+ it('emits a direct per-size font-size rule for the avatar fallback target', () => {
416
414
  const theme = defineTheme({
417
- name: 'test-derived-avatar-size',
415
+ name: 'test-avatar-fallback-size',
418
416
  components: {
419
- avatar: {
417
+ 'avatar-fallback': {
420
418
  'size:sm': {fontSize: '9px'},
421
419
  },
422
420
  },
423
421
  });
424
422
  const rules = generateThemeRules(theme);
425
- const rule = rules.find(r => r.includes('.astryx-avatar.sm'));
423
+ const rule = rules.find(r => r.includes('.astryx-avatar-fallback.sm'));
426
424
  expect(rule).toBeDefined();
427
- expect(rule).toContain('--_avatar-fallback-font-size: 9px');
425
+ expect(rule).toContain('font-size: 9px');
426
+ // Direct class target now — no internal derived var.
427
+ expect(rule).not.toContain('--_avatar-fallback-font-size');
428
428
  });
429
429
 
430
430
  it('does not emit derived vars for components without registry entries', () => {
@@ -475,6 +475,47 @@ describe('derived var expansion', () => {
475
475
  expect(rule).toContain('border-radius: 16px');
476
476
  expect(rule).toContain('--_card-radius: 16px');
477
477
  });
478
+
479
+ it('replaces paddingInline with the var for textarea (no raw property)', () => {
480
+ const theme = defineTheme({
481
+ name: 'test-derived-textarea',
482
+ components: {
483
+ textarea: {
484
+ base: {paddingInline: 'var(--eps-input-padding-x)'},
485
+ },
486
+ },
487
+ });
488
+ const rules = generateThemeRules(theme);
489
+ const rule = rules.find(r => r.includes('.astryx-textarea'));
490
+ expect(rule).toBeDefined();
491
+ // Value flows to the inner <textarea> via the var…
492
+ expect(rule).toContain(
493
+ '--_textarea-inline-padding: var(--eps-input-padding-x)',
494
+ );
495
+ // …and must NOT land on the flush wrapper, which would re-inset the
496
+ // full-bleed textarea and push the native resize grip off the corner.
497
+ expect(rule).not.toContain('padding-inline: var(--eps-input-padding-x)');
498
+ });
499
+
500
+ it('replaces progressbar-mark width/height with vars (no raw properties)', () => {
501
+ const theme = defineTheme({
502
+ name: 'test-derived-progressbar-mark',
503
+ components: {
504
+ 'progressbar-mark': {
505
+ base: {width: '2px', height: '12px'},
506
+ },
507
+ },
508
+ });
509
+ const rules = generateThemeRules(theme);
510
+ const rule = rules.find(r => r.includes('.astryx-progressbar-mark'));
511
+ expect(rule).toBeDefined();
512
+ expect(rule).toContain('--_progressbar-mark-width: 2px');
513
+ expect(rule).toContain('--_progressbar-mark-height: 12px');
514
+ // Raw dimensions would be a same-element fight with the mark's StyleX,
515
+ // which an unlayered consumer build wins — the vars have no competitor.
516
+ expect(rule).not.toMatch(/[{;]\s*width: 2px/);
517
+ expect(rule).not.toMatch(/[{;]\s*height: 12px/);
518
+ });
478
519
  });
479
520
 
480
521
  describe('brutalist-style derived expansion', () => {
@@ -350,9 +350,11 @@ function generateComponentRules(
350
350
  // Entries are processed in order (priority).
351
351
  // - `vars`: emit internal CSS custom property declarations
352
352
  // - `expand: 'container'`: expand padding to container layout tokens
353
+ // - `replaces: true`: emit only the var, dropping the source property
353
354
  let finalProps = props;
354
355
  const derivedProps: [string, string][] = [];
355
356
  let containerExpanded = false;
357
+ const replacedProps = new Set<string>();
356
358
 
357
359
  for (const [prop, value] of props) {
358
360
  const derived = getDerivedVars(component, prop);
@@ -366,6 +368,9 @@ function generateComponentRules(
366
368
  if (entry.expand === 'container' && PADDING_PROPS.has(prop)) {
367
369
  containerExpanded = true;
368
370
  }
371
+ if (entry.replaces) {
372
+ replacedProps.add(prop);
373
+ }
369
374
  if (entry.vars) {
370
375
  for (const varName of entry.vars) {
371
376
  derivedProps.push([varName, value]);
@@ -384,6 +389,12 @@ function generateComponentRules(
384
389
  finalProps = [...nonPaddingProps, ...containerTokens];
385
390
  }
386
391
 
392
+ // Drop properties whose derived entry set `replaces` — their value is
393
+ // carried by the emitted var and must not land on the class element.
394
+ if (replacedProps.size > 0) {
395
+ finalProps = finalProps.filter(([p]) => !replacedProps.has(p));
396
+ }
397
+
387
398
  if (derivedProps.length > 0) {
388
399
  finalProps = [...finalProps, ...derivedProps];
389
400
  }
@@ -130,6 +130,19 @@ export type {
130
130
 
131
131
  export {useTheme, useThemeName, ThemeContext} from './useTheme';
132
132
  export type {UseThemeReturn, ThemeContextValue} from './useTheme';
133
+
134
+ export type {
135
+ IndicatorComponent,
136
+ IndicatorFamily,
137
+ IndicatorFamilyMap,
138
+ IndicatorMap,
139
+ IndicatorName,
140
+ IndicatorNameOfFamily,
141
+ IndicatorProps,
142
+ IndicatorRegistry,
143
+ IndicatorSize,
144
+ IndicatorState,
145
+ } from '../Indicator';
133
146
  export {
134
147
  resolveThemeToken,
135
148
  resolveThemeTokens,
@@ -0,0 +1,163 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file focusOutline.stylex.ts
5
+ * @input Uses StyleX and theme color tokens
6
+ * @output Exports shared focus-outline prop builders
7
+ * @position Internal utility for consistent keyboard focus outlines across core components
8
+ *
9
+ * Centralizes the standard Astryx focus outline, shown only for keyboard focus.
10
+ * Every focusable surface drew the same 2px accent ring at 2px offset already;
11
+ * writing it per component meant five identical definitions to keep in step.
12
+ *
13
+ * These are utility styles, deliberately NOT a theme target. A shared
14
+ * `astryx-focus-outline` class was tried and pulled: a theme can only override
15
+ * the ring unconditionally through it (`generateThemeRules` mangles
16
+ * `:focus-visible` into `.focus-visible` and truncates `:has(:focus-visible)`
17
+ * at the paren), so the one thing such a target exists for — restyling a
18
+ * STATE — is exactly what it cannot express. Making focus outlines themeable
19
+ * is worth doing on top of this consolidation, once that is fixed.
20
+ */
21
+
22
+ import * as stylex from '@stylexjs/stylex';
23
+ import {colorVars} from '../theme/tokens.stylex';
24
+
25
+ const FOCUS_OUTLINE_WIDTH = '2px';
26
+ // 3px, per Design Conventions §User Interaction States: "2px --color-accent
27
+ // outline at 3px offset". Most components had drifted to 2px; Button, Calendar,
28
+ // Dialog and Pagination were the ones matching the spec, so the consolidation
29
+ // takes their value rather than the majority's.
30
+ const FOCUS_OUTLINE_OFFSET = '3px';
31
+ const FOCUS_OUTLINE_COLOR = colorVars['--color-accent'];
32
+
33
+ /**
34
+ * Written as longhands rather than the `outline` shorthand.
35
+ *
36
+ * A shorthand resets every longhand it covers, so `outline: 2px solid accent`
37
+ * would clobber a later `outlineColor` no matter the order — which is how
38
+ * destructive buttons silently lost their red ring. With longhands, a variant
39
+ * can re-color the ring and inherit width, style and offset.
40
+ */
41
+ const focusOutlineLonghands = {
42
+ outlineWidth: FOCUS_OUTLINE_WIDTH,
43
+ outlineStyle: 'solid',
44
+ outlineColor: FOCUS_OUTLINE_COLOR,
45
+ } as const;
46
+
47
+ /**
48
+ * The standard focus ring as plain CSS values, for the one case that has to
49
+ * apply it imperatively: a control whose focusable input is visually hidden and
50
+ * whose ring must land on a *themeable indicator* beside it (see
51
+ * `useIndicatorFocusRing`). Everything else should use the styles above.
52
+ *
53
+ * Longhands, not the `outline` shorthand, for the same reason the styles are:
54
+ * a shorthand resets every longhand it covers, so a caller could not re-color
55
+ * the ring without restating its width and style. Split, each part is
56
+ * independently overridable — and `--color-accent` stays a var, so a theme's
57
+ * accent still flows through.
58
+ *
59
+ * Keys are camelCase to match `HTMLElement.style`, so this spreads straight
60
+ * onto an element:
61
+ *
62
+ * ```ts
63
+ * Object.assign(el.style, FOCUS_OUTLINE_PARTS); // draw
64
+ * Object.assign(el.style, FOCUS_OUTLINE_PARTS_NONE); // clear
65
+ * ```
66
+ */
67
+ export const FOCUS_OUTLINE_PARTS = {
68
+ outlineWidth: FOCUS_OUTLINE_WIDTH,
69
+ outlineStyle: 'solid',
70
+ outlineColor: FOCUS_OUTLINE_COLOR,
71
+ outlineOffset: FOCUS_OUTLINE_OFFSET,
72
+ } as const;
73
+
74
+ /** Clears {@link FOCUS_OUTLINE_PARTS}, one key per part so nothing lingers. */
75
+ export const FOCUS_OUTLINE_PARTS_NONE = {
76
+ outlineWidth: '',
77
+ outlineStyle: '',
78
+ outlineColor: '',
79
+ outlineOffset: '',
80
+ } as const;
81
+
82
+ export const focusOutlineStyles = stylex.create({
83
+ focusVisible: {
84
+ outlineWidth: {
85
+ default: '0',
86
+ ':focus-visible': focusOutlineLonghands.outlineWidth,
87
+ },
88
+ outlineStyle: {
89
+ default: 'none',
90
+ ':focus-visible': focusOutlineLonghands.outlineStyle,
91
+ },
92
+ outlineColor: {
93
+ default: null,
94
+ ':focus-visible': focusOutlineLonghands.outlineColor,
95
+ },
96
+ outlineOffset: {default: '0', ':focus-visible': FOCUS_OUTLINE_OFFSET},
97
+ },
98
+ focusWithin: {
99
+ outlineWidth: {
100
+ default: '0',
101
+ ':has(:focus-visible)': focusOutlineLonghands.outlineWidth,
102
+ },
103
+ outlineStyle: {
104
+ default: 'none',
105
+ ':has(:focus-visible)': focusOutlineLonghands.outlineStyle,
106
+ },
107
+ outlineColor: {
108
+ default: null,
109
+ ':has(:focus-visible)': focusOutlineLonghands.outlineColor,
110
+ },
111
+ outlineOffset: {default: '0', ':has(:focus-visible)': FOCUS_OUTLINE_OFFSET},
112
+ },
113
+ publishFocusVisibleVars: {
114
+ '--_focus-outline': {
115
+ default: 'none',
116
+ ':focus-visible': `${FOCUS_OUTLINE_WIDTH} solid ${FOCUS_OUTLINE_COLOR}`,
117
+ },
118
+ '--_focus-outline-offset': {
119
+ default: '0',
120
+ ':focus-visible': FOCUS_OUTLINE_OFFSET,
121
+ },
122
+ },
123
+ focusWithinOrPublished: {
124
+ outline: {
125
+ default: 'var(--_focus-outline, none)',
126
+ ':has(:focus-visible)': `${FOCUS_OUTLINE_WIDTH} solid ${FOCUS_OUTLINE_COLOR}`,
127
+ },
128
+ outlineOffset: {
129
+ default: 'var(--_focus-outline-offset, 0)',
130
+ ':has(:focus-visible)': FOCUS_OUTLINE_OFFSET,
131
+ },
132
+ },
133
+ });
134
+
135
+ // StyleX does not expose a stable public input type for stylex.props();
136
+ // keep this helper permissive so it mirrors stylex.props() itself.
137
+ type StyleXPropsArg = unknown;
138
+
139
+ function makeFocusOutlineProps(style: StyleXPropsArg) {
140
+ return (...styles: StyleXPropsArg[]) =>
141
+ // Caller styles LAST, so a component can deliberately re-color its ring —
142
+ // destructive buttons ring in error red, not accent. StyleX is last-wins,
143
+ // and reversing this to protect the ring silently ate that override.
144
+ //
145
+ // The hazard in this direction is the opposite one: a caller whose base
146
+ // style carries `outline: 'none'` wipes the ring out entirely (TreeList
147
+ // did, and shipped a focusable row with no visible focus). Two things
148
+ // guard it — this file states the rule, and the ring is written as
149
+ // LONGHANDS, so an override has to name `outlineStyle`/`outlineWidth`
150
+ // explicitly rather than erasing them through the `outline` shorthand.
151
+ stylex.props(style as never, ...(styles as never[]));
152
+ }
153
+
154
+ export const focusOutlineProps = {
155
+ focusVisible: makeFocusOutlineProps(focusOutlineStyles.focusVisible),
156
+ focusWithin: makeFocusOutlineProps(focusOutlineStyles.focusWithin),
157
+ publishFocusVisibleVars: makeFocusOutlineProps(
158
+ focusOutlineStyles.publishFocusVisibleVars,
159
+ ),
160
+ focusWithinOrPublished: makeFocusOutlineProps(
161
+ focusOutlineStyles.focusWithinOrPublished,
162
+ ),
163
+ } as const;
@@ -0,0 +1,42 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, it, expect, afterEach} from 'vitest';
4
+ import {isFocusDetached} from './focusReturn';
5
+
6
+ describe('isFocusDetached', () => {
7
+ afterEach(() => {
8
+ document.body.innerHTML = '';
9
+ });
10
+
11
+ it('is true when focus rests on the body (Escape / empty-space dismiss)', () => {
12
+ // Nothing focused → activeElement is <body>.
13
+ (document.activeElement as HTMLElement | null)?.blur();
14
+ expect(isFocusDetached()).toBe(true);
15
+ });
16
+
17
+ it('is false when a real element holds focus (the user moved focus there)', () => {
18
+ const input = document.createElement('input');
19
+ document.body.appendChild(input);
20
+ input.focus();
21
+ expect(document.activeElement).toBe(input);
22
+ expect(isFocusDetached()).toBe(false);
23
+ });
24
+
25
+ it('treats the documentElement as detached', () => {
26
+ const doc = {
27
+ activeElement: document.documentElement,
28
+ body: document.body,
29
+ documentElement: document.documentElement,
30
+ } as unknown as Document;
31
+ expect(isFocusDetached(doc)).toBe(true);
32
+ });
33
+
34
+ it('treats a null activeElement as detached', () => {
35
+ const doc = {
36
+ activeElement: null,
37
+ body: document.body,
38
+ documentElement: document.documentElement,
39
+ } as unknown as Document;
40
+ expect(isFocusDetached(doc)).toBe(true);
41
+ });
42
+ });
@@ -0,0 +1,31 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file focusReturn.ts
5
+ * @input The document's current active element.
6
+ * @output Whether focus is currently "detached" — on nothing in particular.
7
+ * @position Utility; used by overlay triggers (e.g. DateInput, DateTimeInput)
8
+ * that return focus to their control when the overlay closes, but only when
9
+ * the dismiss did not already move focus somewhere the user chose.
10
+ */
11
+
12
+ /**
13
+ * True when focus rests on nothing in particular — no active element, or the
14
+ * document body / root element.
15
+ *
16
+ * An overlay (popover, calendar, dropdown) that restores focus to its trigger
17
+ * on close should do so ONLY when this is true. A native `popover="auto"`
18
+ * light-dismiss fires its close synchronously with the pointer event that
19
+ * moved focus, so by the time the close handler runs, focus has already
20
+ * landed on whatever the user clicked — another field, a button, anywhere.
21
+ * Restoring focus unconditionally would yank it back and fight that click.
22
+ * The one case the browser leaves unresolved is Escape or a click on
23
+ * non-focusable empty space, which drops focus to the body; that is exactly
24
+ * when the trigger should reclaim it.
25
+ */
26
+ export function isFocusDetached(doc: Document = document): boolean {
27
+ const active = doc.activeElement;
28
+ return (
29
+ active == null || active === doc.body || active === doc.documentElement
30
+ );
31
+ }
@@ -72,6 +72,7 @@ export {getKey, type Key, type KeyFallback} from './getKey';
72
72
 
73
73
  export {mergeProps} from './mergeProps';
74
74
  export {mergeRefs} from './mergeRefs';
75
+ export {isFocusDetached} from './focusReturn';
75
76
  export {composeEventHandlers} from './composeEventHandlers';
76
77
  export {themeProps, themeDataAttributes} from './themeProps';
77
78
  export type {
@@ -0,0 +1,48 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {createElement, createRef} from 'react';
4
+ import {render} from '@testing-library/react';
5
+ import {describe, expect, it, vi} from 'vitest';
6
+ import {mergeRefs} from './mergeRefs';
7
+
8
+ describe('mergeRefs', () => {
9
+ it('forwards the value to callback and object refs', () => {
10
+ const callbackRef = vi.fn();
11
+ const objectRef = createRef<HTMLDivElement>();
12
+
13
+ const {container} = render(
14
+ createElement('div', {ref: mergeRefs(callbackRef, objectRef)}),
15
+ );
16
+
17
+ expect(callbackRef).toHaveBeenCalledWith(container.firstElementChild);
18
+ expect(objectRef.current).toBe(container.firstElementChild);
19
+ });
20
+
21
+ it('runs callback cleanup and clears object refs', () => {
22
+ const cleanup = vi.fn();
23
+ const callbackRef = vi.fn(() => cleanup);
24
+ const objectRef = createRef<HTMLDivElement>();
25
+
26
+ const {unmount} = render(
27
+ createElement('div', {ref: mergeRefs(callbackRef, objectRef)}),
28
+ );
29
+ unmount();
30
+
31
+ expect(cleanup).toHaveBeenCalledTimes(1);
32
+ expect(callbackRef).toHaveBeenCalledTimes(1);
33
+ expect(objectRef.current).toBeNull();
34
+ });
35
+
36
+ it('passes null to callback refs that do not return cleanup functions', () => {
37
+ const callbackRef = vi.fn();
38
+
39
+ const {container, unmount} = render(
40
+ createElement('div', {ref: mergeRefs(callbackRef)}),
41
+ );
42
+ const element = container.firstElementChild;
43
+ unmount();
44
+
45
+ expect(callbackRef).toHaveBeenNthCalledWith(1, element);
46
+ expect(callbackRef).toHaveBeenNthCalledWith(2, null);
47
+ });
48
+ });
@@ -16,16 +16,22 @@ export function mergeRefs<T>(...refs: (Ref<T> | undefined)[]): RefCallback<T> {
16
16
  for (const ref of refs) {
17
17
  if (typeof ref === 'function') {
18
18
  const cleanup = ref(value);
19
- if (typeof cleanup === 'function') {
20
- cleanups.push(cleanup);
21
- }
19
+ cleanups.push(
20
+ typeof cleanup === 'function' ? cleanup : () => ref(null),
21
+ );
22
22
  } else if (ref != null) {
23
- (ref as {current: T | null}).current = value;
23
+ const mutableRef = ref as {current: T | null};
24
+ mutableRef.current = value;
25
+ cleanups.push(() => {
26
+ mutableRef.current = null;
27
+ });
24
28
  }
25
29
  }
26
- if (cleanups.length > 0) {
30
+ if (value != null && cleanups.length > 0) {
27
31
  return () => {
28
- for (const cleanup of cleanups) {cleanup();}
32
+ for (const cleanup of cleanups) {
33
+ cleanup();
34
+ }
29
35
  };
30
36
  }
31
37
  };
@@ -4,8 +4,8 @@
4
4
  * @file rtlStyles.ts
5
5
  * @input None
6
6
  * @output Shared StyleX style that horizontally mirrors an element under RTL
7
- * @position Core utility; applied to directional-icon wrappers in Calendar,
8
- * Lightbox, and the Table expand/disclosure plugins
7
+ * @position Core utility; applied to directional icons in Calendar, Lightbox,
8
+ * Pagination, Carousel and the Table expand/disclosure plugins
9
9
  *
10
10
  * `mirror` flips its element on the horizontal axis only when an ancestor
11
11
  * carries `dir="rtl"`. Using `scaleX(-1)` (not `scale(-1, -1)`) keeps the