@astryxdesign/core 0.1.9 → 0.2.0-canary.0e01213

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 (625) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/dist/Avatar/Avatar.d.ts +42 -3
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +190 -59
  5. package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
  6. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  7. package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
  8. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  9. package/dist/AvatarGroup/AvatarGroup.js +58 -6
  10. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  11. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  12. package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -2
  13. package/dist/Banner/Banner.js +2 -2
  14. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  15. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
  16. package/dist/Breadcrumbs/index.d.ts +1 -0
  17. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  18. package/dist/Breadcrumbs/index.js +2 -1
  19. package/dist/Button/Button.d.ts +1 -1
  20. package/dist/Button/Button.d.ts.map +1 -1
  21. package/dist/Button/Button.js +6 -4
  22. package/dist/Calendar/Calendar.d.ts.map +1 -1
  23. package/dist/Calendar/Calendar.js +50 -9
  24. package/dist/Calendar/dayCellUtils.d.ts +4 -4
  25. package/dist/Calendar/dayCellUtils.js +2 -2
  26. package/dist/Calendar/styles.d.ts +30 -31
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +30 -31
  29. package/dist/Card/Card.js +1 -1
  30. package/dist/Carousel/Carousel.d.ts.map +1 -1
  31. package/dist/Carousel/Carousel.js +22 -12
  32. package/dist/Center/Center.d.ts +20 -3
  33. package/dist/Center/Center.d.ts.map +1 -1
  34. package/dist/Center/Center.js +10 -2
  35. package/dist/Chat/ChatComposerInput.js +1 -1
  36. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  37. package/dist/Chat/ChatDictationButton.js +3 -1
  38. package/dist/Chat/ChatLayout.d.ts +7 -0
  39. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  40. package/dist/Chat/ChatLayout.js +16 -5
  41. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  42. package/dist/Chat/ChatMessageBubble.js +8 -8
  43. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  44. package/dist/Chat/ChatToolCalls.js +10 -3
  45. package/dist/Chat/useTriggerMenu.js +2 -2
  46. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  47. package/dist/CheckboxInput/CheckboxInput.js +6 -6
  48. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  49. package/dist/CheckboxList/CheckboxListItem.js +19 -4
  50. package/dist/Citation/Citation.d.ts +22 -1
  51. package/dist/Citation/Citation.d.ts.map +1 -1
  52. package/dist/Citation/Citation.js +20 -6
  53. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  54. package/dist/CodeBlock/CodeBlock.js +16 -10
  55. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  56. package/dist/Collapsible/Collapsible.js +3 -1
  57. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  58. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  59. package/dist/CommandPalette/CommandPalette.js +42 -3
  60. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  61. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  62. package/dist/ContextMenu/ContextMenu.js +23 -5
  63. package/dist/ContextMenu/index.d.ts +1 -0
  64. package/dist/ContextMenu/index.d.ts.map +1 -1
  65. package/dist/ContextMenu/index.js +3 -1
  66. package/dist/DateInput/DateInput.d.ts +10 -2
  67. package/dist/DateInput/DateInput.d.ts.map +1 -1
  68. package/dist/DateInput/DateInput.js +33 -19
  69. package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
  70. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  71. package/dist/DateRangeInput/DateRangeInput.js +23 -20
  72. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  73. package/dist/DateTimeInput/DateTimeInput.js +23 -18
  74. package/dist/Divider/Divider.d.ts +2 -2
  75. package/dist/Divider/Divider.d.ts.map +1 -1
  76. package/dist/Divider/Divider.js +13 -0
  77. package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
  78. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  79. package/dist/DropdownMenu/DropdownMenu.js +22 -5
  80. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +18 -12
  81. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  82. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +42 -64
  83. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
  85. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
  86. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  87. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
  88. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  89. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  90. package/dist/DropdownMenu/DropdownMenuRadioItem.js +10 -3
  91. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
  92. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
  93. package/dist/DropdownMenu/DropdownMenuSubMenu.js +435 -0
  94. package/dist/DropdownMenu/index.d.ts +10 -0
  95. package/dist/DropdownMenu/index.d.ts.map +1 -1
  96. package/dist/DropdownMenu/index.js +13 -0
  97. package/dist/DropdownMenu/menuItemHover.d.ts +24 -0
  98. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
  99. package/dist/DropdownMenu/menuItemHover.js +34 -0
  100. package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
  101. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
  102. package/dist/DropdownMenu/menuItemRoles.js +10 -1
  103. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  104. package/dist/DropdownMenu/renderDropdownItems.js +27 -10
  105. package/dist/Field/Field.d.ts +3 -1
  106. package/dist/Field/Field.d.ts.map +1 -1
  107. package/dist/Field/Field.js +4 -1
  108. package/dist/Field/FieldLabel.d.ts +2 -1
  109. package/dist/Field/FieldLabel.d.ts.map +1 -1
  110. package/dist/Field/FieldLabel.js +9 -5
  111. package/dist/Field/inputStyles.stylex.d.ts +1 -0
  112. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  113. package/dist/Field/inputStyles.stylex.js +1 -0
  114. package/dist/FieldStatus/FieldStatus.d.ts +10 -0
  115. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  116. package/dist/FieldStatus/FieldStatus.js +51 -5
  117. package/dist/FileInput/FileInput.d.ts +10 -2
  118. package/dist/FileInput/FileInput.d.ts.map +1 -1
  119. package/dist/FileInput/FileInput.js +93 -65
  120. package/dist/Heading/Heading.d.ts.map +1 -1
  121. package/dist/Heading/Heading.js +3 -2
  122. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  123. package/dist/HoverCard/useHoverCard.js +10 -4
  124. package/dist/Icon/Icon.d.ts +15 -1
  125. package/dist/Icon/Icon.d.ts.map +1 -1
  126. package/dist/Icon/Icon.js +19 -3
  127. package/dist/Item/Item.d.ts +16 -3
  128. package/dist/Item/Item.d.ts.map +1 -1
  129. package/dist/Item/Item.js +31 -6
  130. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  131. package/dist/Layer/layerAnimations.stylex.js +10 -2
  132. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  133. package/dist/Lightbox/Lightbox.js +34 -15
  134. package/dist/List/List.d.ts.map +1 -1
  135. package/dist/List/List.js +6 -3
  136. package/dist/List/ListItem.d.ts +11 -1
  137. package/dist/List/ListItem.d.ts.map +1 -1
  138. package/dist/List/ListItem.js +2 -0
  139. package/dist/Markdown/Markdown.d.ts.map +1 -1
  140. package/dist/Markdown/Markdown.js +7 -0
  141. package/dist/MetadataList/MetadataList.d.ts +1 -1
  142. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  143. package/dist/MetadataList/MetadataList.js +4 -2
  144. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  145. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  146. package/dist/MultiSelector/MultiSelector.js +87 -45
  147. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  148. package/dist/NumberInput/NumberInput.d.ts +10 -2
  149. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  150. package/dist/NumberInput/NumberInput.js +22 -17
  151. package/dist/Outline/Outline.js +2 -2
  152. package/dist/Pagination/Pagination.d.ts.map +1 -1
  153. package/dist/Pagination/Pagination.js +11 -3
  154. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  155. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  156. package/dist/PowerSearch/PowerSearch.js +2 -0
  157. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  158. package/dist/ProgressBar/ProgressBar.js +6 -1
  159. package/dist/RadioList/RadioList.d.ts +2 -2
  160. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  161. package/dist/RadioList/RadioListItem.js +5 -5
  162. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  163. package/dist/Resizable/ResizeHandle.js +49 -19
  164. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  165. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  166. package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
  167. package/dist/Selector/Selector.d.ts +8 -0
  168. package/dist/Selector/Selector.d.ts.map +1 -1
  169. package/dist/Selector/Selector.js +72 -19
  170. package/dist/SideNav/SideNav.d.ts.map +1 -1
  171. package/dist/SideNav/SideNav.js +5 -5
  172. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  173. package/dist/SideNav/SideNavCollapseButton.js +13 -10
  174. package/dist/SideNav/SideNavItem.d.ts +1 -1
  175. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  176. package/dist/SideNav/SideNavItem.js +12 -10
  177. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  178. package/dist/Skeleton/Skeleton.js +2 -2
  179. package/dist/Slider/Slider.d.ts.map +1 -1
  180. package/dist/Slider/Slider.js +87 -34
  181. package/dist/Spinner/Spinner.d.ts +3 -2
  182. package/dist/Spinner/Spinner.d.ts.map +1 -1
  183. package/dist/Spinner/Spinner.js +11 -2
  184. package/dist/Switch/Switch.d.ts +8 -1
  185. package/dist/Switch/Switch.d.ts.map +1 -1
  186. package/dist/Switch/Switch.js +171 -91
  187. package/dist/TabList/Tab.js +2 -2
  188. package/dist/TabList/TabList.d.ts +2 -11
  189. package/dist/TabList/TabList.d.ts.map +1 -1
  190. package/dist/TabList/TabList.js +5 -9
  191. package/dist/TabList/TabListContext.d.ts +0 -5
  192. package/dist/TabList/TabListContext.d.ts.map +1 -1
  193. package/dist/TabList/TabListContext.js +0 -5
  194. package/dist/TabList/TabMenu.js +1 -1
  195. package/dist/Table/BaseTable.d.ts.map +1 -1
  196. package/dist/Table/BaseTable.js +30 -4
  197. package/dist/Table/TableCell.js +3 -3
  198. package/dist/Table/TableHeaderCell.js +3 -3
  199. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  200. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
  201. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +18 -3
  202. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  203. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +58 -30
  204. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  205. package/dist/Table/plugins/selection/useTableSelection.js +3 -0
  206. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  207. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
  208. package/dist/Table/plugins/tree/useTableTreeData.d.ts +11 -0
  209. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  210. package/dist/Table/plugins/tree/useTableTreeData.js +65 -25
  211. package/dist/Table/types.d.ts +32 -0
  212. package/dist/Table/types.d.ts.map +1 -1
  213. package/dist/Text/Text.d.ts +10 -1
  214. package/dist/Text/Text.d.ts.map +1 -1
  215. package/dist/Text/Text.js +25 -2
  216. package/dist/Text/index.d.ts +2 -2
  217. package/dist/Text/index.d.ts.map +1 -1
  218. package/dist/TextArea/TextArea.d.ts +10 -1
  219. package/dist/TextArea/TextArea.d.ts.map +1 -1
  220. package/dist/TextArea/TextArea.js +119 -52
  221. package/dist/TextInput/TextInput.d.ts +10 -2
  222. package/dist/TextInput/TextInput.d.ts.map +1 -1
  223. package/dist/TextInput/TextInput.js +20 -17
  224. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  225. package/dist/Thumbnail/Thumbnail.js +51 -45
  226. package/dist/TimeInput/TimeInput.d.ts +10 -2
  227. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  228. package/dist/TimeInput/TimeInput.js +17 -17
  229. package/dist/Timestamp/Timestamp.d.ts +31 -3
  230. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  231. package/dist/Timestamp/Timestamp.js +48 -77
  232. package/dist/Timestamp/formatInstant.d.ts +41 -0
  233. package/dist/Timestamp/formatInstant.d.ts.map +1 -0
  234. package/dist/Timestamp/formatInstant.js +177 -0
  235. package/dist/Timestamp/index.d.ts +1 -0
  236. package/dist/Timestamp/index.d.ts.map +1 -1
  237. package/dist/Timestamp/tooltipEntries.d.ts +56 -0
  238. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
  239. package/dist/Timestamp/tooltipEntries.js +163 -0
  240. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  241. package/dist/Toast/ToastViewport.js +61 -9
  242. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  243. package/dist/ToggleButton/ToggleButton.js +3 -1
  244. package/dist/Token/Token.d.ts +34 -4
  245. package/dist/Token/Token.d.ts.map +1 -1
  246. package/dist/Token/Token.js +85 -45
  247. package/dist/Token/TokenLink.d.ts +62 -0
  248. package/dist/Token/TokenLink.d.ts.map +1 -0
  249. package/dist/Token/TokenLink.js +76 -0
  250. package/dist/Token/index.d.ts +1 -1
  251. package/dist/Token/index.d.ts.map +1 -1
  252. package/dist/Tokenizer/Tokenizer.d.ts +9 -2
  253. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  254. package/dist/Tokenizer/Tokenizer.js +4 -2
  255. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  256. package/dist/Tooltip/useTooltip.js +17 -1
  257. package/dist/TopNav/TopNavItem.d.ts +3 -1
  258. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  259. package/dist/TopNav/TopNavItem.js +30 -3
  260. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  261. package/dist/TopNav/TopNavMegaMenu.js +9 -3
  262. package/dist/TreeList/TreeList.d.ts.map +1 -1
  263. package/dist/TreeList/TreeList.js +1 -0
  264. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  265. package/dist/TreeList/TreeListBranches.js +8 -6
  266. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  267. package/dist/TreeList/TreeListItem.js +32 -14
  268. package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
  269. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  270. package/dist/Typeahead/BaseTypeahead.js +22 -11
  271. package/dist/Typeahead/Typeahead.d.ts +9 -2
  272. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  273. package/dist/Typeahead/Typeahead.js +11 -2
  274. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  275. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  276. package/dist/Typeahead/TypeaheadItem.js +20 -10
  277. package/dist/astryx.css +115 -35
  278. package/dist/astryx.umd.js +51 -51
  279. package/dist/astryx.umd.js.map +4 -4
  280. package/dist/hooks/containerReveal.pool.stylex.d.ts +281 -0
  281. package/dist/hooks/containerReveal.pool.stylex.d.ts.map +1 -0
  282. package/dist/hooks/containerReveal.pool.stylex.js +281 -0
  283. package/dist/hooks/index.d.ts +4 -0
  284. package/dist/hooks/index.d.ts.map +1 -1
  285. package/dist/hooks/index.js +3 -1
  286. package/dist/hooks/isRtlElement.d.ts +18 -0
  287. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  288. package/dist/hooks/isRtlElement.js +27 -0
  289. package/dist/hooks/useAnnounce.d.ts +3 -0
  290. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  291. package/dist/hooks/useAnnounce.js +39 -1
  292. package/dist/hooks/useContainerReveal.d.ts +83 -0
  293. package/dist/hooks/useContainerReveal.d.ts.map +1 -0
  294. package/dist/hooks/useContainerReveal.js +123 -0
  295. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  296. package/dist/hooks/useFocusTrap.js +52 -11
  297. package/dist/hooks/useGridFocus.d.ts +6 -1
  298. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  299. package/dist/hooks/useGridFocus.js +12 -9
  300. package/dist/hooks/useHotkeys.d.ts +9 -0
  301. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  302. package/dist/hooks/useHotkeys.js +9 -0
  303. package/dist/hooks/useInputStatusIcon.d.ts +38 -0
  304. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
  305. package/dist/hooks/useInputStatusIcon.js +169 -0
  306. package/dist/hooks/useKeyboardHint.d.ts +1 -1
  307. package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
  308. package/dist/hooks/useKeyboardHint.js +4 -2
  309. package/dist/hooks/useListFocus.d.ts +39 -1
  310. package/dist/hooks/useListFocus.d.ts.map +1 -1
  311. package/dist/hooks/useListFocus.js +54 -9
  312. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  313. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  314. package/dist/i18n/InternationalizationContext.js +3 -0
  315. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  316. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  317. package/dist/i18n/InternationalizationProvider.js +5 -1
  318. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  319. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  320. package/dist/i18n/getLocaleDirection.js +29 -0
  321. package/dist/i18n/index.d.ts +6 -0
  322. package/dist/i18n/index.d.ts.map +1 -1
  323. package/dist/i18n/index.js +7 -1
  324. package/dist/i18n/useDirection.d.ts +2 -0
  325. package/dist/i18n/useDirection.d.ts.map +1 -0
  326. package/dist/i18n/useDirection.js +27 -0
  327. package/dist/theme/defineTheme.d.ts +6 -0
  328. package/dist/theme/defineTheme.d.ts.map +1 -1
  329. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  330. package/dist/theme/derivedVarRegistry.js +13 -0
  331. package/dist/theme/expandColorScale.d.ts +19 -2
  332. package/dist/theme/expandColorScale.d.ts.map +1 -1
  333. package/dist/theme/expandColorScale.js +38 -10
  334. package/dist/theme/index.d.ts +3 -3
  335. package/dist/theme/index.d.ts.map +1 -1
  336. package/dist/theme/types.d.ts +39 -2
  337. package/dist/theme/types.d.ts.map +1 -1
  338. package/dist/utils/index.d.ts +1 -0
  339. package/dist/utils/index.d.ts.map +1 -1
  340. package/dist/utils/index.js +2 -1
  341. package/dist/utils/plainDate.d.ts +17 -0
  342. package/dist/utils/plainDate.d.ts.map +1 -1
  343. package/dist/utils/plainDate.js +23 -4
  344. package/dist/utils/rtlStyles.d.ts +24 -0
  345. package/dist/utils/rtlStyles.d.ts.map +1 -0
  346. package/dist/utils/rtlStyles.js +27 -0
  347. package/locales/en.json +120 -0
  348. package/locales/pseudo.json +90 -0
  349. package/package.json +8 -3
  350. package/src/Avatar/Avatar.doc.mjs +50 -3
  351. package/src/Avatar/Avatar.test.tsx +218 -0
  352. package/src/Avatar/Avatar.tsx +285 -79
  353. package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
  354. package/src/Avatar/AvatarStatusDot.tsx +6 -4
  355. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  356. package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
  357. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  358. package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
  359. package/src/Banner/Banner.tsx +6 -6
  360. package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
  361. package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
  362. package/src/Breadcrumbs/index.ts +4 -0
  363. package/src/Button/Button.doc.mjs +0 -4
  364. package/src/Button/Button.test.tsx +16 -0
  365. package/src/Button/Button.tsx +6 -4
  366. package/src/Calendar/Calendar.test.tsx +170 -20
  367. package/src/Calendar/Calendar.tsx +73 -16
  368. package/src/Calendar/dayCellUtils.test.ts +18 -18
  369. package/src/Calendar/dayCellUtils.ts +2 -2
  370. package/src/Calendar/styles.ts +33 -39
  371. package/src/Card/Card.tsx +1 -1
  372. package/src/Carousel/Carousel.tsx +25 -6
  373. package/src/Center/Center.doc.mjs +38 -0
  374. package/src/Center/Center.test.tsx +75 -0
  375. package/src/Center/Center.tsx +37 -2
  376. package/src/Chat/ChatComposer.doc.mjs +2 -2
  377. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  378. package/src/Chat/ChatComposerInput.tsx +2 -2
  379. package/src/Chat/ChatDictationButton.tsx +7 -1
  380. package/src/Chat/ChatLayout.test.tsx +57 -0
  381. package/src/Chat/ChatLayout.tsx +26 -5
  382. package/src/Chat/ChatMessageBubble.tsx +15 -10
  383. package/src/Chat/ChatSystemMessage.test.tsx +5 -0
  384. package/src/Chat/ChatToolCalls.tsx +9 -2
  385. package/src/Chat/useTriggerMenu.tsx +1 -1
  386. package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
  387. package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
  388. package/src/CheckboxInput/CheckboxInput.tsx +21 -6
  389. package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
  390. package/src/CheckboxList/CheckboxList.test.tsx +94 -3
  391. package/src/CheckboxList/CheckboxListItem.tsx +17 -10
  392. package/src/Citation/Citation.doc.mjs +4 -3
  393. package/src/Citation/Citation.test.tsx +97 -0
  394. package/src/Citation/Citation.tsx +43 -11
  395. package/src/CodeBlock/CodeBlock.test.tsx +17 -0
  396. package/src/CodeBlock/CodeBlock.tsx +38 -11
  397. package/src/Collapsible/Collapsible.doc.mjs +1 -0
  398. package/src/Collapsible/Collapsible.test.tsx +7 -0
  399. package/src/Collapsible/Collapsible.tsx +16 -6
  400. package/src/CommandPalette/CommandPalette.test.tsx +95 -1
  401. package/src/CommandPalette/CommandPalette.tsx +41 -2
  402. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  403. package/src/ContextMenu/ContextMenu.test.tsx +59 -2
  404. package/src/ContextMenu/ContextMenu.tsx +22 -11
  405. package/src/ContextMenu/index.ts +5 -0
  406. package/src/DateInput/DateInput.doc.mjs +25 -0
  407. package/src/DateInput/DateInput.test.tsx +230 -0
  408. package/src/DateInput/DateInput.tsx +51 -29
  409. package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
  410. package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
  411. package/src/DateRangeInput/DateRangeInput.tsx +42 -30
  412. package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
  413. package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
  414. package/src/DateTimeInput/DateTimeInput.tsx +44 -39
  415. package/src/Divider/Divider.test.tsx +32 -8
  416. package/src/Divider/Divider.tsx +14 -1
  417. package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -2
  418. package/src/DropdownMenu/DropdownMenu.test.tsx +95 -0
  419. package/src/DropdownMenu/DropdownMenu.tsx +31 -12
  420. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +49 -66
  421. package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
  422. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
  423. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
  424. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +19 -4
  425. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +84 -2
  426. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
  427. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +680 -0
  428. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +569 -0
  429. package/src/DropdownMenu/index.ts +16 -0
  430. package/src/DropdownMenu/menuItemHover.ts +40 -0
  431. package/src/DropdownMenu/menuItemRoles.ts +9 -0
  432. package/src/DropdownMenu/renderDropdownItems.tsx +40 -14
  433. package/src/Field/Field.doc.mjs +4 -0
  434. package/src/Field/Field.tsx +14 -9
  435. package/src/Field/FieldLabel.test.tsx +25 -0
  436. package/src/Field/FieldLabel.tsx +12 -3
  437. package/src/Field/inputStyles.stylex.ts +2 -0
  438. package/src/FieldStatus/FieldStatus.doc.mjs +1 -0
  439. package/src/FieldStatus/FieldStatus.test.tsx +133 -0
  440. package/src/FieldStatus/FieldStatus.tsx +61 -4
  441. package/src/FileInput/FileInput.doc.mjs +23 -2
  442. package/src/FileInput/FileInput.test.tsx +104 -13
  443. package/src/FileInput/FileInput.tsx +106 -79
  444. package/src/Heading/Heading.tsx +2 -1
  445. package/src/HoverCard/useHoverCard.tsx +15 -3
  446. package/src/Icon/Icon.doc.mjs +13 -0
  447. package/src/Icon/Icon.test.tsx +89 -0
  448. package/src/Icon/Icon.tsx +51 -3
  449. package/src/Item/Item.doc.mjs +5 -0
  450. package/src/Item/Item.test.tsx +88 -0
  451. package/src/Item/Item.tsx +57 -11
  452. package/src/Layer/layerAnimations.stylex.ts +23 -0
  453. package/src/Lightbox/Lightbox.test.tsx +33 -0
  454. package/src/Lightbox/Lightbox.tsx +30 -10
  455. package/src/List/List.test.tsx +17 -29
  456. package/src/List/List.tsx +6 -1
  457. package/src/List/ListItem.doc.mjs +12 -0
  458. package/src/List/ListItem.tsx +13 -0
  459. package/src/Markdown/Markdown.test.tsx +21 -0
  460. package/src/Markdown/Markdown.tsx +4 -0
  461. package/src/MetadataList/MetadataList.test.tsx +24 -0
  462. package/src/MetadataList/MetadataList.tsx +6 -2
  463. package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
  464. package/src/MultiSelector/MultiSelector.test.tsx +436 -0
  465. package/src/MultiSelector/MultiSelector.tsx +133 -67
  466. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  467. package/src/NumberInput/NumberInput.doc.mjs +21 -0
  468. package/src/NumberInput/NumberInput.test.tsx +71 -0
  469. package/src/NumberInput/NumberInput.tsx +35 -26
  470. package/src/Outline/Outline.test.tsx +12 -12
  471. package/src/Outline/Outline.tsx +2 -2
  472. package/src/Pagination/Pagination.tsx +11 -3
  473. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  474. package/src/PowerSearch/PowerSearch.test.tsx +23 -0
  475. package/src/PowerSearch/PowerSearch.tsx +10 -1
  476. package/src/ProgressBar/ProgressBar.test.tsx +34 -0
  477. package/src/ProgressBar/ProgressBar.tsx +16 -1
  478. package/src/RadioList/RadioList.doc.mjs +6 -0
  479. package/src/RadioList/RadioList.test.tsx +26 -4
  480. package/src/RadioList/RadioList.tsx +2 -2
  481. package/src/RadioList/RadioListItem.tsx +12 -5
  482. package/src/Resizable/ResizeHandle.test.tsx +94 -0
  483. package/src/Resizable/ResizeHandle.tsx +70 -20
  484. package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
  485. package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
  486. package/src/Selector/Selector.doc.mjs +15 -0
  487. package/src/Selector/Selector.test.tsx +400 -0
  488. package/src/Selector/Selector.tsx +95 -23
  489. package/src/SideNav/SideNav.tsx +1 -8
  490. package/src/SideNav/SideNavCollapseButton.tsx +9 -7
  491. package/src/SideNav/SideNavItem.tsx +5 -3
  492. package/src/Skeleton/Skeleton.test.tsx +16 -0
  493. package/src/Skeleton/Skeleton.tsx +13 -1
  494. package/src/Slider/Slider.doc.mjs +6 -0
  495. package/src/Slider/Slider.test.tsx +240 -12
  496. package/src/Slider/Slider.tsx +96 -23
  497. package/src/Spinner/Spinner.test.tsx +10 -8
  498. package/src/Spinner/Spinner.tsx +15 -5
  499. package/src/Switch/Switch.doc.mjs +142 -42
  500. package/src/Switch/Switch.test.tsx +111 -0
  501. package/src/Switch/Switch.tsx +149 -32
  502. package/src/TabList/Tab.tsx +2 -2
  503. package/src/TabList/TabList.doc.mjs +0 -6
  504. package/src/TabList/TabList.test.tsx +3 -15
  505. package/src/TabList/TabList.tsx +6 -17
  506. package/src/TabList/TabListContext.ts +0 -6
  507. package/src/TabList/TabMenu.tsx +2 -2
  508. package/src/Table/BaseTable.tsx +34 -2
  509. package/src/Table/Table.doc.mjs +11 -0
  510. package/src/Table/Table.test.tsx +85 -0
  511. package/src/Table/TableCell.tsx +3 -3
  512. package/src/Table/TableHeaderCell.tsx +3 -3
  513. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
  514. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
  515. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +48 -21
  516. package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
  517. package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
  518. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
  519. package/src/Table/plugins/tree/useTableTreeData.test.tsx +161 -2
  520. package/src/Table/plugins/tree/useTableTreeData.tsx +71 -14
  521. package/src/Table/types.ts +33 -0
  522. package/src/Table/useTableRowExpansion.doc.mjs +55 -2
  523. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  524. package/src/Table/useTableTreeData.doc.mjs +9 -0
  525. package/src/Text/Heading.doc.mjs +3 -3
  526. package/src/Text/Text.doc.mjs +1 -1
  527. package/src/Text/Text.test.tsx +42 -0
  528. package/src/Text/Text.tsx +25 -1
  529. package/src/Text/index.ts +2 -6
  530. package/src/TextArea/TextArea.doc.mjs +23 -2
  531. package/src/TextArea/TextArea.test.tsx +132 -4
  532. package/src/TextArea/TextArea.tsx +161 -67
  533. package/src/TextInput/TextInput.doc.mjs +21 -0
  534. package/src/TextInput/TextInput.test.tsx +150 -0
  535. package/src/TextInput/TextInput.tsx +28 -25
  536. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  537. package/src/Thumbnail/Thumbnail.test.tsx +24 -1
  538. package/src/Thumbnail/Thumbnail.tsx +28 -35
  539. package/src/TimeInput/TimeInput.doc.mjs +21 -0
  540. package/src/TimeInput/TimeInput.test.tsx +23 -0
  541. package/src/TimeInput/TimeInput.tsx +24 -25
  542. package/src/Timestamp/Timestamp.doc.mjs +32 -6
  543. package/src/Timestamp/Timestamp.test.tsx +371 -0
  544. package/src/Timestamp/Timestamp.tsx +96 -93
  545. package/src/Timestamp/formatInstant.ts +218 -0
  546. package/src/Timestamp/index.ts +4 -0
  547. package/src/Timestamp/tooltipEntries.test.ts +552 -0
  548. package/src/Timestamp/tooltipEntries.ts +210 -0
  549. package/src/Toast/ToastViewport.test.tsx +218 -8
  550. package/src/Toast/ToastViewport.tsx +71 -12
  551. package/src/ToggleButton/ToggleButton.test.tsx +24 -0
  552. package/src/ToggleButton/ToggleButton.tsx +19 -1
  553. package/src/Token/Token.test.tsx +166 -15
  554. package/src/Token/Token.tsx +104 -47
  555. package/src/Token/TokenLink.tsx +107 -0
  556. package/src/Token/index.ts +1 -1
  557. package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
  558. package/src/Tokenizer/Tokenizer.test.tsx +23 -0
  559. package/src/Tokenizer/Tokenizer.tsx +14 -2
  560. package/src/Tooltip/Tooltip.test.tsx +46 -0
  561. package/src/Tooltip/useTooltip.tsx +20 -0
  562. package/src/TopNav/TopNav.test.tsx +93 -2
  563. package/src/TopNav/TopNavItem.doc.mjs +3 -3
  564. package/src/TopNav/TopNavItem.tsx +35 -6
  565. package/src/TopNav/TopNavMegaMenu.tsx +26 -2
  566. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
  567. package/src/TreeList/TreeList.doc.mjs +6 -0
  568. package/src/TreeList/TreeList.test.tsx +50 -10
  569. package/src/TreeList/TreeList.tsx +5 -0
  570. package/src/TreeList/TreeListBranches.tsx +8 -6
  571. package/src/TreeList/TreeListItem.tsx +33 -11
  572. package/src/Typeahead/BaseTypeahead.tsx +42 -15
  573. package/src/Typeahead/Typeahead.doc.mjs +13 -0
  574. package/src/Typeahead/Typeahead.test.tsx +112 -0
  575. package/src/Typeahead/Typeahead.tsx +17 -1
  576. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  577. package/src/__tests__/babelPluginAddExtensions.test.ts +190 -0
  578. package/src/__tests__/forcedColors.ts +60 -0
  579. package/src/__tests__/inputWidthContract.test.tsx +62 -0
  580. package/src/doc-mjs.d.ts +19 -0
  581. package/src/hooks/containerReveal.pool.stylex.ts +464 -0
  582. package/src/hooks/index.ts +13 -0
  583. package/src/hooks/isRtlElement.ts +27 -0
  584. package/src/hooks/useAnnounce.test.tsx +75 -2
  585. package/src/hooks/useAnnounce.ts +47 -1
  586. package/src/hooks/useContainerReveal.test.tsx +116 -0
  587. package/src/hooks/useContainerReveal.ts +180 -0
  588. package/src/hooks/useFocusTrap.test.tsx +104 -0
  589. package/src/hooks/useFocusTrap.ts +61 -12
  590. package/src/hooks/useGridFocus.doc.mjs +3 -3
  591. package/src/hooks/useGridFocus.test.tsx +41 -0
  592. package/src/hooks/useGridFocus.ts +21 -10
  593. package/src/hooks/useHotkeys.ts +9 -0
  594. package/src/hooks/useInputStatusIcon.test.tsx +221 -0
  595. package/src/hooks/useInputStatusIcon.tsx +235 -0
  596. package/src/hooks/useKeyboardHint.test.tsx +22 -0
  597. package/src/hooks/useKeyboardHint.tsx +6 -2
  598. package/src/hooks/useListFocus.doc.mjs +25 -3
  599. package/src/hooks/useListFocus.test.tsx +153 -1
  600. package/src/hooks/useListFocus.ts +102 -9
  601. package/src/i18n/InternationalizationContext.ts +4 -0
  602. package/src/i18n/InternationalizationProvider.tsx +12 -2
  603. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  604. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  605. package/src/i18n/getLocaleDirection.ts +29 -0
  606. package/src/i18n/index.ts +6 -0
  607. package/src/i18n/useDirection.ts +29 -0
  608. package/src/reset.css +0 -26
  609. package/src/reset.test.ts +60 -0
  610. package/src/theme/defineTheme.ts +6 -0
  611. package/src/theme/derivedVarRegistry.test.ts +1 -0
  612. package/src/theme/derivedVarRegistry.ts +6 -0
  613. package/src/theme/expandColorScale.test.ts +144 -0
  614. package/src/theme/expandColorScale.ts +53 -15
  615. package/src/theme/generateThemeRules.test.ts +42 -0
  616. package/src/theme/index.ts +4 -8
  617. package/src/theme/types.ts +43 -13
  618. package/src/utils/index.ts +2 -0
  619. package/src/utils/plainDate.test.ts +24 -6
  620. package/src/utils/plainDate.ts +18 -4
  621. package/src/utils/rtlStyles.ts +27 -0
  622. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +0 -9
  623. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +0 -1
  624. package/dist/Thumbnail/thumbnail.markers.stylex.js +0 -14
  625. package/src/Thumbnail/thumbnail.markers.stylex.ts +0 -12
