@astryxdesign/core 0.1.9 → 0.2.0-canary.136a00f

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 (560) 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/Chat/ChatComposerInput.js +1 -1
  33. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  34. package/dist/Chat/ChatDictationButton.js +3 -1
  35. package/dist/Chat/ChatLayout.js +4 -4
  36. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  37. package/dist/Chat/ChatMessageBubble.js +8 -8
  38. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  39. package/dist/Chat/ChatToolCalls.js +10 -3
  40. package/dist/Chat/useTriggerMenu.js +2 -2
  41. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  42. package/dist/CheckboxInput/CheckboxInput.js +6 -6
  43. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  44. package/dist/CheckboxList/CheckboxListItem.js +19 -4
  45. package/dist/Citation/Citation.d.ts +22 -1
  46. package/dist/Citation/Citation.d.ts.map +1 -1
  47. package/dist/Citation/Citation.js +20 -6
  48. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  49. package/dist/CodeBlock/CodeBlock.js +16 -10
  50. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  51. package/dist/Collapsible/Collapsible.js +3 -1
  52. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  53. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  54. package/dist/CommandPalette/CommandPalette.js +42 -3
  55. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  56. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  57. package/dist/ContextMenu/ContextMenu.js +23 -5
  58. package/dist/ContextMenu/index.d.ts +1 -0
  59. package/dist/ContextMenu/index.d.ts.map +1 -1
  60. package/dist/ContextMenu/index.js +3 -1
  61. package/dist/DateInput/DateInput.d.ts +10 -2
  62. package/dist/DateInput/DateInput.d.ts.map +1 -1
  63. package/dist/DateInput/DateInput.js +33 -19
  64. package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
  65. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  66. package/dist/DateRangeInput/DateRangeInput.js +23 -20
  67. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  68. package/dist/DateTimeInput/DateTimeInput.js +23 -18
  69. package/dist/Divider/Divider.d.ts +2 -2
  70. package/dist/Divider/Divider.d.ts.map +1 -1
  71. package/dist/Divider/Divider.js +13 -0
  72. package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
  73. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  74. package/dist/DropdownMenu/DropdownMenu.js +22 -5
  75. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  76. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
  77. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
  79. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
  80. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  81. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
  82. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  83. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuRadioItem.js +5 -2
  85. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
  86. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
  87. package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
  88. package/dist/DropdownMenu/index.d.ts +10 -0
  89. package/dist/DropdownMenu/index.d.ts.map +1 -1
  90. package/dist/DropdownMenu/index.js +13 -0
  91. package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
  92. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
  93. package/dist/DropdownMenu/menuItemHover.js +33 -0
  94. package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
  95. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
  96. package/dist/DropdownMenu/menuItemRoles.js +10 -1
  97. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  98. package/dist/DropdownMenu/renderDropdownItems.js +21 -6
  99. package/dist/Field/Field.d.ts +3 -1
  100. package/dist/Field/Field.d.ts.map +1 -1
  101. package/dist/Field/Field.js +4 -1
  102. package/dist/Field/FieldLabel.d.ts +2 -1
  103. package/dist/Field/FieldLabel.d.ts.map +1 -1
  104. package/dist/Field/FieldLabel.js +9 -5
  105. package/dist/Field/inputStyles.stylex.d.ts +1 -0
  106. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  107. package/dist/Field/inputStyles.stylex.js +1 -0
  108. package/dist/FieldStatus/FieldStatus.d.ts +10 -0
  109. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  110. package/dist/FieldStatus/FieldStatus.js +39 -3
  111. package/dist/FileInput/FileInput.d.ts +10 -2
  112. package/dist/FileInput/FileInput.d.ts.map +1 -1
  113. package/dist/FileInput/FileInput.js +93 -65
  114. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  115. package/dist/HoverCard/useHoverCard.js +10 -4
  116. package/dist/Icon/Icon.d.ts +15 -1
  117. package/dist/Icon/Icon.d.ts.map +1 -1
  118. package/dist/Icon/Icon.js +19 -3
  119. package/dist/Item/Item.d.ts +16 -3
  120. package/dist/Item/Item.d.ts.map +1 -1
  121. package/dist/Item/Item.js +31 -6
  122. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  123. package/dist/Layer/layerAnimations.stylex.js +10 -2
  124. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  125. package/dist/Lightbox/Lightbox.js +19 -13
  126. package/dist/List/List.d.ts.map +1 -1
  127. package/dist/List/List.js +6 -3
  128. package/dist/List/ListItem.d.ts +11 -1
  129. package/dist/List/ListItem.d.ts.map +1 -1
  130. package/dist/List/ListItem.js +2 -0
  131. package/dist/Markdown/Markdown.d.ts.map +1 -1
  132. package/dist/Markdown/Markdown.js +7 -0
  133. package/dist/MetadataList/MetadataList.d.ts +1 -1
  134. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  135. package/dist/MetadataList/MetadataList.js +4 -2
  136. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  137. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  138. package/dist/MultiSelector/MultiSelector.js +80 -42
  139. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  140. package/dist/NumberInput/NumberInput.d.ts +10 -2
  141. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  142. package/dist/NumberInput/NumberInput.js +22 -17
  143. package/dist/Outline/Outline.js +2 -2
  144. package/dist/Pagination/Pagination.d.ts.map +1 -1
  145. package/dist/Pagination/Pagination.js +11 -3
  146. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  147. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  148. package/dist/PowerSearch/PowerSearch.js +2 -0
  149. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  150. package/dist/ProgressBar/ProgressBar.js +6 -1
  151. package/dist/RadioList/RadioList.d.ts +2 -2
  152. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  153. package/dist/RadioList/RadioListItem.js +5 -5
  154. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  155. package/dist/Resizable/ResizeHandle.js +49 -19
  156. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  157. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  158. package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
  159. package/dist/Selector/Selector.d.ts +8 -0
  160. package/dist/Selector/Selector.d.ts.map +1 -1
  161. package/dist/Selector/Selector.js +66 -17
  162. package/dist/SideNav/SideNav.d.ts.map +1 -1
  163. package/dist/SideNav/SideNav.js +5 -5
  164. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  165. package/dist/SideNav/SideNavCollapseButton.js +13 -10
  166. package/dist/SideNav/SideNavItem.d.ts +1 -1
  167. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  168. package/dist/SideNav/SideNavItem.js +12 -10
  169. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  170. package/dist/Skeleton/Skeleton.js +2 -2
  171. package/dist/Slider/Slider.d.ts.map +1 -1
  172. package/dist/Slider/Slider.js +87 -34
  173. package/dist/Spinner/Spinner.d.ts +3 -2
  174. package/dist/Spinner/Spinner.d.ts.map +1 -1
  175. package/dist/Spinner/Spinner.js +11 -2
  176. package/dist/Switch/Switch.d.ts +8 -1
  177. package/dist/Switch/Switch.d.ts.map +1 -1
  178. package/dist/Switch/Switch.js +171 -91
  179. package/dist/TabList/Tab.js +2 -2
  180. package/dist/TabList/TabList.d.ts +2 -11
  181. package/dist/TabList/TabList.d.ts.map +1 -1
  182. package/dist/TabList/TabList.js +5 -9
  183. package/dist/TabList/TabListContext.d.ts +0 -5
  184. package/dist/TabList/TabListContext.d.ts.map +1 -1
  185. package/dist/TabList/TabListContext.js +0 -5
  186. package/dist/TabList/TabMenu.js +1 -1
  187. package/dist/Table/BaseTable.d.ts.map +1 -1
  188. package/dist/Table/BaseTable.js +30 -4
  189. package/dist/Table/TableCell.js +3 -3
  190. package/dist/Table/TableHeaderCell.js +3 -3
  191. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  192. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
  193. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  194. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +37 -27
  195. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  196. package/dist/Table/plugins/selection/useTableSelection.js +3 -0
  197. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  198. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
  199. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  200. package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
  201. package/dist/Table/types.d.ts +32 -0
  202. package/dist/Table/types.d.ts.map +1 -1
  203. package/dist/TextArea/TextArea.d.ts +10 -1
  204. package/dist/TextArea/TextArea.d.ts.map +1 -1
  205. package/dist/TextArea/TextArea.js +18 -19
  206. package/dist/TextInput/TextInput.d.ts +10 -2
  207. package/dist/TextInput/TextInput.d.ts.map +1 -1
  208. package/dist/TextInput/TextInput.js +20 -17
  209. package/dist/Thumbnail/Thumbnail.js +2 -2
  210. package/dist/TimeInput/TimeInput.d.ts +10 -2
  211. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  212. package/dist/TimeInput/TimeInput.js +17 -17
  213. package/dist/Timestamp/Timestamp.d.ts +31 -3
  214. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  215. package/dist/Timestamp/Timestamp.js +47 -76
  216. package/dist/Timestamp/formatInstant.d.ts +41 -0
  217. package/dist/Timestamp/formatInstant.d.ts.map +1 -0
  218. package/dist/Timestamp/formatInstant.js +177 -0
  219. package/dist/Timestamp/index.d.ts +1 -0
  220. package/dist/Timestamp/index.d.ts.map +1 -1
  221. package/dist/Timestamp/tooltipEntries.d.ts +56 -0
  222. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
  223. package/dist/Timestamp/tooltipEntries.js +163 -0
  224. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  225. package/dist/Toast/ToastViewport.js +61 -9
  226. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  227. package/dist/ToggleButton/ToggleButton.js +3 -1
  228. package/dist/Token/Token.d.ts +34 -4
  229. package/dist/Token/Token.d.ts.map +1 -1
  230. package/dist/Token/Token.js +85 -45
  231. package/dist/Token/TokenLink.d.ts +62 -0
  232. package/dist/Token/TokenLink.d.ts.map +1 -0
  233. package/dist/Token/TokenLink.js +76 -0
  234. package/dist/Token/index.d.ts +1 -1
  235. package/dist/Token/index.d.ts.map +1 -1
  236. package/dist/Tokenizer/Tokenizer.d.ts +9 -2
  237. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  238. package/dist/Tokenizer/Tokenizer.js +4 -2
  239. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  240. package/dist/Tooltip/useTooltip.js +17 -1
  241. package/dist/TopNav/TopNavItem.d.ts +3 -1
  242. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  243. package/dist/TopNav/TopNavItem.js +30 -3
  244. package/dist/TreeList/TreeList.d.ts.map +1 -1
  245. package/dist/TreeList/TreeList.js +1 -0
  246. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  247. package/dist/TreeList/TreeListBranches.js +8 -6
  248. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  249. package/dist/TreeList/TreeListItem.js +32 -14
  250. package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
  251. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  252. package/dist/Typeahead/BaseTypeahead.js +22 -11
  253. package/dist/Typeahead/Typeahead.d.ts +9 -2
  254. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  255. package/dist/Typeahead/Typeahead.js +11 -2
  256. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  257. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  258. package/dist/Typeahead/TypeaheadItem.js +20 -10
  259. package/dist/astryx.css +70 -30
  260. package/dist/astryx.umd.js +51 -51
  261. package/dist/astryx.umd.js.map +4 -4
  262. package/dist/hooks/index.d.ts +2 -0
  263. package/dist/hooks/index.d.ts.map +1 -1
  264. package/dist/hooks/index.js +1 -0
  265. package/dist/hooks/isRtlElement.d.ts +18 -0
  266. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  267. package/dist/hooks/isRtlElement.js +27 -0
  268. package/dist/hooks/useAnnounce.d.ts +3 -0
  269. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  270. package/dist/hooks/useAnnounce.js +39 -1
  271. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  272. package/dist/hooks/useFocusTrap.js +52 -11
  273. package/dist/hooks/useGridFocus.d.ts +6 -1
  274. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  275. package/dist/hooks/useGridFocus.js +12 -9
  276. package/dist/hooks/useHotkeys.d.ts +9 -0
  277. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  278. package/dist/hooks/useHotkeys.js +9 -0
  279. package/dist/hooks/useInputStatusIcon.d.ts +38 -0
  280. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
  281. package/dist/hooks/useInputStatusIcon.js +158 -0
  282. package/dist/hooks/useKeyboardHint.d.ts +1 -1
  283. package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
  284. package/dist/hooks/useKeyboardHint.js +4 -2
  285. package/dist/hooks/useListFocus.d.ts +39 -1
  286. package/dist/hooks/useListFocus.d.ts.map +1 -1
  287. package/dist/hooks/useListFocus.js +54 -9
  288. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  289. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  290. package/dist/i18n/InternationalizationContext.js +3 -0
  291. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  292. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  293. package/dist/i18n/InternationalizationProvider.js +5 -1
  294. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  295. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  296. package/dist/i18n/getLocaleDirection.js +29 -0
  297. package/dist/i18n/index.d.ts +6 -0
  298. package/dist/i18n/index.d.ts.map +1 -1
  299. package/dist/i18n/index.js +7 -1
  300. package/dist/i18n/useDirection.d.ts +2 -0
  301. package/dist/i18n/useDirection.d.ts.map +1 -0
  302. package/dist/i18n/useDirection.js +27 -0
  303. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  304. package/dist/theme/derivedVarRegistry.js +13 -0
  305. package/dist/utils/index.d.ts +1 -0
  306. package/dist/utils/index.d.ts.map +1 -1
  307. package/dist/utils/index.js +2 -1
  308. package/dist/utils/plainDate.d.ts +17 -0
  309. package/dist/utils/plainDate.d.ts.map +1 -1
  310. package/dist/utils/plainDate.js +23 -4
  311. package/dist/utils/rtlStyles.d.ts +24 -0
  312. package/dist/utils/rtlStyles.d.ts.map +1 -0
  313. package/dist/utils/rtlStyles.js +27 -0
  314. package/locales/en.json +112 -0
  315. package/locales/pseudo.json +84 -0
  316. package/package.json +6 -1
  317. package/src/Avatar/Avatar.doc.mjs +50 -3
  318. package/src/Avatar/Avatar.test.tsx +218 -0
  319. package/src/Avatar/Avatar.tsx +285 -79
  320. package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
  321. package/src/Avatar/AvatarStatusDot.tsx +6 -4
  322. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  323. package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
  324. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  325. package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
  326. package/src/Banner/Banner.tsx +6 -6
  327. package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
  328. package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
  329. package/src/Breadcrumbs/index.ts +4 -0
  330. package/src/Button/Button.doc.mjs +0 -4
  331. package/src/Button/Button.test.tsx +16 -0
  332. package/src/Button/Button.tsx +6 -4
  333. package/src/Calendar/Calendar.test.tsx +170 -20
  334. package/src/Calendar/Calendar.tsx +73 -16
  335. package/src/Calendar/dayCellUtils.test.ts +18 -18
  336. package/src/Calendar/dayCellUtils.ts +2 -2
  337. package/src/Calendar/styles.ts +33 -39
  338. package/src/Card/Card.tsx +1 -1
  339. package/src/Carousel/Carousel.tsx +25 -6
  340. package/src/Chat/ChatComposer.doc.mjs +2 -2
  341. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  342. package/src/Chat/ChatComposerInput.tsx +2 -2
  343. package/src/Chat/ChatDictationButton.tsx +7 -1
  344. package/src/Chat/ChatLayout.tsx +4 -4
  345. package/src/Chat/ChatMessageBubble.tsx +15 -10
  346. package/src/Chat/ChatSystemMessage.test.tsx +5 -0
  347. package/src/Chat/ChatToolCalls.tsx +9 -2
  348. package/src/Chat/useTriggerMenu.tsx +1 -1
  349. package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
  350. package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
  351. package/src/CheckboxInput/CheckboxInput.tsx +21 -6
  352. package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
  353. package/src/CheckboxList/CheckboxList.test.tsx +94 -3
  354. package/src/CheckboxList/CheckboxListItem.tsx +17 -10
  355. package/src/Citation/Citation.doc.mjs +4 -3
  356. package/src/Citation/Citation.test.tsx +97 -0
  357. package/src/Citation/Citation.tsx +43 -11
  358. package/src/CodeBlock/CodeBlock.test.tsx +17 -0
  359. package/src/CodeBlock/CodeBlock.tsx +38 -11
  360. package/src/Collapsible/Collapsible.doc.mjs +1 -0
  361. package/src/Collapsible/Collapsible.test.tsx +7 -0
  362. package/src/Collapsible/Collapsible.tsx +16 -6
  363. package/src/CommandPalette/CommandPalette.test.tsx +95 -1
  364. package/src/CommandPalette/CommandPalette.tsx +41 -2
  365. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  366. package/src/ContextMenu/ContextMenu.test.tsx +59 -2
  367. package/src/ContextMenu/ContextMenu.tsx +22 -11
  368. package/src/ContextMenu/index.ts +5 -0
  369. package/src/DateInput/DateInput.doc.mjs +25 -0
  370. package/src/DateInput/DateInput.test.tsx +230 -0
  371. package/src/DateInput/DateInput.tsx +51 -29
  372. package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
  373. package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
  374. package/src/DateRangeInput/DateRangeInput.tsx +42 -30
  375. package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
  376. package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
  377. package/src/DateTimeInput/DateTimeInput.tsx +44 -39
  378. package/src/Divider/Divider.test.tsx +32 -8
  379. package/src/Divider/Divider.tsx +14 -1
  380. package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
  381. package/src/DropdownMenu/DropdownMenu.tsx +31 -12
  382. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
  383. package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
  384. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
  385. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
  386. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +9 -3
  387. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +20 -2
  388. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
  389. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
  390. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
  391. package/src/DropdownMenu/index.ts +16 -0
  392. package/src/DropdownMenu/menuItemHover.ts +39 -0
  393. package/src/DropdownMenu/menuItemRoles.ts +9 -0
  394. package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
  395. package/src/Field/Field.tsx +14 -9
  396. package/src/Field/FieldLabel.test.tsx +25 -0
  397. package/src/Field/FieldLabel.tsx +12 -3
  398. package/src/Field/inputStyles.stylex.ts +2 -0
  399. package/src/FieldStatus/FieldStatus.test.tsx +72 -0
  400. package/src/FieldStatus/FieldStatus.tsx +48 -2
  401. package/src/FileInput/FileInput.doc.mjs +23 -2
  402. package/src/FileInput/FileInput.test.tsx +104 -13
  403. package/src/FileInput/FileInput.tsx +106 -79
  404. package/src/HoverCard/useHoverCard.tsx +15 -3
  405. package/src/Icon/Icon.doc.mjs +13 -0
  406. package/src/Icon/Icon.test.tsx +89 -0
  407. package/src/Icon/Icon.tsx +51 -3
  408. package/src/Item/Item.doc.mjs +5 -0
  409. package/src/Item/Item.test.tsx +88 -0
  410. package/src/Item/Item.tsx +57 -11
  411. package/src/Layer/layerAnimations.stylex.ts +23 -0
  412. package/src/Lightbox/Lightbox.tsx +15 -7
  413. package/src/List/List.test.tsx +17 -29
  414. package/src/List/List.tsx +6 -1
  415. package/src/List/ListItem.doc.mjs +12 -0
  416. package/src/List/ListItem.tsx +13 -0
  417. package/src/Markdown/Markdown.test.tsx +21 -0
  418. package/src/Markdown/Markdown.tsx +4 -0
  419. package/src/MetadataList/MetadataList.test.tsx +24 -0
  420. package/src/MetadataList/MetadataList.tsx +6 -2
  421. package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
  422. package/src/MultiSelector/MultiSelector.test.tsx +402 -0
  423. package/src/MultiSelector/MultiSelector.tsx +120 -59
  424. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  425. package/src/NumberInput/NumberInput.doc.mjs +21 -0
  426. package/src/NumberInput/NumberInput.test.tsx +71 -0
  427. package/src/NumberInput/NumberInput.tsx +35 -26
  428. package/src/Outline/Outline.test.tsx +12 -12
  429. package/src/Outline/Outline.tsx +2 -2
  430. package/src/Pagination/Pagination.tsx +11 -3
  431. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  432. package/src/PowerSearch/PowerSearch.test.tsx +23 -0
  433. package/src/PowerSearch/PowerSearch.tsx +10 -1
  434. package/src/ProgressBar/ProgressBar.test.tsx +34 -0
  435. package/src/ProgressBar/ProgressBar.tsx +16 -1
  436. package/src/RadioList/RadioList.doc.mjs +6 -0
  437. package/src/RadioList/RadioList.test.tsx +26 -4
  438. package/src/RadioList/RadioList.tsx +2 -2
  439. package/src/RadioList/RadioListItem.tsx +12 -5
  440. package/src/Resizable/ResizeHandle.test.tsx +94 -0
  441. package/src/Resizable/ResizeHandle.tsx +70 -20
  442. package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
  443. package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
  444. package/src/Selector/Selector.doc.mjs +15 -0
  445. package/src/Selector/Selector.test.tsx +370 -0
  446. package/src/Selector/Selector.tsx +88 -20
  447. package/src/SideNav/SideNav.tsx +1 -8
  448. package/src/SideNav/SideNavCollapseButton.tsx +9 -7
  449. package/src/SideNav/SideNavItem.tsx +5 -3
  450. package/src/Skeleton/Skeleton.test.tsx +16 -0
  451. package/src/Skeleton/Skeleton.tsx +13 -1
  452. package/src/Slider/Slider.doc.mjs +6 -0
  453. package/src/Slider/Slider.test.tsx +240 -12
  454. package/src/Slider/Slider.tsx +96 -23
  455. package/src/Spinner/Spinner.test.tsx +10 -8
  456. package/src/Spinner/Spinner.tsx +15 -5
  457. package/src/Switch/Switch.doc.mjs +142 -42
  458. package/src/Switch/Switch.test.tsx +111 -0
  459. package/src/Switch/Switch.tsx +149 -32
  460. package/src/TabList/Tab.tsx +2 -2
  461. package/src/TabList/TabList.doc.mjs +0 -6
  462. package/src/TabList/TabList.test.tsx +3 -15
  463. package/src/TabList/TabList.tsx +6 -17
  464. package/src/TabList/TabListContext.ts +0 -6
  465. package/src/TabList/TabMenu.tsx +2 -2
  466. package/src/Table/BaseTable.tsx +34 -2
  467. package/src/Table/Table.doc.mjs +11 -0
  468. package/src/Table/Table.test.tsx +85 -0
  469. package/src/Table/TableCell.tsx +3 -3
  470. package/src/Table/TableHeaderCell.tsx +3 -3
  471. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
  472. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
  473. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +27 -18
  474. package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
  475. package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
  476. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
  477. package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
  478. package/src/Table/types.ts +33 -0
  479. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  480. package/src/TextArea/TextArea.doc.mjs +21 -0
  481. package/src/TextArea/TextArea.test.tsx +23 -0
  482. package/src/TextArea/TextArea.tsx +27 -26
  483. package/src/TextInput/TextInput.doc.mjs +21 -0
  484. package/src/TextInput/TextInput.test.tsx +150 -0
  485. package/src/TextInput/TextInput.tsx +28 -25
  486. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  487. package/src/Thumbnail/Thumbnail.tsx +1 -1
  488. package/src/TimeInput/TimeInput.doc.mjs +21 -0
  489. package/src/TimeInput/TimeInput.test.tsx +23 -0
  490. package/src/TimeInput/TimeInput.tsx +24 -25
  491. package/src/Timestamp/Timestamp.doc.mjs +32 -6
  492. package/src/Timestamp/Timestamp.test.tsx +371 -0
  493. package/src/Timestamp/Timestamp.tsx +96 -93
  494. package/src/Timestamp/formatInstant.ts +218 -0
  495. package/src/Timestamp/index.ts +4 -0
  496. package/src/Timestamp/tooltipEntries.test.ts +552 -0
  497. package/src/Timestamp/tooltipEntries.ts +210 -0
  498. package/src/Toast/ToastViewport.test.tsx +218 -8
  499. package/src/Toast/ToastViewport.tsx +71 -12
  500. package/src/ToggleButton/ToggleButton.test.tsx +24 -0
  501. package/src/ToggleButton/ToggleButton.tsx +19 -1
  502. package/src/Token/Token.test.tsx +166 -15
  503. package/src/Token/Token.tsx +104 -47
  504. package/src/Token/TokenLink.tsx +107 -0
  505. package/src/Token/index.ts +1 -1
  506. package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
  507. package/src/Tokenizer/Tokenizer.test.tsx +23 -0
  508. package/src/Tokenizer/Tokenizer.tsx +14 -2
  509. package/src/Tooltip/Tooltip.test.tsx +46 -0
  510. package/src/Tooltip/useTooltip.tsx +20 -0
  511. package/src/TopNav/TopNav.test.tsx +93 -2
  512. package/src/TopNav/TopNavItem.doc.mjs +3 -3
  513. package/src/TopNav/TopNavItem.tsx +35 -6
  514. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
  515. package/src/TreeList/TreeList.doc.mjs +6 -0
  516. package/src/TreeList/TreeList.test.tsx +50 -10
  517. package/src/TreeList/TreeList.tsx +5 -0
  518. package/src/TreeList/TreeListBranches.tsx +8 -6
  519. package/src/TreeList/TreeListItem.tsx +33 -11
  520. package/src/Typeahead/BaseTypeahead.tsx +42 -15
  521. package/src/Typeahead/Typeahead.doc.mjs +13 -0
  522. package/src/Typeahead/Typeahead.test.tsx +112 -0
  523. package/src/Typeahead/Typeahead.tsx +17 -1
  524. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  525. package/src/__tests__/forcedColors.ts +60 -0
  526. package/src/__tests__/inputWidthContract.test.tsx +62 -0
  527. package/src/doc-mjs.d.ts +19 -0
  528. package/src/hooks/index.ts +6 -0
  529. package/src/hooks/isRtlElement.ts +27 -0
  530. package/src/hooks/useAnnounce.test.tsx +75 -2
  531. package/src/hooks/useAnnounce.ts +47 -1
  532. package/src/hooks/useFocusTrap.test.tsx +104 -0
  533. package/src/hooks/useFocusTrap.ts +61 -12
  534. package/src/hooks/useGridFocus.doc.mjs +3 -3
  535. package/src/hooks/useGridFocus.test.tsx +41 -0
  536. package/src/hooks/useGridFocus.ts +21 -10
  537. package/src/hooks/useHotkeys.ts +9 -0
  538. package/src/hooks/useInputStatusIcon.test.tsx +162 -0
  539. package/src/hooks/useInputStatusIcon.tsx +224 -0
  540. package/src/hooks/useKeyboardHint.test.tsx +22 -0
  541. package/src/hooks/useKeyboardHint.tsx +6 -2
  542. package/src/hooks/useListFocus.doc.mjs +25 -3
  543. package/src/hooks/useListFocus.test.tsx +153 -1
  544. package/src/hooks/useListFocus.ts +102 -9
  545. package/src/i18n/InternationalizationContext.ts +4 -0
  546. package/src/i18n/InternationalizationProvider.tsx +12 -2
  547. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  548. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  549. package/src/i18n/getLocaleDirection.ts +29 -0
  550. package/src/i18n/index.ts +6 -0
  551. package/src/i18n/useDirection.ts +29 -0
  552. package/src/reset.css +0 -26
  553. package/src/reset.test.ts +60 -0
  554. package/src/theme/derivedVarRegistry.test.ts +1 -0
  555. package/src/theme/derivedVarRegistry.ts +6 -0
  556. package/src/theme/generateThemeRules.test.ts +42 -0
  557. package/src/utils/index.ts +2 -0
  558. package/src/utils/plainDate.test.ts +24 -6
  559. package/src/utils/plainDate.ts +18 -4
  560. package/src/utils/rtlStyles.ts +27 -0
