@astryxdesign/core 0.1.8 → 0.1.9

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 (487) 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 +18 -2
  7. package/dist/Avatar/Avatar.d.ts.map +1 -1
  8. package/dist/Avatar/Avatar.js +63 -7
  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/Banner/Banner.d.ts +9 -1
  13. package/dist/Banner/Banner.d.ts.map +1 -1
  14. package/dist/Banner/Banner.js +31 -2
  15. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +31 -2
  16. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  17. package/dist/Breadcrumbs/BreadcrumbItem.js +208 -6
  18. package/dist/Breadcrumbs/index.d.ts +5 -0
  19. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  20. package/dist/Breadcrumbs/index.js +9 -1
  21. package/dist/Button/Button.d.ts +8 -2
  22. package/dist/Button/Button.d.ts.map +1 -1
  23. package/dist/Button/Button.js +31 -2
  24. package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
  25. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  26. package/dist/ButtonGroup/ButtonGroup.js +30 -1
  27. package/dist/Calendar/Calendar.d.ts.map +1 -1
  28. package/dist/Calendar/Calendar.js +30 -2
  29. package/dist/Calendar/dayCellUtils.js +1 -1
  30. package/dist/Card/Card.d.ts +8 -2
  31. package/dist/Card/Card.d.ts.map +1 -1
  32. package/dist/Card/Card.js +28 -2
  33. package/dist/Carousel/Carousel.d.ts +4 -1
  34. package/dist/Carousel/Carousel.d.ts.map +1 -1
  35. package/dist/Carousel/Carousel.js +24 -4
  36. package/dist/Chat/ChatComposer.d.ts +8 -0
  37. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  38. package/dist/Chat/ChatComposer.js +46 -7
  39. package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
  40. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  41. package/dist/Chat/ChatComposerDrawer.js +11 -1
  42. package/dist/Chat/ChatComposerInput.d.ts +20 -3
  43. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  44. package/dist/Chat/ChatComposerInput.js +35 -3
  45. package/dist/Chat/ChatContext.d.ts +33 -0
  46. package/dist/Chat/ChatContext.d.ts.map +1 -1
  47. package/dist/Chat/ChatContext.js +16 -2
  48. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  49. package/dist/Chat/ChatDictationButton.js +1 -1
  50. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  51. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  52. package/dist/Chat/ChatLayoutScrollButton.js +4 -4
  53. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  54. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  55. package/dist/Chat/ChatSendButton.js +7 -1
  56. package/dist/Chat/ChatToolCalls.d.ts +5 -1
  57. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  58. package/dist/Chat/ChatToolCalls.js +18 -9
  59. package/dist/Chat/index.d.ts +2 -1
  60. package/dist/Chat/index.d.ts.map +1 -1
  61. package/dist/Chat/index.js +1 -1
  62. package/dist/Chat/useChatStreamScroll.d.ts +2 -1
  63. package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
  64. package/dist/Chat/useChatStreamScroll.js +22 -8
  65. package/dist/Chat/useSpeechRecognition.d.ts +0 -1
  66. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  67. package/dist/Chat/useSpeechRecognition.js +1 -1
  68. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  69. package/dist/CheckboxInput/CheckboxInput.js +1 -1
  70. package/dist/CheckboxList/CheckboxListItem.d.ts +20 -1
  71. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  72. package/dist/CheckboxList/CheckboxListItem.js +11 -1
  73. package/dist/ClickableCard/ClickableCard.d.ts +9 -2
  74. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  75. package/dist/ClickableCard/ClickableCard.js +5 -2
  76. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  77. package/dist/CodeBlock/CodeBlock.js +8 -1
  78. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  79. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  80. package/dist/CommandPalette/CommandPalette.js +3 -1
  81. package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
  82. package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
  83. package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
  84. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  85. package/dist/CommandPalette/CommandPaletteInput.js +6 -1
  86. package/dist/DateInput/DateInput.d.ts +47 -1
  87. package/dist/DateInput/DateInput.d.ts.map +1 -1
  88. package/dist/DateInput/DateInput.js +26 -2
  89. package/dist/DateInput/index.d.ts +1 -1
  90. package/dist/DateInput/index.d.ts.map +1 -1
  91. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  92. package/dist/DateTimeInput/DateTimeInput.js +10 -1
  93. package/dist/Dialog/Dialog.d.ts +3 -0
  94. package/dist/Dialog/Dialog.d.ts.map +1 -1
  95. package/dist/Dialog/Dialog.js +57 -6
  96. package/dist/Dialog/DialogContext.d.ts +7 -0
  97. package/dist/Dialog/DialogContext.d.ts.map +1 -1
  98. package/dist/Dialog/DialogContext.js +2 -2
  99. package/dist/Dialog/DialogHeader.d.ts +5 -2
  100. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  101. package/dist/Dialog/DialogHeader.js +6 -1
  102. package/dist/Divider/Divider.js +1 -1
  103. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
  104. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  105. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
  106. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
  107. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  108. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
  109. package/dist/Field/Field.d.ts.map +1 -1
  110. package/dist/Field/Field.js +2 -3
  111. package/dist/Field/FieldLabel.d.ts +1 -1
  112. package/dist/Field/FieldLabel.d.ts.map +1 -1
  113. package/dist/Field/FieldLabel.js +42 -15
  114. package/dist/FieldStatus/FieldStatus.d.ts +8 -0
  115. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  116. package/dist/FieldStatus/FieldStatus.js +22 -4
  117. package/dist/FileInput/FileInput.d.ts.map +1 -1
  118. package/dist/FileInput/FileInput.js +10 -2
  119. package/dist/HoverCard/HoverCard.d.ts +9 -1
  120. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  121. package/dist/HoverCard/HoverCard.js +2 -0
  122. package/dist/HoverCard/useHoverCard.d.ts +8 -0
  123. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  124. package/dist/HoverCard/useHoverCard.js +7 -2
  125. package/dist/Icon/Icon.d.ts +7 -2
  126. package/dist/Icon/Icon.d.ts.map +1 -1
  127. package/dist/Item/Item.d.ts +6 -1
  128. package/dist/Item/Item.d.ts.map +1 -1
  129. package/dist/Item/Item.js +22 -1
  130. package/dist/Layer/useLayer.d.ts +6 -0
  131. package/dist/Layer/useLayer.d.ts.map +1 -1
  132. package/dist/Layer/useLayer.js +2 -0
  133. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  134. package/dist/MobileNav/MobileNav.js +6 -1
  135. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  136. package/dist/MobileNav/MobileNavToggle.js +4 -0
  137. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  138. package/dist/MultiSelector/MultiSelector.js +39 -12
  139. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  140. package/dist/MultiSelector/hooks.js +16 -0
  141. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  142. package/dist/Outline/Outline.d.ts +0 -1
  143. package/dist/Outline/Outline.d.ts.map +1 -1
  144. package/dist/Outline/Outline.js +0 -1
  145. package/dist/OverflowList/OverflowList.d.ts +20 -3
  146. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  147. package/dist/OverflowList/OverflowList.js +29 -4
  148. package/dist/Popover/Popover.d.ts.map +1 -1
  149. package/dist/Popover/Popover.js +3 -2
  150. package/dist/Popover/usePopover.d.ts.map +1 -1
  151. package/dist/Popover/usePopover.js +3 -9
  152. package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
  153. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  154. package/dist/SelectableCard/SelectableCard.d.ts +9 -2
  155. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  156. package/dist/SelectableCard/SelectableCard.js +16 -13
  157. package/dist/Selector/Selector.d.ts.map +1 -1
  158. package/dist/Selector/Selector.js +4 -2
  159. package/dist/Selector/hooks.d.ts.map +1 -1
  160. package/dist/Selector/hooks.js +16 -0
  161. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  162. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  163. package/dist/SideNav/SideNavHeading.js +21 -8
  164. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  165. package/dist/Slider/Slider.d.ts.map +1 -1
  166. package/dist/Slider/Slider.js +19 -2
  167. package/dist/Stack/stack.stylex.d.ts +9 -9
  168. package/dist/Table/BaseTable.d.ts.map +1 -1
  169. package/dist/Table/BaseTable.js +3 -2
  170. package/dist/Table/index.d.ts +2 -0
  171. package/dist/Table/index.d.ts.map +1 -1
  172. package/dist/Table/index.js +1 -0
  173. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  174. package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
  175. package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
  176. package/dist/Table/plugins/rowStatus/index.js +3 -0
  177. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
  178. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
  179. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
  180. package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
  181. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  182. package/dist/Table/plugins/selection/useTableSelection.js +4 -1
  183. package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
  184. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  185. package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
  186. package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
  187. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
  188. package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
  189. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  190. package/dist/Table/useBaseTablePlugins.js +5 -3
  191. package/dist/Thumbnail/Thumbnail.d.ts +26 -5
  192. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  193. package/dist/Thumbnail/Thumbnail.js +97 -54
  194. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
  195. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
  196. package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
  197. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  198. package/dist/TimeInput/TimeInput.js +15 -4
  199. package/dist/Timestamp/Timestamp.d.ts +3 -1
  200. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  201. package/dist/Timestamp/Timestamp.js +8 -6
  202. package/dist/Toast/useToast.d.ts.map +1 -1
  203. package/dist/Toast/useToast.js +2 -5
  204. package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
  205. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  206. package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
  207. package/dist/Tokenizer/Tokenizer.d.ts +1 -1
  208. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  209. package/dist/Tokenizer/Tokenizer.js +16 -4
  210. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  211. package/dist/TopNav/TopNavHeading.js +18 -8
  212. package/dist/TopNav/TopNavMegaMenu.js +10 -4
  213. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
  214. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  215. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
  216. package/dist/TopNav/TopNavMenu.d.ts +2 -1
  217. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  218. package/dist/TopNav/TopNavMenu.js +68 -6
  219. package/dist/TreeList/TreeList.d.ts +12 -3
  220. package/dist/TreeList/TreeList.d.ts.map +1 -1
  221. package/dist/TreeList/TreeList.js +2 -0
  222. package/dist/TreeList/TreeListBranches.d.ts +5 -0
  223. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  224. package/dist/TreeList/TreeListBranches.js +10 -4
  225. package/dist/TreeList/TreeListItem.d.ts +8 -2
  226. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  227. package/dist/TreeList/TreeListItem.js +27 -7
  228. package/dist/TreeList/TreeListTypes.d.ts +25 -1
  229. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  230. package/dist/TreeList/index.d.ts +2 -2
  231. package/dist/TreeList/index.d.ts.map +1 -1
  232. package/dist/astryx.css +28 -18
  233. package/dist/astryx.umd.js +51 -51
  234. package/dist/astryx.umd.js.map +4 -4
  235. package/dist/authoring/doc.d.ts.map +1 -1
  236. package/dist/docs-types.d.ts +8 -0
  237. package/dist/docs-types.d.ts.map +1 -1
  238. package/dist/hooks/computeOverflow.d.ts +47 -0
  239. package/dist/hooks/computeOverflow.d.ts.map +1 -0
  240. package/dist/hooks/computeOverflow.js +213 -0
  241. package/dist/hooks/index.d.ts +1 -0
  242. package/dist/hooks/index.d.ts.map +1 -1
  243. package/dist/hooks/index.js +2 -1
  244. package/dist/hooks/useDevWarning.d.ts +18 -0
  245. package/dist/hooks/useDevWarning.d.ts.map +1 -0
  246. package/dist/hooks/useDevWarning.js +49 -0
  247. package/dist/hooks/useOverflow.d.ts +19 -0
  248. package/dist/hooks/useOverflow.d.ts.map +1 -1
  249. package/dist/hooks/useOverflow.js +36 -25
  250. package/dist/i18n/resolve.d.ts.map +1 -1
  251. package/dist/i18n/resolve.js +7 -18
  252. package/dist/theme/Theme.d.ts.map +1 -1
  253. package/dist/theme/Theme.js +2 -7
  254. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  255. package/dist/theme/generateThemeRules.js +51 -0
  256. package/dist/theme/hct.d.ts +0 -1
  257. package/dist/theme/hct.d.ts.map +1 -1
  258. package/dist/theme/hct.js +1 -1
  259. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  260. package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
  261. package/dist/utils/devWarning.d.ts +42 -0
  262. package/dist/utils/devWarning.d.ts.map +1 -0
  263. package/dist/utils/devWarning.js +88 -0
  264. package/dist/utils/index.d.ts +3 -1
  265. package/dist/utils/index.d.ts.map +1 -1
  266. package/dist/utils/index.js +3 -2
  267. package/dist/utils/plainDate.d.ts +30 -0
  268. package/dist/utils/plainDate.d.ts.map +1 -1
  269. package/dist/utils/plainDate.js +53 -0
  270. package/dist/utils/types.d.ts +13 -0
  271. package/dist/utils/types.d.ts.map +1 -1
  272. package/locales/en.json +24 -0
  273. package/locales/fr-FR.json +14 -0
  274. package/locales/pseudo.json +18 -0
  275. package/package.json +1 -1
  276. package/src/AppShell/AppShell.tsx +6 -0
  277. package/src/AppShell/AppShellMobileContext.tsx +8 -0
  278. package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
  279. package/src/Avatar/Avatar.doc.mjs +15 -3
  280. package/src/Avatar/Avatar.test.tsx +156 -1
  281. package/src/Avatar/Avatar.tsx +96 -4
  282. package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
  283. package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
  284. package/src/Avatar/AvatarStatusDot.tsx +178 -21
  285. package/src/Banner/Banner.doc.mjs +9 -0
  286. package/src/Banner/Banner.test.tsx +30 -0
  287. package/src/Banner/Banner.tsx +47 -3
  288. package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
  289. package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
  290. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
  291. package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
  292. package/src/Breadcrumbs/index.ts +27 -0
  293. package/src/Button/Button.doc.mjs +9 -0
  294. package/src/Button/Button.test.tsx +49 -0
  295. package/src/Button/Button.tsx +25 -1
  296. package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
  297. package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
  298. package/src/ButtonGroup/ButtonGroup.tsx +32 -0
  299. package/src/Calendar/Calendar.doc.mjs +12 -1
  300. package/src/Calendar/Calendar.test.tsx +193 -0
  301. package/src/Calendar/Calendar.tsx +38 -16
  302. package/src/Calendar/dayCellUtils.test.ts +5 -0
  303. package/src/Calendar/dayCellUtils.ts +1 -1
  304. package/src/Card/Card.doc.mjs +9 -0
  305. package/src/Card/Card.test.tsx +21 -3
  306. package/src/Card/Card.tsx +35 -2
  307. package/src/Carousel/Carousel.doc.mjs +1 -0
  308. package/src/Carousel/Carousel.test.tsx +53 -0
  309. package/src/Carousel/Carousel.tsx +34 -4
  310. package/src/Chat/ChatComposer.doc.mjs +12 -3
  311. package/src/Chat/ChatComposer.test.tsx +115 -0
  312. package/src/Chat/ChatComposer.tsx +73 -9
  313. package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
  314. package/src/Chat/ChatComposerDrawer.tsx +11 -1
  315. package/src/Chat/ChatComposerInput.doc.mjs +7 -0
  316. package/src/Chat/ChatComposerInput.test.tsx +103 -0
  317. package/src/Chat/ChatComposerInput.tsx +49 -3
  318. package/src/Chat/ChatContext.tsx +37 -10
  319. package/src/Chat/ChatDictationButton.tsx +4 -1
  320. package/src/Chat/ChatLayout.tsx +3 -1
  321. package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
  322. package/src/Chat/ChatMessageMetadata.tsx +1 -2
  323. package/src/Chat/ChatSendButton.tsx +11 -1
  324. package/src/Chat/ChatToolCalls.test.tsx +64 -0
  325. package/src/Chat/ChatToolCalls.tsx +25 -4
  326. package/src/Chat/index.ts +5 -1
  327. package/src/Chat/useChatStreamScroll.test.tsx +49 -0
  328. package/src/Chat/useChatStreamScroll.ts +27 -10
  329. package/src/Chat/useSpeechRecognition.ts +1 -1
  330. package/src/Chat/useTriggerMenu.tsx +3 -1
  331. package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
  332. package/src/CheckboxInput/CheckboxInput.tsx +1 -1
  333. package/src/CheckboxList/CheckboxList.test.tsx +81 -3
  334. package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
  335. package/src/CheckboxList/CheckboxListItem.tsx +41 -5
  336. package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
  337. package/src/ClickableCard/ClickableCard.test.tsx +34 -0
  338. package/src/ClickableCard/ClickableCard.tsx +13 -3
  339. package/src/CodeBlock/CodeBlock.test.tsx +56 -0
  340. package/src/CodeBlock/CodeBlock.tsx +9 -1
  341. package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
  342. package/src/CommandPalette/CommandPalette.tsx +3 -1
  343. package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
  344. package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
  345. package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
  346. package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
  347. package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
  348. package/src/ContextMenu/ContextMenu.test.tsx +193 -0
  349. package/src/DateInput/DateInput.doc.mjs +16 -0
  350. package/src/DateInput/DateInput.test.tsx +108 -0
  351. package/src/DateInput/DateInput.tsx +68 -3
  352. package/src/DateInput/index.ts +1 -0
  353. package/src/DateTimeInput/DateTimeInput.test.tsx +35 -0
  354. package/src/DateTimeInput/DateTimeInput.tsx +14 -2
  355. package/src/Dialog/Dialog.doc.mjs +2 -2
  356. package/src/Dialog/Dialog.test.tsx +77 -4
  357. package/src/Dialog/Dialog.tsx +89 -5
  358. package/src/Dialog/DialogContext.ts +9 -2
  359. package/src/Dialog/DialogHeader.doc.mjs +2 -2
  360. package/src/Dialog/DialogHeader.tsx +9 -2
  361. package/src/Divider/Divider.tsx +2 -2
  362. package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
  363. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
  364. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
  365. package/src/Field/Field.test.tsx +57 -12
  366. package/src/Field/Field.tsx +6 -5
  367. package/src/Field/FieldLabel.tsx +8 -0
  368. package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
  369. package/src/FieldStatus/FieldStatus.test.tsx +78 -40
  370. package/src/FieldStatus/FieldStatus.tsx +22 -4
  371. package/src/FileInput/FileInput.test.tsx +52 -3
  372. package/src/FileInput/FileInput.tsx +13 -2
  373. package/src/HoverCard/HoverCard.doc.mjs +13 -0
  374. package/src/HoverCard/HoverCard.test.tsx +21 -2
  375. package/src/HoverCard/HoverCard.tsx +11 -0
  376. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  377. package/src/HoverCard/useHoverCard.tsx +24 -2
  378. package/src/Icon/Icon.doc.mjs +3 -2
  379. package/src/Icon/Icon.tsx +7 -2
  380. package/src/IconButton/IconButton.doc.mjs +8 -0
  381. package/src/IconButton/IconButton.test.tsx +15 -18
  382. package/src/Item/Item.test.tsx +40 -18
  383. package/src/Item/Item.tsx +38 -2
  384. package/src/Layer/useLayer.tsx +8 -0
  385. package/src/List/List.test.tsx +9 -8
  386. package/src/MobileNav/MobileNav.tsx +12 -1
  387. package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
  388. package/src/MobileNav/MobileNavToggle.tsx +9 -1
  389. package/src/MultiSelector/MultiSelector.doc.mjs +4 -2
  390. package/src/MultiSelector/MultiSelector.test.tsx +172 -3
  391. package/src/MultiSelector/MultiSelector.tsx +55 -12
  392. package/src/MultiSelector/hooks.ts +17 -0
  393. package/src/NumberInput/NumberInput.test.tsx +11 -7
  394. package/src/NumberInput/NumberInput.tsx +1 -2
  395. package/src/Outline/Outline.tsx +0 -1
  396. package/src/OverflowList/OverflowList.doc.mjs +39 -6
  397. package/src/OverflowList/OverflowList.test.tsx +111 -0
  398. package/src/OverflowList/OverflowList.tsx +48 -8
  399. package/src/Popover/Popover.tsx +7 -4
  400. package/src/Popover/usePopover.tsx +9 -13
  401. package/src/PowerSearch/PowerSearch.doc.mjs +14 -0
  402. package/src/PowerSearch/PowerSearch.test.tsx +20 -0
  403. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
  404. package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
  405. package/src/PowerSearch/usePowerSearchSource.ts +1 -2
  406. package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
  407. package/src/SelectableCard/SelectableCard.test.tsx +46 -4
  408. package/src/SelectableCard/SelectableCard.tsx +29 -16
  409. package/src/Selector/Selector.test.tsx +69 -0
  410. package/src/Selector/Selector.tsx +5 -1
  411. package/src/Selector/hooks.ts +17 -0
  412. package/src/SideNav/SideNav.test.tsx +119 -3
  413. package/src/SideNav/SideNavCollapseButton.tsx +6 -1
  414. package/src/SideNav/SideNavHeading.tsx +24 -8
  415. package/src/SideNav/SideNavItem.tsx +5 -1
  416. package/src/Slider/Slider.test.tsx +75 -2
  417. package/src/Slider/Slider.tsx +21 -5
  418. package/src/Switch/Switch.test.tsx +32 -1
  419. package/src/Table/BaseTable.tsx +3 -5
  420. package/src/Table/index.ts +5 -0
  421. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
  422. package/src/Table/plugins/rowStatus/index.ts +7 -0
  423. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
  424. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
  425. package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
  426. package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
  427. package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
  428. package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
  429. package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
  430. package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
  431. package/src/Table/useBaseTablePlugins.ts +10 -6
  432. package/src/Table/useTableRowStatus.doc.mjs +30 -0
  433. package/src/Table/useTableSelection.doc.mjs +65 -14
  434. package/src/Table/useTableTreeData.doc.mjs +29 -0
  435. package/src/Table/useTableTreeState.doc.mjs +2 -2
  436. package/src/TextArea/TextArea.test.tsx +9 -1
  437. package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
  438. package/src/Thumbnail/Thumbnail.test.tsx +98 -7
  439. package/src/Thumbnail/Thumbnail.tsx +141 -41
  440. package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
  441. package/src/TimeInput/TimeInput.test.tsx +76 -1
  442. package/src/TimeInput/TimeInput.tsx +19 -6
  443. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  444. package/src/Timestamp/Timestamp.test.tsx +32 -0
  445. package/src/Timestamp/Timestamp.tsx +28 -8
  446. package/src/Toast/useToast.tsx +7 -8
  447. package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
  448. package/src/Tokenizer/Tokenizer.doc.mjs +15 -1
  449. package/src/Tokenizer/Tokenizer.test.tsx +183 -2
  450. package/src/Tokenizer/Tokenizer.tsx +16 -4
  451. package/src/TopNav/TopNav.test.tsx +125 -1
  452. package/src/TopNav/TopNavHeading.tsx +24 -8
  453. package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
  454. package/src/TopNav/TopNavMegaMenu.tsx +10 -4
  455. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
  456. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
  457. package/src/TopNav/TopNavMenu.test.tsx +118 -4
  458. package/src/TopNav/TopNavMenu.tsx +83 -5
  459. package/src/TreeList/TreeList.doc.mjs +22 -0
  460. package/src/TreeList/TreeList.test.tsx +232 -0
  461. package/src/TreeList/TreeList.tsx +18 -2
  462. package/src/TreeList/TreeListBranches.tsx +16 -2
  463. package/src/TreeList/TreeListItem.tsx +51 -11
  464. package/src/TreeList/TreeListTypes.ts +27 -1
  465. package/src/TreeList/index.ts +2 -2
  466. package/src/authoring/doc.ts +1 -3
  467. package/src/docs-types.ts +5 -0
  468. package/src/hooks/computeOverflow.test.ts +422 -0
  469. package/src/hooks/computeOverflow.ts +290 -0
  470. package/src/hooks/index.ts +2 -0
  471. package/src/hooks/useDevWarning.test.tsx +45 -0
  472. package/src/hooks/useDevWarning.ts +54 -0
  473. package/src/hooks/useOverflow.test.ts +96 -4
  474. package/src/hooks/useOverflow.ts +74 -33
  475. package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
  476. package/src/i18n/resolve.ts +9 -21
  477. package/src/theme/Theme.tsx +11 -14
  478. package/src/theme/generateThemeRules.test.ts +65 -0
  479. package/src/theme/generateThemeRules.ts +56 -0
  480. package/src/theme/hct.ts +1 -1
  481. package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
  482. package/src/utils/devWarning.test.ts +56 -0
  483. package/src/utils/devWarning.ts +102 -0
  484. package/src/utils/index.ts +6 -0
  485. package/src/utils/plainDate.test.ts +22 -0
  486. package/src/utils/plainDate.ts +61 -0
  487. package/src/utils/types.ts +14 -0
