@astryxdesign/core 0.1.7 → 0.1.8-canary.0c4d8d7

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 (428) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +30 -19
  3. package/dist/AppShell/AppShell.d.ts.map +1 -1
  4. package/dist/AppShell/AppShell.js +6 -2
  5. package/dist/AppShell/AppShellMobileContext.d.ts +8 -0
  6. package/dist/AppShell/AppShellMobileContext.d.ts.map +1 -1
  7. package/dist/Avatar/Avatar.d.ts +10 -5
  8. package/dist/Avatar/Avatar.d.ts.map +1 -1
  9. package/dist/Avatar/Avatar.js +12 -8
  10. package/dist/Avatar/AvatarSizeContext.d.ts +1 -1
  11. package/dist/Avatar/AvatarSizeContext.js +1 -1
  12. package/dist/Avatar/AvatarStatusDot.d.ts +2 -2
  13. package/dist/Avatar/AvatarStatusDot.js +2 -2
  14. package/dist/AvatarGroup/AvatarGroup.d.ts +2 -2
  15. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  16. package/dist/AvatarGroup/AvatarGroup.js +2 -2
  17. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
  18. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  19. package/dist/AvatarGroup/AvatarGroupOverflow.js +16 -14
  20. package/dist/Banner/Banner.d.ts +9 -1
  21. package/dist/Banner/Banner.d.ts.map +1 -1
  22. package/dist/Banner/Banner.js +31 -2
  23. package/dist/Button/Button.d.ts +8 -2
  24. package/dist/Button/Button.d.ts.map +1 -1
  25. package/dist/Button/Button.js +31 -2
  26. package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
  27. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  28. package/dist/ButtonGroup/ButtonGroup.js +30 -1
  29. package/dist/Card/Card.d.ts +8 -2
  30. package/dist/Card/Card.d.ts.map +1 -1
  31. package/dist/Card/Card.js +28 -2
  32. package/dist/Carousel/Carousel.d.ts +6 -2
  33. package/dist/Carousel/Carousel.d.ts.map +1 -1
  34. package/dist/Carousel/Carousel.js +55 -5
  35. package/dist/Chat/ChatComposer.d.ts +8 -0
  36. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  37. package/dist/Chat/ChatComposer.js +31 -6
  38. package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
  39. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  40. package/dist/Chat/ChatComposerDrawer.js +11 -1
  41. package/dist/Chat/ChatComposerInput.d.ts +20 -3
  42. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  43. package/dist/Chat/ChatComposerInput.js +19 -3
  44. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  45. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  46. package/dist/Chat/ChatMessage.d.ts +1 -1
  47. package/dist/Chat/ChatMessage.d.ts.map +1 -1
  48. package/dist/Chat/ChatMessage.js +1 -1
  49. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  50. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  51. package/dist/Chat/ChatToolCalls.d.ts +5 -1
  52. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  53. package/dist/Chat/ChatToolCalls.js +12 -3
  54. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  55. package/dist/Citation/Citation.d.ts.map +1 -1
  56. package/dist/Citation/Citation.js +10 -4
  57. package/dist/ClickableCard/ClickableCard.d.ts +9 -2
  58. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  59. package/dist/ClickableCard/ClickableCard.js +3 -0
  60. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  61. package/dist/CodeBlock/CodeBlock.js +8 -1
  62. package/dist/Collapsible/Collapsible.d.ts +11 -1
  63. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  64. package/dist/Collapsible/Collapsible.js +36 -4
  65. package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
  66. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  67. package/dist/CommandPalette/CommandPaletteInput.js +6 -1
  68. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  69. package/dist/ContextMenu/ContextMenu.js +4 -3
  70. package/dist/ContextMenu/index.d.ts +3 -0
  71. package/dist/ContextMenu/index.d.ts.map +1 -1
  72. package/dist/ContextMenu/index.js +7 -1
  73. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  74. package/dist/DateTimeInput/DateTimeInput.js +10 -1
  75. package/dist/Dialog/Dialog.d.ts.map +1 -1
  76. package/dist/Dialog/Dialog.js +2 -1
  77. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenu.js +8 -4
  79. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +88 -0
  80. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -0
  81. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +169 -0
  82. package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -1
  83. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuContext.js +18 -0
  85. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +68 -0
  86. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -0
  87. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +69 -0
  88. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +69 -0
  89. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -0
  90. package/dist/DropdownMenu/DropdownMenuRadioItem.js +178 -0
  91. package/dist/DropdownMenu/index.d.ts +5 -1
  92. package/dist/DropdownMenu/index.d.ts.map +1 -1
  93. package/dist/DropdownMenu/index.js +10 -1
  94. package/dist/DropdownMenu/menuItemRoles.d.ts +13 -0
  95. package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -0
  96. package/dist/DropdownMenu/menuItemRoles.js +15 -0
  97. package/dist/FieldStatus/FieldStatus.d.ts +8 -0
  98. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  99. package/dist/FieldStatus/FieldStatus.js +22 -4
  100. package/dist/FileInput/FileInput.d.ts.map +1 -1
  101. package/dist/FileInput/FileInput.js +10 -2
  102. package/dist/HoverCard/HoverCard.d.ts +9 -1
  103. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  104. package/dist/HoverCard/HoverCard.js +2 -0
  105. package/dist/HoverCard/useHoverCard.d.ts +8 -0
  106. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  107. package/dist/HoverCard/useHoverCard.js +7 -2
  108. package/dist/Icon/Icon.d.ts +43 -13
  109. package/dist/Icon/Icon.d.ts.map +1 -1
  110. package/dist/Icon/Icon.js +62 -27
  111. package/dist/Layer/useLayer.d.ts +6 -0
  112. package/dist/Layer/useLayer.d.ts.map +1 -1
  113. package/dist/Layer/useLayer.js +2 -0
  114. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  115. package/dist/MobileNav/MobileNav.js +6 -1
  116. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  117. package/dist/MobileNav/MobileNavToggle.js +4 -0
  118. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  119. package/dist/MultiSelector/MultiSelector.js +39 -12
  120. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  121. package/dist/MultiSelector/hooks.js +16 -0
  122. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  123. package/dist/Outline/Outline.d.ts +68 -3
  124. package/dist/Outline/Outline.d.ts.map +1 -1
  125. package/dist/Outline/Outline.js +128 -26
  126. package/dist/Outline/useScrollSpy.d.ts +27 -7
  127. package/dist/Outline/useScrollSpy.d.ts.map +1 -1
  128. package/dist/Outline/useScrollSpy.js +202 -70
  129. package/dist/OverflowList/OverflowList.d.ts +20 -3
  130. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  131. package/dist/OverflowList/OverflowList.js +29 -4
  132. package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
  133. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  134. package/dist/SelectableCard/SelectableCard.d.ts +9 -2
  135. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  136. package/dist/SelectableCard/SelectableCard.js +14 -11
  137. package/dist/Selector/Selector.d.ts.map +1 -1
  138. package/dist/Selector/Selector.js +4 -2
  139. package/dist/Selector/hooks.d.ts.map +1 -1
  140. package/dist/Selector/hooks.js +16 -0
  141. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  142. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  143. package/dist/SideNav/SideNavHeading.js +21 -8
  144. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  145. package/dist/Slider/Slider.d.ts.map +1 -1
  146. package/dist/Slider/Slider.js +15 -1
  147. package/dist/TabList/Tab.d.ts.map +1 -1
  148. package/dist/TabList/Tab.js +2 -2
  149. package/dist/TabList/TabList.d.ts.map +1 -1
  150. package/dist/TabList/TabList.js +2 -0
  151. package/dist/TabList/TabMenu.d.ts.map +1 -1
  152. package/dist/TabList/TabMenu.js +1 -1
  153. package/dist/Table/Table.d.ts +1 -1
  154. package/dist/Table/Table.js +1 -1
  155. package/dist/Table/index.d.ts +4 -0
  156. package/dist/Table/index.d.ts.map +1 -1
  157. package/dist/Table/index.js +2 -0
  158. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  159. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  160. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +24 -2
  161. package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
  162. package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
  163. package/dist/Table/plugins/rowStatus/index.js +3 -0
  164. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
  165. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
  166. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
  167. package/dist/Table/plugins/selection/useTableSelection.d.ts +12 -0
  168. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  169. package/dist/Table/plugins/selection/useTableSelection.js +4 -1
  170. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  171. package/dist/Table/plugins/sortable/useTableSortable.js +18 -7
  172. package/dist/Table/plugins/tree/index.d.ts +5 -0
  173. package/dist/Table/plugins/tree/index.d.ts.map +1 -0
  174. package/dist/Table/plugins/tree/index.js +4 -0
  175. package/dist/Table/plugins/tree/useTableTreeData.d.ts +38 -0
  176. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -0
  177. package/dist/Table/plugins/tree/useTableTreeData.js +358 -0
  178. package/dist/Table/plugins/tree/useTableTreeState.d.ts +51 -0
  179. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -0
  180. package/dist/Table/plugins/tree/useTableTreeState.js +175 -0
  181. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  182. package/dist/Table/useBaseTablePlugins.js +6 -3
  183. package/dist/Thumbnail/Thumbnail.d.ts +8 -1
  184. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  185. package/dist/Thumbnail/Thumbnail.js +46 -8
  186. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  187. package/dist/TimeInput/TimeInput.js +15 -4
  188. package/dist/Tokenizer/Tokenizer.d.ts +1 -1
  189. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  190. package/dist/Tokenizer/Tokenizer.js +16 -4
  191. package/dist/Toolbar/Toolbar.d.ts.map +1 -1
  192. package/dist/Toolbar/Toolbar.js +8 -1
  193. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  194. package/dist/TopNav/TopNavHeading.js +18 -8
  195. package/dist/TopNav/TopNavMegaMenu.js +10 -4
  196. package/dist/TopNav/TopNavMenu.d.ts +2 -1
  197. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  198. package/dist/TopNav/TopNavMenu.js +68 -6
  199. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  200. package/dist/TreeList/TreeListItem.js +5 -14
  201. package/dist/astryx.css +51 -16
  202. package/dist/astryx.umd.js +56 -56
  203. package/dist/astryx.umd.js.map +4 -4
  204. package/dist/authoring/doc.d.ts.map +1 -1
  205. package/dist/hooks/computeOverflow.d.ts +47 -0
  206. package/dist/hooks/computeOverflow.d.ts.map +1 -0
  207. package/dist/hooks/computeOverflow.js +213 -0
  208. package/dist/hooks/useOverflow.d.ts +19 -0
  209. package/dist/hooks/useOverflow.d.ts.map +1 -1
  210. package/dist/hooks/useOverflow.js +37 -25
  211. package/dist/theme/Theme.js +1 -1
  212. package/dist/theme/defineTheme.d.ts +1 -1
  213. package/dist/theme/defineTheme.js +1 -1
  214. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  215. package/dist/theme/generateThemeRules.js +51 -0
  216. package/dist/theme/hct.d.ts +0 -1
  217. package/dist/theme/hct.d.ts.map +1 -1
  218. package/dist/theme/hct.js +0 -3
  219. package/dist/utils/types.d.ts +13 -0
  220. package/dist/utils/types.d.ts.map +1 -1
  221. package/docs.mjs +32 -461
  222. package/locales/en.json +212 -172
  223. package/locales/fr-FR.json +10 -0
  224. package/locales/pseudo.json +30 -0
  225. package/package.json +3 -1
  226. package/scripts/postinstall.mjs +93 -0
  227. package/src/AppShell/AppShell.tsx +6 -0
  228. package/src/AppShell/AppShellMobileContext.tsx +8 -0
  229. package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
  230. package/src/Avatar/Avatar.doc.mjs +6 -6
  231. package/src/Avatar/Avatar.tsx +16 -11
  232. package/src/Avatar/AvatarSizeContext.ts +1 -1
  233. package/src/Avatar/AvatarStatusDot.tsx +2 -2
  234. package/src/AvatarGroup/AvatarGroup.doc.mjs +1 -1
  235. package/src/AvatarGroup/AvatarGroup.test.tsx +17 -3
  236. package/src/AvatarGroup/AvatarGroup.tsx +3 -3
  237. package/src/AvatarGroup/AvatarGroupOverflow.doc.mjs +4 -4
  238. package/src/AvatarGroup/AvatarGroupOverflow.tsx +21 -5
  239. package/src/Banner/Banner.doc.mjs +9 -0
  240. package/src/Banner/Banner.test.tsx +30 -0
  241. package/src/Banner/Banner.tsx +47 -3
  242. package/src/Button/Button.doc.mjs +9 -0
  243. package/src/Button/Button.test.tsx +49 -0
  244. package/src/Button/Button.tsx +25 -1
  245. package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
  246. package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
  247. package/src/ButtonGroup/ButtonGroup.tsx +32 -0
  248. package/src/Card/Card.doc.mjs +9 -0
  249. package/src/Card/Card.test.tsx +21 -3
  250. package/src/Card/Card.tsx +35 -2
  251. package/src/Carousel/Carousel.doc.mjs +1 -0
  252. package/src/Carousel/Carousel.test.tsx +149 -1
  253. package/src/Carousel/Carousel.tsx +62 -5
  254. package/src/Chat/Chat.doc.mjs +1 -1
  255. package/src/Chat/ChatComposer.doc.mjs +9 -0
  256. package/src/Chat/ChatComposer.test.tsx +35 -0
  257. package/src/Chat/ChatComposer.tsx +58 -9
  258. package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
  259. package/src/Chat/ChatComposerDrawer.tsx +11 -1
  260. package/src/Chat/ChatComposerInput.doc.mjs +7 -0
  261. package/src/Chat/ChatComposerInput.test.tsx +87 -0
  262. package/src/Chat/ChatComposerInput.tsx +35 -3
  263. package/src/Chat/ChatLayout.tsx +3 -1
  264. package/src/Chat/ChatLayoutScrollButton.tsx +3 -1
  265. package/src/Chat/ChatMessage.tsx +4 -2
  266. package/src/Chat/ChatMessageMetadata.tsx +1 -2
  267. package/src/Chat/ChatSendButton.tsx +5 -1
  268. package/src/Chat/ChatToolCalls.test.tsx +64 -0
  269. package/src/Chat/ChatToolCalls.tsx +13 -1
  270. package/src/Chat/useTriggerMenu.tsx +3 -1
  271. package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
  272. package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
  273. package/src/CheckboxList/CheckboxList.test.tsx +9 -1
  274. package/src/Citation/Citation.test.tsx +51 -0
  275. package/src/Citation/Citation.tsx +8 -2
  276. package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
  277. package/src/ClickableCard/ClickableCard.test.tsx +34 -0
  278. package/src/ClickableCard/ClickableCard.tsx +11 -1
  279. package/src/CodeBlock/CodeBlock.test.tsx +56 -0
  280. package/src/CodeBlock/CodeBlock.tsx +9 -1
  281. package/src/Collapsible/Collapsible.doc.mjs +7 -0
  282. package/src/Collapsible/Collapsible.test.tsx +80 -0
  283. package/src/Collapsible/Collapsible.tsx +58 -5
  284. package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
  285. package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
  286. package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
  287. package/src/ContextMenu/ContextMenu.test.tsx +75 -1
  288. package/src/ContextMenu/ContextMenu.tsx +10 -5
  289. package/src/ContextMenu/index.ts +15 -0
  290. package/src/DateTimeInput/DateTimeInput.test.tsx +35 -0
  291. package/src/DateTimeInput/DateTimeInput.tsx +14 -2
  292. package/src/Dialog/Dialog.tsx +12 -2
  293. package/src/DropdownMenu/DropdownMenu.doc.mjs +23 -0
  294. package/src/DropdownMenu/DropdownMenu.tsx +11 -6
  295. package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +95 -0
  296. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +236 -0
  297. package/src/DropdownMenu/DropdownMenuContext.tsx +29 -1
  298. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +7 -1
  299. package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +80 -0
  300. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +118 -0
  301. package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +80 -0
  302. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +232 -0
  303. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +163 -0
  304. package/src/DropdownMenu/index.ts +23 -3
  305. package/src/DropdownMenu/menuItemRoles.ts +22 -0
  306. package/src/Field/Field.doc.mjs +1 -1
  307. package/src/Field/Field.test.tsx +57 -12
  308. package/src/Field/FieldLabel.doc.mjs +1 -1
  309. package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
  310. package/src/FieldStatus/FieldStatus.test.tsx +78 -40
  311. package/src/FieldStatus/FieldStatus.tsx +22 -4
  312. package/src/FileInput/FileInput.test.tsx +52 -3
  313. package/src/FileInput/FileInput.tsx +13 -2
  314. package/src/HoverCard/HoverCard.doc.mjs +13 -0
  315. package/src/HoverCard/HoverCard.test.tsx +21 -2
  316. package/src/HoverCard/HoverCard.tsx +11 -0
  317. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  318. package/src/HoverCard/useHoverCard.tsx +24 -2
  319. package/src/Icon/Icon.doc.mjs +12 -0
  320. package/src/Icon/Icon.test.tsx +142 -0
  321. package/src/Icon/Icon.tsx +98 -30
  322. package/src/IconButton/IconButton.doc.mjs +8 -0
  323. package/src/IconButton/IconButton.test.tsx +15 -18
  324. package/src/Item/Item.doc.mjs +1 -1
  325. package/src/Layer/useLayer.tsx +8 -0
  326. package/src/MobileNav/MobileNav.tsx +12 -1
  327. package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
  328. package/src/MobileNav/MobileNavToggle.tsx +9 -1
  329. package/src/MultiSelector/MultiSelector.doc.mjs +4 -2
  330. package/src/MultiSelector/MultiSelector.test.tsx +162 -1
  331. package/src/MultiSelector/MultiSelector.tsx +55 -12
  332. package/src/MultiSelector/hooks.ts +17 -0
  333. package/src/NumberInput/NumberInput.doc.mjs +2 -2
  334. package/src/NumberInput/NumberInput.test.tsx +11 -7
  335. package/src/NumberInput/NumberInput.tsx +1 -2
  336. package/src/Outline/Outline.doc.mjs +123 -3
  337. package/src/Outline/Outline.test.tsx +735 -0
  338. package/src/Outline/Outline.tsx +183 -33
  339. package/src/Outline/useScrollSpy.ts +248 -72
  340. package/src/OverflowList/OverflowList.doc.mjs +39 -6
  341. package/src/OverflowList/OverflowList.test.tsx +111 -0
  342. package/src/OverflowList/OverflowList.tsx +48 -8
  343. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
  344. package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
  345. package/src/PowerSearch/usePowerSearchSource.ts +1 -2
  346. package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
  347. package/src/SelectableCard/SelectableCard.test.tsx +46 -4
  348. package/src/SelectableCard/SelectableCard.tsx +27 -14
  349. package/src/Selector/Selector.test.tsx +69 -0
  350. package/src/Selector/Selector.tsx +5 -1
  351. package/src/Selector/SelectorOption.doc.mjs +1 -1
  352. package/src/Selector/hooks.ts +17 -0
  353. package/src/SideNav/SideNav.test.tsx +119 -3
  354. package/src/SideNav/SideNavCollapseButton.tsx +6 -1
  355. package/src/SideNav/SideNavHeading.tsx +24 -8
  356. package/src/SideNav/SideNavItem.doc.mjs +2 -2
  357. package/src/SideNav/SideNavItem.tsx +5 -1
  358. package/src/Slider/Slider.test.tsx +62 -2
  359. package/src/Slider/Slider.tsx +15 -1
  360. package/src/Switch/Switch.doc.mjs +1 -1
  361. package/src/Switch/Switch.test.tsx +32 -1
  362. package/src/TabList/Tab.tsx +5 -1
  363. package/src/TabList/TabList.doc.mjs +3 -3
  364. package/src/TabList/TabList.test.tsx +66 -0
  365. package/src/TabList/TabList.tsx +8 -0
  366. package/src/TabList/TabMenu.tsx +4 -1
  367. package/src/Table/Table.doc.mjs +2 -0
  368. package/src/Table/Table.tsx +1 -1
  369. package/src/Table/index.ts +12 -0
  370. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
  371. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +90 -1
  372. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +37 -5
  373. package/src/Table/plugins/rowStatus/index.ts +7 -0
  374. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
  375. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
  376. package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
  377. package/src/Table/plugins/selection/useTableSelection.tsx +18 -1
  378. package/src/Table/plugins/sortable/useTableSortable.test.tsx +95 -9
  379. package/src/Table/plugins/sortable/useTableSortable.tsx +23 -7
  380. package/src/Table/plugins/tree/index.ts +12 -0
  381. package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +163 -0
  382. package/src/Table/plugins/tree/useTableTreeData.test.tsx +594 -0
  383. package/src/Table/plugins/tree/useTableTreeData.tsx +495 -0
  384. package/src/Table/plugins/tree/useTableTreeState.test.tsx +636 -0
  385. package/src/Table/plugins/tree/useTableTreeState.tsx +253 -0
  386. package/src/Table/useBaseTablePlugins.ts +6 -2
  387. package/src/Table/useTableRowStatus.doc.mjs +30 -0
  388. package/src/Table/useTableSelection.doc.mjs +65 -14
  389. package/src/Table/useTableTreeData.doc.mjs +75 -0
  390. package/src/Table/useTableTreeState.doc.mjs +98 -0
  391. package/src/TextArea/TextArea.doc.mjs +1 -1
  392. package/src/TextArea/TextArea.test.tsx +9 -1
  393. package/src/TextInput/TextInput.doc.mjs +1 -1
  394. package/src/Thumbnail/Thumbnail.doc.mjs +9 -0
  395. package/src/Thumbnail/Thumbnail.test.tsx +38 -8
  396. package/src/Thumbnail/Thumbnail.tsx +28 -1
  397. package/src/TimeInput/TimeInput.test.tsx +76 -1
  398. package/src/TimeInput/TimeInput.tsx +19 -6
  399. package/src/Tokenizer/Tokenizer.doc.mjs +1 -1
  400. package/src/Tokenizer/Tokenizer.test.tsx +137 -2
  401. package/src/Tokenizer/Tokenizer.tsx +16 -4
  402. package/src/Toolbar/Toolbar.tsx +10 -3
  403. package/src/TopNav/TopNav.test.tsx +80 -1
  404. package/src/TopNav/TopNavHeading.tsx +24 -8
  405. package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
  406. package/src/TopNav/TopNavMegaMenu.tsx +10 -4
  407. package/src/TopNav/TopNavMenu.test.tsx +118 -4
  408. package/src/TopNav/TopNavMenu.tsx +83 -5
  409. package/src/TreeList/TreeList.test.tsx +32 -1
  410. package/src/TreeList/TreeListItem.tsx +19 -10
  411. package/src/authoring/doc.ts +1 -3
  412. package/src/docs-script.test.mjs +18 -13
  413. package/src/hooks/computeOverflow.test.ts +422 -0
  414. package/src/hooks/computeOverflow.ts +290 -0
  415. package/src/hooks/useOverflow.test.ts +96 -4
  416. package/src/hooks/useOverflow.ts +77 -33
  417. package/src/postinstall.test.mjs +71 -0
  418. package/src/theme/Theme.doc.mjs +4 -4
  419. package/src/theme/Theme.tsx +1 -1
  420. package/src/theme/defineTheme.ts +1 -1
  421. package/src/theme/generateThemeRules.test.ts +65 -0
  422. package/src/theme/generateThemeRules.ts +56 -0
  423. package/src/theme/hct.ts +0 -4
  424. package/src/utils/types.ts +14 -0
  425. package/dist/TreeList/treeListItem.markers.stylex.d.ts +0 -16
  426. package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +0 -1
  427. package/dist/TreeList/treeListItem.markers.stylex.js +0 -22
  428. package/src/TreeList/treeListItem.markers.stylex.ts +0 -20