@@ -158,14 +158,29 @@ const styles = stylex.create({
158
158
  },
159
159
  checkmark: {
160
160
  display: 'none',
161
- color: colorVars['--color-on-accent'],
161
+ color: {
162
+ default: colorVars['--color-on-accent'],
163
+ // Forced colors (Windows High Contrast) does not reliably force an SVG
164
+ // stroke painted with currentColor, so the check stays the same white as
165
+ // the flattened (Canvas) box fill — a white check on a white box.
166
+ // CanvasText keeps it perceivable on the Canvas box, matching the
167
+ // indeterminate mark (WCAG 1.4.11).
168
+ '@media (forced-colors: active)': 'CanvasText',
169
+ },
162
170
  },
163
171
  checkmarkVisible: {
164
172
  display: 'block',
165
173
  },
166
174
  indeterminateMark: {
167
175
  display: 'none',
168
- backgroundColor: colorVars['--color-on-accent'],
176
+ backgroundColor: {
177
+ default: colorVars['--color-on-accent'],
178
+ // Forced colors (Windows High Contrast) strips painted backgrounds,
179
+ // which would make the indeterminate bar invisible; CanvasText keeps it
180
+ // perceivable on the Canvas box fill (WCAG 1.4.11). The checkmark carries
181
+ // the matching CanvasText treatment on its own style.
182
+ '@media (forced-colors: active)': 'CanvasText',
183
+ },
169
184
  borderRadius: radiusVars['--radius-full'],
170
185
  },
171
186
  indeterminateMarkVisible: {
@@ -198,12 +213,12 @@ const wrapperSizeStyles = stylex.create({
198
213
 
199
214
  const checkboxSizeStyles = stylex.create({
200
215
  sm: {
201
- width: 18,
202
- height: 18,
216
+ width: 20,
217
+ height: 20,
203
218
  },
204
219
  md: {
205
- width: 22,
206
- height: 22,
220
+ width: 24,
221
+ height: 24,
207
222
  },
208
223
  });
209
224
 
@@ -88,6 +88,12 @@ export const docs = {
88
88
  type: "{type: 'warning' | 'error' | 'success', message?: string}",
89
89
  description: 'Status indicator ({ type, message }).',
90
90
  },
91
+ {
92
+ name: 'width',
93
+ type: 'SizeValue',
94
+ description:
95
+ 'Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.',
96
+ },
91
97
  {
92
98
  name: 'xstyle',
93
99
  type: 'StyleXStyles',
@@ -154,14 +154,105 @@ describe('CheckboxList', () => {
154
154
  </CheckboxList>,
155
155
  );
156
156
 
157
- // Click the interactive row (invisible-button pattern), which is where the
158
- // composed onClick lives — not the inner checkbox.
159
- await user.click(screen.getByRole('button', {name: 'Option B'}));
157
+ // The row is a pointer-only click surface (no invisible row button — the
158
+ // checkbox is the option's only tab stop). Click the row's label area,
159
+ // where the composed onClick fires — not the inner checkbox.
160
+ expect(
161
+ screen.queryByRole('button', {name: 'Option B'}),
162
+ ).not.toBeInTheDocument();
163
+ // The text also exists in the checkbox's visually hidden <label>; target
164
+ // the row's label <span> to click the row surface.
165
+ await user.click(screen.getByText('Option B', {selector: 'span'}));
160
166
 
161
167
  expect(handleClick).toHaveBeenCalledTimes(1);
162
168
  expect(handleChange).toHaveBeenCalledWith(['a', 'b']);
163
169
  });
164
170
 
171
+ describe('single tab stop per option (WCAG 4.1.2 / APG checkbox pattern)', () => {
172
+ it('renders exactly one focusable control per option — the checkbox, no row button', () => {
173
+ render(
174
+ <CheckboxList label="Preferences" value={['a']} onChange={() => {}}>
175
+ <CheckboxListItem label="Option A" value="a" />
176
+ <CheckboxListItem label="Option B" value="b" />
177
+ </CheckboxList>,
178
+ );
179
+ // No invisible whole-row button duplicating the checkbox's action.
180
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
181
+ for (const item of screen.getAllByRole('listitem')) {
182
+ const focusables = item.querySelectorAll(
183
+ 'button, a[href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
184
+ );
185
+ expect(focusables).toHaveLength(1);
186
+ expect(focusables[0]).toBe(within(item).getByRole('checkbox'));
187
+ }
188
+ });
189
+
190
+ it('Tab moves directly from one option checkbox to the next', async () => {
191
+ const user = userEvent.setup();
192
+ render(
193
+ <CheckboxList label="Preferences" value={[]} onChange={() => {}}>
194
+ <CheckboxListItem label="Option A" value="a" />
195
+ <CheckboxListItem label="Option B" value="b" />
196
+ </CheckboxList>,
197
+ );
198
+ await user.tab();
199
+ expect(screen.getByRole('checkbox', {name: 'Option A'})).toHaveFocus();
200
+ await user.tab();
201
+ expect(screen.getByRole('checkbox', {name: 'Option B'})).toHaveFocus();
202
+ // No further tab stop inside the list (the row itself is not focusable).
203
+ await user.tab();
204
+ expect(document.body).toHaveFocus();
205
+ });
206
+
207
+ it('clicking the row surface (outside the checkbox) still toggles', async () => {
208
+ const user = userEvent.setup();
209
+ const handleChange = vi.fn();
210
+ render(
211
+ <CheckboxList label="Preferences" value={['a']} onChange={handleChange}>
212
+ <CheckboxListItem label="Option A" value="a" />
213
+ <CheckboxListItem label="Option B" value="b" />
214
+ </CheckboxList>,
215
+ );
216
+ // The text also exists in the checkbox's visually hidden <label>;
217
+ // target the row's label <span> to click the row surface.
218
+ await user.click(screen.getByText('Option B', {selector: 'span'}));
219
+ expect(handleChange).toHaveBeenCalledTimes(1);
220
+ expect(handleChange).toHaveBeenCalledWith(['a', 'b']);
221
+ });
222
+
223
+ it('toggles with Space on the focused checkbox, which reports checked state', async () => {
224
+ const user = userEvent.setup();
225
+ const handleChange = vi.fn();
226
+ render(
227
+ <CheckboxList label="Preferences" value={['a']} onChange={handleChange}>
228
+ <CheckboxListItem label="Option A" value="a" />
229
+ <CheckboxListItem label="Option B" value="b" />
230
+ </CheckboxList>,
231
+ );
232
+ await user.tab();
233
+ // The focused control is the checkbox itself, so its accessible name
234
+ // and checked state are what assistive tech announces on focus.
235
+ const checkboxA = screen.getByRole('checkbox', {name: 'Option A'});
236
+ expect(checkboxA).toHaveFocus();
237
+ expect(checkboxA).toBeChecked();
238
+ await user.keyboard(' ');
239
+ expect(handleChange).toHaveBeenCalledTimes(1);
240
+ expect(handleChange).toHaveBeenCalledWith([]);
241
+ });
242
+
243
+ it('the row itself is not focusable', () => {
244
+ render(
245
+ <CheckboxList label="Preferences" value={[]} onChange={() => {}}>
246
+ <CheckboxListItem label="Option A" value="a" />
247
+ </CheckboxList>,
248
+ );
249
+ const item = screen.getByRole('listitem');
250
+ expect(item).not.toHaveAttribute('tabindex');
251
+ item.focus();
252
+ expect(item).not.toHaveFocus();
253
+ });
254
+ });
255
+
165
256
  it('disables all checkboxes when group isDisabled is true', () => {
166
257
  render(
167
258
  <CheckboxList
@@ -16,12 +16,11 @@
16
16
  * - /packages/cli/templates/blocks/components/CheckboxList/ (showcase blocks)
17
17
  */
18
18
 
19
- import {use, type MouseEvent, type ReactNode} from 'react';
19
+ import {use, useRef, type ReactNode} from 'react';
20
20
  import * as stylex from '@stylexjs/stylex';
21
21
  import type {StyleXStyles} from '@stylexjs/stylex';
22
22
  import {colorVars} from '../theme/tokens.stylex';
23
23
  import type {BaseProps} from '../BaseProps';
24
- import {composeEventHandlers} from '../utils';
25
24
  import {useDevWarning} from '../hooks/useDevWarning';
26
25
  import {CheckboxInput} from '../CheckboxInput/CheckboxInput';
27
26
  import {ListItem} from '../List/ListItem';
@@ -212,6 +211,14 @@ export function CheckboxListItem({
212
211
  // Whether this item is interactive (has a toggle handler)
213
212
  const isInteractive = !effectiveReadOnly && (ctx != null || onCheck != null);
214
213
 
214
+ // The checkbox is the row's single keyboard control and action. The row is
215
+ // an enlarged click/tap target that delegates surface clicks to it via
216
+ // ListItem's `interactiveRef` (useClickableContainer), so each option is
217
+ // exactly one tab stop. Delegate whenever the row should respond to clicks:
218
+ // a toggleable item, or one carrying a consumer `onClick`.
219
+ const checkboxRef = useRef<HTMLInputElement | null>(null);
220
+ const hasRowInteraction = isInteractive || onClickProp != null;
221
+
215
222
  const handleToggle = () => {
216
223
  if (effectiveDisabled || effectiveReadOnly || isBusy) {
217
224
  return;
@@ -244,14 +251,12 @@ export function CheckboxListItem({
244
251
  description={description}
245
252
  endContent={endContent}
246
253
  isDisabled={effectiveDisabled}
247
- onClick={
248
- isInteractive || onClickProp
249
- ? composeEventHandlers<MouseEvent>(
250
- onClickProp as ((event: MouseEvent) => void) | undefined,
251
- isInteractive ? handleToggle : undefined,
252
- )
253
- : undefined
254
- }
254
+ // Delegate row clicks to the checkbox instead of wiring onClick (which
255
+ // would add an invisible row button = a second tab stop). The checkbox
256
+ // stays the option's sole focusable control (WCAG 4.1.2 / APG checkbox
257
+ // pattern). A consumer onClick rides on the checkbox itself (below), so
258
+ // it still fires for both direct and delegated (row-surface) clicks.
259
+ interactiveRef={hasRowInteraction ? checkboxRef : undefined}
255
260
  aria-busy={isBusy || undefined}
256
261
  xstyle={
257
262
  [
@@ -266,10 +271,12 @@ export function CheckboxListItem({
266
271
  style={style}
267
272
  startContent={
268
273
  <CheckboxInput
274
+ ref={checkboxRef}
269
275
  label={checkboxLabel}
270
276
  isLabelHidden
271
277
  value={resolvedChecked}
272
278
  onChange={() => handleToggle()}
279
+ onClick={onClickProp}
273
280
  isDisabled={effectiveDisabled}
274
281
  isReadOnly={effectiveReadOnly}
275
282
  isLoading={isBusy}
@@ -39,7 +39,7 @@ export const docs = {
39
39
  name: 'Icon',
40
40
  required: false,
41
41
  description:
42
- 'An optional favicon or source icon displayed before the label text. Only available in the label variant.',
42
+ 'An optional source icon shown before the label text. Accepts a favicon/logo image URL (via source.src) or a React node such as an Astryx <Icon>. Only available in the label variant.',
43
43
  },
44
44
  {
45
45
  name: 'Label text',
@@ -71,7 +71,7 @@ export const docs = {
71
71
  name: 'source',
72
72
  type: 'CitationSource',
73
73
  description:
74
- 'The citation source object containing title, url, and optional icon.',
74
+ 'The citation source object containing title, url, an optional image src, and an optional icon node.',
75
75
  required: true,
76
76
  },
77
77
  {
@@ -121,7 +121,8 @@ export const docsDense = {
121
121
  ],
122
122
  },
123
123
  propDescriptions: {
124
- source: 'citation source object with title, url, optional icon.',
124
+ source:
125
+ 'citation source object with title, url, optional image src, and optional icon node.',
125
126
  number: 'display index for this citation.',
126
127
  variant: 'display style: label chip with source title or compact numbered badge.',
127
128
  },
@@ -169,4 +169,101 @@ describe('Citation', () => {
169
169
  expect(el.classList.contains(cls)).toBe(true);
170
170
  }
171
171
  });
172
+
173
+ // --- Source icon: image URL (back-compat) vs ReactNode ---------------------
174
+
175
+ it('renders a legacy string icon as a decorative image (back-compat)', () => {
176
+ // Existing callers pass a favicon URL to `source.icon`. A bare string must
177
+ // still render as <img src>, unchanged from the original behavior.
178
+ const {container} = render(
179
+ <Citation
180
+ source={{
181
+ title: 'GitHub',
182
+ url: 'https://github.com',
183
+ icon: 'https://example.com/favicon.png',
184
+ }}
185
+ number={1}
186
+ data-testid="citation"
187
+ />,
188
+ );
189
+ const img = container.querySelector('img');
190
+ expect(img).not.toBeNull();
191
+ expect(img).toHaveAttribute('src', 'https://example.com/favicon.png');
192
+ // Decorative: empty alt, and the wrapper is aria-hidden.
193
+ expect(img).toHaveAttribute('alt', '');
194
+ expect(container.querySelector('[aria-hidden="true"] img')).toBe(img);
195
+ });
196
+
197
+ it('renders source.src as a decorative image', () => {
198
+ const {container} = render(
199
+ <Citation
200
+ source={{
201
+ title: 'GitHub',
202
+ url: 'https://github.com',
203
+ src: 'https://example.com/logo.png',
204
+ }}
205
+ number={1}
206
+ data-testid="citation"
207
+ />,
208
+ );
209
+ const img = container.querySelector('img');
210
+ expect(img).toHaveAttribute('src', 'https://example.com/logo.png');
211
+ expect(img).toHaveAttribute('alt', '');
212
+ });
213
+
214
+ it('renders a ReactNode icon as-is (not an <img>)', () => {
215
+ const {container} = render(
216
+ <Citation
217
+ source={{
218
+ title: 'GitHub',
219
+ url: 'https://github.com',
220
+ icon: <svg data-testid="custom-icon" />,
221
+ }}
222
+ number={1}
223
+ data-testid="citation"
224
+ />,
225
+ );
226
+ // The node renders directly; no <img> is produced for a node icon.
227
+ expect(container.querySelector('img')).toBeNull();
228
+ expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
229
+ // Still decorative — wrapped in an aria-hidden container.
230
+ expect(
231
+ container.querySelector(
232
+ '[aria-hidden="true"] [data-testid="custom-icon"]',
233
+ ),
234
+ ).not.toBeNull();
235
+ });
236
+
237
+ it('prefers a node icon over src when both are provided', () => {
238
+ const {container} = render(
239
+ <Citation
240
+ source={{
241
+ title: 'GitHub',
242
+ url: 'https://github.com',
243
+ src: 'https://example.com/logo.png',
244
+ icon: <svg data-testid="custom-icon" />,
245
+ }}
246
+ number={1}
247
+ data-testid="citation"
248
+ />,
249
+ );
250
+ expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
251
+ expect(container.querySelector('img')).toBeNull();
252
+ });
253
+
254
+ it('keeps aria-label as the sole accessible name when an icon is present', () => {
255
+ render(
256
+ <Citation
257
+ source={{
258
+ title: 'GitHub',
259
+ url: 'https://github.com',
260
+ icon: 'https://example.com/favicon.png',
261
+ }}
262
+ number={2}
263
+ data-testid="citation"
264
+ />,
265
+ );
266
+ const el = screen.getByTestId('citation');
267
+ expect(el).toHaveAttribute('aria-label', 'Citation 2: GitHub');
268
+ });
172
269
  });
@@ -10,10 +10,14 @@
10
10
  *
11
11
  * SYNC: When modified, update these files to stay in sync:
12
12
  * - /packages/core/src/Citation/index.ts (exports if types change)
13
+ * - /packages/core/src/Citation/Citation.doc.mjs (props table, features)
14
+ * - /packages/core/src/Citation/Citation.test.tsx (tests for new/changed behavior)
15
+ * - /apps/storybook/stories/Citation.stories.tsx (storybook stories)
13
16
  * - /packages/cli/templates/blocks/components/Citation/ (showcase blocks)
14
17
  */
15
18
 
16
19
  import type React from 'react';
20
+ import type {ReactNode} from 'react';
17
21
  import * as stylex from '@stylexjs/stylex';
18
22
  import {
19
23
  colorVars,
@@ -29,11 +33,29 @@ import {mergeProps} from '../utils';
29
33
  import type {BaseProps} from '../BaseProps';
30
34
  import {themeProps} from '../utils/themeProps';
31
35
  import {useTranslator} from '../i18n';
36
+ import {renderIconSlot} from '../Icon';
32
37
 
33
38
  export interface CitationSource {
34
39
  title?: string;
35
40
  url?: string;
36
- icon?: string;
41
+ /**
42
+ * Image URL for a favicon or source logo, rendered as `<img src>` inside the
43
+ * icon circle. This is the idiomatic field for image sources (mirrors
44
+ * `Avatar`/`Thumbnail` `src`). When both `src` and a non-string `icon` are
45
+ * provided, `icon` wins.
46
+ */
47
+ src?: string;
48
+ /**
49
+ * Source icon shown before the label text (label variant only). Accepts:
50
+ * - a React node / Astryx `<Icon>` / SVG element — rendered as-is, or
51
+ * - a string image URL — rendered as `<img src>` for backward compatibility
52
+ * with callers that passed a favicon URL here.
53
+ *
54
+ * Note: unlike icon slots elsewhere in the system, a bare string is treated
55
+ * as an image URL (not a semantic icon name) to preserve the original
56
+ * favicon behavior. Pass an Astryx `<Icon>` (or other node) for a real icon.
57
+ */
58
+ icon?: ReactNode;
37
59
  }
38
60
 
39
61
  export interface CitationProps extends BaseProps<HTMLElement> {
@@ -162,7 +184,18 @@ export function Citation({
162
184
  const t = useTranslator();
163
185
  const title = source.title ?? String(number);
164
186
  const href = source.url;
165
- const icon = source.icon;
187
+
188
+ // Resolve the source icon. A non-string `icon` node renders as-is (an Astryx
189
+ // <Icon>, SVG, avatar, etc.). Otherwise fall back to an image URL: `src`, or
190
+ // a legacy string passed to `icon` (back-compat — favicon URLs still render
191
+ // as <img>). The icon is decorative; the accessible name comes solely from
192
+ // the element's aria-label, so nothing is double-announced.
193
+ const iconNode =
194
+ source.icon != null && typeof source.icon !== 'string' ? source.icon : null;
195
+ const imageSrc =
196
+ source.src ?? (typeof source.icon === 'string' ? source.icon : undefined);
197
+ const hasIcon = iconNode != null || imageSrc != null;
198
+
166
199
  const Tag = href ? 'a' : 'span';
167
200
  // `doc-noteref` is a reference role — only appropriate on the interactive
168
201
  // link form. On a plain (unlinked) span it is not a permitted role
@@ -218,7 +251,7 @@ export function Citation({
218
251
  themeProps('citation', {variant}),
219
252
  stylex.props(
220
253
  styles.label,
221
- icon != null && styles.labelWithIcon,
254
+ hasIcon && styles.labelWithIcon,
222
255
  href != null && styles.labelHover,
223
256
  href != null && styles.labelInteractive,
224
257
  xstyle,
@@ -226,14 +259,13 @@ export function Citation({
226
259
  className,
227
260
  style,
228
261
  )}>
229
- {icon && (
230
- <span {...stylex.props(styles.iconWrap)}>
231
- <img
232
- src={icon}
233
- alt=""
234
- aria-hidden="true"
235
- {...stylex.props(styles.icon)}
236
- />
262
+ {hasIcon && (
263
+ <span aria-hidden="true" {...stylex.props(styles.iconWrap)}>
264
+ {iconNode != null ? (
265
+ renderIconSlot(iconNode, {size: 'sm'})
266
+ ) : (
267
+ <img src={imageSrc} alt="" {...stylex.props(styles.icon)} />
268
+ )}
237
269
  </span>
238
270
  )}
239
271
  <span {...stylex.props(styles.labelText)}>{title}</span>
@@ -14,6 +14,7 @@ import {act, render, screen, fireEvent, waitFor} from '@testing-library/react';
14
14
  import {CodeBlock} from './CodeBlock';
15
15
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
16
16
  import {dracula} from '../theme/syntax';
17
+ import {InternationalizationProvider} from '../i18n';
17
18
 
18
19
  function politeRegion(): HTMLElement | null {
19
20
  return document.querySelector('[data-astryx-live-region="polite"]');
@@ -72,6 +73,22 @@ describe('CodeBlock', () => {
72
73
  });
73
74
  });
74
75
 
76
+ it('localizes the copy announcement through the i18n catalog', async () => {
77
+ render(
78
+ <InternationalizationProvider
79
+ locale="fr"
80
+ overrides={{fr: {'@astryx.codeBlock.copied': 'Copié'}}}>
81
+ <CodeBlock code="const x = 1;" language="javascript" />
82
+ </InternationalizationProvider>,
83
+ );
84
+ // The button label and the live-region announcement share the same key.
85
+ fireEvent.click(screen.getByRole('button', {name: 'Copy code'}));
86
+ await waitFor(() => {
87
+ expect(politeRegion()).toHaveTextContent('Copié');
88
+ });
89
+ expect(screen.getByRole('button', {name: 'Copié'})).toBeInTheDocument();
90
+ });
91
+
75
92
  it('keeps the copied indicator a full 2s after a rapid re-copy', async () => {
76
93
  vi.useFakeTimers();
77
94
  try {
@@ -88,6 +88,23 @@ const dynamicStyles = stylex.create({
88
88
  }),
89
89
  });
90
90
 
91
+ // Light reveal so the leading chevron eases into view instead of popping in.
92
+ // Growing the chevron's own footprint (width + inline margin) from zero slides
93
+ // the title into place instead of snapping it over, and clipping keeps the
94
+ // glyph from spilling while it's mid-reveal.
95
+ const chevronReveal = stylex.keyframes({
96
+ from: {
97
+ width: 0,
98
+ marginInlineEnd: 0,
99
+ opacity: 0,
100
+ },
101
+ to: {
102
+ width: '14px',
103
+ marginInlineEnd: spacingVars['--spacing-1'],
104
+ opacity: 1,
105
+ },
106
+ });
107
+
91
108
  const styles = stylex.create({
92
109
  root: {
93
110
  position: 'relative',
@@ -133,7 +150,6 @@ const styles = stylex.create({
133
150
  headerTitle: {
134
151
  display: 'flex',
135
152
  alignItems: 'center',
136
- gap: spacingVars['--spacing-1'],
137
153
  fontSize: typeScaleVars['--text-supporting-size'],
138
154
  fontFamily: typographyVars['--font-family-code'],
139
155
  fontWeight: fontWeightVars['--font-weight-medium'],
@@ -173,13 +189,24 @@ const styles = stylex.create({
173
189
  flexShrink: 0,
174
190
  width: '14px',
175
191
  height: '14px',
192
+ marginInlineEnd: spacingVars['--spacing-1'],
193
+ overflow: 'hidden',
176
194
  color: 'var(--color-syntax-comment)',
195
+ animationName: {
196
+ default: chevronReveal,
197
+ '@media (prefers-reduced-motion: reduce)': 'none',
198
+ },
199
+ animationDuration: durationVars['--duration-medium'],
200
+ animationTimingFunction: easeVars['--ease-standard'],
177
201
  transitionProperty: 'transform',
178
202
  transitionDuration: durationVars['--duration-fast'],
179
203
  transitionTimingFunction: easeVars['--ease-standard'],
180
204
  },
181
- collapseChevronCollapsed: {
182
- transform: 'rotate(180deg)',
205
+ collapseChevronExpanded: {
206
+ // Leading disclosure convention (matches TreeList/Table): the resting
207
+ // chevronRight points right (>) when collapsed; rotate it down (v) when
208
+ // expanded.
209
+ transform: 'rotate(90deg)',
183
210
  },
184
211
  headerCollapsible: {
185
212
  cursor: 'pointer',
@@ -296,7 +323,7 @@ const styles = stylex.create({
296
323
  copyButtonAbsolute: {
297
324
  position: 'absolute',
298
325
  top: spacingVars['--spacing-2'],
299
- right: spacingVars['--spacing-2'],
326
+ insetInlineEnd: spacingVars['--spacing-2'],
300
327
  },
301
328
  });
302
329
 
@@ -759,7 +786,7 @@ export function CodeBlock({
759
786
  setCopied(true);
760
787
  // Swapping the button's aria-label alone isn't reliably announced by
761
788
  // screen readers, so confirm the copy via a polite live region.
762
- announce('Copied');
789
+ announce(t('@astryx.codeBlock.copied'));
763
790
  onCopy?.();
764
791
  // Restart the reset timer on every copy — otherwise a rapid re-copy
765
792
  // is reverted early by the previous click's timer.
@@ -773,7 +800,7 @@ export function CodeBlock({
773
800
  } catch {
774
801
  // Clipboard failures leave the copied state unchanged.
775
802
  }
776
- }, [code, onCopy, announce]);
803
+ }, [code, onCopy, announce, t]);
777
804
 
778
805
  const sizeStyle = size === 'sm' ? styles.sizeSm : styles.sizeMd;
779
806
  // Digits in the largest line number — sizes the gutter column width.
@@ -845,18 +872,18 @@ export function CodeBlock({
845
872
  canCollapse && styles.headerCollapsible,
846
873
  )}>
847
874
  <span {...stylex.props(styles.headerTitle)}>
848
- {title}
849
- {title && languageLabel ? ' — ' : ''}
850
- {languageLabel}
851
875
  {canCollapse && (
852
876
  <span
853
877
  {...stylex.props(
854
878
  styles.collapseChevron,
855
- isCollapsed && styles.collapseChevronCollapsed,
879
+ !isCollapsed && styles.collapseChevronExpanded,
856
880
  )}>
857
- <Icon icon="chevronDown" size="xsm" color="inherit" />
881
+ <Icon icon="chevronRight" size="xsm" color="inherit" />
858
882
  </span>
859
883
  )}
884
+ {title}
885
+ {title && languageLabel ? ' — ' : ''}
886
+ {languageLabel}
860
887
  </span>
861
888
  </div>
862
889
  {copyButtonEl}
@@ -17,6 +17,7 @@ export const docs = {
17
17
  theming: {
18
18
  targets: [
19
19
  {className: 'astryx-collapsible', visualProps: ['density']},
20
+ {className: 'astryx-collapsible-trigger', visualProps: ['density']},
20
21
  {className: 'astryx-collapsible-content', visualProps: ['density']},
21
22
  {className: 'astryx-collapsible-group', visualProps: ['density']},
22
23
  ],
@@ -72,6 +72,13 @@ describe('Collapsible', () => {
72
72
  expect(screen.getByTestId('root')).toHaveClass('astryx-collapsible');
73
73
  });
74
74
 
75
+ it('renders the stable astryx-collapsible-trigger class on the trigger button', () => {
76
+ render(<Collapsible trigger="T">c</Collapsible>);
77
+ expect(screen.getByRole('button')).toHaveClass(
78
+ 'astryx-collapsible-trigger',
79
+ );
80
+ });
81
+
75
82
  it('renders the stable astryx-collapsible-content class on the content area', () => {
76
83
  render(<Collapsible trigger="T">c</Collapsible>);
77
84
  const content = contentFor(screen.getByRole('button'));
@@ -51,7 +51,12 @@ const styles = stylex.create({
51
51
  root: {
52
52
  width: '100%',
53
53
  },
54
- // Trigger button — full width, flex row, no browser button styling
54
+ // Trigger button — full width, flex row, no browser button styling.
55
+ // Anchors heading-adjacent typography (body family, large size, semibold)
56
+ // so the label reads as a section header regardless of where the
57
+ // Collapsible is placed. External themes retarget it independently from the
58
+ // content via the `astryx-collapsible-trigger` target — e.g. a heading font
59
+ // on the trigger while the content stays on the body font.
55
60
  trigger: {
56
61
  all: 'unset',
57
62
  boxSizing: 'border-box',
@@ -113,7 +118,7 @@ const styles = stylex.create({
113
118
  // Anchors body typography so revealed text renders at the system's body
114
119
  // scale (family/size/weight/leading) instead of inheriting from wherever
115
120
  // the Collapsible is placed. External themes override via the
116
- // `astryx-collapsible-content` target.
121
+ // `astryx-collapsible-content` target, independently from the trigger.
117
122
  content: {
118
123
  paddingBlockStart: spacingVars['--spacing-1'],
119
124
  fontFamily: typographyVars['--font-family-body'],
@@ -318,10 +323,15 @@ export function Collapsible({
318
323
  // the system-wide disabled convention (never native `disabled`, which
319
324
  // would swallow events like a wrapping tooltip's hover).
320
325
  tabIndex={isDisabled ? -1 : undefined}
321
- {...stylex.props(
322
- styles.trigger,
323
- density != null && triggerDensity[density],
324
- isDisabled && styles.triggerDisabled,
326
+ {...mergeProps(
327
+ themeProps('collapsible-trigger', {
328
+ density: density ?? undefined,
329
+ }),
330
+ stylex.props(
331
+ styles.trigger,
332
+ density != null && triggerDensity[density],
333
+ isDisabled && styles.triggerDisabled,
334
+ ),
325
335
  )}>
326
336
  <span {...stylex.props(styles.triggerLabel)}>{trigger}</span>
327
337
  <span