@astryxdesign/core 0.1.8 → 0.1.9-canary.08c278e

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 (603) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/AppShell/AppShell.d.ts.map +1 -1
  3. package/dist/AppShell/AppShell.js +6 -2
  4. package/dist/AppShell/AppShellMobileContext.d.ts +8 -0
  5. package/dist/AppShell/AppShellMobileContext.d.ts.map +1 -1
  6. package/dist/Avatar/Avatar.d.ts +53 -3
  7. package/dist/Avatar/Avatar.d.ts.map +1 -1
  8. package/dist/Avatar/Avatar.js +203 -49
  9. package/dist/Avatar/AvatarStatusDot.d.ts +33 -5
  10. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  11. package/dist/Avatar/AvatarStatusDot.js +144 -19
  12. package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
  13. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroup.js +58 -6
  15. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  16. package/dist/AvatarGroup/AvatarGroupOverflow.js +1 -0
  17. package/dist/Banner/Banner.d.ts +9 -1
  18. package/dist/Banner/Banner.d.ts.map +1 -1
  19. package/dist/Banner/Banner.js +33 -4
  20. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +31 -2
  21. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  22. package/dist/Breadcrumbs/BreadcrumbItem.js +208 -6
  23. package/dist/Breadcrumbs/index.d.ts +5 -0
  24. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  25. package/dist/Breadcrumbs/index.js +9 -1
  26. package/dist/Button/Button.d.ts +8 -2
  27. package/dist/Button/Button.d.ts.map +1 -1
  28. package/dist/Button/Button.js +33 -4
  29. package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
  30. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  31. package/dist/ButtonGroup/ButtonGroup.js +30 -1
  32. package/dist/Calendar/Calendar.d.ts.map +1 -1
  33. package/dist/Calendar/Calendar.js +30 -2
  34. package/dist/Calendar/dayCellUtils.js +1 -1
  35. package/dist/Card/Card.d.ts +8 -2
  36. package/dist/Card/Card.d.ts.map +1 -1
  37. package/dist/Card/Card.js +28 -2
  38. package/dist/Carousel/Carousel.d.ts +4 -1
  39. package/dist/Carousel/Carousel.d.ts.map +1 -1
  40. package/dist/Carousel/Carousel.js +24 -4
  41. package/dist/Chat/ChatComposer.d.ts +8 -0
  42. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  43. package/dist/Chat/ChatComposer.js +46 -7
  44. package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
  45. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  46. package/dist/Chat/ChatComposerDrawer.js +11 -1
  47. package/dist/Chat/ChatComposerInput.d.ts +20 -3
  48. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  49. package/dist/Chat/ChatComposerInput.js +36 -4
  50. package/dist/Chat/ChatContext.d.ts +33 -0
  51. package/dist/Chat/ChatContext.d.ts.map +1 -1
  52. package/dist/Chat/ChatContext.js +16 -2
  53. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  54. package/dist/Chat/ChatDictationButton.js +1 -1
  55. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  56. package/dist/Chat/ChatLayout.js +4 -4
  57. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  58. package/dist/Chat/ChatLayoutScrollButton.js +4 -4
  59. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  60. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  61. package/dist/Chat/ChatSendButton.js +7 -1
  62. package/dist/Chat/ChatToolCalls.d.ts +5 -1
  63. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  64. package/dist/Chat/ChatToolCalls.js +18 -9
  65. package/dist/Chat/index.d.ts +2 -1
  66. package/dist/Chat/index.d.ts.map +1 -1
  67. package/dist/Chat/index.js +1 -1
  68. package/dist/Chat/useChatStreamScroll.d.ts +2 -1
  69. package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
  70. package/dist/Chat/useChatStreamScroll.js +22 -8
  71. package/dist/Chat/useSpeechRecognition.d.ts +0 -1
  72. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  73. package/dist/Chat/useSpeechRecognition.js +1 -1
  74. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  75. package/dist/Chat/useTriggerMenu.js +2 -2
  76. package/dist/CheckboxInput/CheckboxInput.js +1 -1
  77. package/dist/CheckboxList/CheckboxListItem.d.ts +20 -1
  78. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  79. package/dist/CheckboxList/CheckboxListItem.js +11 -1
  80. package/dist/ClickableCard/ClickableCard.d.ts +9 -2
  81. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  82. package/dist/ClickableCard/ClickableCard.js +5 -2
  83. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  84. package/dist/CodeBlock/CodeBlock.js +9 -2
  85. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  86. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  87. package/dist/CommandPalette/CommandPalette.js +3 -1
  88. package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
  89. package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
  90. package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
  91. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  92. package/dist/CommandPalette/CommandPaletteInput.js +6 -1
  93. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  94. package/dist/DateInput/DateInput.d.ts +55 -2
  95. package/dist/DateInput/DateInput.d.ts.map +1 -1
  96. package/dist/DateInput/DateInput.js +28 -2
  97. package/dist/DateInput/index.d.ts +1 -1
  98. package/dist/DateInput/index.d.ts.map +1 -1
  99. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  100. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  101. package/dist/DateRangeInput/DateRangeInput.js +3 -1
  102. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  103. package/dist/DateTimeInput/DateTimeInput.js +18 -3
  104. package/dist/Dialog/Dialog.d.ts +3 -0
  105. package/dist/Dialog/Dialog.d.ts.map +1 -1
  106. package/dist/Dialog/Dialog.js +57 -6
  107. package/dist/Dialog/DialogContext.d.ts +7 -0
  108. package/dist/Dialog/DialogContext.d.ts.map +1 -1
  109. package/dist/Dialog/DialogContext.js +2 -2
  110. package/dist/Dialog/DialogHeader.d.ts +5 -2
  111. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  112. package/dist/Dialog/DialogHeader.js +6 -1
  113. package/dist/Divider/Divider.js +1 -1
  114. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
  115. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  116. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
  117. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  118. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
  119. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  120. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
  121. package/dist/Field/Field.d.ts.map +1 -1
  122. package/dist/Field/Field.js +2 -3
  123. package/dist/Field/FieldLabel.d.ts +1 -1
  124. package/dist/Field/FieldLabel.d.ts.map +1 -1
  125. package/dist/Field/FieldLabel.js +43 -16
  126. package/dist/FieldStatus/FieldStatus.d.ts +15 -0
  127. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  128. package/dist/FieldStatus/FieldStatus.js +58 -6
  129. package/dist/FileInput/FileInput.d.ts +9 -2
  130. package/dist/FileInput/FileInput.d.ts.map +1 -1
  131. package/dist/FileInput/FileInput.js +42 -20
  132. package/dist/HoverCard/HoverCard.d.ts +9 -1
  133. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  134. package/dist/HoverCard/HoverCard.js +2 -0
  135. package/dist/HoverCard/useHoverCard.d.ts +8 -0
  136. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  137. package/dist/HoverCard/useHoverCard.js +7 -2
  138. package/dist/Icon/Icon.d.ts +7 -2
  139. package/dist/Icon/Icon.d.ts.map +1 -1
  140. package/dist/Item/Item.d.ts +6 -1
  141. package/dist/Item/Item.d.ts.map +1 -1
  142. package/dist/Item/Item.js +22 -1
  143. package/dist/Layer/useLayer.d.ts +6 -0
  144. package/dist/Layer/useLayer.d.ts.map +1 -1
  145. package/dist/Layer/useLayer.js +2 -0
  146. package/dist/Lightbox/Lightbox.js +4 -4
  147. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  148. package/dist/MobileNav/MobileNav.js +6 -1
  149. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  150. package/dist/MobileNav/MobileNavToggle.js +4 -0
  151. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  152. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  153. package/dist/MultiSelector/MultiSelector.js +41 -12
  154. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  155. package/dist/MultiSelector/hooks.js +16 -0
  156. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  157. package/dist/NumberInput/NumberInput.d.ts +9 -2
  158. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  159. package/dist/NumberInput/NumberInput.js +8 -1
  160. package/dist/Outline/Outline.d.ts +0 -1
  161. package/dist/Outline/Outline.d.ts.map +1 -1
  162. package/dist/Outline/Outline.js +0 -1
  163. package/dist/OverflowList/OverflowList.d.ts +20 -3
  164. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  165. package/dist/OverflowList/OverflowList.js +29 -4
  166. package/dist/Pagination/Pagination.d.ts.map +1 -1
  167. package/dist/Pagination/Pagination.js +11 -3
  168. package/dist/Popover/Popover.d.ts.map +1 -1
  169. package/dist/Popover/Popover.js +3 -2
  170. package/dist/Popover/usePopover.d.ts.map +1 -1
  171. package/dist/Popover/usePopover.js +3 -9
  172. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  173. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  174. package/dist/PowerSearch/PowerSearch.js +2 -0
  175. package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
  176. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  177. package/dist/SelectableCard/SelectableCard.d.ts +9 -2
  178. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  179. package/dist/SelectableCard/SelectableCard.js +16 -13
  180. package/dist/Selector/Selector.d.ts +8 -0
  181. package/dist/Selector/Selector.d.ts.map +1 -1
  182. package/dist/Selector/Selector.js +7 -3
  183. package/dist/Selector/hooks.d.ts.map +1 -1
  184. package/dist/Selector/hooks.js +16 -0
  185. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  186. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  187. package/dist/SideNav/SideNavHeading.js +21 -8
  188. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  189. package/dist/Slider/Slider.d.ts.map +1 -1
  190. package/dist/Slider/Slider.js +19 -2
  191. package/dist/Stack/stack.stylex.d.ts +9 -9
  192. package/dist/TabList/Tab.js +2 -2
  193. package/dist/TabList/TabMenu.js +1 -1
  194. package/dist/Table/BaseTable.d.ts.map +1 -1
  195. package/dist/Table/BaseTable.js +3 -2
  196. package/dist/Table/TableCell.js +3 -3
  197. package/dist/Table/TableHeaderCell.js +3 -3
  198. package/dist/Table/index.d.ts +2 -0
  199. package/dist/Table/index.d.ts.map +1 -1
  200. package/dist/Table/index.js +1 -0
  201. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  202. package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
  203. package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
  204. package/dist/Table/plugins/rowStatus/index.js +3 -0
  205. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
  206. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
  207. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
  208. package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
  209. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  210. package/dist/Table/plugins/selection/useTableSelection.js +4 -1
  211. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +1 -1
  212. package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
  213. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  214. package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
  215. package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
  216. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
  217. package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
  218. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  219. package/dist/Table/useBaseTablePlugins.js +5 -3
  220. package/dist/TextArea/TextArea.d.ts +9 -1
  221. package/dist/TextArea/TextArea.d.ts.map +1 -1
  222. package/dist/TextArea/TextArea.js +2 -0
  223. package/dist/TextInput/TextInput.d.ts +9 -2
  224. package/dist/TextInput/TextInput.d.ts.map +1 -1
  225. package/dist/TextInput/TextInput.js +6 -1
  226. package/dist/Thumbnail/Thumbnail.d.ts +26 -5
  227. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  228. package/dist/Thumbnail/Thumbnail.js +97 -54
  229. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
  230. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
  231. package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
  232. package/dist/TimeInput/TimeInput.d.ts +9 -2
  233. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  234. package/dist/TimeInput/TimeInput.js +17 -4
  235. package/dist/Timestamp/Timestamp.d.ts +3 -1
  236. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  237. package/dist/Timestamp/Timestamp.js +8 -6
  238. package/dist/Toast/useToast.d.ts.map +1 -1
  239. package/dist/Toast/useToast.js +2 -5
  240. package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
  241. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  242. package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
  243. package/dist/Tokenizer/Tokenizer.d.ts +10 -3
  244. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  245. package/dist/Tokenizer/Tokenizer.js +18 -4
  246. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  247. package/dist/TopNav/TopNavHeading.js +18 -8
  248. package/dist/TopNav/TopNavMegaMenu.js +10 -4
  249. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
  250. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  251. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
  252. package/dist/TopNav/TopNavMenu.d.ts +2 -1
  253. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  254. package/dist/TopNav/TopNavMenu.js +68 -6
  255. package/dist/TreeList/TreeList.d.ts +12 -3
  256. package/dist/TreeList/TreeList.d.ts.map +1 -1
  257. package/dist/TreeList/TreeList.js +2 -0
  258. package/dist/TreeList/TreeListBranches.d.ts +5 -0
  259. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  260. package/dist/TreeList/TreeListBranches.js +10 -4
  261. package/dist/TreeList/TreeListItem.d.ts +8 -2
  262. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  263. package/dist/TreeList/TreeListItem.js +28 -8
  264. package/dist/TreeList/TreeListTypes.d.ts +25 -1
  265. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  266. package/dist/TreeList/index.d.ts +2 -2
  267. package/dist/TreeList/index.d.ts.map +1 -1
  268. package/dist/Typeahead/BaseTypeahead.js +1 -1
  269. package/dist/Typeahead/Typeahead.d.ts +9 -2
  270. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  271. package/dist/Typeahead/Typeahead.js +2 -0
  272. package/dist/astryx.css +41 -31
  273. package/dist/astryx.umd.js +51 -51
  274. package/dist/astryx.umd.js.map +4 -4
  275. package/dist/authoring/doc.d.ts.map +1 -1
  276. package/dist/docs-types.d.ts +8 -0
  277. package/dist/docs-types.d.ts.map +1 -1
  278. package/dist/hooks/computeOverflow.d.ts +47 -0
  279. package/dist/hooks/computeOverflow.d.ts.map +1 -0
  280. package/dist/hooks/computeOverflow.js +213 -0
  281. package/dist/hooks/index.d.ts +1 -0
  282. package/dist/hooks/index.d.ts.map +1 -1
  283. package/dist/hooks/index.js +2 -1
  284. package/dist/hooks/isRtlElement.d.ts +18 -0
  285. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  286. package/dist/hooks/isRtlElement.js +27 -0
  287. package/dist/hooks/useDevWarning.d.ts +18 -0
  288. package/dist/hooks/useDevWarning.d.ts.map +1 -0
  289. package/dist/hooks/useDevWarning.js +49 -0
  290. package/dist/hooks/useGridFocus.d.ts +6 -1
  291. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  292. package/dist/hooks/useGridFocus.js +12 -9
  293. package/dist/hooks/useListFocus.d.ts +6 -1
  294. package/dist/hooks/useListFocus.d.ts.map +1 -1
  295. package/dist/hooks/useListFocus.js +12 -4
  296. package/dist/hooks/useOverflow.d.ts +19 -0
  297. package/dist/hooks/useOverflow.d.ts.map +1 -1
  298. package/dist/hooks/useOverflow.js +36 -25
  299. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  300. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  301. package/dist/i18n/InternationalizationContext.js +3 -0
  302. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  303. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  304. package/dist/i18n/InternationalizationProvider.js +5 -1
  305. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  306. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  307. package/dist/i18n/getLocaleDirection.js +29 -0
  308. package/dist/i18n/index.d.ts +6 -0
  309. package/dist/i18n/index.d.ts.map +1 -1
  310. package/dist/i18n/index.js +7 -1
  311. package/dist/i18n/resolve.d.ts.map +1 -1
  312. package/dist/i18n/resolve.js +7 -18
  313. package/dist/i18n/useDirection.d.ts +2 -0
  314. package/dist/i18n/useDirection.d.ts.map +1 -0
  315. package/dist/i18n/useDirection.js +27 -0
  316. package/dist/theme/Theme.d.ts.map +1 -1
  317. package/dist/theme/Theme.js +2 -7
  318. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  319. package/dist/theme/derivedVarRegistry.js +13 -0
  320. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  321. package/dist/theme/generateThemeRules.js +51 -0
  322. package/dist/theme/hct.d.ts +0 -1
  323. package/dist/theme/hct.d.ts.map +1 -1
  324. package/dist/theme/hct.js +1 -1
  325. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  326. package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
  327. package/dist/utils/devWarning.d.ts +42 -0
  328. package/dist/utils/devWarning.d.ts.map +1 -0
  329. package/dist/utils/devWarning.js +88 -0
  330. package/dist/utils/index.d.ts +3 -1
  331. package/dist/utils/index.d.ts.map +1 -1
  332. package/dist/utils/index.js +3 -2
  333. package/dist/utils/plainDate.d.ts +30 -0
  334. package/dist/utils/plainDate.d.ts.map +1 -1
  335. package/dist/utils/plainDate.js +53 -0
  336. package/dist/utils/types.d.ts +13 -0
  337. package/dist/utils/types.d.ts.map +1 -1
  338. package/locales/en.json +32 -0
  339. package/locales/fr-FR.json +14 -0
  340. package/locales/pseudo.json +24 -0
  341. package/package.json +1 -1
  342. package/src/AppShell/AppShell.tsx +6 -0
  343. package/src/AppShell/AppShellMobileContext.tsx +8 -0
  344. package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
  345. package/src/Avatar/Avatar.doc.mjs +60 -3
  346. package/src/Avatar/Avatar.test.tsx +281 -1
  347. package/src/Avatar/Avatar.tsx +324 -64
  348. package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
  349. package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
  350. package/src/Avatar/AvatarStatusDot.tsx +178 -21
  351. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  352. package/src/AvatarGroup/AvatarGroup.test.tsx +125 -0
  353. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  354. package/src/AvatarGroup/AvatarGroupOverflow.tsx +1 -0
  355. package/src/Banner/Banner.doc.mjs +9 -0
  356. package/src/Banner/Banner.test.tsx +30 -0
  357. package/src/Banner/Banner.tsx +53 -9
  358. package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
  359. package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
  360. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
  361. package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
  362. package/src/Breadcrumbs/index.ts +27 -0
  363. package/src/Button/Button.doc.mjs +9 -0
  364. package/src/Button/Button.test.tsx +49 -0
  365. package/src/Button/Button.tsx +27 -3
  366. package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
  367. package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
  368. package/src/ButtonGroup/ButtonGroup.tsx +32 -0
  369. package/src/Calendar/Calendar.doc.mjs +12 -1
  370. package/src/Calendar/Calendar.test.tsx +193 -0
  371. package/src/Calendar/Calendar.tsx +38 -16
  372. package/src/Calendar/dayCellUtils.test.ts +5 -0
  373. package/src/Calendar/dayCellUtils.ts +1 -1
  374. package/src/Card/Card.doc.mjs +9 -0
  375. package/src/Card/Card.test.tsx +21 -3
  376. package/src/Card/Card.tsx +35 -2
  377. package/src/Carousel/Carousel.doc.mjs +1 -0
  378. package/src/Carousel/Carousel.test.tsx +53 -0
  379. package/src/Carousel/Carousel.tsx +34 -4
  380. package/src/Chat/ChatComposer.doc.mjs +12 -3
  381. package/src/Chat/ChatComposer.test.tsx +115 -0
  382. package/src/Chat/ChatComposer.tsx +73 -9
  383. package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
  384. package/src/Chat/ChatComposerDrawer.tsx +11 -1
  385. package/src/Chat/ChatComposerInput.doc.mjs +7 -0
  386. package/src/Chat/ChatComposerInput.test.tsx +103 -0
  387. package/src/Chat/ChatComposerInput.tsx +51 -5
  388. package/src/Chat/ChatContext.tsx +37 -10
  389. package/src/Chat/ChatDictationButton.tsx +4 -1
  390. package/src/Chat/ChatLayout.tsx +7 -5
  391. package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
  392. package/src/Chat/ChatMessageMetadata.tsx +1 -2
  393. package/src/Chat/ChatSendButton.tsx +11 -1
  394. package/src/Chat/ChatToolCalls.test.tsx +64 -0
  395. package/src/Chat/ChatToolCalls.tsx +25 -4
  396. package/src/Chat/index.ts +5 -1
  397. package/src/Chat/useChatStreamScroll.test.tsx +49 -0
  398. package/src/Chat/useChatStreamScroll.ts +27 -10
  399. package/src/Chat/useSpeechRecognition.ts +1 -1
  400. package/src/Chat/useTriggerMenu.tsx +4 -2
  401. package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
  402. package/src/CheckboxInput/CheckboxInput.tsx +1 -1
  403. package/src/CheckboxList/CheckboxList.test.tsx +81 -3
  404. package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
  405. package/src/CheckboxList/CheckboxListItem.tsx +41 -5
  406. package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
  407. package/src/ClickableCard/ClickableCard.test.tsx +34 -0
  408. package/src/ClickableCard/ClickableCard.tsx +13 -3
  409. package/src/CodeBlock/CodeBlock.test.tsx +56 -0
  410. package/src/CodeBlock/CodeBlock.tsx +10 -2
  411. package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
  412. package/src/CommandPalette/CommandPalette.tsx +3 -1
  413. package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
  414. package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
  415. package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
  416. package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
  417. package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
  418. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  419. package/src/ContextMenu/ContextMenu.test.tsx +193 -0
  420. package/src/DateInput/DateInput.doc.mjs +31 -0
  421. package/src/DateInput/DateInput.test.tsx +131 -0
  422. package/src/DateInput/DateInput.tsx +78 -3
  423. package/src/DateInput/index.ts +1 -0
  424. package/src/DateRangeInput/DateRangeInput.doc.mjs +8 -0
  425. package/src/DateRangeInput/DateRangeInput.test.tsx +23 -0
  426. package/src/DateRangeInput/DateRangeInput.tsx +13 -3
  427. package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -1
  428. package/src/DateTimeInput/DateTimeInput.test.tsx +147 -0
  429. package/src/DateTimeInput/DateTimeInput.tsx +42 -18
  430. package/src/Dialog/Dialog.doc.mjs +2 -2
  431. package/src/Dialog/Dialog.test.tsx +77 -4
  432. package/src/Dialog/Dialog.tsx +89 -5
  433. package/src/Dialog/DialogContext.ts +9 -2
  434. package/src/Dialog/DialogHeader.doc.mjs +2 -2
  435. package/src/Dialog/DialogHeader.tsx +9 -2
  436. package/src/Divider/Divider.tsx +2 -2
  437. package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
  438. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
  439. package/src/DropdownMenu/DropdownMenuItem.tsx +1 -1
  440. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
  441. package/src/Field/Field.test.tsx +57 -12
  442. package/src/Field/Field.tsx +6 -5
  443. package/src/Field/FieldLabel.tsx +9 -1
  444. package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
  445. package/src/FieldStatus/FieldStatus.test.tsx +150 -40
  446. package/src/FieldStatus/FieldStatus.tsx +63 -5
  447. package/src/FileInput/FileInput.doc.mjs +17 -2
  448. package/src/FileInput/FileInput.test.tsx +135 -12
  449. package/src/FileInput/FileInput.tsx +53 -28
  450. package/src/HoverCard/HoverCard.doc.mjs +13 -0
  451. package/src/HoverCard/HoverCard.test.tsx +21 -2
  452. package/src/HoverCard/HoverCard.tsx +11 -0
  453. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  454. package/src/HoverCard/useHoverCard.tsx +24 -2
  455. package/src/Icon/Icon.doc.mjs +3 -2
  456. package/src/Icon/Icon.tsx +7 -2
  457. package/src/IconButton/IconButton.doc.mjs +8 -0
  458. package/src/IconButton/IconButton.test.tsx +15 -18
  459. package/src/Item/Item.test.tsx +40 -18
  460. package/src/Item/Item.tsx +38 -2
  461. package/src/Layer/useLayer.tsx +8 -0
  462. package/src/Lightbox/Lightbox.tsx +4 -4
  463. package/src/List/List.test.tsx +9 -8
  464. package/src/MobileNav/MobileNav.tsx +12 -1
  465. package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
  466. package/src/MobileNav/MobileNavToggle.tsx +9 -1
  467. package/src/MultiSelector/MultiSelector.doc.mjs +13 -2
  468. package/src/MultiSelector/MultiSelector.test.tsx +195 -3
  469. package/src/MultiSelector/MultiSelector.tsx +65 -12
  470. package/src/MultiSelector/hooks.ts +17 -0
  471. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  472. package/src/NumberInput/NumberInput.doc.mjs +15 -0
  473. package/src/NumberInput/NumberInput.test.tsx +82 -7
  474. package/src/NumberInput/NumberInput.tsx +21 -4
  475. package/src/Outline/Outline.tsx +0 -1
  476. package/src/OverflowList/OverflowList.doc.mjs +39 -6
  477. package/src/OverflowList/OverflowList.test.tsx +111 -0
  478. package/src/OverflowList/OverflowList.tsx +48 -8
  479. package/src/Pagination/Pagination.tsx +11 -3
  480. package/src/Popover/Popover.tsx +7 -4
  481. package/src/Popover/usePopover.tsx +9 -13
  482. package/src/PowerSearch/PowerSearch.doc.mjs +29 -0
  483. package/src/PowerSearch/PowerSearch.test.tsx +43 -0
  484. package/src/PowerSearch/PowerSearch.tsx +10 -1
  485. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
  486. package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
  487. package/src/PowerSearch/usePowerSearchSource.ts +1 -2
  488. package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
  489. package/src/SelectableCard/SelectableCard.test.tsx +46 -4
  490. package/src/SelectableCard/SelectableCard.tsx +29 -16
  491. package/src/Selector/Selector.doc.mjs +7 -0
  492. package/src/Selector/Selector.test.tsx +92 -0
  493. package/src/Selector/Selector.tsx +16 -2
  494. package/src/Selector/hooks.ts +17 -0
  495. package/src/SideNav/SideNav.test.tsx +119 -3
  496. package/src/SideNav/SideNavCollapseButton.tsx +6 -1
  497. package/src/SideNav/SideNavHeading.tsx +24 -8
  498. package/src/SideNav/SideNavItem.tsx +5 -1
  499. package/src/Slider/Slider.test.tsx +75 -2
  500. package/src/Slider/Slider.tsx +21 -5
  501. package/src/Switch/Switch.test.tsx +32 -1
  502. package/src/TabList/Tab.tsx +2 -2
  503. package/src/TabList/TabMenu.tsx +2 -2
  504. package/src/Table/BaseTable.tsx +3 -5
  505. package/src/Table/TableCell.tsx +3 -3
  506. package/src/Table/TableHeaderCell.tsx +3 -3
  507. package/src/Table/index.ts +5 -0
  508. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
  509. package/src/Table/plugins/rowStatus/index.ts +7 -0
  510. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
  511. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
  512. package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
  513. package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
  514. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -1
  515. package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
  516. package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
  517. package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
  518. package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
  519. package/src/Table/useBaseTablePlugins.ts +10 -6
  520. package/src/Table/useTableRowStatus.doc.mjs +30 -0
  521. package/src/Table/useTableSelection.doc.mjs +65 -14
  522. package/src/Table/useTableTreeData.doc.mjs +29 -0
  523. package/src/Table/useTableTreeState.doc.mjs +2 -2
  524. package/src/TextArea/TextArea.doc.mjs +15 -0
  525. package/src/TextArea/TextArea.test.tsx +32 -1
  526. package/src/TextArea/TextArea.tsx +10 -0
  527. package/src/TextInput/TextInput.doc.mjs +15 -0
  528. package/src/TextInput/TextInput.test.tsx +44 -0
  529. package/src/TextInput/TextInput.tsx +13 -1
  530. package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
  531. package/src/Thumbnail/Thumbnail.test.tsx +98 -7
  532. package/src/Thumbnail/Thumbnail.tsx +142 -42
  533. package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
  534. package/src/TimeInput/TimeInput.doc.mjs +15 -0
  535. package/src/TimeInput/TimeInput.test.tsx +99 -1
  536. package/src/TimeInput/TimeInput.tsx +29 -6
  537. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  538. package/src/Timestamp/Timestamp.test.tsx +32 -0
  539. package/src/Timestamp/Timestamp.tsx +28 -8
  540. package/src/Toast/useToast.tsx +7 -8
  541. package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
  542. package/src/Tokenizer/Tokenizer.doc.mjs +30 -1
  543. package/src/Tokenizer/Tokenizer.test.tsx +206 -2
  544. package/src/Tokenizer/Tokenizer.tsx +26 -4
  545. package/src/TopNav/TopNav.test.tsx +125 -1
  546. package/src/TopNav/TopNavHeading.tsx +24 -8
  547. package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
  548. package/src/TopNav/TopNavMegaMenu.tsx +10 -4
  549. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
  550. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
  551. package/src/TopNav/TopNavMenu.test.tsx +118 -4
  552. package/src/TopNav/TopNavMenu.tsx +83 -5
  553. package/src/TreeList/TreeList.doc.mjs +22 -0
  554. package/src/TreeList/TreeList.test.tsx +232 -0
  555. package/src/TreeList/TreeList.tsx +18 -2
  556. package/src/TreeList/TreeListBranches.tsx +16 -2
  557. package/src/TreeList/TreeListItem.tsx +52 -12
  558. package/src/TreeList/TreeListTypes.ts +27 -1
  559. package/src/TreeList/index.ts +2 -2
  560. package/src/Typeahead/BaseTypeahead.tsx +1 -1
  561. package/src/Typeahead/Typeahead.doc.mjs +7 -0
  562. package/src/Typeahead/Typeahead.test.tsx +23 -0
  563. package/src/Typeahead/Typeahead.tsx +10 -0
  564. package/src/authoring/doc.ts +1 -3
  565. package/src/docs-types.ts +5 -0
  566. package/src/hooks/computeOverflow.test.ts +422 -0
  567. package/src/hooks/computeOverflow.ts +290 -0
  568. package/src/hooks/index.ts +2 -0
  569. package/src/hooks/isRtlElement.ts +27 -0
  570. package/src/hooks/useDevWarning.test.tsx +45 -0
  571. package/src/hooks/useDevWarning.ts +54 -0
  572. package/src/hooks/useGridFocus.doc.mjs +3 -3
  573. package/src/hooks/useGridFocus.test.tsx +41 -0
  574. package/src/hooks/useGridFocus.ts +21 -10
  575. package/src/hooks/useListFocus.doc.mjs +3 -3
  576. package/src/hooks/useListFocus.test.tsx +67 -1
  577. package/src/hooks/useListFocus.ts +21 -5
  578. package/src/hooks/useOverflow.test.ts +96 -4
  579. package/src/hooks/useOverflow.ts +74 -33
  580. package/src/i18n/InternationalizationContext.ts +4 -0
  581. package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
  582. package/src/i18n/InternationalizationProvider.tsx +12 -2
  583. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  584. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  585. package/src/i18n/getLocaleDirection.ts +29 -0
  586. package/src/i18n/index.ts +6 -0
  587. package/src/i18n/resolve.ts +9 -21
  588. package/src/i18n/useDirection.ts +29 -0
  589. package/src/reset.css +0 -26
  590. package/src/reset.test.ts +60 -0
  591. package/src/theme/Theme.tsx +11 -14
  592. package/src/theme/derivedVarRegistry.test.ts +1 -0
  593. package/src/theme/derivedVarRegistry.ts +6 -0
  594. package/src/theme/generateThemeRules.test.ts +107 -0
  595. package/src/theme/generateThemeRules.ts +56 -0
  596. package/src/theme/hct.ts +1 -1
  597. package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
  598. package/src/utils/devWarning.test.ts +56 -0
  599. package/src/utils/devWarning.ts +102 -0
  600. package/src/utils/index.ts +6 -0
  601. package/src/utils/plainDate.test.ts +22 -0
  602. package/src/utils/plainDate.ts +61 -0
  603. package/src/utils/types.ts +14 -0
