@astryxdesign/core 0.3.0 → 0.4.0

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 (551) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +10 -2
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +22 -3
  5. package/dist/AppShell/AppShell.d.ts +2 -2
  6. package/dist/AppShell/AppShell.d.ts.map +1 -1
  7. package/dist/AppShell/AppShell.js +40 -9
  8. package/dist/AspectRatio/AspectRatio.d.ts +13 -0
  9. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  10. package/dist/AspectRatio/AspectRatio.js +9 -0
  11. package/dist/Avatar/Avatar.d.ts.map +1 -1
  12. package/dist/Avatar/Avatar.js +33 -20
  13. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroupOverflow.js +2 -3
  15. package/dist/Banner/Banner.d.ts.map +1 -1
  16. package/dist/Banner/Banner.js +15 -14
  17. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  18. package/dist/Breadcrumbs/BreadcrumbItem.js +21 -8
  19. package/dist/Breadcrumbs/index.d.ts +2 -1
  20. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  21. package/dist/Breadcrumbs/index.js +1 -0
  22. package/dist/Button/Button.d.ts.map +1 -1
  23. package/dist/Button/Button.js +11 -15
  24. package/dist/Calendar/Calendar.d.ts.map +1 -1
  25. package/dist/Calendar/Calendar.js +2 -1
  26. package/dist/Calendar/styles.d.ts +0 -2
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +0 -2
  29. package/dist/Carousel/Carousel.d.ts.map +1 -1
  30. package/dist/Carousel/Carousel.js +8 -12
  31. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  32. package/dist/Chat/ChatDictationButton.js +2 -1
  33. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  34. package/dist/Chat/ChatLayoutScrollButton.js +3 -1
  35. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  36. package/dist/Chat/ChatSendButton.js +4 -3
  37. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  38. package/dist/Chat/ChatToolCalls.js +17 -17
  39. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  40. package/dist/Chat/useTriggerMenu.js +2 -6
  41. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  42. package/dist/CheckboxInput/CheckboxInput.js +36 -125
  43. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  44. package/dist/ClickableCard/ClickableCard.js +3 -11
  45. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  46. package/dist/CodeBlock/CodeBlock.js +84 -67
  47. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  48. package/dist/Collapsible/Collapsible.js +35 -15
  49. package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -1
  50. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  51. package/dist/CommandPalette/CommandPaletteItem.js +6 -3
  52. package/dist/CommandPalette/CommandPaletteList.js +1 -1
  53. package/dist/ComplexSelector/ComplexSelector.d.ts +1 -1
  54. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  55. package/dist/ComplexSelector/ComplexSelector.js +35 -33
  56. package/dist/ContextMenu/ContextMenu.d.ts +2 -2
  57. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  58. package/dist/ContextMenu/ContextMenu.js +1 -1
  59. package/dist/ContextMenu/index.d.ts +2 -1
  60. package/dist/ContextMenu/index.d.ts.map +1 -1
  61. package/dist/ContextMenu/index.js +1 -0
  62. package/dist/DateInput/DateInput.d.ts +9 -2
  63. package/dist/DateInput/DateInput.d.ts.map +1 -1
  64. package/dist/DateInput/DateInput.js +24 -23
  65. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  66. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  67. package/dist/DateRangeInput/DateRangeInput.js +11 -16
  68. package/dist/DateTimeInput/DateTimeInput.d.ts +9 -1
  69. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  70. package/dist/DateTimeInput/DateTimeInput.js +22 -17
  71. package/dist/Dialog/Dialog.d.ts.map +1 -1
  72. package/dist/Dialog/Dialog.js +4 -4
  73. package/dist/DropdownMenu/DropdownMenu.d.ts +33 -8
  74. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  75. package/dist/DropdownMenu/DropdownMenu.js +62 -20
  76. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +8 -11
  77. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +32 -31
  79. package/dist/DropdownMenu/DropdownMenuDivider.d.ts +25 -0
  80. package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -0
  81. package/dist/DropdownMenu/DropdownMenuDivider.js +66 -0
  82. package/dist/DropdownMenu/DropdownMenuItem.d.ts +15 -2
  83. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuItem.js +20 -8
  85. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +5 -5
  86. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  87. package/dist/DropdownMenu/DropdownMenuRadioItem.js +24 -67
  88. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  89. package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -8
  90. package/dist/DropdownMenu/index.d.ts +2 -1
  91. package/dist/DropdownMenu/index.d.ts.map +1 -1
  92. package/dist/DropdownMenu/index.js +4 -0
  93. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  94. package/dist/DropdownMenu/renderDropdownItems.js +35 -27
  95. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  96. package/dist/EmptyState/EmptyState.js +9 -5
  97. package/dist/Field/InputClearButton.d.ts +16 -3
  98. package/dist/Field/InputClearButton.d.ts.map +1 -1
  99. package/dist/Field/InputClearButton.js +15 -4
  100. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  101. package/dist/HoverCard/useHoverCard.js +3 -19
  102. package/dist/Indicator/CheckIndicator.d.ts +25 -0
  103. package/dist/Indicator/CheckIndicator.d.ts.map +1 -0
  104. package/dist/Indicator/CheckIndicator.js +155 -0
  105. package/dist/Indicator/CheckboxIndicator.d.ts +22 -0
  106. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -0
  107. package/dist/Indicator/CheckboxIndicator.js +173 -0
  108. package/dist/Indicator/RadioIndicator.d.ts +23 -0
  109. package/dist/Indicator/RadioIndicator.d.ts.map +1 -0
  110. package/dist/Indicator/RadioIndicator.js +137 -0
  111. package/dist/Indicator/index.d.ts +24 -0
  112. package/dist/Indicator/index.d.ts.map +1 -0
  113. package/dist/Indicator/index.js +26 -0
  114. package/dist/Indicator/indicator.markers.stylex.d.ts +16 -0
  115. package/dist/Indicator/indicator.markers.stylex.d.ts.map +1 -0
  116. package/dist/Indicator/indicator.markers.stylex.js +21 -0
  117. package/dist/Indicator/indicatorRegistry.d.ts +71 -0
  118. package/dist/Indicator/indicatorRegistry.d.ts.map +1 -0
  119. package/dist/Indicator/indicatorRegistry.js +93 -0
  120. package/dist/Indicator/types.d.ts +167 -0
  121. package/dist/Indicator/types.d.ts.map +1 -0
  122. package/dist/Indicator/types.js +1 -0
  123. package/dist/Indicator/useIndicator.d.ts +18 -0
  124. package/dist/Indicator/useIndicator.d.ts.map +1 -0
  125. package/dist/Indicator/useIndicator.js +30 -0
  126. package/dist/Item/Item.d.ts.map +1 -1
  127. package/dist/Item/Item.js +4 -8
  128. package/dist/Layer/useLayer.d.ts +14 -0
  129. package/dist/Layer/useLayer.d.ts.map +1 -1
  130. package/dist/Layer/useLayer.js +25 -2
  131. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  132. package/dist/Lightbox/Lightbox.js +56 -53
  133. package/dist/Link/Link.d.ts.map +1 -1
  134. package/dist/Link/Link.js +4 -5
  135. package/dist/MobileNav/MobileNav.js +8 -8
  136. package/dist/MoreMenu/MoreMenu.d.ts +14 -1
  137. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  138. package/dist/MoreMenu/MoreMenu.js +4 -0
  139. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  140. package/dist/MultiSelector/MultiSelector.js +78 -75
  141. package/dist/NumberInput/NumberInput.d.ts +27 -1
  142. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  143. package/dist/NumberInput/NumberInput.js +230 -42
  144. package/dist/Outline/Outline.d.ts.map +1 -1
  145. package/dist/Outline/Outline.js +2 -3
  146. package/dist/Pagination/Pagination.d.ts.map +1 -1
  147. package/dist/Pagination/Pagination.js +61 -63
  148. package/dist/Popover/Popover.d.ts.map +1 -1
  149. package/dist/Popover/Popover.js +6 -8
  150. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  151. package/dist/PowerSearch/PowerSearch.js +1 -1
  152. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  153. package/dist/PowerSearch/PowerSearchEditPopover.js +7 -0
  154. package/dist/ProgressBar/ProgressBar.d.ts +11 -4
  155. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  156. package/dist/ProgressBar/ProgressBar.js +96 -6
  157. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  158. package/dist/RadioList/RadioListItem.js +29 -84
  159. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  160. package/dist/Resizable/ResizeHandle.js +2 -3
  161. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  162. package/dist/SegmentedControl/SegmentedControlItem.js +2 -3
  163. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  164. package/dist/SelectableCard/SelectableCard.js +3 -11
  165. package/dist/Selector/Selector.d.ts +2 -1
  166. package/dist/Selector/Selector.d.ts.map +1 -1
  167. package/dist/Selector/Selector.js +164 -94
  168. package/dist/Selector/hooks.d.ts +18 -6
  169. package/dist/Selector/hooks.d.ts.map +1 -1
  170. package/dist/Selector/hooks.js +57 -40
  171. package/dist/SideNav/SideNav.d.ts.map +1 -1
  172. package/dist/SideNav/SideNav.js +1 -1
  173. package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
  174. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  175. package/dist/SideNav/SideNavCollapseButton.js +29 -14
  176. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  177. package/dist/SideNav/SideNavHeading.js +56 -20
  178. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  179. package/dist/SideNav/SideNavItem.js +28 -22
  180. package/dist/Stack/stack.stylex.d.ts +3 -3
  181. package/dist/Switch/Switch.js +11 -10
  182. package/dist/TabList/Tab.d.ts.map +1 -1
  183. package/dist/TabList/Tab.js +2 -3
  184. package/dist/TabList/TabMenu.d.ts.map +1 -1
  185. package/dist/TabList/TabMenu.js +41 -19
  186. package/dist/Table/BaseTable.d.ts.map +1 -1
  187. package/dist/Table/BaseTable.js +8 -0
  188. package/dist/Table/index.d.ts +1 -1
  189. package/dist/Table/index.d.ts.map +1 -1
  190. package/dist/Table/index.js +1 -1
  191. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
  192. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  193. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +22 -18
  194. package/dist/Table/plugins/rowExpansion/index.d.ts +1 -1
  195. package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -1
  196. package/dist/Table/plugins/rowExpansion/index.js +1 -1
  197. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +41 -76
  198. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  199. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +94 -345
  200. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  201. package/dist/Table/plugins/sortable/useTableSortable.js +23 -4
  202. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  203. package/dist/Table/plugins/tree/useTableTreeData.js +29 -33
  204. package/dist/Table/tableContextMenu.d.ts.map +1 -1
  205. package/dist/Table/tableContextMenu.js +2 -1
  206. package/dist/Table/types.d.ts +11 -0
  207. package/dist/Table/types.d.ts.map +1 -1
  208. package/dist/TextArea/TextArea.d.ts +10 -1
  209. package/dist/TextArea/TextArea.d.ts.map +1 -1
  210. package/dist/TextArea/TextArea.js +16 -6
  211. package/dist/TextInput/TextInput.d.ts +10 -1
  212. package/dist/TextInput/TextInput.d.ts.map +1 -1
  213. package/dist/TextInput/TextInput.js +13 -19
  214. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  215. package/dist/Thumbnail/Thumbnail.js +32 -26
  216. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  217. package/dist/TimeInput/TimeInput.js +7 -15
  218. package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -1
  219. package/dist/Timestamp/TimestampHoverCard.js +16 -34
  220. package/dist/Token/Token.d.ts.map +1 -1
  221. package/dist/Token/Token.js +20 -11
  222. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  223. package/dist/Tokenizer/Tokenizer.js +4 -2
  224. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  225. package/dist/Tooltip/useTooltip.js +3 -19
  226. package/dist/TopNav/TopNav.d.ts.map +1 -1
  227. package/dist/TopNav/TopNav.js +6 -5
  228. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  229. package/dist/TopNav/TopNavHeading.js +54 -16
  230. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  231. package/dist/TopNav/TopNavItem.js +3 -9
  232. package/dist/TopNav/TopNavMegaMenu.d.ts +7 -0
  233. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  234. package/dist/TopNav/TopNavMegaMenu.js +146 -60
  235. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  236. package/dist/TopNav/TopNavMegaMenuItem.js +22 -3
  237. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  238. package/dist/TopNav/TopNavMenu.js +83 -38
  239. package/dist/TreeList/TreeList.d.ts.map +1 -1
  240. package/dist/TreeList/TreeList.js +13 -0
  241. package/dist/TreeList/TreeListBranches.d.ts +1 -1
  242. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  243. package/dist/TreeList/TreeListBranches.js +14 -4
  244. package/dist/TreeList/TreeListItem.d.ts +11 -1
  245. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  246. package/dist/TreeList/TreeListItem.js +57 -30
  247. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  248. package/dist/Typeahead/BaseTypeahead.js +16 -8
  249. package/dist/astryx.css +74 -85
  250. package/dist/astryx.umd.js +56 -56
  251. package/dist/astryx.umd.js.map +4 -4
  252. package/dist/hooks/containerReveal.stylex.d.ts +61 -0
  253. package/dist/hooks/containerReveal.stylex.d.ts.map +1 -0
  254. package/dist/hooks/containerReveal.stylex.js +63 -0
  255. package/dist/hooks/index.d.ts +3 -0
  256. package/dist/hooks/index.d.ts.map +1 -1
  257. package/dist/hooks/index.js +2 -0
  258. package/dist/hooks/useClipboard.d.ts +59 -0
  259. package/dist/hooks/useClipboard.d.ts.map +1 -0
  260. package/dist/hooks/useClipboard.js +106 -0
  261. package/dist/hooks/useContainerReveal.d.ts +14 -8
  262. package/dist/hooks/useContainerReveal.d.ts.map +1 -1
  263. package/dist/hooks/useContainerReveal.js +28 -69
  264. package/dist/hooks/useIndicatorFocusRing.d.ts +28 -0
  265. package/dist/hooks/useIndicatorFocusRing.d.ts.map +1 -0
  266. package/dist/hooks/useIndicatorFocusRing.js +96 -0
  267. package/dist/hooks/useLongPress.d.ts.map +1 -1
  268. package/dist/hooks/useLongPress.js +12 -2
  269. package/dist/hooks/useScrollLock.d.ts.map +1 -1
  270. package/dist/hooks/useScrollLock.js +33 -18
  271. package/dist/hooks/useStreamingText.d.ts +18 -3
  272. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  273. package/dist/hooks/useStreamingText.js +47 -7
  274. package/dist/hooks/useTreeFocus.d.ts.map +1 -1
  275. package/dist/hooks/useTreeFocus.js +9 -3
  276. package/dist/hooks/useTypeahead.d.ts +3 -2
  277. package/dist/hooks/useTypeahead.d.ts.map +1 -1
  278. package/dist/hooks/useTypeahead.js +19 -7
  279. package/dist/index.d.ts +1 -0
  280. package/dist/index.d.ts.map +1 -1
  281. package/dist/index.js +1 -0
  282. package/dist/theme/defineTheme.d.ts +16 -0
  283. package/dist/theme/defineTheme.d.ts.map +1 -1
  284. package/dist/theme/defineTheme.js +8 -0
  285. package/dist/theme/derivedVarRegistry.d.ts +8 -0
  286. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  287. package/dist/theme/derivedVarRegistry.js +14 -13
  288. package/dist/theme/expandColorScale.d.ts +3 -1
  289. package/dist/theme/expandColorScale.d.ts.map +1 -1
  290. package/dist/theme/expandColorScale.js +17 -7
  291. package/dist/theme/expandTypeScale.d.ts.map +1 -1
  292. package/dist/theme/expandTypeScale.js +17 -0
  293. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  294. package/dist/theme/generateThemeRules.js +11 -0
  295. package/dist/theme/index.d.ts +1 -0
  296. package/dist/theme/index.d.ts.map +1 -1
  297. package/dist/utils/focusOutline.stylex.d.ts +107 -0
  298. package/dist/utils/focusOutline.stylex.d.ts.map +1 -0
  299. package/dist/utils/focusOutline.stylex.js +130 -0
  300. package/dist/utils/focusReturn.d.ts +24 -0
  301. package/dist/utils/focusReturn.d.ts.map +1 -0
  302. package/dist/utils/focusReturn.js +29 -0
  303. package/dist/utils/index.d.ts +1 -0
  304. package/dist/utils/index.d.ts.map +1 -1
  305. package/dist/utils/index.js +1 -0
  306. package/dist/utils/mergeRefs.d.ts.map +1 -1
  307. package/dist/utils/mergeRefs.js +7 -5
  308. package/dist/utils/rtlStyles.d.ts +2 -2
  309. package/dist/utils/rtlStyles.js +2 -2
  310. package/dist/utils/themeProps.d.ts +20 -1
  311. package/dist/utils/themeProps.d.ts.map +1 -1
  312. package/dist/utils/themeProps.js +8 -2
  313. package/locales/en.json +12 -0
  314. package/locales/pseudo.json +9 -0
  315. package/package.json +7 -2
  316. package/src/AlertDialog/AlertDialog.doc.mjs +16 -3
  317. package/src/AlertDialog/AlertDialog.test.tsx +208 -1
  318. package/src/AlertDialog/AlertDialog.tsx +21 -3
  319. package/src/AppShell/AppShell.doc.mjs +11 -0
  320. package/src/AppShell/AppShell.test.tsx +139 -0
  321. package/src/AppShell/AppShell.tsx +32 -22
  322. package/src/AspectRatio/AspectRatio.doc.mjs +27 -3
  323. package/src/AspectRatio/AspectRatio.test.tsx +30 -0
  324. package/src/AspectRatio/AspectRatio.tsx +13 -0
  325. package/src/Avatar/Avatar.doc.mjs +2 -13
  326. package/src/Avatar/Avatar.test.tsx +33 -8
  327. package/src/Avatar/Avatar.tsx +52 -50
  328. package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -9
  329. package/src/Banner/Banner.tsx +9 -6
  330. package/src/Breadcrumbs/BreadcrumbItem.tsx +16 -6
  331. package/src/Breadcrumbs/index.ts +5 -1
  332. package/src/Button/Button.tsx +21 -41
  333. package/src/Calendar/Calendar.tsx +2 -1
  334. package/src/Calendar/styles.ts +0 -8
  335. package/src/Carousel/Carousel.doc.mjs +3 -0
  336. package/src/Carousel/Carousel.tsx +10 -6
  337. package/src/Chat/Chat.doc.mjs +2 -0
  338. package/src/Chat/ChatDictationButton.tsx +7 -1
  339. package/src/Chat/ChatLayoutScrollButton.test.tsx +22 -0
  340. package/src/Chat/ChatLayoutScrollButton.tsx +8 -1
  341. package/src/Chat/ChatSendButton.tsx +2 -3
  342. package/src/Chat/ChatToolCalls.test.tsx +35 -0
  343. package/src/Chat/ChatToolCalls.tsx +36 -16
  344. package/src/Chat/useTriggerMenu.tsx +2 -5
  345. package/src/CheckboxInput/CheckboxInput.doc.mjs +4 -2
  346. package/src/CheckboxInput/CheckboxInput.test.tsx +115 -0
  347. package/src/CheckboxInput/CheckboxInput.tsx +45 -202
  348. package/src/ClickableCard/ClickableCard.tsx +6 -11
  349. package/src/CodeBlock/CodeBlock.doc.mjs +3 -0
  350. package/src/CodeBlock/CodeBlock.test.tsx +91 -0
  351. package/src/CodeBlock/CodeBlock.tsx +57 -80
  352. package/src/Collapsible/Collapsible.tsx +22 -18
  353. package/src/CommandPalette/CommandPalette.test.tsx +29 -0
  354. package/src/CommandPalette/CommandPaletteItem.tsx +7 -4
  355. package/src/CommandPalette/CommandPaletteList.tsx +2 -2
  356. package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
  357. package/src/ComplexSelector/ComplexSelector.test.tsx +64 -0
  358. package/src/ComplexSelector/ComplexSelector.tsx +46 -29
  359. package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
  360. package/src/ContextMenu/ContextMenu.test.tsx +41 -0
  361. package/src/ContextMenu/ContextMenu.tsx +3 -3
  362. package/src/ContextMenu/index.ts +5 -1
  363. package/src/DateInput/DateInput.doc.mjs +18 -3
  364. package/src/DateInput/DateInput.test.tsx +93 -11
  365. package/src/DateInput/DateInput.tsx +41 -19
  366. package/src/DateRangeInput/DateRangeInput.doc.mjs +10 -2
  367. package/src/DateRangeInput/DateRangeInput.test.tsx +110 -14
  368. package/src/DateRangeInput/DateRangeInput.tsx +24 -12
  369. package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -2
  370. package/src/DateTimeInput/DateTimeInput.test.tsx +75 -0
  371. package/src/DateTimeInput/DateTimeInput.tsx +35 -8
  372. package/src/Dialog/Dialog.tsx +2 -9
  373. package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -9
  374. package/src/DropdownMenu/DropdownMenu.test.tsx +534 -4
  375. package/src/DropdownMenu/DropdownMenu.tsx +113 -52
  376. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +27 -30
  377. package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +34 -0
  378. package/src/DropdownMenu/DropdownMenuDivider.tsx +81 -0
  379. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +39 -4
  380. package/src/DropdownMenu/DropdownMenuItem.tsx +48 -10
  381. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +30 -76
  382. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +25 -19
  383. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +44 -14
  384. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +1 -5
  385. package/src/DropdownMenu/index.ts +8 -1
  386. package/src/DropdownMenu/renderDropdownItems.tsx +33 -34
  387. package/src/EmptyState/EmptyState.doc.mjs +4 -0
  388. package/src/EmptyState/EmptyState.test.tsx +62 -0
  389. package/src/EmptyState/EmptyState.tsx +16 -6
  390. package/src/Field/Field.doc.mjs +1 -0
  391. package/src/Field/InputClearButton.test.tsx +117 -0
  392. package/src/Field/InputClearButton.tsx +30 -3
  393. package/src/HoverCard/useHoverCard.tsx +2 -23
  394. package/src/Icon/Icon.doc.mjs +2 -1
  395. package/src/Indicator/CheckIndicator.tsx +174 -0
  396. package/src/Indicator/CheckboxIndicator.tsx +257 -0
  397. package/src/Indicator/Indicator.doc.mjs +344 -0
  398. package/src/Indicator/Indicator.test.tsx +393 -0
  399. package/src/Indicator/RadioIndicator.tsx +206 -0
  400. package/src/Indicator/index.ts +45 -0
  401. package/src/Indicator/indicator.markers.stylex.ts +19 -0
  402. package/src/Indicator/indicatorRegistry.test.tsx +106 -0
  403. package/src/Indicator/indicatorRegistry.ts +120 -0
  404. package/src/Indicator/types.ts +186 -0
  405. package/src/Indicator/useIndicator.ts +39 -0
  406. package/src/Item/Item.doc.mjs +1 -1
  407. package/src/Item/Item.tsx +7 -14
  408. package/src/Layer/useLayer.doc.mjs +2 -2
  409. package/src/Layer/useLayer.test.tsx +85 -0
  410. package/src/Layer/useLayer.tsx +39 -1
  411. package/src/Lightbox/Lightbox.doc.mjs +1 -1
  412. package/src/Lightbox/Lightbox.tsx +43 -38
  413. package/src/Link/Link.tsx +4 -11
  414. package/src/MobileNav/MobileNav.tsx +3 -3
  415. package/src/MoreMenu/MoreMenu.doc.mjs +31 -0
  416. package/src/MoreMenu/MoreMenu.test.tsx +68 -1
  417. package/src/MoreMenu/MoreMenu.tsx +19 -0
  418. package/src/MultiSelector/MultiSelector.doc.mjs +9 -1
  419. package/src/MultiSelector/MultiSelector.test.tsx +255 -16
  420. package/src/MultiSelector/MultiSelector.tsx +103 -99
  421. package/src/NumberInput/NumberInput.doc.mjs +265 -50
  422. package/src/NumberInput/NumberInput.test.tsx +726 -21
  423. package/src/NumberInput/NumberInput.tsx +353 -59
  424. package/src/Outline/Outline.tsx +2 -5
  425. package/src/Pagination/Pagination.doc.mjs +1 -1
  426. package/src/Pagination/Pagination.test.tsx +22 -7
  427. package/src/Pagination/Pagination.tsx +38 -35
  428. package/src/Popover/Popover.tsx +6 -7
  429. package/src/PowerSearch/PowerSearch.tsx +1 -1
  430. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +42 -0
  431. package/src/PowerSearch/PowerSearchEditPopover.tsx +7 -0
  432. package/src/ProgressBar/ProgressBar.doc.mjs +27 -5
  433. package/src/ProgressBar/ProgressBar.test.tsx +224 -1
  434. package/src/ProgressBar/ProgressBar.tsx +124 -22
  435. package/src/RadioList/RadioList.doc.mjs +4 -2
  436. package/src/RadioList/RadioListItem.tsx +31 -130
  437. package/src/Resizable/ResizeHandle.tsx +2 -9
  438. package/src/SegmentedControl/SegmentedControlItem.tsx +2 -9
  439. package/src/SelectableCard/SelectableCard.tsx +4 -9
  440. package/src/Selector/Selector.doc.mjs +7 -4
  441. package/src/Selector/Selector.test.tsx +935 -25
  442. package/src/Selector/Selector.tsx +189 -106
  443. package/src/Selector/hooks.ts +77 -50
  444. package/src/SideNav/SideNav.test.tsx +46 -0
  445. package/src/SideNav/SideNav.tsx +1 -0
  446. package/src/SideNav/SideNavCollapseButton.tsx +15 -10
  447. package/src/SideNav/SideNavHeading.tsx +48 -10
  448. package/src/SideNav/SideNavItem.tsx +20 -12
  449. package/src/Stack/Stack.doc.mjs +110 -0
  450. package/src/StatusDot/StatusDot.doc.mjs +12 -3
  451. package/src/Switch/Switch.test.tsx +32 -0
  452. package/src/Switch/Switch.tsx +8 -8
  453. package/src/TabList/Tab.tsx +2 -9
  454. package/src/TabList/TabMenu.tsx +14 -21
  455. package/src/Table/BaseTable.tsx +11 -0
  456. package/src/Table/index.ts +1 -4
  457. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +30 -14
  458. package/src/Table/plugins/rowExpansion/index.ts +1 -4
  459. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +125 -175
  460. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +115 -458
  461. package/src/Table/plugins/sortable/useTableSortable.tsx +2 -6
  462. package/src/Table/plugins/tree/useTableTreeData.tsx +43 -24
  463. package/src/Table/tableContextMenu.test.tsx +27 -0
  464. package/src/Table/tableContextMenu.tsx +1 -0
  465. package/src/Table/types.ts +11 -0
  466. package/src/Table/useTableGroupedRows.doc.mjs +1 -1
  467. package/src/Table/useTableRowExpansion.doc.mjs +43 -66
  468. package/src/TextArea/TextArea.doc.mjs +42 -2
  469. package/src/TextArea/TextArea.test.tsx +219 -0
  470. package/src/TextArea/TextArea.tsx +34 -7
  471. package/src/TextInput/TextInput.doc.mjs +18 -2
  472. package/src/TextInput/TextInput.test.tsx +189 -0
  473. package/src/TextInput/TextInput.tsx +25 -31
  474. package/src/Thumbnail/Thumbnail.tsx +2 -9
  475. package/src/TimeInput/TimeInput.doc.mjs +2 -2
  476. package/src/TimeInput/TimeInput.test.tsx +30 -3
  477. package/src/TimeInput/TimeInput.tsx +9 -26
  478. package/src/Timestamp/Timestamp.doc.mjs +4 -3
  479. package/src/Timestamp/TimestampHoverCard.tsx +13 -35
  480. package/src/Token/Token.tsx +5 -28
  481. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  482. package/src/Tokenizer/Tokenizer.test.tsx +45 -3
  483. package/src/Tokenizer/Tokenizer.tsx +10 -2
  484. package/src/Tooltip/useTooltip.tsx +2 -23
  485. package/src/TopNav/TopNav.tsx +1 -3
  486. package/src/TopNav/TopNavHeading.tsx +42 -13
  487. package/src/TopNav/TopNavItem.tsx +3 -21
  488. package/src/TopNav/TopNavMegaMenu.test.tsx +433 -33
  489. package/src/TopNav/TopNavMegaMenu.tsx +118 -53
  490. package/src/TopNav/TopNavMegaMenuItem.tsx +2 -9
  491. package/src/TopNav/TopNavMenu.tsx +34 -37
  492. package/src/TreeList/TreeList.doc.mjs +5 -0
  493. package/src/TreeList/TreeList.test.tsx +206 -7
  494. package/src/TreeList/TreeList.tsx +22 -0
  495. package/src/TreeList/TreeListBranches.tsx +25 -2
  496. package/src/TreeList/TreeListItem.tsx +89 -52
  497. package/src/Typeahead/BaseTypeahead.tsx +19 -6
  498. package/src/Typeahead/Typeahead.doc.mjs +1 -0
  499. package/src/Typeahead/Typeahead.test.tsx +76 -3
  500. package/src/hooks/containerReveal.stylex.ts +102 -0
  501. package/src/hooks/index.ts +4 -0
  502. package/src/hooks/useClipboard.doc.mjs +87 -0
  503. package/src/hooks/useClipboard.test.tsx +151 -0
  504. package/src/hooks/useClipboard.ts +135 -0
  505. package/src/hooks/useContainerReveal.doc.mjs +7 -7
  506. package/src/hooks/useContainerReveal.test.tsx +42 -62
  507. package/src/hooks/useContainerReveal.ts +36 -91
  508. package/src/hooks/useImageMode.test.ts +1 -1
  509. package/src/hooks/useIndicatorFocusRing.tsx +120 -0
  510. package/src/hooks/useLongPress.test.tsx +18 -0
  511. package/src/hooks/useLongPress.ts +12 -2
  512. package/src/hooks/useScrollLock.test.ts +72 -0
  513. package/src/hooks/useScrollLock.ts +51 -19
  514. package/src/hooks/useStreamingText.test.ts +46 -1
  515. package/src/hooks/useStreamingText.ts +49 -7
  516. package/src/hooks/useTreeFocus.test.tsx +50 -0
  517. package/src/hooks/useTreeFocus.ts +14 -3
  518. package/src/hooks/useTypeahead.test.tsx +150 -0
  519. package/src/hooks/useTypeahead.ts +24 -9
  520. package/src/i18n/InternationalizationProvider.doc.mjs +7 -2
  521. package/src/index.ts +1 -0
  522. package/src/theme/defineTheme.ts +24 -0
  523. package/src/theme/derivedVarRegistry.test.ts +21 -1
  524. package/src/theme/derivedVarRegistry.ts +19 -6
  525. package/src/theme/expandColorScale.test.ts +14 -0
  526. package/src/theme/expandColorScale.ts +24 -9
  527. package/src/theme/expandTypeScale.test.ts +43 -0
  528. package/src/theme/expandTypeScale.ts +17 -0
  529. package/src/theme/generateThemeRules.test.ts +61 -20
  530. package/src/theme/generateThemeRules.ts +11 -0
  531. package/src/theme/index.ts +13 -0
  532. package/src/utils/focusOutline.stylex.ts +163 -0
  533. package/src/utils/focusReturn.test.ts +42 -0
  534. package/src/utils/focusReturn.ts +31 -0
  535. package/src/utils/index.ts +1 -0
  536. package/src/utils/mergeRefs.test.ts +48 -0
  537. package/src/utils/mergeRefs.ts +12 -6
  538. package/src/utils/rtlStyles.ts +2 -2
  539. package/src/utils/themeProps.ts +26 -4
  540. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts +0 -9
  541. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts.map +0 -1
  542. package/dist/CheckboxInput/checkbox.markers.stylex.js +0 -14
  543. package/dist/RadioList/radio.markers.stylex.d.ts +0 -7
  544. package/dist/RadioList/radio.markers.stylex.d.ts.map +0 -1
  545. package/dist/RadioList/radio.markers.stylex.js +0 -12
  546. package/dist/hooks/containerReveal.pool.stylex.d.ts +0 -303
  547. package/dist/hooks/containerReveal.pool.stylex.d.ts.map +0 -1
  548. package/dist/hooks/containerReveal.pool.stylex.js +0 -292
  549. package/src/CheckboxInput/checkbox.markers.stylex.ts +0 -12
  550. package/src/RadioList/radio.markers.stylex.ts +0 -10
  551. package/src/hooks/containerReveal.pool.stylex.ts +0 -571