@@ -46,8 +46,10 @@ import {
46
46
  borderVars,
47
47
  durationVars,
48
48
  easeVars,
49
+ shadowVars,
49
50
  } from '../theme/tokens.stylex';
50
51
  import {mergeProps} from '../utils';
52
+ import type {Elevation} from '../utils/types';
51
53
  import {edgeCompSlot} from '../Layout/edgeCompensation.stylex';
52
54
  import {themeProps} from '../utils/themeProps';
53
55
  import {useTranslator} from '../i18n';
@@ -157,6 +159,13 @@ export interface BannerProps extends BaseProps<HTMLDivElement> {
157
159
  * @default 'card'
158
160
  */
159
161
  container?: BannerContainer;
162
+ /**
163
+ * Resting elevation — the shadow depth the banner sits at. Use for a
164
+ * floating banner that hovers above content. `none` is the default inline
165
+ * banner.
166
+ * @default 'none'
167
+ */
168
+ elevation?: Elevation;
160
169
  /**
161
170
  * Whether the content area (children) starts expanded.
162
171
  * Only relevant when children are provided.
@@ -215,6 +224,11 @@ const styles = stylex.create({
215
224
  flexDirection: 'column',
216
225
  fontFamily: 'inherit',
217
226
  },
227
+ // When elevated, a card-container banner rounds its root so the shadow
228
+ // follows the same silhouette as the header/content border-radius.
229
+ rootElevatedCard: {
230
+ borderRadius: radiusVars['--radius-container'],
231
+ },
218
232
  // Header area — colored status background with icon, title, description, actions
219
233
  // This is the primary theme target ('banner')
220
234
  header: {
@@ -323,6 +337,18 @@ const statusStyles = stylex.create({
323
337
  },
324
338
  });
325
339
 
340
+ // Resting elevation for the banner. Applied to the root so the shadow wraps
341
+ // the whole banner (header + optional content). 'none' is the default and
342
+ // leaves the layout-only root untouched. For the `card` container the root is
343
+ // rounded (rootElevatedCard) so the shadow follows the card silhouette; the
344
+ // full-width `section` container stays square.
345
+ const elevationStyles = stylex.create({
346
+ none: {boxShadow: 'none'},
347
+ low: {boxShadow: shadowVars['--shadow-low']},
348
+ med: {boxShadow: shadowVars['--shadow-med']},
349
+ high: {boxShadow: shadowVars['--shadow-high']},
350
+ });
351
+
326
352
  // =============================================================================
327
353
  // Component
328
354
  // =============================================================================
@@ -381,6 +407,7 @@ export function Banner({
381
407
  onDismiss,
382
408
  endContent,
383
409
  container = 'card',
410
+ elevation = 'none',
384
411
  defaultIsExpanded = false,
385
412
  children,
386
413
  xstyle,
@@ -429,7 +456,16 @@ export function Banner({
429
456
  <div
430
457
  ref={ref}
431
458
  role={role}
432
- {...mergeProps(stylex.props(styles.root, xstyle), className, style)}
459
+ {...mergeProps(
460
+ stylex.props(
461
+ styles.root,
462
+ elevationStyles[elevation],
463
+ isCard && elevation !== 'none' && styles.rootElevatedCard,
464
+ xstyle,
465
+ ),
466
+ className,
467
+ style,
468
+ )}
433
469
  {...rest}>
434
470
  {/* Header: colored status background — primary theme target ('banner') */}