@@ -157,6 +157,16 @@ export interface BaseTypeaheadProps<T extends SearchableItem> extends Omit<
157
157
  */
158
158
  inputXStyle?: StyleXStyles;
159
159
 
160
+ /**
161
+ * Tab-order override for the input element. Typeahead passes `-1` while
162
+ * its selected-value token is shown: the input is visually collapsed
163
+ * (width 0 / opacity 0) but must stay programmatically focusable for
164
+ * token edit/clear interactions, so removing it from the Tab order is
165
+ * what prevents an invisible tab stop (WCAG 2.4.3 / 2.4.7). The input
166
+ * remains focusable via `.focus()` regardless of this value.
167
+ */
168
+ inputTabIndex?: number;
169
+
160
170
  /**
161
171
  * Ref to the anchor element for dropdown positioning.
162
172
  * The dropdown will be positioned relative to this element.
@@ -230,7 +240,7 @@ const styles = stylex.create({
230
240
  outline: 'none',
231
241
  backgroundColor: 'transparent',
232
242
  border: 'none',
233
- textAlign: 'left',
243
+ textAlign: 'start',
234
244
  },
235
245
  itemHighlighted: {
236
246
  backgroundColor: colorVars['--color-overlay-hover'],
@@ -316,6 +326,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
316
326
  ariaDescribedBy,
317
327
  ariaLabelledBy,
318
328
  inputXStyle,
329
+ inputTabIndex,
319
330
  anchorRef,
320
331
  onKeyDown: externalOnKeyDown,
321
332
  debounceMs = 150,
@@ -431,7 +442,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
431
442
  resultsGenRef.current = gen;
432
443
  const shown = searchResults.slice(0, maxMenuItems);
433
444
  setResults(shown);
434
- setHighlightedIndex(searchResults.length > 0 ? 0 : -1);
445
+ setHighlightedIndex(shown.length > 0 ? 0 : -1);
435
446
  if (searchResults.length > 0 || searchQuery.length > 0) {
436
447
  showLayer();
437
448
  }
@@ -469,8 +480,9 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
469
480
  return;
470
481
  }
471
482
  resultsGenRef.current = gen;
472
- setResults(bootstrapResults.slice(0, maxMenuItems));
473
- setHighlightedIndex(bootstrapResults.length > 0 ? 0 : -1);
483
+ const shown = bootstrapResults.slice(0, maxMenuItems);
484
+ setResults(shown);
485
+ setHighlightedIndex(shown.length > 0 ? 0 : -1);
474
486
  if (bootstrapResults.length > 0) {
475
487
  showLayer();
476
488
  }
@@ -637,15 +649,19 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
637
649
  switch (e.key) {
638
650
  case 'ArrowDown':
639
651
  e.preventDefault();
640
- setHighlightedIndex(prev =>
641
- prev < results.length - 1 ? prev + 1 : 0,
642
- );
652
+ if (results.length > 0) {
653
+ setHighlightedIndex(prev =>
654
+ prev < results.length - 1 ? prev + 1 : 0,
655
+ );
656
+ }
643
657
  break;
644
658
  case 'ArrowUp':
645
659
  e.preventDefault();
646
- setHighlightedIndex(prev =>
647
- prev > 0 ? prev - 1 : results.length - 1,
648
- );
660
+ if (results.length > 0) {
661
+ setHighlightedIndex(prev =>
662
+ prev > 0 ? prev - 1 : results.length - 1,
663
+ );
664
+ }
649
665
  break;
650
666
  case 'Enter':
651
667
  e.preventDefault();
@@ -660,13 +676,17 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
660
676
  case 'Home':
661
677
  if (popover.isOpen) {
662
678
  e.preventDefault();
663
- setHighlightedIndex(0);
679
+ if (results.length > 0) {
680
+ setHighlightedIndex(0);
681
+ }
664
682
  }
665
683
  break;
666
684
  case 'End':
667
685
  if (popover.isOpen) {
668
686
  e.preventDefault();
669
- setHighlightedIndex(results.length - 1);
687
+ if (results.length > 0) {
688
+ setHighlightedIndex(results.length - 1);
689
+ }
670
690
  }
671
691
  break;
672
692
  }
@@ -694,13 +714,17 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
694
714
  // cursor walks off-screen once navigation passes the visible window. Mirrors
695
715
  // CommandPaletteItem's scrollIntoView({block: 'nearest'}) behavior.
696
716
  useEffect(() => {
697
- if (!popover.isOpen || highlightedIndex < 0) {
717
+ if (
718
+ !popover.isOpen ||
719
+ highlightedIndex < 0 ||
720
+ highlightedIndex >= results.length
721
+ ) {
698
722
  return;
699
723
  }
700
724
  document
701
725
  .getElementById(getItemId(highlightedIndex))
702
726
  ?.scrollIntoView?.({block: 'nearest'});
703
- }, [popover.isOpen, highlightedIndex, getItemId]);
727
+ }, [popover.isOpen, highlightedIndex, getItemId, results.length]);
704
728
 
705
729
  const selectedKey =
706
730
  value == null ? null : getKey(value.id, () => results.indexOf(value));
@@ -725,7 +749,9 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
725
749
  aria-expanded={popover.isOpen}
726
750
  aria-controls={listboxId}
727
751
  aria-activedescendant={
728
- popover.isOpen && highlightedIndex >= 0
752
+ popover.isOpen &&
753
+ highlightedIndex >= 0 &&
754
+ highlightedIndex < results.length
729
755
  ? getItemId(highlightedIndex)
730
756
  : undefined
731
757
  }
@@ -733,6 +759,7 @@ export const BaseTypeahead = function BaseTypeahead<T extends SearchableItem>({
733
759
  aria-describedby={ariaDescribedBy}
734
760
  aria-labelledby={ariaLabelledBy}
735
761
  aria-disabled={isFocusableDisabled ? 'true' : undefined}
762
+ tabIndex={inputTabIndex}
736
763
  value={query}
737
764
  onChange={handleInputChange}
738
765
  onPointerDown={() => {
@@ -89,6 +89,13 @@ export const docs = {
89
89
  description:
90
90
  'Validation status object with type and message for error/warning/success states.',
91
91
  },
92
+ {
93
+ name: 'statusVariant',
94
+ type: "'attached' | 'detached'",
95
+ description:
96
+ '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.',
97
+ default: "'attached'",
98
+ },
92
99
  {
93
100
  name: 'renderItem',
94
101
  type: '(item: T) => ReactNode',
@@ -158,6 +165,12 @@ export const docs = {
158
165
  type: '(isOpen: boolean) => void',
159
166
  description: 'Callback when the dropdown opens or closes.',
160
167
  },
168
+ {
169
+ name: 'width',
170
+ type: 'SizeValue',
171
+ description:
172
+ '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.',
173
+ },
161
174
  {
162
175
  name: 'xstyle',
163
176
  type: 'StyleXStyles',
@@ -171,6 +171,33 @@ describe('BaseTypeahead', () => {
171
171
  });
172
172
  });
173
173
 
174
+ describe('empty results active descendant (#4059)', () => {
175
+ it('does not set aria-activedescendant when search has 0 results', async () => {
176
+ render(
177
+ <BaseTypeahead
178
+ searchSource={fruitSource}
179
+ value={null}
180
+ onChange={() => {}}
181
+ debounceMs={0}
182
+ />,
183
+ );
184
+ const input = screen.getByRole('combobox');
185
+ fireEvent.change(input, {target: {value: 'zzzzz'}});
186
+
187
+ await waitFor(() => {
188
+ expect(input).not.toHaveAttribute('aria-activedescendant');
189
+ });
190
+
191
+ // Press ArrowDown — should NOT set aria-activedescendant to option-0
192
+ fireEvent.keyDown(input, {key: 'ArrowDown'});
193
+ expect(input).not.toHaveAttribute('aria-activedescendant');
194
+
195
+ // Press Home — should NOT set aria-activedescendant
196
+ fireEvent.keyDown(input, {key: 'Home'});
197
+ expect(input).not.toHaveAttribute('aria-activedescendant');
198
+ });
199
+ });
200
+
174
201
  it('disables input when isDisabled', () => {
175
202
  render(
176
203
  <BaseTypeahead
@@ -710,6 +737,68 @@ describe('Typeahead edit mode', () => {
710
737
  });
711
738
  });
712
739
 
740
+ describe('Typeahead collapsed input tab order', () => {
741
+ it('removes the invisible input from the Tab order while a token is shown', () => {
742
+ render(
743
+ <Typeahead
744
+ label="Fruit"
745
+ searchSource={fruitSource}
746
+ value={fruits[0]}
747
+ onChange={() => {}}
748
+ />,
749
+ );
750
+ // While the token is shown the input is collapsed (width 0 / opacity 0);
751
+ // it must stay programmatically focusable for token interactions but must
752
+ // not be an invisible Tab stop (WCAG 2.4.3 / 2.4.7).
753
+ expect(screen.getByRole('combobox')).toHaveAttribute('tabindex', '-1');
754
+ });
755
+
756
+ it('Tab from the token skips the invisible input', async () => {
757
+ const user = userEvent.setup();
758
+ render(
759
+ <Typeahead
760
+ label="Fruit"
761
+ searchSource={fruitSource}
762
+ value={fruits[0]}
763
+ onChange={() => {}}
764
+ />,
765
+ );
766
+ // Focus the token's internal button, then Tab away — focus must not land
767
+ // on the visually hidden combobox input.
768
+ const tokenButton = screen.getByRole('button', {name: fruits[0].label});
769
+ tokenButton.focus();
770
+ await user.tab();
771
+ expect(screen.getByRole('combobox')).not.toHaveFocus();
772
+ });
773
+
774
+ it('keeps the input in the Tab order when no token is shown', () => {
775
+ render(
776
+ <Typeahead
777
+ label="Fruit"
778
+ searchSource={fruitSource}
779
+ value={null}
780
+ onChange={() => {}}
781
+ />,
782
+ );
783
+ expect(screen.getByRole('combobox')).not.toHaveAttribute('tabindex');
784
+ });
785
+
786
+ it('restores the input to the Tab order in edit mode', () => {
787
+ render(
788
+ <Typeahead
789
+ label="Fruit"
790
+ searchSource={fruitSource}
791
+ value={fruits[0]}
792
+ onChange={() => {}}
793
+ />,
794
+ );
795
+ // Entering edit mode removes the token and uncollapses the input
796
+ const tokenText = screen.getByText(fruits[0].label);
797
+ fireEvent.click(tokenText.closest('div')!);
798
+ expect(screen.getByRole('combobox')).not.toHaveAttribute('tabindex');
799
+ });
800
+ });
801
+
713
802
  describe('BaseTypeahead paste behavior', () => {
714
803
  it('pasting text triggers search results like typing', async () => {
715
804
  const user = userEvent.setup();
@@ -948,3 +1037,26 @@ describe('Typeahead disabledMessage', () => {
948
1037
  expect(input).not.toHaveAttribute('aria-disabled');
949
1038
  });
950
1039
  });
1040
+
1041
+
1042
+ describe('Typeahead statusVariant forwarding', () => {
1043
+ it('defaults to attached (status renders with data-variant="attached")', () => {
1044
+ const {container} = render(
1045
+ <Typeahead label="Fruit" searchSource={fruitSource} value={null} onChange={() => {}} status={{type: 'error', message: 'Required'}} />,
1046
+ );
1047
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1048
+ 'data-variant',
1049
+ 'attached',
1050
+ );
1051
+ });
1052
+
1053
+ it('forwards statusVariant="detached" to the underlying Field status', () => {
1054
+ const {container} = render(
1055
+ <Typeahead label="Fruit" searchSource={fruitSource} value={null} onChange={() => {}} status={{type: 'error', message: 'Required'}} statusVariant="detached" />,
1056
+ );
1057
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1058
+ 'data-variant',
1059
+ 'detached',
1060
+ );
1061
+ });
1062
+ });
@@ -36,6 +36,7 @@ import {
36
36
  inputStatusBorderStyles,
37
37
  inputStatusHoverShadowStyles,
38
38
  inputStatusFocusWithinStyles,
39
+ type FieldStatusVariant,
39
40
  } from '../Field';
40
41
  import {Token} from '../Token';
41
42
  import {useTooltip} from '../Tooltip';
@@ -75,6 +76,13 @@ export interface TypeaheadProps<T extends SearchableItem> extends Omit<
75
76
  isOptional?: boolean;
76
77
  /** Validation status. */