@@ -14,6 +14,11 @@
14
14
  *
15
15
  * Both modes use useListFocus for DOM-based keyboard navigation.
16
16
  *
17
+ * Initial focus on open follows the input modality: a keyboard open
18
+ * (Enter / Space / ArrowDown on the trigger) focuses the first enabled item
19
+ * (APG menu-button); a pointer open focuses the menu container itself so no
20
+ * item reads as pre-selected, and the first ArrowDown then moves to item 1.
21
+ *
17
22
  * SYNC: When modified, update these files to stay in sync:
18
23
  * - /packages/core/src/DropdownMenu/DropdownMenu.doc.mjs
19
24
  * - /packages/core/src/DropdownMenu/DropdownMenu.test.tsx
@@ -35,9 +40,9 @@ import * as stylex from '@stylexjs/stylex';
35
40
  import {usePopover} from '../Popover/usePopover';
36
41
  import {Button, type ButtonProps} from '../Button';
37
42
  import {Icon} from '../Icon';
38
- import type {IconType} from '../Icon';
39
43
 
40
44
  import {renderDropdownItems} from './renderDropdownItems';
45
+ import type {DropdownMenuItemProps} from './DropdownMenuItem';
41
46
  import {
42
47
  MENU_ITEM_ROLES,
43
48
  MENU_ITEM_SELECTOR,
@@ -82,14 +87,6 @@ const styles = stylex.create({
82
87
  popover: {
83
88
  minWidth: 'anchor-size(width)',
84
89
  },
85
- popoverBlockGap: {
86
- marginBlockStart: spacingVars['--spacing-1'],
87
- marginBlockEnd: spacingVars['--spacing-1'],
88
- },
89
- popoverInlineGap: {
90
- marginInlineStart: spacingVars['--spacing-1'],
91
- marginInlineEnd: spacingVars['--spacing-1'],
92
- },
93
90
  popoverCustomWidth: (width: string | number) => ({
94
91
  minWidth: typeof width === 'number' ? `${width}px` : width,
95
92
  }),
@@ -99,11 +96,34 @@ const styles = stylex.create({
99
96
  // Types
100
97
  // =============================================================================
101
98
 
102
- export interface DropdownMenuItemData {
103
- label: string;
104
- onClick?: () => void;
105
- isDisabled?: boolean;
106
- icon?: ReactNode | IconType;
99
+ /**
100
+ * Data-mode shape for one menu row.
101
+ *
102
+ * The item fields are sourced from `DropdownMenuItemProps` — data mode renders
103
+ * through `DropdownMenuItem`, so the two APIs describe the same thing and must
104
+ * not drift. Only the fields listed here are part of the data API; add a key to
105
+ * the `Pick` to expose more of the item's props to `items`.
106
+ */
107
+ export interface DropdownMenuItemData extends Pick<
108
+ DropdownMenuItemProps,
109
+ | 'icon'
110
+ | 'onClick'
111
+ | 'isDisabled'
112
+ | 'variant'
113
+ | 'description'
114
+ | 'endContent'
115
+ | 'hasCloseOnSelect'
116
+ > {
117
+ /**
118
+ * Stable identity for the row, used as its React key (as on
119
+ * `TreeListItemData`). Omit it and the row is keyed by position, which is
120
+ * correct for a fixed menu; set it when `items` can reorder, filter, or grow,
121
+ * so a row keeps its DOM node — and therefore keyboard focus — as the array
122
+ * changes around it.
123
+ */
124
+ id?: string;
125
+ /** Primary label content. */
126
+ label: ReactNode;
107
127
  /**
108
128
  * Nested submenu entries. When present, this row becomes a submenu (a
109
129
  * flyout revealing `items`) instead of a leaf action — no separate item
@@ -112,18 +132,24 @@ export interface DropdownMenuItemData {
112
132
  items?: DropdownMenuOption[];
113
133
  }
114
134
 
115
- export interface DropdownMenuDivider {
135
+ /**
136
+ * Data-mode shape for a divider row. The compound-mode peer is the
137
+ * `DropdownMenuDivider` component, which both modes render.
138
+ */
139
+ export interface DropdownMenuDividerData {
116
140
  type: 'divider';
117
141
  }
118
142
 
119
143
  export interface DropdownMenuSection {
120
144
  type: 'section';
145
+ /** Stable identity for the group; see {@link DropdownMenuItemData.id}. */
146
+ id?: string;
121
147
  title?: string;
122
148
  items: DropdownMenuItemData[];
123
149
  }
124
150
 
125
151
  export type DropdownMenuOption =
126
- DropdownMenuItemData | DropdownMenuDivider | DropdownMenuSection;
152
+ DropdownMenuItemData | DropdownMenuDividerData | DropdownMenuSection;
127
153
 
128
154
  // =============================================================================
129
155
  // Props
@@ -254,6 +280,13 @@ export function DropdownMenu({
254
280
  // captures the trigger instead of the first menu item.
255
281
  const shouldFocusOnOpenRef = useRef(false);
256
282
 
283
+ // How the next open was initiated. Keyboard (and programmatic) opens focus
284
+ // the first enabled item per the APG menu-button pattern; pointer opens
285
+ // focus the menu container instead, so no item is visually highlighted as
286
+ // if pre-selected (#4477). Reset to 'keyboard' after every open so
287
+ // programmatic controlled opens keep the item-focus behavior.
288
+ const openModalityRef = useRef<'keyboard' | 'pointer'>('keyboard');
289
+
257
290
  const handleLayerShow = useCallback(() => {
258
291
  onOpenChange?.(true);
259
292
  if (!isControlled) {
@@ -319,14 +352,26 @@ export function DropdownMenu({
319
352
  }
320
353
  }, [controlledIsOpen, isControlled, popover]);
321
354
 
322
- // Move focus into the menu only after the layer has committed open.
355
+ // Move focus into the menu only after the layer has committed open,
356
+ // honoring the input modality: keyboard (and programmatic) opens land on
357
+ // the first enabled item per the APG menu-button pattern; pointer opens
358
+ // focus the menu container itself (tabIndex={-1}) so no item is
359
+ // highlighted as if pre-selected (#4477). Container focus keeps arrows,
360
+ // typeahead, Escape and Tab in the menu's onKeyDown, and is also the
361
+ // fallback when no item is focusable (e.g. all disabled), mirroring the
362
+ // submenu flyout fallback.
323
363
  useEffect(() => {
324
364
  if (!popover.isOpen || !shouldFocusOnOpenRef.current) {
325
365
  return;
326
366
  }
327
367
  shouldFocusOnOpenRef.current = false;
328
- requestAnimationFrame(() => focusFirst());
329
- }, [popover.isOpen, focusFirst]);
368
+ requestAnimationFrame(() => {
369
+ if (openModalityRef.current === 'pointer' || !focusFirst()) {
370
+ listRef.current?.focus();
371
+ }
372
+ openModalityRef.current = 'keyboard';
373
+ });
374
+ }, [popover.isOpen, focusFirst, listRef]);
330
375
 
331
376
  // Extend useListFocus with Enter/Space activation + typeahead
332
377
  const listKeyDown = useCallback(
@@ -366,36 +411,51 @@ export function DropdownMenu({
366
411
  [listNavKeyDown, closeMenu, typeahead, ownsEvent],
367
412
  );
368
413
 
369
- const openAndFocus = useCallback(() => {
370
- shouldFocusOnOpenRef.current = true;
371
- popover.show();
372
- }, [popover]);
414
+ const openAndFocus = useCallback(
415
+ (modality: 'keyboard' | 'pointer' = 'keyboard') => {
416
+ openModalityRef.current = modality;
417
+ shouldFocusOnOpenRef.current = true;
418
+ popover.show();
419
+ },
420
+ [popover],
421
+ );
373
422
 
374
- const handleButtonClick = useCallback(() => {
375
- // If the menu was just closed by light dismiss (e.g. iOS Safari fires
376
- // pointerdown hide before the trigger's click), the click would
377
- // otherwise immediately re-open it. Short-circuit within the guard window.
378
- if (Date.now() - lastHideTimeRef.current < 50) {
379
- return;
380
- }
381
- onClick?.();
382
- if (isControlled) {
383
- onOpenChange?.(!controlledIsOpen);
384
- } else {
385
- if (popover.isOpen) {
386
- popover.hide();
423
+ const handleButtonClick = useCallback(
424
+ (e: React.MouseEvent<HTMLButtonElement>) => {
425
+ // If the menu was just closed by light dismiss (e.g. iOS Safari fires
426
+ // pointerdown hide before the trigger's click), the click would
427
+ // otherwise immediately re-open it. Short-circuit within the guard
428
+ // window.
429
+ if (Date.now() - lastHideTimeRef.current < 50) {
430
+ return;
431
+ }
432
+ onClick?.();
433
+ // detail === 0 marks a synthesized click (screen reader / AT
434
+ // activation): treat it as keyboard so those users still land on the
435
+ // first item. Real pointer clicks report detail >= 1.
436
+ const modality = e.detail === 0 ? 'keyboard' : 'pointer';
437
+ if (isControlled) {
438
+ if (!controlledIsOpen) {
439
+ openModalityRef.current = modality;
440
+ }
441
+ onOpenChange?.(!controlledIsOpen);
387
442
  } else {
388
- openAndFocus();
443
+ if (popover.isOpen) {
444
+ popover.hide();
445
+ } else {
446
+ openAndFocus(modality);
447
+ }
389
448
  }
390
- }
391
- }, [
392
- onClick,
393
- isControlled,
394
- onOpenChange,
395
- controlledIsOpen,
396
- popover,
397
- openAndFocus,
398
- ]);
449
+ },
450
+ [
451
+ onClick,
452
+ isControlled,
453
+ onOpenChange,
454
+ controlledIsOpen,
455
+ popover,
456
+ openAndFocus,
457
+ ],
458
+ );
399
459
 
400
460
  const handleButtonKeyDown = useCallback(
401
461
  (e: React.KeyboardEvent) => {
@@ -421,11 +481,6 @@ export function DropdownMenu({
421
481
  const popoverXstyle = menuWidth
422
482
  ? styles.popoverCustomWidth(menuWidth)
423
483
  : styles.popover;
424
- const popoverGapStyle =
425
- placement === 'above' || placement === 'below'
426
- ? styles.popoverBlockGap
427
- : styles.popoverInlineGap;
428
-
429
484
  // Context for compound items
430
485
  const contextValue = useMemo<DropdownMenuContextValue>(
431
486
  () => ({closeMenu, menuSize}),
@@ -468,6 +523,11 @@ export function DropdownMenu({
468
523
  ref={listRef}
469
524
  id={menuId}
470
525
  role="menu"
526
+ // Focus target for pointer opens (not in the Tab order): holding
527
+ // focus on the container keeps key events (arrows, typeahead,
528
+ // Escape, Tab) inside the menu without highlighting any item.
529
+ // Mirrors the DropdownMenuSubMenu flyout container.
530
+ tabIndex={-1}
471
531
  // Give the menu an accessible name from its trigger's label, so
472
532
  // screen readers announce e.g. "Actions menu" rather than an unnamed
473
533
  // menu (menus-13).
@@ -486,7 +546,8 @@ export function DropdownMenu({
486
546
  {
487
547
  placement,
488
548
  alignment,
489
- xstyle: [popoverXstyle, popoverGapStyle, layerAnimations[placement]],
549
+ offset: spacingVars['--spacing-1'],
550
+ xstyle: [popoverXstyle, layerAnimations[placement]],
490
551
  },
491
552
  )}
492
553
  </>
@@ -15,24 +15,21 @@
15
15
  * Enter/Space activation come from the parent DropdownMenu's useListFocus +
16
16
  * activation path, which matches menuitemcheckbox alongside plain menuitem rows.
17
17
  *
18
- * The checkbox visual composes the real CheckboxInput primitive so its checkmark
19
- * matches CheckboxListItem and picks up the standard `checkbox` theming slots.
20
- * It is purely decorative: the composed control is wrapped in an element that is
21
- * both `aria-hidden` and `inert`, so it contributes nothing to the row's
22
- * accessible name, and its native <input> and sr-only label stay out of the tab
23
- * order and the accessibility tree while pointer clicks fall through to the row
24
- * the same shim MultiSelector uses. The row owns the checked state and
25
- * accessible name. The control size is derived from the menu's item size (a
26
- * `sm` menu gets the compact control; `md`/`lg` get the standard one) and it
27
- * swaps to the inline-end of the row on coarse-pointer (touch) devices via CSS
28
- * `order`, so it lands where selection toggles are conventionally placed on
18
+ * The checkbox visual is the shared checkbox indicator, decorative
19
+ * (aria-hidden) the row owns the role, checked state, and accessible name, so
20
+ * there is no nested native <input> to shim out of the accessibility tree. It
21
+ * picks up the same `checkbox` theming (and any theme replacement) as
22
+ * CheckboxInput. The control size is derived from the menu's item size (a `sm`
23
+ * menu gets the compact control; `md`/`lg` get the standard one) and the marker
24
+ * box swaps to the inline-end of the row on coarse-pointer (touch) devices via
25
+ * CSS `order`, so it lands where selection toggles are conventionally placed on
29
26
  * mobile.
30
27
  */
31
28
 
32
29
  import {useCallback, type PointerEvent, type ReactNode} from 'react';
33
30
  import * as stylex from '@stylexjs/stylex';
34
31
  import {renderIconSlot, type IconType} from '../Icon';
35
- import {CheckboxInput} from '../CheckboxInput/CheckboxInput';
32
+ import {useIndicator} from '../Indicator';
36
33
  import {Item} from '../Item';
37
34
  import {useDropdownMenuContext} from './DropdownMenuContext';
38
35
  import {focusMenuItemOnHover} from './menuItemHover';
@@ -61,9 +58,10 @@ const styles = stylex.create({
61
58
  // `aria-hidden` + `inert` + pointer-events:none keep the composed CheckboxInput
62
59
  // decorative: it adds no accessible name, and clicks fall through to the row,
63
60
  // which owns the role and activation.
64
- markerBox: {
65
- display: 'flex',
66
- flexShrink: 0,
61
+ // Placement of the marker within the row. The indicator draws its own box
62
+ // (size, fill, border) — these are only the rules the MENU owns: where the
63
+ // marker sits in the row, and that it never takes the pointer.
64
+ marker: {
67
65
  pointerEvents: 'none',
68
66
  order: {
69
67
  default: 0,
@@ -76,6 +74,8 @@ const styles = stylex.create({
76
74
  },
77
75
  });
78
76
 
77
+ // Matches the control sizes CheckboxInput uses, so a checkbox reads the same in
78
+ // a menu row as it does in a form.
79
79
  export interface DropdownMenuCheckboxItemProps extends Omit<
80
80
  BaseProps,
81
81
  'onChange' | 'role' | 'aria-checked' | 'tabIndex'
@@ -157,12 +157,7 @@ export function DropdownMenuCheckboxItem({
157
157
  const ctx = useDropdownMenuContext();
158
158
  const menuSize = ctx?.menuSize ?? 'md';
159
159
  const controlSize = menuSize === 'sm' ? 'sm' : 'md';
160
-
161
- // The composed checkbox is decorative and inert, so its label never reaches
162
- // the accessibility tree — the row's `label` prop provides the announced
163
- // name. CheckboxInput still requires a string label, so pass one through when
164
- // the row label is a plain string.
165
- const checkboxLabel = typeof label === 'string' ? label : '';
160
+ const CheckboxControl = useIndicator('checkbox');
166
161
 
167
162
  const handleClick = useCallback(() => {
168
163
  if (isDisabled) {
@@ -187,15 +182,17 @@ export function DropdownMenuCheckboxItem({
187
182
  tabIndex={isDisabled ? undefined : -1}
188
183
  onPointerMove={handlePointerMove}
189
184
  marker={
190
- <div aria-hidden="true" inert {...stylex.props(styles.markerBox)}>
191
- <CheckboxInput
192
- label={checkboxLabel}
193
- isLabelHidden
194
- value={value}
195
- isDisabled={isDisabled}
196
- size={controlSize}
197
- />
198
- </div>
185
+ // No wrapper, and no menu-specific theme target: the shared
186
+ // `astryx-checkbox` target is already on this element (main reached
187
+ // the menu checkbox through it too), so the menu adds only its own
188
+ // placement rules. A wrapper here would have duplicated the
189
+ // indicator's control size and moved nothing themeable.
190
+ <CheckboxControl
191
+ state={value ? 'checked' : 'unchecked'}
192
+ size={controlSize}
193
+ isDisabled={isDisabled}
194
+ xstyle={styles.marker}
195
+ />
199
196
  }
200
197
  startContent={
201
198
  icon
@@ -0,0 +1,34 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
4
+
5
+ export const docs = {
6
+ name: 'DropdownMenuDivider',
7
+ subComponentOf: 'DropdownMenu',
8
+ displayName: 'Dropdown Menu Divider',
9
+ isHiddenFromOverview: true,
10
+ description:
11
+ 'A horizontal rule separating groups of rows in a compound menu. Renders role="separator", so it is never a stop in the arrow-key order. The data-driven equivalent is the `{type: "divider"}` entry in `items`; both modes render this component, so they look and theme identically.',
12
+ props: [
13
+ {
14
+ name: 'xstyle',
15
+ type: 'StyleXStyles',
16
+ description:
17
+ 'StyleX styles applied after the menu spacing. Must be a stylex.create() value: not an inline style object like style={{}}.',
18
+ },
19
+ ],
20
+ theming: {
21
+ targets: [{className: 'astryx-dropdown-menu-divider'}],
22
+ },
23
+ };
24
+
25
+ export const docsDense = {
26
+ name: 'DropdownMenuDivider',
27
+ isHiddenFromOverview: true,
28
+ displayName: 'Dropdown Menu Divider',
29
+ description:
30
+ 'separator row for compound menus; compound peer of the data API\'s {type: "divider"}',
31
+ propDescriptions: {
32
+ xstyle: 'StyleX styles applied after the menu spacing',
33
+ },
34
+ };
@@ -0,0 +1,81 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file DropdownMenuDivider.tsx
7
+ * @input Uses Divider, spacing tokens, themeProps
8
+ * @output Exports DropdownMenuDivider component and DropdownMenuDividerProps
9
+ * @position Sub-component; used inside DropdownMenu
10
+ *
11
+ * The compound-mode peer of the data API's `{type: 'divider'}` option. The
12
+ * data path renders this same component, so neither mode can drift from the
13
+ * other in DOM, spacing, or theme target.
14
+ *
15
+ * SYNC: When modified, update these files to stay in sync:
16
+ * - /packages/core/src/DropdownMenu/DropdownMenu.doc.mjs
17
+ * - /packages/core/src/DropdownMenu/DropdownMenuDivider.doc.mjs
18
+ * - /packages/core/src/DropdownMenu/DropdownMenu.test.tsx
19
+ * - /packages/core/src/DropdownMenu/index.ts
20
+ * - /packages/core/src/ContextMenu/index.ts
21
+ * - /packages/core/src/Breadcrumbs/index.ts
22
+ * - /apps/storybook/stories/DropdownMenu.stories.tsx
23
+ * - /packages/cli/assets/templates/blocks/components/DropdownMenu/ (showcase blocks)
24
+ */
25
+
26
+ import * as stylex from '@stylexjs/stylex';
27
+ import {Divider} from '../Divider';
28
+ import {spacingVars} from '../theme/tokens.stylex';
29
+ import type {BaseProps} from '../BaseProps';
30
+ import {themeProps} from '../utils/themeProps';
31
+
32
+ const styles = stylex.create({
33
+ divider: {
34
+ marginBlock: spacingVars['--spacing-1'],
35
+ },
36
+ });
37
+
38
+ const THEME_CLASS_NAME = themeProps('dropdown-menu-divider').className;
39
+
40
+ export interface DropdownMenuDividerProps extends Pick<
41
+ BaseProps,
42
+ 'xstyle' | 'className' | 'style'
43
+ > {
44
+ /** Ref forwarded to the separator element. */
45
+ ref?: React.Ref<HTMLDivElement>;
46
+ }
47
+
48
+ /**
49
+ * A horizontal rule separating groups of menu rows.
50
+ *
51
+ * Renders `role="separator"`, so it is never a stop in the menu's arrow-key
52
+ * order. Equivalent to `{type: 'divider'}` in the `items` data API.
53
+ *
54
+ * @example
55
+ * ```
56
+ * <DropdownMenu button={{ label: 'Actions' }}>
57
+ * <DropdownMenuItem label="Edit" onClick={handleEdit} />
58
+ * <DropdownMenuDivider />
59
+ * <DropdownMenuItem label="Delete" variant="destructive" onClick={handleDelete} />
60
+ * </DropdownMenu>
61
+ * ```
62
+ */
63
+ export function DropdownMenuDivider({
64
+ xstyle,
65
+ className,
66
+ style,
67
+ ref,
68
+ }: DropdownMenuDividerProps) {
69
+ return (
70
+ <Divider
71
+ ref={ref}
72
+ xstyle={[styles.divider, xstyle]}
73
+ className={
74
+ className ? `${THEME_CLASS_NAME} ${className}` : THEME_CLASS_NAME
75
+ }
76
+ style={style}
77
+ />
78
+ );
79
+ }
80
+
81
+ DropdownMenuDivider.displayName = 'DropdownMenuDivider';
@@ -7,7 +7,8 @@ export const docs = {
7
7
  subComponentOf: 'DropdownMenu',
8
8
  displayName: 'Dropdown Menu Item',
9
9
  isHiddenFromOverview: true,
10
- description: 'Helper component for custom item rendering with consistent styling.',
10
+ description:
11
+ 'Helper component for custom item rendering with consistent styling.',
11
12
  playground: {
12
13
  // Standalone DropdownMenuItem has no required props, so the properties-tab
13
14
  // preview renders an empty row without seeded content. Seed a label and
@@ -18,7 +19,8 @@ export const docs = {
18
19
  {
19
20
  name: 'icon',
20
21
  type: 'IconType',
21
- description: 'Icon to display before the label. See `astryx docs icons` for valid semantic names.',
22
+ description:
23
+ 'Icon to display before the label. See `astryx docs icons` for valid semantic names.',
22
24
  },
23
25
  {
24
26
  name: 'label',
@@ -33,12 +35,28 @@ export const docs = {
33
35
  {
34
36
  name: 'endContent',
35
37
  type: 'ReactNode',
36
- description: 'Additional content rendered after the label and description.',
38
+ description:
39
+ 'Additional content rendered after the label and description.',
40
+ },
41
+ {
42
+ name: 'hasCloseOnSelect',
43
+ type: 'boolean',
44
+ description:
45
+ 'Whether activating the item closes the menu. Set false for an action that reports its result on the item itself.',
46
+ default: 'true',
47
+ },
48
+ {
49
+ name: 'variant',
50
+ type: "'default' | 'destructive'",
51
+ description:
52
+ "Visual variant. 'destructive' renders the label, description, and icon in the error color for dangerous actions (e.g. Delete).",
53
+ default: "'default'",
37
54
  },
38
55
  {
39
56
  name: 'xstyle',
40
57
  type: 'StyleXStyles',
41
- description: 'StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}.',
58
+ description:
59
+ 'StyleX styles for layout customization (margins, positioning, sizing). Must be a stylex.create() value: not an inline style object like style={{}}.',
42
60
  },
43
61
  ],
44
62
  };
@@ -69,6 +87,19 @@ export const docsZh = {
69
87
  type: 'ReactNode',
70
88
  description: '在标签和描述之后渲染的附加内容。',
71
89
  },
90
+ {
91
+ name: 'hasCloseOnSelect',
92
+ type: 'boolean',
93
+ description: '激活该项时是否关闭菜单。若操作要在该项上就地反馈结果,请设为 false。',
94
+ default: 'true',
95
+ },
96
+ {
97
+ name: 'variant',
98
+ type: "'default' | 'destructive'",
99
+ description:
100
+ "视觉变体。'destructive' 会以错误色渲染标签、描述和图标,用于危险操作(如删除)。",
101
+ default: "'default'",
102
+ },
72
103
  {
73
104
  name: 'xstyle',
74
105
  type: 'StyleXStyles',
@@ -87,6 +118,10 @@ export const docsDense = {
87
118
  label: 'primary label text',
88
119
  description: 'secondary text below label',
89
120
  endContent: 'additional content after label+description',
121
+ hasCloseOnSelect:
122
+ 'false keeps the menu open on activation (in-place result on the item)',
123
+ variant:
124
+ "'destructive' renders the item in the error color for dangerous actions",
90
125
  xstyle: 'StyleX styles for root container',
91
126
  },
92
127
  };
@@ -62,6 +62,15 @@ const menuItemStyles = stylex.create({
62
62
  opacity: 0.5,
63
63
  cursor: 'not-allowed',
64
64
  },
65
+ destructive: {
66
+ // Only recolor the text/icon; the hover / focus background stays the shared
67
+ // neutral overlay from `root` so the hover state matches every other menu
68
+ // item. The root color covers the label/description via the Item custom
69
+ // properties (and any bare text). Semantic error tokens keep it theme-aware.
70
+ color: colorVars['--color-error'],
71
+ '--_item-label-color': colorVars['--color-error'],
72
+ '--_item-description-color': colorVars['--color-error'],
73
+ },
65
74
  });
66
75
 
67
76
  const itemSizeStyles = stylex.create({
@@ -91,6 +100,19 @@ export interface DropdownMenuItemProps extends Pick<
91
100
  isDisabled?: boolean;
92
101
  /** Additional content to render after the label/description. */
93
102
  endContent?: ReactNode;
103
+ /**
104
+ * Whether activating the item closes the menu. Set `false` for an action
105
+ * that reports its result on the item itself (a copy row swapping to
106
+ * "Copied"), matching the checkbox and radio items, which already decide
107
+ * this for themselves.
108
+ * @default true
109
+ */
110
+ hasCloseOnSelect?: boolean;
111
+ /**
112
+ * Visual variant. `'destructive'` renders the label, description, and icon in
113
+ * the error color for dangerous actions (e.g. Delete). @default 'default'
114
+ */
115
+ variant?: 'default' | 'destructive';
94
116
  }
95
117
 
96
118
  /**
@@ -103,7 +125,7 @@ export interface DropdownMenuItemProps extends Pick<
103
125
  * ```
104
126
  * <DropdownMenu button={{ label: 'Actions' }}>
105
127
  * <DropdownMenuItem icon={PencilIcon} label="Edit" onClick={handleEdit} />
106
- * <DropdownMenuItem label="Delete" endContent={<Badge label="⌘D" />} onClick={handleDelete} />
128
+ * <DropdownMenuItem label="Delete" variant="destructive" onClick={handleDelete} />
107
129
  * </DropdownMenu>
108
130
  * ```
109
131
  */
@@ -114,6 +136,8 @@ export function DropdownMenuItem({
114
136
  onClick,
115
137
  isDisabled = false,
116
138
  endContent,
139
+ hasCloseOnSelect = true,
140
+ variant = 'default',
117
141
  xstyle,
118
142
  className,
119
143
  style,
@@ -122,18 +146,22 @@ export function DropdownMenuItem({
122
146
  const menuSize = ctx?.menuSize ?? 'md';
123
147
 
124
148
  const handleClick = useCallback(() => {
125
- if (isDisabled || !onClick) {
149
+ if (isDisabled) {
126
150
  return;
127
151
  }
128
- onClick();
129
- ctx?.closeMenu();
130
- }, [isDisabled, onClick, ctx]);
152
+ onClick?.();
153
+ if (hasCloseOnSelect) {
154
+ ctx?.closeMenu();
155
+ }
156
+ }, [isDisabled, onClick, hasCloseOnSelect, ctx]);
131
157
 
132
158
  const handlePointerMove = useCallback(
133
159
  (e: PointerEvent<HTMLElement>) => focusMenuItemOnHover(e, isDisabled),
134
160
  [isDisabled],
135
161
  );
136
162
 
163
+ const isDestructive = variant === 'destructive';
164
+
137
165
  return (
138
166
  <Item
139
167
  role="menuitem"
@@ -141,7 +169,10 @@ export function DropdownMenuItem({
141
169
  onPointerMove={handlePointerMove}
142
170
  startContent={
143
171
  icon
144
- ? renderIconSlot(icon, {size: 'sm', color: 'secondary'})
172
+ ? renderIconSlot(icon, {
173
+ size: 'sm',
174
+ color: isDestructive ? 'error' : 'secondary',
175
+ })
145
176
  : undefined
146
177
  }
147
178
  label={label}
@@ -152,13 +183,20 @@ export function DropdownMenuItem({
152
183
  xstyle={[
153
184
  menuItemStyles.root,
154
185
  itemSizeStyles[menuSize],
186
+ isDestructive && menuItemStyles.destructive,
155
187
  isDisabled && menuItemStyles.disabled,
156
188
  xstyle,
157
189
  ]}
158
- {...mergeProps(themeProps('dropdown-menu-item', {size: menuSize}), {
159
- className,
160
- style,
161
- })}
190
+ {...mergeProps(
191
+ themeProps('dropdown-menu-item', {
192
+ size: menuSize,
193
+ variant: isDestructive ? 'destructive' : null,
194
+ }),
195
+ {
196
+ className,
197
+ style,
198
+ },
199
+ )}
162
200
  />
163
201
  );
164
202
  }