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

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 (565) 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/Chat/ChatComposerInput.js +1 -1
  33. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  34. package/dist/Chat/ChatDictationButton.js +3 -1
  35. package/dist/Chat/ChatLayout.js +4 -4
  36. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  37. package/dist/Chat/ChatMessageBubble.js +8 -8
  38. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  39. package/dist/Chat/ChatToolCalls.js +10 -3
  40. package/dist/Chat/useTriggerMenu.js +2 -2
  41. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  42. package/dist/CheckboxInput/CheckboxInput.js +6 -6
  43. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  44. package/dist/CheckboxList/CheckboxListItem.js +19 -4
  45. package/dist/Citation/Citation.d.ts +22 -1
  46. package/dist/Citation/Citation.d.ts.map +1 -1
  47. package/dist/Citation/Citation.js +20 -6
  48. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  49. package/dist/CodeBlock/CodeBlock.js +16 -10
  50. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  51. package/dist/Collapsible/Collapsible.js +3 -1
  52. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  53. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  54. package/dist/CommandPalette/CommandPalette.js +42 -3
  55. package/dist/CommandPalette/CommandPaletteItem.js +1 -1
  56. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  57. package/dist/ContextMenu/ContextMenu.js +23 -5
  58. package/dist/ContextMenu/index.d.ts +1 -0
  59. package/dist/ContextMenu/index.d.ts.map +1 -1
  60. package/dist/ContextMenu/index.js +3 -1
  61. package/dist/DateInput/DateInput.d.ts +10 -2
  62. package/dist/DateInput/DateInput.d.ts.map +1 -1
  63. package/dist/DateInput/DateInput.js +33 -19
  64. package/dist/DateRangeInput/DateRangeInput.d.ts +10 -2
  65. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  66. package/dist/DateRangeInput/DateRangeInput.js +23 -20
  67. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  68. package/dist/DateTimeInput/DateTimeInput.js +23 -18
  69. package/dist/Divider/Divider.d.ts +2 -2
  70. package/dist/Divider/Divider.d.ts.map +1 -1
  71. package/dist/Divider/Divider.js +13 -0
  72. package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
  73. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  74. package/dist/DropdownMenu/DropdownMenu.js +22 -5
  75. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  76. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
  77. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenuItem.js +5 -2
  79. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +8 -11
  80. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  81. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +3 -1
  82. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +1 -1
  83. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuRadioItem.js +5 -2
  85. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
  86. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
  87. package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
  88. package/dist/DropdownMenu/index.d.ts +10 -0
  89. package/dist/DropdownMenu/index.d.ts.map +1 -1
  90. package/dist/DropdownMenu/index.js +13 -0
  91. package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
  92. package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
  93. package/dist/DropdownMenu/menuItemHover.js +33 -0
  94. package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
  95. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
  96. package/dist/DropdownMenu/menuItemRoles.js +10 -1
  97. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  98. package/dist/DropdownMenu/renderDropdownItems.js +21 -6
  99. package/dist/Field/Field.d.ts +3 -1
  100. package/dist/Field/Field.d.ts.map +1 -1
  101. package/dist/Field/Field.js +4 -1
  102. package/dist/Field/FieldLabel.d.ts +2 -1
  103. package/dist/Field/FieldLabel.d.ts.map +1 -1
  104. package/dist/Field/FieldLabel.js +9 -5
  105. package/dist/Field/inputStyles.stylex.d.ts +1 -0
  106. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  107. package/dist/Field/inputStyles.stylex.js +1 -0
  108. package/dist/FieldStatus/FieldStatus.d.ts +10 -0
  109. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  110. package/dist/FieldStatus/FieldStatus.js +51 -5
  111. package/dist/FileInput/FileInput.d.ts +10 -2
  112. package/dist/FileInput/FileInput.d.ts.map +1 -1
  113. package/dist/FileInput/FileInput.js +93 -65
  114. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  115. package/dist/HoverCard/useHoverCard.js +10 -4
  116. package/dist/Icon/Icon.d.ts +15 -1
  117. package/dist/Icon/Icon.d.ts.map +1 -1
  118. package/dist/Icon/Icon.js +19 -3
  119. package/dist/Item/Item.d.ts +16 -3
  120. package/dist/Item/Item.d.ts.map +1 -1
  121. package/dist/Item/Item.js +31 -6
  122. package/dist/Layer/layerAnimations.stylex.d.ts.map +1 -1
  123. package/dist/Layer/layerAnimations.stylex.js +10 -2
  124. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  125. package/dist/Lightbox/Lightbox.js +19 -13
  126. package/dist/List/List.d.ts.map +1 -1
  127. package/dist/List/List.js +6 -3
  128. package/dist/List/ListItem.d.ts +11 -1
  129. package/dist/List/ListItem.d.ts.map +1 -1
  130. package/dist/List/ListItem.js +2 -0
  131. package/dist/Markdown/Markdown.d.ts.map +1 -1
  132. package/dist/Markdown/Markdown.js +7 -0
  133. package/dist/MetadataList/MetadataList.d.ts +1 -1
  134. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  135. package/dist/MetadataList/MetadataList.js +4 -2
  136. package/dist/MultiSelector/MultiSelector.d.ts +9 -1
  137. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  138. package/dist/MultiSelector/MultiSelector.js +80 -42
  139. package/dist/NavMenu/NavHeadingMenuItem.js +1 -1
  140. package/dist/NumberInput/NumberInput.d.ts +10 -2
  141. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  142. package/dist/NumberInput/NumberInput.js +22 -17
  143. package/dist/Outline/Outline.js +2 -2
  144. package/dist/Pagination/Pagination.d.ts.map +1 -1
  145. package/dist/Pagination/Pagination.js +11 -3
  146. package/dist/PowerSearch/PowerSearch.d.ts +9 -2
  147. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  148. package/dist/PowerSearch/PowerSearch.js +2 -0
  149. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  150. package/dist/ProgressBar/ProgressBar.js +6 -1
  151. package/dist/RadioList/RadioList.d.ts +2 -2
  152. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  153. package/dist/RadioList/RadioListItem.js +5 -5
  154. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  155. package/dist/Resizable/ResizeHandle.js +49 -19
  156. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  157. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  158. package/dist/SegmentedControl/SegmentedControlItem.js +5 -3
  159. package/dist/Selector/Selector.d.ts +8 -0
  160. package/dist/Selector/Selector.d.ts.map +1 -1
  161. package/dist/Selector/Selector.js +66 -17
  162. package/dist/SideNav/SideNav.d.ts.map +1 -1
  163. package/dist/SideNav/SideNav.js +5 -5
  164. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  165. package/dist/SideNav/SideNavCollapseButton.js +13 -10
  166. package/dist/SideNav/SideNavItem.d.ts +1 -1
  167. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  168. package/dist/SideNav/SideNavItem.js +12 -10
  169. package/dist/Skeleton/Skeleton.d.ts.map +1 -1
  170. package/dist/Skeleton/Skeleton.js +2 -2
  171. package/dist/Slider/Slider.d.ts.map +1 -1
  172. package/dist/Slider/Slider.js +87 -34
  173. package/dist/Spinner/Spinner.d.ts +3 -2
  174. package/dist/Spinner/Spinner.d.ts.map +1 -1
  175. package/dist/Spinner/Spinner.js +11 -2
  176. package/dist/Switch/Switch.d.ts +8 -1
  177. package/dist/Switch/Switch.d.ts.map +1 -1
  178. package/dist/Switch/Switch.js +171 -91
  179. package/dist/TabList/Tab.js +2 -2
  180. package/dist/TabList/TabList.d.ts +2 -11
  181. package/dist/TabList/TabList.d.ts.map +1 -1
  182. package/dist/TabList/TabList.js +5 -9
  183. package/dist/TabList/TabListContext.d.ts +0 -5
  184. package/dist/TabList/TabListContext.d.ts.map +1 -1
  185. package/dist/TabList/TabListContext.js +0 -5
  186. package/dist/TabList/TabMenu.js +1 -1
  187. package/dist/Table/BaseTable.d.ts.map +1 -1
  188. package/dist/Table/BaseTable.js +30 -4
  189. package/dist/Table/TableCell.js +3 -3
  190. package/dist/Table/TableHeaderCell.js +3 -3
  191. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  192. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
  193. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  194. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +37 -27
  195. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  196. package/dist/Table/plugins/selection/useTableSelection.js +3 -0
  197. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
  198. package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +15 -7
  199. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  200. package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
  201. package/dist/Table/types.d.ts +32 -0
  202. package/dist/Table/types.d.ts.map +1 -1
  203. package/dist/TextArea/TextArea.d.ts +10 -1
  204. package/dist/TextArea/TextArea.d.ts.map +1 -1
  205. package/dist/TextArea/TextArea.js +18 -19
  206. package/dist/TextInput/TextInput.d.ts +10 -2
  207. package/dist/TextInput/TextInput.d.ts.map +1 -1
  208. package/dist/TextInput/TextInput.js +20 -17
  209. package/dist/Thumbnail/Thumbnail.js +2 -2
  210. package/dist/TimeInput/TimeInput.d.ts +10 -2
  211. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  212. package/dist/TimeInput/TimeInput.js +17 -17
  213. package/dist/Timestamp/Timestamp.d.ts +31 -3
  214. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  215. package/dist/Timestamp/Timestamp.js +47 -76
  216. package/dist/Timestamp/formatInstant.d.ts +41 -0
  217. package/dist/Timestamp/formatInstant.d.ts.map +1 -0
  218. package/dist/Timestamp/formatInstant.js +177 -0
  219. package/dist/Timestamp/index.d.ts +1 -0
  220. package/dist/Timestamp/index.d.ts.map +1 -1
  221. package/dist/Timestamp/tooltipEntries.d.ts +56 -0
  222. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
  223. package/dist/Timestamp/tooltipEntries.js +163 -0
  224. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  225. package/dist/Toast/ToastViewport.js +61 -9
  226. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  227. package/dist/ToggleButton/ToggleButton.js +3 -1
  228. package/dist/Token/Token.d.ts +34 -4
  229. package/dist/Token/Token.d.ts.map +1 -1
  230. package/dist/Token/Token.js +85 -45
  231. package/dist/Token/TokenLink.d.ts +62 -0
  232. package/dist/Token/TokenLink.d.ts.map +1 -0
  233. package/dist/Token/TokenLink.js +76 -0
  234. package/dist/Token/index.d.ts +1 -1
  235. package/dist/Token/index.d.ts.map +1 -1
  236. package/dist/Tokenizer/Tokenizer.d.ts +9 -2
  237. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  238. package/dist/Tokenizer/Tokenizer.js +4 -2
  239. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  240. package/dist/Tooltip/useTooltip.js +17 -1
  241. package/dist/TopNav/TopNavItem.d.ts +3 -1
  242. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  243. package/dist/TopNav/TopNavItem.js +30 -3
  244. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  245. package/dist/TopNav/TopNavMegaMenu.js +9 -3
  246. package/dist/TreeList/TreeList.d.ts.map +1 -1
  247. package/dist/TreeList/TreeList.js +1 -0
  248. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  249. package/dist/TreeList/TreeListBranches.js +8 -6
  250. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  251. package/dist/TreeList/TreeListItem.js +32 -14
  252. package/dist/Typeahead/BaseTypeahead.d.ts +9 -0
  253. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  254. package/dist/Typeahead/BaseTypeahead.js +22 -11
  255. package/dist/Typeahead/Typeahead.d.ts +9 -2
  256. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  257. package/dist/Typeahead/Typeahead.js +11 -2
  258. package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
  259. package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
  260. package/dist/Typeahead/TypeaheadItem.js +20 -10
  261. package/dist/astryx.css +74 -33
  262. package/dist/astryx.umd.js +51 -51
  263. package/dist/astryx.umd.js.map +4 -4
  264. package/dist/hooks/index.d.ts +2 -0
  265. package/dist/hooks/index.d.ts.map +1 -1
  266. package/dist/hooks/index.js +1 -0
  267. package/dist/hooks/isRtlElement.d.ts +18 -0
  268. package/dist/hooks/isRtlElement.d.ts.map +1 -0
  269. package/dist/hooks/isRtlElement.js +27 -0
  270. package/dist/hooks/useAnnounce.d.ts +3 -0
  271. package/dist/hooks/useAnnounce.d.ts.map +1 -1
  272. package/dist/hooks/useAnnounce.js +39 -1
  273. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  274. package/dist/hooks/useFocusTrap.js +52 -11
  275. package/dist/hooks/useGridFocus.d.ts +6 -1
  276. package/dist/hooks/useGridFocus.d.ts.map +1 -1
  277. package/dist/hooks/useGridFocus.js +12 -9
  278. package/dist/hooks/useHotkeys.d.ts +9 -0
  279. package/dist/hooks/useHotkeys.d.ts.map +1 -1
  280. package/dist/hooks/useHotkeys.js +9 -0
  281. package/dist/hooks/useInputStatusIcon.d.ts +38 -0
  282. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
  283. package/dist/hooks/useInputStatusIcon.js +169 -0
  284. package/dist/hooks/useKeyboardHint.d.ts +1 -1
  285. package/dist/hooks/useKeyboardHint.d.ts.map +1 -1
  286. package/dist/hooks/useKeyboardHint.js +4 -2
  287. package/dist/hooks/useListFocus.d.ts +39 -1
  288. package/dist/hooks/useListFocus.d.ts.map +1 -1
  289. package/dist/hooks/useListFocus.js +54 -9
  290. package/dist/i18n/InternationalizationContext.d.ts +1 -0
  291. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  292. package/dist/i18n/InternationalizationContext.js +3 -0
  293. package/dist/i18n/InternationalizationProvider.d.ts +8 -1
  294. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
  295. package/dist/i18n/InternationalizationProvider.js +5 -1
  296. package/dist/i18n/getLocaleDirection.d.ts +18 -0
  297. package/dist/i18n/getLocaleDirection.d.ts.map +1 -0
  298. package/dist/i18n/getLocaleDirection.js +29 -0
  299. package/dist/i18n/index.d.ts +6 -0
  300. package/dist/i18n/index.d.ts.map +1 -1
  301. package/dist/i18n/index.js +7 -1
  302. package/dist/i18n/useDirection.d.ts +2 -0
  303. package/dist/i18n/useDirection.d.ts.map +1 -0
  304. package/dist/i18n/useDirection.js +27 -0
  305. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  306. package/dist/theme/derivedVarRegistry.js +13 -0
  307. package/dist/utils/index.d.ts +1 -0
  308. package/dist/utils/index.d.ts.map +1 -1
  309. package/dist/utils/index.js +2 -1
  310. package/dist/utils/plainDate.d.ts +17 -0
  311. package/dist/utils/plainDate.d.ts.map +1 -1
  312. package/dist/utils/plainDate.js +23 -4
  313. package/dist/utils/rtlStyles.d.ts +24 -0
  314. package/dist/utils/rtlStyles.d.ts.map +1 -0
  315. package/dist/utils/rtlStyles.js +27 -0
  316. package/locales/en.json +112 -0
  317. package/locales/pseudo.json +84 -0
  318. package/package.json +6 -1
  319. package/src/Avatar/Avatar.doc.mjs +50 -3
  320. package/src/Avatar/Avatar.test.tsx +218 -0
  321. package/src/Avatar/Avatar.tsx +285 -79
  322. package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
  323. package/src/Avatar/AvatarStatusDot.tsx +6 -4
  324. package/src/AvatarGroup/AvatarGroup.doc.mjs +2 -0
  325. package/src/AvatarGroup/AvatarGroup.test.tsx +162 -2
  326. package/src/AvatarGroup/AvatarGroup.tsx +58 -3
  327. package/src/AvatarGroup/AvatarGroupOverflow.tsx +5 -2
  328. package/src/Banner/Banner.tsx +6 -6
  329. package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
  330. package/src/Breadcrumbs/Breadcrumbs.test.tsx +52 -1
  331. package/src/Breadcrumbs/index.ts +4 -0
  332. package/src/Button/Button.doc.mjs +0 -4
  333. package/src/Button/Button.test.tsx +16 -0
  334. package/src/Button/Button.tsx +6 -4
  335. package/src/Calendar/Calendar.test.tsx +170 -20
  336. package/src/Calendar/Calendar.tsx +73 -16
  337. package/src/Calendar/dayCellUtils.test.ts +18 -18
  338. package/src/Calendar/dayCellUtils.ts +2 -2
  339. package/src/Calendar/styles.ts +33 -39
  340. package/src/Card/Card.tsx +1 -1
  341. package/src/Carousel/Carousel.tsx +25 -6
  342. package/src/Chat/ChatComposer.doc.mjs +2 -2
  343. package/src/Chat/ChatComposerInput.doc.mjs +1 -1
  344. package/src/Chat/ChatComposerInput.tsx +2 -2
  345. package/src/Chat/ChatDictationButton.tsx +7 -1
  346. package/src/Chat/ChatLayout.tsx +4 -4
  347. package/src/Chat/ChatMessageBubble.tsx +15 -10
  348. package/src/Chat/ChatSystemMessage.test.tsx +5 -0
  349. package/src/Chat/ChatToolCalls.tsx +9 -2
  350. package/src/Chat/useTriggerMenu.tsx +1 -1
  351. package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
  352. package/src/CheckboxInput/CheckboxInput.test.tsx +23 -0
  353. package/src/CheckboxInput/CheckboxInput.tsx +21 -6
  354. package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
  355. package/src/CheckboxList/CheckboxList.test.tsx +94 -3
  356. package/src/CheckboxList/CheckboxListItem.tsx +17 -10
  357. package/src/Citation/Citation.doc.mjs +4 -3
  358. package/src/Citation/Citation.test.tsx +97 -0
  359. package/src/Citation/Citation.tsx +43 -11
  360. package/src/CodeBlock/CodeBlock.test.tsx +17 -0
  361. package/src/CodeBlock/CodeBlock.tsx +38 -11
  362. package/src/Collapsible/Collapsible.doc.mjs +1 -0
  363. package/src/Collapsible/Collapsible.test.tsx +7 -0
  364. package/src/Collapsible/Collapsible.tsx +16 -6
  365. package/src/CommandPalette/CommandPalette.test.tsx +95 -1
  366. package/src/CommandPalette/CommandPalette.tsx +41 -2
  367. package/src/CommandPalette/CommandPaletteItem.tsx +1 -1
  368. package/src/ContextMenu/ContextMenu.test.tsx +59 -2
  369. package/src/ContextMenu/ContextMenu.tsx +22 -11
  370. package/src/ContextMenu/index.ts +5 -0
  371. package/src/DateInput/DateInput.doc.mjs +25 -0
  372. package/src/DateInput/DateInput.test.tsx +230 -0
  373. package/src/DateInput/DateInput.tsx +51 -29
  374. package/src/DateRangeInput/DateRangeInput.doc.mjs +16 -0
  375. package/src/DateRangeInput/DateRangeInput.test.tsx +140 -0
  376. package/src/DateRangeInput/DateRangeInput.tsx +42 -30
  377. package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
  378. package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
  379. package/src/DateTimeInput/DateTimeInput.tsx +44 -39
  380. package/src/Divider/Divider.test.tsx +32 -8
  381. package/src/Divider/Divider.tsx +14 -1
  382. package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
  383. package/src/DropdownMenu/DropdownMenu.tsx +31 -12
  384. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
  385. package/src/DropdownMenu/DropdownMenuItem.tsx +9 -3
  386. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +4 -12
  387. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +9 -10
  388. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +9 -3
  389. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +20 -2
  390. package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
  391. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
  392. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
  393. package/src/DropdownMenu/index.ts +16 -0
  394. package/src/DropdownMenu/menuItemHover.ts +39 -0
  395. package/src/DropdownMenu/menuItemRoles.ts +9 -0
  396. package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
  397. package/src/Field/Field.doc.mjs +4 -0
  398. package/src/Field/Field.tsx +14 -9
  399. package/src/Field/FieldLabel.test.tsx +25 -0
  400. package/src/Field/FieldLabel.tsx +12 -3
  401. package/src/Field/inputStyles.stylex.ts +2 -0
  402. package/src/FieldStatus/FieldStatus.doc.mjs +1 -0
  403. package/src/FieldStatus/FieldStatus.test.tsx +133 -0
  404. package/src/FieldStatus/FieldStatus.tsx +61 -4
  405. package/src/FileInput/FileInput.doc.mjs +23 -2
  406. package/src/FileInput/FileInput.test.tsx +104 -13
  407. package/src/FileInput/FileInput.tsx +106 -79
  408. package/src/HoverCard/useHoverCard.tsx +15 -3
  409. package/src/Icon/Icon.doc.mjs +13 -0
  410. package/src/Icon/Icon.test.tsx +89 -0
  411. package/src/Icon/Icon.tsx +51 -3
  412. package/src/Item/Item.doc.mjs +5 -0
  413. package/src/Item/Item.test.tsx +88 -0
  414. package/src/Item/Item.tsx +57 -11
  415. package/src/Layer/layerAnimations.stylex.ts +23 -0
  416. package/src/Lightbox/Lightbox.tsx +15 -7
  417. package/src/List/List.test.tsx +17 -29
  418. package/src/List/List.tsx +6 -1
  419. package/src/List/ListItem.doc.mjs +12 -0
  420. package/src/List/ListItem.tsx +13 -0
  421. package/src/Markdown/Markdown.test.tsx +21 -0
  422. package/src/Markdown/Markdown.tsx +4 -0
  423. package/src/MetadataList/MetadataList.test.tsx +24 -0
  424. package/src/MetadataList/MetadataList.tsx +6 -2
  425. package/src/MultiSelector/MultiSelector.doc.mjs +20 -0
  426. package/src/MultiSelector/MultiSelector.test.tsx +402 -0
  427. package/src/MultiSelector/MultiSelector.tsx +120 -59
  428. package/src/NavMenu/NavHeadingMenuItem.tsx +1 -1
  429. package/src/NumberInput/NumberInput.doc.mjs +21 -0
  430. package/src/NumberInput/NumberInput.test.tsx +71 -0
  431. package/src/NumberInput/NumberInput.tsx +35 -26
  432. package/src/Outline/Outline.test.tsx +12 -12
  433. package/src/Outline/Outline.tsx +2 -2
  434. package/src/Pagination/Pagination.tsx +11 -3
  435. package/src/PowerSearch/PowerSearch.doc.mjs +15 -0
  436. package/src/PowerSearch/PowerSearch.test.tsx +23 -0
  437. package/src/PowerSearch/PowerSearch.tsx +10 -1
  438. package/src/ProgressBar/ProgressBar.test.tsx +34 -0
  439. package/src/ProgressBar/ProgressBar.tsx +16 -1
  440. package/src/RadioList/RadioList.doc.mjs +6 -0
  441. package/src/RadioList/RadioList.test.tsx +26 -4
  442. package/src/RadioList/RadioList.tsx +2 -2
  443. package/src/RadioList/RadioListItem.tsx +12 -5
  444. package/src/Resizable/ResizeHandle.test.tsx +94 -0
  445. package/src/Resizable/ResizeHandle.tsx +70 -20
  446. package/src/SegmentedControl/SegmentedControl.test.tsx +28 -0
  447. package/src/SegmentedControl/SegmentedControlItem.tsx +22 -2
  448. package/src/Selector/Selector.doc.mjs +15 -0
  449. package/src/Selector/Selector.test.tsx +370 -0
  450. package/src/Selector/Selector.tsx +88 -20
  451. package/src/SideNav/SideNav.tsx +1 -8
  452. package/src/SideNav/SideNavCollapseButton.tsx +9 -7
  453. package/src/SideNav/SideNavItem.tsx +5 -3
  454. package/src/Skeleton/Skeleton.test.tsx +16 -0
  455. package/src/Skeleton/Skeleton.tsx +13 -1
  456. package/src/Slider/Slider.doc.mjs +6 -0
  457. package/src/Slider/Slider.test.tsx +240 -12
  458. package/src/Slider/Slider.tsx +96 -23
  459. package/src/Spinner/Spinner.test.tsx +10 -8
  460. package/src/Spinner/Spinner.tsx +15 -5
  461. package/src/Switch/Switch.doc.mjs +142 -42
  462. package/src/Switch/Switch.test.tsx +111 -0
  463. package/src/Switch/Switch.tsx +149 -32
  464. package/src/TabList/Tab.tsx +2 -2
  465. package/src/TabList/TabList.doc.mjs +0 -6
  466. package/src/TabList/TabList.test.tsx +3 -15
  467. package/src/TabList/TabList.tsx +6 -17
  468. package/src/TabList/TabListContext.ts +0 -6
  469. package/src/TabList/TabMenu.tsx +2 -2
  470. package/src/Table/BaseTable.tsx +34 -2
  471. package/src/Table/Table.doc.mjs +11 -0
  472. package/src/Table/Table.test.tsx +85 -0
  473. package/src/Table/TableCell.tsx +3 -3
  474. package/src/Table/TableHeaderCell.tsx +3 -3
  475. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
  476. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +19 -0
  477. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +27 -18
  478. package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
  479. package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
  480. package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +38 -9
  481. package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
  482. package/src/Table/types.ts +33 -0
  483. package/src/Table/useTableRowStatus.doc.mjs +1 -1
  484. package/src/TextArea/TextArea.doc.mjs +21 -0
  485. package/src/TextArea/TextArea.test.tsx +23 -0
  486. package/src/TextArea/TextArea.tsx +27 -26
  487. package/src/TextInput/TextInput.doc.mjs +21 -0
  488. package/src/TextInput/TextInput.test.tsx +150 -0
  489. package/src/TextInput/TextInput.tsx +28 -25
  490. package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
  491. package/src/Thumbnail/Thumbnail.tsx +1 -1
  492. package/src/TimeInput/TimeInput.doc.mjs +21 -0
  493. package/src/TimeInput/TimeInput.test.tsx +23 -0
  494. package/src/TimeInput/TimeInput.tsx +24 -25
  495. package/src/Timestamp/Timestamp.doc.mjs +32 -6
  496. package/src/Timestamp/Timestamp.test.tsx +371 -0
  497. package/src/Timestamp/Timestamp.tsx +96 -93
  498. package/src/Timestamp/formatInstant.ts +218 -0
  499. package/src/Timestamp/index.ts +4 -0
  500. package/src/Timestamp/tooltipEntries.test.ts +552 -0
  501. package/src/Timestamp/tooltipEntries.ts +210 -0
  502. package/src/Toast/ToastViewport.test.tsx +218 -8
  503. package/src/Toast/ToastViewport.tsx +71 -12
  504. package/src/ToggleButton/ToggleButton.test.tsx +24 -0
  505. package/src/ToggleButton/ToggleButton.tsx +19 -1
  506. package/src/Token/Token.test.tsx +166 -15
  507. package/src/Token/Token.tsx +104 -47
  508. package/src/Token/TokenLink.tsx +107 -0
  509. package/src/Token/index.ts +1 -1
  510. package/src/Tokenizer/Tokenizer.doc.mjs +23 -1
  511. package/src/Tokenizer/Tokenizer.test.tsx +23 -0
  512. package/src/Tokenizer/Tokenizer.tsx +14 -2
  513. package/src/Tooltip/Tooltip.test.tsx +46 -0
  514. package/src/Tooltip/useTooltip.tsx +20 -0
  515. package/src/TopNav/TopNav.test.tsx +93 -2
  516. package/src/TopNav/TopNavItem.doc.mjs +3 -3
  517. package/src/TopNav/TopNavItem.tsx +35 -6
  518. package/src/TopNav/TopNavMegaMenu.tsx +26 -2
  519. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
  520. package/src/TreeList/TreeList.doc.mjs +6 -0
  521. package/src/TreeList/TreeList.test.tsx +50 -10
  522. package/src/TreeList/TreeList.tsx +5 -0
  523. package/src/TreeList/TreeListBranches.tsx +8 -6
  524. package/src/TreeList/TreeListItem.tsx +33 -11
  525. package/src/Typeahead/BaseTypeahead.tsx +42 -15
  526. package/src/Typeahead/Typeahead.doc.mjs +13 -0
  527. package/src/Typeahead/Typeahead.test.tsx +112 -0
  528. package/src/Typeahead/Typeahead.tsx +17 -1
  529. package/src/Typeahead/TypeaheadItem.tsx +2 -1
  530. package/src/__tests__/forcedColors.ts +60 -0
  531. package/src/__tests__/inputWidthContract.test.tsx +62 -0
  532. package/src/doc-mjs.d.ts +19 -0
  533. package/src/hooks/index.ts +6 -0
  534. package/src/hooks/isRtlElement.ts +27 -0
  535. package/src/hooks/useAnnounce.test.tsx +75 -2
  536. package/src/hooks/useAnnounce.ts +47 -1
  537. package/src/hooks/useFocusTrap.test.tsx +104 -0
  538. package/src/hooks/useFocusTrap.ts +61 -12
  539. package/src/hooks/useGridFocus.doc.mjs +3 -3
  540. package/src/hooks/useGridFocus.test.tsx +41 -0
  541. package/src/hooks/useGridFocus.ts +21 -10
  542. package/src/hooks/useHotkeys.ts +9 -0
  543. package/src/hooks/useInputStatusIcon.test.tsx +221 -0
  544. package/src/hooks/useInputStatusIcon.tsx +235 -0
  545. package/src/hooks/useKeyboardHint.test.tsx +22 -0
  546. package/src/hooks/useKeyboardHint.tsx +6 -2
  547. package/src/hooks/useListFocus.doc.mjs +25 -3
  548. package/src/hooks/useListFocus.test.tsx +153 -1
  549. package/src/hooks/useListFocus.ts +102 -9
  550. package/src/i18n/InternationalizationContext.ts +4 -0
  551. package/src/i18n/InternationalizationProvider.tsx +12 -2
  552. package/src/i18n/__tests__/getLocaleDirection.test.ts +40 -0
  553. package/src/i18n/__tests__/useDirection.test.tsx +66 -0
  554. package/src/i18n/getLocaleDirection.ts +29 -0
  555. package/src/i18n/index.ts +6 -0
  556. package/src/i18n/useDirection.ts +29 -0
  557. package/src/reset.css +0 -26
  558. package/src/reset.test.ts +60 -0
  559. package/src/theme/derivedVarRegistry.test.ts +1 -0
  560. package/src/theme/derivedVarRegistry.ts +6 -0
  561. package/src/theme/generateThemeRules.test.ts +42 -0
  562. package/src/utils/index.ts +2 -0
  563. package/src/utils/plainDate.test.ts +24 -6
  564. package/src/utils/plainDate.ts +18 -4
  565. package/src/utils/rtlStyles.ts +27 -0