77
78
  status?: InputStatus;
79
+ /**
80
+ * How the status message is placed relative to the input.
81
+ * - 'attached': message overlaps directly below the input (bordered treatment)
82
+ * - 'detached': message floats below as a separate element with spacing
83
+ * @default 'attached'
84
+ */
85
+ statusVariant?: FieldStatusVariant;
78
86
  /**
79
87
  * Icon to display at the start of the input.
80
88
  * Accepts a ReactNode (e.g. `<Icon icon={SearchIcon} />`) or an SVG icon component directly.
@@ -226,6 +234,7 @@ export function Typeahead<T extends SearchableItem>({
226
234
  isRequired = false,
227
235
  isOptional = false,
228
236
  status,
237
+ statusVariant = 'attached',
229
238
  startIcon,
230
239
  labelTooltip,
231
240
  searchSource,
@@ -412,7 +421,7 @@ export function Typeahead<T extends SearchableItem>({
412
421
  styles.wrapper,
413
422
  sizeStyle,
414
423
  status && inputStatusBorderStyles[status.type],
415
- status && inputStatusHoverShadowStyles[status.type],
424
+ status && !isDisabled && inputStatusHoverShadowStyles[status.type],
416
425
  status && inputStatusFocusWithinStyles[status.type],
417
426
  isDisabled && inputWrapperStyles.disabled,
418
427
  inputGroup && groupStyles.inGroup,
@@ -458,6 +467,12 @@ export function Typeahead<T extends SearchableItem>({
458
467
  anchorRef={wrapperRef}
459
468
  onKeyDown={handleKeyDown}
460
469
  inputXStyle={showToken ? styles.inputHidden : undefined}
470
+ // While the token is shown the input is collapsed (width 0 /
471
+ // opacity 0) — take it out of the Tab order so keyboard users
472
+ // don't hit an invisible stop (WCAG 2.4.3 / 2.4.7). It stays
473
+ // programmatically focusable: entering edit mode and clearing
474
+ // both refocus it after it uncollapses.
475
+ inputTabIndex={showToken ? -1 : undefined}
461
476
  size={size}
462
477
  />
463
478
  {hasClear && value && !isDisabled && (
@@ -500,6 +515,7 @@ export function Typeahead<T extends SearchableItem>({
500
515
  }
501
516
  : undefined
502
517
  }
518
+ statusVariant={statusVariant}
503
519
  labelTooltip={labelTooltip}
504
520
  width={width}
505
521
  xstyle={xstyle}
@@ -132,6 +132,7 @@ export function TypeaheadItem<T extends SearchableItem>({
132
132
  icon,
133
133
  description,
134
134
  isDisabled = false,
135
+ xstyle,
135
136
  }: TypeaheadItemProps<T>) {
136
137
  // If item has a pre-rendered element, use it
137
138
  if (item.element) {
@@ -143,7 +144,7 @@ export function TypeaheadItem<T extends SearchableItem>({
143
144
  ref={ref}
144
145
  {...mergeProps(
145
146
  themeProps('typeahead-item'),
146
- stylex.props(styles.container, isDisabled && styles.disabled),
147
+ stylex.props(styles.container, isDisabled && styles.disabled, xstyle),
147
148
  )}>
148
149
  {icon}
149
150
  <div {...stylex.props(styles.content)}>
@@ -0,0 +1,60 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file forcedColors.ts
5
+ * @input Uses the jsdom document (StyleX dev runtime injects rules into it)
6
+ * @output Exports getForcedColorsRules, getAllInjectedCss test helpers
7
+ * @position Shared test utility for asserting forced-colors style output
8
+ *
9
+ * jsdom cannot emulate `@media (forced-colors: active)` rendering, so
10
+ * component tests assert the next-best thing: that the StyleX dev runtime
11
+ * (runtimeInjection in vitest.config.ts) actually injected the forced-colors
12
+ * rules a component relies on for Windows High Contrast support (WCAG 1.4.11).
13
+ * Visual behavior needs manual verification in a forced-colors environment.
14
+ */
15
+
16
+ /**
17
+ * Collects the cssText of every injected CSS rule scoped to
18
+ * `@media (forced-colors: active)`, including rules nested in other
19
+ * conditions. Returns one string for substring assertions.
20
+ */
21
+ export function getForcedColorsRules(): string {
22
+ const chunks: string[] = [];
23
+ for (const sheet of Array.from(document.styleSheets)) {
24
+ let rules: CSSRule[];
25
+ try {
26
+ rules = Array.from(sheet.cssRules);
27
+ } catch {
28
+ continue;
29
+ }
30
+ for (const rule of rules) {
31
+ if (rule.cssText.includes('forced-colors: active')) {
32
+ chunks.push(rule.cssText);
33
+ }
34
+ }
35
+ }
36
+ return chunks.join('\n');
37
+ }
38
+
39
+ /**
40
+ * Collects the cssText of every injected CSS rule, regardless of condition.
41
+ * Use to assert declarations that live OUTSIDE `@media (forced-colors: active)`
42
+ * yet still exist for forced-colors support — e.g. `forced-color-adjust: none`
43
+ * (an unconditional declaration) or a hover tint gated behind
44
+ * `(forced-colors: none)` so it cannot override the forced-colors state.
45
+ */
46
+ export function getAllInjectedCss(): string {
47
+ const chunks: string[] = [];
48
+ for (const sheet of Array.from(document.styleSheets)) {
49
+ let rules: CSSRule[];
50
+ try {
51
+ rules = Array.from(sheet.cssRules);
52
+ } catch {
53
+ continue;
54
+ }
55
+ for (const rule of rules) {
56
+ chunks.push(rule.cssText);
57
+ }
58
+ }
59
+ return chunks.join('\n');
60
+ }
@@ -0,0 +1,62 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ import {describe, it, expect} from 'vitest';
4
+
5
+ import {docs as CheckboxInputDocs} from '../CheckboxInput/CheckboxInput.doc.mjs';
6
+ import {docs as CheckboxListDocs} from '../CheckboxList/CheckboxList.doc.mjs';
7
+ import {docs as DateInputDocs} from '../DateInput/DateInput.doc.mjs';
8
+ import {docs as DateRangeInputDocs} from '../DateRangeInput/DateRangeInput.doc.mjs';
9
+ import {docs as DateTimeInputDocs} from '../DateTimeInput/DateTimeInput.doc.mjs';
10
+ import {docs as FileInputDocs} from '../FileInput/FileInput.doc.mjs';
11
+ import {docs as MultiSelectorDocs} from '../MultiSelector/MultiSelector.doc.mjs';
12
+ import {docs as NumberInputDocs} from '../NumberInput/NumberInput.doc.mjs';
13
+ import {docs as RadioListDocs} from '../RadioList/RadioList.doc.mjs';
14
+ import {docs as SelectorDocs} from '../Selector/Selector.doc.mjs';
15
+ import {docs as SliderDocs} from '../Slider/Slider.doc.mjs';
16
+ import {docs as SwitchDocs} from '../Switch/Switch.doc.mjs';
17
+ import {docs as TextAreaDocs} from '../TextArea/TextArea.doc.mjs';
18
+ import {docs as TextInputDocs} from '../TextInput/TextInput.doc.mjs';
19
+ import {docs as TimeInputDocs} from '../TimeInput/TimeInput.doc.mjs';
20
+ import {docs as TokenizerDocs} from '../Tokenizer/Tokenizer.doc.mjs';
21
+ import {docs as TypeaheadDocs} from '../Typeahead/Typeahead.doc.mjs';
22
+
23
+ const inputDocsSuite = [
24
+ {name: 'CheckboxInput', docs: CheckboxInputDocs},
25
+ {name: 'CheckboxList', docs: CheckboxListDocs},
26
+ {name: 'DateInput', docs: DateInputDocs},
27
+ {name: 'DateRangeInput', docs: DateRangeInputDocs},
28
+ {name: 'DateTimeInput', docs: DateTimeInputDocs},
29
+ {name: 'FileInput', docs: FileInputDocs},
30
+ {name: 'MultiSelector', docs: MultiSelectorDocs},
31
+ {name: 'NumberInput', docs: NumberInputDocs},
32
+ {name: 'RadioList', docs: RadioListDocs},
33
+ {name: 'Selector', docs: SelectorDocs},
34
+ {name: 'Slider', docs: SliderDocs},
35
+ {name: 'Switch', docs: SwitchDocs},
36
+ {name: 'TextArea', docs: TextAreaDocs},
37
+ {name: 'TextInput', docs: TextInputDocs},
38
+ {name: 'TimeInput', docs: TimeInputDocs},
39
+ {name: 'Tokenizer', docs: TokenizerDocs},
40
+ {name: 'Typeahead', docs: TypeaheadDocs},
41
+ ];
42
+
43
+ describe('Input Family width Prop Contract (#4163)', () => {
44
+ inputDocsSuite.forEach(({name, docs}) => {
45
+ it(`documents the width prop for ${name}`, () => {
46
+ const propsList = (docs.props || docs.components?.[0]?.props) as {
47
+ name: string;
48
+ type: string;
49
+ }[];
50
+ expect(
51
+ propsList,
52
+ `${name}.doc.mjs must expose a props array`,
53
+ ).toBeDefined();
54
+ const widthProp = propsList.find(p => p.name === 'width');
55
+ expect(
56
+ widthProp,
57
+ `${name}.doc.mjs must document the width prop`,
58
+ ).toBeDefined();
59
+ expect(widthProp?.type).toBe('SizeValue');
60
+ });
61
+ });
62
+ });
@@ -0,0 +1,19 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Ambient module declaration for `*.doc.mjs` imports.
5
+ *
6
+ * Component contract tests (packages/core/src/__tests__/*Contract.test.tsx)
7
+ * import `{Name}.doc.mjs` files directly to assert their documented props
8
+ * stay in sync with the component's real API. Without this declaration,
9
+ * TypeScript has no way to type a `.mjs` import and fails with
10
+ * TS7016 ("Could not find a declaration file for module").
11
+ */
12
+
13
+ declare module '*.doc.mjs' {
14
+ import type {ComponentDoc, TranslationDoc} from './docs-types';
15
+
16
+ export const docs: ComponentDoc;
17
+ export const docsZh: ComponentDoc;
18
+ export const docsDense: TranslationDoc;
19
+ }
@@ -76,6 +76,12 @@ export type {
76
76
  export {useInputContainer} from './useInputContainer';
77
77
  export type {UseInputContainerOptions} from './useInputContainer';
78
78
 
79
+ export {useInputStatusIcon} from './useInputStatusIcon';
80
+ export type {
81
+ UseInputStatusIconOptions,
82
+ UseInputStatusIconReturn,
83
+ } from './useInputStatusIcon';
84
+
79
85
  export {useInteractiveRole} from './useInteractiveRole';
80
86
  export type {
81
87
  InteractiveRole,
@@ -0,0 +1,27 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file isRtlElement.ts
7
+ * @input DOM element (nullable)
8
+ * @output Exports isRtlElement helper resolving an element's computed text
9
+ * direction
10
+ * @position Internal hook utility; used by useListFocus and useGridFocus to
11
+ * auto-detect RTL for arrow-key navigation (same getComputedStyle precedent
12
+ * as Resizable's ResizeHandle drag deltas).
13
+ */
14
+
15
+ /**
16
+ * Whether `el` renders right-to-left, per its computed `direction`.
17
+ *
18
+ * SSR-safe: returns false when `el` is null or no DOM is available. Callers
19
+ * should invoke this lazily (on keydown, not on render) so getComputedStyle
20
+ * runs only when a horizontal arrow key is actually handled.
21
+ */
22
+ export function isRtlElement(el: HTMLElement | null): boolean {
23
+ if (!el || typeof window === 'undefined') {
24
+ return false;
25
+ }
26
+ return window.getComputedStyle(el).direction === 'rtl';
27
+ }
@@ -9,8 +9,8 @@
9
9
  * SYNC: When useAnnounce.ts changes, update tests to match new behavior
10
10
  */
11
11
 
12
- import {describe, it, expect, afterEach} from 'vitest';
13
- import {renderHook, waitFor} from '@testing-library/react';
12
+ import {describe, it, expect, afterEach, vi} from 'vitest';
13
+ import {act, renderHook, waitFor} from '@testing-library/react';
14
14
  import {useAnnounce, __resetLiveRegionsForTest} from './useAnnounce';
15
15
 
16
16
  afterEach(() => {
@@ -82,6 +82,79 @@ describe('useAnnounce', () => {
82
82
  expect(politeRegion()).toBeNull();
83
83
  });
84
84
 
85
+ it('clears the region after the clear delay, but not before', () => {
86
+ vi.useFakeTimers();
87
+ try {
88
+ const {result} = renderHook(() => useAnnounce());
89
+ result.current('Saved');
90
+ // Flush the rAF that re-sets the message.
91
+ act(() => {
92
+ vi.advanceTimersByTime(50);
93
+ });
94
+ expect(politeRegion()?.textContent).toBe('Saved');
95
+
96
+ // The message survives long enough for AT to finish reading it.
97
+ act(() => {
98
+ vi.advanceTimersByTime(1000);
99
+ });
100
+ expect(politeRegion()?.textContent).toBe('Saved');
101
+
102
+ // After the clear delay, stale status text is removed from the DOM.
103
+ act(() => {
104
+ vi.advanceTimersByTime(10_000);
105
+ });
106
+ expect(politeRegion()?.textContent).toBe('');
107
+ } finally {
108
+ vi.useRealTimers();
109
+ }
110
+ });
111
+
112
+ it('resets the clear timer on each announce', () => {
113
+ vi.useFakeTimers();
114
+ try {
115
+ const {result} = renderHook(() => useAnnounce());
116
+ result.current('first');
117
+ act(() => {
118
+ vi.advanceTimersByTime(1500);
119
+ });
120
+ // Announcing again must reset the pending clear, not inherit it.
121
+ result.current('second');
122
+ act(() => {
123
+ vi.advanceTimersByTime(1900);
124
+ });
125
+ // 3.4s after 'first' (past its clear point) but only 1.9s after
126
+ // 'second' — the newer message must still be present.
127
+ expect(politeRegion()?.textContent).toBe('second');
128
+ act(() => {
129
+ vi.advanceTimersByTime(10_000);
130
+ });
131
+ expect(politeRegion()?.textContent).toBe('');
132
+ } finally {
133
+ vi.useRealTimers();
134
+ }
135
+ });
136
+
137
+ it('re-announces normally after a clear', () => {
138
+ vi.useFakeTimers();
139
+ try {
140
+ const {result} = renderHook(() => useAnnounce());
141
+ result.current('gone soon');
142
+ act(() => {
143
+ vi.advanceTimersByTime(10_000);
144
+ });
145
+ expect(politeRegion()?.textContent).toBe('');
146
+
147
+ // The clear-then-rAF re-announce pattern still works after a clear.
148
+ result.current('back again');
149
+ act(() => {
150
+ vi.advanceTimersByTime(50);
151
+ });
152
+ expect(politeRegion()?.textContent).toBe('back again');
153
+ } finally {
154
+ vi.useRealTimers();
155
+ }
156
+ });
157
+
85
158
  it('reuses the same singleton regions across hook instances', async () => {
86
159
  const {result: a} = renderHook(() => useAnnounce());
87
160
  a.current('first');