@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
@@ -147,16 +147,33 @@ describe('FileInput', () => {
147
147
  expect(screen.getByText('Upload')).toBeInTheDocument();
148
148
  });
149
149
 
150
- it('sets aria-required when isRequired is true', () => {
150
+ it('conveys required state through the accessible description', () => {
151
151
  render(
152
152
  <FileInput label="Resume" isRequired value={null} onChange={() => {}} />,
153
153
  );
154
- // aria-required lives on the focusable role="button" wrapper, not the
154
+ const trigger = screen.getByRole('button', {name: 'Resume'});
155
+ // Required is conveyed via a visually hidden "Required" node referenced
156
+ // from aria-describedby on the focusable role="button" trigger — not the
155
157
  // hidden file input (forms-6).
156
- expect(screen.getByRole('button', {name: 'Resume'})).toHaveAttribute(
157
- 'aria-required',
158
- 'true',
158
+ expect(trigger).toHaveAccessibleDescription(/Required/);
159
+ // aria-required is not a supported property of role="button" in
160
+ // WAI-ARIA 1.2 (AT does not announce it), so it must never appear.
161
+ expect(trigger).not.toHaveAttribute('aria-required');
162
+ });
163
+
164
+ it('combines required with the description in the accessible description', () => {
165
+ render(
166
+ <FileInput
167
+ label="Resume"
168
+ description="PDF only"
169
+ isRequired
170
+ value={null}
171
+ onChange={() => {}}
172
+ />,
159
173
  );
174
+ const trigger = screen.getByRole('button', {name: 'Resume'});
175
+ expect(trigger).toHaveAccessibleDescription(/PDF only/);
176
+ expect(trigger).toHaveAccessibleDescription(/Required/);
160
177
  });
161
178
 
162
179
  it('places aria-describedby on the focusable button, not the hidden input (forms-6)', () => {
@@ -176,11 +193,11 @@ describe('FileInput', () => {
176
193
  expect(input).toHaveAttribute('aria-hidden', 'true');
177
194
  });
178
195
 
179
- it('does not set aria-required by default', () => {
196
+ it('does not mention required without isRequired', () => {
180
197
  render(<FileInput label="Resume" value={null} onChange={() => {}} />);
181
- expect(screen.getByRole('button', {name: 'Resume'})).not.toHaveAttribute(
182
- 'aria-required',
183
- );
198
+ const trigger = screen.getByRole('button', {name: 'Resume'});
199
+ expect(trigger).not.toHaveAccessibleDescription(/Required/);
200
+ expect(trigger).not.toHaveAttribute('aria-required');
184
201
  });
185
202
 
186
203
  it('sets disabled attribute when isDisabled is true', () => {
@@ -353,6 +370,40 @@ describe('FileInput', () => {
353
370
  // FieldStatus, but the polite channel must stay empty.)
354
371
  expect(politeRegion()?.textContent ?? '').toBe('');
355
372
  });
373
+
374
+ it('announces a validation error exactly once across live regions', async () => {
375
+ render(
376
+ <FileInput
377
+ label="Upload"
378
+ value={null}
379
+ onChange={() => {}}
380
+ accept=".pdf"
381
+ />,
382
+ );
383
+ fireEvent.change(fileInputEl(), {
384
+ target: {files: [createFile('note.txt', 100)]},
385
+ });
386
+ const errorText = '"note.txt" is not an accepted file type';
387
+ // The error lands in the assertive announce region (via the FieldStatus
388
+ // the derived error status mounts)…
389
+ await waitFor(() => {
390
+ expect(
391
+ document.querySelector('[data-astryx-live-region="assertive"]'),
392
+ ).toHaveTextContent(errorText);
393
+ });
394
+ // …and in exactly one live region overall. FileInput's own role="status"
395
+ // region used to duplicate the FieldStatus announcement, so the same
396
+ // error was read twice (assertively, then politely).
397
+ const liveRegions = Array.from(
398
+ document.querySelectorAll(
399
+ '[role="status"], [role="alert"], [aria-live]',
400
+ ),
401
+ );
402
+ const regionsWithError = liveRegions.filter(el =>
403
+ (el.textContent ?? '').includes(errorText),
404
+ );
405
+ expect(regionsWithError).toHaveLength(1);
406
+ });
356
407
  });
357
408
 
358
409
  describe('validation', () => {
@@ -719,16 +770,20 @@ describe('FileInput', () => {
719
770
  />,
720
771
  );
721
772
 
722
- const trigger = screen.getByRole('button');
723
773
  const tooltip = screen.getByRole('tooltip', h);
724
774
  expect(tooltip).toHaveTextContent('You need the Editor role');
725
775
 
726
- fireEvent.mouseEnter(trigger);
776
+ // The trigger button is visually hidden, so the disabled-reason tooltip
777
+ // anchors its hover listeners to the visible container surface.
778
+ const surface = document.querySelector(
779
+ '.astryx-file-input',
780
+ ) as HTMLElement;
781
+ fireEvent.mouseEnter(surface);
727
782
  await waitFor(() => {
728
783
  expect(tooltip).toHaveAttribute('popover-open');
729
784
  });
730
785
 
731
- fireEvent.mouseLeave(trigger);
786
+ fireEvent.mouseLeave(surface);
732
787
  await waitFor(() => {
733
788
  expect(tooltip).not.toHaveAttribute('popover-open');
734
789
  });
@@ -809,7 +864,10 @@ describe('FileInput', () => {
809
864
  });
810
865
 
811
866
  it('blocks opening the file picker while focusable-disabled', async () => {
812
- const user = userEvent.setup();
867
+ // The trigger is a visually-hidden button (pointer-events: none) — real
868
+ // pointer clicks land on the container surface, so bypass the pointer
869
+ // check to exercise the disabled guard directly.
870
+ const user = userEvent.setup({pointerEventsCheck: 0});
813
871
  render(
814
872
  <FileInput
815
873
  label="Resume"
@@ -849,3 +907,36 @@ describe('FileInput', () => {
849
907
  });
850
908
  });
851
909
  });
910
+
911
+ describe('FileInput statusVariant forwarding', () => {
912
+ it('defaults to attached (status renders with data-variant="attached")', () => {
913
+ const {container} = render(
914
+ <FileInput
915
+ label="Upload"
916
+ value={null}
917
+ onChange={() => {}}
918
+ status={{type: 'error', message: 'Something went wrong'}}
919
+ />,
920
+ );
921
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
922
+ 'data-variant',
923
+ 'attached',
924
+ );
925
+ });
926
+
927
+ it('forwards statusVariant="detached" to the underlying Field status', () => {
928
+ const {container} = render(
929
+ <FileInput
930
+ label="Upload"
931
+ value={null}
932
+ onChange={() => {}}
933
+ status={{type: 'error', message: 'Something went wrong'}}
934
+ statusVariant="detached"
935
+ />,
936
+ );
937
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
938
+ 'data-variant',
939
+ 'detached',
940
+ );
941
+ });
942
+ });
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file FileInput.tsx
7
- * @input Uses React, useId, Field, Icon, Spinner
7
+ * @input Uses React, useId, Field, Icon, Spinner, VisuallyHidden
8
8
  * @output Exports FileInput component, FileInputProps, FileInputStatus
9
9
  * @position Core implementation; consumed by index.ts, tested by FileInput.test.tsx
10
10
  *
@@ -40,11 +40,14 @@ import {
40
40
  Field,
41
41
  InputClearButton,
42
42
  type InputStatus,
43
- type InputStatusType,
43
+ type FieldStatusVariant,
44
44
  } from '../Field';
45
- import {Icon, type IconName} from '../Icon';
45
+ import {Icon} from '../Icon';
46
46
  import {Spinner} from '../Spinner';
47
+ import {VisuallyHidden} from '../VisuallyHidden';
47
48
  import {useAnnounce} from '../hooks/useAnnounce';
49
+ import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
50
+ import {useClickableContainer} from '../hooks/useClickableContainer';
48
51
  import {useTooltip} from '../Tooltip';
49
52
 
50
53
  export type {
@@ -246,17 +249,6 @@ const styles = stylex.create({
246
249
  flex: 1,
247
250
  minWidth: 0,
248
251
  },
249
- liveRegion: {
250
- position: 'absolute',
251
- width: 1,
252
- height: 1,
253
- padding: 0,
254
- margin: -1,
255
- overflow: 'hidden',
256
- clip: 'rect(0, 0, 0, 0)',
257
- whiteSpace: 'nowrap',
258
- borderWidth: 0,
259
- },
260
252
  });
261
253
 
262
254
  const statusBorderStyles = stylex.create({
@@ -358,6 +350,14 @@ export interface FileInputProps extends Omit<
358
350
  * Validation status for the input.
359
351
  */
360
352
  status?: InputStatus;
353
+ /**
354
+ * How the status message is placed relative to the input.
355
+ * - 'attached': message overlaps directly below the input (bordered treatment)
356
+ * - 'detached': message floats below as a separate element with spacing
357
+ * - 'tooltip': no message box; the status icon becomes a focusable info-tip button that reveals the message on hover, keyboard focus, or tap
358
+ * @default 'attached'
359
+ */
360
+ statusVariant?: FieldStatusVariant;
361
361
  /**
362
362
  * Description text displayed below the label.
363
363
  */
@@ -414,6 +414,7 @@ export function FileInput({
414
414
  isRequired = false,
415
415
  isLoading = false,
416
416
  status: statusProp,
417
+ statusVariant = 'attached',
417
418
  description,
418
419
  placeholder,
419
420
  mode = 'input',
@@ -430,22 +431,24 @@ export function FileInput({
430
431
  const id = useId();
431
432
  const descriptionID = useId();
432
433
  const statusMessageID = useId();
433
- const liveRegionID = useId();
434
+ const requiredID = useId();
434
435
  const inputRef = useRef<HTMLInputElement | null>(null);
436
+ const containerRef = useRef<HTMLDivElement | null>(null);
435
437
  const [isDragOver, setIsDragOver] = useState(false);
436
438
  const [validationError, setValidationError] = useState<string | null>(null);
437
439
  const [, startTransition] = useTransition();
438
440
 
439
441
  // Announce successful file selection to screen readers via a persistent
440
- // live region (forms-17). The component's own role="status" region only
441
- // carries validation errors, so a successful attach was previously silent.
442
+ // live region (forms-17). Validation errors are announced (assertively) by
443
+ // the FieldStatus that the derived error status mounts, so only the
444
+ // successful attach needs an explicit announcement here.
442
445
  const announce = useAnnounce();
443
446
 
444
447
  // Disabled-reason tooltip. Disabled controls swallow pointer events, so the
445
- // tooltip listeners attach to the role="button" trigger (which already
446
- // exists) and the trigger stays perceivable via aria-disabled instead of the
447
- // native disabled attribute. Opening the picker is blocked by the isDisabled
448
- // guards in handleClick / handleKeyDown / handleFiles.
448
+ // tooltip listeners attach to the visible container (which stays hoverable)
449
+ // and the trigger stays perceivable via aria-disabled instead of the native
450
+ // disabled attribute. Opening the picker is blocked by the isDisabled guards
451
+ // in the handlers.
449
452
  const showsDisabledMessage = isDisabled && !!disabledMessage;
450
453
  const disabledMessageTooltip = useTooltip({
451
454
  placement: 'above',
@@ -459,25 +462,27 @@ export function FileInput({
459
462
  ? {type: 'error' as const, message: validationError}
460
463
  : undefined);
461
464
 
462
- const statusIconMap: Record<InputStatusType, IconName> = {
463
- warning: 'warning',
464
- error: 'error',
465
- success: 'success',
466
- };
465
+ const {statusIcon, describedBy: statusTooltipDescribedBy} =
466
+ useInputStatusIcon({
467
+ status,
468
+ statusVariant,
469
+ });
467
470
 
468
- const statusIconColorMap: Record<
469
- InputStatusType,
470
- 'warning' | 'error' | 'success'
471
- > = {
472
- warning: 'warning',
473
- error: 'error',
474
- success: 'success',
475
- };
471
+ // Required state. The trigger is a real button, but AT does not reliably
472
+ // announce aria-required, so the trigger instead points its aria-describedby
473
+ // at a visually hidden "Required" span — mirroring the Field label's visible
474
+ // indicator (where isOptional takes precedence) and the pattern Slider uses
475
+ // for its thumbs.
476
+ const conveysRequired = isRequired && !isOptional;
476
477
 
477
478
  const ariaDescribedBy =
478
479
  [
479
480
  description ? descriptionID : null,
480
- status?.message ? statusMessageID : null,
481
+ statusVariant !== 'tooltip' && status?.message ? statusMessageID : null,
482
+ // The tooltip variant renders no message box; describe the input by the
483
+ // tooltip's content instead so the status is still announced.
484
+ statusTooltipDescribedBy,
485
+ conveysRequired ? requiredID : null,
481
486
  showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
482
487
  ]
483
488
  .filter(Boolean)
@@ -515,8 +520,9 @@ export function FileInput({
515
520
  onChange(result);
516
521
 
517
522
  // Announce the successful selection politely. Validation errors are
518
- // handled by the role="status" region below, so only announce the
519
- // attach here (do not double-announce errors).
523
+ // announced assertively by the FieldStatus that the derived error
524
+ // status mounts, so only announce the attach here (do not
525
+ // double-announce errors).
520
526
  if (errors.length === 0) {
521
527
  announce(
522
528
  valid.length === 1
@@ -574,6 +580,9 @@ export function FileInput({
574
580
  }
575
581
  }, [isDisabled]);
576
582
 
583
+ // Explicit keyboard activation so Enter/Space open the picker even where a
584
+ // synthetic keydown does not raise a native click. The isDisabled guard
585
+ // blocks activation while focusable-disabled.
577
586
  const handleKeyDown = useCallback(
578
587
  (e: React.KeyboardEvent) => {
579
588
  if ((e.key === 'Enter' || e.key === ' ') && !isDisabled) {
@@ -584,6 +593,16 @@ export function FileInput({
584
593
  [isDisabled],
585
594
  );
586
595
 
596
+ // Make the surface clickable without giving it an interactive role. Clicks on
597
+ // the nested clear/status controls are ignored by the hook, so those buttons
598
+ // are plain siblings — no nested-interactive violation.
599
+ const {onClick: onContainerClick, onMouseUp: onContainerMouseUp} =
600
+ useClickableContainer({
601
+ containerRef,
602
+ onClick: handleClick,
603
+ disabled: isDisabled,
604
+ });
605
+
587
606
  const handleDragEnter = useCallback(
588
607
  (e: DragEvent) => {
589
608
  e.preventDefault();
@@ -687,13 +706,7 @@ export function FileInput({
687
706
  )}>
688
707
  {fileNames ?? displayPlaceholder}
689
708
  </span>
690
- {status && (
691
- <Icon
692
- icon={statusIconMap[status.type]}
693
- size="md"
694
- color={statusIconColorMap[status.type]}
695
- />
696
- )}
709
+ {statusIcon}
697
710
  </>
698
711
  );
699
712
  };
@@ -728,39 +741,21 @@ export function FileInput({
728
741
  }
729
742
  : undefined
730
743
  }
744
+ statusVariant={statusVariant}
731
745
  labelTooltip={labelTooltip}
732
746
  width={width}>
733
747
  <div
734
748
  ref={el => {
735
- // Anchor + hover/focus listeners for the disabled-message tooltip.
736
- // Handlers are gated internally by isEnabled, and anchor names
737
- // compose, so attaching unconditionally is safe.
749
+ containerRef.current = el;
750
+ // Anchor + hover/focus listeners for the disabled-message tooltip on
751
+ // the visible container (the focusable trigger is visually hidden, so
752
+ // anchoring there would place the tooltip at a 1px box). focusin
753
+ // bubbles from the trigger button, so the tooltip still opens on
754
+ // keyboard focus. Handlers are gated internally by isEnabled.
738
755
  disabledMessageTooltip.ref(el);
739
756
  }}
740
- role="button"
741
- // With a disabledMessage the trigger keeps focusability via
742
- // aria-disabled so the reason is focus-discoverable; opening the picker
743
- // is still blocked by the isDisabled guards in the handlers.
744
- tabIndex={isDisabled && !showsDisabledMessage ? -1 : 0}
745
- aria-disabled={showsDisabledMessage ? 'true' : undefined}
746
- onClick={handleClick}
747
- onKeyDown={handleKeyDown}
748
- // aria-label suppresses child content from the accessible name, so
749
- // compose the selected filenames into it — otherwise a screen-reader
750
- // user refocusing the control hears only the field label and cannot
751
- // tell what (if anything) is attached.
752
- aria-label={
753
- hasFiles && fileNames
754
- ? t('@astryx.fileInput.triggerWithFiles', {label, fileNames})
755
- : label
756
- }
757
- aria-busy={isLoading || undefined}
758
- // These describe the operable control, so they belong on the focusable
759
- // role="button" wrapper — not the hidden tabIndex={-1} file input the
760
- // user never focuses (forms-6).
761
- aria-describedby={ariaDescribedBy}
762
- aria-required={isRequired ? 'true' : undefined}
763
- aria-invalid={status?.type === 'error' ? 'true' : undefined}
757
+ onClick={!isDisabled ? onContainerClick : undefined}
758
+ onMouseUp={!isDisabled ? onContainerMouseUp : undefined}
764
759
  {...dragDropProps}
765
760
  {...mergeProps(
766
761
  themeProps('file-input', {mode, status: status?.type ?? null}),
@@ -776,6 +771,40 @@ export function FileInput({
776
771
  className,
777
772
  style,
778
773
  )}>
774
+ {/* Visually hidden real button carrying the accessible role, name, and
775
+ ARIA. Kept as a sibling of the clear/status controls inside a
776
+ non-interactive container, so no interactive element nests inside
777
+ another (WCAG 4.1.2). The visible focus feedback is the container's
778
+ :focus-within border; the surface click is handled by the container
779
+ (VisuallyHidden disables the button's own pointer events), and
780
+ keyboard activation still fires here. */}
781
+ <VisuallyHidden>
782
+ <button
783
+ type="button"
784
+ // With a disabledMessage the trigger keeps focusability via
785
+ // aria-disabled so the reason is focus-discoverable; opening the
786
+ // picker is still blocked by the isDisabled guards in the handlers.
787
+ // Otherwise the native disabled attribute removes it from the tab
788
+ // order.
789
+ disabled={isDisabled && !showsDisabledMessage}
790
+ tabIndex={isDisabled && !showsDisabledMessage ? -1 : 0}
791
+ aria-disabled={showsDisabledMessage ? 'true' : undefined}
792
+ onClick={handleClick}
793
+ onKeyDown={handleKeyDown}
794
+ // aria-label suppresses child content from the accessible name, so
795
+ // compose the selected filenames into it — otherwise a
796
+ // screen-reader user refocusing the control hears only the field
797
+ // label and cannot tell what (if anything) is attached.
798
+ aria-label={
799
+ hasFiles && fileNames
800
+ ? t('@astryx.fileInput.triggerWithFiles', {label, fileNames})
801
+ : label
802
+ }
803
+ aria-busy={isLoading || undefined}
804
+ aria-describedby={ariaDescribedBy}
805
+ aria-invalid={status?.type === 'error' ? 'true' : undefined}
806
+ />
807
+ </VisuallyHidden>
779
808
  <input
780
809
  {...rest}
781
810
  ref={mergeRefs(ref, inputRef)}
@@ -786,7 +815,7 @@ export function FileInput({
786
815
  disabled={isDisabled}
787
816
  onChange={handleInputChange}
788
817
  // The visually-hidden native input is never focused (tabIndex={-1});
789
- // its describedby/required/invalid live on the role="button" wrapper.
818
+ // its describedby/required/invalid live on the trigger button.
790
819
  aria-hidden="true"
791
820
  tabIndex={-1}
792
821
  {...stylex.props(styles.hiddenInput)}
@@ -799,13 +828,11 @@ export function FileInput({
799
828
  />
800
829
  )}
801
830
  </div>
802
- <div
803
- id={liveRegionID}
804
- role="status"
805
- aria-live="polite"
806
- {...stylex.props(styles.liveRegion)}>
807
- {validationError}
808
- </div>
831
+ {conveysRequired && (
832
+ <VisuallyHidden id={requiredID}>
833
+ {t('@astryx.fileInput.required')}
834
+ </VisuallyHidden>
835
+ )}
809
836
  {showsDisabledMessage &&
810
837
  disabledMessageTooltip.renderTooltip(disabledMessage)}
811
838
  </Field>
@@ -41,6 +41,7 @@ import {
41
41
  truncationTooltipStyles,
42
42
  } from '../Text/text.stylex';
43
43
  import {useTruncation} from '../Text/useTruncation';
44
+ import {resolveStyleColor} from '../Text/Text';
44
45
  import type {LayerPlacement} from '../Layer';
45
46
  import {mergeProps, mergeRefs} from '../utils';
46
47
  import type {BaseProps} from '../BaseProps';
@@ -251,7 +252,7 @@ export function Heading({
251
252
  {...mergeProps(
252
253
  themeProps('heading', {level, color, ...(type && {type})}),
253
254
  stylex.props(
254
- colorStyles[color],
255
+ colorStyles[resolveStyleColor(color)],
255
256
  type ? sizeByTypeStyles[type] : sizeByLevelStyles[level],
256
257
  type && defaultWeightByTypeStyles[type],
257
258
  // Display: use truncation styles when maxLines > 0
@@ -34,7 +34,6 @@ import {
34
34
  radiusVars,
35
35
  spacingVars,
36
36
  } from '../theme/tokens.stylex';
37
- import {mergeProps} from '../utils';
38
37
  import {themeProps} from '../utils/themeProps';
39
38
 
40
39
  const styles = stylex.create({
@@ -469,6 +468,7 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
469
468
  props?: Omit<ContextRenderProps, 'positioning'>,
470
469
  ): ReactNode => {
471
470
  const renderPlacement = props?.placement ?? placement;
471
+ const themeClassName = themeProps('hovercard').className;
472
472
  const renderProps = {
473
473
  placement: renderPlacement,
474
474
  alignment: props?.alignment ?? alignment,
@@ -477,7 +477,19 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
477
477
  // are non-modal, so group is honest semantics without a name.
478
478
  role: label ? 'dialog' : 'group',
479
479
  'aria-label': label || undefined,
480
- xstyle: [popoverXstyle, layerAnimations[renderPlacement]],
480
+ // Consumer surface style props land on the layer container — the
481
+ // themed surface (bg/radius/shadow) where the theme class lives — so
482
+ // customizing the card targets the same element as the theme. The inner
483
+ // span keeps `styles.content` for padding.
484
+ xstyle: [
485
+ popoverXstyle,
486
+ layerAnimations[renderPlacement],
487
+ props?.xstyle,
488
+ ],
489
+ className: props?.className
490
+ ? `${themeClassName} ${props.className}`
491
+ : themeClassName,
492
+ style: props?.style,
481
493
  // Render the layer as inline-safe phrasing markup so HoverCard stays
482
494
  // valid (and hydration-stable) inside inline contexts like a `<p>`.
483
495
  as: 'span' as const,
@@ -485,7 +497,7 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
485
497
 
486
498
  return layer.render(
487
499
  <span
488
- {...mergeProps(themeProps('hovercard'), stylex.props(styles.content))}
500
+ {...stylex.props(styles.content)}
489
501
  onMouseEnter={() => {
490
502
  isHoveringContentRef.current = true;
491
503
  clearTimeouts();
@@ -39,6 +39,12 @@ export const docs = {
39
39
  type: 'string',
40
40
  description: 'Accessible name for a MEANINGFUL, standalone icon (a status glyph or icon-only indicator with no adjacent text). Setting it exposes the icon to screen readers as role="img" with this text as the accessible name (aria-label) and removes the default aria-hidden. Omit it (default) for decorative icons and the icon stays hidden from assistive tech (aria-hidden="true"). This is the accessible-name / alt-text prop for icons: one prop instead of manually setting aria-label + role + aria-hidden. An empty string is treated as decorative. Do not set it when an interactive parent (Button, IconButton, link) already names the control.',
41
41
  },
42
+ {
43
+ name: 'xstyle',
44
+ type: 'StyleXStyles',
45
+ description:
46
+ 'StyleX styles for customization (color, size, opacity). Folded into the icon\'s own stylex.props() call so it composes with the base color/size styles. Must be a stylex.create() value, not an inline style object like style={{}}.',
47
+ },
42
48
  ],
43
49
  theming: {
44
50
  targets: [
@@ -90,6 +96,12 @@ export const docsZh = {
90
96
  type: 'string',
91
97
  description: '有含义的独立图标的可访问名称(无相邻文字的状态图标或纯图标指示器)。设置后会将图标以 role="img" 暴露给辅助技术,并以该文本作为可访问名称(aria-label),同时移除默认的 aria-hidden。省略(默认)用于装饰性图标,图标对辅助技术保持隐藏(aria-hidden="true")。空字符串按装饰性处理。当交互式父元素(Button、IconButton、链接)已命名该控件时请勿设置。',
92
98
  },
99
+ {
100
+ name: 'xstyle',
101
+ type: 'StyleXStyles',
102
+ description:
103
+ '用于自定义的 StyleX 样式(颜色、尺寸、不透明度)。会并入图标自身的 stylex.props() 调用,从而与基础的颜色/尺寸样式组合。必须是 stylex.create() 的值,而不是像 style={{}} 这样的内联样式对象。',
104
+ },
93
105
  ],
94
106
  theming: {
95
107
  targets: [
@@ -136,5 +148,6 @@ export const docsDense = {
136
148
  color: 'Color variant mapped to Astryx icon color tokens.',
137
149
  size: 'Icon size.',
138
150
  label: 'Accessible name for a meaningful, standalone icon. Sets role="img" + aria-label and drops the default aria-hidden. Omit (default) for decorative icons (stays aria-hidden). Empty string = decorative. The accessible-name/alt-text prop for icons.',
151
+ xstyle: 'StyleX styles (color, size, opacity) via stylex.create(); composes with the base color/size styles.',
139
152
  },
140
153
  };