@astryxdesign/core 0.1.9-canary.d2d84f8 → 0.1.9-canary.e00a241

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 (414) hide show
  1. package/dist/Avatar/Avatar.d.ts +6 -1
  2. package/dist/Avatar/Avatar.d.ts.map +1 -1
  3. package/dist/Avatar/Avatar.js +46 -12
  4. package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
  5. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  6. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  7. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
  8. package/dist/Breadcrumbs/index.d.ts +1 -0
  9. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  10. package/dist/Breadcrumbs/index.js +2 -1
  11. package/dist/Calendar/Calendar.d.ts.map +1 -1
  12. package/dist/Calendar/Calendar.js +50 -9
  13. package/dist/Calendar/dayCellUtils.d.ts +4 -4
  14. package/dist/Calendar/dayCellUtils.js +2 -2
  15. package/dist/Calendar/styles.d.ts +30 -31
  16. package/dist/Calendar/styles.d.ts.map +1 -1
  17. package/dist/Calendar/styles.js +30 -31
  18. package/dist/Card/Card.js +1 -1
  19. package/dist/Carousel/Carousel.d.ts.map +1 -1
  20. package/dist/Carousel/Carousel.js +22 -12
  21. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  22. package/dist/Chat/ChatDictationButton.js +3 -1
  23. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  24. package/dist/Chat/ChatMessageBubble.js +8 -8
  25. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  26. package/dist/Chat/ChatToolCalls.js +10 -3
  27. package/dist/CheckboxInput/CheckboxInput.js +4 -4
  28. package/dist/Citation/Citation.d.ts +22 -1
  29. package/dist/Citation/Citation.d.ts.map +1 -1
  30. package/dist/Citation/Citation.js +20 -6
  31. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  32. package/dist/CodeBlock/CodeBlock.js +13 -7
  33. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  34. package/dist/Collapsible/Collapsible.js +3 -1
  35. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  36. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  37. package/dist/CommandPalette/CommandPalette.js +42 -3
  38. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  39. package/dist/ContextMenu/ContextMenu.js +14 -5
  40. package/dist/ContextMenu/index.d.ts +1 -0
  41. package/dist/ContextMenu/index.d.ts.map +1 -1
  42. package/dist/ContextMenu/index.js +3 -1
  43. package/dist/DateInput/DateInput.d.ts +1 -0
  44. package/dist/DateInput/DateInput.d.ts.map +1 -1
  45. package/dist/DateInput/DateInput.js +31 -19
  46. package/dist/DateRangeInput/DateRangeInput.d.ts +1 -0
  47. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  48. package/dist/DateRangeInput/DateRangeInput.js +20 -19
  49. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  50. package/dist/DateTimeInput/DateTimeInput.js +23 -18
  51. package/dist/Divider/Divider.d.ts +2 -2
  52. package/dist/Divider/Divider.d.ts.map +1 -1
  53. package/dist/Divider/Divider.js +13 -0
  54. package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
  55. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  56. package/dist/DropdownMenu/DropdownMenu.js +22 -5
  57. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  58. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
  59. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  60. package/dist/DropdownMenu/DropdownMenuItem.js +4 -1
  61. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  62. package/dist/DropdownMenu/DropdownMenuRadioItem.js +4 -1
  63. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
  64. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
  65. package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
  66. package/dist/DropdownMenu/index.d.ts +10 -0
  67. package/dist/DropdownMenu/index.d.ts.map +1 -1
  68. package/dist/DropdownMenu/index.js +13 -0
  69. package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
  70. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
  71. package/dist/DropdownMenu/menuItemHover.js +33 -0
  72. package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
  73. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
  74. package/dist/DropdownMenu/menuItemRoles.js +10 -1
  75. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  76. package/dist/DropdownMenu/renderDropdownItems.js +21 -6
  77. package/dist/Field/Field.d.ts +3 -1
  78. package/dist/Field/Field.d.ts.map +1 -1
  79. package/dist/Field/Field.js +4 -1
  80. package/dist/Field/inputStyles.stylex.d.ts +1 -0
  81. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  82. package/dist/Field/inputStyles.stylex.js +1 -0
  83. package/dist/FieldStatus/FieldStatus.d.ts +4 -1
  84. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  85. package/dist/FieldStatus/FieldStatus.js +4 -2
  86. package/dist/FileInput/FileInput.d.ts +1 -0
  87. package/dist/FileInput/FileInput.d.ts.map +1 -1
  88. package/dist/FileInput/FileInput.js +91 -65
  89. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  90. package/dist/HoverCard/useHoverCard.js +10 -4
  91. package/dist/Icon/Icon.d.ts +15 -1
  92. package/dist/Icon/Icon.d.ts.map +1 -1
  93. package/dist/Icon/Icon.js +19 -3
  94. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  95. package/dist/Lightbox/Lightbox.js +15 -9
  96. package/dist/List/List.d.ts.map +1 -1
  97. package/dist/List/List.js +6 -3
  98. package/dist/Markdown/Markdown.d.ts.map +1 -1
  99. package/dist/Markdown/Markdown.js +7 -0
  100. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  101. package/dist/MultiSelector/MultiSelector.js +65 -40
  102. package/dist/NumberInput/NumberInput.d.ts +1 -0
  103. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  104. package/dist/NumberInput/NumberInput.js +20 -17
  105. package/dist/Outline/Outline.js +2 -2
  106. package/dist/RadioList/RadioList.d.ts +2 -2
  107. package/dist/RadioList/RadioListItem.js +4 -4
  108. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  109. package/dist/Resizable/ResizeHandle.js +49 -19
  110. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  111. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  112. package/dist/SegmentedControl/SegmentedControlItem.js +2 -1
  113. package/dist/Selector/Selector.d.ts.map +1 -1
  114. package/dist/Selector/Selector.js +58 -16
  115. package/dist/SideNav/SideNav.d.ts.map +1 -1
  116. package/dist/SideNav/SideNav.js +5 -5
  117. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  118. package/dist/SideNav/SideNavCollapseButton.js +13 -10
  119. package/dist/SideNav/SideNavItem.d.ts +1 -1
  120. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  121. package/dist/SideNav/SideNavItem.js +12 -10
  122. package/dist/Slider/Slider.d.ts.map +1 -1
  123. package/dist/Slider/Slider.js +87 -34
  124. package/dist/Spinner/Spinner.d.ts +3 -2
  125. package/dist/Spinner/Spinner.d.ts.map +1 -1
  126. package/dist/Spinner/Spinner.js +11 -2
  127. package/dist/Switch/Switch.d.ts +8 -1
  128. package/dist/Switch/Switch.d.ts.map +1 -1
  129. package/dist/Switch/Switch.js +160 -91
  130. package/dist/TabList/TabList.d.ts +2 -11
  131. package/dist/TabList/TabList.d.ts.map +1 -1
  132. package/dist/TabList/TabList.js +5 -9
  133. package/dist/TabList/TabListContext.d.ts +0 -5
  134. package/dist/TabList/TabListContext.d.ts.map +1 -1
  135. package/dist/TabList/TabListContext.js +0 -5
  136. package/dist/Table/BaseTable.d.ts.map +1 -1
  137. package/dist/Table/BaseTable.js +30 -4
  138. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  139. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
  140. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  141. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +36 -26
  142. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  143. package/dist/Table/plugins/selection/useTableSelection.js +3 -0
  144. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  145. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +14 -6
  146. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  147. package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
  148. package/dist/Table/types.d.ts +32 -0
  149. package/dist/Table/types.d.ts.map +1 -1
  150. package/dist/TextArea/TextArea.d.ts +1 -0
  151. package/dist/TextArea/TextArea.d.ts.map +1 -1
  152. package/dist/TextArea/TextArea.js +16 -19
  153. package/dist/TextInput/TextInput.d.ts +1 -0
  154. package/dist/TextInput/TextInput.d.ts.map +1 -1
  155. package/dist/TextInput/TextInput.js +18 -17
  156. package/dist/TimeInput/TimeInput.d.ts +1 -0
  157. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  158. package/dist/TimeInput/TimeInput.js +15 -17
  159. package/dist/Timestamp/Timestamp.d.ts +31 -3
  160. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  161. package/dist/Timestamp/Timestamp.js +47 -76
  162. package/dist/Timestamp/formatInstant.d.ts +41 -0
  163. package/dist/Timestamp/formatInstant.d.ts.map +1 -0
  164. package/dist/Timestamp/formatInstant.js +177 -0
  165. package/dist/Timestamp/index.d.ts +1 -0
  166. package/dist/Timestamp/index.d.ts.map +1 -1
  167. package/dist/Timestamp/tooltipEntries.d.ts +56 -0
  168. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
  169. package/dist/Timestamp/tooltipEntries.js +163 -0
  170. package/dist/Token/Token.d.ts +30 -3
  171. package/dist/Token/Token.d.ts.map +1 -1
  172. package/dist/Token/Token.js +17 -2
  173. package/dist/Token/index.d.ts +1 -1
  174. package/dist/Token/index.d.ts.map +1 -1
  175. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  176. package/dist/Tokenizer/Tokenizer.js +2 -2
  177. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  178. package/dist/Tooltip/useTooltip.js +17 -1
  179. package/dist/TopNav/TopNavItem.d.ts +3 -1
  180. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  181. package/dist/TopNav/TopNavItem.js +30 -3
  182. package/dist/TreeList/TreeList.d.ts.map +1 -1
  183. package/dist/TreeList/TreeList.js +1 -0
  184. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  185. package/dist/TreeList/TreeListBranches.js +8 -6
  186. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  187. package/dist/TreeList/TreeListItem.js +32 -14
  188. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  189. package/dist/Typeahead/BaseTypeahead.js +19 -10
  190. package/dist/Typeahead/Typeahead.js +1 -1
  191. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  192. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  193. package/dist/Typeahead/TypeaheadItem.js +20 -10
  194. package/dist/astryx.css +38 -14
  195. package/dist/astryx.umd.js +52 -52
  196. package/dist/astryx.umd.js.map +4 -4
  197. package/dist/hooks/index.d.ts +2 -0
  198. package/dist/hooks/index.d.ts.map +1 -1
  199. package/dist/hooks/index.js +1 -0
  200. package/dist/hooks/isRtlElement.d.ts +18 -0
  201. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  202. package/dist/hooks/isRtlElement.js +27 -0
  203. package/dist/hooks/useAnnounce.d.ts +3 -0
  204. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  205. package/dist/hooks/useAnnounce.js +39 -1
  206. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  207. package/dist/hooks/useFocusTrap.js +52 -11
  208. package/dist/hooks/useGridFocus.d.ts +6 -1
  209. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  210. package/dist/hooks/useGridFocus.js +12 -9
  211. package/dist/hooks/useHotkeys.d.ts +9 -0
  212. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  213. package/dist/hooks/useHotkeys.js +9 -0
  214. package/dist/hooks/useInputStatusIcon.d.ts +38 -0
  215. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
  216. package/dist/hooks/useInputStatusIcon.js +158 -0
  217. package/dist/hooks/useListFocus.d.ts +39 -1
  218. package/dist/hooks/useListFocus.d.ts.map +1 -1
  219. package/dist/hooks/useListFocus.js +54 -9
  220. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  221. package/dist/theme/derivedVarRegistry.js +13 -0
  222. package/dist/utils/index.d.ts +1 -0
  223. package/dist/utils/index.d.ts.map +1 -1
  224. package/dist/utils/index.js +2 -1
  225. package/dist/utils/plainDate.d.ts +17 -0
  226. package/dist/utils/plainDate.d.ts.map +1 -1
  227. package/dist/utils/plainDate.js +23 -4
  228. package/dist/utils/rtlStyles.d.ts +24 -0
  229. package/dist/utils/rtlStyles.d.ts.map +1 -0
  230. package/dist/utils/rtlStyles.js +27 -0
  231. package/locales/en.json +76 -0
  232. package/locales/pseudo.json +57 -0
  233. package/package.json +6 -1
  234. package/src/Avatar/Avatar.doc.mjs +18 -4
  235. package/src/Avatar/Avatar.test.tsx +106 -0
  236. package/src/Avatar/Avatar.tsx +62 -10
  237. package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
  238. package/src/Avatar/AvatarStatusDot.tsx +6 -4
  239. package/src/AvatarGroup/AvatarGroup.test.tsx +16 -1
  240. package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
  241. package/src/Breadcrumbs/Breadcrumbs.test.tsx +51 -0
  242. package/src/Breadcrumbs/index.ts +4 -0
  243. package/src/Button/Button.doc.mjs +0 -4
  244. package/src/Calendar/Calendar.test.tsx +170 -20
  245. package/src/Calendar/Calendar.tsx +73 -16
  246. package/src/Calendar/dayCellUtils.test.ts +18 -18
  247. package/src/Calendar/dayCellUtils.ts +2 -2
  248. package/src/Calendar/styles.ts +33 -39
  249. package/src/Card/Card.tsx +1 -1
  250. package/src/Carousel/Carousel.tsx +25 -6
  251. package/src/Chat/ChatComposer.doc.mjs +2 -2
  252. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  253. package/src/Chat/ChatDictationButton.tsx +7 -1
  254. package/src/Chat/ChatMessageBubble.tsx +15 -10
  255. package/src/Chat/ChatSystemMessage.test.tsx +5 -0
  256. package/src/Chat/ChatToolCalls.tsx +9 -2
  257. package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
  258. package/src/CheckboxInput/CheckboxInput.tsx +4 -4
  259. package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
  260. package/src/Citation/Citation.doc.mjs +4 -3
  261. package/src/Citation/Citation.test.tsx +97 -0
  262. package/src/Citation/Citation.tsx +43 -11
  263. package/src/CodeBlock/CodeBlock.tsx +35 -8
  264. package/src/Collapsible/Collapsible.doc.mjs +1 -0
  265. package/src/Collapsible/Collapsible.test.tsx +7 -0
  266. package/src/Collapsible/Collapsible.tsx +16 -6
  267. package/src/CommandPalette/CommandPalette.test.tsx +95 -1
  268. package/src/CommandPalette/CommandPalette.tsx +41 -2
  269. package/src/ContextMenu/ContextMenu.test.tsx +42 -0
  270. package/src/ContextMenu/ContextMenu.tsx +13 -11
  271. package/src/ContextMenu/index.ts +5 -0
  272. package/src/DateInput/DateInput.doc.mjs +15 -5
  273. package/src/DateInput/DateInput.test.tsx +210 -3
  274. package/src/DateInput/DateInput.tsx +41 -29
  275. package/src/DateRangeInput/DateRangeInput.doc.mjs +11 -3
  276. package/src/DateRangeInput/DateRangeInput.test.tsx +120 -3
  277. package/src/DateRangeInput/DateRangeInput.tsx +29 -27
  278. package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
  279. package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
  280. package/src/DateTimeInput/DateTimeInput.tsx +44 -39
  281. package/src/Divider/Divider.test.tsx +32 -8
  282. package/src/Divider/Divider.tsx +14 -1
  283. package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
  284. package/src/DropdownMenu/DropdownMenu.tsx +31 -12
  285. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
  286. package/src/DropdownMenu/DropdownMenuItem.tsx +8 -2
  287. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +8 -2
  288. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
  289. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
  290. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
  291. package/src/DropdownMenu/index.ts +16 -0
  292. package/src/DropdownMenu/menuItemHover.ts +39 -0
  293. package/src/DropdownMenu/menuItemRoles.ts +9 -0
  294. package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
  295. package/src/Field/Field.tsx +14 -9
  296. package/src/Field/inputStyles.stylex.ts +2 -0
  297. package/src/FieldStatus/FieldStatus.tsx +10 -4
  298. package/src/FileInput/FileInput.doc.mjs +13 -7
  299. package/src/FileInput/FileInput.test.tsx +84 -16
  300. package/src/FileInput/FileInput.tsx +96 -79
  301. package/src/HoverCard/useHoverCard.tsx +15 -3
  302. package/src/Icon/Icon.doc.mjs +13 -0
  303. package/src/Icon/Icon.test.tsx +89 -0
  304. package/src/Icon/Icon.tsx +51 -3
  305. package/src/Lightbox/Lightbox.tsx +11 -3
  306. package/src/List/List.test.tsx +17 -29
  307. package/src/List/List.tsx +6 -1
  308. package/src/Markdown/Markdown.test.tsx +21 -0
  309. package/src/Markdown/Markdown.tsx +4 -0
  310. package/src/MultiSelector/MultiSelector.doc.mjs +11 -0
  311. package/src/MultiSelector/MultiSelector.test.tsx +306 -3
  312. package/src/MultiSelector/MultiSelector.tsx +88 -57
  313. package/src/NumberInput/NumberInput.doc.mjs +11 -5
  314. package/src/NumberInput/NumberInput.test.tsx +48 -0
  315. package/src/NumberInput/NumberInput.tsx +25 -26
  316. package/src/Outline/Outline.test.tsx +12 -12
  317. package/src/Outline/Outline.tsx +2 -2
  318. package/src/RadioList/RadioList.doc.mjs +6 -0
  319. package/src/RadioList/RadioList.tsx +2 -2
  320. package/src/RadioList/RadioListItem.tsx +4 -4
  321. package/src/Resizable/ResizeHandle.test.tsx +94 -0
  322. package/src/Resizable/ResizeHandle.tsx +70 -20
  323. package/src/SegmentedControl/SegmentedControlItem.tsx +2 -0
  324. package/src/Selector/Selector.doc.mjs +8 -0
  325. package/src/Selector/Selector.test.tsx +328 -3
  326. package/src/Selector/Selector.tsx +70 -19
  327. package/src/SideNav/SideNav.tsx +1 -8
  328. package/src/SideNav/SideNavCollapseButton.tsx +9 -7
  329. package/src/SideNav/SideNavItem.tsx +5 -3
  330. package/src/Slider/Slider.doc.mjs +6 -0
  331. package/src/Slider/Slider.test.tsx +240 -12
  332. package/src/Slider/Slider.tsx +96 -23
  333. package/src/Spinner/Spinner.test.tsx +10 -8
  334. package/src/Spinner/Spinner.tsx +15 -5
  335. package/src/Switch/Switch.doc.mjs +142 -42
  336. package/src/Switch/Switch.test.tsx +22 -0
  337. package/src/Switch/Switch.tsx +90 -33
  338. package/src/TabList/TabList.doc.mjs +0 -6
  339. package/src/TabList/TabList.test.tsx +3 -15
  340. package/src/TabList/TabList.tsx +6 -17
  341. package/src/TabList/TabListContext.ts +0 -6
  342. package/src/Table/BaseTable.tsx +34 -2
  343. package/src/Table/Table.doc.mjs +11 -0
  344. package/src/Table/Table.test.tsx +85 -0
  345. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
  346. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +24 -17
  347. package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
  348. package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
  349. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +37 -8
  350. package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
  351. package/src/Table/types.ts +33 -0
  352. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  353. package/src/TextArea/TextArea.doc.mjs +11 -5
  354. package/src/TextArea/TextArea.tsx +17 -26
  355. package/src/TextInput/TextInput.doc.mjs +11 -5
  356. package/src/TextInput/TextInput.test.tsx +130 -3
  357. package/src/TextInput/TextInput.tsx +18 -25
  358. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  359. package/src/TimeInput/TimeInput.doc.mjs +11 -5
  360. package/src/TimeInput/TimeInput.tsx +14 -25
  361. package/src/Timestamp/Timestamp.doc.mjs +32 -6
  362. package/src/Timestamp/Timestamp.test.tsx +371 -0
  363. package/src/Timestamp/Timestamp.tsx +96 -93
  364. package/src/Timestamp/formatInstant.ts +218 -0
  365. package/src/Timestamp/index.ts +4 -0
  366. package/src/Timestamp/tooltipEntries.test.ts +552 -0
  367. package/src/Timestamp/tooltipEntries.ts +210 -0
  368. package/src/Token/Token.test.tsx +21 -15
  369. package/src/Token/Token.tsx +31 -14
  370. package/src/Token/index.ts +1 -1
  371. package/src/Tokenizer/Tokenizer.doc.mjs +8 -1
  372. package/src/Tokenizer/Tokenizer.tsx +4 -2
  373. package/src/Tooltip/Tooltip.test.tsx +46 -0
  374. package/src/Tooltip/useTooltip.tsx +20 -0
  375. package/src/TopNav/TopNav.test.tsx +93 -2
  376. package/src/TopNav/TopNavItem.doc.mjs +3 -3
  377. package/src/TopNav/TopNavItem.tsx +35 -6
  378. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
  379. package/src/TreeList/TreeList.doc.mjs +6 -0
  380. package/src/TreeList/TreeList.test.tsx +50 -10
  381. package/src/TreeList/TreeList.tsx +5 -0
  382. package/src/TreeList/TreeListBranches.tsx +8 -6
  383. package/src/TreeList/TreeListItem.tsx +33 -11
  384. package/src/Typeahead/BaseTypeahead.tsx +29 -14
  385. package/src/Typeahead/Typeahead.doc.mjs +6 -0
  386. package/src/Typeahead/Typeahead.test.tsx +27 -0
  387. package/src/Typeahead/Typeahead.tsx +1 -1
  388. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  389. package/src/__tests__/inputWidthContract.test.tsx +62 -0
  390. package/src/doc-mjs.d.ts +19 -0
  391. package/src/hooks/index.ts +6 -0
  392. package/src/hooks/isRtlElement.ts +27 -0
  393. package/src/hooks/useAnnounce.test.tsx +75 -2
  394. package/src/hooks/useAnnounce.ts +47 -1
  395. package/src/hooks/useFocusTrap.test.tsx +104 -0
  396. package/src/hooks/useFocusTrap.ts +61 -12
  397. package/src/hooks/useGridFocus.doc.mjs +3 -3
  398. package/src/hooks/useGridFocus.test.tsx +41 -0
  399. package/src/hooks/useGridFocus.ts +21 -10
  400. package/src/hooks/useHotkeys.ts +9 -0
  401. package/src/hooks/useInputStatusIcon.test.tsx +162 -0
  402. package/src/hooks/useInputStatusIcon.tsx +224 -0
  403. package/src/hooks/useListFocus.doc.mjs +25 -3
  404. package/src/hooks/useListFocus.test.tsx +153 -1
  405. package/src/hooks/useListFocus.ts +102 -9
  406. package/src/reset.css +0 -26
  407. package/src/reset.test.ts +60 -0
  408. package/src/theme/derivedVarRegistry.test.ts +1 -0
  409. package/src/theme/derivedVarRegistry.ts +6 -0
  410. package/src/theme/generateThemeRules.test.ts +42 -0
  411. package/src/utils/index.ts +2 -0
  412. package/src/utils/plainDate.test.ts +24 -6
  413. package/src/utils/plainDate.ts +18 -4
  414. package/src/utils/rtlStyles.ts +27 -0