@@ -221,4 +221,50 @@ describe('Tooltip', () => {
221
221
  expect(onOpenChange).not.toHaveBeenCalledWith(false);
222
222
  });
223
223
  });
224
+
225
+ describe('press-to-dismiss', () => {
226
+ it('hides the tooltip when the trigger is pressed', async () => {
227
+ const onOpenChange = vi.fn();
228
+ render(
229
+ <Tooltip content="Copy link" onOpenChange={onOpenChange} delay={0}>
230
+ <button type="button">Trigger</button>
231
+ </Tooltip>,
232
+ );
233
+
234
+ const trigger = screen.getByRole('button', {name: 'Trigger'});
235
+ fireEvent.mouseEnter(trigger);
236
+ await waitFor(() => {
237
+ expect(onOpenChange).toHaveBeenCalledWith(true);
238
+ });
239
+
240
+ fireEvent.pointerDown(trigger);
241
+ await waitFor(() => {
242
+ expect(onOpenChange).toHaveBeenCalledWith(false);
243
+ });
244
+ });
245
+
246
+ it('does not press-dismiss a controlled tooltip', async () => {
247
+ const onOpenChange = vi.fn();
248
+ render(
249
+ <Tooltip
250
+ content="Controlled"
251
+ isOpen
252
+ onOpenChange={onOpenChange}
253
+ delay={0}>
254
+ <button type="button">Trigger</button>
255
+ </Tooltip>,
256
+ );
257
+
258
+ const trigger = screen.getByRole('button', {name: 'Trigger'});
259
+ await waitFor(() => {
260
+ expect(onOpenChange).toHaveBeenCalledWith(true);
261
+ });
262
+ onOpenChange.mockClear();
263
+
264
+ fireEvent.pointerDown(trigger);
265
+ // Give any (incorrect) async hide a chance to run.
266
+ await new Promise(r => setTimeout(r, 20));
267
+ expect(onOpenChange).not.toHaveBeenCalledWith(false);
268
+ });
269
+ });
224
270
  });