@@ -46,8 +46,10 @@ import {
46
46
  borderVars,
47
47
  durationVars,
48
48
  easeVars,
49
+ shadowVars,
49
50
  } from '../theme/tokens.stylex';
50
51
  import {mergeProps} from '../utils';
52
+ import type {Elevation} from '../utils/types';
51
53
  import {edgeCompSlot} from '../Layout/edgeCompensation.stylex';
52
54
  import {themeProps} from '../utils/themeProps';
53
55
  import {useTranslator} from '../i18n';
@@ -157,6 +159,13 @@ export interface BannerProps extends BaseProps<HTMLDivElement> {
157
159
  * @default 'card'
158
160
  */
159
161
  container?: BannerContainer;
162
+ /**
163
+ * Resting elevation — the shadow depth the banner sits at. Use for a
164
+ * floating banner that hovers above content. `none` is the default inline
165
+ * banner.
166
+ * @default 'none'
167
+ */
168
+ elevation?: Elevation;
160
169
  /**
161
170
  * Whether the content area (children) starts expanded.
162
171
  * Only relevant when children are provided.
@@ -215,6 +224,11 @@ const styles = stylex.create({
215
224
  flexDirection: 'column',
216
225
  fontFamily: 'inherit',
217
226
  },
227
+ // When elevated, a card-container banner rounds its root so the shadow
228
+ // follows the same silhouette as the header/content border-radius.
229
+ rootElevatedCard: {
230
+ borderRadius: radiusVars['--radius-container'],
231
+ },
218
232
  // Header area — colored status background with icon, title, description, actions
219
233
  // This is the primary theme target ('banner')
220
234
  header: {
@@ -323,6 +337,18 @@ const statusStyles = stylex.create({
323
337
  },
324
338
  });
325
339
 
340
+ // Resting elevation for the banner. Applied to the root so the shadow wraps
341
+ // the whole banner (header + optional content). 'none' is the default and
342
+ // leaves the layout-only root untouched. For the `card` container the root is
343
+ // rounded (rootElevatedCard) so the shadow follows the card silhouette; the
344
+ // full-width `section` container stays square.
345
+ const elevationStyles = stylex.create({
346
+ none: {boxShadow: 'none'},
347
+ low: {boxShadow: shadowVars['--shadow-low']},
348
+ med: {boxShadow: shadowVars['--shadow-med']},
349
+ high: {boxShadow: shadowVars['--shadow-high']},
350
+ });
351
+
326
352
  // =============================================================================
327
353
  // Component
328
354
  // =============================================================================
@@ -381,6 +407,7 @@ export function Banner({
381
407
  onDismiss,
382
408
  endContent,
383
409
  container = 'card',
410
+ elevation = 'none',
384
411
  defaultIsExpanded = false,
385
412
  children,
386
413
  xstyle,
@@ -429,7 +456,16 @@ export function Banner({
429
456
  <div
430
457
  ref={ref}
431
458
  role={role}
432
- {...mergeProps(stylex.props(styles.root, xstyle), className, style)}
459
+ {...mergeProps(
460
+ stylex.props(
461
+ styles.root,
462
+ elevationStyles[elevation],
463
+ isCard && elevation !== 'none' && styles.rootElevatedCard,
464
+ xstyle,
465
+ ),
466
+ className,
467
+ style,
468
+ )}
433
469
  {...rest}>
434
470
  {/* Header: colored status background — primary theme target ('banner') */}