@@ -570,6 +570,21 @@ export interface MultiSelectorProps<
570
570
  'data-testid'?: string;
571
571
  }
572
572
 
573
+ // Case-insensitive substring match for a single option. The one predicate used
574
+ // by both the flat filter (count + keyboard nav) and the grouped renderer, so
575
+ // what is shown while searching stays in lockstep with the announced count.
576
+ function optionMatchesQuery(
577
+ option: MultiSelectorOptionData,
578
+ query: string,
579
+ ): boolean {
580
+ if (!query) {
581
+ return true;
582
+ }
583
+ return (option.label ?? option.value)
584
+ .toLowerCase()
585
+ .includes(query.toLowerCase());
586
+ }
587
+
573
588
  // Case-insensitive substring filter over the selectable options. Shared by the
574
589
  // `filteredItems` memo (rendering) and the search-change handler, which needs
575
590
  // the count for the *next* query synchronously to announce it exactly once per
@@ -581,10 +596,7 @@ function filterOptionsByQuery(
581
596
  if (!query) {
582
597
  return items;
583
598
  }
584
- const q = query.toLowerCase();
585
- return items.filter(item =>
586
- (item.label ?? item.value).toLowerCase().includes(q),
587
- );
599
+ return items.filter(item => optionMatchesQuery(item, query));
588
600
  }