@@ -366,6 +366,19 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
366
366
  scheduleHide();
367
367
  }, [scheduleHide]);
368
368
 
369
+ // Pressing the trigger hides its own tooltip: once the control is activated
370
+ // the hint has served its purpose, and a tooltip lingering over a
371
+ // just-pressed control reads as stale. Fires on pointerdown so it feels
372
+ // immediate. Uncontrolled tooltips only — a controlled tooltip's visibility
373
+ // is owned by the consumer. `layer.hide()` self-guards when already closed.
374
+ const handlePointerDown = useCallback(() => {
375
+ if (isOpen !== undefined) {
376
+ return;
377
+ }
378
+ clearTimeouts();
379
+ layer.hide();
380
+ }, [isOpen, clearTimeouts, layer]);
381
+
369
382
  // Interaction ref that handles event listeners only
370
383
  const interactionRef: RefCallback<HTMLElement> = useCallback(
371
384
  (el: HTMLElement | null) => {
@@ -375,12 +388,18 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
375
388
  triggerRef.current.removeEventListener('mouseleave', handleMouseLeave);
376
389
  triggerRef.current.removeEventListener('focusin', handleFocusIn);
377
390
  triggerRef.current.removeEventListener('focusout', handleFocusOut);
391
+ triggerRef.current.removeEventListener(
392
+ 'pointerdown',
393
+ handlePointerDown,
394
+ );
378
395
  }
379
396
 
380
397
  if (el) {
381
398
  // Attach hover listeners
382
399
  el.addEventListener('mouseenter', handleMouseEnter);
383
400
  el.addEventListener('mouseleave', handleMouseLeave);
401
+ // Press-to-dismiss: activating the trigger hides its own tooltip.
402
+ el.addEventListener('pointerdown', handlePointerDown);
384
403
 
385
404
  // Attach focus listeners based on focusTrigger option
386
405
  const shouldAttachFocus =
@@ -401,6 +420,7 @@ export function useTooltip(options: TooltipOptions = {}): TooltipReturn {
401
420
  handleMouseLeave,
402
421
  handleFocusIn,
403
422
  handleFocusOut,
423
+ handlePointerDown,
404
424
  ],
405
425
  );
406
426
 
@@ -420,12 +420,103 @@ describe('TopNavItem', () => {
420
420
 
421
421
  it('applies aria-disabled when isDisabled', () => {
422
422
  render(<TopNavItem label="Home" href="#" isDisabled />);
423
- expect(screen.getByRole('link')).toHaveAttribute('aria-disabled', 'true');
423
+ expect(screen.getByText('Home').closest('a')).toHaveAttribute(
424
+ 'aria-disabled',
425
+ 'true',
426
+ );
424
427
  });
425
428
 
426
429
  it('sets tabIndex to -1 when disabled', () => {
427
430
  render(<TopNavItem label="Home" href="#" isDisabled />);
428
- expect(screen.getByRole('link')).toHaveAttribute('tabIndex', '-1');
431
+ expect(screen.getByText('Home').closest('a')).toHaveAttribute(
432
+ 'tabIndex',
433
+ '-1',
434
+ );
435
+ });
436
+
437
+ describe('disabled items do not navigate', () => {
438
+ it('drops href/target and suppresses clicks when disabled (default mode)', () => {
439
+ const handleClick = vi.fn();
440
+ render(
441
+ <TopNavItem
442
+ label="Home"
443
+ href="/home"
444
+ target="_blank"
445
+ onClick={handleClick}
446
+ isDisabled
447
+ />,
448
+ );
449
+ // An href-less anchor exposes no link role, so it is not announced
450
+ // with a live destination.
451
+ expect(screen.queryByRole('link')).not.toBeInTheDocument();
452
+ const item = screen.getByText('Home').closest('a') as HTMLAnchorElement;
453
+ expect(item).not.toHaveAttribute('href');
454
+ expect(item).not.toHaveAttribute('target');
455
+ expect(item).toHaveAttribute('aria-disabled', 'true');
456
+ expect(item).toHaveAttribute('tabIndex', '-1');
457
+
458
+ // fireEvent bypasses pointer-events: none, simulating programmatic/AT
459
+ // activation. It returns false when preventDefault was called, i.e.
460
+ // any default navigation behavior is cancelled.
461
+ const notCancelled = fireEvent.click(item);
462
+ expect(notCancelled).toBe(false);
463
+ expect(handleClick).not.toHaveBeenCalled();
464
+ });
465
+
466
+ it('drops href/target and suppresses clicks when disabled (drawer mode)', () => {
467
+ const handleClick = vi.fn();
468
+ render(
469
+ <TopNavRenderContext value="drawer">
470
+ <TopNavItem
471
+ label="Home"
472
+ href="/home"
473
+ target="_blank"
474
+ onClick={handleClick}
475
+ isDisabled
476
+ />
477
+ </TopNavRenderContext>,
478
+ );
479
+ expect(screen.queryByRole('link')).not.toBeInTheDocument();
480
+ const item = screen.getByText('Home').closest('a') as HTMLAnchorElement;
481
+ expect(item).not.toHaveAttribute('href');
482
+ expect(item).not.toHaveAttribute('target');
483
+ expect(item).toHaveAttribute('aria-disabled', 'true');
484
+ expect(item).toHaveAttribute('tabIndex', '-1');
485
+
486
+ // fireEvent bypasses pointer-events: none, simulating programmatic/AT
487
+ // activation. It returns false when preventDefault was called.
488
+ const notCancelled = fireEvent.click(item);
489
+ expect(notCancelled).toBe(false);
490
+ expect(handleClick).not.toHaveBeenCalled();
491
+ });
492
+
493
+ it('keeps href and click behavior for enabled items (default mode)', async () => {
494
+ const user = userEvent.setup();
495
+ const handleClick = vi.fn();
496
+ render(<TopNavItem label="Home" href="#" onClick={handleClick} />);
497
+ const link = screen.getByRole('link', {name: 'Home'});
498
+ expect(link).toHaveAttribute('href', '#');
499
+ expect(link).not.toHaveAttribute('aria-disabled');
500
+
501
+ await user.click(link);
502
+ expect(handleClick).toHaveBeenCalledTimes(1);
503
+ });
504
+
505
+ it('keeps href and click behavior for enabled items (drawer mode)', async () => {
506
+ const user = userEvent.setup();
507
+ const handleClick = vi.fn();
508
+ render(
509
+ <TopNavRenderContext value="drawer">
510
+ <TopNavItem label="Home" href="#" onClick={handleClick} />
511
+ </TopNavRenderContext>,
512
+ );
513
+ const link = screen.getByRole('link', {name: 'Home'});
514
+ expect(link).toHaveAttribute('href', '#');
515
+ expect(link).not.toHaveAttribute('aria-disabled');
516
+
517
+ await user.click(link);
518
+ expect(handleClick).toHaveBeenCalledTimes(1);
519
+ });
429
520
  });
430
521
 
431
522
  it('renders icon with label', () => {
@@ -29,7 +29,7 @@ export const docs = {
29
29
  {
30
30
  name: 'isDisabled',
31
31
  type: 'boolean',
32
- description: 'Whether the nav item is disabled. Sets aria-disabled and prevents interaction.',
32
+ description: 'Whether the nav item is disabled. Sets aria-disabled, drops href/target so the item cannot navigate, and prevents interaction.',
33
33
  default: 'false',
34
34
  },
35
35
  {
@@ -91,7 +91,7 @@ export const docsZh = {
91
91
  {
92
92
  name: 'isDisabled',
93
93
  type: 'boolean',
94
- description: '导航项是否被禁用。设置 aria-disabled 并阻止交互。',
94
+ description: '导航项是否被禁用。设置 aria-disabled,移除 href/target 使其无法导航,并阻止交互。',
95
95
  default: 'false',
96
96
  },
97
97
  {
@@ -121,7 +121,7 @@ export const docsDense = {
121
121
  label: 'Visible text or aria-label when isIconOnly is true.',
122
122
  href: 'Navigation URL.',
123
123
  isSelected: 'Sets aria-current="page"+highlighted styles.',
124
- isDisabled: 'Sets aria-disabled, prevents interaction.',
124
+ isDisabled: 'Sets aria-disabled, drops href/target (no navigation), prevents interaction.',
125
125
  icon: 'Icon before label.',
126
126
  children: 'Custom content instead of label text.',
127
127
  as: 'Custom link component. Overrides LinkProvider default. Must accept href, className, style, children.',
@@ -131,6 +131,8 @@ export interface TopNavItemProps extends BaseProps<HTMLAnchorElement> {
131
131
  isSelected?: boolean;
132
132
  /**
133
133
  * Whether the nav item is disabled.
134
+ * A disabled item renders as a plain anchor without an href (and without
135
+ * target), so it cannot navigate and is removed from the tab order.
134
136
  * @default false
135
137
  */
136
138
  isDisabled?: boolean;
@@ -157,6 +159,15 @@ export interface TopNavItemProps extends BaseProps<HTMLAnchorElement> {
157
159
  size?: NavItemSize;
158
160
  }
159
161
 
162
+ /**
163
+ * Click handler for disabled items. The disabled anchor renders without an
164
+ * href, so there is no navigation to block in practice; preventDefault is a
165
+ * defensive guard against synthetic/programmatic clicks.
166
+ */
167
+ function preventDefaultClick(event: React.MouseEvent<HTMLAnchorElement>): void {
168
+ event.preventDefault();
169
+ }
170
+
160
171
  /**
161
172
  * A navigation item for use within TopNav startContent.
162
173
  *
@@ -178,6 +189,9 @@ export interface TopNavItemProps extends BaseProps<HTMLAnchorElement> {
178
189
  */
179
190
  export function TopNavItem({
180
191
  as,
192
+ href,
193
+ target,
194
+ onClick,
181
195
  label,
182
196
  isSelected = false,
183
197
  isDisabled = false,
@@ -195,22 +209,34 @@ export function TopNavItem({
195
209
  const renderMode = useTopNavRenderMode();
196
210
  const {closeMobileNav} = useAppShellMobile();
197
211
 
212
+ // A disabled item renders as a plain <a> with no href: an href-less anchor
213
+ // is not focusable and exposes no link affordance, so programmatic focus +
214
+ // Enter, AT activation commands, and middle-click cannot navigate or fire
215
+ // the consumer onClick. The router LinkComponent is deliberately skipped —
216
+ // a disabled item performs no navigation, and custom router links may
217
+ // require a live href. target is omitted with the href. (Mirrors the
218
+ // disabled paths of Link and SideNavItem.)
219
+ const Root = isDisabled ? 'a' : LinkComponent;
220
+
198
221
  // =========================================================================
199
222
  // Drawer mode — render as a SideNavItem-style vertical list element
200
223
  // =========================================================================
201
224
  if (renderMode === 'drawer') {
202
- const handleDrawerClick = (e: React.MouseEvent) => {
225
+ const handleDrawerClick = (e: React.MouseEvent<HTMLAnchorElement>) => {
203
226
  if (isDisabled) {
227
+ preventDefaultClick(e);
204
228
  return;
205
229
  }
206
230
  // Forward the original onClick if present
207
- (props as {onClick?: (e: React.MouseEvent) => void}).onClick?.(e);
231
+ onClick?.(e);
208
232
  closeMobileNav();
209
233
  };
210
234
 
211
235
  return (
212
- <LinkComponent
236
+ <Root
213
237
  ref={ref}
238
+ href={isDisabled ? undefined : href}
239
+ target={isDisabled ? undefined : target}
214
240
  aria-label={isIconOnly ? label : undefined}
215
241
  aria-current={isSelected ? 'page' : undefined}
216
242
  aria-disabled={isDisabled || undefined}
@@ -235,7 +261,7 @@ export function TopNavItem({
235
261
  onClick={handleDrawerClick}>
236
262
  {icon}
237
263
  {!isIconOnly && (children ?? label)}
238
- </LinkComponent>
264
+ </Root>
239
265
  );
240
266
  }
241
267
 
@@ -244,8 +270,11 @@ export function TopNavItem({
244
270
  // =========================================================================
245
271
 
246
272
  return (
247
- <LinkComponent
273
+ <Root
248
274
  ref={ref}
275
+ href={isDisabled ? undefined : href}
276
+ target={isDisabled ? undefined : target}
277
+ onClick={isDisabled ? preventDefaultClick : onClick}
249
278
  aria-label={isIconOnly ? label : undefined}
250
279
  aria-current={isSelected ? 'page' : undefined}
251
280
  aria-disabled={isDisabled || undefined}
@@ -267,7 +296,7 @@ export function TopNavItem({
267
296
  {...props}>
268
297
  {icon}
269
298
  {!isIconOnly && (children ?? label)}
270
- </LinkComponent>
299
+ </Root>
271
300
  );
272
301
  }
273
302
 
@@ -123,6 +123,18 @@ const styles = stylex.create({
123
123
  transform: 'translateY(-4px)',
124
124
  },
125
125
  },
126
+ // Clamp the anchored layer to the space available below the nav so a tall
127
+ // menu never runs off the bottom of the viewport. The layer is positioned
128
+ // with position-area: self-block-end, so its containing block spans from
129
+ // the nav's block-end to the viewport edge — 100% is exactly that space.
130
+ // The layer is a flex column so panelContainer can shrink and scroll its
131
+ // own content, keeping the surface radius/shadow static at the edges.
132
+ // Internal scroll is a stopgap until the mobile bottom-sheet lands.
133
+ panelViewportFit: {
134
+ display: 'flex',
135
+ flexDirection: 'column',
136
+ maxHeight: `calc(100% - ${spacingVars['--spacing-3']})`,
137
+ },
126
138
  // Visual styles for the panel content container.
127
139
  panelContainer: {
128
140
  backgroundColor: colorVars['--color-background-popover'],
@@ -132,6 +144,11 @@ const styles = stylex.create({
132
144
  borderRadius: radiusVars['--radius-container'],
133
145
  boxShadow: shadowVars['--shadow-low'],
134
146
  overflow: 'hidden',
147
+ // Allow the container to shrink inside the height-clamped layer so its
148
+ // content (panelContent) can scroll rather than overflow the viewport.
149
+ display: 'flex',
150
+ flexDirection: 'column',
151
+ minHeight: 0,
135
152
  },
136
153
  panelContent: {
137
154
  display: 'flex',
@@ -139,7 +156,14 @@ const styles = stylex.create({
139
156
  gap: spacingVars['--spacing-6'],
140
157
  paddingBlock: spacingVars['--spacing-3'],
141
158
  paddingInline: spacingVars['--spacing-3'],
142
- maxWidth: 960,
159
+ // Clamp to the viewport (minus a gutter) so the anchored panel never
160
+ // overflows the screen edge on narrow viewports; caps at 960px otherwise.
161
+ maxWidth: `min(960px, calc(100dvw - ${spacingVars['--spacing-4']}))`,
162
+ boxSizing: 'border-box',
163
+ // Scroll internally when the menu is taller than the available space
164
+ // below the nav (paired with panelViewportFit on the layer).
165
+ overflowY: 'auto',
166
+ overscrollBehavior: 'contain',
143
167
  },
144
168
  menuWrapper: {
145
169
  flexGrow: 2,
@@ -484,7 +508,7 @@ function DefaultMegaMenu({
484
508
  {
485
509
  placement: 'below',
486
510
  alignment: slot,
487
- xstyle: styles.panelAnimation,
511
+ xstyle: [styles.panelAnimation, styles.panelViewportFit],
488
512
  },
489
513
  )}
490
514
  </>
@@ -27,7 +27,7 @@ export const docs = {
27
27
  {
28
28
  name: 'imageAlt',
29
29
  type: 'string',
30
- description: 'Alt text for the image. When omitted, the image is explicitly decorative (alt="", role="presentation", aria-hidden) — usually correct since the card already has a visible title. Provide it only when the image conveys information beyond the title and description.',
30
+ description: 'Alt text for the image. When omitted, the image is explicitly decorative (alt="", role="presentation", aria-hidden), usually correct since the card already has a visible title. Provide it only when the image conveys information beyond the title and description.',
31
31
  },
32
32
  {
33
33
  name: 'linkLabel',
@@ -30,6 +30,9 @@ export const docs = {
30
30
  {className: 'astryx-tree-list-item-label', states: ['selected']},
31
31
  {className: 'astryx-tree-list-guide'},
32
32
  ],
33
+ vars: [
34
+ {name: '--tree-list-indent', description: 'Per-level indentation step. Each nesting level indents its rows by this distance, and the guide lines follow it so they stay aligned. Set it on the `tree-list` target to retune the metric (e.g. `var(--spacing-5)` for a wider indent).', default: 'var(--spacing-4)'},
35
+ ],
33
36
  },
34
37
  components: [
35
38
  {
@@ -104,6 +107,9 @@ export const docsZh = {
104
107
  {className: 'astryx-tree-list-item-label', states: ['selected']},
105
108
  {className: 'astryx-tree-list-guide'},
106
109
  ],
110
+ vars: [
111
+ {name: '--tree-list-indent', description: '每级缩进步长。每个嵌套层级的行按此距离缩进,引导线随之对齐。在 `tree-list` 目标上设置以调整该度量(例如用 `var(--spacing-5)` 获得更宽的缩进)。', default: 'var(--spacing-4)'},
112
+ ],
107
113
  },
108
114
  components: [
109
115
  {
@@ -431,26 +431,29 @@ describe('TreeList', () => {
431
431
  });
432
432
 
433
433
  it("variant='noGuides' preserves per-level indentation on the rows", () => {
434
- // Indentation lives on the row's marginLeft (not the guide element), so
435
- // it must survive when the connectors are suppressed. A deeper row is
436
- // indented more than a shallower one.
434
+ // Indentation lives on the row's margin-inline-start (not the guide
435
+ // element), so it must survive when the connectors are suppressed. The
436
+ // per-row distance is published as the `--_tree-indent` custom property
437
+ // (not an inline longhand — see #4308), so the theme layer can override
438
+ // the `margin-inline-start` declaration. A deeper row is indented more
439
+ // than a shallower one.
437
440
  const {container} = render(
438
441
  <TreeList items={deepItems} variant="noGuides" />,
439
442
  );
440
- const marginOf = (text: string): string => {
443
+ const indentOf = (text: string): string => {
441
444
  const li = screen.getByText(text).closest('li')!;
442
- const styled = li.querySelector('[style*="margin-left"]');
445
+ const styled = li.querySelector('[style*="--_tree-indent"]');
443
446
  return styled?.getAttribute('style') ?? '';
444
447
  };
445
448
  // Guides are gone…
446
449
  expect(container.querySelector('.astryx-tree-list-guide')).toBeNull();
447
- // …but each level still carries an inline margin-left, and the level
450
+ // …but each level still publishes an indent distance, and the level
448
451
  // multiplier grows with depth (0, 1, 2).
449
- expect(marginOf('Root')).toContain('margin-left');
450
- expect(marginOf('Mid')).toContain('margin-left');
451
- expect(marginOf('Leaf')).toContain('margin-left');
452
+ expect(indentOf('Root')).toContain('--_tree-indent');
453
+ expect(indentOf('Mid')).toContain('--_tree-indent');
454
+ expect(indentOf('Leaf')).toContain('--_tree-indent');
452
455
  const level = (text: string): number => {
453
- const m = /calc\((\d+)/.exec(marginOf(text));
456
+ const m = /calc\((\d+)/.exec(indentOf(text));
454
457
  return m ? Number(m[1]) : NaN;
455
458
  };
456
459
  expect(level('Mid')).toBeGreaterThan(level('Root'));
@@ -504,6 +507,43 @@ describe('TreeList', () => {
504
507
  });
505
508
  });
506
509
 
510
+ // ===========================================================================
511
+ // Indent lever (--tree-list-indent)
512
+ // ===========================================================================
513
+
514
+ describe('indent lever', () => {
515
+ it('lets a theme retune the indent step via the tree-list target', () => {
516
+ // The per-level step is a public, themeable var (default --spacing-4) set
517
+ // on the tree-list root, so a theme can retune the indent metric (e.g. to
518
+ // --spacing-5) via defineTheme. jsdom cannot resolve the @layer cascade,
519
+ // so the generated CSS is what proves the override reaches the lever.
520
+ const theme = defineTheme({
521
+ name: 'tree-list-indent-test',
522
+ components: {
523
+ 'tree-list': {
524
+ base: {'--tree-list-indent': 'var(--spacing-5)'},
525
+ },
526
+ },
527
+ });
528
+ const css = generateThemeCSSFlat(theme);
529
+ expect(css).toContain('.astryx-tree-list {');
530
+ expect(css).toContain('--tree-list-indent: var(--spacing-5)');
531
+ });
532
+
533
+ it('rows consume the indent step in their published indent distance', () => {
534
+ // Each row's --_tree-indent is calc(level * var(--tree-list-indent)),
535
+ // so retuning the step scales every level uniformly.
536
+ render(<TreeList items={deepItems} variant="noGuides" />);
537
+ const indentOf = (text: string): string => {
538
+ const li = screen.getByText(text).closest('li')!;
539
+ const styled = li.querySelector('[style*="--_tree-indent"]');
540
+ return styled?.getAttribute('style') ?? '';
541
+ };
542
+ expect(indentOf('Mid')).toContain('var(--tree-list-indent)');
543
+ expect(indentOf('Leaf')).toContain('var(--tree-list-indent)');
544
+ });
545
+ });
546
+
507
547
  // ===========================================================================
508
548
  // xds class name
509
549
  // ===========================================================================
@@ -83,6 +83,11 @@ export interface TreeListProps extends BaseProps<HTMLDivElement> {
83
83
  const styles = stylex.create({
84
84
  root: {
85
85
  position: 'relative',
86
+ // Per-level indentation step. Public, themeable lever: a theme can retune
87
+ // the tree's indent metric (e.g. to `var(--spacing-5)`) via `defineTheme`
88
+ // on the `tree-list` target, and both the row margins (TreeListItem) and
89
+ // the guide-line offsets (TreeListBranches) read it so they stay aligned.
90
+ '--tree-list-indent': spacingVars['--spacing-4'],
86
91
  },
87
92
  list: {
88
93
  margin: 0,
@@ -26,8 +26,10 @@ const LINE_WIDTH = 1;
26
26
  */
27
27
  const BRANCH_MARGIN = `calc(${spacingVars['--spacing-2']} + ${spacingVars['--spacing-0-5']})`;
28
28
 
29
- /** Per-level indent width, matching --spacing-4 (16px). */
30
- const LEVEL_INDENT = spacingVars['--spacing-4'];
29
+ /** Per-level indent width. Reads the public, themeable `--tree-list-indent`
30
+ * lever set on the tree-list root (default `--spacing-4`, 16px), so the guide
31
+ * lines stay aligned with the row indent when a theme retunes the step. */
32
+ const LEVEL_INDENT = 'var(--tree-list-indent)';
31
33
 
32
34
  const styles = stylex.create({
33
35
  container: {
@@ -37,10 +39,10 @@ const styles = stylex.create({
37
39
  },
38
40
  verticalLine: {
39
41
  borderRadius: 1,
40
- left: 0,
42
+ insetInlineStart: 0,
41
43
  margin: 'auto',
42
44
  position: 'absolute',
43
- right: 0,
45
+ insetInlineEnd: 0,
44
46
  width: LINE_WIDTH,
45
47
  backgroundColor: colorVars['--color-border-emphasized'],
46
48
  },
@@ -92,7 +94,7 @@ export function TreeListBranches({
92
94
  key={level}
93
95
  {...mergeProps(stylex.props(styles.container), {
94
96
  style: {
95
- left: branchOffset,
97
+ insetInlineStart: branchOffset,
96
98
  },
97
99
  })}>
98
100
  <div
@@ -109,7 +111,7 @@ export function TreeListBranches({
109
111
  <div
110
112
  {...mergeProps(stylex.props(styles.container), {
111
113
  style: {
112
- left: `calc(${BRANCH_MARGIN} + ${nestedLevel - 1} * ${LEVEL_INDENT})`,
114
+ insetInlineStart: `calc(${BRANCH_MARGIN} + ${nestedLevel - 1} * ${LEVEL_INDENT})`,
113
115
  },
114
116
  })}>
115
117
  <div
@@ -25,7 +25,7 @@ import {
25
25
  typeScaleVars,
26
26
  } from '../theme/tokens.stylex';
27
27
  import {getIcon} from '../Icon/globalIconRegistry';
28
- import {mergeProps} from '../utils';
28
+ import {mergeProps, rtlStyles} from '../utils';
29
29
  import {useLinkComponent} from '../Link/useLinkComponent';
30
30
  import {TreeListBranches} from './TreeListBranches';
31
31
  import type {TreeListDensity, TreeListVariant} from './TreeListTypes';
@@ -82,6 +82,12 @@ const styles = stylex.create({
82
82
  position: 'relative',
83
83
  boxSizing: 'border-box',
84
84
  textAlign: 'start',
85
+ // Per-level indent. Declared here (not inline) so it lives in
86
+ // `@layer astryx-base` and the theme layer can override it in normal
87
+ // cascade order — an inline longhand would outrank every layer. The row
88
+ // publishes only the computed distance as `--_tree-indent`; the per-level
89
+ // step is the public `--tree-list-indent` lever (see TreeList `root`).
90
+ marginInlineStart: 'var(--_tree-indent, 0px)',
85
91
  },
86
92
  interactive: {
87
93
  cursor: 'pointer',
@@ -246,6 +252,11 @@ const descriptionSizeStyles = stylex.create({
246
252
  },
247
253
  });
248
254
 
255
+ // `CSSProperties` has no index signature for custom properties, so the row's
256
+ // inline style — which publishes the computed indent distance as the private
257
+ // `--_tree-indent` — needs this augmentation to typecheck.
258
+ type IndentStyle = React.CSSProperties & Record<'--_tree-indent', string>;
259
+
249
260
  // =============================================================================
250
261
  // Types
251
262
  // =============================================================================
@@ -353,9 +364,18 @@ export function TreeListItem({
353
364
  return undefined;
354
365
  }, [onClick, hasChildren, onToggle, id, isDisabled]);
355
366
 
356
- const computedMarginLeft = hasChildren
357
- ? `calc(${nestedLevel} * ${spacingVars['--spacing-4']})`
358
- : `calc(${nestedLevel} * ${spacingVars['--spacing-4']} + ${spacingVars['--spacing-4']} + ${spacingVars['--spacing-2']})`;
367
+ // Per-level indent distance. The per-level step is the public, themeable
368
+ // `--tree-list-indent` lever (default `--spacing-4`, set on the tree-list
369
+ // root). Leaves add a fixed chevron-column offset (chevron width + gap) so
370
+ // their labels line up with sibling parents' labels; that offset is tied to
371
+ // the chevron's own dimensions, not the indent step, so it does not scale
372
+ // with the lever. Published as the private `--_tree-indent` and consumed by
373
+ // `contentWrapper`'s stylesheet `margin-inline-start` (kept out of the inline
374
+ // style so the theme layer can override it — see #4308).
375
+ const indentDistance = hasChildren
376
+ ? `calc(${nestedLevel} * var(--tree-list-indent))`
377
+ : `calc(${nestedLevel} * var(--tree-list-indent) + ${spacingVars['--spacing-4']} + ${spacingVars['--spacing-2']})`;
378
+ const indentStyle: IndentStyle = {'--_tree-indent': indentDistance};
359
379
 
360
380
  const labelAndDescription = (
361
381
  <>
@@ -386,12 +406,14 @@ export function TreeListItem({
386
406
  );
387
407
 
388
408
  const chevronIcon = (
389
- <span
390
- {...stylex.props(
391
- styles.chevronSvg,
392
- isExpanded ? styles.chevronExpanded : styles.chevronCollapsed,
393
- )}>
394
- {getIcon('chevronRight')}
409
+ <span {...stylex.props(rtlStyles.mirror)}>
410
+ <span
411
+ {...stylex.props(
412
+ styles.chevronSvg,
413
+ isExpanded ? styles.chevronExpanded : styles.chevronCollapsed,
414
+ )}>
415
+ {getIcon('chevronRight')}
416
+ </span>
395
417
  </span>
396
418
  );
397
419
 
@@ -527,7 +549,7 @@ export function TreeListItem({
527
549
  isSelected && styles.selected,
528
550
  ),
529
551
  )}
530
- style={{marginLeft: computedMarginLeft}}
552
+ style={indentStyle}
531
553
  onClick={handleClick}>
532
554
  {innerContent}
533
555
  </div>