@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
@@ -0,0 +1,106 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file indicatorRegistry.test.tsx
5
+ *
6
+ * Pins the seam between the indicators core ships and the ones other packages
7
+ * add, because that seam used to lie: `defaultIndicators` was typed as a total
8
+ * map over the OPEN `IndicatorName` union, so augmenting `IndicatorMap` made
9
+ * the compiler promise a component for a name nothing had registered, and
10
+ * rendering the `undefined` it actually returned threw.
11
+ *
12
+ * The augmentation below is deliberately real, not a cast — it is exactly what
13
+ * a downstream package writes, and it is what makes `defaultIndicators`
14
+ * failing to cover `'brand-star'` a compile error if anyone re-widens the map.
15
+ */
16
+
17
+ import {describe, expect, it} from 'vitest';
18
+ import {render} from '@testing-library/react';
19
+ import {defineTheme} from '../theme/defineTheme';
20
+ import {CheckboxIndicator} from './CheckboxIndicator';
21
+ import {CheckIndicator} from './CheckIndicator';
22
+ import {RadioIndicator} from './RadioIndicator';
23
+ import {defaultIndicators, getIndicator} from './indicatorRegistry';
24
+ import type {CoreIndicatorName} from './indicatorRegistry';
25
+ import type {IndicatorName, IndicatorProps} from './types';
26
+
27
+ declare module './types' {
28
+ interface IndicatorMap {
29
+ 'brand-star': 'singleSelection';
30
+ }
31
+ }
32
+
33
+ function BrandStar({state}: IndicatorProps<'singleSelection'>) {
34
+ return <span aria-hidden="true" data-testid="star" data-state={state} />;
35
+ }
36
+
37
+ describe('defaultIndicators', () => {
38
+ it('covers exactly the core indicator names', () => {
39
+ // A Record over the union, not an array: adding a name to
40
+ // CoreIndicatorName without shipping a default fails to compile here
41
+ // before it can fail at runtime anywhere else.
42
+ const coreNames: Record<CoreIndicatorName, true> = {
43
+ check: true,
44
+ checkbox: true,
45
+ radio: true,
46
+ };
47
+
48
+ expect(Object.keys(defaultIndicators).sort()).toEqual(
49
+ Object.keys(coreNames).sort(),
50
+ );
51
+ expect(defaultIndicators.check).toBe(CheckIndicator);
52
+ expect(defaultIndicators.checkbox).toBe(CheckboxIndicator);
53
+ expect(defaultIndicators.radio).toBe(RadioIndicator);
54
+ });
55
+ });
56
+
57
+ describe('getIndicator', () => {
58
+ it('resolves a core name to its built-in with no theme', () => {
59
+ expect(getIndicator('check')).toBe(CheckIndicator);
60
+ expect(getIndicator('radio')).toBe(RadioIndicator);
61
+ });
62
+
63
+ it('prefers a theme override, by name, across every host', () => {
64
+ const theme = defineTheme({
65
+ name: 'registry-override',
66
+ indicators: {check: RadioIndicator},
67
+ });
68
+
69
+ expect(getIndicator('check', theme)).toBe(RadioIndicator);
70
+ // Unmapped names keep their built-in.
71
+ expect(getIndicator('checkbox', theme)).toBe(CheckboxIndicator);
72
+ });
73
+
74
+ it('returns undefined for an augmented name no theme supplies', () => {
75
+ // The honest answer: core ships no `brand-star`. The type says
76
+ // `| undefined` for exactly this reason, so a caller writes `?? BrandStar`
77
+ // instead of rendering undefined.
78
+ expect(getIndicator('brand-star')).toBeUndefined();
79
+ });
80
+
81
+ it('resolves an augmented name the theme does supply', () => {
82
+ const theme = defineTheme({
83
+ name: 'brand-star-theme',
84
+ indicators: {'brand-star': BrandStar},
85
+ });
86
+
87
+ const Star = getIndicator('brand-star', theme);
88
+ expect(Star).toBe(BrandStar);
89
+
90
+ const {container} = render(<BrandStar state="checked" />);
91
+ expect(container.querySelector('[data-testid="star"]')).toBeInTheDocument();
92
+ });
93
+
94
+ it('types a core name as always resolvable and an open name as maybe', () => {
95
+ // Compile-time assertions; the runtime body only keeps them referenced.
96
+ const core = getIndicator('check');
97
+ const open = getIndicator('brand-star' as IndicatorName);
98
+
99
+ // @ts-expect-error — an augmented name may have no default; callers must
100
+ // handle undefined rather than render it.
101
+ const _mustHandle: NonNullable<typeof open> = open;
102
+
103
+ expect(core).toBeDefined();
104
+ expect(_mustHandle ?? null).toBeDefined();
105
+ });
106
+ });
@@ -0,0 +1,120 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file indicatorRegistry.ts
5
+ * @input Theme source and indicator name
6
+ * @output Exports the default indicator map and getIndicator resolution
7
+ * @position Server-safe indicator resolver; no 'use client' so it is
8
+ * importable from RSC
9
+ *
10
+ * Two name spaces meet here, and keeping them apart is the whole design:
11
+ *
12
+ * - {@link CoreIndicatorName} — the indicators Astryx itself ships. Closed,
13
+ * and every one of them has a default, so resolving one always yields a
14
+ * component.
15
+ * - {@link IndicatorName} — every indicator name that exists, including the
16
+ * ones other packages add by augmenting `IndicatorMap`. Open, and core has
17
+ * no default for a name it has never heard of.
18
+ *
19
+ * `getIndicator` is overloaded along that seam: a core name resolves to a
20
+ * component, an augmented name resolves to a component *or* `undefined`, and
21
+ * the caller has to say what to do about it. Typing the map as total over the
22
+ * open union instead — which is what shipped in #4712 — made the compiler
23
+ * promise a component for `getIndicator('brand-star')` and hand back
24
+ * `undefined` at runtime.
25
+ */
26
+
27
+ import type {DefinedTheme} from '../theme/defineTheme';
28
+ import {getRegisteredTheme} from '../theme/themeRegistry';
29
+ import {CheckboxIndicator} from './CheckboxIndicator';
30
+ import {CheckIndicator} from './CheckIndicator';
31
+ import {RadioIndicator} from './RadioIndicator';
32
+ import type {
33
+ IndicatorComponent,
34
+ IndicatorMap,
35
+ IndicatorName,
36
+ IndicatorRegistry,
37
+ } from './types';
38
+
39
+ /**
40
+ * The indicator names Astryx ships a default for.
41
+ *
42
+ * Written out rather than derived from {@link IndicatorMap}, because that
43
+ * interface is open to augmentation and this set is not: it is exactly what is
44
+ * in {@link defaultIndicators} below. `indicatorRegistry.test.tsx` pins the two
45
+ * together in both directions.
46
+ */
47
+ export type CoreIndicatorName = 'check' | 'checkbox' | 'radio';
48
+
49
+ /**
50
+ * The indicators Astryx ships. A theme's `indicators` entries override these
51
+ * by name.
52
+ *
53
+ * Typed per family (rather than as one widened component type) so a default
54
+ * declared here has to accept the states its family passes — the same rule
55
+ * {@link IndicatorRegistry} holds replacements to.
56
+ */
57
+ export const defaultIndicators: {
58
+ [N in CoreIndicatorName]: IndicatorComponent<IndicatorMap[N]>;
59
+ } = {
60
+ check: CheckIndicator,
61
+ checkbox: CheckboxIndicator,
62
+ radio: RadioIndicator,
63
+ };
64
+
65
+ export type IndicatorRegistrySource = DefinedTheme | string | null | undefined;
66
+
67
+ function getTheme(source: IndicatorRegistrySource): DefinedTheme | null {
68
+ if (source == null) {
69
+ return null;
70
+ }
71
+ return typeof source === 'string' ? getRegisteredTheme(source) : source;
72
+ }
73
+
74
+ function getThemeIndicators(
75
+ source: IndicatorRegistrySource,
76
+ ): IndicatorRegistry | null {
77
+ return getTheme(source)?.indicators ?? null;
78
+ }
79
+
80
+ /**
81
+ * Resolve an indicator component by name, preferring the theme's override and
82
+ * falling back to the built-in indicator.
83
+ *
84
+ * Works in both server and client environments. Client components should use
85
+ * the {@link useIndicator} hook, which resolves against the nearest `<Theme>`.
86
+ *
87
+ * @example
88
+ * ```
89
+ * const Radio = getIndicator('radio', themeName);
90
+ * <Radio state="checked" />
91
+ * ```
92
+ *
93
+ * For a name contributed by augmentation there is no built-in to fall back to,
94
+ * so the result is `undefined` unless a theme supplies one — the package that
95
+ * added the name owns its default:
96
+ *
97
+ * @example
98
+ * ```
99
+ * const Star = getIndicator('brand-star', themeName) ?? BrandStar;
100
+ * ```
101
+ */
102
+ export function getIndicator<N extends CoreIndicatorName>(
103
+ name: N,
104
+ source?: IndicatorRegistrySource,
105
+ ): IndicatorComponent<IndicatorMap[N]>;
106
+ export function getIndicator<N extends IndicatorName>(
107
+ name: N,
108
+ source?: IndicatorRegistrySource,
109
+ ): IndicatorComponent<IndicatorMap[N]> | undefined;
110
+ export function getIndicator(
111
+ name: IndicatorName,
112
+ source?: IndicatorRegistrySource,
113
+ ): IndicatorComponent | undefined {
114
+ const override = getThemeIndicators(source)?.[name];
115
+ return (override ??
116
+ // `name` may be an augmented one, which this map has no entry for — hence
117
+ // the `| undefined` the overloads expose to those callers.
118
+ (defaultIndicators as Partial<Record<IndicatorName, unknown>>)[name]) as
119
+ IndicatorComponent | undefined;
120
+ }
@@ -0,0 +1,186 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file types.ts
5
+ * @input None (pure type definitions)
6
+ * @output The indicator contract: families, states, props, names, registry
7
+ * @position Type foundation for stateful control visuals
8
+ *
9
+ * An **indicator** is a decorative visual that expresses a piece of component
10
+ * state: the box a checkbox draws, the circle a radio draws, the mark on a
11
+ * chosen list option. The owning component keeps the input, role, accessible
12
+ * name, focus, and keyboard behavior; the indicator turns state into a picture.
13
+ *
14
+ * Componentizing them buys three things a theme could not otherwise have:
15
+ *
16
+ * 1. **Theme it** — an indicator renders stable `astryx-*` class targets, so
17
+ * `defineTheme({components})` restyles it like any other component, in one
18
+ * place rather than per host component.
19
+ * 2. **Swizzle it** — `astryx swizzle <Name>` copies the source to own.
20
+ * 3. **Replace it** — `defineTheme({indicators})` swaps in another component
21
+ * by name, and every component that renders that indicator follows. A
22
+ * product that wants radio visuals for single selection replaces `check`.
23
+ *
24
+ * Indicators come in **families**, and a family fixes the state space. That is
25
+ * what lets one mechanism serve semantics as different as "is this option
26
+ * chosen" and "are several of these chosen" without either pretending to be
27
+ * the other, and without a shared enum that would typecheck `indeterminate` on
28
+ * a radio.
29
+ *
30
+ * Each family's vocabulary is the one the accessibility layer already uses, so
31
+ * a component passing state down says the same word its ARIA attribute says.
32
+ * Sharing one enum across families was measured and rejected (#4831): it
33
+ * produced call sites reading `aria-expanded={isOpen}` beside
34
+ * `state={isOpen ? 'on' : 'off'}`.
35
+ */
36
+
37
+ import type {ComponentType, ReactNode, Ref} from 'react';
38
+ import type {BaseProps} from '../BaseProps';
39
+
40
+ /**
41
+ * The indicator families, each mapped to the states it can express.
42
+ *
43
+ * Single and multi selection are separate families because their state spaces
44
+ * genuinely differ: `aria-checked` is `true|false` for a radio and
45
+ * `true|false|mixed` for a checkbox. Keeping them apart is what makes a
46
+ * replacement type-checkable — a checkbox visual cannot stand in where only
47
+ * two states are ever passed, and a radio cannot be asked to draw a partial
48
+ * state it has no picture for.
49
+ *
50
+ * Adding a family is additive: declare it here, then declare indicators of
51
+ * that family in {@link IndicatorMap}. Packages outside core can contribute
52
+ * families through module augmentation.
53
+ */
54
+ export interface IndicatorFamilyMap {
55
+ /** Is this one thing chosen? Radios, and the mark on a selected option. */
56
+ singleSelection: 'unchecked' | 'checked';
57
+ /** Which of these are chosen? Checkboxes, including the partial state. */
58
+ multiSelection: 'unchecked' | 'checked' | 'indeterminate';
59
+ }
60
+
61
+ export type IndicatorFamily = keyof IndicatorFamilyMap & string;
62
+
63
+ /** The states an indicator of family `F` can be asked to draw. */
64
+ export type IndicatorState<F extends IndicatorFamily = IndicatorFamily> =
65
+ IndicatorFamilyMap[F];
66
+
67
+ /** Indicator size scale — matches the control sizes of the owning inputs. */
68
+ export type IndicatorSize = 'sm' | 'md';
69
+
70
+ /**
71
+ * Props every indicator accepts.
72
+ *
73
+ * Indicators are **decorative**: they render `aria-hidden` visuals and own no
74
+ * role, focus, keyboard handling, or state. The component that renders one
75
+ * (CheckboxInput, RadioListItem, a listbox option) keeps all of that. An
76
+ * indicator's only job is to turn `state` into a picture.
77
+ *
78
+ * The a11y props are omitted from this interface rather than left to
79
+ * convention: un-hiding an indicator has it announced next to the control that
80
+ * owns the accessible name — the same thing said twice (#4918). A replacement
81
+ * that genuinely needs announcing is not an indicator; name the owning control.
82
+ *
83
+ * `tabIndex` is omitted for the same reason, one step on: the element is
84
+ * unconditionally `aria-hidden`, so a tab stop on it is a focusable node inside
85
+ * a hidden subtree. Measured with axe in real Chromium: 0 `aria-hidden-focus`
86
+ * violations becomes 1 the moment it is forwarded.
87
+ *
88
+ * The omission is only half enforceable, and it is worth knowing which half.
89
+ * TypeScript exempts JSX attribute names that are not valid JS identifiers from
90
+ * excess-property checking, so a LITERAL `role=` is a compile error while
91
+ * `aria-hidden` and `aria-label` are not — and a spread (`{...props}`, the
92
+ * ordinary host idiom) bypasses the check for every member, `role` included.
93
+ * Measured, not assumed. So the components also emit their own `aria-hidden`
94
+ * AFTER `{...rest}` and drop a forwarded `tabIndex`: that ordering, not the
95
+ * type, is what enforces the contract. Nothing else is stripped — a forwarded
96
+ * `aria-label` still reaches the DOM, inert inside an `aria-hidden` subtree.
97
+ *
98
+ * Interaction state is deliberately *not* a prop. Hover and focus reach an
99
+ * indicator through the CSS ancestor marker ({@link indicatorScope}) applied
100
+ * by its owner, so a row hover tints the control without anyone threading a
101
+ * boolean through React — and an owner that should not tint its indicator
102
+ * simply does not apply the marker.
103
+ */
104
+ export interface IndicatorProps<
105
+ F extends IndicatorFamily = IndicatorFamily,
106
+ > extends Omit<
107
+ BaseProps<HTMLSpanElement>,
108
+ 'aria-hidden' | 'role' | 'aria-label' | 'aria-labelledby' | 'tabIndex'
109
+ > {
110
+ /** Ref forwarded to the indicator's root element. */
111
+ ref?: Ref<HTMLSpanElement>;
112
+ /** Which state to draw. The state space is fixed by the family. */
113
+ state: IndicatorState<F>;
114
+ /**
115
+ * Control size.
116
+ * @default 'md'
117
+ */
118
+ size?: IndicatorSize;
119
+ /**
120
+ * Whether the owning control is disabled. Purely visual — the owner still
121
+ * owns the actual disabled semantics.
122
+ * @default false
123
+ */
124
+ isDisabled?: boolean;
125
+ /**
126
+ * Content rendered inside the indicator chrome *instead of* the state mark.
127
+ * CheckboxInput uses this to show a loading Spinner inside the box while a
128
+ * change action is pending.
129
+ */
130
+ children?: ReactNode;
131
+ }
132
+
133
+ /** An indicator is any component accepting {@link IndicatorProps} of its family. */
134
+ export type IndicatorComponent<F extends IndicatorFamily = IndicatorFamily> =
135
+ ComponentType<IndicatorProps<F>>;
136
+
137
+ /**
138
+ * The named indicators a theme can replace, each mapped to its family.
139
+ *
140
+ * The name is what a theme addresses, and what every component renders
141
+ * through — so replacing `check` reaches every single-selection mark at once,
142
+ * which is the point.
143
+ *
144
+ * Packages outside core can contribute their own through module augmentation.
145
+ * Core ships no default for a name it does not know, so the package that adds
146
+ * the name owns its default — `getIndicator`/`useIndicator` return
147
+ * `| undefined` for it, and the call site supplies the fallback:
148
+ *
149
+ * ```ts
150
+ * declare module '@astryxdesign/core/Indicator' {
151
+ * interface IndicatorMap {
152
+ * 'brand-star': 'singleSelection';
153
+ * }
154
+ * }
155
+ *
156
+ * const Star = useIndicator('brand-star') ?? BrandStar;
157
+ * ```
158
+ */
159
+ export interface IndicatorMap {
160
+ /** The mark on a chosen option — a checkmark by default. */
161
+ check: 'singleSelection';
162
+ /** The filled circle of a radio control. */
163
+ radio: 'singleSelection';
164
+ /** The box of a checkbox control, including its partial state. */
165
+ checkbox: 'multiSelection';
166
+ }
167
+
168
+ export type IndicatorName = keyof IndicatorMap & string;
169
+
170
+ /** The indicator names belonging to family `F`. */
171
+ export type IndicatorNameOfFamily<F extends IndicatorFamily> = {
172
+ [N in IndicatorName]: IndicatorMap[N] extends F ? N : never;
173
+ }[IndicatorName];
174
+
175
+ /**
176
+ * Theme-provided indicator overrides, keyed by indicator name.
177
+ *
178
+ * Family-checked: each entry must accept the state space of that indicator's
179
+ * family, so a replacement cannot be written against the wrong states. A
180
+ * `check` replacement that only handles `collapsed`/`expanded`, or a `radio`
181
+ * replacement expecting `indeterminate`, is a type error rather than a
182
+ * runtime surprise.
183
+ */
184
+ export type IndicatorRegistry = {
185
+ [N in IndicatorName]?: IndicatorComponent<IndicatorMap[N]>;
186
+ };
@@ -0,0 +1,39 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file useIndicator.ts
7
+ * @input Indicator name
8
+ * @output Exports useIndicator hook for theme-aware indicator components
9
+ * @position Client hook used by controls that render a selection visual
10
+ */
11
+
12
+ import {useThemeName} from '../theme/useTheme';
13
+ import {getIndicator, type CoreIndicatorName} from './indicatorRegistry';
14
+ import type {IndicatorComponent, IndicatorMap, IndicatorName} from './types';
15
+
16
+ /**
17
+ * Resolve an indicator component from the nearest `<Theme>`.
18
+ *
19
+ * A core indicator always resolves. A name contributed by augmentation
20
+ * resolves only if a theme supplies it, so that overload returns
21
+ * `| undefined` — see {@link getIndicator}.
22
+ *
23
+ * @example
24
+ * ```
25
+ * const Checkbox = useIndicator('checkbox');
26
+ * return <Checkbox state={isChecked ? 'checked' : 'unchecked'} size={size} />;
27
+ * ```
28
+ */
29
+ export function useIndicator<N extends CoreIndicatorName>(
30
+ name: N,
31
+ ): IndicatorComponent<IndicatorMap[N]>;
32
+ export function useIndicator<N extends IndicatorName>(
33
+ name: N,
34
+ ): IndicatorComponent<IndicatorMap[N]> | undefined;
35
+ export function useIndicator(
36
+ name: IndicatorName,
37
+ ): IndicatorComponent | undefined {
38
+ return getIndicator(name, useThemeName());
39
+ }
@@ -37,7 +37,7 @@ export const docs = {
37
37
  {name: 'labelLines', type: 'number', description: 'Max lines before label truncates with ellipsis.'},
38
38
  {name: 'descriptionLines', type: 'number', description: 'Max lines before description truncates with ellipsis.'},
39
39
  {name: 'onClick', type: '(event: MouseEvent) => void', description: 'Click handler. Makes the item clickable with button semantics.'},
40
- {name: 'interactiveRef', type: 'RefObject<HTMLElement | null>', description: 'Ref to a nested control (e.g. a checkbox in startContent) that owns the item\'s keyboard access and action. The row becomes an enlarged click/tap target that delegates surface clicks to it (useClickableContainer) and renders no invisible button/anchor, so the row adds no second tab stop (WCAG 4.1.2). Mutually exclusive with onClick/href those are ignored when set.'},
40
+ {name: 'interactiveRef', type: 'RefObject<HTMLElement | null>', description: 'Ref to a nested control (e.g. a checkbox in startContent) that owns the item\'s keyboard access and action. The row becomes an enlarged click/tap target that delegates surface clicks to it (useClickableContainer) and renders no invisible button/anchor, so the row adds no second tab stop (WCAG 4.1.2). Mutually exclusive with onClick/href; those are ignored when set.'},
41
41
  {name: 'href', type: 'string', description: 'Link URL. Makes the item a link via an invisible anchor element.'},
42
42
  {name: 'target', type: "'_blank' | '_self'", description: 'Link target. Only used with href. target="_blank" automatically adds noopener noreferrer.'},
43
43
  {name: 'rel', type: 'string', description: 'Link relationship tokens. noopener noreferrer are merged automatically for target="_blank".'},
package/src/Item/Item.tsx CHANGED
@@ -33,6 +33,7 @@ import {useLinkComponent} from '../Link/useLinkComponent';
33
33
  import {useClickableContainer} from '../hooks/useClickableContainer';
34
34
  import {useDevWarning} from '../hooks/useDevWarning';
35
35
  import {themeProps} from '../utils/themeProps';
36
+ import {focusOutlineProps} from '../utils/focusOutline.stylex';
36
37
 
37
38
  // =============================================================================
38
39
  // Types
@@ -218,16 +219,6 @@ const styles = stylex.create({
218
219
  ':active': colorVars['--color-overlay-pressed'],
219
220
  },
220
221
  },
221
- focusVisibleOutline: {
222
- outline: {
223
- default: 'none',
224
- ':has(:focus-visible)': `2px solid ${colorVars['--color-accent']}`,
225
- },
226
- outlineOffset: {
227
- default: '0',
228
- ':has(:focus-visible)': '2px',
229
- },
230
- },
231
222
  highlighted: {
232
223
  backgroundColor: colorVars['--color-overlay-hover'],
233
224
  },
@@ -274,7 +265,9 @@ const styles = stylex.create({
274
265
  textAlign: 'start',
275
266
  },
276
267
  label: {
277
- color: colorVars['--color-text-primary'],
268
+ // Falls back to the primary text token; a parent (e.g. a destructive menu
269
+ // item) can recolor the label by setting --_item-label-color.
270
+ color: `var(--_item-label-color, ${colorVars['--color-text-primary']})`,
278
271
  fontSize: typeScaleVars['--text-body-size'],
279
272
  lineHeight: typeScaleVars['--text-body-leading'],
280
273
  },
@@ -289,7 +282,8 @@ const styles = stylex.create({
289
282
  WebkitBoxOrient: 'vertical' as const,
290
283
  },
291
284
  description: {
292
- color: colorVars['--color-text-secondary'],
285
+ // Companion to --_item-label-color for the secondary line.
286
+ color: `var(--_item-description-color, ${colorVars['--color-text-secondary']})`,
293
287
  fontSize: typeScaleVars['--text-supporting-size'],
294
288
  lineHeight: typeScaleVars['--text-supporting-leading'],
295
289
  },
@@ -555,12 +549,11 @@ export function Item({
555
549
  aria-disabled={isDisabled || undefined}
556
550
  {...mergeProps(
557
551
  themeProps('item', {density, align}),
558
- stylex.props(
552
+ focusOutlineProps.focusWithin(
559
553
  styles.root,
560
554
  densityStyles[density],
561
555
  align === 'start' && styles.alignStart,
562
556
  isInteractive && styles.interactive,
563
- isInteractive && styles.focusVisibleOutline,
564
557
  isHighlighted && styles.highlighted,
565
558
  isSelected && styles.selected,
566
559
  isDisabled && !hasParentRole && styles.disabled,
@@ -79,7 +79,7 @@ export const docs = {
79
79
  name: 'render',
80
80
  type: '(children: ReactNode, props: ContextRenderProps | FixedRenderProps) => ReactNode',
81
81
  description:
82
- 'Render function for the popover element. Pass placement/alignment in context mode or x/y in fixed mode. Placement/alignment are logical: they map to the self-* position-area keyword family, which resolves against the popover\'s own inherited direction, so RTL contexts mirror automatically in pure CSS. Pass `positioning: "custom"` in context mode to author position styles yourself via `style` (e.g. explicit anchor() insets or an anchor-size() cover): the hook keeps the popover behavior and position-anchor wiring but derives no position styles, including the automatic RTL mirroring, which becomes your responsibility. In context mode, pass `as: "span"` to render an inline-safe layer (e.g. inside a paragraph). The layer renders inline in the React tree; the Popover API promotes it to the top layer when shown, so it escapes ancestor clipping and stacking without a portal. When the layer would overflow the viewport, position-try fallbacks flip it to the opposite side; centered layers additionally slide along the alignment axis (span fallbacks) so they stay on-screen near viewport edges.',
82
+ 'Render function for the popover element. Pass placement/alignment in context mode or x/y in fixed mode. Placement/alignment are logical: they map to the self-* position-area keyword family, which resolves against the popover\'s own inherited direction, so RTL contexts mirror automatically in pure CSS. Pass `positioning: "custom"` in context mode to author position styles yourself via `style` (e.g. explicit anchor() insets or an anchor-size() cover): the hook keeps the popover behavior and position-anchor wiring but derives no position styles, including the automatic RTL mirroring, which becomes your responsibility. Pass `offset` (a CSS length; a number is px) in context mode for clearance from the anchor: it applies to both edges of the placement axis, so the gap survives a flip. Layers are flush by default. In context mode, pass `as: "span"` to render an inline-safe layer (e.g. inside a paragraph). The layer renders inline in the React tree; the Popover API promotes it to the top layer when shown, so it escapes ancestor clipping and stacking without a portal. When the layer would overflow the viewport, position-try fallbacks flip it to the opposite side; centered layers additionally slide along the alignment axis (span fallbacks) so they stay on-screen near viewport edges.',
83
83
  },
84
84
  ],
85
85
  usage: {
@@ -131,7 +131,7 @@ export const docsDense = {
131
131
  hide: 'hide layer.',
132
132
  isOpen: 'whether layer is open.',
133
133
  id: 'unique ARIA id.',
134
- render: 'renders popover element; pass placement/alignment or x/y. Placement/alignment logical: mapped to self-* position-area keywords resolved against the popover\'s inherited direction (RTL mirrors in pure CSS). `positioning: "custom"` (context mode) = author position styles yourself via `style`; keeps popover behavior + position-anchor wiring, derives nothing (incl. RTL mirroring, which becomes yours). Context mode accepts `as: "span"` for inline-safe layers. Renders inline; the Popover API top layer escapes clipping/stacking without a portal. Viewport overflow: flips to opposite side; centered layers also slide along the alignment axis (span fallbacks).',
134
+ render: 'renders popover element; pass placement/alignment or x/y. Placement/alignment logical: mapped to self-* position-area keywords resolved against the popover\'s inherited direction (RTL mirrors in pure CSS). `positioning: "custom"` (context mode) = author position styles yourself via `style`; keeps popover behavior + position-anchor wiring, derives nothing (incl. RTL mirroring, which becomes yours). `offset` (context mode) = clearance from the anchor as a CSS length (number = px), applied to both edges of the placement axis so it survives a flip; layers are flush by default. Context mode accepts `as: "span"` for inline-safe layers. Renders inline; the Popover API top layer escapes clipping/stacking without a portal. Viewport overflow: flips to opposite side; centered layers also slide along the alignment axis (span fallbacks).',
135
135
  },
136
136
  usage: {
137
137
  description:
@@ -440,6 +440,91 @@ describe('useLayer context positioning', () => {
440
440
  });
441
441
  });
442
442
 
443
+ describe('offset', () => {
444
+ function OffsetHarness({
445
+ placement,
446
+ offset,
447
+ positioning,
448
+ }: {
449
+ placement?: LayerPlacement;
450
+ offset?: number | string;
451
+ positioning?: 'anchor' | 'custom';
452
+ }) {
453
+ const layer = useLayer({mode: 'context'});
454
+ return (
455
+ <>
456
+ <button type="button" ref={layer.ref} onClick={layer.show}>
457
+ trigger
458
+ </button>
459
+ {layer.render(<span>content</span>, {
460
+ placement,
461
+ offset,
462
+ positioning,
463
+ })}
464
+ </>
465
+ );
466
+ }
467
+
468
+ // Debug-mode StyleX variable names for the dynamic offset style, as in
469
+ // Grid.test.tsx. jsdom resolves neither the var indirection nor logical
470
+ // margin properties, so the declarations themselves are the assertion.
471
+ async function openAndGetOffsets(ui: React.ReactElement) {
472
+ const user = userEvent.setup();
473
+ const {container, getByRole} = render(ui);
474
+ await user.click(getByRole('button', {name: 'trigger'}));
475
+ const el = container.querySelector('[popover]') as HTMLElement;
476
+ const read = (prop: string) => el.style.getPropertyValue(`--x-${prop}`);
477
+ return {
478
+ blockStart: read('marginBlockStart'),
479
+ blockEnd: read('marginBlockEnd'),
480
+ inlineStart: read('marginInlineStart'),
481
+ inlineEnd: read('marginInlineEnd'),
482
+ };
483
+ }
484
+
485
+ const NONE = {blockStart: '', blockEnd: '', inlineStart: '', inlineEnd: ''};
486
+
487
+ it('is flush by default', async () => {
488
+ expect(await openAndGetOffsets(<OffsetHarness placement="below" />)).toEqual(
489
+ NONE,
490
+ );
491
+ });
492
+
493
+ // Both edges of the axis, so the gap survives a position-try-fallbacks
494
+ // flip to the opposite side (#4803).
495
+ it('clears both block edges for a block placement', async () => {
496
+ expect(
497
+ await openAndGetOffsets(<OffsetHarness placement="above" offset={8} />),
498
+ ).toEqual({...NONE, blockStart: '8px', blockEnd: '8px'});
499
+ });
500
+
501
+ it('clears both inline edges for an inline placement', async () => {
502
+ expect(
503
+ await openAndGetOffsets(<OffsetHarness placement="end" offset={8} />),
504
+ ).toEqual({...NONE, inlineStart: '8px', inlineEnd: '8px'});
505
+ });
506
+
507
+ it('takes a CSS length string', async () => {
508
+ expect(
509
+ await openAndGetOffsets(
510
+ <OffsetHarness placement="below" offset="var(--spacing-1)" />,
511
+ ),
512
+ ).toEqual({
513
+ ...NONE,
514
+ blockStart: 'var(--spacing-1)',
515
+ blockEnd: 'var(--spacing-1)',
516
+ });
517
+ });
518
+
519
+ it('is ignored under custom positioning, which owns its own insets', async () => {
520
+ expect(
521
+ await openAndGetOffsets(
522
+ <OffsetHarness placement="below" offset={8} positioning="custom" />,
523
+ ),
524
+ ).toEqual(NONE);
525
+ });
526
+ });
527
+
443
528
  it('fixed mode emits no anchor-positioning styles', async () => {
444
529
  function FixedHarness() {
445
530
  const layer = useLayer({mode: 'fixed'});