435
471
  <div
@@ -474,8 +510,16 @@ export function Banner({
474
510
  <Button
475
511
  variant="ghost"
476
512
  size="sm"
477
- label={isExpanded ? t('@astryx.banner.collapse') : t('@astryx.banner.expand')}
478
- tooltip={isExpanded ? t('@astryx.banner.collapse') : t('@astryx.banner.expand')}
513
+ label={
514
+ isExpanded
515
+ ? t('@astryx.banner.collapse')
516
+ : t('@astryx.banner.expand')
517
+ }
518
+ tooltip={
519
+ isExpanded
520
+ ? t('@astryx.banner.collapse')
521
+ : t('@astryx.banner.expand')
522
+ }
479
523
  icon={
480
524
  <span
481
525
  {...stylex.props(
@@ -45,6 +45,18 @@ export const docs = {
45
45
  },
46
46
  ],
47
47
  },
48
+ {
49
+ name: 'menu',
50
+ type: 'DropdownMenuOption[] | ReactNode',
51
+ description:
52
+ 'Menu opened when the item is activated, using the same item API as DropdownMenu/MoreMenu/ContextMenu (a DropdownMenuOption[] array or composed DropdownMenuItem children). Renders a link-styled menu trigger with a chevron and aria-haspopup="menu". Takes precedence over href/onClick.',
53
+ },
54
+ {
55
+ name: 'menuSize',
56
+ type: "'sm' | 'md' | 'lg'",
57
+ description:
58
+ "Size passed to the menu items. Defaults from the breadcrumb variant ('supporting' → 'sm', otherwise 'md').",
59
+ },
48
60
  {
49
61
  name: 'as',
50
62
  type: 'LinkComponentType',
@@ -86,6 +98,18 @@ export const docsZh = {
86
98
  type: 'ReactNode',
87
99
  description: '在项目标签前渲染的图标。',
88
100
  },
101
+ {
102
+ name: 'menu',
103
+ type: 'DropdownMenuOption[] | ReactNode',
104
+ description:
105
+ '激活项目时打开的菜单,使用与 DropdownMenu/MoreMenu/ContextMenu 相同的项目 API(DropdownMenuOption[] 数组或组合的 DropdownMenuItem 子元素)。渲染为带 chevron 和 aria-haspopup="menu" 的链接样式触发器。优先于 href/onClick。',
106
+ },
107
+ {
108
+ name: 'menuSize',
109
+ type: "'sm' | 'md' | 'lg'",
110
+ description:
111
+ "传递给菜单项的尺寸。默认根据面包屑变体推断('supporting' → 'sm',否则 'md')。",
112
+ },
89
113
  {
90
114
  name: 'as',
91
115
  type: 'LinkComponentType',
@@ -105,6 +129,8 @@ export const docsDense = {
105
129
  onClick: 'click handler',
106
130
  isCurrent: 'marks current page w/ aria-current="page"',
107
131
  startIcon: 'icon before label',
132
+ menu: 'DropdownMenuOption[] | children; opens a menu trigger (aria-haspopup="menu"); reuses the DropdownMenu item API',
133
+ menuSize: "menu item size; defaults from variant (supporting→sm, else md)",
108
134
  as: 'custom link component; overrides LinkProvider default',
109
135
  },
110
136
  };
@@ -4,10 +4,16 @@
4
4
 
5
5
  /**
6
6
  * @file BreadcrumbItem.tsx
7
- * @input Uses React use/useRef/useEffect, stylex, theme tokens, BreadcrumbContext
7
+ * @input Uses React use/useRef/useEffect, stylex, theme tokens, BreadcrumbContext,
8
+ * and (for the menu trigger) usePopover + the shared DropdownMenu item API
9
+ * (renderDropdownItems, DropdownMenuContext, MENU_ITEM_SELECTOR, useListFocus)
8
10
  * @output Exports BreadcrumbItem component and BreadcrumbItemProps
9
11
  * @position Individual breadcrumb item; used inside Breadcrumbs
10
12
  *
13
+ * A `menu` prop turns the item's link-styled button into a menu trigger whose
14
+ * popover reuses DropdownMenu's item pipeline — the same wiring ContextMenu
15
+ * uses — so menu-item definitions are portable across the menu family.
16
+ *
11
17
  * SYNC: When modified, update these files to stay in sync:
12
18
  * - /packages/core/src/Breadcrumbs/Breadcrumbs.doc.mjs
13
19
  * - /packages/core/src/Breadcrumbs/Breadcrumbs.test.tsx
@@ -18,19 +24,43 @@
18
24
 
19
25
  import React, {
20
26
  use,
27
+ useCallback,
28
+ useId,
29
+ useMemo,
21
30
  useRef,
22
31
  useEffect,
23
32
  type ReactNode,
24
33
  type MouseEvent,
25
34
  } from 'react';
26
35
  import * as stylex from '@stylexjs/stylex';
27
- import {colorVars, spacingVars, typeScaleVars} from '../theme/tokens.stylex';
36
+ import {
37
+ colorVars,
38
+ spacingVars,
39
+ typeScaleVars,
40
+ radiusVars,
41
+ } from '../theme/tokens.stylex';
28
42
  import {BreadcrumbContext} from './Breadcrumbs';
29
43
  import {useLinkComponent} from '../Link/useLinkComponent';
30
44
  import type {LinkComponentType} from '../Link/types';
31
45
  import {mergeProps, mergeRefs} from '../utils';
32
46
  import type {BaseProps} from '../BaseProps';
33
47
  import {themeProps} from '../utils/themeProps';
48
+ import {getIcon} from '../Icon/globalIconRegistry';
49
+ import {usePopover} from '../Popover/usePopover';
50
+ import {useListFocus} from '../hooks/useListFocus';
51
+ import {useTypeahead} from '../hooks/useTypeahead';
52
+ import {layerAnimations} from '../Layer/layerAnimations.stylex';
53
+ import {renderDropdownItems} from '../DropdownMenu/renderDropdownItems';
54
+ import {
55
+ DropdownMenuContext,
56
+ type DropdownMenuContextValue,
57
+ type DropdownMenuSize,
58
+ } from '../DropdownMenu/DropdownMenuContext';
59
+ import {
60
+ MENU_ITEM_ROLES,
61
+ MENU_ITEM_SELECTOR,
62
+ } from '../DropdownMenu/menuItemRoles';
63
+ import type {DropdownMenuOption} from '../DropdownMenu/DropdownMenu';
34
64
 
35
65
  // =============================================================================
36
66
  // Props
@@ -69,6 +99,27 @@ export interface BreadcrumbItemProps extends Omit<
69
99
  * Optional icon rendered before the label.
70
100
  */
71
101
  startIcon?: ReactNode;
102
+ /**
103
+ * Menu opened when the item is activated. Accepts the SAME item API as
104
+ * DropdownMenu / MoreMenu / ContextMenu, so a consumer's existing menu-item
105
+ * definitions are portable into a breadcrumb with no rewrite:
106
+ * - a `DropdownMenuOption[]` data array (items, sections, dividers), or
107
+ * - composed `DropdownMenuItem` / `DropdownMenuCheckboxItem` /
108
+ * `DropdownMenuRadioGroup` children.
109
+ *
110
+ * When set, the item renders as a link-styled menu trigger (button + a
111
+ * trailing chevron, `aria-haspopup="menu"` / `aria-expanded`) whose popover
112
+ * is a `role="menu"` container that provides `DropdownMenuContext` and runs
113
+ * `useListFocus`. Takes precedence over `href` / `onClick` (which are
114
+ * ignored when `menu` is set — a dev-time warning is logged).
115
+ */
116
+ menu?: DropdownMenuOption[] | ReactNode;
117
+ /**
118
+ * Size passed to the menu items via `DropdownMenuContext` (item
119
+ * padding/typography). Defaults from the breadcrumb variant:
120
+ * `'supporting'` → `'sm'`, otherwise `'md'`.
121
+ */
122
+ menuSize?: DropdownMenuSize;
72
123
  }
73
124
 
74
125
  // =============================================================================
@@ -140,6 +191,12 @@ const itemStyles = stylex.create({
140
191
  alignItems: 'center',
141
192
  flexShrink: 0,
142
193
  },
194
+ chevron: {
195
+ display: 'flex',
196
+ alignItems: 'center',
197
+ flexShrink: 0,
198
+ fontSize: typeScaleVars['--text-supporting-size'],
199
+ },
143
200
  separator: {
144
201
  display: 'var(--separator-display)',
145
202
  alignItems: 'center',
@@ -149,6 +206,26 @@ const itemStyles = stylex.create({
149
206
  },
150
207
  });
151
208
 
209
+ const menuStyles = stylex.create({
210
+ menu: {
211
+ boxSizing: 'border-box',
212
+ display: 'flex',
213
+ flexDirection: 'column',
214
+ gap: spacingVars['--spacing-0-5'],
215
+ maxHeight: '300px',
216
+ overflowY: 'auto',
217
+ '--_dropdown-menu-radius': radiusVars['--radius-container'],
218
+ '--_dropdown-menu-padding': spacingVars['--spacing-1'],
219
+ padding: spacingVars['--spacing-1'],
220
+ borderRadius: 'var(--_dropdown-menu-radius)',
221
+ userSelect: 'none',
222
+ },
223
+ popover: {
224
+ minWidth: '160px',
225
+ marginBlock: spacingVars['--spacing-1'],
226
+ },
227
+ });
228
+
152
229
  // =============================================================================
153
230
  // Component
154
231
  // =============================================================================
@@ -175,6 +252,8 @@ export function BreadcrumbItem({
175
252
  onClick,
176
253
  isCurrent: isCurrentProp,
177
254
  startIcon,
255
+ menu,
256
+ menuSize,
178
257
  xstyle,
179
258
  className,
180
259
  style,
@@ -192,6 +271,28 @@ export function BreadcrumbItem({
192
271
 
193
272
  const isCurrent = isCurrentProp === true;
194
273
  const isAutoCandidate = isCurrentProp == null;
274
+ const hasMenu = menu != null;
275
+ const resolvedMenuSize: DropdownMenuSize =
276
+ menuSize ?? (isSupporting ? 'sm' : 'md');
277
+
278
+ // `menu` owns the click interaction; a label can't both navigate/act and
279
+ // open a menu on the same activation. Warn once so the (ignored) href/onClick
280
+ // don't silently disappear on the consumer.
281
+ useEffect(() => {
282
+ if (process.env.NODE_ENV !== 'production' && hasMenu) {
283
+ if (href != null) {
284
+ console.warn(
285
+ 'BreadcrumbItem: `menu` and `href` are mutually exclusive; `menu` ' +
286
+ 'takes precedence and `href` is ignored.',
287
+ );
288
+ } else if (onClick != null) {
289
+ console.warn(
290
+ 'BreadcrumbItem: `menu` and `onClick` are mutually exclusive; ' +
291
+ '`menu` takes precedence and `onClick` is ignored.',
292
+ );
293
+ }
294
+ }
295
+ }, [hasMenu, href, onClick]);
195
296
 
196
297
  // Auto-detect: if no sibling has aria-current="page" and this is the last
197
298
  // non-separator item, set aria-current on our content element.
@@ -258,17 +359,31 @@ export function BreadcrumbItem({
258
359
  <span aria-hidden="true" {...stylex.props(itemStyles.separator)}>
259
360
  {ctx.separator}
260
361
  </span>
261
- <span
262
- {...stylex.props(
263
- itemStyles.contentWrapper,
264
- itemStyles.current,
265
- isSupporting
266
- ? itemStyles.supportingCurrent
267
- : itemStyles.defaultCurrent,
268
- )}
269
- aria-current="page">
270
- {content}
271
- </span>
362
+ {hasMenu ? (
363
+ // A current crumb can also open a sibling menu — the trigger keeps
364
+ // both aria-current="page" and aria-haspopup="menu".
365
+ <BreadcrumbMenuTrigger
366
+ ref={contentRef}
367
+ menu={menu}
368
+ menuSize={resolvedMenuSize}
369
+ isSupporting={isSupporting}
370
+ isCurrent
371
+ label={children}>
372
+ {content}
373
+ </BreadcrumbMenuTrigger>
374
+ ) : (
375
+ <span
376
+ {...stylex.props(
377
+ itemStyles.contentWrapper,
378
+ itemStyles.current,
379
+ isSupporting
380
+ ? itemStyles.supportingCurrent
381
+ : itemStyles.defaultCurrent,
382
+ )}
383
+ aria-current="page">
384
+ {content}
385
+ </span>
386
+ )}
272
387
  </li>
273
388
  );
274
389
  }
@@ -293,7 +408,16 @@ export function BreadcrumbItem({
293
408
  <span aria-hidden="true" {...stylex.props(itemStyles.separator)}>
294
409
  {ctx.separator}
295
410
  </span>
296
- {href != null ? (
411
+ {hasMenu ? (
412
+ <BreadcrumbMenuTrigger
413
+ ref={contentRef}
414
+ menu={menu}
415
+ menuSize={resolvedMenuSize}
416
+ isSupporting={isSupporting}
417
+ label={children}>
418
+ {content}
419
+ </BreadcrumbMenuTrigger>
420
+ ) : href != null ? (
297
421
  <LinkComponent
298
422
  ref={contentRef}
299
423
  href={href}
@@ -334,3 +458,198 @@ export function BreadcrumbItem({
334
458
  }
335
459
 
336
460
  BreadcrumbItem.displayName = 'BreadcrumbItem';
461
+
462
+ // =============================================================================
463
+ // Menu trigger
464
+ // =============================================================================
465
+
466
+ interface BreadcrumbMenuTriggerProps {
467
+ ref: React.Ref<HTMLElement>;
468
+ /** The link-styled label content rendered inside the trigger button. */
469
+ children: ReactNode;
470
+ /** Accessible name for the menu surface (the crumb's label). */
471
+ label: ReactNode;
472
+ menu: DropdownMenuOption[] | ReactNode;
473
+ menuSize: DropdownMenuSize;
474
+ isSupporting: boolean;
475
+ isCurrent?: boolean;
476
+ }
477
+
478
+ /**
479
+ * The link-styled `<button>` trigger + its `role="menu"` popover. Reuses the
480
+ * DropdownMenu item pipeline (`renderDropdownItems` for arrays, the item
481
+ * components for children) inside a `useListFocus` container that provides
482
+ * `DropdownMenuContext` — the same wiring ContextMenu uses — so menu-item
483
+ * definitions are portable into a breadcrumb with no rewrite.
484
+ */
485
+ function BreadcrumbMenuTrigger({
486
+ ref,
487
+ children,
488
+ label,
489
+ menu,
490
+ menuSize,
491
+ isSupporting,
492
+ isCurrent = false,
493
+ }: BreadcrumbMenuTriggerProps) {
494
+ const menuId = useId();
495
+ const buttonRef = useRef<HTMLButtonElement>(null);
496
+
497
+ const popover = usePopover({
498
+ onHide: useCallback(() => {
499
+ buttonRef.current?.focus();
500
+ }, []),
501
+ hasLightDismiss: true,
502
+ hasCloseButton: false,
503
+ hasAutoFocus: false,
504
+ // The popup's own role="menu" is the exposed semantics; a modal dialog
505
+ // wrapper would announce an unnamed dialog around the menu.
506
+ role: 'none',
507
+ });
508
+
509
+ const closeMenu = useCallback(() => {
510
+ popover.hide();
511
+ }, [popover]);
512
+
513
+ const {
514
+ listRef,
515
+ handleKeyDown: listNavKeyDown,
516
+ focusFirst,
517
+ focusItem,
518
+ } = useListFocus<HTMLDivElement>({
519
+ itemSelector: MENU_ITEM_SELECTOR,
520
+ wrap: false,
521
+ onEscape: closeMenu,
522
+ });
523
+
524
+ const getMenuItems = useCallback(
525
+ (): HTMLElement[] =>
526
+ listRef.current
527
+ ? Array.from(
528
+ listRef.current.querySelectorAll<HTMLElement>(MENU_ITEM_SELECTOR),
529
+ )
530
+ : [],
531
+ [listRef],
532
+ );
533
+ const typeahead = useTypeahead({
534
+ getItemLabels: () => getMenuItems().map(el => el.textContent),
535
+ onMatch: focusItem,
536
+ getCurrentIndex: () =>
537
+ getMenuItems().findIndex(
538
+ el =>
539
+ el === document.activeElement || el.contains(document.activeElement),
540
+ ),
541
+ });
542
+
543
+ const listKeyDown = useCallback(
544
+ (e: React.KeyboardEvent) => {
545
+ if (e.key === 'Enter' || e.key === ' ') {
546
+ e.preventDefault();
547
+ const focused = document.activeElement as HTMLElement | null;
548
+ if (
549
+ focused &&
550
+ MENU_ITEM_ROLES.has(focused.getAttribute('role') ?? '')
551
+ ) {
552
+ focused.click();
553
+ }
554
+ return;
555
+ }
556
+ // APG menu-button pattern: Tab closes the menu (items are tabIndex={-1}).
557
+ if (e.key === 'Tab') {
558
+ closeMenu();
559
+ return;
560
+ }
561
+ if (typeahead.onKeyDown(e)) {
562
+ e.preventDefault();
563
+ return;
564
+ }
565
+ listNavKeyDown(e);
566
+ },
567
+ [listNavKeyDown, closeMenu, typeahead],
568
+ );
569
+
570
+ const openAndFocus = useCallback(() => {
571
+ popover.show();
572
+ requestAnimationFrame(() => focusFirst());
573
+ }, [popover, focusFirst]);
574
+
575
+ const handleClick = useCallback(() => {
576
+ if (popover.isOpen) {
577
+ popover.hide();
578
+ } else {
579
+ openAndFocus();
580
+ }
581
+ }, [popover, openAndFocus]);
582
+
583
+ const handleKeyDown = useCallback(
584
+ (e: React.KeyboardEvent) => {
585
+ if (!popover.isOpen) {
586
+ if (e.key === 'ArrowDown' || e.key === 'Enter' || e.key === ' ') {
587
+ e.preventDefault();
588
+ openAndFocus();
589
+ }
590
+ }
591
+ },
592
+ [popover.isOpen, openAndFocus],
593
+ );
594
+
595
+ const contextValue = useMemo<DropdownMenuContextValue>(
596
+ () => ({closeMenu, menuSize}),
597
+ [closeMenu, menuSize],
598
+ );
599
+
600
+ const menuContent = Array.isArray(menu) ? renderDropdownItems(menu) : menu;
601
+
602
+ return (
603
+ <>
604
+ <button
605
+ ref={mergeRefs(
606
+ ref as React.Ref<HTMLButtonElement>,
607
+ buttonRef,
608
+ popover.triggerRef,
609
+ )}
610
+ type="button"
611
+ onClick={handleClick}
612
+ onKeyDown={handleKeyDown}
613
+ {...mergeProps(themeProps('breadcrumb-item-menu-trigger'), {
614
+ ...popover.triggerProps,
615
+ 'aria-haspopup': 'menu' as const,
616
+ 'aria-controls': menuId,
617
+ 'aria-current': isCurrent ? ('page' as const) : undefined,
618
+ })}
619
+ {...stylex.props(
620
+ itemStyles.link,
621
+ itemStyles.buttonReset,
622
+ isSupporting ? itemStyles.supportingLink : itemStyles.defaultLink,
623
+ )}>
624
+ {children}
625
+ <span aria-hidden="true" {...stylex.props(itemStyles.chevron)}>
626
+ {getIcon('chevronDown')}
627
+ </span>
628
+ </button>
629
+
630
+ {popover.render(
631
+ <div
632
+ ref={listRef}
633
+ id={menuId}
634
+ role="menu"
635
+ aria-label={typeof label === 'string' ? label : undefined}
636
+ onKeyDown={listKeyDown}
637
+ {...mergeProps(
638
+ themeProps('breadcrumb-menu'),
639
+ stylex.props(menuStyles.menu),
640
+ )}>
641
+ <DropdownMenuContext value={contextValue}>
642
+ {menuContent}
643
+ </DropdownMenuContext>
644
+ </div>,
645
+ {
646
+ placement: 'below',
647
+ alignment: 'start',
648
+ xstyle: [menuStyles.popover, layerAnimations.below],
649
+ },
650
+ )}
651
+ </>
652
+ );
653
+ }
654
+
655
+ BreadcrumbMenuTrigger.displayName = 'BreadcrumbMenuTrigger';
@@ -30,6 +30,8 @@ export const docs = {
30
30
  theming: {
31
31
  targets: [
32
32
  {className: 'astryx-breadcrumb-item'},
33
+ {className: 'astryx-breadcrumb-item-menu-trigger'},
34
+ {className: 'astryx-breadcrumb-menu'},
33
35
  {className: 'astryx-breadcrumbs', visualProps: ['variant']},
34
36
  ],
35
37
  },