@astryxdesign/core 0.1.9 → 0.2.0-canary.0e01213

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 (625) hide show
  1. package/CHANGELOG.md +107 -0
  2. package/dist/Avatar/Avatar.d.ts +42 -3
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +190 -59
  5. package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
  6. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  7. package/dist/AvatarGroup/AvatarGroup.d.ts +7 -1
  8. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  9. package/dist/AvatarGroup/AvatarGroup.js +58 -6
  10. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  11. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  12. package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -2
  13. package/dist/Banner/Banner.js +2 -2
  14. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  15. package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
  16. package/dist/Breadcrumbs/index.d.ts +1 -0
  17. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  18. package/dist/Breadcrumbs/index.js +2 -1
  19. package/dist/Button/Button.d.ts +1 -1
  20. package/dist/Button/Button.d.ts.map +1 -1
  21. package/dist/Button/Button.js +6 -4
  22. package/dist/Calendar/Calendar.d.ts.map +1 -1
  23. package/dist/Calendar/Calendar.js +50 -9
  24. package/dist/Calendar/dayCellUtils.d.ts +4 -4
  25. package/dist/Calendar/dayCellUtils.js +2 -2
  26. package/dist/Calendar/styles.d.ts +30 -31
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +30 -31
  29. package/dist/Card/Card.js +1 -1
  30. package/dist/Carousel/Carousel.d.ts.map +1 -1
  31. package/dist/Carousel/Carousel.js +22 -12
  32. package/dist/Center/Center.d.ts +20 -3
  33. package/dist/Center/Center.d.ts.map +1 -1
  34. package/dist/Center/Center.js +10 -2
  35. package/dist/Chat/ChatComposerInput.js +1 -1
  36. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  37. package/dist/Chat/ChatDictationButton.js +3 -1
  38. package/dist/Chat/ChatLayout.d.ts +7 -0
  39. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  40. package/dist/Chat/ChatLayout.js +16 -5
  41. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  42. package/dist/Chat/ChatMessageBubble.js +8 -8
  43. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  44. package/dist/Chat/ChatToolCalls.js +10 -3
  45. package/dist/Chat/useTriggerMenu.js +2 -2
  46. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  47. package/dist/CheckboxInput/CheckboxInput.js +6 -6
  48. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  49. package/dist/CheckboxList/CheckboxListItem.js +19 -4
  50. package/dist/Citation/Citation.d.ts +22 -1
  51. package/dist/Citation/Citation.d.ts.map +1 -1
  52. package/dist/Citation/Citation.js +20 -6
  53. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  54. package/dist/CodeBlock/CodeBlock.js +16 -10
  55. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  56. package/dist/Collapsible/Collapsible.js +3 -1
  57. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  58. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  59. package/dist/CommandPalette/CommandPalette.js +42 -3
  60. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  61. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  62. package/dist/ContextMenu/ContextMenu.js +23 -5
  63. package/dist/ContextMenu/index.d.ts +1 -0
  64. package/dist/ContextMenu/index.d.ts.map +1 -1
  65. package/dist/ContextMenu/index.js +3 -1
  66. package/dist/DateInput/DateInput.d.ts +10 -2
  67. package/dist/DateInput/DateInput.d.ts.map +1 -1
  68. package/dist/DateInput/DateInput.js +33 -19
  69. package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
  70. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  71. package/dist/DateRangeInput/DateRangeInput.js +23 -20
  72. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  73. package/dist/DateTimeInput/DateTimeInput.js +23 -18
  74. package/dist/Divider/Divider.d.ts +2 -2
  75. package/dist/Divider/Divider.d.ts.map +1 -1
  76. package/dist/Divider/Divider.js +13 -0
  77. package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
  78. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  79. package/dist/DropdownMenu/DropdownMenu.js +22 -5
  80. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +18 -12
  81. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  82. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +42 -64
  83. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
  85. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
  86. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  87. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
  88. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  89. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  90. package/dist/DropdownMenu/DropdownMenuRadioItem.js +10 -3
  91. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
  92. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
  93. package/dist/DropdownMenu/DropdownMenuSubMenu.js +435 -0
  94. package/dist/DropdownMenu/index.d.ts +10 -0
  95. package/dist/DropdownMenu/index.d.ts.map +1 -1
  96. package/dist/DropdownMenu/index.js +13 -0
  97. package/dist/DropdownMenu/menuItemHover.d.ts +24 -0
  98. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
  99. package/dist/DropdownMenu/menuItemHover.js +34 -0
  100. package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
  101. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
  102. package/dist/DropdownMenu/menuItemRoles.js +10 -1
  103. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  104. package/dist/DropdownMenu/renderDropdownItems.js +27 -10
  105. package/dist/Field/Field.d.ts +3 -1
  106. package/dist/Field/Field.d.ts.map +1 -1
  107. package/dist/Field/Field.js +4 -1
  108. package/dist/Field/FieldLabel.d.ts +2 -1
  109. package/dist/Field/FieldLabel.d.ts.map +1 -1
  110. package/dist/Field/FieldLabel.js +9 -5
  111. package/dist/Field/inputStyles.stylex.d.ts +1 -0
  112. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  113. package/dist/Field/inputStyles.stylex.js +1 -0
  114. package/dist/FieldStatus/FieldStatus.d.ts +10 -0
  115. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  116. package/dist/FieldStatus/FieldStatus.js +51 -5
  117. package/dist/FileInput/FileInput.d.ts +10 -2
  118. package/dist/FileInput/FileInput.d.ts.map +1 -1
  119. package/dist/FileInput/FileInput.js +93 -65
  120. package/dist/Heading/Heading.d.ts.map +1 -1
  121. package/dist/Heading/Heading.js +3 -2
  122. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  123. package/dist/HoverCard/useHoverCard.js +10 -4
  124. package/dist/Icon/Icon.d.ts +15 -1
  125. package/dist/Icon/Icon.d.ts.map +1 -1
  126. package/dist/Icon/Icon.js +19 -3
  127. package/dist/Item/Item.d.ts +16 -3
  128. package/dist/Item/Item.d.ts.map +1 -1
  129. package/dist/Item/Item.js +31 -6
  130. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  131. package/dist/Layer/layerAnimations.stylex.js +10 -2
  132. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  133. package/dist/Lightbox/Lightbox.js +34 -15
  134. package/dist/List/List.d.ts.map +1 -1
  135. package/dist/List/List.js +6 -3
  136. package/dist/List/ListItem.d.ts +11 -1
  137. package/dist/List/ListItem.d.ts.map +1 -1
  138. package/dist/List/ListItem.js +2 -0
  139. package/dist/Markdown/Markdown.d.ts.map +1 -1
  140. package/dist/Markdown/Markdown.js +7 -0
  141. package/dist/MetadataList/MetadataList.d.ts +1 -1
  142. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  143. package/dist/MetadataList/MetadataList.js +4 -2
  144. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  145. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  146. package/dist/MultiSelector/MultiSelector.js +87 -45
  147. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  148. package/dist/NumberInput/NumberInput.d.ts +10 -2
  149. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  150. package/dist/NumberInput/NumberInput.js +22 -17
  151. package/dist/Outline/Outline.js +2 -2
  152. package/dist/Pagination/Pagination.d.ts.map +1 -1
  153. package/dist/Pagination/Pagination.js +11 -3
  154. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  155. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  156. package/dist/PowerSearch/PowerSearch.js +2 -0
  157. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  158. package/dist/ProgressBar/ProgressBar.js +6 -1
  159. package/dist/RadioList/RadioList.d.ts +2 -2
  160. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  161. package/dist/RadioList/RadioListItem.js +5 -5
  162. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  163. package/dist/Resizable/ResizeHandle.js +49 -19
  164. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  165. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  166. package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
  167. package/dist/Selector/Selector.d.ts +8 -0
  168. package/dist/Selector/Selector.d.ts.map +1 -1
  169. package/dist/Selector/Selector.js +72 -19
  170. package/dist/SideNav/SideNav.d.ts.map +1 -1
  171. package/dist/SideNav/SideNav.js +5 -5
  172. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  173. package/dist/SideNav/SideNavCollapseButton.js +13 -10
  174. package/dist/SideNav/SideNavItem.d.ts +1 -1
  175. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  176. package/dist/SideNav/SideNavItem.js +12 -10
  177. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  178. package/dist/Skeleton/Skeleton.js +2 -2
  179. package/dist/Slider/Slider.d.ts.map +1 -1
  180. package/dist/Slider/Slider.js +87 -34
  181. package/dist/Spinner/Spinner.d.ts +3 -2
  182. package/dist/Spinner/Spinner.d.ts.map +1 -1
  183. package/dist/Spinner/Spinner.js +11 -2
  184. package/dist/Switch/Switch.d.ts +8 -1
  185. package/dist/Switch/Switch.d.ts.map +1 -1
  186. package/dist/Switch/Switch.js +171 -91
  187. package/dist/TabList/Tab.js +2 -2
  188. package/dist/TabList/TabList.d.ts +2 -11
  189. package/dist/TabList/TabList.d.ts.map +1 -1
  190. package/dist/TabList/TabList.js +5 -9
  191. package/dist/TabList/TabListContext.d.ts +0 -5
  192. package/dist/TabList/TabListContext.d.ts.map +1 -1
  193. package/dist/TabList/TabListContext.js +0 -5
  194. package/dist/TabList/TabMenu.js +1 -1
  195. package/dist/Table/BaseTable.d.ts.map +1 -1
  196. package/dist/Table/BaseTable.js +30 -4
  197. package/dist/Table/TableCell.js +3 -3
  198. package/dist/Table/TableHeaderCell.js +3 -3
  199. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  200. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
  201. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +18 -3
  202. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  203. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +58 -30
  204. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  205. package/dist/Table/plugins/selection/useTableSelection.js +3 -0
  206. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  207. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
  208. package/dist/Table/plugins/tree/useTableTreeData.d.ts +11 -0
  209. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  210. package/dist/Table/plugins/tree/useTableTreeData.js +65 -25
  211. package/dist/Table/types.d.ts +32 -0
  212. package/dist/Table/types.d.ts.map +1 -1
  213. package/dist/Text/Text.d.ts +10 -1
  214. package/dist/Text/Text.d.ts.map +1 -1
  215. package/dist/Text/Text.js +25 -2
  216. package/dist/Text/index.d.ts +2 -2
  217. package/dist/Text/index.d.ts.map +1 -1
  218. package/dist/TextArea/TextArea.d.ts +10 -1
  219. package/dist/TextArea/TextArea.d.ts.map +1 -1
  220. package/dist/TextArea/TextArea.js +119 -52
  221. package/dist/TextInput/TextInput.d.ts +10 -2
  222. package/dist/TextInput/TextInput.d.ts.map +1 -1
  223. package/dist/TextInput/TextInput.js +20 -17
  224. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  225. package/dist/Thumbnail/Thumbnail.js +51 -45
  226. package/dist/TimeInput/TimeInput.d.ts +10 -2
  227. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  228. package/dist/TimeInput/TimeInput.js +17 -17
  229. package/dist/Timestamp/Timestamp.d.ts +31 -3
  230. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  231. package/dist/Timestamp/Timestamp.js +48 -77
  232. package/dist/Timestamp/formatInstant.d.ts +41 -0
  233. package/dist/Timestamp/formatInstant.d.ts.map +1 -0
  234. package/dist/Timestamp/formatInstant.js +177 -0
  235. package/dist/Timestamp/index.d.ts +1 -0
  236. package/dist/Timestamp/index.d.ts.map +1 -1
  237. package/dist/Timestamp/tooltipEntries.d.ts +56 -0
  238. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
  239. package/dist/Timestamp/tooltipEntries.js +163 -0
  240. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  241. package/dist/Toast/ToastViewport.js +61 -9
  242. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  243. package/dist/ToggleButton/ToggleButton.js +3 -1
  244. package/dist/Token/Token.d.ts +34 -4
  245. package/dist/Token/Token.d.ts.map +1 -1
  246. package/dist/Token/Token.js +85 -45
  247. package/dist/Token/TokenLink.d.ts +62 -0
  248. package/dist/Token/TokenLink.d.ts.map +1 -0
  249. package/dist/Token/TokenLink.js +76 -0
  250. package/dist/Token/index.d.ts +1 -1
  251. package/dist/Token/index.d.ts.map +1 -1
  252. package/dist/Tokenizer/Tokenizer.d.ts +9 -2
  253. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  254. package/dist/Tokenizer/Tokenizer.js +4 -2
  255. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  256. package/dist/Tooltip/useTooltip.js +17 -1
  257. package/dist/TopNav/TopNavItem.d.ts +3 -1
  258. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  259. package/dist/TopNav/TopNavItem.js +30 -3
  260. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  261. package/dist/TopNav/TopNavMegaMenu.js +9 -3
  262. package/dist/TreeList/TreeList.d.ts.map +1 -1
  263. package/dist/TreeList/TreeList.js +1 -0
  264. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  265. package/dist/TreeList/TreeListBranches.js +8 -6
  266. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  267. package/dist/TreeList/TreeListItem.js +32 -14
  268. package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
  269. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  270. package/dist/Typeahead/BaseTypeahead.js +22 -11
  271. package/dist/Typeahead/Typeahead.d.ts +9 -2
  272. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  273. package/dist/Typeahead/Typeahead.js +11 -2
  274. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  275. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  276. package/dist/Typeahead/TypeaheadItem.js +20 -10
  277. package/dist/astryx.css +115 -35
  278. package/dist/astryx.umd.js +51 -51
  279. package/dist/astryx.umd.js.map +4 -4
  280. package/dist/hooks/containerReveal.pool.stylex.d.ts +281 -0
  281. package/dist/hooks/containerReveal.pool.stylex.d.ts.map +1 -0
  282. package/dist/hooks/containerReveal.pool.stylex.js +281 -0
  283. package/dist/hooks/index.d.ts +4 -0
  284. package/dist/hooks/index.d.ts.map +1 -1
  285. package/dist/hooks/index.js +3 -1
  286. package/dist/hooks/isRtlElement.d.ts +18 -0
  287. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  288. package/dist/hooks/isRtlElement.js +27 -0
  289. package/dist/hooks/useAnnounce.d.ts +3 -0
  290. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  291. package/dist/hooks/useAnnounce.js +39 -1
  292. package/dist/hooks/useContainerReveal.d.ts +83 -0
  293. package/dist/hooks/useContainerReveal.d.ts.map +1 -0
  294. package/dist/hooks/useContainerReveal.js +123 -0
  295. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  296. package/dist/hooks/useFocusTrap.js +52 -11
  297. package/dist/hooks/useGridFocus.d.ts +6 -1
  298. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  299. package/dist/hooks/useGridFocus.js +12 -9
  300. package/dist/hooks/useHotkeys.d.ts +9 -0
  301. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  302. package/dist/hooks/useHotkeys.js +9 -0
  303. package/dist/hooks/useInputStatusIcon.d.ts +38 -0
  304. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
  305. package/dist/hooks/useInputStatusIcon.js +169 -0
  306. package/dist/hooks/useKeyboardHint.d.ts +1 -1
  307. package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
  308. package/dist/hooks/useKeyboardHint.js +4 -2
  309. package/dist/hooks/useListFocus.d.ts +39 -1
  310. package/dist/hooks/useListFocus.d.ts.map +1 -1
  311. package/dist/hooks/useListFocus.js +54 -9
  312. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  313. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  314. package/dist/i18n/InternationalizationContext.js +3 -0
  315. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  316. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  317. package/dist/i18n/InternationalizationProvider.js +5 -1
  318. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  319. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  320. package/dist/i18n/getLocaleDirection.js +29 -0
  321. package/dist/i18n/index.d.ts +6 -0
  322. package/dist/i18n/index.d.ts.map +1 -1
  323. package/dist/i18n/index.js +7 -1
  324. package/dist/i18n/useDirection.d.ts +2 -0
  325. package/dist/i18n/useDirection.d.ts.map +1 -0
  326. package/dist/i18n/useDirection.js +27 -0
  327. package/dist/theme/defineTheme.d.ts +6 -0
  328. package/dist/theme/defineTheme.d.ts.map +1 -1
  329. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  330. package/dist/theme/derivedVarRegistry.js +13 -0
  331. package/dist/theme/expandColorScale.d.ts +19 -2
  332. package/dist/theme/expandColorScale.d.ts.map +1 -1
  333. package/dist/theme/expandColorScale.js +38 -10
  334. package/dist/theme/index.d.ts +3 -3
  335. package/dist/theme/index.d.ts.map +1 -1
  336. package/dist/theme/types.d.ts +39 -2
  337. package/dist/theme/types.d.ts.map +1 -1
  338. package/dist/utils/index.d.ts +1 -0
  339. package/dist/utils/index.d.ts.map +1 -1
  340. package/dist/utils/index.js +2 -1
  341. package/dist/utils/plainDate.d.ts +17 -0
  342. package/dist/utils/plainDate.d.ts.map +1 -1
  343. package/dist/utils/plainDate.js +23 -4
  344. package/dist/utils/rtlStyles.d.ts +24 -0
  345. package/dist/utils/rtlStyles.d.ts.map +1 -0
  346. package/dist/utils/rtlStyles.js +27 -0
  347. package/locales/en.json +120 -0
  348. package/locales/pseudo.json +90 -0
  349. package/package.json +8 -3
  350. package/src/Avatar/Avatar.doc.mjs +50 -3
  351. package/src/Avatar/Avatar.test.tsx +218 -0
  352. package/src/Avatar/Avatar.tsx +285 -79
  353. package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
  354. package/src/Avatar/AvatarStatusDot.tsx +6 -4
  355. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  356. package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
  357. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  358. package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
  359. package/src/Banner/Banner.tsx +6 -6
  360. package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
  361. package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
  362. package/src/Breadcrumbs/index.ts +4 -0
  363. package/src/Button/Button.doc.mjs +0 -4
  364. package/src/Button/Button.test.tsx +16 -0
  365. package/src/Button/Button.tsx +6 -4
  366. package/src/Calendar/Calendar.test.tsx +170 -20
  367. package/src/Calendar/Calendar.tsx +73 -16
  368. package/src/Calendar/dayCellUtils.test.ts +18 -18
  369. package/src/Calendar/dayCellUtils.ts +2 -2
  370. package/src/Calendar/styles.ts +33 -39
  371. package/src/Card/Card.tsx +1 -1
  372. package/src/Carousel/Carousel.tsx +25 -6
  373. package/src/Center/Center.doc.mjs +38 -0
  374. package/src/Center/Center.test.tsx +75 -0
  375. package/src/Center/Center.tsx +37 -2
  376. package/src/Chat/ChatComposer.doc.mjs +2 -2
  377. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  378. package/src/Chat/ChatComposerInput.tsx +2 -2
  379. package/src/Chat/ChatDictationButton.tsx +7 -1
  380. package/src/Chat/ChatLayout.test.tsx +57 -0
  381. package/src/Chat/ChatLayout.tsx +26 -5
  382. package/src/Chat/ChatMessageBubble.tsx +15 -10
  383. package/src/Chat/ChatSystemMessage.test.tsx +5 -0
  384. package/src/Chat/ChatToolCalls.tsx +9 -2
  385. package/src/Chat/useTriggerMenu.tsx +1 -1
  386. package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
  387. package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
  388. package/src/CheckboxInput/CheckboxInput.tsx +21 -6
  389. package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
  390. package/src/CheckboxList/CheckboxList.test.tsx +94 -3
  391. package/src/CheckboxList/CheckboxListItem.tsx +17 -10
  392. package/src/Citation/Citation.doc.mjs +4 -3
  393. package/src/Citation/Citation.test.tsx +97 -0
  394. package/src/Citation/Citation.tsx +43 -11
  395. package/src/CodeBlock/CodeBlock.test.tsx +17 -0
  396. package/src/CodeBlock/CodeBlock.tsx +38 -11
  397. package/src/Collapsible/Collapsible.doc.mjs +1 -0
  398. package/src/Collapsible/Collapsible.test.tsx +7 -0
  399. package/src/Collapsible/Collapsible.tsx +16 -6
  400. package/src/CommandPalette/CommandPalette.test.tsx +95 -1
  401. package/src/CommandPalette/CommandPalette.tsx +41 -2
  402. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  403. package/src/ContextMenu/ContextMenu.test.tsx +59 -2
  404. package/src/ContextMenu/ContextMenu.tsx +22 -11
  405. package/src/ContextMenu/index.ts +5 -0
  406. package/src/DateInput/DateInput.doc.mjs +25 -0
  407. package/src/DateInput/DateInput.test.tsx +230 -0
  408. package/src/DateInput/DateInput.tsx +51 -29
  409. package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
  410. package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
  411. package/src/DateRangeInput/DateRangeInput.tsx +42 -30
  412. package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
  413. package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
  414. package/src/DateTimeInput/DateTimeInput.tsx +44 -39
  415. package/src/Divider/Divider.test.tsx +32 -8
  416. package/src/Divider/Divider.tsx +14 -1
  417. package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -2
  418. package/src/DropdownMenu/DropdownMenu.test.tsx +95 -0
  419. package/src/DropdownMenu/DropdownMenu.tsx +31 -12
  420. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +49 -66
  421. package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
  422. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
  423. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
  424. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +19 -4
  425. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +84 -2
  426. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
  427. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +680 -0
  428. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +569 -0
  429. package/src/DropdownMenu/index.ts +16 -0
  430. package/src/DropdownMenu/menuItemHover.ts +40 -0
  431. package/src/DropdownMenu/menuItemRoles.ts +9 -0
  432. package/src/DropdownMenu/renderDropdownItems.tsx +40 -14
  433. package/src/Field/Field.doc.mjs +4 -0
  434. package/src/Field/Field.tsx +14 -9
  435. package/src/Field/FieldLabel.test.tsx +25 -0
  436. package/src/Field/FieldLabel.tsx +12 -3
  437. package/src/Field/inputStyles.stylex.ts +2 -0
  438. package/src/FieldStatus/FieldStatus.doc.mjs +1 -0
  439. package/src/FieldStatus/FieldStatus.test.tsx +133 -0
  440. package/src/FieldStatus/FieldStatus.tsx +61 -4
  441. package/src/FileInput/FileInput.doc.mjs +23 -2
  442. package/src/FileInput/FileInput.test.tsx +104 -13
  443. package/src/FileInput/FileInput.tsx +106 -79
  444. package/src/Heading/Heading.tsx +2 -1
  445. package/src/HoverCard/useHoverCard.tsx +15 -3
  446. package/src/Icon/Icon.doc.mjs +13 -0
  447. package/src/Icon/Icon.test.tsx +89 -0
  448. package/src/Icon/Icon.tsx +51 -3
  449. package/src/Item/Item.doc.mjs +5 -0
  450. package/src/Item/Item.test.tsx +88 -0
  451. package/src/Item/Item.tsx +57 -11
  452. package/src/Layer/layerAnimations.stylex.ts +23 -0
  453. package/src/Lightbox/Lightbox.test.tsx +33 -0
  454. package/src/Lightbox/Lightbox.tsx +30 -10
  455. package/src/List/List.test.tsx +17 -29
  456. package/src/List/List.tsx +6 -1
  457. package/src/List/ListItem.doc.mjs +12 -0
  458. package/src/List/ListItem.tsx +13 -0
  459. package/src/Markdown/Markdown.test.tsx +21 -0
  460. package/src/Markdown/Markdown.tsx +4 -0
  461. package/src/MetadataList/MetadataList.test.tsx +24 -0
  462. package/src/MetadataList/MetadataList.tsx +6 -2
  463. package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
  464. package/src/MultiSelector/MultiSelector.test.tsx +436 -0
  465. package/src/MultiSelector/MultiSelector.tsx +133 -67
  466. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  467. package/src/NumberInput/NumberInput.doc.mjs +21 -0
  468. package/src/NumberInput/NumberInput.test.tsx +71 -0
  469. package/src/NumberInput/NumberInput.tsx +35 -26
  470. package/src/Outline/Outline.test.tsx +12 -12
  471. package/src/Outline/Outline.tsx +2 -2
  472. package/src/Pagination/Pagination.tsx +11 -3
  473. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  474. package/src/PowerSearch/PowerSearch.test.tsx +23 -0
  475. package/src/PowerSearch/PowerSearch.tsx +10 -1
  476. package/src/ProgressBar/ProgressBar.test.tsx +34 -0
  477. package/src/ProgressBar/ProgressBar.tsx +16 -1
  478. package/src/RadioList/RadioList.doc.mjs +6 -0
  479. package/src/RadioList/RadioList.test.tsx +26 -4
  480. package/src/RadioList/RadioList.tsx +2 -2
  481. package/src/RadioList/RadioListItem.tsx +12 -5
  482. package/src/Resizable/ResizeHandle.test.tsx +94 -0
  483. package/src/Resizable/ResizeHandle.tsx +70 -20
  484. package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
  485. package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
  486. package/src/Selector/Selector.doc.mjs +15 -0
  487. package/src/Selector/Selector.test.tsx +400 -0
  488. package/src/Selector/Selector.tsx +95 -23
  489. package/src/SideNav/SideNav.tsx +1 -8
  490. package/src/SideNav/SideNavCollapseButton.tsx +9 -7
  491. package/src/SideNav/SideNavItem.tsx +5 -3
  492. package/src/Skeleton/Skeleton.test.tsx +16 -0
  493. package/src/Skeleton/Skeleton.tsx +13 -1
  494. package/src/Slider/Slider.doc.mjs +6 -0
  495. package/src/Slider/Slider.test.tsx +240 -12
  496. package/src/Slider/Slider.tsx +96 -23
  497. package/src/Spinner/Spinner.test.tsx +10 -8
  498. package/src/Spinner/Spinner.tsx +15 -5
  499. package/src/Switch/Switch.doc.mjs +142 -42
  500. package/src/Switch/Switch.test.tsx +111 -0
  501. package/src/Switch/Switch.tsx +149 -32
  502. package/src/TabList/Tab.tsx +2 -2
  503. package/src/TabList/TabList.doc.mjs +0 -6
  504. package/src/TabList/TabList.test.tsx +3 -15
  505. package/src/TabList/TabList.tsx +6 -17
  506. package/src/TabList/TabListContext.ts +0 -6
  507. package/src/TabList/TabMenu.tsx +2 -2
  508. package/src/Table/BaseTable.tsx +34 -2
  509. package/src/Table/Table.doc.mjs +11 -0
  510. package/src/Table/Table.test.tsx +85 -0
  511. package/src/Table/TableCell.tsx +3 -3
  512. package/src/Table/TableHeaderCell.tsx +3 -3
  513. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
  514. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
  515. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +48 -21
  516. package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
  517. package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
  518. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
  519. package/src/Table/plugins/tree/useTableTreeData.test.tsx +161 -2
  520. package/src/Table/plugins/tree/useTableTreeData.tsx +71 -14
  521. package/src/Table/types.ts +33 -0
  522. package/src/Table/useTableRowExpansion.doc.mjs +55 -2
  523. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  524. package/src/Table/useTableTreeData.doc.mjs +9 -0
  525. package/src/Text/Heading.doc.mjs +3 -3
  526. package/src/Text/Text.doc.mjs +1 -1
  527. package/src/Text/Text.test.tsx +42 -0
  528. package/src/Text/Text.tsx +25 -1
  529. package/src/Text/index.ts +2 -6
  530. package/src/TextArea/TextArea.doc.mjs +23 -2
  531. package/src/TextArea/TextArea.test.tsx +132 -4
  532. package/src/TextArea/TextArea.tsx +161 -67
  533. package/src/TextInput/TextInput.doc.mjs +21 -0
  534. package/src/TextInput/TextInput.test.tsx +150 -0
  535. package/src/TextInput/TextInput.tsx +28 -25
  536. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  537. package/src/Thumbnail/Thumbnail.test.tsx +24 -1
  538. package/src/Thumbnail/Thumbnail.tsx +28 -35
  539. package/src/TimeInput/TimeInput.doc.mjs +21 -0
  540. package/src/TimeInput/TimeInput.test.tsx +23 -0
  541. package/src/TimeInput/TimeInput.tsx +24 -25
  542. package/src/Timestamp/Timestamp.doc.mjs +32 -6
  543. package/src/Timestamp/Timestamp.test.tsx +371 -0
  544. package/src/Timestamp/Timestamp.tsx +96 -93
  545. package/src/Timestamp/formatInstant.ts +218 -0
  546. package/src/Timestamp/index.ts +4 -0
  547. package/src/Timestamp/tooltipEntries.test.ts +552 -0
  548. package/src/Timestamp/tooltipEntries.ts +210 -0
  549. package/src/Toast/ToastViewport.test.tsx +218 -8
  550. package/src/Toast/ToastViewport.tsx +71 -12
  551. package/src/ToggleButton/ToggleButton.test.tsx +24 -0
  552. package/src/ToggleButton/ToggleButton.tsx +19 -1
  553. package/src/Token/Token.test.tsx +166 -15
  554. package/src/Token/Token.tsx +104 -47
  555. package/src/Token/TokenLink.tsx +107 -0
  556. package/src/Token/index.ts +1 -1
  557. package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
  558. package/src/Tokenizer/Tokenizer.test.tsx +23 -0
  559. package/src/Tokenizer/Tokenizer.tsx +14 -2
  560. package/src/Tooltip/Tooltip.test.tsx +46 -0
  561. package/src/Tooltip/useTooltip.tsx +20 -0
  562. package/src/TopNav/TopNav.test.tsx +93 -2
  563. package/src/TopNav/TopNavItem.doc.mjs +3 -3
  564. package/src/TopNav/TopNavItem.tsx +35 -6
  565. package/src/TopNav/TopNavMegaMenu.tsx +26 -2
  566. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
  567. package/src/TreeList/TreeList.doc.mjs +6 -0
  568. package/src/TreeList/TreeList.test.tsx +50 -10
  569. package/src/TreeList/TreeList.tsx +5 -0
  570. package/src/TreeList/TreeListBranches.tsx +8 -6
  571. package/src/TreeList/TreeListItem.tsx +33 -11
  572. package/src/Typeahead/BaseTypeahead.tsx +42 -15
  573. package/src/Typeahead/Typeahead.doc.mjs +13 -0
  574. package/src/Typeahead/Typeahead.test.tsx +112 -0
  575. package/src/Typeahead/Typeahead.tsx +17 -1
  576. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  577. package/src/__tests__/babelPluginAddExtensions.test.ts +190 -0
  578. package/src/__tests__/forcedColors.ts +60 -0
  579. package/src/__tests__/inputWidthContract.test.tsx +62 -0
  580. package/src/doc-mjs.d.ts +19 -0
  581. package/src/hooks/containerReveal.pool.stylex.ts +464 -0
  582. package/src/hooks/index.ts +13 -0
  583. package/src/hooks/isRtlElement.ts +27 -0
  584. package/src/hooks/useAnnounce.test.tsx +75 -2
  585. package/src/hooks/useAnnounce.ts +47 -1
  586. package/src/hooks/useContainerReveal.test.tsx +116 -0
  587. package/src/hooks/useContainerReveal.ts +180 -0
  588. package/src/hooks/useFocusTrap.test.tsx +104 -0
  589. package/src/hooks/useFocusTrap.ts +61 -12
  590. package/src/hooks/useGridFocus.doc.mjs +3 -3
  591. package/src/hooks/useGridFocus.test.tsx +41 -0
  592. package/src/hooks/useGridFocus.ts +21 -10
  593. package/src/hooks/useHotkeys.ts +9 -0
  594. package/src/hooks/useInputStatusIcon.test.tsx +221 -0
  595. package/src/hooks/useInputStatusIcon.tsx +235 -0
  596. package/src/hooks/useKeyboardHint.test.tsx +22 -0
  597. package/src/hooks/useKeyboardHint.tsx +6 -2
  598. package/src/hooks/useListFocus.doc.mjs +25 -3
  599. package/src/hooks/useListFocus.test.tsx +153 -1
  600. package/src/hooks/useListFocus.ts +102 -9
  601. package/src/i18n/InternationalizationContext.ts +4 -0
  602. package/src/i18n/InternationalizationProvider.tsx +12 -2
  603. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  604. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  605. package/src/i18n/getLocaleDirection.ts +29 -0
  606. package/src/i18n/index.ts +6 -0
  607. package/src/i18n/useDirection.ts +29 -0
  608. package/src/reset.css +0 -26
  609. package/src/reset.test.ts +60 -0
  610. package/src/theme/defineTheme.ts +6 -0
  611. package/src/theme/derivedVarRegistry.test.ts +1 -0
  612. package/src/theme/derivedVarRegistry.ts +6 -0
  613. package/src/theme/expandColorScale.test.ts +144 -0
  614. package/src/theme/expandColorScale.ts +53 -15
  615. package/src/theme/generateThemeRules.test.ts +42 -0
  616. package/src/theme/index.ts +4 -8
  617. package/src/theme/types.ts +43 -13
  618. package/src/utils/index.ts +2 -0
  619. package/src/utils/plainDate.test.ts +24 -6
  620. package/src/utils/plainDate.ts +18 -4
  621. package/src/utils/rtlStyles.ts +27 -0
  622. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +0 -9
  623. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +0 -1
  624. package/dist/Thumbnail/thumbnail.markers.stylex.js +0 -14
  625. package/src/Thumbnail/thumbnail.markers.stylex.ts +0 -12
