@astryxdesign/core 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (487) hide show
  1. package/CHANGELOG.md +100 -0
  2. package/dist/AppShell/AppShell.d.ts.map +1 -1
  3. package/dist/AppShell/AppShell.js +6 -2
  4. package/dist/AppShell/AppShellMobileContext.d.ts +8 -0
  5. package/dist/AppShell/AppShellMobileContext.d.ts.map +1 -1
  6. package/dist/Avatar/Avatar.d.ts +18 -2
  7. package/dist/Avatar/Avatar.d.ts.map +1 -1
  8. package/dist/Avatar/Avatar.js +63 -7
  9. package/dist/Avatar/AvatarStatusDot.d.ts +33 -5
  10. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  11. package/dist/Avatar/AvatarStatusDot.js +144 -19
  12. package/dist/Banner/Banner.d.ts +9 -1
  13. package/dist/Banner/Banner.d.ts.map +1 -1
  14. package/dist/Banner/Banner.js +31 -2
  15. package/dist/Breadcrumbs/BreadcrumbItem.d.ts +31 -2
  16. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  17. package/dist/Breadcrumbs/BreadcrumbItem.js +208 -6
  18. package/dist/Breadcrumbs/index.d.ts +5 -0
  19. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  20. package/dist/Breadcrumbs/index.js +9 -1
  21. package/dist/Button/Button.d.ts +8 -2
  22. package/dist/Button/Button.d.ts.map +1 -1
  23. package/dist/Button/Button.js +31 -2
  24. package/dist/ButtonGroup/ButtonGroup.d.ts +9 -1
  25. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  26. package/dist/ButtonGroup/ButtonGroup.js +30 -1
  27. package/dist/Calendar/Calendar.d.ts.map +1 -1
  28. package/dist/Calendar/Calendar.js +30 -2
  29. package/dist/Calendar/dayCellUtils.js +1 -1
  30. package/dist/Card/Card.d.ts +8 -2
  31. package/dist/Card/Card.d.ts.map +1 -1
  32. package/dist/Card/Card.js +28 -2
  33. package/dist/Carousel/Carousel.d.ts +4 -1
  34. package/dist/Carousel/Carousel.d.ts.map +1 -1
  35. package/dist/Carousel/Carousel.js +24 -4
  36. package/dist/Chat/ChatComposer.d.ts +8 -0
  37. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  38. package/dist/Chat/ChatComposer.js +46 -7
  39. package/dist/Chat/ChatComposerDrawer.d.ts +2 -0
  40. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  41. package/dist/Chat/ChatComposerDrawer.js +11 -1
  42. package/dist/Chat/ChatComposerInput.d.ts +20 -3
  43. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  44. package/dist/Chat/ChatComposerInput.js +35 -3
  45. package/dist/Chat/ChatContext.d.ts +33 -0
  46. package/dist/Chat/ChatContext.d.ts.map +1 -1
  47. package/dist/Chat/ChatContext.js +16 -2
  48. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  49. package/dist/Chat/ChatDictationButton.js +1 -1
  50. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  51. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  52. package/dist/Chat/ChatLayoutScrollButton.js +4 -4
  53. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  54. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  55. package/dist/Chat/ChatSendButton.js +7 -1
  56. package/dist/Chat/ChatToolCalls.d.ts +5 -1
  57. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  58. package/dist/Chat/ChatToolCalls.js +18 -9
  59. package/dist/Chat/index.d.ts +2 -1
  60. package/dist/Chat/index.d.ts.map +1 -1
  61. package/dist/Chat/index.js +1 -1
  62. package/dist/Chat/useChatStreamScroll.d.ts +2 -1
  63. package/dist/Chat/useChatStreamScroll.d.ts.map +1 -1
  64. package/dist/Chat/useChatStreamScroll.js +22 -8
  65. package/dist/Chat/useSpeechRecognition.d.ts +0 -1
  66. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  67. package/dist/Chat/useSpeechRecognition.js +1 -1
  68. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  69. package/dist/CheckboxInput/CheckboxInput.js +1 -1
  70. package/dist/CheckboxList/CheckboxListItem.d.ts +20 -1
  71. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  72. package/dist/CheckboxList/CheckboxListItem.js +11 -1
  73. package/dist/ClickableCard/ClickableCard.d.ts +9 -2
  74. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  75. package/dist/ClickableCard/ClickableCard.js +5 -2
  76. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  77. package/dist/CodeBlock/CodeBlock.js +8 -1
  78. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  79. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  80. package/dist/CommandPalette/CommandPalette.js +3 -1
  81. package/dist/CommandPalette/CommandPaletteGroup.d.ts.map +1 -1
  82. package/dist/CommandPalette/CommandPaletteGroup.js +9 -2
  83. package/dist/CommandPalette/CommandPaletteInput.d.ts +7 -1
  84. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  85. package/dist/CommandPalette/CommandPaletteInput.js +6 -1
  86. package/dist/DateInput/DateInput.d.ts +47 -1
  87. package/dist/DateInput/DateInput.d.ts.map +1 -1
  88. package/dist/DateInput/DateInput.js +26 -2
  89. package/dist/DateInput/index.d.ts +1 -1
  90. package/dist/DateInput/index.d.ts.map +1 -1
  91. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  92. package/dist/DateTimeInput/DateTimeInput.js +10 -1
  93. package/dist/Dialog/Dialog.d.ts +3 -0
  94. package/dist/Dialog/Dialog.d.ts.map +1 -1
  95. package/dist/Dialog/Dialog.js +57 -6
  96. package/dist/Dialog/DialogContext.d.ts +7 -0
  97. package/dist/Dialog/DialogContext.d.ts.map +1 -1
  98. package/dist/Dialog/DialogContext.js +2 -2
  99. package/dist/Dialog/DialogHeader.d.ts +5 -2
  100. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  101. package/dist/Dialog/DialogHeader.js +6 -1
  102. package/dist/Divider/Divider.js +1 -1
  103. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -2
  104. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  105. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +1 -2
  106. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +1 -2
  107. package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -1
  108. package/dist/DropdownMenu/DropdownMenuRadioGroup.js +1 -2
  109. package/dist/Field/Field.d.ts.map +1 -1
  110. package/dist/Field/Field.js +2 -3
  111. package/dist/Field/FieldLabel.d.ts +1 -1
  112. package/dist/Field/FieldLabel.d.ts.map +1 -1
  113. package/dist/Field/FieldLabel.js +42 -15
  114. package/dist/FieldStatus/FieldStatus.d.ts +8 -0
  115. package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
  116. package/dist/FieldStatus/FieldStatus.js +22 -4
  117. package/dist/FileInput/FileInput.d.ts.map +1 -1
  118. package/dist/FileInput/FileInput.js +10 -2
  119. package/dist/HoverCard/HoverCard.d.ts +9 -1
  120. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  121. package/dist/HoverCard/HoverCard.js +2 -0
  122. package/dist/HoverCard/useHoverCard.d.ts +8 -0
  123. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  124. package/dist/HoverCard/useHoverCard.js +7 -2
  125. package/dist/Icon/Icon.d.ts +7 -2
  126. package/dist/Icon/Icon.d.ts.map +1 -1
  127. package/dist/Item/Item.d.ts +6 -1
  128. package/dist/Item/Item.d.ts.map +1 -1
  129. package/dist/Item/Item.js +22 -1
  130. package/dist/Layer/useLayer.d.ts +6 -0
  131. package/dist/Layer/useLayer.d.ts.map +1 -1
  132. package/dist/Layer/useLayer.js +2 -0
  133. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  134. package/dist/MobileNav/MobileNav.js +6 -1
  135. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  136. package/dist/MobileNav/MobileNavToggle.js +4 -0
  137. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  138. package/dist/MultiSelector/MultiSelector.js +39 -12
  139. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  140. package/dist/MultiSelector/hooks.js +16 -0
  141. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  142. package/dist/Outline/Outline.d.ts +0 -1
  143. package/dist/Outline/Outline.d.ts.map +1 -1
  144. package/dist/Outline/Outline.js +0 -1
  145. package/dist/OverflowList/OverflowList.d.ts +20 -3
  146. package/dist/OverflowList/OverflowList.d.ts.map +1 -1
  147. package/dist/OverflowList/OverflowList.js +29 -4
  148. package/dist/Popover/Popover.d.ts.map +1 -1
  149. package/dist/Popover/Popover.js +3 -2
  150. package/dist/Popover/usePopover.d.ts.map +1 -1
  151. package/dist/Popover/usePopover.js +3 -9
  152. package/dist/PowerSearch/PowerSearchEditPopover.js +1 -1
  153. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  154. package/dist/SelectableCard/SelectableCard.d.ts +9 -2
  155. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  156. package/dist/SelectableCard/SelectableCard.js +16 -13
  157. package/dist/Selector/Selector.d.ts.map +1 -1
  158. package/dist/Selector/Selector.js +4 -2
  159. package/dist/Selector/hooks.d.ts.map +1 -1
  160. package/dist/Selector/hooks.js +16 -0
  161. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  162. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  163. package/dist/SideNav/SideNavHeading.js +21 -8
  164. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  165. package/dist/Slider/Slider.d.ts.map +1 -1
  166. package/dist/Slider/Slider.js +19 -2
  167. package/dist/Stack/stack.stylex.d.ts +9 -9
  168. package/dist/Table/BaseTable.d.ts.map +1 -1
  169. package/dist/Table/BaseTable.js +3 -2
  170. package/dist/Table/index.d.ts +2 -0
  171. package/dist/Table/index.d.ts.map +1 -1
  172. package/dist/Table/index.js +1 -0
  173. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  174. package/dist/Table/plugins/rowStatus/index.d.ts +3 -0
  175. package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -0
  176. package/dist/Table/plugins/rowStatus/index.js +3 -0
  177. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +60 -0
  178. package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -0
  179. package/dist/Table/plugins/rowStatus/useTableRowStatus.js +145 -0
  180. package/dist/Table/plugins/selection/useTableSelection.d.ts +13 -0
  181. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  182. package/dist/Table/plugins/selection/useTableSelection.js +4 -1
  183. package/dist/Table/plugins/tree/useTableTreeData.d.ts +16 -0
  184. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  185. package/dist/Table/plugins/tree/useTableTreeData.js +87 -0
  186. package/dist/Table/plugins/tree/useTableTreeState.d.ts +6 -0
  187. package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -1
  188. package/dist/Table/plugins/tree/useTableTreeState.js +22 -1
  189. package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
  190. package/dist/Table/useBaseTablePlugins.js +5 -3
  191. package/dist/Thumbnail/Thumbnail.d.ts +26 -5
  192. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  193. package/dist/Thumbnail/Thumbnail.js +97 -54
  194. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts +9 -0
  195. package/dist/Thumbnail/thumbnail.markers.stylex.d.ts.map +1 -0
  196. package/dist/Thumbnail/thumbnail.markers.stylex.js +14 -0
  197. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  198. package/dist/TimeInput/TimeInput.js +15 -4
  199. package/dist/Timestamp/Timestamp.d.ts +3 -1
  200. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  201. package/dist/Timestamp/Timestamp.js +8 -6
  202. package/dist/Toast/useToast.d.ts.map +1 -1
  203. package/dist/Toast/useToast.js +2 -5
  204. package/dist/ToggleButton/ToggleButtonGroup.d.ts +0 -1
  205. package/dist/ToggleButton/ToggleButtonGroup.d.ts.map +1 -1
  206. package/dist/ToggleButton/ToggleButtonGroup.js +1 -1
  207. package/dist/Tokenizer/Tokenizer.d.ts +1 -1
  208. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  209. package/dist/Tokenizer/Tokenizer.js +16 -4
  210. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  211. package/dist/TopNav/TopNavHeading.js +18 -8
  212. package/dist/TopNav/TopNavMegaMenu.js +10 -4
  213. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +9 -1
  214. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  215. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +8 -1
  216. package/dist/TopNav/TopNavMenu.d.ts +2 -1
  217. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  218. package/dist/TopNav/TopNavMenu.js +68 -6
  219. package/dist/TreeList/TreeList.d.ts +12 -3
  220. package/dist/TreeList/TreeList.d.ts.map +1 -1
  221. package/dist/TreeList/TreeList.js +2 -0
  222. package/dist/TreeList/TreeListBranches.d.ts +5 -0
  223. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  224. package/dist/TreeList/TreeListBranches.js +10 -4
  225. package/dist/TreeList/TreeListItem.d.ts +8 -2
  226. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  227. package/dist/TreeList/TreeListItem.js +27 -7
  228. package/dist/TreeList/TreeListTypes.d.ts +25 -1
  229. package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
  230. package/dist/TreeList/index.d.ts +2 -2
  231. package/dist/TreeList/index.d.ts.map +1 -1
  232. package/dist/astryx.css +28 -18
  233. package/dist/astryx.umd.js +51 -51
  234. package/dist/astryx.umd.js.map +4 -4
  235. package/dist/authoring/doc.d.ts.map +1 -1
  236. package/dist/docs-types.d.ts +8 -0
  237. package/dist/docs-types.d.ts.map +1 -1
  238. package/dist/hooks/computeOverflow.d.ts +47 -0
  239. package/dist/hooks/computeOverflow.d.ts.map +1 -0
  240. package/dist/hooks/computeOverflow.js +213 -0
  241. package/dist/hooks/index.d.ts +1 -0
  242. package/dist/hooks/index.d.ts.map +1 -1
  243. package/dist/hooks/index.js +2 -1
  244. package/dist/hooks/useDevWarning.d.ts +18 -0
  245. package/dist/hooks/useDevWarning.d.ts.map +1 -0
  246. package/dist/hooks/useDevWarning.js +49 -0
  247. package/dist/hooks/useOverflow.d.ts +19 -0
  248. package/dist/hooks/useOverflow.d.ts.map +1 -1
  249. package/dist/hooks/useOverflow.js +36 -25
  250. package/dist/i18n/resolve.d.ts.map +1 -1
  251. package/dist/i18n/resolve.js +7 -18
  252. package/dist/theme/Theme.d.ts.map +1 -1
  253. package/dist/theme/Theme.js +2 -7
  254. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  255. package/dist/theme/generateThemeRules.js +51 -0
  256. package/dist/theme/hct.d.ts +0 -1
  257. package/dist/theme/hct.d.ts.map +1 -1
  258. package/dist/theme/hct.js +1 -1
  259. package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
  260. package/dist/theme/syntax/defineSyntaxTheme.js +2 -1
  261. package/dist/utils/devWarning.d.ts +42 -0
  262. package/dist/utils/devWarning.d.ts.map +1 -0
  263. package/dist/utils/devWarning.js +88 -0
  264. package/dist/utils/index.d.ts +3 -1
  265. package/dist/utils/index.d.ts.map +1 -1
  266. package/dist/utils/index.js +3 -2
  267. package/dist/utils/plainDate.d.ts +30 -0
  268. package/dist/utils/plainDate.d.ts.map +1 -1
  269. package/dist/utils/plainDate.js +53 -0
  270. package/dist/utils/types.d.ts +13 -0
  271. package/dist/utils/types.d.ts.map +1 -1
  272. package/locales/en.json +24 -0
  273. package/locales/fr-FR.json +14 -0
  274. package/locales/pseudo.json +18 -0
  275. package/package.json +1 -1
  276. package/src/AppShell/AppShell.tsx +6 -0
  277. package/src/AppShell/AppShellMobileContext.tsx +8 -0
  278. package/src/AppShell/useAppShellMobile.doc.mjs +8 -0
  279. package/src/Avatar/Avatar.doc.mjs +15 -3
  280. package/src/Avatar/Avatar.test.tsx +156 -1
  281. package/src/Avatar/Avatar.tsx +96 -4
  282. package/src/Avatar/AvatarStatusDot.doc.mjs +23 -12
  283. package/src/Avatar/AvatarStatusDot.test.tsx +284 -0
  284. package/src/Avatar/AvatarStatusDot.tsx +178 -21
  285. package/src/Banner/Banner.doc.mjs +9 -0
  286. package/src/Banner/Banner.test.tsx +30 -0
  287. package/src/Banner/Banner.tsx +47 -3
  288. package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +26 -0
  289. package/src/Breadcrumbs/BreadcrumbItem.tsx +333 -14
  290. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -0
  291. package/src/Breadcrumbs/Breadcrumbs.test.tsx +284 -2
  292. package/src/Breadcrumbs/index.ts +27 -0
  293. package/src/Button/Button.doc.mjs +9 -0
  294. package/src/Button/Button.test.tsx +49 -0
  295. package/src/Button/Button.tsx +25 -1
  296. package/src/ButtonGroup/ButtonGroup.doc.mjs +3 -0
  297. package/src/ButtonGroup/ButtonGroup.test.tsx +37 -0
  298. package/src/ButtonGroup/ButtonGroup.tsx +32 -0
  299. package/src/Calendar/Calendar.doc.mjs +12 -1
  300. package/src/Calendar/Calendar.test.tsx +193 -0
  301. package/src/Calendar/Calendar.tsx +38 -16
  302. package/src/Calendar/dayCellUtils.test.ts +5 -0
  303. package/src/Calendar/dayCellUtils.ts +1 -1
  304. package/src/Card/Card.doc.mjs +9 -0
  305. package/src/Card/Card.test.tsx +21 -3
  306. package/src/Card/Card.tsx +35 -2
  307. package/src/Carousel/Carousel.doc.mjs +1 -0
  308. package/src/Carousel/Carousel.test.tsx +53 -0
  309. package/src/Carousel/Carousel.tsx +34 -4
  310. package/src/Chat/ChatComposer.doc.mjs +12 -3
  311. package/src/Chat/ChatComposer.test.tsx +115 -0
  312. package/src/Chat/ChatComposer.tsx +73 -9
  313. package/src/Chat/ChatComposerDrawer.test.tsx +61 -0
  314. package/src/Chat/ChatComposerDrawer.tsx +11 -1
  315. package/src/Chat/ChatComposerInput.doc.mjs +7 -0
  316. package/src/Chat/ChatComposerInput.test.tsx +103 -0
  317. package/src/Chat/ChatComposerInput.tsx +49 -3
  318. package/src/Chat/ChatContext.tsx +37 -10
  319. package/src/Chat/ChatDictationButton.tsx +4 -1
  320. package/src/Chat/ChatLayout.tsx +3 -1
  321. package/src/Chat/ChatLayoutScrollButton.tsx +7 -2
  322. package/src/Chat/ChatMessageMetadata.tsx +1 -2
  323. package/src/Chat/ChatSendButton.tsx +11 -1
  324. package/src/Chat/ChatToolCalls.test.tsx +64 -0
  325. package/src/Chat/ChatToolCalls.tsx +25 -4
  326. package/src/Chat/index.ts +5 -1
  327. package/src/Chat/useChatStreamScroll.test.tsx +49 -0
  328. package/src/Chat/useChatStreamScroll.ts +27 -10
  329. package/src/Chat/useSpeechRecognition.ts +1 -1
  330. package/src/Chat/useTriggerMenu.tsx +3 -1
  331. package/src/CheckboxInput/CheckboxInput.test.tsx +32 -1
  332. package/src/CheckboxInput/CheckboxInput.tsx +1 -1
  333. package/src/CheckboxList/CheckboxList.test.tsx +81 -3
  334. package/src/CheckboxList/CheckboxListItem.doc.mjs +33 -5
  335. package/src/CheckboxList/CheckboxListItem.tsx +41 -5
  336. package/src/ClickableCard/ClickableCard.doc.mjs +2 -0
  337. package/src/ClickableCard/ClickableCard.test.tsx +34 -0
  338. package/src/ClickableCard/ClickableCard.tsx +13 -3
  339. package/src/CodeBlock/CodeBlock.test.tsx +56 -0
  340. package/src/CodeBlock/CodeBlock.tsx +9 -1
  341. package/src/CommandPalette/CommandPalette.doc.mjs +1 -0
  342. package/src/CommandPalette/CommandPalette.tsx +3 -1
  343. package/src/CommandPalette/CommandPaletteGroup.test.tsx +71 -0
  344. package/src/CommandPalette/CommandPaletteGroup.tsx +12 -1
  345. package/src/CommandPalette/CommandPaletteInput.doc.mjs +26 -9
  346. package/src/CommandPalette/CommandPaletteInput.test.tsx +34 -0
  347. package/src/CommandPalette/CommandPaletteInput.tsx +11 -0
  348. package/src/ContextMenu/ContextMenu.test.tsx +193 -0
  349. package/src/DateInput/DateInput.doc.mjs +16 -0
  350. package/src/DateInput/DateInput.test.tsx +108 -0
  351. package/src/DateInput/DateInput.tsx +68 -3
  352. package/src/DateInput/index.ts +1 -0
  353. package/src/DateTimeInput/DateTimeInput.test.tsx +35 -0
  354. package/src/DateTimeInput/DateTimeInput.tsx +14 -2
  355. package/src/Dialog/Dialog.doc.mjs +2 -2
  356. package/src/Dialog/Dialog.test.tsx +77 -4
  357. package/src/Dialog/Dialog.tsx +89 -5
  358. package/src/Dialog/DialogContext.ts +9 -2
  359. package/src/Dialog/DialogHeader.doc.mjs +2 -2
  360. package/src/Dialog/DialogHeader.tsx +9 -2
  361. package/src/Divider/Divider.tsx +2 -2
  362. package/src/DropdownMenu/DropdownMenu.test.tsx +169 -0
  363. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -2
  364. package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +1 -2
  365. package/src/Field/Field.test.tsx +57 -12
  366. package/src/Field/Field.tsx +6 -5
  367. package/src/Field/FieldLabel.tsx +8 -0
  368. package/src/FieldStatus/FieldStatus.doc.mjs +17 -5
  369. package/src/FieldStatus/FieldStatus.test.tsx +78 -40
  370. package/src/FieldStatus/FieldStatus.tsx +22 -4
  371. package/src/FileInput/FileInput.test.tsx +52 -3
  372. package/src/FileInput/FileInput.tsx +13 -2
  373. package/src/HoverCard/HoverCard.doc.mjs +13 -0
  374. package/src/HoverCard/HoverCard.test.tsx +21 -2
  375. package/src/HoverCard/HoverCard.tsx +11 -0
  376. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  377. package/src/HoverCard/useHoverCard.tsx +24 -2
  378. package/src/Icon/Icon.doc.mjs +3 -2
  379. package/src/Icon/Icon.tsx +7 -2
  380. package/src/IconButton/IconButton.doc.mjs +8 -0
  381. package/src/IconButton/IconButton.test.tsx +15 -18
  382. package/src/Item/Item.test.tsx +40 -18
  383. package/src/Item/Item.tsx +38 -2
  384. package/src/Layer/useLayer.tsx +8 -0
  385. package/src/List/List.test.tsx +9 -8
  386. package/src/MobileNav/MobileNav.tsx +12 -1
  387. package/src/MobileNav/MobileNavToggle.test.tsx +116 -0
  388. package/src/MobileNav/MobileNavToggle.tsx +9 -1
  389. package/src/MultiSelector/MultiSelector.doc.mjs +4 -2
  390. package/src/MultiSelector/MultiSelector.test.tsx +172 -3
  391. package/src/MultiSelector/MultiSelector.tsx +55 -12
  392. package/src/MultiSelector/hooks.ts +17 -0
  393. package/src/NumberInput/NumberInput.test.tsx +11 -7
  394. package/src/NumberInput/NumberInput.tsx +1 -2
  395. package/src/Outline/Outline.tsx +0 -1
  396. package/src/OverflowList/OverflowList.doc.mjs +39 -6
  397. package/src/OverflowList/OverflowList.test.tsx +111 -0
  398. package/src/OverflowList/OverflowList.tsx +48 -8
  399. package/src/Popover/Popover.tsx +7 -4
  400. package/src/Popover/usePopover.tsx +9 -13
  401. package/src/PowerSearch/PowerSearch.doc.mjs +14 -0
  402. package/src/PowerSearch/PowerSearch.test.tsx +20 -0
  403. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +67 -0
  404. package/src/PowerSearch/PowerSearchEditPopover.tsx +1 -1
  405. package/src/PowerSearch/usePowerSearchSource.ts +1 -2
  406. package/src/SelectableCard/SelectableCard.doc.mjs +2 -0
  407. package/src/SelectableCard/SelectableCard.test.tsx +46 -4
  408. package/src/SelectableCard/SelectableCard.tsx +29 -16
  409. package/src/Selector/Selector.test.tsx +69 -0
  410. package/src/Selector/Selector.tsx +5 -1
  411. package/src/Selector/hooks.ts +17 -0
  412. package/src/SideNav/SideNav.test.tsx +119 -3
  413. package/src/SideNav/SideNavCollapseButton.tsx +6 -1
  414. package/src/SideNav/SideNavHeading.tsx +24 -8
  415. package/src/SideNav/SideNavItem.tsx +5 -1
  416. package/src/Slider/Slider.test.tsx +75 -2
  417. package/src/Slider/Slider.tsx +21 -5
  418. package/src/Switch/Switch.test.tsx +32 -1
  419. package/src/Table/BaseTable.tsx +3 -5
  420. package/src/Table/index.ts +5 -0
  421. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +6 -2
  422. package/src/Table/plugins/rowStatus/index.ts +7 -0
  423. package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +138 -0
  424. package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +189 -0
  425. package/src/Table/plugins/selection/useTableSelection.test.tsx +16 -0
  426. package/src/Table/plugins/selection/useTableSelection.tsx +19 -1
  427. package/src/Table/plugins/tree/useTableTreeData.test.tsx +135 -3
  428. package/src/Table/plugins/tree/useTableTreeData.tsx +128 -1
  429. package/src/Table/plugins/tree/useTableTreeState.test.tsx +104 -0
  430. package/src/Table/plugins/tree/useTableTreeState.tsx +46 -2
  431. package/src/Table/useBaseTablePlugins.ts +10 -6
  432. package/src/Table/useTableRowStatus.doc.mjs +30 -0
  433. package/src/Table/useTableSelection.doc.mjs +65 -14
  434. package/src/Table/useTableTreeData.doc.mjs +29 -0
  435. package/src/Table/useTableTreeState.doc.mjs +2 -2
  436. package/src/TextArea/TextArea.test.tsx +9 -1
  437. package/src/Thumbnail/Thumbnail.doc.mjs +19 -10
  438. package/src/Thumbnail/Thumbnail.test.tsx +98 -7
  439. package/src/Thumbnail/Thumbnail.tsx +141 -41
  440. package/src/Thumbnail/thumbnail.markers.stylex.ts +12 -0
  441. package/src/TimeInput/TimeInput.test.tsx +76 -1
  442. package/src/TimeInput/TimeInput.tsx +19 -6
  443. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  444. package/src/Timestamp/Timestamp.test.tsx +32 -0
  445. package/src/Timestamp/Timestamp.tsx +28 -8
  446. package/src/Toast/useToast.tsx +7 -8
  447. package/src/ToggleButton/ToggleButtonGroup.tsx +1 -1
  448. package/src/Tokenizer/Tokenizer.doc.mjs +15 -1
  449. package/src/Tokenizer/Tokenizer.test.tsx +183 -2
  450. package/src/Tokenizer/Tokenizer.tsx +16 -4
  451. package/src/TopNav/TopNav.test.tsx +125 -1
  452. package/src/TopNav/TopNavHeading.tsx +24 -8
  453. package/src/TopNav/TopNavMegaMenu.test.tsx +149 -1
  454. package/src/TopNav/TopNavMegaMenu.tsx +10 -4
  455. package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +3 -3
  456. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +19 -2
  457. package/src/TopNav/TopNavMenu.test.tsx +118 -4
  458. package/src/TopNav/TopNavMenu.tsx +83 -5
  459. package/src/TreeList/TreeList.doc.mjs +22 -0
  460. package/src/TreeList/TreeList.test.tsx +232 -0
  461. package/src/TreeList/TreeList.tsx +18 -2
  462. package/src/TreeList/TreeListBranches.tsx +16 -2
  463. package/src/TreeList/TreeListItem.tsx +51 -11
  464. package/src/TreeList/TreeListTypes.ts +27 -1
  465. package/src/TreeList/index.ts +2 -2
  466. package/src/authoring/doc.ts +1 -3
  467. package/src/docs-types.ts +5 -0
  468. package/src/hooks/computeOverflow.test.ts +422 -0
  469. package/src/hooks/computeOverflow.ts +290 -0
  470. package/src/hooks/index.ts +2 -0
  471. package/src/hooks/useDevWarning.test.tsx +45 -0
  472. package/src/hooks/useDevWarning.ts +54 -0
  473. package/src/hooks/useOverflow.test.ts +96 -4
  474. package/src/hooks/useOverflow.ts +74 -33
  475. package/src/i18n/InternationalizationProvider.doc.mjs +99 -2
  476. package/src/i18n/resolve.ts +9 -21
  477. package/src/theme/Theme.tsx +11 -14
  478. package/src/theme/generateThemeRules.test.ts +65 -0
  479. package/src/theme/generateThemeRules.ts +56 -0
  480. package/src/theme/hct.ts +1 -1
  481. package/src/theme/syntax/defineSyntaxTheme.ts +5 -6
  482. package/src/utils/devWarning.test.ts +56 -0
  483. package/src/utils/devWarning.ts +102 -0
  484. package/src/utils/index.ts +6 -0
  485. package/src/utils/plainDate.test.ts +22 -0
  486. package/src/utils/plainDate.ts +61 -0
  487. package/src/utils/types.ts +14 -0
