@astryxdesign/core 0.1.8 → 0.1.9-canary.09e9ddd

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 (610) 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/Citation/Citation.d.ts +22 -1
  81. package/dist/Citation/Citation.d.ts.map +1 -1
  82. package/dist/Citation/Citation.js +20 -6
  83. package/dist/ClickableCard/ClickableCard.d.ts +9 -2
  84. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  85. package/dist/ClickableCard/ClickableCard.js +5 -2
  86. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  87. package/dist/CodeBlock/CodeBlock.js +9 -2
  88. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  89. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  90. package/dist/CommandPalette/CommandPalette.js +3 -1
  91. package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
  92. package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
  93. package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
  94. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  95. package/dist/CommandPalette/CommandPaletteInput.js +6 -1
  96. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  97. package/dist/DateInput/DateInput.d.ts +55 -2
  98. package/dist/DateInput/DateInput.d.ts.map +1 -1
  99. package/dist/DateInput/DateInput.js +28 -2
  100. package/dist/DateInput/index.d.ts +1 -1
  101. package/dist/DateInput/index.d.ts.map +1 -1
  102. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  103. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  104. package/dist/DateRangeInput/DateRangeInput.js +3 -1
  105. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  106. package/dist/DateTimeInput/DateTimeInput.js +18 -3
  107. package/dist/Dialog/Dialog.d.ts +3 -0
  108. package/dist/Dialog/Dialog.d.ts.map +1 -1
  109. package/dist/Dialog/Dialog.js +57 -6
  110. package/dist/Dialog/DialogContext.d.ts +7 -0
  111. package/dist/Dialog/DialogContext.d.ts.map +1 -1
  112. package/dist/Dialog/DialogContext.js +2 -2
  113. package/dist/Dialog/DialogHeader.d.ts +5 -2
  114. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  115. package/dist/Dialog/DialogHeader.js +6 -1
  116. package/dist/Divider/Divider.js +1 -1
  117. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
  118. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  119. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
  120. package/dist/DropdownMenu/DropdownMenuItem.js +1 -1
  121. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
  122. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  123. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
  124. package/dist/Field/Field.d.ts.map +1 -1
  125. package/dist/Field/Field.js +2 -3
  126. package/dist/Field/FieldLabel.d.ts +1 -1
  127. package/dist/Field/FieldLabel.d.ts.map +1 -1
  128. package/dist/Field/FieldLabel.js +43 -16
  129. package/dist/FieldStatus/FieldStatus.d.ts +15 -0
  130. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  131. package/dist/FieldStatus/FieldStatus.js +58 -6
  132. package/dist/FileInput/FileInput.d.ts +9 -2
  133. package/dist/FileInput/FileInput.d.ts.map +1 -1
  134. package/dist/FileInput/FileInput.js +42 -20
  135. package/dist/HoverCard/HoverCard.d.ts +9 -1
  136. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  137. package/dist/HoverCard/HoverCard.js +2 -0
  138. package/dist/HoverCard/useHoverCard.d.ts +8 -0
  139. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  140. package/dist/HoverCard/useHoverCard.js +7 -2
  141. package/dist/Icon/Icon.d.ts +7 -2
  142. package/dist/Icon/Icon.d.ts.map +1 -1
  143. package/dist/Item/Item.d.ts +6 -1
  144. package/dist/Item/Item.d.ts.map +1 -1
  145. package/dist/Item/Item.js +22 -1
  146. package/dist/Layer/useLayer.d.ts +6 -0
  147. package/dist/Layer/useLayer.d.ts.map +1 -1
  148. package/dist/Layer/useLayer.js +2 -0
  149. package/dist/Lightbox/Lightbox.js +4 -4
  150. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  151. package/dist/MobileNav/MobileNav.js +6 -1
  152. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  153. package/dist/MobileNav/MobileNavToggle.js +4 -0
  154. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  155. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  156. package/dist/MultiSelector/MultiSelector.js +41 -12
  157. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  158. package/dist/MultiSelector/hooks.js +16 -0
  159. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  160. package/dist/NumberInput/NumberInput.d.ts +9 -2
  161. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  162. package/dist/NumberInput/NumberInput.js +8 -1
  163. package/dist/Outline/Outline.d.ts +0 -1
  164. package/dist/Outline/Outline.d.ts.map +1 -1
  165. package/dist/Outline/Outline.js +0 -1
  166. package/dist/OverflowList/OverflowList.d.ts +20 -3
  167. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  168. package/dist/OverflowList/OverflowList.js +29 -4
  169. package/dist/Pagination/Pagination.d.ts.map +1 -1
  170. package/dist/Pagination/Pagination.js +11 -3
  171. package/dist/Popover/Popover.d.ts.map +1 -1
  172. package/dist/Popover/Popover.js +3 -2
  173. package/dist/Popover/usePopover.d.ts.map +1 -1
  174. package/dist/Popover/usePopover.js +3 -9
  175. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  176. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  177. package/dist/PowerSearch/PowerSearch.js +2 -0
  178. package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
  179. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  180. package/dist/SelectableCard/SelectableCard.d.ts +9 -2
  181. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  182. package/dist/SelectableCard/SelectableCard.js +16 -13
  183. package/dist/Selector/Selector.d.ts +8 -0
  184. package/dist/Selector/Selector.d.ts.map +1 -1
  185. package/dist/Selector/Selector.js +7 -3
  186. package/dist/Selector/hooks.d.ts.map +1 -1
  187. package/dist/Selector/hooks.js +16 -0
  188. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  189. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  190. package/dist/SideNav/SideNavHeading.js +21 -8
  191. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  192. package/dist/Slider/Slider.d.ts.map +1 -1
  193. package/dist/Slider/Slider.js +19 -2
  194. package/dist/Stack/stack.stylex.d.ts +9 -9
  195. package/dist/TabList/Tab.js +2 -2
  196. package/dist/TabList/TabMenu.js +1 -1
  197. package/dist/Table/BaseTable.d.ts.map +1 -1
  198. package/dist/Table/BaseTable.js +3 -2
  199. package/dist/Table/TableCell.js +3 -3
  200. package/dist/Table/TableHeaderCell.js +3 -3
  201. package/dist/Table/index.d.ts +2 -0
  202. package/dist/Table/index.d.ts.map +1 -1
  203. package/dist/Table/index.js +1 -0
  204. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  205. package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
  206. package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
  207. package/dist/Table/plugins/rowStatus/index.js +3 -0
  208. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
  209. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
  210. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
  211. package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
  212. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  213. package/dist/Table/plugins/selection/useTableSelection.js +4 -1
  214. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +1 -1
  215. package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
  216. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  217. package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
  218. package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
  219. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
  220. package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
  221. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  222. package/dist/Table/useBaseTablePlugins.js +5 -3
  223. package/dist/TextArea/TextArea.d.ts +9 -1
  224. package/dist/TextArea/TextArea.d.ts.map +1 -1
  225. package/dist/TextArea/TextArea.js +2 -0
  226. package/dist/TextInput/TextInput.d.ts +9 -2
  227. package/dist/TextInput/TextInput.d.ts.map +1 -1
  228. package/dist/TextInput/TextInput.js +6 -1
  229. package/dist/Thumbnail/Thumbnail.d.ts +26 -5
  230. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  231. package/dist/Thumbnail/Thumbnail.js +97 -54
  232. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
  233. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
  234. package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
  235. package/dist/TimeInput/TimeInput.d.ts +9 -2
  236. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  237. package/dist/TimeInput/TimeInput.js +17 -4
  238. package/dist/Timestamp/Timestamp.d.ts +3 -1
  239. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  240. package/dist/Timestamp/Timestamp.js +8 -6
  241. package/dist/Toast/useToast.d.ts.map +1 -1
  242. package/dist/Toast/useToast.js +2 -5
  243. package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
  244. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  245. package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
  246. package/dist/Tokenizer/Tokenizer.d.ts +10 -3
  247. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  248. package/dist/Tokenizer/Tokenizer.js +18 -4
  249. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  250. package/dist/TopNav/TopNavHeading.js +18 -8
  251. package/dist/TopNav/TopNavMegaMenu.js +10 -4
  252. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
  253. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  254. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
  255. package/dist/TopNav/TopNavMenu.d.ts +2 -1
  256. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  257. package/dist/TopNav/TopNavMenu.js +68 -6
  258. package/dist/TreeList/TreeList.d.ts +12 -3
  259. package/dist/TreeList/TreeList.d.ts.map +1 -1
  260. package/dist/TreeList/TreeList.js +2 -0
  261. package/dist/TreeList/TreeListBranches.d.ts +5 -0
  262. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  263. package/dist/TreeList/TreeListBranches.js +10 -4
  264. package/dist/TreeList/TreeListItem.d.ts +8 -2
  265. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  266. package/dist/TreeList/TreeListItem.js +28 -8
  267. package/dist/TreeList/TreeListTypes.d.ts +25 -1
  268. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  269. package/dist/TreeList/index.d.ts +2 -2
  270. package/dist/TreeList/index.d.ts.map +1 -1
  271. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  272. package/dist/Typeahead/BaseTypeahead.js +20 -11
  273. package/dist/Typeahead/Typeahead.d.ts +9 -2
  274. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  275. package/dist/Typeahead/Typeahead.js +2 -0
  276. package/dist/astryx.css +41 -31
  277. package/dist/astryx.umd.js +51 -51
  278. package/dist/astryx.umd.js.map +4 -4
  279. package/dist/authoring/doc.d.ts.map +1 -1
  280. package/dist/docs-types.d.ts +8 -0
  281. package/dist/docs-types.d.ts.map +1 -1
  282. package/dist/hooks/computeOverflow.d.ts +47 -0
  283. package/dist/hooks/computeOverflow.d.ts.map +1 -0
  284. package/dist/hooks/computeOverflow.js +213 -0
  285. package/dist/hooks/index.d.ts +1 -0
  286. package/dist/hooks/index.d.ts.map +1 -1
  287. package/dist/hooks/index.js +2 -1
  288. package/dist/hooks/isRtlElement.d.ts +18 -0
  289. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  290. package/dist/hooks/isRtlElement.js +27 -0
  291. package/dist/hooks/useDevWarning.d.ts +18 -0
  292. package/dist/hooks/useDevWarning.d.ts.map +1 -0
  293. package/dist/hooks/useDevWarning.js +49 -0
  294. package/dist/hooks/useGridFocus.d.ts +6 -1
  295. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  296. package/dist/hooks/useGridFocus.js +12 -9
  297. package/dist/hooks/useListFocus.d.ts +6 -1
  298. package/dist/hooks/useListFocus.d.ts.map +1 -1
  299. package/dist/hooks/useListFocus.js +12 -4
  300. package/dist/hooks/useOverflow.d.ts +19 -0
  301. package/dist/hooks/useOverflow.d.ts.map +1 -1
  302. package/dist/hooks/useOverflow.js +36 -25
  303. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  304. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  305. package/dist/i18n/InternationalizationContext.js +3 -0
  306. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  307. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  308. package/dist/i18n/InternationalizationProvider.js +5 -1
  309. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  310. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  311. package/dist/i18n/getLocaleDirection.js +29 -0
  312. package/dist/i18n/index.d.ts +6 -0
  313. package/dist/i18n/index.d.ts.map +1 -1
  314. package/dist/i18n/index.js +7 -1
  315. package/dist/i18n/resolve.d.ts.map +1 -1
  316. package/dist/i18n/resolve.js +7 -18
  317. package/dist/i18n/useDirection.d.ts +2 -0
  318. package/dist/i18n/useDirection.d.ts.map +1 -0
  319. package/dist/i18n/useDirection.js +27 -0
  320. package/dist/theme/Theme.d.ts.map +1 -1
  321. package/dist/theme/Theme.js +2 -7
  322. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  323. package/dist/theme/derivedVarRegistry.js +13 -0
  324. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  325. package/dist/theme/generateThemeRules.js +51 -0
  326. package/dist/theme/hct.d.ts +0 -1
  327. package/dist/theme/hct.d.ts.map +1 -1
  328. package/dist/theme/hct.js +1 -1
  329. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  330. package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
  331. package/dist/utils/devWarning.d.ts +42 -0
  332. package/dist/utils/devWarning.d.ts.map +1 -0
  333. package/dist/utils/devWarning.js +88 -0
  334. package/dist/utils/index.d.ts +3 -1
  335. package/dist/utils/index.d.ts.map +1 -1
  336. package/dist/utils/index.js +3 -2
  337. package/dist/utils/plainDate.d.ts +30 -0
  338. package/dist/utils/plainDate.d.ts.map +1 -1
  339. package/dist/utils/plainDate.js +53 -0
  340. package/dist/utils/types.d.ts +13 -0
  341. package/dist/utils/types.d.ts.map +1 -1
  342. package/locales/en.json +32 -0
  343. package/locales/fr-FR.json +14 -0
  344. package/locales/pseudo.json +24 -0
  345. package/package.json +1 -1
  346. package/src/AppShell/AppShell.tsx +6 -0
  347. package/src/AppShell/AppShellMobileContext.tsx +8 -0
  348. package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
  349. package/src/Avatar/Avatar.doc.mjs +60 -3
  350. package/src/Avatar/Avatar.test.tsx +281 -1
  351. package/src/Avatar/Avatar.tsx +324 -64
  352. package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
  353. package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
  354. package/src/Avatar/AvatarStatusDot.tsx +178 -21
  355. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  356. package/src/AvatarGroup/AvatarGroup.test.tsx +125 -0
  357. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  358. package/src/AvatarGroup/AvatarGroupOverflow.tsx +1 -0
  359. package/src/Banner/Banner.doc.mjs +9 -0
  360. package/src/Banner/Banner.test.tsx +30 -0
  361. package/src/Banner/Banner.tsx +53 -9
  362. package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
  363. package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
  364. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
  365. package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
  366. package/src/Breadcrumbs/index.ts +27 -0
  367. package/src/Button/Button.doc.mjs +9 -4
  368. package/src/Button/Button.test.tsx +49 -0
  369. package/src/Button/Button.tsx +27 -3
  370. package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
  371. package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
  372. package/src/ButtonGroup/ButtonGroup.tsx +32 -0
  373. package/src/Calendar/Calendar.doc.mjs +12 -1
  374. package/src/Calendar/Calendar.test.tsx +193 -0
  375. package/src/Calendar/Calendar.tsx +38 -16
  376. package/src/Calendar/dayCellUtils.test.ts +5 -0
  377. package/src/Calendar/dayCellUtils.ts +1 -1
  378. package/src/Card/Card.doc.mjs +9 -0
  379. package/src/Card/Card.test.tsx +21 -3
  380. package/src/Card/Card.tsx +35 -2
  381. package/src/Carousel/Carousel.doc.mjs +1 -0
  382. package/src/Carousel/Carousel.test.tsx +53 -0
  383. package/src/Carousel/Carousel.tsx +34 -4
  384. package/src/Chat/ChatComposer.doc.mjs +12 -3
  385. package/src/Chat/ChatComposer.test.tsx +115 -0
  386. package/src/Chat/ChatComposer.tsx +73 -9
  387. package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
  388. package/src/Chat/ChatComposerDrawer.tsx +11 -1
  389. package/src/Chat/ChatComposerInput.doc.mjs +7 -0
  390. package/src/Chat/ChatComposerInput.test.tsx +103 -0
  391. package/src/Chat/ChatComposerInput.tsx +51 -5
  392. package/src/Chat/ChatContext.tsx +37 -10
  393. package/src/Chat/ChatDictationButton.tsx +4 -1
  394. package/src/Chat/ChatLayout.tsx +7 -5
  395. package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
  396. package/src/Chat/ChatMessageMetadata.tsx +1 -2
  397. package/src/Chat/ChatSendButton.tsx +11 -1
  398. package/src/Chat/ChatToolCalls.test.tsx +64 -0
  399. package/src/Chat/ChatToolCalls.tsx +25 -4
  400. package/src/Chat/index.ts +5 -1
  401. package/src/Chat/useChatStreamScroll.test.tsx +49 -0
  402. package/src/Chat/useChatStreamScroll.ts +27 -10
  403. package/src/Chat/useSpeechRecognition.ts +1 -1
  404. package/src/Chat/useTriggerMenu.tsx +4 -2
  405. package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
  406. package/src/CheckboxInput/CheckboxInput.tsx +1 -1
  407. package/src/CheckboxList/CheckboxList.test.tsx +81 -3
  408. package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
  409. package/src/CheckboxList/CheckboxListItem.tsx +41 -5
  410. package/src/Citation/Citation.doc.mjs +4 -3
  411. package/src/Citation/Citation.test.tsx +97 -0
  412. package/src/Citation/Citation.tsx +43 -11
  413. package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
  414. package/src/ClickableCard/ClickableCard.test.tsx +34 -0
  415. package/src/ClickableCard/ClickableCard.tsx +13 -3
  416. package/src/CodeBlock/CodeBlock.test.tsx +56 -0
  417. package/src/CodeBlock/CodeBlock.tsx +10 -2
  418. package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
  419. package/src/CommandPalette/CommandPalette.tsx +3 -1
  420. package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
  421. package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
  422. package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
  423. package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
  424. package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
  425. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  426. package/src/ContextMenu/ContextMenu.test.tsx +193 -0
  427. package/src/DateInput/DateInput.doc.mjs +31 -0
  428. package/src/DateInput/DateInput.test.tsx +131 -0
  429. package/src/DateInput/DateInput.tsx +78 -3
  430. package/src/DateInput/index.ts +1 -0
  431. package/src/DateRangeInput/DateRangeInput.doc.mjs +8 -0
  432. package/src/DateRangeInput/DateRangeInput.test.tsx +23 -0
  433. package/src/DateRangeInput/DateRangeInput.tsx +13 -3
  434. package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -1
  435. package/src/DateTimeInput/DateTimeInput.test.tsx +147 -0
  436. package/src/DateTimeInput/DateTimeInput.tsx +42 -18
  437. package/src/Dialog/Dialog.doc.mjs +2 -2
  438. package/src/Dialog/Dialog.test.tsx +77 -4
  439. package/src/Dialog/Dialog.tsx +89 -5
  440. package/src/Dialog/DialogContext.ts +9 -2
  441. package/src/Dialog/DialogHeader.doc.mjs +2 -2
  442. package/src/Dialog/DialogHeader.tsx +9 -2
  443. package/src/Divider/Divider.tsx +2 -2
  444. package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
  445. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
  446. package/src/DropdownMenu/DropdownMenuItem.tsx +1 -1
  447. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
  448. package/src/Field/Field.test.tsx +57 -12
  449. package/src/Field/Field.tsx +6 -5
  450. package/src/Field/FieldLabel.tsx +9 -1
  451. package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
  452. package/src/FieldStatus/FieldStatus.test.tsx +150 -40
  453. package/src/FieldStatus/FieldStatus.tsx +63 -5
  454. package/src/FileInput/FileInput.doc.mjs +17 -2
  455. package/src/FileInput/FileInput.test.tsx +135 -12
  456. package/src/FileInput/FileInput.tsx +53 -28
  457. package/src/HoverCard/HoverCard.doc.mjs +13 -0
  458. package/src/HoverCard/HoverCard.test.tsx +21 -2
  459. package/src/HoverCard/HoverCard.tsx +11 -0
  460. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  461. package/src/HoverCard/useHoverCard.tsx +24 -2
  462. package/src/Icon/Icon.doc.mjs +3 -2
  463. package/src/Icon/Icon.tsx +7 -2
  464. package/src/IconButton/IconButton.doc.mjs +8 -0
  465. package/src/IconButton/IconButton.test.tsx +15 -18
  466. package/src/Item/Item.test.tsx +40 -18
  467. package/src/Item/Item.tsx +38 -2
  468. package/src/Layer/useLayer.tsx +8 -0
  469. package/src/Lightbox/Lightbox.tsx +4 -4
  470. package/src/List/List.test.tsx +9 -8
  471. package/src/MobileNav/MobileNav.tsx +12 -1
  472. package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
  473. package/src/MobileNav/MobileNavToggle.tsx +9 -1
  474. package/src/MultiSelector/MultiSelector.doc.mjs +13 -2
  475. package/src/MultiSelector/MultiSelector.test.tsx +195 -3
  476. package/src/MultiSelector/MultiSelector.tsx +65 -12
  477. package/src/MultiSelector/hooks.ts +17 -0
  478. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  479. package/src/NumberInput/NumberInput.doc.mjs +15 -0
  480. package/src/NumberInput/NumberInput.test.tsx +82 -7
  481. package/src/NumberInput/NumberInput.tsx +21 -4
  482. package/src/Outline/Outline.tsx +0 -1
  483. package/src/OverflowList/OverflowList.doc.mjs +39 -6
  484. package/src/OverflowList/OverflowList.test.tsx +111 -0
  485. package/src/OverflowList/OverflowList.tsx +48 -8
  486. package/src/Pagination/Pagination.tsx +11 -3
  487. package/src/Popover/Popover.tsx +7 -4
  488. package/src/Popover/usePopover.tsx +9 -13
  489. package/src/PowerSearch/PowerSearch.doc.mjs +29 -0
  490. package/src/PowerSearch/PowerSearch.test.tsx +43 -0
  491. package/src/PowerSearch/PowerSearch.tsx +10 -1
  492. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
  493. package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
  494. package/src/PowerSearch/usePowerSearchSource.ts +1 -2
  495. package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
  496. package/src/SelectableCard/SelectableCard.test.tsx +46 -4
  497. package/src/SelectableCard/SelectableCard.tsx +29 -16
  498. package/src/Selector/Selector.doc.mjs +7 -0
  499. package/src/Selector/Selector.test.tsx +92 -0
  500. package/src/Selector/Selector.tsx +16 -2
  501. package/src/Selector/hooks.ts +17 -0
  502. package/src/SideNav/SideNav.test.tsx +119 -3
  503. package/src/SideNav/SideNavCollapseButton.tsx +6 -1
  504. package/src/SideNav/SideNavHeading.tsx +24 -8
  505. package/src/SideNav/SideNavItem.tsx +5 -1
  506. package/src/Slider/Slider.test.tsx +75 -2
  507. package/src/Slider/Slider.tsx +21 -5
  508. package/src/Switch/Switch.test.tsx +32 -1
  509. package/src/TabList/Tab.tsx +2 -2
  510. package/src/TabList/TabMenu.tsx +2 -2
  511. package/src/Table/BaseTable.tsx +3 -5
  512. package/src/Table/TableCell.tsx +3 -3
  513. package/src/Table/TableHeaderCell.tsx +3 -3
  514. package/src/Table/index.ts +5 -0
  515. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
  516. package/src/Table/plugins/rowStatus/index.ts +7 -0
  517. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
  518. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
  519. package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
  520. package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
  521. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -1
  522. package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
  523. package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
  524. package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
  525. package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
  526. package/src/Table/useBaseTablePlugins.ts +10 -6
  527. package/src/Table/useTableRowStatus.doc.mjs +30 -0
  528. package/src/Table/useTableSelection.doc.mjs +65 -14
  529. package/src/Table/useTableTreeData.doc.mjs +29 -0
  530. package/src/Table/useTableTreeState.doc.mjs +2 -2
  531. package/src/TextArea/TextArea.doc.mjs +15 -0
  532. package/src/TextArea/TextArea.test.tsx +32 -1
  533. package/src/TextArea/TextArea.tsx +10 -0
  534. package/src/TextInput/TextInput.doc.mjs +15 -0
  535. package/src/TextInput/TextInput.test.tsx +44 -0
  536. package/src/TextInput/TextInput.tsx +13 -1
  537. package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
  538. package/src/Thumbnail/Thumbnail.test.tsx +98 -7
  539. package/src/Thumbnail/Thumbnail.tsx +142 -42
  540. package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
  541. package/src/TimeInput/TimeInput.doc.mjs +15 -0
  542. package/src/TimeInput/TimeInput.test.tsx +99 -1
  543. package/src/TimeInput/TimeInput.tsx +29 -6
  544. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  545. package/src/Timestamp/Timestamp.test.tsx +32 -0
  546. package/src/Timestamp/Timestamp.tsx +28 -8
  547. package/src/Toast/useToast.tsx +7 -8
  548. package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
  549. package/src/Tokenizer/Tokenizer.doc.mjs +30 -1
  550. package/src/Tokenizer/Tokenizer.test.tsx +206 -2
  551. package/src/Tokenizer/Tokenizer.tsx +26 -4
  552. package/src/TopNav/TopNav.test.tsx +125 -1
  553. package/src/TopNav/TopNavHeading.tsx +24 -8
  554. package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
  555. package/src/TopNav/TopNavMegaMenu.tsx +10 -4
  556. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
  557. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
  558. package/src/TopNav/TopNavMenu.test.tsx +118 -4
  559. package/src/TopNav/TopNavMenu.tsx +83 -5
  560. package/src/TreeList/TreeList.doc.mjs +22 -0
  561. package/src/TreeList/TreeList.test.tsx +232 -0
  562. package/src/TreeList/TreeList.tsx +18 -2
  563. package/src/TreeList/TreeListBranches.tsx +16 -2
  564. package/src/TreeList/TreeListItem.tsx +52 -12
  565. package/src/TreeList/TreeListTypes.ts +27 -1
  566. package/src/TreeList/index.ts +2 -2
  567. package/src/Typeahead/BaseTypeahead.tsx +30 -15
  568. package/src/Typeahead/Typeahead.doc.mjs +7 -0
  569. package/src/Typeahead/Typeahead.test.tsx +50 -0
  570. package/src/Typeahead/Typeahead.tsx +10 -0
  571. package/src/authoring/doc.ts +1 -3
  572. package/src/docs-types.ts +5 -0
  573. package/src/hooks/computeOverflow.test.ts +422 -0
  574. package/src/hooks/computeOverflow.ts +290 -0
  575. package/src/hooks/index.ts +2 -0
  576. package/src/hooks/isRtlElement.ts +27 -0
  577. package/src/hooks/useDevWarning.test.tsx +45 -0
  578. package/src/hooks/useDevWarning.ts +54 -0
  579. package/src/hooks/useGridFocus.doc.mjs +3 -3
  580. package/src/hooks/useGridFocus.test.tsx +41 -0
  581. package/src/hooks/useGridFocus.ts +21 -10
  582. package/src/hooks/useListFocus.doc.mjs +3 -3
  583. package/src/hooks/useListFocus.test.tsx +67 -1
  584. package/src/hooks/useListFocus.ts +21 -5
  585. package/src/hooks/useOverflow.test.ts +96 -4
  586. package/src/hooks/useOverflow.ts +74 -33
  587. package/src/i18n/InternationalizationContext.ts +4 -0
  588. package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
  589. package/src/i18n/InternationalizationProvider.tsx +12 -2
  590. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  591. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  592. package/src/i18n/getLocaleDirection.ts +29 -0
  593. package/src/i18n/index.ts +6 -0
  594. package/src/i18n/resolve.ts +9 -21
  595. package/src/i18n/useDirection.ts +29 -0
  596. package/src/reset.css +0 -26
  597. package/src/reset.test.ts +60 -0
  598. package/src/theme/Theme.tsx +11 -14
  599. package/src/theme/derivedVarRegistry.test.ts +1 -0
  600. package/src/theme/derivedVarRegistry.ts +6 -0
  601. package/src/theme/generateThemeRules.test.ts +107 -0
  602. package/src/theme/generateThemeRules.ts +56 -0
  603. package/src/theme/hct.ts +1 -1
  604. package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
  605. package/src/utils/devWarning.test.ts +56 -0
  606. package/src/utils/devWarning.ts +102 -0
  607. package/src/utils/index.ts +6 -0
  608. package/src/utils/plainDate.test.ts +22 -0
  609. package/src/utils/plainDate.ts +61 -0
  610. package/src/utils/types.ts +14 -0