@@ -0,0 +1,569 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file DropdownMenuSubMenu.tsx
7
+ * @input React, stylex, useLayer (context mode), useListFocus, useMenuHover,
8
+ * useTypeahead, Item, Icon, Spinner, DropdownMenu context + item roles.
9
+ * @output Exports DropdownMenuSubMenu — a single menu row that reveals a nested
10
+ * flyout menu of its own children/items.
11
+ * @position Sub-component; place inside a DropdownMenu (or ContextMenu)
12
+ * alongside plain items.
13
+ *
14
+ * One component, not three. The row itself adopts DropdownMenuItem semantics
15
+ * (label / icon / description / isDisabled) and its children become the
16
+ * flyout's content. This mirrors how SideNavItem / TreeListItem promote a
17
+ * normal row into a nested surface when given children, rather than the Radix
18
+ * Sub / SubTrigger / SubContent split. Data-driven menus never touch this
19
+ * component directly — renderDropdownItems renders it from a nested `items`
20
+ * array and passes the rendered children in.
21
+ *
22
+ * Built on existing primitives — no bespoke floating code:
23
+ * - Positioning: useLayer context mode opens the flyout inline-end with
24
+ * viewport auto-flip via CSS anchor positioning (RTL-correct by default).
25
+ * - Pointer: useMenuHover for open/close intent.
26
+ * - Keyboard: a per-level useListFocus + useTypeahead. Right (Left in RTL) /
27
+ * Enter / Space opens the flyout and focuses its first item; Left (Right in
28
+ * RTL) / Escape closes it and returns focus to the trigger row.
29
+ *
30
+ * Prior art: legacy internal XDS `XDSDropdownSubMenuItem` (APG menubar-
31
+ * navigation submenu). This re-expresses the same contract on Astryx primitives.
32
+ *
33
+ * SYNC: When modified, update these files to stay in sync:
34
+ * - /packages/core/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs
35
+ * - /packages/core/src/DropdownMenu/DropdownMenuSubMenu.test.tsx
36
+ * - /packages/core/src/DropdownMenu/index.ts
37
+ * - /apps/storybook/stories/DropdownMenu.stories.tsx
38
+ * - /packages/cli/templates/blocks/components/DropdownMenu/ (showcase blocks)
39
+ */
40
+
41
+ import React, {
42
+ useCallback,
43
+ useId,
44
+ useMemo,
45
+ useRef,
46
+ useState,
47
+ type PointerEvent,
48
+ type ReactNode,
49
+ } from 'react';
50
+ import * as stylex from '@stylexjs/stylex';
51
+ import {Icon, renderIconSlot, type IconType} from '../Icon';
52
+ import {Spinner} from '../Spinner';
53
+ import {Item} from '../Item';
54
+ import {useLayer} from '../Layer/useLayer';
55
+ import {layerAnimations} from '../Layer/layerAnimations.stylex';
56
+ import {useListFocus} from '../hooks/useListFocus';
57
+ import {useMenuHover} from '../hooks/useMenuHover';
58
+ import {useTypeahead} from '../hooks/useTypeahead';
59
+ import {
60
+ colorVars,
61
+ spacingVars,
62
+ radiusVars,
63
+ durationVars,
64
+ easeVars,
65
+ shadowVars,
66
+ typographyVars,
67
+ typeScaleVars,
68
+ } from '../theme/tokens.stylex';
69
+ import {mergeProps} from '../utils';
70
+ import {themeProps} from '../utils/themeProps';
71
+ import type {BaseProps} from '../BaseProps';
72
+ import {
73
+ MENU_ITEM_ROLES,
74
+ MENU_ITEM_SELECTOR,
75
+ MENU_BOUNDARY_SELECTOR,
76
+ } from './menuItemRoles';
77
+ import {
78
+ DropdownMenuContext,
79
+ useDropdownMenuContext,
80
+ type DropdownMenuContextValue,
81
+ } from './DropdownMenuContext';
82
+ import {focusMenuItemOnHover} from './menuItemHover';
83
+
84
+ const triggerStyles = stylex.create({
85
+ root: {
86
+ boxSizing: 'border-box',
87
+ width: '100%',
88
+ paddingBlock: spacingVars['--spacing-2'],
89
+ paddingInline: spacingVars['--spacing-2'],
90
+ borderRadius: `max(0px, calc(var(--_dropdown-menu-radius, ${spacingVars['--spacing-2']}) - var(--_dropdown-menu-padding, ${spacingVars['--spacing-1']})))`,
91
+ fontFamily: typographyVars['--font-family-body'],
92
+ fontSize: typeScaleVars['--text-label-size'],
93
+ color: colorVars['--color-text-primary'],
94
+ backgroundColor: {
95
+ default: 'transparent',
96
+ ':focus': colorVars['--color-overlay-hover'],
97
+ },
98
+ border: 'none',
99
+ cursor: 'pointer',
100
+ textAlign: 'start',
101
+ outline: 'none',
102
+ },
103
+ // While the flyout is open, keep the trigger visibly active so the open
104
+ // branch reads as the current path even when focus has moved into the child.
105
+ open: {
106
+ backgroundColor: colorVars['--color-overlay-hover'],
107
+ },
108
+ disabled: {
109
+ opacity: 0.5,
110
+ cursor: 'not-allowed',
111
+ },
112
+ caret: {
113
+ display: 'flex',
114
+ alignItems: 'center',
115
+ },
116
+ });
117
+
118
+ const triggerSizeStyles = stylex.create({
119
+ sm: {
120
+ paddingBlock: spacingVars['--spacing-1'],
121
+ paddingInline: spacingVars['--spacing-2'],
122
+ },
123
+ md: {
124
+ paddingBlock: spacingVars['--spacing-1-5'],
125
+ },
126
+ lg: {},
127
+ });
128
+
129
+ const flyoutStyles = stylex.create({
130
+ menu: {
131
+ boxSizing: 'border-box',
132
+ display: 'flex',
133
+ flexDirection: 'column',
134
+ gap: spacingVars['--spacing-0-5'],
135
+ maxHeight: '300px',
136
+ overflowY: 'auto',
137
+ '--_dropdown-menu-radius': radiusVars['--radius-container'],
138
+ '--_dropdown-menu-padding': spacingVars['--spacing-1'],
139
+ padding: spacingVars['--spacing-1'],
140
+ borderRadius: 'var(--_dropdown-menu-radius)',
141
+ backgroundColor: colorVars['--color-background-popover'],
142
+ boxShadow: shadowVars['--shadow-low'],
143
+ opacity: 1,
144
+ transitionProperty: 'opacity',
145
+ transitionDuration: durationVars['--duration-fast'],
146
+ transitionTimingFunction: easeVars['--ease-standard'],
147
+ },
148
+ popover: {
149
+ minWidth: '160px',
150
+ // Small inline gap so the flyout doesn't sit flush against the parent menu.
151
+ marginInlineStart: spacingVars['--spacing-1'],
152
+ marginInlineEnd: spacingVars['--spacing-1'],
153
+ },
154
+ popoverCustomWidth: (width: string | number) => ({
155
+ minWidth: typeof width === 'number' ? `${width}px` : width,
156
+ marginInlineStart: spacingVars['--spacing-1'],
157
+ marginInlineEnd: spacingVars['--spacing-1'],
158
+ }),
159
+ });
160
+
161
+ interface DropdownMenuSubMenuBaseProps extends Pick<
162
+ BaseProps,
163
+ 'xstyle' | 'className' | 'style'
164
+ > {
165
+ /** Icon to display before the label on the trigger row. */
166
+ icon?: ReactNode | IconType;
167
+ /** Primary label text for the trigger row. */
168
+ label: ReactNode;
169
+ /** Secondary description text displayed below the label. */
170
+ description?: ReactNode;
171
+ /**
172
+ * Whether the submenu is disabled. A disabled submenu renders its trigger
173
+ * row but never opens the flyout.
174
+ * @default false
175
+ */
176
+ isDisabled?: boolean;
177
+ /**
178
+ * Show a spinner in place of the caret, e.g. while a lazy submenu's children
179
+ * are loading. Ported from the legacy `hasSpinner` async-submenu affordance.
180
+ * @default false
181
+ */
182
+ hasSpinner?: boolean;
183
+ /** Fixed flyout width. Defaults to sizing to its content (min 160px). */
184
+ menuWidth?: number | string;
185
+ /** Called when the flyout opens or closes. */
186
+ onOpenChange?: (isOpen: boolean) => void;
187
+ /** Test id for the trigger row. */
188
+ 'data-testid'?: string;
189
+ /** Test id for the flyout menu. */
190
+ menuDataTestId?: string;
191
+ }
192
+
193
+ export interface DropdownMenuSubMenuProps extends DropdownMenuSubMenuBaseProps {
194
+ /**
195
+ * The flyout's menu items — the same components used at the top level
196
+ * (`DropdownMenuItem`, `DropdownMenuSubMenu`, selectable items, etc.).
197
+ *
198
+ * Data-mode parity lives one level up: give a `DropdownMenu`/`ContextMenu`
199
+ * item a nested `items` array and it renders a `DropdownMenuSubMenu` with
200
+ * these children automatically — so the data path never has to reach into
201
+ * this component.
202
+ */
203
+ children: ReactNode;
204
+ }
205
+
206
+ /**
207
+ * A single menu row that reveals a nested flyout of its own items. The row
208
+ * adopts DropdownMenuItem semantics (label / icon / description / isDisabled);
209
+ * its `children` become the flyout content. Place inside a DropdownMenu (or
210
+ * ContextMenu) alongside plain items.
211
+ *
212
+ * For data-driven menus, don't use this directly — give a menu item a nested
213
+ * `items` array and DropdownMenu/ContextMenu renders the submenu for you.
214
+ *
215
+ * @example
216
+ * ```
217
+ * <DropdownMenu button={{label: 'Actions'}}>
218
+ * <DropdownMenuItem label="Rename" onClick={rename} />
219
+ * <DropdownMenuSubMenu label="Move to" icon="folder">
220
+ * <DropdownMenuItem label="Folder A" onClick={() => move('a')} />
221
+ * <DropdownMenuItem label="Folder B" onClick={() => move('b')} />
222
+ * </DropdownMenuSubMenu>
223
+ * </DropdownMenu>
224
+ * ```
225
+ */
226
+ export function DropdownMenuSubMenu(
227
+ props: DropdownMenuSubMenuProps,
228
+ ): ReactNode {
229
+ const {
230
+ icon,
231
+ label,
232
+ description,
233
+ isDisabled = false,
234
+ hasSpinner = false,
235
+ menuWidth,
236
+ onOpenChange,
237
+ children,
238
+ xstyle,
239
+ className,
240
+ style,
241
+ 'data-testid': testId,
242
+ menuDataTestId,
243
+ } = props;
244
+
245
+ const menuCtx = useDropdownMenuContext();
246
+ const menuSize = menuCtx?.menuSize ?? 'md';
247
+ const canOpen = !isDisabled;
248
+
249
+ const contentId = useId();
250
+ const triggerId = useId();
251
+ const triggerRef = useRef<HTMLDivElement | null>(null);
252
+
253
+ const [isOpen, setIsOpen] = useState(false);
254
+
255
+ const layer = useLayer({
256
+ mode: 'context',
257
+ lightDismiss: false,
258
+ onShow: useCallback(() => {
259
+ setIsOpen(true);
260
+ onOpenChange?.(true);
261
+ }, [onOpenChange]),
262
+ onHide: useCallback(() => {
263
+ setIsOpen(false);
264
+ onOpenChange?.(false);
265
+ }, [onOpenChange]),
266
+ });
267
+
268
+ const showLayer = useCallback(() => {
269
+ if (canOpen) {
270
+ layer.show();
271
+ }
272
+ }, [canOpen, layer]);
273
+ const hideLayer = useCallback(() => {
274
+ layer.hide();
275
+ }, [layer]);
276
+
277
+ // Dedicated roving-focus + typeahead for this flyout level. The boundary
278
+ // selector scopes item collection and key handling to this flyout's own
279
+ // `role="menu"` — so a submenu nested inside this one (also inline, also
280
+ // `role="menu"`) doesn't pollute this level's items or double-handle keys.
281
+ const {
282
+ listRef: menuRef,
283
+ handleKeyDown: listNavKeyDown,
284
+ focusFirst,
285
+ focusItem,
286
+ ownsEvent,
287
+ getItems,
288
+ } = useListFocus<HTMLDivElement>({
289
+ itemSelector: MENU_ITEM_SELECTOR,
290
+ boundarySelector: MENU_BOUNDARY_SELECTOR,
291
+ wrap: false,
292
+ onEscape: () => close({focusTrigger: true}),
293
+ });
294
+
295
+ const typeahead = useTypeahead({
296
+ getItemLabels: () => getItems().map(el => el.textContent),
297
+ onMatch: focusItem,
298
+ getCurrentIndex: () =>
299
+ getItems().findIndex(
300
+ el =>
301
+ el === document.activeElement || el.contains(document.activeElement),
302
+ ),
303
+ });
304
+
305
+ // Hover-intent: entering the trigger opens after a short delay; leaving
306
+ // either surface closes after a delay. Hover-open does not steal focus.
307
+ const {triggerProps, contentProps} = useMenuHover<HTMLDivElement>({
308
+ show: showLayer,
309
+ hide: hideLayer,
310
+ isOpen,
311
+ isEnabled: canOpen,
312
+ });
313
+
314
+ const open = useCallback(
315
+ (options?: {focusFirst?: boolean}) => {
316
+ if (!canOpen) {
317
+ return;
318
+ }
319
+ layer.show();
320
+ if (options?.focusFirst) {
321
+ requestAnimationFrame(() => {
322
+ // Move focus into the flyout. When it has no focusable items yet
323
+ // (e.g. an async submenu showing only a disabled "Loading…" row via
324
+ // hasSpinner), focusFirst() finds nothing — fall back to focusing the
325
+ // flyout container itself so keyboard ownership still transfers off
326
+ // the parent list. Otherwise the parent would keep focus, letting
327
+ // arrow keys rove the parent while the empty flyout stays open.
328
+ const focusedItem = focusFirst();
329
+ if (!focusedItem) {
330
+ menuRef.current?.focus();
331
+ }
332
+ });
333
+ }
334
+ },
335
+ [canOpen, layer, focusFirst, menuRef],
336
+ );
337
+
338
+ const close = useCallback(
339
+ (options?: {focusTrigger?: boolean}) => {
340
+ layer.hide();
341
+ if (options?.focusTrigger !== false) {
342
+ triggerRef.current?.focus();
343
+ }
344
+ },
345
+ [layer],
346
+ );
347
+
348
+ // Single ref for the trigger row: store it for focus management AND wire it
349
+ // as the flyout's positioning anchor (CSS anchor positioning).
350
+ const setTriggerEl = useCallback(
351
+ (el: HTMLDivElement | null) => {
352
+ triggerRef.current = el;
353
+ layer.ref(el);
354
+ },
355
+ [layer],
356
+ );
357
+
358
+ const handleTriggerClick = useCallback(() => {
359
+ if (isDisabled) {
360
+ return;
361
+ }
362
+ // Click toggles the flyout, moving focus into it on open.
363
+ if (isOpen) {
364
+ close({focusTrigger: true});
365
+ } else {
366
+ open({focusFirst: true});
367
+ }
368
+ }, [isDisabled, isOpen, open, close]);
369
+
370
+ const handleTriggerKeyDown = useCallback(
371
+ (e: React.KeyboardEvent) => {
372
+ if (isDisabled) {
373
+ return;
374
+ }
375
+ const isRtl =
376
+ typeof window !== 'undefined' && triggerRef.current
377
+ ? window.getComputedStyle(triggerRef.current).direction === 'rtl'
378
+ : false;
379
+ const openKey = isRtl ? 'ArrowLeft' : 'ArrowRight';
380
+ if (e.key === openKey || e.key === 'Enter' || e.key === ' ') {
381
+ e.preventDefault();
382
+ // The trigger row is a direct child of the parent menu (not a nested
383
+ // role="menu"), so the parent's key handler would otherwise also act on
384
+ // this event (e.g. Enter clicking the focused row). Stop it here — this
385
+ // level fully handles opening the flyout.
386
+ e.stopPropagation();
387
+ open({focusFirst: true});
388
+ }
389
+ },
390
+ [isDisabled, open],
391
+ );
392
+
393
+ // Move the single focus-driven highlight onto the trigger as the pointer
394
+ // enters it, so a sibling item that still holds focus doesn't stay
395
+ // highlighted alongside the hovered trigger. This is separate from the
396
+ // hover-open intent (onMouseEnter/onMouseLeave) — the flyout still opens on
397
+ // the hover delay; this only keeps the highlight single.
398
+ const handlePointerMove = useCallback(
399
+ (e: PointerEvent<HTMLElement>) => focusMenuItemOnHover(e, isDisabled),
400
+ [isDisabled],
401
+ );
402
+
403
+ // Enter/Space activate the focused row; typeahead jumps by first character;
404
+ // the close key (Left, or Right in RTL) returns focus to the trigger;
405
+ // arrows/Home/End defer to useListFocus (RTL-aware).
406
+ //
407
+ // The flyout renders inline (useLayer context mode is a native popover, not a
408
+ // portal), so a submenu nested inside this one bubbles its key events up to
409
+ // this handler. `ownsEvent` (from useListFocus, scoped by boundarySelector)
410
+ // tells us whether the event originated in THIS flyout or a deeper one; we
411
+ // only act on our own, letting the deeper level keep ownership. No manual
412
+ // stopPropagation needed — each level self-filters.
413
+ const handleContentKeyDown = useCallback(
414
+ (e: React.KeyboardEvent) => {
415
+ if (!ownsEvent(e)) {
416
+ return;
417
+ }
418
+ // Escape closes just this submenu and returns focus to its trigger (APG:
419
+ // Escape collapses the current level, not the whole stack). The root
420
+ // popover's focus-trap listens for Escape at the document level and bails
421
+ // when the event is already handled, so we mark it handled here (stop
422
+ // propagation + preventDefault) to keep the parent menu open.
423
+ if (e.key === 'Escape') {
424
+ e.preventDefault();
425
+ e.stopPropagation();
426
+ close({focusTrigger: true});
427
+ return;
428
+ }
429
+ if (e.key === 'Enter' || e.key === ' ') {
430
+ e.preventDefault();
431
+ const focused = document.activeElement as HTMLElement | null;
432
+ if (
433
+ focused &&
434
+ MENU_ITEM_ROLES.has(focused.getAttribute('role') ?? '')
435
+ ) {
436
+ focused.click();
437
+ }
438
+ return;
439
+ }
440
+ const isRtl =
441
+ typeof window !== 'undefined' && menuRef.current
442
+ ? window.getComputedStyle(menuRef.current).direction === 'rtl'
443
+ : false;
444
+ const closeKey = isRtl ? 'ArrowRight' : 'ArrowLeft';
445
+ if (e.key === closeKey) {
446
+ e.preventDefault();
447
+ close({focusTrigger: true});
448
+ return;
449
+ }
450
+ if (typeahead.onKeyDown(e)) {
451
+ e.preventDefault();
452
+ return;
453
+ }
454
+ listNavKeyDown(e);
455
+ },
456
+ [ownsEvent, close, listNavKeyDown, typeahead, menuRef],
457
+ );
458
+
459
+ // Re-provide the menu context so nested items behave exactly like top-level
460
+ // ones. Selecting a leaf item must dismiss the WHOLE stack, not just this
461
+ // flyout: close this level (without stealing focus back to the trigger) and
462
+ // propagate up via the parent menu's closeMenu. Because every level
463
+ // re-provides the context, this chains from the deepest flyout all the way to
464
+ // the root DropdownMenu (whose closeMenu hides the popover).
465
+ const nestedMenuContext = useMemo<DropdownMenuContextValue>(
466
+ () => ({
467
+ menuSize,
468
+ closeMenu: () => {
469
+ close({focusTrigger: false});
470
+ menuCtx?.closeMenu();
471
+ },
472
+ }),
473
+ [menuSize, close, menuCtx],
474
+ );
475
+
476
+ const endAffordance = hasSpinner ? (
477
+ <span
478
+ {...mergeProps(
479
+ themeProps('dropdown-menu-indicator-icon'),
480
+ stylex.props(triggerStyles.caret),
481
+ )}>
482
+ <Spinner size="sm" />
483
+ </span>
484
+ ) : (
485
+ <span
486
+ {...mergeProps(
487
+ themeProps('dropdown-menu-indicator-icon'),
488
+ stylex.props(triggerStyles.caret),
489
+ )}>
490
+ <Icon icon="chevronRight" size="sm" color="secondary" />
491
+ </span>
492
+ );
493
+
494
+ const popoverXstyle = menuWidth
495
+ ? flyoutStyles.popoverCustomWidth(menuWidth)
496
+ : flyoutStyles.popover;
497
+
498
+ return (
499
+ <>
500
+ <Item
501
+ ref={el => setTriggerEl(el as HTMLDivElement | null)}
502
+ id={triggerId}
503
+ role="menuitem"
504
+ tabIndex={isDisabled ? undefined : -1}
505
+ aria-haspopup="menu"
506
+ aria-expanded={isOpen}
507
+ aria-controls={isOpen ? contentId : undefined}
508
+ aria-disabled={isDisabled || undefined}
509
+ data-testid={testId}
510
+ onMouseEnter={triggerProps.onMouseEnter}
511
+ onMouseLeave={triggerProps.onMouseLeave}
512
+ onPointerMove={handlePointerMove}
513
+ startContent={
514
+ icon
515
+ ? renderIconSlot(icon, {size: 'sm', color: 'secondary'})
516
+ : undefined
517
+ }
518
+ label={label}
519
+ description={description}
520
+ endContent={endAffordance}
521
+ onClick={handleTriggerClick}
522
+ onKeyDown={handleTriggerKeyDown}
523
+ isDisabled={isDisabled}
524
+ xstyle={[
525
+ triggerStyles.root,
526
+ triggerSizeStyles[menuSize],
527
+ isOpen && triggerStyles.open,
528
+ isDisabled && triggerStyles.disabled,
529
+ xstyle,
530
+ ]}
531
+ {...mergeProps(themeProps('dropdown-menu-item', {size: menuSize}), {
532
+ className,
533
+ style,
534
+ })}
535
+ />
536
+ {layer.render(
537
+ <div
538
+ ref={menuRef}
539
+ id={contentId}
540
+ role="menu"
541
+ // Focusable as a fallback target so an empty/loading flyout (e.g.
542
+ // hasSpinner with only a disabled row) can still receive keyboard
543
+ // focus and own arrow/Escape keys instead of leaving focus on the
544
+ // parent list.
545
+ tabIndex={-1}
546
+ aria-labelledby={triggerId}
547
+ onKeyDown={handleContentKeyDown}
548
+ onMouseEnter={contentProps.onMouseEnter}
549
+ onMouseLeave={contentProps.onMouseLeave}
550
+ data-testid={menuDataTestId}
551
+ {...mergeProps(
552
+ themeProps('dropdown-menu'),
553
+ stylex.props(flyoutStyles.menu),
554
+ )}>
555
+ <DropdownMenuContext value={nestedMenuContext}>
556
+ {children}
557
+ </DropdownMenuContext>
558
+ </div>,
559
+ {
560
+ placement: 'end',
561
+ alignment: 'start',
562
+ xstyle: [popoverXstyle, layerAnimations.end],
563
+ },
564
+ )}
565
+ </>
566
+ );
567
+ }
568
+
569
+ DropdownMenuSubMenu.displayName = 'DropdownMenuSubMenu';
@@ -6,6 +6,15 @@
6
6
  * @file index.ts