589
601
 
590
602
  /**
@@ -725,35 +737,25 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
725
737
 
726
738
  // Single source of truth for item order. Both the hook (keyboard navigation)
727
739
  // and renderOptions (DOM rendering) consume this list — no independent sorting.
728
- // Selected-at-open items are placed first within each group/section.
740
+ // Selected-at-open items are placed first within each group/section, and the
741
+ // same walk applies while searching so group structure survives filtering
742
+ // (only matching items are kept; the query is empty in non-search mode).
729
743
  const sortedItems = useMemo(() => {
730
744
  const selectedSet = selectedAtOpen ?? new Set<string>();
731
- if (searchQuery) {
732
- const selected = filteredItems.filter(item =>
733
- selectedSet.has(item.value),
734
- );
735
- const unselected = filteredItems.filter(
736
- item => !selectedSet.has(item.value),
737
- );
738
- const items = [...selected, ...unselected];
739
- if (hasSelectAll) {
740
- return [{value: SELECT_ALL_VALUE, label: selectAllLabel}, ...items];
741
- }
742
- return items;
743
- }
744
- // For non-search mode, flatten options in the same order as renderOptions
745
745
  const result: MultiSelectorOptionData[] = [];
746
746
  let pendingFlat: MultiSelectorOptionData[] = [];
747
747
 
748
+ const orderSelectedFirst = (items: MultiSelectorOptionData[]) => {
749
+ const selected = items.filter(item => selectedSet.has(item.value));
750
+ const unselected = items.filter(item => !selectedSet.has(item.value));
751
+ return [...selected, ...unselected];
752
+ };
753
+
748
754
  const flushFlat = () => {
749
755
  if (pendingFlat.length === 0) {
750
756
  return;
751
757
  }
752
- const selected = pendingFlat.filter(item => selectedSet.has(item.value));
753
- const unselected = pendingFlat.filter(
754
- item => !selectedSet.has(item.value),
755
- );
756
- result.push(...selected, ...unselected);
758
+ result.push(...orderSelectedFirst(pendingFlat));
757
759
  pendingFlat = [];
758
760
  };
759
761
 
@@ -762,16 +764,15 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
762
764
  flushFlat();
763
765
  } else if (isSection(option)) {
764
766
  flushFlat();
765
- const sectionOptions = option.options.map(opt => normalizeOption(opt));
766
- const selected = sectionOptions.filter(item =>
767
- selectedSet.has(item.value),
768
- );
769
- const unselected = sectionOptions.filter(
770
- item => !selectedSet.has(item.value),
771
- );
772
- result.push(...selected, ...unselected);
767
+ const sectionOptions = option.options
768
+ .map(opt => normalizeOption(opt))
769
+ .filter(opt => optionMatchesQuery(opt, searchQuery));
770
+ result.push(...orderSelectedFirst(sectionOptions));
773
771
  } else if (isOptionData(option)) {
774
- pendingFlat.push(normalizeOption(option));
772
+ const normalized = normalizeOption(option);
773
+ if (optionMatchesQuery(normalized, searchQuery)) {
774
+ pendingFlat.push(normalized);
775
+ }
775
776
  }
776
777
  }
777
778
  flushFlat();
@@ -780,14 +781,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
780
781
  return [{value: SELECT_ALL_VALUE, label: selectAllLabel}, ...result];
781
782
  }
782
783
  return result;
783
- }, [
784
- filteredItems,
785
- searchQuery,
786
- options,
787
- selectedAtOpen,
788
- hasSelectAll,
789
- selectAllLabel,
790
- ]);
784
+ }, [searchQuery, options, selectedAtOpen, hasSelectAll, selectAllLabel]);
791
785
 
792
786
  // Layer for dropdown positioning
793
787
  const handleLayerHide = useCallback(() => {
@@ -1227,15 +1221,12 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1227
1221
  return elements;
1228
1222
  }
1229
1223
 
1230
- if (searchQuery) {
1231
- for (let i = cursor; i < sortedItems.length; i++) {
1232
- elements.push(renderItem(sortedItems[i], i));
1233
- }
1234
- return elements;
1235
- }
1236
-
1237
- // Non-search: consume items from sortedItems in order, interleaving
1238
- // structural elements (dividers, section headers) from the options prop.
1224
+ // Consume items from sortedItems in order, interleaving structural elements
1225
+ // (dividers, section headers) from the options prop. While searching, only
1226
+ // matching items are present in sortedItems, so a section consumes just its
1227
+ // matches and is skipped entirely when none match — no header left standing
1228
+ // over nothing, and the cursor stays aligned with the combobox indices.
1229
+ const isSearching = Boolean(searchQuery);
1239
1230
  let pendingCount = 0;
1240
1231
 
1241
1232
  const flushPending = () => {
@@ -1251,12 +1242,25 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1251
1242
 
1252
1243
  if (isDivider(option)) {
1253
1244
  flushPending();
1254
- elements.push(<Divider key={`divider-${i}`} xstyle={styles.divider} />);
1245
+ // A standalone divider between groups would orphan itself once its
1246
+ // neighbors are filtered out, so skip it while searching.
1247
+ if (!isSearching) {
1248
+ elements.push(
1249
+ <Divider key={`divider-${i}`} xstyle={styles.divider} />,
1250
+ );
1251
+ }
1255
1252
  } else if (isSection(option)) {
1256
1253
  flushPending();
1257
- const count = option.options.length;
1254
+ const matchCount = isSearching
1255
+ ? option.options.filter(opt =>
1256
+ optionMatchesQuery(normalizeOption(opt), searchQuery),
1257
+ ).length
1258
+ : option.options.length;
1259
+ if (matchCount === 0) {
1260
+ continue;
1261
+ }
1258
1262
  const sectionItems: ReactNode[] = [];
1259
- for (let j = 0; j < count; j++) {
1263
+ for (let j = 0; j < matchCount; j++) {
1260
1264
  sectionItems.push(renderItem(sortedItems[cursor], cursor));
1261
1265
  cursor++;
1262
1266
  }
@@ -1275,7 +1279,12 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1275
1279
  </div>,
1276
1280
  );
1277
1281
  } else if (isOptionData(option)) {
1278
- pendingCount++;
1282
+ if (
1283
+ !isSearching ||
1284
+ optionMatchesQuery(normalizeOption(option), searchQuery)
1285
+ ) {
1286
+ pendingCount++;
1287
+ }
1279
1288
  }
1280
1289
  }
1281
1290
  flushPending();
@@ -1304,7 +1313,7 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1304
1313
  isDisabled && inputWrapperStyles.disabled,
1305
1314
  optimisticValue.length === 0 && styles.triggerPlaceholder,
1306
1315
  status && inputStatusBorderStyles[status.type],
1307
- status && inputStatusHoverShadowStyles[status.type],
1316
+ status && !isDisabled && inputStatusHoverShadowStyles[status.type],
1308
1317
  inputGroup && groupStyles.inGroup,
1309
1318
  xstyle,
1310
1319
  ),
@@ -1368,7 +1377,17 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1368
1377
  onClick={handleClear}
1369
1378
  aria-label={t('@astryx.multiSelector.clearAll', {label})}
1370
1379
  {...stylex.props(styles.clearButton)}>
1371
- <Icon icon="close" size="sm" color="secondary" />
1380
+ <Icon
1381
+ icon="close"
1382
+ size="sm"
1383
+ color="secondary"
1384
+ // Stable theme target on the clear glyph itself, so a theme can
1385
+ // restyle just this icon (color, size, hover) via `defineTheme`.
1386
+ // Same-element rules in @layer astryx-theme win over the icon's
1387
+ // own base color/size, which a button-level target could not
1388
+ // reach.
1389
+ {...themeProps('multi-selector-clear-icon')}
1390
+ />
1372
1391
  </button>
1373
1392
  )}
1374
1393
  <span
@@ -1384,7 +1403,19 @@ export function MultiSelector<T extends MultiSelectorOptionType>({
1384
1403
  color={STATUS_ICON_COLOR_MAP[status.type]}
1385
1404
  />
1386
1405
  ) : (
1387
- <Icon icon="chevronDown" size="sm" color="inherit" />
1406
+ <Icon
1407
+ icon="chevronDown"
1408
+ size="sm"
1409
+ color="inherit"
1410
+ // Stable theme target on the chevron glyph itself, so a theme can
1411
+ // restyle just this icon (color, size, hover) — and its
1412
+ // open/closed state — via `defineTheme`. Same-element rules in
1413
+ // @layer astryx-theme win over the icon's own base color/size,
1414
+ // which a button-level target could not reach.
1415
+ {...themeProps('multi-selector-indicator-icon', {
1416
+ state: popover.isOpen ? 'expanded' : 'collapsed',
1417
+ })}
1418
+ />
1388
1419
  )}
1389
1420
  </span>
1390
1421
  </div>
@@ -96,9 +96,9 @@ export const docs = {
96
96
  },
97
97
  {
98
98
  name: 'statusVariant',
99
- type: "'attached' | 'detached'",
99
+ type: "'attached' | 'detached' | 'tooltip'",
100
100
  description:
101
- 'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing.',
101
+ 'How the status message is placed relative to the input. attached overlaps directly below the input (bordered treatment); detached floats below as a separate element with spacing; tooltip hides the message box and surfaces it in a tooltip on the status icon.',
102
102
  default: "'attached'",
103
103
  },
104
104
  {
@@ -145,6 +145,12 @@ export const docs = {
145
145
  type: 'string',
146
146
  description: 'HTML autocomplete attribute.',
147
147
  },
148
+ {
149
+ name: 'width',
150
+ type: 'SizeValue',
151
+ description:
152
+ '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.',
153
+ },
148
154
  {
149
155
  name: 'hasAutoFocus',
150
156
  type: 'boolean',
@@ -284,9 +290,9 @@ export const docsZh = {
284
290
  },
285
291
  {
286
292
  name: 'statusVariant',
287
- type: "'attached' | 'detached'",
293
+ type: "'attached' | 'detached' | 'tooltip'",
288
294
  description:
289
- '状态消息相对于输入框的放置方式。attached 直接叠加在输入框下方(带边框处理);detached 作为独立元素浮于下方并留有间距。',
295
+ '状态消息相对于输入框的放置方式。attached 直接叠加在输入框下方(带边框处理);detached 作为独立元素浮于下方并留有间距;tooltip 隐藏消息框,并在状态图标上以提示气泡形式显示。',
290
296
  default: "'attached'",
291
297
  },
292
298
  {
@@ -416,7 +422,7 @@ export const docsDense = {
416
422
  startIcon: 'Icon at input start.',
417
423
  labelIcon: 'Icon before label text.',
418
424
  status: 'Validation status w/ optional message.',
419
- statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing.',
425
+ statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing; tooltip hides the box and shows it on the status icon.',
420
426
  min: 'Minimum value allowed.',
421
427
  max: 'Maximum value allowed.',
422
428
  step: 'Step increment.',
@@ -13,6 +13,7 @@ import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
13
13
  import {render, screen, fireEvent, waitFor} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
15
  import {TestIcon} from '../__tests__/TestIcon';
16
+ import {InputGroup} from '../InputGroup';
16
17
  import {NumberInput} from './NumberInput';
17
18
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
18
19
 
@@ -336,6 +337,33 @@ describe('NumberInput', () => {
336
337
  expect(screen.queryByText('%')).not.toBeInTheDocument();
337
338
  expect(screen.queryByText('GB')).not.toBeInTheDocument();
338
339
  });
340
+
341
+ it('includes the units text in the accessible description (WCAG 1.3.1)', () => {
342
+ render(
343
+ <NumberInput
344
+ label="Storage"
345
+ value={50}
346
+ onChange={() => {}}
347
+ units="GB"
348
+ />,
349
+ );
350
+ expect(screen.getByRole('spinbutton')).toHaveAccessibleDescription(/GB/);
351
+ });
352
+
353
+ it('combines units with the description in the accessible description', () => {
354
+ render(
355
+ <NumberInput
356
+ label="Discount"
357
+ value={10}
358
+ onChange={() => {}}
359
+ description="Applied at checkout"
360
+ units="%"
361
+ />,
362
+ );
363
+ const input = screen.getByRole('spinbutton');
364
+ expect(input).toHaveAccessibleDescription(/Applied at checkout/);
365
+ expect(input).toHaveAccessibleDescription(/%/);
366
+ });
339
367
  });
340
368
 
341
369
  describe('event callbacks', () => {
@@ -463,6 +491,26 @@ describe('NumberInput', () => {
463
491
  expect(screen.getByText('Value must be positive')).toBeInTheDocument();
464
492
  });
465
493
 
494
+ it('has no dangling aria-describedby ids inside InputGroup (WCAG 1.3.1)', () => {
495
+ // Inside an InputGroup no Field renders, so the status message element
496
+ // does not exist; aria-describedby must not reference its id.
497
+ render(
498
+ <InputGroup label="Price">
499
+ <NumberInput
500
+ label="Amount"
501
+ value={null}
502
+ onChange={() => {}}
503
+ status={{type: 'error', message: 'Value must be positive'}}
504
+ />
505
+ </InputGroup>,
506
+ );
507
+ const input = screen.getByRole('spinbutton');
508
+ const describedBy = input.getAttribute('aria-describedby') ?? '';
509
+ for (const idToken of describedBy.split(/\s+/).filter(Boolean)) {
510
+ expect(document.getElementById(idToken)).not.toBeNull();
511
+ }
512
+ });
513
+
466
514
  it('does not render status message when not provided', () => {
467
515
  render(
468
516
  <NumberInput
@@ -27,7 +27,6 @@ import {
27
27
  type ReactNode,
28
28
  } from 'react';
29
29
  import * as stylex from '@stylexjs/stylex';
30
- import type {IconName} from '../Icon';
31
30
  import {
32
31
  colorVars,
33
32
  sizeVars,
@@ -39,7 +38,6 @@ import {
39
38
  import {
40
39
  Field,
41
40
  type InputStatus,
42
- type InputStatusType,
43
41
  inputWrapperStyles,
44
42
  inputStatusBorderStyles,
45
43
  inputStatusHoverShadowStyles,
@@ -52,6 +50,7 @@ import {useTooltip} from '../Tooltip';
52
50
  import {getInputARIA} from '../utils';
53
51
  import {useSize} from '../SizeContext/SizeContext';
54
52
  import {useInputContainer} from '../hooks/useInputContainer';
53
+ import {useInputStatusIcon} from '../hooks/useInputStatusIcon';
55
54
  import {useInputGroup} from '../InputGroup/InputGroupContext';
56
55
 
57
56
  const styles = stylex.create({
@@ -212,6 +211,7 @@ interface NumberInputPropsBase extends Omit<
212
211
  * How the status message is placed relative to the input.
213
212
  * - 'attached': message overlaps directly below the input (bordered treatment)
214
213
  * - 'detached': message floats below as a separate element with spacing
214
+ * - 'tooltip': no message box; the status icon becomes a focusable info-tip button that reveals the message on hover, keyboard focus, or tap
215
215
  * @default 'attached'
216
216
  */