@@ -16,7 +16,10 @@ import {getButton} from '../__tests__/fastRoleQueries';
16
16
  import * as stylex from '@stylexjs/stylex';
17
17
  import {Calendar} from './Calendar';
18
18
  import type {CalendarHandle} from './Calendar';
19
+ import type {ISODateString} from './Calendar';
19
20
  import {calendarStyles} from './styles';
21
+ import {defineTheme} from '../theme/defineTheme';
22
+ import {generateThemeCSSFlat} from '../theme/generateThemeRules';
20
23
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
21
24
 
22
25
  afterEach(() => {
@@ -881,4 +884,194 @@ describe('Calendar', () => {
881
884
  expect(screen.getByText('February 2026')).toBeInTheDocument();
882
885
  });
883
886
  });
887
+
888
+
889
+ // ─── Day-cell marker theming (#4286) ─────────────────────────
890
+ describe('day-cell marker theme state', () => {
891
+ // Tests use the real "today" (as the existing aria-current tests do) since
892
+ // Calendar derives it internally. Helpers pin the exact ISO strings.
893
+ function todayISO(): ISODateString {
894
+ const n = new Date();
895
+ return `${n.getFullYear()}-${String(n.getMonth() + 1).padStart(2, '0')}-${String(n.getDate()).padStart(2, '0')}` as ISODateString;
896
+ }
897
+ function isoOffsetFromToday(deltaDays: number): ISODateString {
898
+ const n = new Date();
899
+ n.setDate(n.getDate() + deltaDays);
900
+ return `${n.getFullYear()}-${String(n.getMonth() + 1).padStart(2, '0')}-${String(n.getDate()).padStart(2, '0')}` as ISODateString;
901
+ }
902
+ function todayCell(): HTMLElement {
903
+ const el = document.querySelector<HTMLElement>(
904
+ `button[data-date="${todayISO()}"]`,
905
+ );
906
+ expect(el).not.toBeNull();
907
+ return el as HTMLElement;
908
+ }
909
+
910
+ it('reflects marker="today-only" for a plain today cell (no selection)', () => {
911
+ render(<Calendar />);
912
+ const cell = todayCell();
913
+ expect(cell).toHaveAttribute('data-marker', 'today-only');
914
+ expect(cell).toHaveAttribute('data-today', 'today');
915
+ expect(cell).not.toHaveAttribute('data-selected');
916
+ expect(cell).not.toHaveAttribute('data-in-range');
917
+ });
918
+
919
+ it('reflects marker="today-in-range" when today is strictly inside a range', () => {
920
+ render(
921
+ <Calendar
922
+ mode="range"
923
+ value={{start: isoOffsetFromToday(-2), end: isoOffsetFromToday(2)}}
924
+ />,
925
+ );
926
+ const cell = todayCell();
927
+ // Today is inside the range but not an endpoint: the today-in-range ring
928
+ // is shown, so `marker` reflects that compound state precisely.
929
+ expect(cell).toHaveAttribute('data-marker', 'today-in-range');
930
+ expect(cell).toHaveAttribute('data-in-range', 'in-range');
931
+ expect(cell).not.toHaveAttribute('data-selected');
932
+ });
933
+
934
+ it('shows no marker state when today is the single-selected date', () => {
935
+ render(<Calendar mode="single" value={todayISO()} />);
936
+ const cell = todayCell();
937
+ // A single-mode selected cell shows no ring by default — `marker` is
938
+ // absent, while `selected` (which owns the selected treatment) is present.
939
+ expect(cell).not.toHaveAttribute('data-marker');
940
+ expect(cell).toHaveAttribute('data-selected', 'selected');
941
+ expect(cell).toHaveAttribute('data-today', 'today');
942
+ });
943
+
944
+ it('preserves the today-in-range ring on a today range endpoint', () => {
945
+ render(
946
+ <Calendar
947
+ mode="range"
948
+ value={{start: todayISO(), end: isoOffsetFromToday(3)}}
949
+ />,
950
+ );
951
+ const cell = todayCell();
952
+ // A range endpoint is NOT `isSelected` (that flag is single-mode only),
953
+ // so by default the today-in-range ring IS drawn on a today endpoint
954
+ // alongside the endpoint styling. `marker` mirrors that exactly — this
955
+ // asserts the default rendering is preserved, byte-for-byte.
956
+ expect(cell).toHaveAttribute('data-marker', 'today-in-range');
957
+ expect(cell).toHaveAttribute('data-in-range', 'in-range');
958
+ });
959
+
960
+ it('omits the marker state for non-today cells', () => {
961
+ render(<Calendar />);
962
+ const other = document.querySelector(
963
+ `button[data-date="${isoOffsetFromToday(1)}"]`,
964
+ );
965
+ // Guard against the +1 day landing in an adjacent month with outside days
966
+ // hidden; if present it must carry no marker.
967
+ if (other) {
968
+ expect(other).not.toHaveAttribute('data-marker');
969
+ }
970
+ });
971
+
972
+ it('exposes the marker states as themeable defineTheme targets', () => {
973
+ // jsdom can't resolve the @layer cascade, so the DOM-reflection tests
974
+ // above cover that the right state renders; this asserts the state is
975
+ // reachable by a theme via the sanctioned defineTheme channel.
976
+ const theme = defineTheme({
977
+ name: 'calendar-marker-test',
978
+ components: {
979
+ 'calendar-day': {
980
+ 'marker:today-only': {
981
+ boxShadow: 'inset 0 0 0 2px var(--color-accent)',
982
+ },
983
+ 'marker:today-in-range': {
984
+ boxShadow: 'inset 0 0 0 2px var(--color-text-primary)',
985
+ },
986
+ },
987
+ },
988
+ });
989
+ const css = generateThemeCSSFlat(theme);
990
+ expect(css).toContain('.astryx-calendar-day.today-only');
991
+ expect(css).toContain('.astryx-calendar-day.today-in-range');
992
+ expect(css).toContain('box-shadow: inset 0 0 0 2px var(--color-accent)');
993
+ expect(css).toContain(
994
+ 'box-shadow: inset 0 0 0 2px var(--color-text-primary)',
995
+ );
996
+ });
997
+ });
998
+
999
+ // ─── Theming targets ─────────────────────────────────────────
1000
+ describe('theming targets', () => {
1001
+ it('renders the astryx-calendar-nav target on both month-nav buttons', () => {
1002
+ render(<Calendar focusDate="2026-01-01" />);
1003
+
1004
+ const prev = getButton('Previous month');
1005
+ const next = getButton('Next month');
1006
+
1007
+ // Dedicated, stable theme target — scoped to the nav controls, not the
1008
+ // global astryx-button handle that hits every Button in the app.
1009
+ expect(prev).toHaveClass('astryx-calendar-nav');
1010
+ expect(next).toHaveClass('astryx-calendar-nav');
1011
+
1012
+ // Direction is reflected so a theme can target one arrow alone.
1013
+ expect(prev).toHaveAttribute('data-nav', 'prev');
1014
+ expect(next).toHaveAttribute('data-nav', 'next');
1015
+ });
1016
+
1017
+ it('reflects the disabled nav state as a data attribute at the range edges', () => {
1018
+ // Clamp navigation so "Previous month" is disabled and "Next" is not.
1019
+ render(
1020
+ <Calendar focusDate="2026-01-15" min="2026-01-01" max="2026-03-31" />,
1021
+ );
1022
+
1023
+ const prev = getButton('Previous month');
1024
+ const next = getButton('Next month');
1025
+
1026
+ expect(prev).toHaveAttribute('data-disabled', 'disabled');
1027
+ expect(next).not.toHaveAttribute('data-disabled');
1028
+ });
1029
+
1030
+ it('keeps the default nav rendering unchanged (still a ghost icon button)', () => {
1031
+ render(<Calendar focusDate="2026-01-01" />);
1032
+
1033
+ // The new target is additive — the nav still carries the stock Button
1034
+ // classes, so default appearance is preserved.
1035
+ const prev = getButton('Previous month');
1036
+ expect(prev).toHaveClass('astryx-button');
1037
+ expect(prev).toHaveClass('ghost');
1038
+ expect(prev.tagName).toBe('BUTTON');
1039
+ });
1040
+
1041
+ it('renders the astryx-calendar-day target with its reflected states', () => {
1042
+ render(
1043
+ <Calendar mode="single" value="2026-01-15" focusDate="2026-01-01" />,
1044
+ );
1045
+
1046
+ const selected = getDayButton(15);
1047
+ expect(selected).toHaveClass('astryx-calendar-day');
1048
+ expect(selected).toHaveAttribute('data-selected', 'selected');
1049
+
1050
+ // A non-selected weekday cell still carries the base target and no
1051
+ // selected/today reflection.
1052
+ const plain = getDayButton(20);
1053
+ expect(plain).toHaveClass('astryx-calendar-day');
1054
+ expect(plain).not.toHaveAttribute('data-selected');
1055
+ });
1056
+
1057
+ it('exposes calendar-nav as a themeable defineTheme target', () => {
1058
+ // The generated CSS is what proves the target is reachable by a theme:
1059
+ // jsdom cannot resolve the @layer cascade, so the DOM-class assertions
1060
+ // above and this generation assertion together cover the seam.
1061
+ const theme = defineTheme({
1062
+ name: 'calendar-nav-test',
1063
+ components: {
1064
+ 'calendar-nav': {
1065
+ base: {color: 'var(--color-accent)'},
1066
+ 'nav:next': {backgroundColor: 'var(--color-accent-muted)'},
1067
+ },
1068
+ },
1069
+ });
1070
+ const css = generateThemeCSSFlat(theme);
1071
+ expect(css).toContain('.astryx-calendar-nav {');
1072
+ expect(css).toContain('color: var(--color-accent)');
1073
+ expect(css).toContain('.astryx-calendar-nav.next');
1074
+ expect(css).toContain('background-color: var(--color-accent-muted)');
1075
+ });
1076
+ });
884
1077
  });