7
7
  * @output Exports DropdownMenu, DropdownMenuItem and related types
8
8
  * @position Public API entry point
9
+ *
10
+ * SYNC: The item components below are re-exported (aliased) by the other menu
11
+ * surfaces that reuse the DropdownMenu item pipeline. When you add or remove an
12
+ * item component here, mirror it in:
13
+ * - /packages/core/src/ContextMenu/index.ts (ContextMenu* aliases)
14
+ * - /packages/core/src/Breadcrumbs/index.ts (BreadcrumbMenu* aliases)
15
+ * Those surfaces render menu items through the same renderDropdownItems +
16
+ * DropdownMenuContext + useListFocus path, so a new item type (e.g. a submenu)
17
+ * only shows up in their public API once it's aliased there too.
9
18
  */
10
19
 
11
20
  export {
@@ -34,6 +43,13 @@ export {
34
43
  type DropdownMenuRadioItemProps,
35
44
  } from './DropdownMenuRadioItem';
36
45
 
46
+ // Submenu — a single menu row that reveals a nested flyout of its own
47
+ // children/items. Data mode via DropdownMenuItemData.items.
48
+ export {
49
+ DropdownMenuSubMenu,
50
+ type DropdownMenuSubMenuProps,
51
+ } from './DropdownMenuSubMenu';
52
+
37
53
  // Menu-coordination context — public so consumers can build custom menu items
38
54
  // that read the menu size / close the menu.
39
55
  export {
@@ -0,0 +1,40 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ /**
6
+ * @file menuItemHover.ts
7
+ * @output Exports focusMenuItemOnHover
8
+ * @position Shared helper for DropdownMenu/ContextMenu item components
9
+ *
10
+ * Menus keep a single highlighted item by using DOM focus as the sole
11
+ * highlight source. Mouse hover moves focus onto the pointed-at item so the
12
+ * one focus highlight follows the pointer — instead of a separate `:hover`
13
+ * background leaving the keyboard-focused item highlighted at the same time.
14
+ *
15
+ * SYNC: When modified, update the item components that use it:
16
+ * - /packages/core/src/DropdownMenu/DropdownMenuItem.tsx
17
+ * - /packages/core/src/DropdownMenu/DropdownMenuCheckboxItem.tsx
18
+ * - /packages/core/src/DropdownMenu/DropdownMenuRadioItem.tsx
19
+ * - /packages/core/src/DropdownMenu/DropdownMenuSubMenu.tsx
20
+ */
21
+
22
+ import type {PointerEvent} from 'react';
23
+
24
+ /**
25
+ * Move focus to a menu item as the pointer moves over it, so hover and
26
+ * keyboard navigation share a single focus-driven highlight. Only reacts to a
27
+ * real mouse (not touch/pen, which have no hover), and skips disabled items.
28
+ */
29
+ export function focusMenuItemOnHover(
30
+ e: PointerEvent<HTMLElement>,
31
+ isDisabled?: boolean,
32
+ ): void {
33
+ if (isDisabled || e.pointerType !== 'mouse') {
34
+ return;
35
+ }
36
+ const el = e.currentTarget;
37
+ if (el !== el.ownerDocument.activeElement) {
38
+ el.focus();
39
+ }
40
+ }
@@ -20,3 +20,12 @@ export const MENU_ITEM_ROLES: ReadonlySet<string> = new Set([
20
20
  export const MENU_ITEM_SELECTOR: string = [...MENU_ITEM_ROLES]
21
21
  .map(role => `[role="${role}"]:not([aria-disabled="true"])`)
22
22
  .join(',');
23
+
24
+ /**
25
+ * Boundary selector for a single menu level. A menu and its submenu flyouts
26
+ * both use `role="menu"`, and flyouts render inline (native popover, not a
27
+ * portal), so a nested menu's items and key events would otherwise be picked
28
+ * up by the parent. Pass this as `useListFocus`'s `boundarySelector` so each
29
+ * level scopes item collection and key handling to its own container.
30
+ */
31
+ export const MENU_BOUNDARY_SELECTOR = '[role="menu"]';