217
217
  statusVariant?: FieldStatusVariant;
@@ -414,6 +414,7 @@ export function NumberInput({
414
414
  const inputLabelID = useId();
415
415
  const descriptionID = useId();
416
416
  const statusMessageID = useId();
417
+ const unitsID = useId();
417
418
  const inputRef = useRef<HTMLInputElement | null>(null);
418
419
  const containerRef = useRef<HTMLDivElement | null>(null);
419
420
  const inputGroup = useInputGroup();
@@ -435,26 +436,26 @@ export function NumberInput({
435
436
  isEnabled: showsDisabledMessage,
436
437
  });
437
438
 
438
- const statusIconMap: Record<InputStatusType, IconName> = {
439
- warning: 'warning',
440
- error: 'error',
441
- success: 'success',
442
- };
443
-
444
- const statusIconColorMap: Record<
445
- InputStatusType,
446
- 'warning' | 'error' | 'success'
447
- > = {
448
- warning: 'warning',
449
- error: 'error',
450
- success: 'success',
451
- };
439
+ const {statusIcon, describedBy: statusTooltipDescribedBy} =
440
+ useInputStatusIcon({
441
+ status,
442
+ statusVariant,
443
+ isInGroup: !!inputGroup,
444
+ });
452
445
 
453
446
  const {ariaLabelledBy, ariaDescribedBy} = getInputARIA(
454
447
  inputLabelID,
455
448
  [
456
449
  description ? descriptionID : null,
457
- status?.message ? statusMessageID : null,
450
+ // The status message element is rendered by Field, which is skipped
451
+ // inside an InputGroup — only reference it when it actually exists.
452
+ !inputGroup && statusVariant !== 'tooltip' && status?.message
453
+ ? statusMessageID
454
+ : null,
455
+ // The tooltip variant renders no message box; describe the input by the
456
+ // tooltip's content instead so the status is still announced.
457
+ statusTooltipDescribedBy,
458
+ units ? unitsID : null,
458
459
  showsDisabledMessage ? disabledMessageTooltip.describedBy : null,
459
460
  ],
460
461
  inputGroup,
@@ -614,7 +615,7 @@ export function NumberInput({
614
615
  sizeStyles[size],
615
616
  isDisabled && inputWrapperStyles.disabled,
616
617
  status && inputStatusBorderStyles[status.type],
617
- status && inputStatusHoverShadowStyles[status.type],
618
+ status && !isDisabled && inputStatusHoverShadowStyles[status.type],
618
619
  status && inputStatusFocusWithinStyles[status.type],
619
620
  inputGroup && groupStyles.inGroup,
620
621
  xstyle,
@@ -660,7 +661,11 @@ export function NumberInput({
660
661
  !isInputValid && styles.inputInvalid,
661
662
  )}
662
663
  />
663
- {units && <span {...stylex.props(styles.units)}>{units}</span>}
664
+ {units && (
665
+ <span id={unitsID} {...stylex.props(styles.units)}>
666
+ {units}
667
+ </span>
668
+ )}
664
669
  {/*
665
670
  Live region announcing invalid typed input to assistive technology.
666
671
  The value silently reverts on blur, so without this a screen-reader
@@ -678,13 +683,7 @@ export function NumberInput({
678
683
  <Icon icon="close" size="sm" color="secondary" />
679
684
  </button>
680
685
  )}
681
- {status && !inputGroup && (
682
- <Icon
683
- icon={statusIconMap[status.type]}
684
- size="md"
685
- color={statusIconColorMap[status.type]}
686
- />
687
- )}
686
+ {statusIcon}
688
687
  </div>
689
688
  );
690
689
 
@@ -86,7 +86,7 @@ describe('Outline', () => {
86
86
  render(<Outline items={items} activeId="install" />);
87
87
  expect(screen.getByRole('link', {name: 'Installation'})).toHaveAttribute(
88
88
  'aria-current',
89
- 'true',
89
+ 'location',
90
90
  );
91
91
  expect(
92
92
  screen.getByRole('link', {name: 'Introduction'}),
@@ -111,7 +111,7 @@ describe('Outline', () => {
111
111
  // so it has not moved to the clicked item yet.
112
112
  expect(
113
113
  screen.getByRole('link', {name: 'Installation'}),
114
- ).not.toHaveAttribute('aria-current', 'true');
114
+ ).not.toHaveAttribute('aria-current', 'location');
115
115
 
116
116
  // When the scroll settles, the indicator lands on the clicked item.
117
117
  act(() => {
@@ -120,7 +120,7 @@ describe('Outline', () => {
120
120
  expect(onActiveIdChange).toHaveBeenCalledWith('install');
121
121
  expect(screen.getByRole('link', {name: 'Installation'})).toHaveAttribute(
122
122
  'aria-current',
123
- 'true',
123
+ 'location',
124
124
  );
125
125
 
126
126
  document.body.removeChild(target);
@@ -224,7 +224,7 @@ describe('Outline', () => {
224
224
 
225
225
  expect(screen.getByRole('link', {name: 'Introduction'})).toHaveAttribute(
226
226
  'aria-current',
227
- 'true',
227
+ 'location',
228
228
  );
229
229
 
230
230
  // Controlled active id is driven entirely by the prop.
@@ -237,7 +237,7 @@ describe('Outline', () => {
237
237
  );
238
238
  expect(screen.getByRole('link', {name: 'API'})).toHaveAttribute(
239
239
  'aria-current',
240
- 'true',
240
+ 'location',
241
241
  );
242
242
  expect(
243
243
  screen.getByRole('link', {name: 'Introduction'}),
@@ -277,7 +277,7 @@ describe('Outline', () => {
277
277
 
278
278
  expect(screen.getByRole('link', {name: 'Installation'})).toHaveAttribute(
279
279
  'aria-current',
280
- 'true',
280
+ 'location',
281
281
  );
282
282
  expect(onActiveIdChange).toHaveBeenCalledWith('install');
283
283
 
@@ -493,7 +493,7 @@ describe('Outline keyboard navigation', () => {
493
493
  expect(onNavigateEnd).toHaveBeenCalledTimes(1);
494
494
  expect(screen.getByRole('link', {name: 'Installation'})).toHaveAttribute(
495
495
  'aria-current',
496
- 'true',
496
+ 'location',
497
497
  );
498
498
 
499
499
  cleanup();
@@ -764,7 +764,7 @@ describe('Outline scroll scoping', () => {
764
764
  expect(onNavigateEnd).toHaveBeenCalledWith('install');
765
765
  expect(screen.getByRole('link', {name: 'Installation'})).toHaveAttribute(
766
766
  'aria-current',
767
- 'true',
767
+ 'location',
768
768
  );
769
769
 
770
770
  cleanup();
@@ -797,7 +797,7 @@ describe('Outline scroll scoping', () => {
797
797
  // has not reached it, so `intro` stays active.
798
798
  expect(screen.getByRole('link', {name: 'Introduction'})).toHaveAttribute(
799
799
  'aria-current',
800
- 'true',
800
+ 'location',
801
801
  );
802
802
 
803
803
  rerender(<Outline items={items} offset={64} />);
@@ -806,7 +806,7 @@ describe('Outline scroll scoping', () => {
806
806
  });
807
807
  expect(screen.getByRole('link', {name: 'Installation'})).toHaveAttribute(
808
808
  'aria-current',
809
- 'true',
809
+ 'location',
810
810
  );
811
811
 
812
812
  cleanup();
@@ -930,7 +930,7 @@ describe('Outline scroll scoping', () => {
930
930
 
931
931
  expect(screen.getByRole('link', {name: 'Installation'})).toHaveAttribute(
932
932
  'aria-current',
933
- 'true',
933
+ 'location',
934
934
  );
935
935
  expect(screen.getByRole('link', {name: 'API'})).not.toHaveAttribute(
936
936
  'aria-current',
@@ -981,7 +981,7 @@ describe('Outline scroll scoping', () => {
981
981
 
982
982
  expect(screen.getByRole('link', {name: 'Installation'})).toHaveAttribute(
983
983
  'aria-current',
984
- 'true',
984
+ 'location',
985
985
  );
986
986
 
987
987
  pane.remove();
@@ -372,7 +372,7 @@ export function Outline({
372
372
  }
373
373
  const links = Array.from(list.querySelectorAll<HTMLElement>('a[href]'));
374
374
  const active = links.find(
375
- link => link.getAttribute('aria-current') === 'true',
375
+ link => link.getAttribute('aria-current') === 'location',
376
376
  );
377
377
  if (active == null) {
378
378
  return;
@@ -465,7 +465,7 @@ export function Outline({
465
465
  <li key={item.id} {...stylex.props(styles.item)} role="listitem">
466
466
  <LinkComponent
467
467
  href={`#${item.id}`}
468
- aria-current={isActive ? 'true' : undefined}
468
+ aria-current={isActive ? 'location' : undefined}
469
469
  onClick={handleClick(item.id)}
470
470
  onKeyDown={handleKeyDown(item.id)}
471
471
  {...mergeProps(
@@ -114,6 +114,12 @@ export const docs = {
114
114
  type: 'string',
115
115
  description: 'Tooltip text for an info icon next to the label.',
116
116
  },
117
+ {
118
+ name: 'width',
119
+ type: 'SizeValue',
120
+ description:
121
+ '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.',
122
+ },
117
123
  {
118
124
  name: 'xstyle',
119
125
  type: 'StyleXStyles',
@@ -146,8 +146,8 @@ export interface RadioListProps extends Omit<
146
146
  status?: InputStatus;
147
147
  /**
148
148
  * The size of the radio controls.
149
- * - 'sm': Compact size (18px radio, 20px wrapper)
150
- * - 'md': Default size (22px radio, 24px wrapper)
149
+ * - 'sm': Compact size (20px radio)
150
+ * - 'md': Default size (24px radio)
151
151
  * @default 'md'
152
152
  */
153
153
  size?: RadioListSize;
@@ -140,12 +140,12 @@ const wrapperSizeStyles = stylex.create({
140
140
 
141
141
  const radioSizeStyles = stylex.create({
142
142
  sm: {
143
- width: 18,
144
- height: 18,
143
+ width: 20,
144
+ height: 20,
145
145
  },
146
146
  md: {
147
- width: 22,
148
- height: 22,
147
+ width: 24,
148
+ height: 24,
149
149
  },
150
150
  });
151
151