435
471
  <div
@@ -474,8 +510,16 @@ export function Banner({
474
510
  <Button
475
511
  variant="ghost"
476
512
  size="sm"
477
- label={isExpanded ? t('@astryx.banner.collapse') : t('@astryx.banner.expand')}
478
- tooltip={isExpanded ? t('@astryx.banner.collapse') : t('@astryx.banner.expand')}
513
+ label={
514
+ isExpanded
515
+ ? t('@astryx.banner.collapse')
516
+ : t('@astryx.banner.expand')
517
+ }
518
+ tooltip={
519
+ isExpanded
520
+ ? t('@astryx.banner.collapse')
521
+ : t('@astryx.banner.expand')
522
+ }
479
523
  icon={
480
524
  <span
481
525
  {...stylex.props(
@@ -51,6 +51,13 @@ export const docs = {
51
51
  description: 'Size variant.',
52
52
  default: "'md'",
53
53
  },
54
+ {
55
+ name: 'elevation',
56
+ type: "'none' | 'low' | 'med' | 'high'",
57
+ description:
58
+ 'Resting shadow depth for floating buttons (e.g. a FAB). `none` is the default flat button; `low`/`med`/`high` map to the shadow token scale. Ignored inside a ButtonGroup, where elevation is owned by the group.',
59
+ default: "'none'",
60
+ },
54
61
  {
55
62
  name: 'type',
56
63
  type: "'button' | 'submit' | 'reset'",
@@ -199,6 +206,7 @@ export const docsZh = {
199
206
  default: "'secondary'",
200
207
  },
201
208
  {name: 'size', type: "'sm' | 'md' | 'lg'", description: '尺寸变体。', default: "'md'"},
209
+ {name: 'elevation', type: "'none' | 'low' | 'med' | 'high'", description: '浮动按钮(如 FAB)的静止阴影深度。`none` 为默认扁平按钮;在 ButtonGroup 内忽略。', default: "'none'"},
202
210
  {name: 'type', type: "'button' | 'submit' | 'reset'", description: 'HTML 按钮类型属性。', default: "'button'"},
203
211
  {name: 'name', type: 'string', description: '表单提交的 HTML name 属性。'},
204
212
  {name: 'value', type: 'string | number | readonly string[]', description: '表单提交的 HTML value 属性。'},
@@ -271,6 +279,7 @@ export const docsDense = {
271
279
  label: 'accessible label; visible text by default, aria-label when isIconOnly',
272
280
  variant: 'visual style variant',
273
281
  size: 'size variant',
282
+ elevation: 'resting shadow depth for floating buttons/FABs: none|low|med|high; ignored inside ButtonGroup',
274
283
  type: 'HTML button type; defaults to "button"',
275
284
  name: 'HTML name for form submission',
276
285
  displayName: 'HTML name for form submission',
@@ -445,4 +445,53 @@ describe('Button', () => {
445
445
  rerender(<Button label="Submit" isLoading />);
446
446
  expect(liveRegion).toHaveTextContent('Loading');
447
447
  });
448
+
449
+ describe('elevation', () => {
450
+ it('renders a distinct class for each elevation level', () => {
451
+ const classFor = (elevation: 'none' | 'low' | 'med' | 'high') => {
452
+ const {container} = render(
453
+ <Button label="Save" elevation={elevation} />,
454
+ );
455
+ return container.querySelector('button')!.className;
456
+ };
457
+ const classes = new Set([
458
+ classFor('none'),
459
+ classFor('low'),
460
+ classFor('med'),
461
+ classFor('high'),
462
+ ]);
463
+ expect(classes.size).toBe(4);
464
+ });
465
+
466
+ it('defaults to flat (elevation none)', () => {
467
+ const {container: def} = render(<Button label="Save" />);
468
+ const {container: none} = render(
469
+ <Button label="Save" elevation="none" />,
470
+ );
471
+ expect(def.querySelector('button')!.className).toBe(
472
+ none.querySelector('button')!.className,
473
+ );
474
+ });
475
+ });
476
+
477
+ it('exposes aria-busy on the link-rendered button while loading', () => {
478
+ // Non-interruptible loading disables the button, which falls back to
479
+ // <button> rendering — so an anchor only shows loading when interruptible.
480
+ render(
481
+ <Button
482
+ label="Docs"
483
+ href="https://example.com"
484
+ isLoading
485
+ isInterruptible
486
+ />,
487
+ );
488
+ const link = screen.getByRole('link');
489
+ expect(link).toHaveAttribute('aria-busy', 'true');
490
+ });
491
+
492
+ it('does not set aria-busy on the link-rendered button when not loading', () => {
493
+ render(<Button label="Docs" href="https://example.com" />);
494
+ const link = screen.getByRole('link');
495
+ expect(link).not.toHaveAttribute('aria-busy');
496
+ });
448
497
  });
@@ -20,7 +20,7 @@
20
20
 
21
21
  import {useRef, useTransition, type ReactNode} from 'react';
22
22
  import type {BaseProps} from '../BaseProps';
23
- import type {SizeValue} from '../utils/types';
23
+ import type {Elevation, SizeValue} from '../utils/types';
24
24
  import * as stylex from '@stylexjs/stylex';
25
25
  import {useTooltip} from '../Tooltip/useTooltip';
26
26
  import {
@@ -33,6 +33,7 @@ import {
33
33
  easeVars,
34
34
  fontWeightVars,
35
35
  typeScaleVars,
36
+ shadowVars,
36
37
  } from '../theme/tokens.stylex';
37
38
  import {Spinner} from '../Spinner';
38
39
  import {VisuallyHidden} from '../VisuallyHidden';
@@ -160,6 +161,18 @@ const iconSizeStyles = stylex.create({
160
161
  lg: {width: 20, height: 20, fontSize: 20},
161
162
  });
162
163
 
164
+ /**
165
+ * Resting elevation for floating buttons (e.g. a FAB). `none` is the default
166
+ * flat button; `low`/`med`/`high` map to the shadow token scale. 'none' stays
167
+ * a literal so it never conflicts with a variant's background layering.
168
+ */
169
+ const elevationStyles = stylex.create({
170
+ none: {boxShadow: 'none'},
171
+ low: {boxShadow: shadowVars['--shadow-low']},
172
+ med: {boxShadow: shadowVars['--shadow-med']},
173
+ high: {boxShadow: shadowVars['--shadow-high']},
174
+ });
175
+
163
176
  /**
164
177
  * Variant styles using backgroundImage for layered colors
165
178
  * Pseudo-classes are nested within properties per StyleX recommendation
@@ -307,6 +320,12 @@ export interface ButtonProps extends BaseProps<HTMLButtonElement> {
307
320
  * @default 'md'
308
321
  */
309
322
  size?: ButtonSize;
323
+ /**
324
+ * Resting elevation — the shadow depth the button sits at. Use for floating
325
+ * buttons (FABs) that hover above content. `none` is the default flat button.
326
+ * @default 'none'
327
+ */
328
+ elevation?: Elevation;
310
329
  /**
311
330
  * Whether the button is disabled.
312
331
  * @default false
@@ -578,6 +597,7 @@ export function Button({
578
597
  icon,
579
598
  isIconOnly = false,
580
599
  width,
600
+ elevation = 'none',
581
601
  children,
582
602
  endContent,
583
603
  tooltip,
@@ -691,6 +711,9 @@ export function Button({
691
711
  (buttonGroup.orientation === 'horizontal'
692
712
  ? groupStyles.onSolidHorizontal
693
713
  : groupStyles.onSolidVertical),
714
+ // Standalone floating buttons only — a grouped button's elevation is owned
715
+ // by the ButtonGroup so the shared surface lifts as one unit.
716
+ !buttonGroup && elevationStyles[elevation],
694
717
  width != null && dynamicStyles.width(width),
695
718
  xstyle,
696
719
  );
@@ -786,6 +809,7 @@ export function Button({
786
809
  {...ariaLabelProp}
787
810
  {...describedByProp}
788
811
  {...edgeCompAttr}
812
+ aria-busy={isLoadingState || undefined}
789
813
  onClick={handleClick}>
790
814
  {buttonContent}
791
815
  </LinkComponent>
@@ -29,6 +29,7 @@ export const docs = {
29
29
  {name: 'orientation', type: "'horizontal' | 'vertical'", description: 'Layout direction of the button group.', default: "'horizontal'"},
30
30
  {name: 'size', type: "'sm' | 'md' | 'lg'", description: 'Default size for buttons in the group. Individual buttons can override.', default: "'md'"},
31
31
  {name: 'isDisabled', type: 'boolean', description: 'Whether all buttons in the group are disabled.', default: 'false'},
32
+ {name: 'elevation', type: "'none' | 'low' | 'med' | 'high'", description: 'Resting shadow depth for the whole group. The connected buttons share one surface, so the shadow lifts them as a unit. Use for a group that floats above content.', default: "'none'"},
32
33
  {name: 'ref', type: 'React.Ref<HTMLDivElement>', description: 'Ref forwarded to the root element.'},
33
34
  {name: 'xstyle', type: 'StyleXStyles', description: 'StyleX styles for layout customization. Must be a stylex.create() value.'},
34
35
  {name: 'data-testid', type: 'string', description: 'Test selector for automated testing frameworks.'},
@@ -66,6 +67,7 @@ export const docsZh = {
66
67
  orientation: '按钮组的布局方向。',
67
68
  size: '组内按钮的默认尺寸。单个按钮可覆盖。',
68
69
  isDisabled: '组内所有按钮是否禁用。',
70
+ elevation: '整个组的静止阴影深度。连接的按钮共享一个表面,阴影将它们作为整体抬起。',
69
71
  ref: '转发到根元素的引用。',
70
72
  xstyle: 'StyleX 样式,用于布局自定义。必须是 stylex.create() 的值。',
71
73
  'data-testid': '自动化测试的选择器。',
@@ -116,6 +118,7 @@ export const docsDense = {
116
118
  orientation: 'layout direction',
117
119
  size: 'default btn size; individual btns override',
118
120
  isDisabled: 'all btns disabled',
121
+ elevation: 'resting shadow depth for whole group: none|low|med|high',
119
122
  xstyle: 'StyleX layout styles; must be stylex.create() value',
120
123
  'data-testid': 'test selector',
121
124
  },
@@ -572,4 +572,41 @@ describe('ButtonGroup', () => {
572
572
  expect(hasRoundedTrailingCorners(save)).toBe(false);
573
573
  });
574
574
  });
575
+
576
+ describe('elevation', () => {
577
+ it('renders a distinct class on the group for each elevation level', () => {
578
+ const classFor = (elevation: 'none' | 'low' | 'med' | 'high') => {
579
+ const {container} = render(
580
+ <ButtonGroup label="Actions" elevation={elevation}>
581
+ <Button label="One" />
582
+ <Button label="Two" />
583
+ </ButtonGroup>,
584
+ );
585
+ return container.querySelector('[role="group"]')!.className;
586
+ };
587
+ const classes = new Set([
588
+ classFor('none'),
589
+ classFor('low'),
590
+ classFor('med'),
591
+ classFor('high'),
592
+ ]);
593
+ expect(classes.size).toBe(4);
594
+ });
595
+
596
+ it('defaults to flat (elevation none)', () => {
597
+ const {container: def} = render(
598
+ <ButtonGroup label="Actions">
599
+ <Button label="One" />
600
+ </ButtonGroup>,
601
+ );
602
+ const {container: none} = render(
603
+ <ButtonGroup label="Actions" elevation="none">
604
+ <Button label="One" />
605
+ </ButtonGroup>,
606
+ );
607
+ expect(def.querySelector('[role="group"]')!.className).toBe(
608
+ none.querySelector('[role="group"]')!.className,
609
+ );
610
+ });
611
+ });
575
612
  });
@@ -24,6 +24,8 @@
24
24
  import {useMemo, type ReactNode} from 'react';
25
25
  import * as stylex from '@stylexjs/stylex';
26
26
  import type {ButtonSize} from '../Button';
27
+ import {radiusVars, shadowVars} from '../theme/tokens.stylex';
28
+ import type {Elevation} from '../utils/types';
27
29
  import {SizeProvider, useSize} from '../SizeContext/SizeContext';
28
30
  import {useListFocus} from '../hooks/useListFocus';
29
31
  import {mergeProps, mergeRefs, composeEventHandlers} from '../utils';
@@ -63,6 +65,14 @@ export interface ButtonGroupProps extends BaseProps<HTMLDivElement> {
63
65
  */
64
66
  size?: ButtonSize;
65
67
 
68
+ /**
69
+ * Resting elevation for the group. The connected buttons share one surface,
70
+ * so the shadow sits on the group and lifts them together. Use for a floating
71
+ * group of actions above content.
72
+ * @default 'none'
73
+ */
74
+ elevation?: Elevation;
75
+
66
76
  /**
67
77
  * Whether all buttons in the group are disabled.
68
78
  * @default false
@@ -89,6 +99,26 @@ const styles = stylex.create({
89
99
  },
90
100
  });
91
101
 
102
+ // Resting elevation for the whole group — the connected buttons share one
103
+ // surface, so the shadow sits on the group wrapper and lifts them as a unit.
104
+ // The wrapper takes the element radius so the shadow follows the group's
105
+ // rounded outer corners rather than a bare rectangle. 'none' is the default.
106
+ const elevationStyles = stylex.create({
107
+ none: {boxShadow: 'none'},
108
+ low: {
109
+ boxShadow: shadowVars['--shadow-low'],
110
+ borderRadius: radiusVars['--radius-element'],
111
+ },
112
+ med: {
113
+ boxShadow: shadowVars['--shadow-med'],
114
+ borderRadius: radiusVars['--radius-element'],
115
+ },
116
+ high: {
117
+ boxShadow: shadowVars['--shadow-high'],
118
+ borderRadius: radiusVars['--radius-element'],
119
+ },
120
+ });
121
+
92
122
  // =============================================================================
93
123
  // Component
94
124
  // =============================================================================
@@ -129,6 +159,7 @@ export function ButtonGroup({
129
159
  orientation = 'horizontal',
130
160
  size: sizeProp,
131
161
  isDisabled = false,
162
+ elevation = 'none',
132
163
  xstyle,
133
164
  className,
134
165
  style,
@@ -160,6 +191,7 @@ export function ButtonGroup({
160
191
  stylex.props(
161
192
  styles.group,
162
193
  orientation === 'vertical' && styles.vertical,
194
+ elevationStyles[elevation],
163
195
  xstyle,
164
196
  ),
165
197
  className,
@@ -67,6 +67,13 @@ export const docs = {
67
67
  'Background color variant. `default` uses the standard card background. `transparent` drops the background entirely. `muted` uses the muted background for de-emphasised cards. The non-semantic variants use the corresponding `--color-background-<name>` token.',
68
68
  default: "'default'",
69
69
  },
70
+ {
71
+ name: 'elevation',
72
+ type: "'none' | 'low' | 'med' | 'high'",
73
+ description:
74
+ 'Resting shadow depth. `none` is flat; `low`/`med`/`high` map to the shadow token scale. Raise a card only when it needs to float above surrounding content.',
75
+ default: "'none'",
76
+ },
70
77
  ],
71
78
  playground: {
72
79
  defaults: {
@@ -127,6 +134,7 @@ export const docsZh = {
127
134
  {name: 'minHeight', type: 'SizeValue', description: '卡片最小高度。'},
128
135
  {name: 'children', type: 'ReactNode', description: '在卡片内部渲染的内容。'},
129
136
  {name: 'padding', type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10', description: '使用间距比例的内边距。', default: '4'},
137
+ {name: 'elevation', type: "'none' | 'low' | 'med' | 'high'", description: '静止阴影深度。`none` 为扁平;`low`/`med`/`high` 对应阴影令牌比例。', default: "'none'"},
130
138
  ],
131
139
  theming: {
132
140
  container: true,
@@ -170,5 +178,6 @@ export const docsDense = {
170
178
  children: 'content inside card',
171
179
  padding: 'internal padding via spacing scale',
172
180
  variant: 'background color variant; `default` = standard card bg, `transparent` = no background at all, `muted` = muted bg for de-emphasised cards; non-semantic variants use the corresponding `--color-background-<name>` token',
181
+ elevation: 'resting shadow depth: none (flat) | low | med | high (shadow token scale). Raise only to float above content.',
173
182
  },
174
183
  };
@@ -17,11 +17,29 @@ describe('Card', () => {
17
17
  });
18
18
 
19
19
  it('renders transparent variant with variant class', () => {
20
- const {container} = render(
21
- <Card variant="transparent">Content</Card>,
22
- );
20
+ const {container} = render(<Card variant="transparent">Content</Card>);
23
21
  const root = container.firstElementChild!;
24
22
  expect(root.className).toContain('astryx-card');
25
23
  expect(root.className).toContain('transparent');
26
24
  });
25
+
26
+ it('applies a distinct class for each elevation level', () => {
27
+ const classFor = (elevation: 'none' | 'low' | 'med' | 'high') => {
28
+ const {container} = render(<Card elevation={elevation}>C</Card>);
29
+ return container.firstElementChild!.className;
30
+ };
31
+ const none = classFor('none');
32
+ const low = classFor('low');
33
+ const med = classFor('med');
34
+ const high = classFor('high');
35
+ expect(new Set([none, low, med, high]).size).toBe(4);
36
+ });
37
+
38
+ it('defaults to flat (elevation none) — same class as explicit none', () => {
39
+ const {container: defaultContainer} = render(<Card>C</Card>);
40
+ const {container: noneContainer} = render(<Card elevation="none">C</Card>);
41
+ expect(defaultContainer.firstElementChild!.className).toBe(
42
+ noneContainer.firstElementChild!.className,
43
+ );
44
+ });
27
45
  });
package/src/Card/Card.tsx CHANGED
@@ -17,7 +17,12 @@
17
17
 
18
18
  import type {ReactNode} from 'react';
19
19
  import * as stylex from '@stylexjs/stylex';
20
- import {borderVars, colorVars, radiusVars} from '../theme/tokens.stylex';
20
+ import {
21
+ borderVars,
22
+ colorVars,
23
+ radiusVars,
24
+ shadowVars,
25
+ } from '../theme/tokens.stylex';
21
26
  import {container} from '../Layout/container.stylex';
22
27
  import type {SpacingToken} from '../Layout/container.stylex';
23
28
  import {
@@ -27,7 +32,7 @@ import {
27
32
  containerPaddingBlockEndVarStyles,
28
33
  spacingStepToToken,
29
34
  } from '../Layout/padding.stylex';
30
- import type {SizeValue, SpacingStep} from '../utils/types';
35
+ import type {Elevation, SizeValue, SpacingStep} from '../utils/types';
31
36
  import {mergeProps} from '../utils';
32
37
  import type {BaseProps} from '../BaseProps';
33
38
  import {themeProps} from '../utils/themeProps';
@@ -73,6 +78,13 @@ const styles = stylex.create({
73
78
  '--_card-radius': radiusVars['--radius-container'],
74
79
  borderRadius: 'var(--_card-radius)',
75
80
  overflow: 'clip',
81
+ // Resting elevation is set via --_card-elevation (see elevationStyles).
82
+ // The shadow list also reads --_card-ring so composing surfaces — e.g.
83
+ // SelectableCard's inset selection ring — can layer their own shadow
84
+ // alongside elevation instead of clobbering the single box-shadow property.
85
+ // Unset vars fall back to a transparent no-op shadow.
86
+ boxShadow:
87
+ 'var(--_card-ring, 0 0 transparent), var(--_card-elevation, 0 0 transparent)',
76
88
  },
77
89
  // The border is drawn *inside* the padding — its width is subtracted from
78
90
  // each side — so total inset (border + padding) equals the padding token
@@ -135,6 +147,18 @@ const variantStyles = stylex.create({
135
147
  },
136
148
  });
137
149
 
150
+ // Elevation → shadow-token map. Sets the private --_card-elevation variable
151
+ // (not box-shadow directly) so it composes with --_card-ring in the shadow
152
+ // list above — a selection ring and a resting elevation coexist without one
153
+ // overwriting the other. 'none' is a transparent no-op (not the CSS literal
154
+ // `none`, which would be invalid inside the comma-separated shadow list).
155
+ const elevationStyles = stylex.create({
156
+ none: {'--_card-elevation': '0 0 transparent'},
157
+ low: {'--_card-elevation': shadowVars['--shadow-low']},
158
+ med: {'--_card-elevation': shadowVars['--shadow-med']},
159
+ high: {'--_card-elevation': shadowVars['--shadow-high']},
160
+ });
161
+
138
162
  // Dynamic styles for sizing props
139
163
  const dynamicStyles = stylex.create({
140
164
  sizing: (
@@ -208,6 +232,13 @@ export interface CardProps extends BaseProps<HTMLDivElement> {
208
232
  * @default 'default'
209
233
  */
210
234
  variant?: CardVariant;
235
+
236
+ /**
237
+ * Resting elevation — the shadow depth the card sits at.
238
+ * `none` is flat; `low`/`med`/`high` map to the shadow token scale.
239
+ * @default 'none'
240
+ */
241
+ elevation?: Elevation;
211
242
  }
212
243
 
213
244
  /**
@@ -252,6 +283,7 @@ export function Card({
252
283
  children,
253
284
  padding,
254
285
  variant = 'default',
286
+ elevation = 'none',
255
287
  xstyle,
256
288
  className,
257
289
  style,
@@ -274,6 +306,7 @@ export function Card({
274
306
  stylex.props(
275
307
  styles.card,
276
308
  variantStyles[variant],
309
+ elevationStyles[elevation],
277
310
  hasFixedHeight && styles.scrollable,
278
311
  dynamicStyles.sizing(
279
312
  width ?? null,
@@ -14,6 +14,7 @@ export const docs = {
14
14
  {guidance: true, description: 'Enable scroll-snap when each item should land precisely at the start edge, like a gallery or product list.'},
15
15
  {guidance: true, description: 'Always provide an aria-label that describes what the carousel contains, like "Featured products" or "Team members".'},
16
16
  {guidance: true, description: 'Use a consistent gap and item width so the carousel looks intentional, not like content overflowing by accident.'},
17
+ {guidance: true, description: 'Trust the built-in navigation: trackpad users can swipe horizontally, and mouse users can hold Shift while scrolling the wheel to move through items.'},
17
18
  {guidance: false, description: 'Use a carousel for content every user must see. Not everyone scrolls horizontally, so put critical content above the fold.'},
18
19
  {guidance: false, description: 'Auto-advance items. Let the user scroll at their own pace.'},
19
20
  {guidance: false, description: 'Nest carousels. A carousel inside a carousel is confusing and breaks keyboard navigation.'},