@@ -452,6 +452,10 @@ export function Calendar({ref, ...props}: CalendarProps) {
452
452
  {/* Header with navigation */}
453
453
  <div {...stylex.props(calendarStyles.header)}>
454
454
  <Button
455
+ {...themeProps('calendar-nav', {
456
+ nav: 'prev',
457
+ disabled: !canNavigatePrevious ? 'disabled' : null,
458
+ })}
455
459
  label={t('@astryx.calendar.previousMonth')}
456
460
  variant="ghost"
457
461
  icon={
@@ -472,6 +476,10 @@ export function Calendar({ref, ...props}: CalendarProps) {
472
476
  </span>
473
477
 
474
478
  <Button
479
+ {...themeProps('calendar-nav', {
480
+ nav: 'next',
481
+ disabled: !canNavigateNext ? 'disabled' : null,
482
+ })}
475
483
  label={t('@astryx.calendar.nextMonth')}
476
484
  variant="ghost"
477
485
  icon={
@@ -941,6 +949,21 @@ function DayCell({
941
949
  });
942
950
 
943
951
  const endpoint = isEndpoint(state);
952
+
953
+ // The day's focus-ring treatment, derived once so the reflected `marker`
954
+ // theme state and the StyleX ring styles below share a single source of
955
+ // truth. `state.isSelected` is single-select only, so a range endpoint that
956
+ // is today still qualifies for the today-in-range ring (unchanged prior
957
+ // behavior).
958
+ const showsTodayRing = state.isToday && !state.isSelected && !state.isInRange;
959
+ const showsTodayInRangeRing =
960
+ state.isToday && !state.isSelected && state.isInRange;
961
+ const markerState: 'today-only' | 'today-in-range' | null = showsTodayRing
962
+ ? 'today-only'
963
+ : showsTodayInRangeRing
964
+ ? 'today-in-range'
965
+ : null;
966
+
944
967
  const rangeRounding = computeRangeRounding(state, {
945
968
  prevInRange: neighbors.prevInRange,
946
969
  nextInRange: neighbors.nextInRange,
@@ -1010,28 +1033,27 @@ function DayCell({
1010
1033
  today: state.isToday ? 'today' : null,
1011
1034
  disabled: state.effectivelyDisabled ? 'disabled' : null,
1012
1035
  'in-range': state.isInRange ? 'in-range' : null,
1036
+ // `marker` reflects the day's *actual* focus-ring treatment as a
1037
+ // single compound state, so a theme can target exactly the states
1038
+ // the ring is drawn under without needing `:not()` in the theme
1039
+ // key. It is null unless a ring is shown:
1040
+ // 'today-only' → today, not single-selected, not in a range
1041
+ // 'today-in-range' → today, not single-selected, inside a range
1042
+ // `isSelected` here is single-select only (see computeDayCellState),
1043
+ // so a today range endpoint still shows the today-in-range ring —
1044
+ // `marker` mirrors the StyleX conditions below exactly, preserving
1045
+ // the default rendering.
1046
+ marker: markerState,
1013
1047
  }),
1014
1048
  stylex.props(
1015
1049
  dayCellStyles.day,
1016
1050
  dayCellTheme.day,
1017
1051
  isOutside && dayCellStyles.dayOutside,
1018
1052
  isOutside && dayCellTheme.dayOutside,
1019
- state.isToday &&
1020
- !state.isSelected &&
1021
- !state.isInRange &&
1022
- dayCellStyles.dayToday,
1023
- state.isToday &&
1024
- !state.isSelected &&
1025
- !state.isInRange &&
1026
- dayCellTheme.dayToday,
1027
- state.isToday &&
1028
- !state.isSelected &&
1029
- state.isInRange &&
1030
- dayCellStyles.dayTodayInRange,
1031
- state.isToday &&
1032
- !state.isSelected &&
1033
- state.isInRange &&
1034
- dayCellTheme.dayTodayInRange,
1053
+ showsTodayRing && dayCellStyles.dayToday,
1054
+ showsTodayRing && dayCellTheme.dayToday,
1055
+ showsTodayInRangeRing && dayCellStyles.dayTodayInRange,
1056
+ showsTodayInRangeRing && dayCellTheme.dayTodayInRange,
1035
1057
  endpoint && dayCellStyles.daySelected,
1036
1058
  endpoint && dayCellTheme.daySelected,
1037
1059
  state.effectivelyDisabled && dayCellStyles.dayDisabled,
@@ -45,6 +45,11 @@ describe('computeDayCellState', () => {
45
45
  expect(state.isToday).toBe(false);
46
46
  });
47
47
 
48
+ it('does not identify an outside day as today', () => {
49
+ const state = computeDayCellState(makeInput({isOutside: true}));
50
+ expect(state.isToday).toBe(false);
51
+ });
52
+
48
53
  it('identifies selected day in single mode', () => {
49
54
  const state = computeDayCellState(
50
55
  makeInput({selectedDate: plainDateFromISO('2024-03-15')}),
@@ -56,7 +56,7 @@ export function computeDayCellState(input: DayCellStateInput): DayCellState {
56
56
 
57
57
  return {
58
58
  effectivelyDisabled: isDisabled || isOutside,
59
- isToday: plainDateIsEqual(date, today),
59
+ isToday: !isOutside && plainDateIsEqual(date, today),
60
60
  isSelected: !!(
61
61
  !isOutside &&
62
62
  mode === 'single' &&
@@ -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,
@@ -91,6 +91,7 @@ export const docsDense = {
91
91
  {guidance: true, description: 'Enable scroll-snap when each item should land precisely at the start edge: gallery, product list.'},
92
92
  {guidance: true, description: 'Always provide an aria-label describing what the carousel contains: "Featured products", "Team members".'},
93
93
  {guidance: true, description: 'Use consistent gap + item width so the carousel looks intentional, not like content overflowing by accident.'},
94
+ {guidance: true, description: 'Trust built-in navigation: trackpad users swipe horizontally, mouse users hold Shift + wheel to move through items.'},
94
95
  {guidance: false, description: 'Use a carousel for content every user must see. Not everyone scrolls horizontally, so put critical content above the fold.'},
95
96
  {guidance: false, description: 'Auto-advance items. Let the user scroll at their own pace.'},
96
97
  {guidance: false, description: 'Nest carousels. A carousel inside a carousel is confusing and breaks keyboard navigation.'},
@@ -92,6 +92,59 @@ describe('Carousel', () => {
92
92
  expect(screen.getByLabelText('Scroll right')).toBeInTheDocument();
93
93
  });
94
94
 
95
+ describe('slide semantics', () => {
96
+ it('exposes each slide as a group with aria-roledescription="slide" and a positional name', () => {
97
+ render(
98
+ <Carousel aria-label="Photos">
99
+ <div>One</div>
100
+ <div>Two</div>
101
+ <div>Three</div>
102
+ </Carousel>,
103
+ );
104
+ // APG carousel pattern: each slide container is role=group with
105
+ // aria-roledescription="slide" and an "N of M" accessible name.
106
+ const slides = screen.getAllByRole('group');
107
+ expect(slides).toHaveLength(3);
108
+ slides.forEach((slide, i) => {
109
+ expect(slide).toHaveAttribute('aria-roledescription', 'slide');
110
+ expect(slide).toHaveAccessibleName(`Slide ${i + 1} of 3`);
111
+ });
112
+ });
113
+
114
+ it('reflects the rendered child count, skipping null and boolean children', () => {
115
+ render(
116
+ <Carousel aria-label="Photos">
117
+ <div>One</div>
118
+ {null}
119
+ {false}
120
+ <div>Two</div>
121
+ </Carousel>,
122
+ );
123
+ const slides = screen.getAllByRole('group');
124
+ expect(slides).toHaveLength(2);
125
+ expect(
126
+ screen.getByRole('group', {name: 'Slide 1 of 2'}),
127
+ ).toBeInTheDocument();
128
+ expect(
129
+ screen.getByRole('group', {name: 'Slide 2 of 2'}),
130
+ ).toBeInTheDocument();
131
+ });
132
+
133
+ it('keeps the container region semantics unchanged around labelled slides', () => {
134
+ render(
135
+ <Carousel aria-label="Gallery">
136
+ <div>One</div>
137
+ <div>Two</div>
138
+ </Carousel>,
139
+ );
140
+ const region = screen.getByRole('region', {name: 'Gallery'});
141
+ expect(region).toHaveAttribute('aria-roledescription', 'carousel');
142
+ const slides = screen.getAllByRole('group');
143
+ expect(slides).toHaveLength(2);
144
+ slides.forEach(slide => expect(region).toContainElement(slide));
145
+ });
146
+ });
147
+
95
148
  it('disables edge scroll buttons instead of removing them from the tab order', () => {
96
149
  // In jsdom there is no measurable overflow, so both edges are at rest and
97
150
  // the scroll buttons are in their hidden/inert state. They must stay
@@ -9,7 +9,10 @@
9
9
  * @position Horizontal scroll container with fade-edge overflow indication,
10
10
  * optional prev/next buttons on the top layer, scroll-snap, a 1px
11
11
  * visual bleed allowance for child selection indicators, and Shift + wheel
12
- * mapping so mouse users can scroll horizontally.
12
+ * mapping so mouse users can scroll horizontally. Exposes APG
13
+ * carousel semantics: the root is a labelled region with
14
+ * aria-roledescription="carousel" and each item wrapper is a group with
15
+ * aria-roledescription="slide" named "Slide N of M".
13
16
  *
14
17
  * SYNC: When modified, update:
15
18
  * - /packages/core/src/Carousel/index.ts (exports)
@@ -17,7 +20,14 @@
17
20
  * - /packages/cli/templates/blocks/components/Carousel/ (showcase blocks)
18
21
  */
19
22
 
20
- import {type ReactNode, useRef, useCallback, useEffect, Children} from 'react';
23
+ import {
24
+ type ReactNode,
25
+ useRef,
26
+ useCallback,
27
+ useEffect,
28
+ Children,
29
+ isValidElement,
30
+ } from 'react';
21
31
  import * as stylex from '@stylexjs/stylex';
22
32
  import {
23
33
  spacingVars,
@@ -270,6 +280,11 @@ export function Carousel({
270
280
  const scrollElRef = useRef<HTMLElement | null>(null);
271
281
  const {scrollRef, overflowStart, overflowEnd} = useScrollOverflow();
272
282
 
283
+ // Children.toArray drops null/undefined/boolean children and assigns
284
+ // stable keys, so slide numbering ("Slide N of M") matches what actually
285
+ // renders even when some children are conditionally omitted.
286
+ const slides = Children.toArray(children);
287
+
273
288
  const layer = useLayer({
274
289
  mode: 'context',
275
290
  lightDismiss: false,
@@ -380,8 +395,23 @@ export function Carousel({
380
395
  hasSnap && styles.snap,
381
396
  fadeStyle,
382
397
  )}>
383
- {Children.map(children, child => (
384
- <div {...stylex.props(styles.item)}>{child}</div>
398
+ {slides.map((child, index) => (
399
+ // APG carousel pattern: each slide container is a group with
400
+ // aria-roledescription="slide" and an "N of M" accessible name so
401
+ // ATs announce slide boundaries and position instead of anonymous
402
+ // generics.
403
+ <div
404
+ // eslint-disable-next-line @eslint-react/no-array-index-key -- index fallback only applies to text/number children, which are positional by definition; elements keep their Children.toArray keys
405
+ key={isValidElement(child) ? child.key : index}
406
+ role="group"
407
+ aria-roledescription="slide"
408
+ aria-label={t('@astryx.carousel.slideLabel', {
409
+ current: index + 1,
410
+ total: slides.length,
411
+ })}
412
+ {...stylex.props(styles.item)}>
413
+ {child}
414
+ </div>
385
415
  ))}
386
416
  </div>
387
417
 
@@ -56,6 +56,13 @@ export const docs = {
56
56
  description: 'Visual density.',
57
57
  default: "'balanced'",
58
58
  },
59
+ {
60
+ name: 'elevation',
61
+ type: "'none' | 'low'",
62
+ description:
63
+ "Resting elevation of the composer body. `low` (the default) keeps today's raised look — low at rest, bumping to med on hover / focus. `none` flattens it and draws a border with the same rest / hover / focus treatment as a text input (emphasized border → accent on focus, matching inset rings).",
64
+ default: "'low'",
65
+ },
59
66
  {
60
67
  name: 'drawer',
61
68
  type: 'ReactNode',
@@ -102,7 +109,7 @@ export const docs = {
102
109
  {
103
110
  name: 'input',
104
111
  type: 'ReactNode',
105
- description: 'Slot: custom input element. Replaces the default textarea. Use ChatComposerInput for trigger menus.',
112
+ description: 'Slot: custom input element. Replaces the default input. Use ChatComposerInput for trigger menus/tokens, or wire any input (plain textarea, rich editor) to the composition contract via useChatComposerContext() — read value/onChange/onSubmit/canSend and register a focus control on inputControlRef so body-click-to-focus works.',
106
113
  slotElements: [
107
114
  {
108
115
  __element: 'TextInput',
@@ -185,10 +192,11 @@ export const docsZh = {
185
192
  placeholder: '输入为空时显示的占位文本。',
186
193
  isDisabled: '禁用编写器。',
187
194
  density: '视觉密度。',
195
+ elevation: "编写器主体的静止高度。low(默认)保持当前的抬起外观——静止时 low,悬停/聚焦时升至 med。none 则扁平化。",
188
196
  drawer: '插槽:输入上方的可折叠抽屉——附件、上下文标签等。使用 ChatComposerDrawer。',
189
197
  headerActions: '插槽:标题左侧操作按钮(附件、提及按钮)。使用仅图标 size="sm" 按钮。',
190
198
  headerContext: '插槽:标题右侧上下文信息(上下文窗口使用情况、ProgressBar、辅助文本)。',
191
- input: '插槽:自定义输入元素。替换默认文本区域。使用 ChatComposerInput 实现触发菜单。',
199
+ input: '插槽:自定义输入元素。替换默认输入。使用 ChatComposerInput 实现触发菜单/标记,或通过 useChatComposerContext() 将任意输入(纯 textarea、富文本编辑器)接入组合契约——读取 value/onChange/onSubmit/canSend,并在 inputControlRef 上注册聚焦控制,使点击空白处聚焦生效。',
192
200
  footerActions: '插槽:左对齐的页脚操作(模型选择器等)。',
193
201
  sendActions: '插槽:发送按钮左侧的操作。',
194
202
  sendButton: '插槽:自定义发送按钮。替换默认的发送/停止按钮。',
@@ -210,10 +218,11 @@ export const docsDense = {
210
218
  placeholder: 'placeholder when empty',
211
219
  isDisabled: 'disabled; use during streaming or unmet prereqs',
212
220
  density: 'visual density',
221
+ elevation: "resting elevation of composer body: low (default; low→med on hover/focus) | none (flat)",
213
222
  drawer: 'slot: collapsible drawer above input: attachments, context chips, etc.; use ChatComposerDrawer',
214
223
  headerActions: 'slot: left header actions (attach, mention); icon-only sm buttons',
215
224
  headerContext: 'slot: right header context info (window usage, ProgressBar, text)',
216
- input: 'slot: custom input; replaces default textarea; use ChatComposerInput for triggers',
225
+ input: 'slot: custom input; replaces default. use ChatComposerInput for triggers/tokens, or wire any input via useChatComposerContext() (value/onChange/onSubmit/canSend + register focus on inputControlRef)',
217
226
  footerActions: 'slot: left footer actions (model selector etc)',
218
227
  sendActions: 'slot: actions left of send btn',
219
228
  sendButton: 'slot: custom send btn; replaces default',