@@ -100,6 +100,12 @@ export interface ContextRenderProps {
100
100
  * non-hashed selector for the layer.
101
101
  */
102
102
  role?: string;
103
+ /**
104
+ * Accessible name applied to the popover container via `aria-label`.
105
+ * Pair with `role` so layers with a named role (e.g. `'dialog'`) expose a
106
+ * proper name to assistive technology.
107
+ */
108
+ 'aria-label'?: string;
103
109
  /**
104
110
  * StyleX styles for the popover container.
105
111
  */
@@ -525,6 +531,7 @@ export function useLayer(
525
531
  alignment = 'center',
526
532
  positioning = 'anchor',
527
533
  role,
534
+ 'aria-label': ariaLabel,
528
535
  xstyle,
529
536
  className: extraClassName,
530
537
  style: extraStyle,
@@ -561,6 +568,7 @@ export function useLayer(
561
568
  ref={popoverRefCallback}
562
569
  id={id}
563
570
  role={role}
571
+ aria-label={ariaLabel}
564
572
  popover={lightDismiss ? 'auto' : 'manual'}
565
573
  className={combinedClassName}
566
574
  style={{...stylexResult.style, ...anchorStyle, ...extraStyle}}
@@ -199,7 +199,7 @@ const styles = stylex.create({
199
199
  closeButton: {
200
200
  position: 'absolute',
201
201
  top: spacingVars['--spacing-3'],
202
- right: spacingVars['--spacing-3'],
202
+ insetInlineEnd: spacingVars['--spacing-3'],
203
203
  zIndex: 1,
204
204
  },
205
205
  navButton: {
@@ -209,15 +209,15 @@ const styles = stylex.create({
209
209
  zIndex: 1,
210
210
  },
211
211
  navPrev: {
212
- left: spacingVars['--spacing-3'],
212
+ insetInlineStart: spacingVars['--spacing-3'],
213
213
  },
214
214
  navNext: {
215
- right: spacingVars['--spacing-3'],
215
+ insetInlineEnd: spacingVars['--spacing-3'],
216
216
  },
217
217
  counter: {
218
218
  position: 'absolute',
219
219
  top: spacingVars['--spacing-3'],
220
- left: spacingVars['--spacing-3'],
220
+ insetInlineStart: spacingVars['--spacing-3'],
221
221
  color: colorVars['--color-on-dark'],
222
222
  fontSize: typeScaleVars['--text-body-size'],
223
223
  lineHeight: typeScaleVars['--text-body-leading'],
@@ -436,11 +436,7 @@ describe('List', () => {
436
436
  it('sets target on anchor when provided', () => {
437
437
  const {container} = render(
438
438
  <List>
439
- <ListItem
440
- label="External"
441
- href="https://example.com"
442
- target="_blank"
443
- />
439
+ <ListItem label="External" href="https://example.com" target="_blank" />
444
440
  </List>,
445
441
  );
446
442
  const anchor = container.querySelector('a');
@@ -500,17 +496,21 @@ describe('List', () => {
500
496
  // Selected state
501
497
  // ===========================================================================
502
498
 
503
- it('applies aria-selected when isSelected', () => {
499
+ it('conveys selection via aria-current when isSelected', () => {
500
+ // aria-selected is not permitted on an li (role listitem, axe:
501
+ // aria-allowed-attr), so selection is exposed via aria-current — valid on
502
+ // any element — so screen-reader users are still told which item is chosen.
504
503
  const {container} = render(
505
504
  <List>
506
505
  <ListItem label="Selected" isSelected onClick={() => {}} />
507
506
  </List>,
508
507
  );
509
508
  const item = container.querySelector('.astryx-item');
510
- expect(item).toHaveAttribute('aria-selected', 'true');
509
+ expect(item).not.toHaveAttribute('aria-selected');
510
+ expect(item).toHaveAttribute('aria-current', 'true');
511
511
  });
512
512
 
513
- it('does not apply aria-selected when not selected', () => {
513
+ it('applies neither aria-selected nor aria-current when not selected', () => {
514
514
  const {container} = render(
515
515
  <List>
516
516
  <ListItem label="Not Selected" />
@@ -518,6 +518,7 @@ describe('List', () => {
518
518
  );
519
519
  const li = container.querySelector('li');
520
520
  expect(li).not.toHaveAttribute('aria-selected');
521
+ expect(li).not.toHaveAttribute('aria-current');
521
522
  });
522
523
 
523
524
  // ===========================================================================
@@ -29,6 +29,7 @@
29
29
  import {
30
30
  useCallback,
31
31
  useEffect,
32
+ useId,
32
33
  useMemo,
33
34
  useRef,
34
35
  useState,
@@ -295,6 +296,10 @@ export function MobileNav({
295
296
  // Read from AppShell context as fallback
296
297
  const appShellMobile = useAppShellMobile();
297
298
  const isOpen = isOpenProp ?? appShellMobile.isMobileNavOpen;
299
+ // Share the id from AppShell context so the toggle's aria-controls resolves to
300
+ // this drawer; fall back to a locally generated id when used standalone.
301
+ const fallbackId = useId();
302
+ const dialogId = appShellMobile.mobileNavId || fallbackId;
298
303
  const onOpenChange = useMemo(
299
304
  () =>
300
305
  onOpenChangeProp ??
@@ -411,6 +416,7 @@ export function MobileNav({
411
416
  return (
412
417
  <dialog
413
418
  ref={mergeRefs(ref, dialogRef)}
419
+ id={dialogId}
414
420
  {...mergeProps(
415
421
  themeProps('mobile-nav', {side: resolvedSide}),
416
422
  stylex.props(
@@ -425,7 +431,12 @@ export function MobileNav({
425
431
  )}
426
432
  {...rest}
427
433
  data-testid={testId}
428
- aria-label={label ?? (typeof header === 'string' ? header : t('@astryx.mobileNav.navigation'))}
434
+ aria-label={
435
+ label ??
436
+ (typeof header === 'string'
437
+ ? header
438
+ : t('@astryx.mobileNav.navigation'))
439
+ }
429
440
  onClick={composeEventHandlers(onClickProp, handleDialogClick)}
430
441
  onCancel={handleCancel}>
431
442
  {/* Drawer panel — tabIndex so showModal() focuses the drawer, not the close button */}
@@ -0,0 +1,116 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file MobileNavToggle.test.tsx
5
+ * @input Uses vitest, @testing-library/react, AppShell + SideNav
6
+ * @output Unit tests for MobileNavToggle ARIA wiring
7
+ * @position Testing; validates MobileNavToggle.tsx exposes aria-expanded and
8
+ * aria-controls so screen-reader users know the drawer state and target.
9
+ *
10
+ * SYNC: When MobileNavToggle.tsx changes, update tests to match new behavior
11
+ */
12
+
13
+ import {
14
+ describe,
15
+ it,
16
+ expect,
17
+ vi,
18
+ beforeAll,
19
+ beforeEach,
20
+ afterEach,
21
+ } from 'vitest';
22
+ import {render, screen, fireEvent} from '@testing-library/react';
23
+ import {AppShell} from '../AppShell/AppShell';
24
+ import {SideNav, SideNavItem, SideNavSection} from '../SideNav';
25
+
26
+ // jsdom doesn't implement showModal/close on <dialog>, so we mock them
27
+ beforeAll(() => {
28
+ HTMLDialogElement.prototype.showModal =
29
+ HTMLDialogElement.prototype.showModal ||
30
+ function (this: HTMLDialogElement) {
31
+ this.setAttribute('open', '');
32
+ };
33
+ HTMLDialogElement.prototype.close =
34
+ HTMLDialogElement.prototype.close ||
35
+ function (this: HTMLDialogElement) {
36
+ this.removeAttribute('open');
37
+ };
38
+ });
39
+
40
+ class MockResizeObserver {
41
+ observe() {}
42
+ unobserve() {}
43
+ disconnect() {}
44
+ }
45
+ vi.stubGlobal('ResizeObserver', MockResizeObserver);
46
+
47
+ function createMockMatchMedia(matches: boolean) {
48
+ return {
49
+ matches,
50
+ media: '',
51
+ onchange: null,
52
+ addEventListener: vi.fn(),
53
+ removeEventListener: vi.fn(),
54
+ addListener: vi.fn(),
55
+ removeListener: vi.fn(),
56
+ dispatchEvent: vi.fn(),
57
+ };
58
+ }
59
+
60
+ beforeEach(() => {
61
+ // Below the breakpoint so the mobile nav (and its toggle) render.
62
+ vi.stubGlobal(
63
+ 'matchMedia',
64
+ vi.fn().mockReturnValue(createMockMatchMedia(true)),
65
+ );
66
+ });
67
+
68
+ afterEach(() => {
69
+ vi.restoreAllMocks();
70
+ });
71
+
72
+ function TestShell() {
73
+ return (
74
+ <AppShell
75
+ sideNav={
76
+ <SideNav>
77
+ <SideNavSection title="Test" isHeaderHidden>
78
+ <SideNavItem label="Home" />
79
+ </SideNavSection>
80
+ </SideNav>
81
+ }
82
+ mobileNav={{breakpoint: 'md'}}>
83
+ <div>Content</div>
84
+ </AppShell>
85
+ );
86
+ }
87
+
88
+ describe('MobileNavToggle ARIA wiring', () => {
89
+ it('exposes aria-expanded="false" when the drawer is closed', () => {
90
+ render(<TestShell />);
91
+
92
+ const toggle = screen.getByRole('button', {name: /open navigation/i});
93
+ expect(toggle).toHaveAttribute('aria-expanded', 'false');
94
+ });
95
+
96
+ it('exposes aria-expanded="true" after opening the drawer', () => {
97
+ render(<TestShell />);
98
+
99
+ const toggle = screen.getByRole('button', {name: /open navigation/i});
100
+ fireEvent.click(toggle);
101
+ expect(toggle).toHaveAttribute('aria-expanded', 'true');
102
+ });
103
+
104
+ it('references the nav drawer via aria-controls that resolves to the dialog', () => {
105
+ render(<TestShell />);
106
+
107
+ const toggle = screen.getByRole('button', {name: /open navigation/i});
108
+ const controls = toggle.getAttribute('aria-controls');
109
+ expect(controls).toBeTruthy();
110
+
111
+ const target = document.getElementById(controls!);
112
+ expect(target).not.toBeNull();
113
+ expect(target).toBe(screen.getAllByRole('dialog', {hidden: true})[0]);
114
+ expect(target?.tagName).toBe('DIALOG');
115
+ });
116
+ });
@@ -69,7 +69,13 @@ export function MobileNavToggle({
69
69
  }: MobileNavToggleProps) {
70
70
  const t = useTranslator();
71
71
  const label = labelFromProps ?? t('@astryx.mobileNav.toggle.open');
72
- const {isMobile, isMobileNavEnabled, toggleMobileNav} = useAppShellMobile();
72
+ const {
73
+ isMobile,
74
+ isMobileNavEnabled,
75
+ isMobileNavOpen,
76
+ mobileNavId,
77
+ toggleMobileNav,
78
+ } = useAppShellMobile();
73
79
 
74
80
  // Don't render above the breakpoint or when mobile nav is disabled
75
81
  if (!isMobile || !isMobileNavEnabled) {
@@ -83,6 +89,8 @@ export function MobileNavToggle({
83
89
  label={label}
84
90
  icon={children ?? <Icon icon="menu" color="inherit" />}
85
91
  onClick={toggleMobileNav}
92
+ aria-expanded={isMobileNavOpen}
93
+ aria-controls={mobileNavId || undefined}
86
94
  data-testid={testId ?? 'mobile-nav-toggle'}
87
95
  xstyle={xstyle}
88
96
  className={className}
@@ -99,7 +99,8 @@ export const docs = {
99
99
  {
100
100
  name: 'hasSearch',
101
101
  type: 'boolean',
102
- description: 'Whether to show a search input for filtering options.',
102
+ description:
103
+ 'Whether to show a search input for filtering options. As the user types, the match count (or "No results found") is announced to screen readers via a polite live region.',
103
104
  },
104
105
  {
105
106
  name: 'searchPlaceholder',
@@ -154,6 +155,13 @@ export const docs = {
154
155
  type: "{type: 'error' | 'warning' | 'success', message?: string}",
155
156
  description: 'Validation status with an optional message.',
156
157
  },
158
+ {
159
+ name: 'statusVariant',
160
+ type: "'attached' | 'detached'",
161
+ description:
162
+ '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.',
163
+ default: "'attached'",
164
+ },
157
165
  {
158
166
  name: 'renderOption',
159
167
  type: '(option: MultiSelectorOptionData) => ReactNode',
@@ -239,7 +247,8 @@ export const docsZh = {
239
247
  hasSearch: '是否显示用于过滤选项的搜索输入。',
240
248
  searchPlaceholder: '搜索输入的占位文本。',
241
249
  isDisabled: '禁用选择器。',
242
- htmlName: '用于表单提交的 HTML name 属性。为每个已选值渲染一个隐藏输入,类似原生多选。',
250
+ htmlName:
251
+ '用于表单提交的 HTML name 属性。为每个已选值渲染一个隐藏输入,类似原生多选。',
243
252
  disabledMessage:
244
253
  '解释选择器被禁用的原因。与 isDisabled 一起使用时,悬停/键盘聚焦时显示工具提示,并通过 aria-disabled 保持触发器可聚焦(仍无法激活)。请使用此属性,而不是用 Tooltip 包裹被禁用的选择器。',
245
254
  isLabelHidden: '视觉上隐藏标签同时保持其可访问性。',
@@ -248,6 +257,7 @@ export const docsZh = {
248
257
  isRequired: '将字段标记为必填。',
249
258
  isLoading: '在触发器中显示加载旋转器。',
250
259
  status: '带可选消息的验证状态。',
260
+ statusVariant: '状态消息的放置方式:attached 直接叠加在输入框下方;detached 作为独立元素浮于下方并留有间距。',
251
261
  renderOption:
252
262
  '每个可选选项的自定义渲染函数。不会用于分隔线、分组或全选行。',
253
263
  xstyle: '布局自定义的 StyleX 样式,必须是 stylex.create() 值。',
@@ -373,6 +383,7 @@ export const docsDense = {
373
383
  isRequired: 'marks required',
374
384
  isLoading: 'spinner in trigger',
375
385
  status: 'validation status w/ optional message',
386
+ statusVariant: 'How status message is placed: attached overlaps below input; detached floats below w/ spacing.',
376
387
  renderOption:
377
388
  'custom render fn per selectable option; not dividers/sections/select-all',
378
389
  xstyle: 'StyleX layout styles; stylex.create() only',
@@ -10,7 +10,13 @@
10
10
  */
11
11
 
12
12
  import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
13
- import {render, screen, fireEvent, waitFor} from '@testing-library/react';
13
+ import {
14
+ render,
15
+ screen,
16
+ fireEvent,
17
+ waitFor,
18
+ within,
19
+ } from '@testing-library/react';
14
20
  import userEvent from '@testing-library/user-event';
15
21
  import {MultiSelector} from './MultiSelector';
16
22
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
@@ -360,6 +366,30 @@ describe('MultiSelector', () => {
360
366
  expect(activeId).toBeTruthy();
361
367
  });
362
368
 
369
+ it('End/Home jump the highlight to the last/first option (non-search)', async () => {
370
+ const user = userEvent.setup();
371
+ render(
372
+ <MultiSelector
373
+ label="Fruit"
374
+ options={defaultOptions}
375
+ value={[]}
376
+ onChange={() => {}}
377
+ />,
378
+ );
379
+
380
+ const trigger = screen.getByRole('combobox');
381
+ await user.click(trigger);
382
+ const options = screen.getAllByRole('option', h);
383
+
384
+ await user.keyboard('{End}');
385
+ expect(trigger).toHaveAttribute(
386
+ 'aria-activedescendant',
387
+ options[options.length - 1].id,
388
+ );
389
+ await user.keyboard('{Home}');
390
+ expect(trigger).toHaveAttribute('aria-activedescendant', options[0].id);
391
+ });
392
+
363
393
  it('toggles item with Enter key', async () => {
364
394
  const user = userEvent.setup();
365
395
  const onChange = vi.fn();
@@ -535,6 +565,65 @@ describe('MultiSelector', () => {
535
565
  expect(options).toHaveLength(1);
536
566
  });
537
567
 
568
+ it('PageDown/PageUp jump the highlight to the last/first filtered option', async () => {
569
+ const user = userEvent.setup();
570
+ render(
571
+ <MultiSelector
572
+ label="Fruit"
573
+ options={defaultOptions}
574
+ value={[]}
575
+ onChange={() => {}}
576
+ hasSearch
577
+ />,
578
+ );
579
+
580
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
581
+ const searchInput = screen.getByRole('combobox', h);
582
+ // Filter to Banana and Orange so "last" means last *visible* option.
583
+ await user.type(searchInput, 'an');
584
+ const options = screen.getAllByRole('option', h);
585
+ expect(options).toHaveLength(2);
586
+
587
+ await user.keyboard('{PageDown}');
588
+ expect(searchInput).toHaveAttribute(
589
+ 'aria-activedescendant',
590
+ options[options.length - 1].id,
591
+ );
592
+ await user.keyboard('{PageUp}');
593
+ expect(searchInput).toHaveAttribute('aria-activedescendant', options[0].id);
594
+ });
595
+
596
+ it('Home/End move the search caret, not the option highlight', async () => {
597
+ const user = userEvent.setup();
598
+ render(
599
+ <MultiSelector
600
+ label="Fruit"
601
+ options={defaultOptions}
602
+ value={[]}
603
+ onChange={() => {}}
604
+ hasSearch
605
+ />,
606
+ );
607
+
608
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
609
+ const searchInput = screen.getByRole<HTMLInputElement>('combobox', h);
610
+ await user.type(searchInput, 'an');
611
+ expect(searchInput.selectionStart).toBe(2);
612
+ const activeBefore = searchInput.getAttribute('aria-activedescendant');
613
+ // Home/End stay on the input for caret movement (APG editable combobox);
614
+ // the option highlight must not move.
615
+ await user.keyboard('{Home}');
616
+ expect(searchInput.selectionStart).toBe(0);
617
+ expect(searchInput.getAttribute('aria-activedescendant')).toBe(
618
+ activeBefore,
619
+ );
620
+ await user.keyboard('{End}');
621
+ expect(searchInput.selectionStart).toBe(2);
622
+ expect(searchInput.getAttribute('aria-activedescendant')).toBe(
623
+ activeBefore,
624
+ );
625
+ });
626
+
538
627
  it('shows empty state when search has no results', async () => {
539
628
  const user = userEvent.setup();
540
629
  render(
@@ -551,7 +640,85 @@ describe('MultiSelector', () => {
551
640
  const searchInput = screen.getByRole('combobox', h);
552
641
  await user.type(searchInput, 'xyz');
553
642
 
554
- expect(screen.getByText('No results found')).toBeInTheDocument();
643
+ expect(
644
+ within(screen.getByRole('listbox', h)).getByText('No results found'),
645
+ ).toBeInTheDocument();
646
+ });
647
+
648
+ describe('result announcements', () => {
649
+ it('announces the match count politely while searching', async () => {
650
+ const user = userEvent.setup();
651
+ render(
652
+ <MultiSelector
653
+ label="Fruit"
654
+ options={defaultOptions}
655
+ value={EMPTY_VALUE}
656
+ onChange={() => {}}
657
+ hasSearch
658
+ />,
659
+ );
660
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
661
+ // "an" matches Banana and Orange.
662
+ await user.type(screen.getByRole('combobox', h), 'an');
663
+ await waitFor(() => {
664
+ expect(politeRegion()).toHaveTextContent('2 results');
665
+ });
666
+ });
667
+
668
+ it('announces the singular form when one option matches', async () => {
669
+ const user = userEvent.setup();
670
+ render(
671
+ <MultiSelector
672
+ label="Fruit"
673
+ options={defaultOptions}
674
+ value={EMPTY_VALUE}
675
+ onChange={() => {}}
676
+ hasSearch
677
+ />,
678
+ );
679
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
680
+ // "app" matches only Apple. Anchored so it cannot pass on "1 results".
681
+ await user.type(screen.getByRole('combobox', h), 'app');
682
+ await waitFor(() => {
683
+ expect(politeRegion()).toHaveTextContent(/^1 result$/);
684
+ });
685
+ });
686
+
687
+ it('announces "No results found" when nothing matches', async () => {
688
+ const user = userEvent.setup();
689
+ render(
690
+ <MultiSelector
691
+ label="Fruit"
692
+ options={defaultOptions}
693
+ value={EMPTY_VALUE}
694
+ onChange={() => {}}
695
+ hasSearch
696
+ />,
697
+ );
698
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
699
+ await user.type(screen.getByRole('combobox', h), 'xyz');
700
+ await waitFor(() => {
701
+ expect(politeRegion()).toHaveTextContent('No results found');
702
+ });
703
+ });
704
+
705
+ it('does not announce results until the user searches', async () => {
706
+ const user = userEvent.setup();
707
+ render(
708
+ <MultiSelector
709
+ label="Fruit"
710
+ options={defaultOptions}
711
+ value={EMPTY_VALUE}
712
+ onChange={() => {}}
713
+ hasSearch
714
+ />,
715
+ );
716
+ // Popover closed: nothing announced.
717
+ expect(politeRegion()?.textContent ?? '').toBe('');
718
+ // Open with an empty query: still nothing announced.
719
+ await user.click(screen.getByRole('button', {name: 'Fruit'}));
720
+ expect(politeRegion()?.textContent ?? '').toBe('');
721
+ });
555
722
  });
556
723
 
557
724
  it('renders with description', () => {
@@ -1072,7 +1239,32 @@ describe('MultiSelector', () => {
1072
1239
  />
1073
1240
  </form>,
1074
1241
  );
1075
- expect([...new FormData(container.querySelector('form')!).keys()]).toEqual([]);
1242
+ expect([
1243
+ ...new FormData(container.querySelector('form')!).keys(),
1244
+ ]).toEqual([]);
1076
1245
  });
1077
1246
  });
1078
1247
  });
1248
+
1249
+
1250
+ describe('MultiSelector statusVariant forwarding', () => {
1251
+ it('defaults to attached (status renders with data-variant="attached")', () => {
1252
+ const {container} = render(
1253
+ <MultiSelector label="Fruit" options={['Apple', 'Banana']} value={[]} onChange={() => {}} status={{type: 'error', message: 'Required'}} />,
1254
+ );
1255
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1256
+ 'data-variant',
1257
+ 'attached',
1258
+ );
1259
+ });
1260
+
1261
+ it('forwards statusVariant="detached" to the underlying Field status', () => {
1262
+ const {container} = render(
1263
+ <MultiSelector label="Fruit" options={['Apple', 'Banana']} value={[]} onChange={() => {}} status={{type: 'error', message: 'Required'}} statusVariant="detached" />,
1264
+ );
1265
+ expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
1266
+ 'data-variant',
1267
+ 'detached',
1268
+ );
1269
+ });
1270
+ });