@@ -111,7 +111,7 @@ export const docs = {
111
111
  { guidance: false, description: 'Use the fullscreen variant for simple confirmations; it is meant for complex content like editors or long forms.' },
112
112
  ],
113
113
  anatomy: [
114
- {name: 'Header', required: true, description: 'Title, optional subtitle, and close button. The title receives focus on open for accessibility.'},
114
+ {name: 'Header', required: true, description: 'Title, optional subtitle, and close button. The title receives focus on open and labels the dialog via aria-labelledby.'},
115
115
  {name: 'Body', required: true, description: 'The main content area: text, forms, lists, or any layout.'},
116
116
  {name: 'Footer', required: false, description: 'Action buttons like Save/Cancel or Accept/Decline, aligned to the end.'},
117
117
  {name: 'Backdrop', required: true, description: 'Semi-transparent overlay behind the dialog that blocks page interaction.'},
@@ -133,7 +133,7 @@ export const docsZh = {
133
133
  { guidance: false, description: 'Use the fullscreen variant for simple confirmations; it is meant for complex content like editors or long forms.' },
134
134
  ],
135
135
  anatomy: [
136
- {name: 'Header', required: true, description: 'Title, optional subtitle, and close button. The title receives focus on open for accessibility.'},
136
+ {name: 'Header', required: true, description: 'Title, optional subtitle, and close button. The title receives focus on open and labels the dialog via aria-labelledby.'},
137
137
  {name: 'Body', required: true, description: 'The main content area: text, forms, lists, or any layout.'},
138
138
  {name: 'Footer', required: false, description: 'Action buttons like Save/Cancel or Accept/Decline, aligned to the end.'},
139
139
  {name: 'Backdrop', required: true, description: 'Semi-transparent overlay behind the dialog that blocks page interaction.'},
@@ -212,10 +212,7 @@ describe('Dialog', () => {
212
212
 
213
213
  it('forwards additional props to dialog element', () => {
214
214
  render(
215
- <Dialog
216
- isOpen={true}
217
- onOpenChange={() => {}}
218
- data-testid="custom-dialog">
215
+ <Dialog isOpen={true} onOpenChange={() => {}} data-testid="custom-dialog">
219
216
  Content
220
217
  </Dialog>,
221
218
  );
@@ -267,6 +264,82 @@ describe('Dialog', () => {
267
264
  });
268
265
  });
269
266
 
267
+ describe('accessible name', () => {
268
+ it('is labelled by the DialogHeader title by default', () => {
269
+ render(
270
+ <Dialog isOpen={true} onOpenChange={() => {}}>
271
+ <DialogHeader title="Dialog title" />
272
+ </Dialog>,
273
+ );
274
+ const dialog = screen.getByRole('dialog');
275
+ const heading = screen.getByRole('heading', {name: 'Dialog title'});
276
+ expect(heading.id).not.toBe('');
277
+ expect(dialog).toHaveAttribute('aria-labelledby', heading.id);
278
+ expect(dialog).toHaveAccessibleName('Dialog title');
279
+ });
280
+
281
+ it('prefers a consumer-provided aria-label over the header title', () => {
282
+ render(
283
+ <Dialog isOpen={true} onOpenChange={() => {}} aria-label="Custom name">
284
+ <DialogHeader title="Dialog title" />
285
+ </Dialog>,
286
+ );
287
+ const dialog = screen.getByRole('dialog');
288
+ expect(dialog).not.toHaveAttribute('aria-labelledby');
289
+ expect(dialog).toHaveAccessibleName('Custom name');
290
+ });
291
+
292
+ it('prefers a consumer-provided aria-labelledby over the header title', () => {
293
+ render(
294
+ <>
295
+ <span id="external-label">External name</span>
296
+ <Dialog
297
+ isOpen={true}
298
+ onOpenChange={() => {}}
299
+ aria-labelledby="external-label">
300
+ <DialogHeader title="Dialog title" />
301
+ </Dialog>
302
+ </>,
303
+ );
304
+ const dialog = screen.getByRole('dialog');
305
+ expect(dialog).toHaveAttribute('aria-labelledby', 'external-label');
306
+ expect(dialog).toHaveAccessibleName('External name');
307
+ });
308
+
309
+ it('omits aria-labelledby and warns when open with no name source', () => {
310
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
311
+ try {
312
+ render(
313
+ <Dialog isOpen={true} onOpenChange={() => {}}>
314
+ Content
315
+ </Dialog>,
316
+ );
317
+ const dialog = screen.getByRole('dialog');
318
+ expect(dialog).not.toHaveAttribute('aria-labelledby');
319
+ expect(warnSpy).toHaveBeenCalledTimes(1);
320
+ expect(warnSpy).toHaveBeenCalledWith(
321
+ expect.stringContaining('accessible name'),
322
+ );
323
+ } finally {
324
+ warnSpy.mockRestore();
325
+ }
326
+ });
327
+
328
+ it('does not warn when the header provides a title', () => {
329
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
330
+ try {
331
+ render(
332
+ <Dialog isOpen={true} onOpenChange={() => {}}>
333
+ <DialogHeader title="Dialog title" />
334
+ </Dialog>,
335
+ );
336
+ expect(warnSpy).not.toHaveBeenCalled();
337
+ } finally {
338
+ warnSpy.mockRestore();
339
+ }
340
+ });
341
+ });
342
+
270
343
  describe('inner flex wrapper', () => {
271
344
  it('wraps children in a flex container for scroll support', () => {
272
345
  render(
@@ -16,7 +16,14 @@
16
16
  * - /packages/cli/templates/blocks/components/Dialog/ (showcase blocks)
17
17
  */
18
18
 
19
- import {useEffect, useMemo, useRef, type ReactNode} from 'react';
19
+ import {
20
+ useCallback,
21
+ useEffect,
22
+ useId,
23
+ useMemo,
24
+ useRef,
25
+ type ReactNode,
26
+ } from 'react';
20
27
  import type {BaseProps} from '../BaseProps';
21
28
  import * as stylex from '@stylexjs/stylex';
22
29
  import {useScrollLock} from '../hooks/useScrollLock';
@@ -39,6 +46,7 @@ import {
39
46
  } from '../Layout/padding.stylex';
40
47
  import type {SpacingStep} from '../utils/types';
41
48
  import {mergeProps, mergeRefs} from '../utils';
49
+ import {devWarn} from '../utils/devWarning';
42
50
  import {DialogContext} from './DialogContext';
43
51
  import {themeProps} from '../utils/themeProps';
44
52
 
@@ -152,7 +160,13 @@ const styles = stylex.create({
152
160
  open: {
153
161
  display: 'flex',
154
162
  opacity: 1,
155
- animationName: enterDirectional,
163
+ // Disable the entry keyframe animation under
164
+ // `prefers-reduced-motion: reduce` so the dialog appears instantly
165
+ // instead of translating/scaling in (same pattern as layerAnimations).
166
+ animationName: {
167
+ default: enterDirectional,
168
+ '@media (prefers-reduced-motion: reduce)': 'none',
169
+ },
156
170
  },
157
171
  // Backdrop using ::backdrop pseudo-element
158
172
  backdrop: {
@@ -312,6 +326,9 @@ export interface DialogProps extends BaseProps<HTMLDialogElement> {
312
326
  *
313
327
  * Designed to be used with Layout as its child for structured content.
314
328
  * Uses the browser's built-in modal behavior for optimal accessibility.
329
+ * When a DialogHeader is rendered inside, its title automatically names the
330
+ * dialog via aria-labelledby; pass `aria-label` or `aria-labelledby` to
331
+ * override.
315
332
  *
316
333
  * @example
317
334
  * ```
@@ -348,10 +365,47 @@ export function Dialog({
348
365
  const paddingToken = spacingStepToToken[effectivePadding] as SpacingToken;
349
366
 
350
367
  const isFullscreen = variant === 'fullscreen';
351
- const dialogContextValue = useMemo(() => ({isInline}), [isInline]);
368
+
369
+ // Default accessible name: publish a title id through DialogContext so a
370
+ // DialogHeader applies it to its heading (mirrors AlertDialog's explicit
371
+ // useId wiring). Whether to emit the default aria-labelledby is decided
372
+ // imperatively in the callback ref below by checking whether the title
373
+ // element actually rendered — so a dialog with no header never points at a
374
+ // missing id, and we avoid the extra render a registration-via-state effect
375
+ // would cost at the dialog level.
376
+ const titleId = useId();
377
+
378
+ const dialogContextValue = useMemo(
379
+ () => ({isInline, titleId}),
380
+ [isInline, titleId],
381
+ );
382
+
383
+ // Consumer-provided labels always win over the DialogHeader default.
384
+ const hasConsumerName =
385
+ props['aria-label'] != null || props['aria-labelledby'] != null;
352
386
 
353
387
  const dialogRef = useRef<HTMLDialogElement>(null);
354
388
 
389
+ // Callback ref on the <dialog>: sync the default aria-labelledby from the
390
+ // DialogHeader title (if one rendered) in the same commit, with no second
391
+ // render. Consumer aria-label/aria-labelledby win — when present we leave
392
+ // the attribute to the {...safeProps} spread and never touch it here.
393
+ const attachDialog = useCallback(
394
+ (node: HTMLDialogElement | null) => {
395
+ dialogRef.current = node;
396
+ if (!node || hasConsumerName) {
397
+ return;
398
+ }
399
+ const hasTitle = node.querySelector(`#${CSS.escape(titleId)}`) != null;
400
+ if (hasTitle) {
401
+ node.setAttribute('aria-labelledby', titleId);
402
+ } else {
403
+ node.removeAttribute('aria-labelledby');
404
+ }
405
+ },
406
+ [titleId, hasConsumerName],
407
+ );
408
+
355
409
  // Capture the element that was focused when the dialog opened,
356
410
  // for directional animation origin and focus restoration on close.
357
411
  const triggerElementRef = useRef<HTMLElement | null>(null);
@@ -440,6 +494,29 @@ export function Dialog({
440
494
  return () => dialog.removeEventListener('keydown', handleKeyDown);
441
495
  }, [isOpen, isInline, allowEscape, onOpenChange]);
442
496
 
497
+ // Dev-time guardrail: an open modal should always have an accessible name.
498
+ // The header-title check reads the DOM, so this stays in an effect; the ref
499
+ // keeps it to one warning per component instance.
500
+ const warnedUnnamedDialogRef = useRef(false);
501
+ useEffect(() => {
502
+ const hasHeaderTitle =
503
+ dialogRef.current?.querySelector(`#${CSS.escape(titleId)}`) != null;
504
+ if (
505
+ isOpen &&
506
+ !isInline &&
507
+ !hasConsumerName &&
508
+ !hasHeaderTitle &&
509
+ !warnedUnnamedDialogRef.current
510
+ ) {
511
+ warnedUnnamedDialogRef.current = true;
512
+ devWarn(
513
+ 'Dialog',
514
+ 'open dialog has no accessible name. Add a DialogHeader ' +
515
+ 'with a `title`, or pass `aria-label`/`aria-labelledby`.',
516
+ );
517
+ }
518
+ }, [isOpen, isInline, hasConsumerName, titleId]);
519
+
443
520
  // Handle backdrop click — when the user clicks the ::backdrop pseudo-element,
444
521
  // the event target is the <dialog> element itself; clicks on child content
445
522
  // always target the child. This avoids false positives from native browser
@@ -531,7 +608,11 @@ export function Dialog({
531
608
  ),
532
609
  className,
533
610
  style,
534
- )}>
611
+ )}
612
+ data-testid={
613
+ (props as Record<string, unknown>)['data-testid'] as
614
+ string | undefined
615
+ }>
535
616
  {innerContent}
536
617
  </div>
537
618
  );
@@ -541,7 +622,7 @@ export function Dialog({
541
622
 
542
623
  return (
543
624
  <dialog
544
- ref={mergeRefs(ref, dialogRef)}
625
+ ref={mergeRefs(ref, attachDialog)}
545
626
  {...safeProps}
546
627
  {...mergeProps(
547
628
  themeProps('dialog', {variant}),
@@ -566,6 +647,9 @@ export function Dialog({
566
647
  onClick={handleClick}
567
648
  onCancel={handleCancel}
568
649
  aria-modal="true"
650
+ // The default aria-labelledby (from a DialogHeader title) is set
651
+ // imperatively in `attachDialog`; a consumer-provided aria-labelledby
652
+ // flows through {...safeProps} above and wins.
569
653
  {...(purpose === 'required' ? {role: 'alertdialog'} : undefined)}>
570
654
  {innerContent}
571
655
  </dialog>
@@ -5,8 +5,8 @@
5
5
  /**
6
6
  * @file DialogContext.ts
7
7
  * @input React context
8
- * @output Internal dialog context for child focus behavior
9
- * @position Dialog internals; consumed by focus-managing children
8
+ * @output Internal dialog context for child focus behavior and default labelling
9
+ * @position Dialog internals; consumed by focus-managing children and DialogHeader
10
10
  */
11
11
 
12
12
  import {createContext, use} from 'react';
@@ -14,6 +14,13 @@ import {createContext, use} from 'react';
14
14
  export interface DialogContextValue {
15
15
  /** Whether the dialog is rendered inline for docs/showcases. */
16
16
  isInline: boolean;
17
+ /**
18
+ * Id the DialogHeader title should render with so the dialog can name
19
+ * itself via aria-labelledby. The dialog detects the title element's
20
+ * presence directly (via a callback ref), so it only emits aria-labelledby
21
+ * when the title actually rendered — never pointing at a nonexistent id.
22
+ */
23
+ titleId?: string;
17
24
  }
18
25
 
19
26
  export const DialogContext = createContext<DialogContextValue | null>(null);
@@ -12,7 +12,7 @@ export const docs = {
12
12
  {
13
13
  name: 'title',
14
14
  type: 'string',
15
- description: 'Dialog title (receives focus on open).',
15
+ description: 'Dialog title (receives focus on open and labels the dialog via aria-labelledby).',
16
16
  },
17
17
  {
18
18
  name: 'subtitle',
@@ -158,7 +158,7 @@ export const docsDense = {
158
158
  displayName: 'Dialog Header',
159
159
  description: 'dialog header w/ title, optional subtitle, close button, start/end content slots',
160
160
  propDescriptions: {
161
- title: 'dialog title (receives focus on open)',
161
+ title: 'dialog title (focused on open; labels dialog via aria-labelledby)',
162
162
  subtitle: 'subtitle below title',
163
163
  onOpenChange: 'close button callback (omit=no button)',
164
164
  startContent: 'content before title (e.g. back button)',
@@ -65,7 +65,9 @@ export interface DialogHeaderProps extends BaseProps<HTMLDivElement> {
65
65
  ref?: React.Ref<HTMLDivElement>;
66
66
  /**
67
67
  * The title of the dialog.
68
- * This title receives focus when the dialog opens for screen reader accessibility.
68
+ * This title receives focus when the dialog opens for screen reader
69
+ * accessibility, and names the parent Dialog via aria-labelledby unless the
70
+ * consumer passes an explicit aria-label/aria-labelledby to the Dialog.
69
71
  */
70
72
  title: string;
71
73
 
@@ -105,7 +107,8 @@ export interface DialogHeaderProps extends BaseProps<HTMLDivElement> {
105
107
  * Renders a title that receives focus when a modal dialog opens (for screen reader accessibility)
106
108
  * and an optional close button. Inline documentation previews suppress this autofocus.
107
109
  * The title is an h2 element with tabIndex={-1} so it can be programmatically focused but
108
- * doesn't appear in the tab order.
110
+ * doesn't appear in the tab order. The title also names the parent Dialog via
111
+ * aria-labelledby (unless the Dialog receives an explicit aria-label/aria-labelledby).
109
112
  *
110
113
  * Uses LayoutHeader internally for consistent styling with other layout headers.
111
114
  *
@@ -137,10 +140,13 @@ export function DialogHeader({
137
140
  const titleRef = useRef<HTMLHeadingElement>(null);
138
141
  const dialogContext = useDialogContext();
139
142
  const shouldAutoFocus = dialogContext?.isInline !== true;
143
+ const titleId = dialogContext?.titleId;
140
144
 
141
145
  // Auto-focus the title when mounted for screen reader accessibility.
142
146
  // Inline dialogs are documentation/showcase previews, so suppress focus to
143
147
  // avoid stealing scroll position from the surrounding page.
148
+ // The parent Dialog detects this title (by `titleId`) via a callback ref to
149
+ // set its default aria-labelledby — no registration handshake needed here.
144
150
  useEffect(() => {
145
151
  if (shouldAutoFocus && titleRef.current) {
146
152
  titleRef.current.focus();
@@ -162,6 +168,7 @@ export function DialogHeader({
162
168
  <div {...stylex.props(styles.titleWrapper)}>
163
169
  <Heading
164
170
  ref={titleRef}
171
+ id={titleId}
165
172
  level={2}
166
173
  tabIndex={-1}
167
174
  xstyle={styles.titleFocusable}>
@@ -172,6 +172,7 @@ export function Divider({
172
172
  return (
173
173
  <div
174
174
  ref={ref}
175
+ {...props}
175
176
  role="separator"
176
177
  aria-orientation={orientation}
177
178
  {...mergeProps(
@@ -186,8 +187,7 @@ export function Divider({
186
187
  ),
187
188
  className,
188
189
  style,
189
- )}
190
- {...props}>
190
+ )}>
191
191
  <div
192
192
  {...stylex.props(
193
193
  isHorizontal ? lineStyles.horizontalLine : lineStyles.verticalLine,
@@ -613,3 +613,172 @@ describe('DropdownMenu compound mode', () => {
613
613
  ).toBeInTheDocument();
614
614
  });
615
615
  });
616
+
617
+ describe('DropdownMenu keyboard access for menuitemradio/menuitemcheckbox (#3829)', () => {
618
+ it('arrow navigation reaches consumer-rendered menuitemradio and menuitemcheckbox items', async () => {
619
+ const user = userEvent.setup();
620
+ render(
621
+ <DropdownMenu button={{label: 'Sort'}}>
622
+ <DropdownMenuItem label="Edit" onClick={() => {}} />
623
+ <div role="menuitemradio" tabIndex={-1} aria-checked="false">
624
+ Newest
625
+ </div>
626
+ <div role="menuitemcheckbox" tabIndex={-1} aria-checked="false">
627
+ Archived
628
+ </div>
629
+ </DropdownMenu>,
630
+ );
631
+
632
+ await user.click(screen.getByRole('button', {name: /Sort/}));
633
+ const menu = screen.getByRole('menu', {hidden: true});
634
+ screen.getByRole('menuitem', {name: 'Edit', hidden: true}).focus();
635
+
636
+ fireEvent.keyDown(menu, {key: 'ArrowDown'});
637
+ expect(
638
+ screen.getByRole('menuitemradio', {name: 'Newest', hidden: true}),
639
+ ).toHaveFocus();
640
+
641
+ fireEvent.keyDown(menu, {key: 'ArrowDown'});
642
+ expect(
643
+ screen.getByRole('menuitemcheckbox', {name: 'Archived', hidden: true}),
644
+ ).toHaveFocus();
645
+ });
646
+
647
+ it('activates a focused menuitemradio with Enter and a menuitemcheckbox with Space', async () => {
648
+ const user = userEvent.setup();
649
+ const onSelect = vi.fn();
650
+ const onToggle = vi.fn();
651
+ render(
652
+ <DropdownMenu button={{label: 'Sort'}}>
653
+ <DropdownMenuItem label="Edit" onClick={() => {}} />
654
+ <div
655
+ role="menuitemradio"
656
+ tabIndex={-1}
657
+ aria-checked="false"
658
+ onClick={onSelect}>
659
+ Newest
660
+ </div>
661
+ <div
662
+ role="menuitemcheckbox"
663
+ tabIndex={-1}
664
+ aria-checked="false"
665
+ onClick={onToggle}>
666
+ Archived
667
+ </div>
668
+ </DropdownMenu>,
669
+ );
670
+
671
+ await user.click(screen.getByRole('button', {name: /Sort/}));
672
+ const menu = screen.getByRole('menu', {hidden: true});
673
+
674
+ screen.getByRole('menuitemradio', {name: 'Newest', hidden: true}).focus();
675
+ fireEvent.keyDown(menu, {key: 'Enter'});
676
+ expect(onSelect).toHaveBeenCalledTimes(1);
677
+
678
+ screen
679
+ .getByRole('menuitemcheckbox', {name: 'Archived', hidden: true})
680
+ .focus();
681
+ fireEvent.keyDown(menu, {key: ' '});
682
+ expect(onToggle).toHaveBeenCalledTimes(1);
683
+ });
684
+
685
+ it('typeahead matches a menuitemradio label', async () => {
686
+ const user = userEvent.setup();
687
+ render(
688
+ <DropdownMenu button={{label: 'Sort'}}>
689
+ <DropdownMenuItem label="Edit" onClick={() => {}} />
690
+ <div role="menuitemradio" tabIndex={-1} aria-checked="false">
691
+ Newest
692
+ </div>
693
+ <div role="menuitemcheckbox" tabIndex={-1} aria-checked="false">
694
+ Archived
695
+ </div>
696
+ </DropdownMenu>,
697
+ );
698
+
699
+ await user.click(screen.getByRole('button', {name: /Sort/}));
700
+ fireEvent.keyDown(screen.getByRole('menu', {hidden: true}), {key: 'n'});
701
+ expect(
702
+ screen.getByRole('menuitemradio', {name: 'Newest', hidden: true}),
703
+ ).toHaveFocus();
704
+ });
705
+
706
+ it('typeahead matches a menuitemcheckbox label', async () => {
707
+ const user = userEvent.setup();
708
+ render(
709
+ <DropdownMenu button={{label: 'Sort'}}>
710
+ <DropdownMenuItem label="Edit" onClick={() => {}} />
711
+ <div role="menuitemradio" tabIndex={-1} aria-checked="false">
712
+ Newest
713
+ </div>
714
+ <div role="menuitemcheckbox" tabIndex={-1} aria-checked="false">
715
+ Archived
716
+ </div>
717
+ </DropdownMenu>,
718
+ );
719
+
720
+ await user.click(screen.getByRole('button', {name: /Sort/}));
721
+ fireEvent.keyDown(screen.getByRole('menu', {hidden: true}), {key: 'a'});
722
+ expect(
723
+ screen.getByRole('menuitemcheckbox', {name: 'Archived', hidden: true}),
724
+ ).toHaveFocus();
725
+ });
726
+
727
+ it('typeahead skips an aria-disabled item and matches the next enabled label', async () => {
728
+ const user = userEvent.setup();
729
+ render(
730
+ <DropdownMenu button={{label: 'Sort'}}>
731
+ <DropdownMenuItem label="Edit" onClick={() => {}} />
732
+ <div role="menuitemradio" tabIndex={-1} aria-disabled="true">
733
+ Newest
734
+ </div>
735
+ <div role="menuitemcheckbox" tabIndex={-1} aria-checked="false">
736
+ Nightly
737
+ </div>
738
+ </DropdownMenu>,
739
+ );
740
+
741
+ await user.click(screen.getByRole('button', {name: /Sort/}));
742
+ // Anchor the search on 'Edit' so typeahead scans forward and meets the
743
+ // disabled 'Newest' (also an 'n' match) before the enabled 'Nightly'.
744
+ // This pins the `:not([aria-disabled="true"])` in MENU_ITEM_SELECTOR: the
745
+ // menus never pass useTypeahead's `isDisabled` option, so that clause is
746
+ // the only thing keeping disabled rows out of the typeahead list. An
747
+ // arrow-key test cannot cover it — useListFocus re-filters disabled items
748
+ // independently, so arrow navigation is guarded twice over.
749
+ // The disabled row keeps tabIndex={-1} on purpose: it stays focusable, so
750
+ // the selector clause is the sole reason focus skips it.
751
+ screen.getByRole('menuitem', {name: 'Edit', hidden: true}).focus();
752
+ fireEvent.keyDown(screen.getByRole('menu', {hidden: true}), {key: 'n'});
753
+ expect(
754
+ screen.getByRole('menuitemcheckbox', {name: 'Nightly', hidden: true}),
755
+ ).toHaveFocus();
756
+ });
757
+
758
+ it('skips aria-disabled menuitemradio and menuitemcheckbox items during arrow navigation', async () => {
759
+ const user = userEvent.setup();
760
+ render(
761
+ <DropdownMenu button={{label: 'Sort'}}>
762
+ <DropdownMenuItem label="Edit" onClick={() => {}} />
763
+ <div role="menuitemradio" tabIndex={-1} aria-disabled="true">
764
+ Newest
765
+ </div>
766
+ <div role="menuitemcheckbox" tabIndex={-1} aria-disabled="true">
767
+ Archived
768
+ </div>
769
+ <div role="menuitemradio" tabIndex={-1} aria-checked="false">
770
+ Oldest
771
+ </div>
772
+ </DropdownMenu>,
773
+ );
774
+
775
+ await user.click(screen.getByRole('button', {name: /Sort/}));
776
+ const menu = screen.getByRole('menu', {hidden: true});
777
+ screen.getByRole('menuitem', {name: 'Edit', hidden: true}).focus();
778
+
779
+ fireEvent.keyDown(menu, {key: 'ArrowDown'});
780
+ expect(
781
+ screen.getByRole('menuitemradio', {name: 'Oldest', hidden: true}),
782
+ ).toHaveFocus();
783
+ });
784
+ });
@@ -152,8 +152,7 @@ export interface DropdownMenuCheckboxItemProps extends Omit<
152
152
  *
153
153
  * @example
154
154
  * ```
155
- * * import {DropdownMenuCheckboxItem} from '@astryxdesign/core/DropdownMenu';
156
- *
155
+ * import {DropdownMenuCheckboxItem} from '@astryxdesign/core/DropdownMenu';
157
156
  * <DropdownMenu button={{label: 'View'}}>
158
157
  * <DropdownMenuCheckboxItem
159
158
  * label="Show archived"
@@ -55,7 +55,7 @@ const menuItemStyles = stylex.create({
55
55
  },
56
56
  border: 'none',
57
57
  cursor: 'pointer',
58
- textAlign: 'left',
58
+ textAlign: 'start',
59
59
  outline: 'none',
60
60
  },
61
61
  disabled: {
@@ -77,11 +77,10 @@ export interface DropdownMenuRadioGroupProps extends Omit<
77
77
  *
78
78
  * @example
79
79
  * ```
80
- * * import {
80
+ * import {
81
81
  * DropdownMenuRadioGroup,
82
82
  * DropdownMenuRadioItem,
83
83
  * } from '@astryxdesign/core/DropdownMenu';
84
- *
85
84
  * <DropdownMenu button={{label: 'Sort'}}>
86
85
  * <DropdownMenuRadioGroup value={sort} onChange={setSort} aria-label="Sort by">
87
86
  * <DropdownMenuRadioItem value="newest" label="Newest" />