@astryxdesign/core 0.1.4 → 0.1.5-canary.76e6697

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 (635) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +20 -18
  5. package/dist/AlertDialog/useImperativeAlertDialog.d.ts +0 -2
  6. package/dist/AlertDialog/useImperativeAlertDialog.d.ts.map +1 -1
  7. package/dist/AlertDialog/useImperativeAlertDialog.js +3 -5
  8. package/dist/AppShell/AppShell.d.ts +1 -1
  9. package/dist/AppShell/AppShell.d.ts.map +1 -1
  10. package/dist/AppShell/AppShell.js +55 -53
  11. package/dist/AspectRatio/AspectRatio.d.ts +48 -10
  12. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  13. package/dist/AspectRatio/AspectRatio.js +33 -12
  14. package/dist/AspectRatio/index.d.ts +1 -1
  15. package/dist/AspectRatio/index.d.ts.map +1 -1
  16. package/dist/Avatar/Avatar.d.ts.map +1 -1
  17. package/dist/Avatar/Avatar.js +28 -26
  18. package/dist/Avatar/AvatarStatusDot.js +6 -6
  19. package/dist/AvatarGroup/AvatarGroup.js +6 -6
  20. package/dist/AvatarGroup/AvatarGroupOverflow.js +7 -7
  21. package/dist/Badge/Badge.js +3 -3
  22. package/dist/Banner/Banner.d.ts.map +1 -1
  23. package/dist/Banner/Banner.js +32 -25
  24. package/dist/Blockquote/Blockquote.js +7 -7
  25. package/dist/Breadcrumbs/BreadcrumbItem.js +17 -17
  26. package/dist/Breadcrumbs/Breadcrumbs.js +7 -7
  27. package/dist/Button/Button.js +19 -19
  28. package/dist/ButtonGroup/ButtonGroup.js +7 -7
  29. package/dist/Calendar/Calendar.d.ts.map +1 -1
  30. package/dist/Calendar/Calendar.js +68 -48
  31. package/dist/Calendar/dayCellUtils.d.ts.map +1 -1
  32. package/dist/Calendar/styles.d.ts +2 -2
  33. package/dist/Calendar/styles.d.ts.map +1 -1
  34. package/dist/Calendar/styles.js +2 -2
  35. package/dist/Card/Card.d.ts +4 -2
  36. package/dist/Card/Card.d.ts.map +1 -1
  37. package/dist/Card/Card.js +18 -10
  38. package/dist/Carousel/Carousel.d.ts.map +1 -1
  39. package/dist/Carousel/Carousel.js +24 -21
  40. package/dist/Center/Center.js +3 -3
  41. package/dist/Chat/ChatComposer.js +23 -23
  42. package/dist/Chat/ChatComposerDrawer.js +14 -14
  43. package/dist/Chat/ChatComposerInput.d.ts +1 -1
  44. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  45. package/dist/Chat/ChatComposerInput.js +27 -15
  46. package/dist/Chat/ChatDictationButton.d.ts +1 -1
  47. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  48. package/dist/Chat/ChatDictationButton.js +13 -11
  49. package/dist/Chat/ChatLayout.js +17 -17
  50. package/dist/Chat/ChatLayoutScrollButton.d.ts +1 -1
  51. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  52. package/dist/Chat/ChatLayoutScrollButton.js +12 -10
  53. package/dist/Chat/ChatMessage.js +12 -12
  54. package/dist/Chat/ChatMessageBubble.js +7 -7
  55. package/dist/Chat/ChatMessageList.js +14 -14
  56. package/dist/Chat/ChatMessageMetadata.d.ts +1 -1
  57. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  58. package/dist/Chat/ChatMessageMetadata.js +14 -12
  59. package/dist/Chat/ChatPastedTextToken.js +13 -13
  60. package/dist/Chat/ChatSendButton.js +3 -3
  61. package/dist/Chat/ChatSystemMessage.d.ts +1 -1
  62. package/dist/Chat/ChatSystemMessage.d.ts.map +1 -1
  63. package/dist/Chat/ChatSystemMessage.js +17 -17
  64. package/dist/Chat/ChatTokenizedText.d.ts +1 -1
  65. package/dist/Chat/ChatTokenizedText.d.ts.map +1 -1
  66. package/dist/Chat/ChatTokenizedText.js +24 -15
  67. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  68. package/dist/Chat/ChatToolCalls.js +81 -74
  69. package/dist/Chat/index.d.ts +1 -1
  70. package/dist/Chat/index.d.ts.map +1 -1
  71. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  72. package/dist/Chat/useTriggerMenu.js +15 -15
  73. package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
  74. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  75. package/dist/CheckboxInput/CheckboxInput.js +25 -23
  76. package/dist/CheckboxList/CheckboxList.js +9 -9
  77. package/dist/CheckboxList/CheckboxListItem.d.ts +1 -1
  78. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  79. package/dist/CheckboxList/CheckboxListItem.js +8 -6
  80. package/dist/Citation/Citation.js +10 -10
  81. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  82. package/dist/ClickableCard/ClickableCard.js +32 -9
  83. package/dist/Code/Code.js +3 -3
  84. package/dist/CodeBlock/CodeBlock.d.ts +10 -1
  85. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  86. package/dist/CodeBlock/CodeBlock.js +88 -52
  87. package/dist/Collapsible/Collapsible.d.ts +9 -3
  88. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  89. package/dist/Collapsible/Collapsible.js +109 -22
  90. package/dist/Collapsible/CollapsibleGroup.d.ts +37 -7
  91. package/dist/Collapsible/CollapsibleGroup.d.ts.map +1 -1
  92. package/dist/Collapsible/CollapsibleGroup.js +64 -12
  93. package/dist/Collapsible/CollapsibleGroupContext.d.ts +24 -0
  94. package/dist/Collapsible/CollapsibleGroupContext.d.ts.map +1 -1
  95. package/dist/Collapsible/CollapsibleGroupContext.js +26 -3
  96. package/dist/Collapsible/index.d.ts +1 -0
  97. package/dist/Collapsible/index.d.ts.map +1 -1
  98. package/dist/Collapsible/useCollapsible.d.ts +4 -1
  99. package/dist/Collapsible/useCollapsible.d.ts.map +1 -1
  100. package/dist/Collapsible/useCollapsible.js +20 -6
  101. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  102. package/dist/CommandPalette/CommandPalette.js +36 -34
  103. package/dist/CommandPalette/CommandPaletteEmpty.js +3 -3
  104. package/dist/CommandPalette/CommandPaletteFooter.js +16 -16
  105. package/dist/CommandPalette/CommandPaletteGroup.js +5 -5
  106. package/dist/CommandPalette/CommandPaletteInput.js +13 -13
  107. package/dist/CommandPalette/CommandPaletteItem.js +3 -3
  108. package/dist/CommandPalette/CommandPaletteList.js +3 -3
  109. package/dist/ContextMenu/ContextMenu.d.ts +7 -2
  110. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  111. package/dist/ContextMenu/ContextMenu.js +76 -43
  112. package/dist/DateInput/DateInput.js +18 -18
  113. package/dist/DateRangeInput/DateRangeInput.js +21 -21
  114. package/dist/DateTimeInput/DateTimeInput.d.ts +5 -2
  115. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  116. package/dist/DateTimeInput/DateTimeInput.js +30 -26
  117. package/dist/DateTimeInput/index.d.ts +1 -1
  118. package/dist/DateTimeInput/index.d.ts.map +1 -1
  119. package/dist/Dialog/Dialog.js +9 -9
  120. package/dist/Dialog/DialogHeader.js +16 -16
  121. package/dist/Dialog/useImperativeDialog.js +3 -3
  122. package/dist/Divider/Divider.js +7 -7
  123. package/dist/DropdownMenu/DropdownMenu.js +10 -10
  124. package/dist/DropdownMenu/DropdownMenuItem.d.ts +2 -17
  125. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  126. package/dist/DropdownMenu/DropdownMenuItem.js +3 -3
  127. package/dist/DropdownMenu/renderDropdownItems.js +10 -10
  128. package/dist/EmptyState/EmptyState.js +9 -9
  129. package/dist/Field/Field.js +17 -17
  130. package/dist/Field/FieldLabel.js +15 -15
  131. package/dist/Field/InputClearButton.js +5 -5
  132. package/dist/FieldStatus/FieldStatus.js +3 -3
  133. package/dist/FileInput/FileInput.js +29 -29
  134. package/dist/FormLayout/FormLayout.js +5 -5
  135. package/dist/Grid/Grid.d.ts +4 -3
  136. package/dist/Grid/Grid.d.ts.map +1 -1
  137. package/dist/Grid/Grid.js +29 -12
  138. package/dist/Grid/GridSpan.js +3 -3
  139. package/dist/HStack/HStack.js +3 -3
  140. package/dist/Heading/Heading.js +10 -10
  141. package/dist/HoverCard/HoverCard.js +9 -9
  142. package/dist/HoverCard/useHoverCard.d.ts +5 -1
  143. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  144. package/dist/HoverCard/useHoverCard.js +3 -3
  145. package/dist/Icon/Icon.d.ts.map +1 -1
  146. package/dist/Icon/Icon.js +16 -12
  147. package/dist/Icon/defaultIcons.js +116 -116
  148. package/dist/IconButton/IconButton.js +3 -3
  149. package/dist/InputGroup/InputGroup.js +11 -11
  150. package/dist/InputGroup/InputGroupText.js +3 -3
  151. package/dist/Item/Item.js +18 -18
  152. package/dist/Kbd/Kbd.js +5 -5
  153. package/dist/Layer/LayerProvider.js +7 -7
  154. package/dist/Layer/useLayer.d.ts +29 -2
  155. package/dist/Layer/useLayer.d.ts.map +1 -1
  156. package/dist/Layer/useLayer.js +44 -31
  157. package/dist/Layout/Layout.js +21 -21
  158. package/dist/Layout/LayoutContent.js +3 -3
  159. package/dist/Layout/LayoutFooter.js +5 -5
  160. package/dist/Layout/LayoutHeader.js +5 -5
  161. package/dist/Layout/LayoutPanel.js +3 -3
  162. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  163. package/dist/Lightbox/Lightbox.js +55 -31
  164. package/dist/Lightbox/useLightbox.d.ts +0 -1
  165. package/dist/Lightbox/useLightbox.d.ts.map +1 -1
  166. package/dist/Lightbox/useLightbox.js +3 -4
  167. package/dist/Link/Link.d.ts +0 -2
  168. package/dist/Link/Link.d.ts.map +1 -1
  169. package/dist/Link/Link.js +15 -17
  170. package/dist/Link/LinkProvider.js +3 -3
  171. package/dist/Link/useLinkify.js +3 -3
  172. package/dist/List/List.js +11 -11
  173. package/dist/List/ListItem.js +11 -11
  174. package/dist/Markdown/Markdown.d.ts.map +1 -1
  175. package/dist/Markdown/Markdown.js +102 -102
  176. package/dist/MetadataList/MetadataList.js +10 -10
  177. package/dist/MetadataList/MetadataListItem.js +15 -15
  178. package/dist/MobileNav/MobileNav.d.ts +1 -1
  179. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  180. package/dist/MobileNav/MobileNav.js +26 -23
  181. package/dist/MobileNav/MobileNavToggle.js +5 -5
  182. package/dist/MoreMenu/MoreMenu.js +3 -3
  183. package/dist/MultiSelector/MultiSelector.js +56 -56
  184. package/dist/NavIcon/NavIcon.js +3 -3
  185. package/dist/NavMenu/NavHeadingMenu.js +5 -5
  186. package/dist/NavMenu/NavHeadingMenuItem.js +8 -8
  187. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  188. package/dist/NumberInput/NumberInput.js +48 -32
  189. package/dist/Outline/Outline.js +15 -15
  190. package/dist/OverflowList/OverflowList.js +8 -8
  191. package/dist/Overlay/Overlay.js +3 -3
  192. package/dist/Overlay/OverlayScrim.js +5 -5
  193. package/dist/Overlay/useOverlay.d.ts +0 -3
  194. package/dist/Overlay/useOverlay.d.ts.map +1 -1
  195. package/dist/Overlay/useOverlay.js +3 -6
  196. package/dist/Pagination/Pagination.d.ts +1 -1
  197. package/dist/Pagination/Pagination.d.ts.map +1 -1
  198. package/dist/Pagination/Pagination.js +125 -72
  199. package/dist/Popover/Popover.js +16 -16
  200. package/dist/Popover/usePopover.js +7 -7
  201. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  202. package/dist/PowerSearch/PowerSearch.js +110 -92
  203. package/dist/PowerSearch/PowerSearchEditPopover.js +84 -84
  204. package/dist/PowerSearch/PowerSearchFilterEditor.js +3 -3
  205. package/dist/PowerSearch/PowerSearchToken.js +5 -5
  206. package/dist/PowerSearch/PowerSearchValueEditor.js +54 -54
  207. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  208. package/dist/ProgressBar/ProgressBar.js +25 -18
  209. package/dist/RadioList/RadioList.js +7 -7
  210. package/dist/RadioList/RadioListItem.d.ts +1 -1
  211. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  212. package/dist/RadioList/RadioListItem.js +24 -21
  213. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  214. package/dist/Resizable/ResizeHandle.js +28 -10
  215. package/dist/Section/Section.js +5 -5
  216. package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
  217. package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  218. package/dist/SegmentedControl/SegmentedControl.js +32 -10
  219. package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
  220. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  221. package/dist/SegmentedControl/SegmentedControlItem.js +18 -12
  222. package/dist/SelectableCard/SelectableCard.js +5 -5
  223. package/dist/Selector/Selector.js +46 -46
  224. package/dist/Selector/SelectorOption.js +3 -3
  225. package/dist/SideNav/SideNav.d.ts.map +1 -1
  226. package/dist/SideNav/SideNav.js +38 -34
  227. package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
  228. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  229. package/dist/SideNav/SideNavCollapseButton.js +8 -6
  230. package/dist/SideNav/SideNavHeading.js +87 -87
  231. package/dist/SideNav/SideNavItem.js +42 -42
  232. package/dist/SideNav/SideNavSection.d.ts +1 -1
  233. package/dist/SideNav/SideNavSection.d.ts.map +1 -1
  234. package/dist/SideNav/SideNavSection.js +18 -16
  235. package/dist/Skeleton/Skeleton.js +3 -3
  236. package/dist/Slider/Slider.js +23 -23
  237. package/dist/Spinner/Spinner.js +9 -9
  238. package/dist/StatusDot/StatusDot.js +5 -5
  239. package/dist/Switch/Switch.d.ts +8 -4
  240. package/dist/Switch/Switch.d.ts.map +1 -1
  241. package/dist/Switch/Switch.js +34 -29
  242. package/dist/TabList/Tab.js +18 -18
  243. package/dist/TabList/TabList.js +5 -5
  244. package/dist/TabList/TabMenu.d.ts.map +1 -1
  245. package/dist/TabList/TabMenu.js +57 -30
  246. package/dist/TabList/tab.markers.stylex.d.ts +1 -1
  247. package/dist/Table/BaseTable.d.ts.map +1 -1
  248. package/dist/Table/BaseTable.js +50 -39
  249. package/dist/Table/Table.js +7 -7
  250. package/dist/Table/TableBody.d.ts +1 -1
  251. package/dist/Table/TableBody.d.ts.map +1 -1
  252. package/dist/Table/TableBody.js +9 -5
  253. package/dist/Table/TableCell.js +3 -3
  254. package/dist/Table/TableFooter.d.ts +1 -1
  255. package/dist/Table/TableFooter.d.ts.map +1 -1
  256. package/dist/Table/TableFooter.js +9 -5
  257. package/dist/Table/TableHeader.d.ts +1 -1
  258. package/dist/Table/TableHeader.d.ts.map +1 -1
  259. package/dist/Table/TableHeader.js +9 -5
  260. package/dist/Table/TableHeaderCell.js +3 -3
  261. package/dist/Table/TableRow.js +5 -5
  262. package/dist/Table/index.d.ts +2 -0
  263. package/dist/Table/index.d.ts.map +1 -1
  264. package/dist/Table/index.js +1 -0
  265. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  266. package/dist/Table/plugins/columnResize/useTableColumnResize.js +14 -11
  267. package/dist/Table/plugins/filtering/useTableFiltering.js +71 -71
  268. package/dist/Table/plugins/groupedRows/index.d.ts +3 -0
  269. package/dist/Table/plugins/groupedRows/index.d.ts.map +1 -0
  270. package/dist/Table/plugins/groupedRows/index.js +3 -0
  271. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +78 -0
  272. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -0
  273. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +250 -0
  274. package/dist/Table/plugins/pagination/paginateData.d.ts.map +1 -1
  275. package/dist/Table/plugins/pagination/paginateData.js +5 -1
  276. package/dist/Table/plugins/pagination/useTablePagination.js +7 -7
  277. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +1 -1
  278. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +23 -23
  279. package/dist/Table/plugins/selection/useTableSelection.js +18 -18
  280. package/dist/Table/plugins/selection/useTableSelectionState.d.ts.map +1 -1
  281. package/dist/Table/plugins/selection/useTableSelectionState.js +11 -1
  282. package/dist/Table/plugins/sortable/useTableSortable.js +17 -17
  283. package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
  284. package/dist/Table/plugins/sortable/useTableSortableState.js +8 -4
  285. package/dist/Table/tableContextMenu.js +9 -9
  286. package/dist/Text/Text.js +10 -10
  287. package/dist/TextArea/TextArea.js +14 -14
  288. package/dist/TextInput/TextInput.js +15 -15
  289. package/dist/Thumbnail/Thumbnail.d.ts +3 -2
  290. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  291. package/dist/Thumbnail/Thumbnail.js +30 -29
  292. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  293. package/dist/TimeInput/TimeInput.js +26 -21
  294. package/dist/Timestamp/Timestamp.d.ts +1 -1
  295. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  296. package/dist/Timestamp/Timestamp.js +37 -26
  297. package/dist/Toast/Toast.d.ts.map +1 -1
  298. package/dist/Toast/Toast.js +25 -17
  299. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  300. package/dist/Toast/ToastViewport.js +23 -11
  301. package/dist/Toast/useToast.d.ts.map +1 -1
  302. package/dist/Toast/useToast.js +44 -4
  303. package/dist/ToggleButton/ToggleButton.js +12 -12
  304. package/dist/ToggleButton/ToggleButtonGroup.js +5 -5
  305. package/dist/Token/Token.js +21 -21
  306. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  307. package/dist/Tokenizer/Tokenizer.js +36 -34
  308. package/dist/Toolbar/Toolbar.js +18 -18
  309. package/dist/Tooltip/Tooltip.js +11 -11
  310. package/dist/Tooltip/useTooltip.d.ts +5 -1
  311. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  312. package/dist/Tooltip/useTooltip.js +3 -3
  313. package/dist/TopNav/TopNav.js +32 -32
  314. package/dist/TopNav/TopNavHeading.js +67 -67
  315. package/dist/TopNav/TopNavItem.js +5 -5
  316. package/dist/TopNav/TopNavMegaMenu.js +30 -30
  317. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts +1 -1
  318. package/dist/TopNav/TopNavMegaMenuFeaturedCard.d.ts.map +1 -1
  319. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +25 -14
  320. package/dist/TopNav/TopNavMegaMenuItem.js +16 -16
  321. package/dist/TopNav/TopNavMenu.js +32 -32
  322. package/dist/TreeList/TreeList.js +8 -8
  323. package/dist/TreeList/TreeListBranches.js +11 -11
  324. package/dist/TreeList/TreeListItem.js +30 -30
  325. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  326. package/dist/Typeahead/BaseTypeahead.js +23 -20
  327. package/dist/Typeahead/Typeahead.js +12 -12
  328. package/dist/Typeahead/TypeaheadItem.js +10 -10
  329. package/dist/VStack/VStack.js +3 -3
  330. package/dist/VisuallyHidden/VisuallyHidden.d.ts +0 -3
  331. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -1
  332. package/dist/VisuallyHidden/VisuallyHidden.js +0 -3
  333. package/dist/astryx.css +7 -0
  334. package/dist/astryx.umd.js +63 -63
  335. package/dist/astryx.umd.js.map +4 -4
  336. package/dist/docs-types.d.ts +8 -2
  337. package/dist/docs-types.d.ts.map +1 -1
  338. package/dist/hooks/focusableSelector.d.ts +1 -1
  339. package/dist/hooks/focusableSelector.d.ts.map +1 -1
  340. package/dist/hooks/focusableSelector.js +1 -1
  341. package/dist/hooks/index.d.ts +2 -0
  342. package/dist/hooks/index.d.ts.map +1 -1
  343. package/dist/hooks/index.js +1 -0
  344. package/dist/hooks/useFocusTrap.d.ts +3 -0
  345. package/dist/hooks/useFocusTrap.d.ts.map +1 -1
  346. package/dist/hooks/useFocusTrap.js +38 -1
  347. package/dist/hooks/useHotkeys.d.ts +51 -0
  348. package/dist/hooks/useHotkeys.d.ts.map +1 -0
  349. package/dist/hooks/useHotkeys.js +160 -0
  350. package/dist/hooks/useInteractiveRole.d.ts +6 -2
  351. package/dist/hooks/useInteractiveRole.d.ts.map +1 -1
  352. package/dist/hooks/useInteractiveRole.js +6 -2
  353. package/dist/hooks/useKeyboardHint.js +9 -9
  354. package/dist/hooks/useStreamingText.d.ts +3 -1
  355. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  356. package/dist/hooks/useStreamingText.js +14 -5
  357. package/dist/theme/MediaTheme.js +3 -3
  358. package/dist/theme/Theme.js +7 -7
  359. package/dist/theme/defineTheme.d.ts +1 -1
  360. package/dist/theme/defineTheme.d.ts.map +1 -1
  361. package/dist/theme/expandColorScale.d.ts.map +1 -1
  362. package/dist/theme/expandColorScale.js +10 -3
  363. package/dist/theme/hct.d.ts +0 -15
  364. package/dist/theme/hct.d.ts.map +1 -1
  365. package/dist/theme/hct.js +9 -9
  366. package/dist/theme/syntax/SyntaxTheme.js +5 -5
  367. package/dist/theme/tokens.d.ts +10 -2
  368. package/dist/theme/tokens.d.ts.map +1 -1
  369. package/dist/theme/tokens.js +220 -4
  370. package/dist/theme/useTheme.d.ts +3 -2
  371. package/dist/theme/useTheme.d.ts.map +1 -1
  372. package/dist/theme/useTheme.js +73 -6
  373. package/dist/utils/color.d.ts +42 -0
  374. package/dist/utils/color.d.ts.map +1 -0
  375. package/dist/utils/color.js +150 -0
  376. package/dist/utils/composeEventHandlers.d.ts +30 -0
  377. package/dist/utils/composeEventHandlers.d.ts.map +1 -0
  378. package/dist/utils/composeEventHandlers.js +40 -0
  379. package/dist/utils/index.d.ts +3 -0
  380. package/dist/utils/index.d.ts.map +1 -1
  381. package/dist/utils/index.js +3 -1
  382. package/dist/utils/timeParser.d.ts.map +1 -1
  383. package/dist/utils/timeParser.js +8 -5
  384. package/package.json +4 -4
  385. package/src/AlertDialog/AlertDialog.doc.mjs +4 -0
  386. package/src/AlertDialog/AlertDialog.tsx +2 -0
  387. package/src/AlertDialog/useImperativeAlertDialog.tsx +0 -2
  388. package/src/AppShell/AppShell.tsx +2 -0
  389. package/src/AspectRatio/AspectRatio.doc.mjs +28 -1
  390. package/src/AspectRatio/AspectRatio.test.tsx +142 -1
  391. package/src/AspectRatio/AspectRatio.tsx +70 -10
  392. package/src/AspectRatio/index.ts +5 -1
  393. package/src/Avatar/Avatar.doc.mjs +11 -0
  394. package/src/Avatar/Avatar.test.tsx +32 -1
  395. package/src/Avatar/Avatar.tsx +14 -22
  396. package/src/Avatar/AvatarStatusDot.tsx +2 -2
  397. package/src/AvatarGroup/AvatarGroup.doc.mjs +1 -0
  398. package/src/AvatarGroup/AvatarGroup.tsx +2 -2
  399. package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -2
  400. package/src/Banner/Banner.doc.mjs +8 -0
  401. package/src/Banner/Banner.test.tsx +38 -0
  402. package/src/Banner/Banner.tsx +8 -1
  403. package/src/Calendar/Calendar.doc.mjs +1 -1
  404. package/src/Calendar/Calendar.test.tsx +122 -17
  405. package/src/Calendar/Calendar.tsx +26 -5
  406. package/src/Calendar/dayCellUtils.ts +3 -1
  407. package/src/Calendar/styles.ts +12 -2
  408. package/src/Card/Card.doc.mjs +1 -1
  409. package/src/Card/Card.tsx +16 -6
  410. package/src/Carousel/Carousel.doc.mjs +12 -12
  411. package/src/Carousel/Carousel.test.tsx +13 -0
  412. package/src/Carousel/Carousel.tsx +4 -2
  413. package/src/Chat/Chat.doc.mjs +1 -1
  414. package/src/Chat/ChatComposerInput.test.tsx +27 -1
  415. package/src/Chat/ChatComposerInput.tsx +20 -15
  416. package/src/Chat/ChatDictationButton.test.tsx +43 -0
  417. package/src/Chat/ChatDictationButton.tsx +4 -4
  418. package/src/Chat/ChatLayoutScrollButton.test.tsx +33 -0
  419. package/src/Chat/ChatLayoutScrollButton.tsx +3 -1
  420. package/src/Chat/ChatMessageMetadata.test.tsx +32 -0
  421. package/src/Chat/ChatMessageMetadata.tsx +4 -6
  422. package/src/Chat/ChatSystemMessage.test.tsx +26 -11
  423. package/src/Chat/ChatSystemMessage.tsx +7 -7
  424. package/src/Chat/ChatTokenizedText.test.tsx +29 -16
  425. package/src/Chat/ChatTokenizedText.tsx +15 -8
  426. package/src/Chat/ChatToolCalls.test.tsx +55 -0
  427. package/src/Chat/ChatToolCalls.tsx +10 -12
  428. package/src/Chat/index.ts +1 -4
  429. package/src/Chat/useTriggerMenu.tsx +1 -4
  430. package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -3
  431. package/src/CheckboxInput/CheckboxInput.test.tsx +71 -4
  432. package/src/CheckboxInput/CheckboxInput.tsx +2 -0
  433. package/src/CheckboxList/CheckboxList.test.tsx +19 -0
  434. package/src/CheckboxList/CheckboxListItem.tsx +11 -2
  435. package/src/Citation/Citation.doc.mjs +5 -0
  436. package/src/ClickableCard/ClickableCard.tsx +45 -2
  437. package/src/CodeBlock/CodeBlock.doc.mjs +7 -2
  438. package/src/CodeBlock/CodeBlock.test.tsx +122 -3
  439. package/src/CodeBlock/CodeBlock.tsx +62 -4
  440. package/src/Collapsible/Collapsible.doc.mjs +8 -4
  441. package/src/Collapsible/Collapsible.test.tsx +403 -0
  442. package/src/Collapsible/Collapsible.tsx +85 -10
  443. package/src/Collapsible/CollapsibleGroup.doc.mjs +27 -3
  444. package/src/Collapsible/CollapsibleGroup.test.tsx +314 -0
  445. package/src/Collapsible/CollapsibleGroup.tsx +97 -9
  446. package/src/Collapsible/CollapsibleGroupContext.tsx +34 -2
  447. package/src/Collapsible/index.ts +1 -0
  448. package/src/Collapsible/useCollapsible.ts +20 -6
  449. package/src/CommandPalette/CommandPalette.doc.mjs +5 -0
  450. package/src/CommandPalette/CommandPalette.tsx +5 -3
  451. package/src/CommandPalette/CommandPaletteEmpty.doc.mjs +5 -0
  452. package/src/CommandPalette/CommandPaletteGroup.doc.mjs +10 -0
  453. package/src/CommandPalette/CommandPaletteInput.doc.mjs +6 -0
  454. package/src/CommandPalette/CommandPaletteItem.doc.mjs +6 -0
  455. package/src/CommandPalette/CommandPaletteList.doc.mjs +9 -0
  456. package/src/ContextMenu/ContextMenu.doc.mjs +15 -0
  457. package/src/ContextMenu/ContextMenu.test.tsx +87 -0
  458. package/src/ContextMenu/ContextMenu.tsx +87 -28
  459. package/src/ContextMenu/ContextMenuItem.doc.mjs +6 -0
  460. package/src/DateInput/DateInput.test.tsx +11 -20
  461. package/src/DateRangeInput/DateRangeInput.doc.mjs +9 -6
  462. package/src/DateRangeInput/DateRangeInput.test.tsx +31 -44
  463. package/src/DateTimeInput/DateTimeInput.doc.mjs +3 -2
  464. package/src/DateTimeInput/DateTimeInput.test.tsx +118 -16
  465. package/src/DateTimeInput/DateTimeInput.tsx +8 -2
  466. package/src/DateTimeInput/index.ts +1 -0
  467. package/src/Dialog/Dialog.doc.mjs +4 -0
  468. package/src/Dialog/DialogHeader.doc.mjs +45 -0
  469. package/src/DropdownMenu/DropdownMenu.doc.mjs +1 -1
  470. package/src/DropdownMenu/DropdownMenu.test.tsx +22 -2
  471. package/src/DropdownMenu/DropdownMenuItem.tsx +5 -17
  472. package/src/EmptyState/EmptyState.doc.mjs +1 -1
  473. package/src/Field/Field.test.tsx +1 -4
  474. package/src/Field/FieldLabel.test.tsx +2 -2
  475. package/src/FieldStatus/FieldStatus.test.tsx +282 -0
  476. package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +0 -3
  477. package/src/Grid/Grid.test.tsx +43 -18
  478. package/src/Grid/Grid.tsx +26 -9
  479. package/src/HoverCard/HoverCard.doc.mjs +6 -6
  480. package/src/HoverCard/useHoverCard.doc.mjs +5 -5
  481. package/src/HoverCard/useHoverCard.tsx +9 -2
  482. package/src/Icon/Icon.test.tsx +41 -29
  483. package/src/Icon/Icon.tsx +6 -2
  484. package/src/InputGroup/InputGroup.doc.mjs +1 -0
  485. package/src/InputGroup/InputGroup.tsx +2 -2
  486. package/src/InteractiveRoleContext/InteractiveRoleContext.test.tsx +185 -0
  487. package/src/Item/Item.tsx +1 -1
  488. package/src/Layer/useLayer.doc.mjs +2 -2
  489. package/src/Layer/useLayer.test.tsx +221 -2
  490. package/src/Layer/useLayer.tsx +69 -30
  491. package/src/Layout/Layout.test.tsx +285 -0
  492. package/src/Layout/LayoutContent.doc.mjs +12 -0
  493. package/src/Layout/LayoutPanel.doc.mjs +40 -0
  494. package/src/Layout/LayoutSlots.test.tsx +364 -0
  495. package/src/Lightbox/Lightbox.doc.mjs +5 -0
  496. package/src/Lightbox/Lightbox.test.tsx +123 -2
  497. package/src/Lightbox/Lightbox.tsx +29 -1
  498. package/src/Lightbox/useLightbox.tsx +0 -1
  499. package/src/Link/Link.tsx +0 -2
  500. package/src/Markdown/Markdown.tsx +9 -7
  501. package/src/Markdown/parser.perf.test.ts +34 -12
  502. package/src/MobileNav/MobileNav.test.tsx +56 -0
  503. package/src/MobileNav/MobileNav.tsx +13 -8
  504. package/src/NavMenu/NavMenu.doc.mjs +15 -0
  505. package/src/NumberInput/NumberInput.test.tsx +48 -3
  506. package/src/NumberInput/NumberInput.tsx +32 -15
  507. package/src/Outline/Outline.doc.mjs +2 -0
  508. package/src/Outline/parseOutlineFromMarkdown.test.ts +80 -0
  509. package/src/OverflowList/OverflowList.test.tsx +416 -0
  510. package/src/Overlay/Overlay.doc.mjs +6 -0
  511. package/src/Overlay/Overlay.test.tsx +356 -0
  512. package/src/Overlay/useOverlay.tsx +0 -3
  513. package/src/Pagination/Pagination.test.tsx +162 -0
  514. package/src/Pagination/Pagination.tsx +80 -26
  515. package/src/Popover/Popover.doc.mjs +6 -6
  516. package/src/Popover/Popover.test.tsx +65 -0
  517. package/src/Popover/usePopover.doc.mjs +1 -1
  518. package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
  519. package/src/PowerSearch/PowerSearch.test.tsx +109 -1
  520. package/src/PowerSearch/PowerSearch.tsx +37 -16
  521. package/src/ProgressBar/ProgressBar.doc.mjs +2 -0
  522. package/src/ProgressBar/ProgressBar.test.tsx +30 -0
  523. package/src/ProgressBar/ProgressBar.tsx +12 -5
  524. package/src/RadioList/RadioList.test.tsx +19 -0
  525. package/src/RadioList/RadioListItem.tsx +9 -4
  526. package/src/Resizable/ResizeHandle.test.tsx +218 -0
  527. package/src/Resizable/ResizeHandle.tsx +22 -4
  528. package/src/SegmentedControl/SegmentedControl.doc.mjs +1 -1
  529. package/src/SegmentedControl/SegmentedControl.test.tsx +192 -0
  530. package/src/SegmentedControl/SegmentedControl.tsx +27 -5
  531. package/src/SegmentedControl/SegmentedControlItem.tsx +9 -4
  532. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  533. package/src/Selector/Selector.test.tsx +27 -1
  534. package/src/SideNav/SideNav.doc.mjs +7 -1
  535. package/src/SideNav/SideNav.test.tsx +66 -0
  536. package/src/SideNav/SideNav.tsx +6 -2
  537. package/src/SideNav/SideNavCollapseButton.tsx +4 -3
  538. package/src/SideNav/SideNavSection.tsx +6 -4
  539. package/src/SizeContext/SizeContext.test.tsx +226 -0
  540. package/src/Switch/Switch.doc.mjs +7 -7
  541. package/src/Switch/Switch.test.tsx +102 -3
  542. package/src/Switch/Switch.tsx +20 -7
  543. package/src/TabList/TabList.test.tsx +185 -1
  544. package/src/TabList/TabMenu.tsx +45 -9
  545. package/src/Table/BaseTable.tsx +13 -2
  546. package/src/Table/Table.doc.mjs +6 -1
  547. package/src/Table/Table.test.tsx +87 -0
  548. package/src/Table/TableBody.tsx +15 -2
  549. package/src/Table/TableFooter.tsx +15 -2
  550. package/src/Table/TableHeader.tsx +15 -2
  551. package/src/Table/index.ts +5 -0
  552. package/src/Table/plugins/columnResize/useTableColumnResize.test.tsx +13 -0
  553. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +3 -1
  554. package/src/Table/plugins/groupedRows/index.ts +7 -0
  555. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +231 -0
  556. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +349 -0
  557. package/src/Table/plugins/pagination/paginateData.ts +5 -1
  558. package/src/Table/plugins/pagination/useTablePagination.test.tsx +13 -0
  559. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +1 -1
  560. package/src/Table/plugins/selection/useTableSelectionState.test.tsx +23 -0
  561. package/src/Table/plugins/selection/useTableSelectionState.tsx +11 -6
  562. package/src/Table/plugins/sortable/useTableSortableState.test.tsx +35 -1
  563. package/src/Table/plugins/sortable/useTableSortableState.tsx +8 -4
  564. package/src/Table/useTableGroupedRows.doc.mjs +71 -0
  565. package/src/TextArea/TextArea.test.tsx +3 -3
  566. package/src/TextInput/TextInput.test.tsx +3 -3
  567. package/src/Thumbnail/Thumbnail.test.tsx +36 -2
  568. package/src/Thumbnail/Thumbnail.tsx +4 -2
  569. package/src/TimeInput/TimeInput.test.tsx +37 -0
  570. package/src/TimeInput/TimeInput.tsx +11 -1
  571. package/src/Timestamp/Timestamp.doc.mjs +1 -1
  572. package/src/Timestamp/Timestamp.test.tsx +52 -0
  573. package/src/Timestamp/Timestamp.tsx +30 -16
  574. package/src/Toast/Toast.tsx +11 -3
  575. package/src/Toast/ToastViewport.test.tsx +64 -0
  576. package/src/Toast/ToastViewport.tsx +12 -0
  577. package/src/Toast/useToast.test.tsx +258 -0
  578. package/src/Toast/useToast.tsx +41 -0
  579. package/src/ToggleButton/ToggleButton.doc.mjs +1 -0
  580. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  581. package/src/Tokenizer/Tokenizer.test.tsx +54 -0
  582. package/src/Tokenizer/Tokenizer.tsx +5 -4
  583. package/src/Tooltip/Tooltip.doc.mjs +6 -6
  584. package/src/Tooltip/useTooltip.doc.mjs +5 -5
  585. package/src/Tooltip/useTooltip.tsx +12 -2
  586. package/src/TopNav/TopNav.doc.mjs +1 -1
  587. package/src/TopNav/TopNav.test.tsx +23 -7
  588. package/src/TopNav/TopNavMegaMenuFeaturedCard.tsx +9 -2
  589. package/src/TreeList/TreeList.doc.mjs +2 -2
  590. package/src/Typeahead/BaseTypeahead.doc.mjs +19 -0
  591. package/src/Typeahead/BaseTypeahead.tsx +5 -2
  592. package/src/Typeahead/Typeahead.doc.mjs +1 -1
  593. package/src/Typeahead/Typeahead.test.tsx +45 -1
  594. package/src/VisuallyHidden/VisuallyHidden.tsx +0 -3
  595. package/src/__tests__/TestIcon.tsx +26 -0
  596. package/src/__tests__/fastRoleQueries.ts +66 -0
  597. package/src/docPropReferences.test.ts +178 -0
  598. package/src/docs-types.ts +9 -1
  599. package/src/hooks/focusableSelector.ts +1 -1
  600. package/src/hooks/index.ts +3 -0
  601. package/src/hooks/useFocusTrap.doc.mjs +4 -2
  602. package/src/hooks/useFocusTrap.test.tsx +149 -1
  603. package/src/hooks/useFocusTrap.ts +50 -1
  604. package/src/hooks/useHotkeys.doc.mjs +52 -0
  605. package/src/hooks/useHotkeys.test.ts +245 -0
  606. package/src/hooks/useHotkeys.ts +203 -0
  607. package/src/hooks/useInteractiveRole.ts +12 -4
  608. package/src/hooks/useStreamingText.test.ts +54 -19
  609. package/src/hooks/useStreamingText.ts +16 -5
  610. package/src/hooks/useTreeFocus.test.tsx +1 -3
  611. package/src/reset.css +29 -0
  612. package/src/theme/SyntaxTheme.doc.mjs +4 -4
  613. package/src/theme/defineTheme.ts +4 -13
  614. package/src/theme/derivedVarRegistry.test.ts +2 -2
  615. package/src/theme/expandColorScale.test.ts +29 -0
  616. package/src/theme/expandColorScale.ts +11 -6
  617. package/src/theme/hct.ts +9 -17
  618. package/src/theme/themingTargets.test.ts +353 -0
  619. package/src/theme/tokens.test.ts +182 -9
  620. package/src/theme/tokens.ts +239 -4
  621. package/src/theme/useTheme.test.tsx +126 -2
  622. package/src/theme/useTheme.ts +87 -6
  623. package/src/utils/color.test.ts +133 -0
  624. package/src/utils/color.ts +148 -0
  625. package/src/utils/composeEventHandlers.test.ts +71 -0
  626. package/src/utils/composeEventHandlers.ts +44 -0
  627. package/src/utils/index.ts +4 -0
  628. package/src/utils/mergeProps.test.ts +166 -0
  629. package/src/utils/sharedResizeObserver.test.ts +2 -2
  630. package/src/utils/timeParser.test.ts +13 -0
  631. package/src/utils/timeParser.ts +8 -5
  632. package/dist/Carousel/carousel.markers.stylex.d.ts +0 -7
  633. package/dist/Carousel/carousel.markers.stylex.d.ts.map +0 -1
  634. package/dist/Carousel/carousel.markers.stylex.js +0 -12
  635. package/src/Carousel/carousel.markers.stylex.ts +0 -10
@@ -12,8 +12,11 @@
12
12
  import {describe, it, expect, vi} from 'vitest';
13
13
  import {act, render, screen, within} from '@testing-library/react';
14
14
  import userEvent from '@testing-library/user-event';
15
+ import {getButton} from '../__tests__/fastRoleQueries';
16
+ import * as stylex from '@stylexjs/stylex';
15
17
  import {Calendar} from './Calendar';
16
18
  import type {CalendarHandle} from './Calendar';
19
+ import {calendarStyles} from './styles';
17
20
 
18
21
  /**
19
22
  * Helper to find a day button by its day number.
@@ -24,7 +27,7 @@ import type {CalendarHandle} from './Calendar';
24
27
  function getDayButton(day: number, month = 'January', year = 2026) {
25
28
  // Match the full date pattern with the day number
26
29
  const pattern = new RegExp(`${month}\\s+${day},\\s+${year}`);
27
- return screen.getByRole('button', {name: pattern});
30
+ return getButton(pattern);
28
31
  }
29
32
 
30
33
  describe('Calendar', () => {
@@ -71,6 +74,24 @@ describe('Calendar', () => {
71
74
  expect(screen.getByText(expectedLabel)).toBeInTheDocument();
72
75
  });
73
76
 
77
+ it("marks today's cell with aria-current='date'", () => {
78
+ render(<Calendar />);
79
+
80
+ const now = new Date();
81
+ const iso = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')}`;
82
+
83
+ const todayCell = document.querySelector(`button[data-date="${iso}"]`);
84
+ expect(todayCell).not.toBeNull();
85
+ expect(todayCell).toHaveAttribute('aria-current', 'date');
86
+
87
+ // Only today's cell is marked current.
88
+ const others = Array.from(
89
+ document.querySelectorAll('button[data-date]'),
90
+ ).filter(el => el.getAttribute('data-date') !== iso);
91
+ expect(others.length).toBeGreaterThan(0);
92
+ others.forEach(el => expect(el).not.toHaveAttribute('aria-current'));
93
+ });
94
+
74
95
  it('displays day names', () => {
75
96
  render(<Calendar />);
76
97
 
@@ -97,7 +118,11 @@ describe('Calendar', () => {
97
118
  render(<Calendar value="2026-01-15" focusDate="2026-01-01" />);
98
119
 
99
120
  const day15 = getDayButton(15);
100
- expect(day15).toHaveAttribute('aria-selected', 'true');
121
+ // In an ARIA grid, selection state lives on the gridcell, not the button
122
+ // (a plain button role does not permit aria-selected).
123
+ const gridcell15 = day15.closest('[role="gridcell"]');
124
+ expect(gridcell15).toHaveAttribute('aria-selected', 'true');
125
+ expect(day15).not.toHaveAttribute('aria-selected');
101
126
  });
102
127
 
103
128
  it('calls onChange when date is selected', async () => {
@@ -123,7 +148,7 @@ describe('Calendar', () => {
123
148
  // Verify we start on February
124
149
  expect(screen.getByText('February 2026')).toBeInTheDocument();
125
150
 
126
- const prevButton = screen.getByRole('button', {name: 'Previous month'});
151
+ const prevButton = getButton('Previous month');
127
152
  await user.click(prevButton);
128
153
 
129
154
  expect(screen.getByText('January 2026')).toBeInTheDocument();
@@ -137,7 +162,7 @@ describe('Calendar', () => {
137
162
  // Verify we start on January
138
163
  expect(screen.getByText('January 2026')).toBeInTheDocument();
139
164
 
140
- const nextButton = screen.getByRole('button', {name: 'Next month'});
165
+ const nextButton = getButton('Next month');
141
166
  await user.click(nextButton);
142
167
 
143
168
  expect(screen.getByText('February 2026')).toBeInTheDocument();
@@ -151,7 +176,7 @@ describe('Calendar', () => {
151
176
  <Calendar focusDate="2026-01-01" onFocusDateChange={handleFocusChange} />,
152
177
  );
153
178
 
154
- const nextButton = screen.getByRole('button', {name: 'Next month'});
179
+ const nextButton = getButton('Next month');
155
180
  await user.click(nextButton);
156
181
 
157
182
  expect(handleFocusChange).toHaveBeenCalledWith('2026-02-01');
@@ -209,12 +234,39 @@ describe('Calendar', () => {
209
234
 
210
235
  render(<Calendar numberOfMonths={2} focusDate="2026-01-01" />);
211
236
 
212
- const nextButton = screen.getByRole('button', {name: 'Next month'});
237
+ const nextButton = getButton('Next month');
213
238
  await user.click(nextButton);
214
239
 
215
240
  expect(screen.getByText(/February 2026.*March 2026/)).toBeInTheDocument();
216
241
  });
217
242
 
243
+ it('clamps out-of-range numberOfMonths to a single month', () => {
244
+ // 1000 would otherwise try to render 1000 month grids and lock the page up.
245
+ render(
246
+ <Calendar
247
+ numberOfMonths={1000 as unknown as 1 | 2}
248
+ focusDate="2026-01-01"
249
+ />,
250
+ );
251
+
252
+ // Only the focused month renders — no second month, no range separator.
253
+ expect(screen.getByText('January 2026')).toBeInTheDocument();
254
+ expect(screen.queryByText(/February 2026/)).not.toBeInTheDocument();
255
+ });
256
+
257
+ it('clamps numberOfMonths={0} to a single month', () => {
258
+ render(
259
+ <Calendar
260
+ numberOfMonths={0 as unknown as 1 | 2}
261
+ focusDate="2026-01-01"
262
+ />,
263
+ );
264
+
265
+ // 0 previously rendered no months at all; now falls back to one.
266
+ expect(screen.getByText('January 2026')).toBeInTheDocument();
267
+ expect(screen.getAllByRole('gridcell').length).toBeGreaterThan(0);
268
+ });
269
+
218
270
  // ─── Display Options ─────────────────────────────────────────
219
271
 
220
272
  it('shows week numbers when hasWeekNumbers is true', () => {
@@ -310,9 +362,22 @@ describe('Calendar', () => {
310
362
  const day12 = getDayButton(12);
311
363
  const day15 = getDayButton(15);
312
364
 
313
- expect(day10).toHaveAttribute('aria-selected', 'true');
314
- expect(day12).toHaveAttribute('aria-selected', 'true');
315
- expect(day15).toHaveAttribute('aria-selected', 'true');
365
+ // Selection state lives on the gridcell wrapper, not the day button.
366
+ expect(day10.closest('[role="gridcell"]')).toHaveAttribute(
367
+ 'aria-selected',
368
+ 'true',
369
+ );
370
+ expect(day12.closest('[role="gridcell"]')).toHaveAttribute(
371
+ 'aria-selected',
372
+ 'true',
373
+ );
374
+ expect(day15.closest('[role="gridcell"]')).toHaveAttribute(
375
+ 'aria-selected',
376
+ 'true',
377
+ );
378
+ expect(day10).not.toHaveAttribute('aria-selected');
379
+ expect(day12).not.toHaveAttribute('aria-selected');
380
+ expect(day15).not.toHaveAttribute('aria-selected');
316
381
  });
317
382
 
318
383
  it('caps the range highlight next to a disabled mid-range day (#2715)', () => {
@@ -476,12 +541,8 @@ describe('Calendar', () => {
476
541
  it('has navigation buttons with accessible labels', () => {
477
542
  render(<Calendar />);
478
543
 
479
- expect(
480
- screen.getByRole('button', {name: 'Previous month'}),
481
- ).toBeInTheDocument();
482
- expect(
483
- screen.getByRole('button', {name: 'Next month'}),
484
- ).toBeInTheDocument();
544
+ expect(getButton('Previous month')).toBeInTheDocument();
545
+ expect(getButton('Next month')).toBeInTheDocument();
485
546
  });
486
547
 
487
548
  // ─── Bug Regression Tests ───────────────────────────────────
@@ -589,14 +650,14 @@ describe('Calendar', () => {
589
650
  it('prev button is disabled when focusDate month contains min', () => {
590
651
  render(<Calendar focusDate="2026-01-01" min="2026-01-15" />);
591
652
 
592
- const prevButton = screen.getByRole('button', {name: 'Previous month'});
653
+ const prevButton = getButton('Previous month');
593
654
  expect(prevButton).toBeDisabled();
594
655
  });
595
656
 
596
657
  it('next button is disabled when focusDate month contains max', () => {
597
658
  render(<Calendar focusDate="2026-01-01" max="2026-01-15" />);
598
659
 
599
- const nextButton = screen.getByRole('button', {name: 'Next month'});
660
+ const nextButton = getButton('Next month');
600
661
  expect(nextButton).toBeDisabled();
601
662
  });
602
663
 
@@ -675,4 +736,48 @@ describe('Calendar', () => {
675
736
  }
676
737
  }
677
738
  });
739
+
740
+ // ─── RTL (#3388) ─────────────────────────────────────────────
741
+
742
+ describe('RTL month navigation', () => {
743
+ // jsdom does not apply compiled StyleX CSS, so the scaleX(-1) mirror
744
+ // itself is only observable in a browser (see the dir="rtl" Storybook
745
+ // story). These tests pin the structure the fix depends on: both nav
746
+ // chevrons render inside the navIcon wrapper that carries the
747
+ // ':is([dir="rtl"] *)' conditional transform.
748
+ it('wraps both nav chevrons in the RTL-mirroring navIcon wrapper', () => {
749
+ render(<Calendar focusDate="2026-01-01" />);
750
+
751
+ const {className: navIconClass} = stylex.props(calendarStyles.navIcon);
752
+ expect(navIconClass).toBeTruthy();
753
+
754
+ for (const name of ['Previous month', 'Next month']) {
755
+ const button = getButton(name);
756
+ const wrappers = Array.from(button.querySelectorAll('span')).filter(
757
+ span => span.className === navIconClass,
758
+ );
759
+ expect(wrappers.length).toBe(1);
760
+ }
761
+ });
762
+
763
+ it('keeps navigation semantics unchanged under dir="rtl"', async () => {
764
+ const user = userEvent.setup();
765
+
766
+ render(
767
+ <div dir="rtl">
768
+ <Calendar focusDate="2026-02-01" />
769
+ </div>,
770
+ );
771
+
772
+ expect(screen.getByText('February 2026')).toBeInTheDocument();
773
+
774
+ // DOM order and handlers must not change in RTL: flexbox already
775
+ // places "Previous month" at the visual right; only the glyph mirrors.
776
+ await user.click(getButton('Previous month'));
777
+ expect(screen.getByText('January 2026')).toBeInTheDocument();
778
+
779
+ await user.click(getButton('Next month'));
780
+ expect(screen.getByText('February 2026')).toBeInTheDocument();
781
+ });
782
+ });
678
783
  });
@@ -203,7 +203,7 @@ export function Calendar({ref, ...props}: CalendarProps) {
203
203
  value,
204
204
  defaultValue,
205
205
  onChange,
206
- numberOfMonths = 1,
206
+ numberOfMonths: numberOfMonthsProp = 1,
207
207
  min,
208
208
  max,
209
209
  dateConstraints,
@@ -223,6 +223,11 @@ export function Calendar({ref, ...props}: CalendarProps) {
223
223
  // DayOfWeek so all downstream date math keeps working with an index.
224
224
  const weekStartsOn = normalizeDayOfWeek(weekStartsOnProp);
225
225
 
226
+ // `numberOfMonths` is typed `1 | 2`; defensively clamp anything else that
227
+ // slips through at runtime to 1 so `Array.from({length})` can't render an
228
+ // absurd number of month grids (e.g. `numberOfMonths={1000}`).
229
+ const numberOfMonths = numberOfMonthsProp === 2 ? 2 : 1;
230
+
226
231
  // Today's date (memoized)
227
232
  const today = useMemo(() => plainDateToday(), []);
228
233
 
@@ -426,7 +431,14 @@ export function Calendar({ref, ...props}: CalendarProps) {
426
431
  <Button
427
432
  label="Previous month"
428
433
  variant="ghost"
429
- icon={<Icon icon="chevronLeft" size="sm" color="inherit" />}
434
+ icon={
435
+ // Wrapper span (not Icon props): Icon's string mode clobbers
436
+ // caller classNames, so the RTL mirror must live on its own
437
+ // element.
438
+ <span {...stylex.props(calendarStyles.navIcon)}>
439
+ <Icon icon="chevronLeft" size="sm" color="inherit" />
440
+ </span>
441
+ }
430
442
  onClick={() => navigateMonth(-1)}
431
443
  isDisabled={!canNavigatePrevious}
432
444
  isIconOnly
@@ -439,7 +451,11 @@ export function Calendar({ref, ...props}: CalendarProps) {
439
451
  <Button
440
452
  label="Next month"
441
453
  variant="ghost"
442
- icon={<Icon icon="chevronRight" size="sm" color="inherit" />}
454
+ icon={
455
+ <span {...stylex.props(calendarStyles.navIcon)}>
456
+ <Icon icon="chevronRight" size="sm" color="inherit" />
457
+ </span>
458
+ }
443
459
  onClick={() => navigateMonth(1)}
444
460
  isDisabled={!canNavigateNext}
445
461
  isIconOnly
@@ -912,7 +928,10 @@ function DayCell({
912
928
  });
913
929
 
914
930
  return (
915
- <div role="gridcell" {...stylex.props(dayCellStyles.cell)}>
931
+ <div
932
+ role="gridcell"
933
+ aria-selected={state.isSelected || state.isInRange || undefined}
934
+ {...stylex.props(dayCellStyles.cell)}>
916
935
  {/* Range background */}
917
936
  {state.isInRange && (
918
937
  <div
@@ -952,8 +971,10 @@ function DayCell({
952
971
  type="button"
953
972
  data-date={day.iso}
954
973
  aria-label={plainDateFormat(date, DATE_FORMAT_WITH_WEEKDAY)}
955
- aria-selected={state.isSelected || state.isInRange || undefined}
956
974
  aria-disabled={state.effectivelyDisabled || undefined}
975
+ // Mark today's cell programmatically (APG date-picker pattern), not just
976
+ // visually, so screen-reader users can identify the current date.
977
+ aria-current={state.isToday ? 'date' : undefined}
957
978
  disabled={isDisabled}
958
979
  // Initial roving tab-stop seed; useGridFocus owns it after mount.
959
980
  tabIndex={isTabbableDay ? 0 : -1}
@@ -193,7 +193,9 @@ export function isRangeHighlighted(input: {
193
193
  isDisabled: boolean;
194
194
  isOutside: boolean;
195
195
  }): boolean {
196
- if (input.mode !== 'range') {return false;}
196
+ if (input.mode !== 'range') {
197
+ return false;
198
+ }
197
199
  return isSpanHighlighted({
198
200
  date: input.date,
199
201
  spanStart: input.rangeStart,
@@ -64,9 +64,19 @@ export const calendarStyles = stylex.create({
64
64
  whiteSpace: 'nowrap',
65
65
  borderWidth: 0,
66
66
  },
67
+ /**
68
+ * Wrapper for the month nav chevrons. In RTL the flex header already
69
+ * swaps the buttons' visual sides; the glyphs must mirror with them so
70
+ * "Previous month" points outward (visually right) instead of inward.
71
+ * Keyed on the dir attribute (dir="rtl"), same as MobileNav's drawer
72
+ * transform — bare CSS `direction: rtl` alone won't trigger it.
73
+ */
67
74
  navIcon: {
68
- width: spacingVars['--spacing-4'],
69
- height: spacingVars['--spacing-4'],
75
+ display: 'inline-flex',
76
+ transform: {
77
+ default: null,
78
+ ':is([dir="rtl"] *)': 'scaleX(-1)',
79
+ },
70
80
  },
71
81
  });
72
82
 
@@ -131,7 +131,7 @@ export const docsZh = {
131
131
  theming: {
132
132
  container: true,
133
133
  targets: [
134
- {className: 'astryx-card'},
134
+ {className: 'astryx-card', visualProps: ['variant']},
135
135
  ],
136
136
  vars: [
137
137
  {name: '--_card-radius', description: 'Border radius of the card', default: 'var(--radius-container)', private: true},
package/src/Card/Card.tsx CHANGED
@@ -44,8 +44,10 @@ import {themeProps} from '../utils/themeProps';
44
44
  * - Non-semantic palette: `blue | cyan | gray | green | orange | pink | purple | red | teal | yellow`
45
45
  * Each uses the corresponding `--color-background-<name>` token (20% opacity tint).
46
46
  *
47
- * All variants include a transparent border to prevent layout jitter
48
- * when switching variants. Themes can override borderWidth/borderColor.
47
+ * Only `default` draws a visible border. Its border width is subtracted from
48
+ * the padding so the total inset (border + padding) equals the padding token —
49
+ * keeping content geometry faithful to the spacing scale and identical to the
50
+ * borderless variants. Themes can override borderWidth/borderColor.
49
51
  */
50
52
  export type CardVariant =
51
53
  | 'default'
@@ -71,12 +73,18 @@ const styles = stylex.create({
71
73
  '--_card-radius': radiusVars['--radius-container'],
72
74
  borderRadius: 'var(--_card-radius)',
73
75
  overflow: 'clip',
74
- borderWidth: borderVars['--border-width'],
75
- borderStyle: 'solid',
76
- borderColor: 'transparent',
77
76
  },
77
+ // The border is drawn *inside* the padding — its width is subtracted from
78
+ // each side — so total inset (border + padding) equals the padding token
79
+ // rather than exceeding it by the border width.
78
80
  withBorder: {
81
+ borderWidth: borderVars['--border-width'],
82
+ borderStyle: 'solid',
79
83
  borderColor: colorVars['--color-border-emphasized'],
84
+ paddingInlineStart: `calc(var(--container-padding-inline-start) - ${borderVars['--border-width']})`,
85
+ paddingInlineEnd: `calc(var(--container-padding-inline-end) - ${borderVars['--border-width']})`,
86
+ paddingBlockStart: `calc(var(--container-padding-block-start) - ${borderVars['--border-width']})`,
87
+ paddingBlockEnd: `calc(var(--container-padding-block-end) - ${borderVars['--border-width']})`,
80
88
  },
81
89
  // Fixed-height cards scroll content; overflow: auto also clips to border-radius
82
90
  scrollable: {
@@ -266,7 +274,6 @@ export function Card({
266
274
  stylex.props(
267
275
  styles.card,
268
276
  variantStyles[variant],
269
- variant === 'default' && styles.withBorder,
270
277
  hasFixedHeight && styles.scrollable,
271
278
  dynamicStyles.sizing(
272
279
  width ?? null,
@@ -296,6 +303,9 @@ export function Card({
296
303
  !useThemeDefault &&
297
304
  effectivePadding !== 4 &&
298
305
  containerPaddingBlockEndVarStyles[effectivePadding],
306
+ // Applied after the container padding so the border-inset calc wins;
307
+ // it reads the --container-padding-* vars set above.
308
+ variant === 'default' && styles.withBorder,
299
309
  xstyle,
300
310
  ),
301
311
  className,
@@ -20,15 +20,15 @@ export const docs = {
20
20
  ],
21
21
  anatomy: [
22
22
  {name: 'Scroll container', required: true, description: 'The horizontal overflow area that holds all items.'},
23
- {name: 'Items', required: true, description: 'The children rendered in a row. Each item is animated with a scroll-driven scale effect.'},
23
+ {name: 'Items', required: true, description: 'The children rendered in a row inside the scroll container. With hasSnap, each item snaps to the start edge.'},
24
24
  {name: 'Fade edges', required: false, description: 'Gradient fades on the left and right edges that indicate more content is available. Enabled by default, disable with hasEdgeFade={false}.'},
25
- {name: 'Navigation buttons', required: false, description: 'Prev/next buttons that appear on hover. Enabled by default, disable with hasButtons={false}.'},
25
+ {name: 'Navigation buttons', required: false, description: 'Prev/next buttons that appear when the content can scroll in that direction. Enabled by default, disable with hasButtons={false}.'},
26
26
  ],
27
27
  },
28
28
  props: [
29
29
  {name: 'children', type: 'ReactNode', description: 'Carousel items rendered in a horizontal scroll container.', required: true},
30
30
  {name: 'gap', type: "0 | 0.5 | 1 | 1.5 | 2 | 3 | 4", description: 'Gap between items using the spacing token scale.', default: '1'},
31
- {name: 'hasButtons', type: 'boolean', description: 'Show prev/next navigation buttons on hover (desktop only).', default: 'true'},
31
+ {name: 'hasButtons', type: 'boolean', description: 'Show prev/next navigation buttons when content is scrollable.', default: 'true'},
32
32
  {name: 'hasEdgeFade', type: 'boolean', description: 'Show a gradient edge-fade mask when content overflows, signalling that more items exist off-screen.', default: 'true'},
33
33
  {name: 'hasSnap', type: 'boolean', description: 'Enable scroll-snap so each child snaps to the start edge.', default: 'false'},
34
34
  {name: 'padding', type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10', description: 'Inline padding inside the scroll container, with matching scroll-padding so snap points align to the content edge.'},
@@ -59,20 +59,20 @@ export const docs = {
59
59
  export const docsZh = {
60
60
  usage: {
61
61
  description:
62
- 'Carousel scrolls a row of items horizontally when they overflow the available width. Use it for card grids, image galleries, product lists, or any set of items that should be browsable without taking up the full page.',
62
+ 'Carousel 在项目超出可用宽度时将一行项目水平滚动。适用于卡片网格、图片画廊、产品列表,或任何希望无需占据整页即可浏览的项目集合。',
63
63
  bestPractices: [
64
- {guidance: true, description: 'Enable scroll-snap when each item should land precisely at the start edge, like a gallery or product list.'},
65
- {guidance: true, description: 'Always provide an aria-label that describes what the carousel contains, like "Featured products" or "Team members".'},
66
- {guidance: true, description: 'Use a consistent gap and item width so the carousel looks intentional, not like content overflowing by accident.'},
67
- {guidance: false, description: 'Use a carousel for content every user must see. Not everyone scrolls horizontally, so put critical content above the fold.'},
68
- {guidance: false, description: 'Auto-advance items. Let the user scroll at their own pace.'},
69
- {guidance: false, description: 'Nest carousels. A carousel inside a carousel is confusing and breaks keyboard navigation.'},
64
+ {guidance: true, description: '当每个项目应精确对齐到起始边缘时启用滚动吸附,例如画廊或产品列表。'},
65
+ {guidance: true, description: '始终提供描述轮播内容的 aria-label,例如"精选产品""团队成员"'},
66
+ {guidance: true, description: '使用一致的间距和项目宽度,让轮播看起来是有意为之,而不是内容意外溢出。'},
67
+ {guidance: false, description: '将每位用户都必须看到的内容放入轮播。并非所有人都会水平滚动,关键内容应放在首屏。'},
68
+ {guidance: false, description: '自动轮播项目。让用户按自己的节奏滚动。'},
69
+ {guidance: false, description: '嵌套轮播。轮播中嵌套轮播会造成困惑并破坏键盘导航。'},
70
70
  ],
71
71
  },
72
72
  propDescriptions: {
73
73
  children: '在水平滚动容器中渲染的轮播项目。',
74
74
  gap: '使用间距令牌比例的项目间距。',
75
- hasButtons: '悬停时显示上一个/下一个导航按钮(仅桌面端)。',
75
+ hasButtons: '内容可滚动时显示上一个/下一个导航按钮。',
76
76
  hasEdgeFade: '内容溢出时显示渐变边缘遮罩,提示屏幕外还有更多项目。',
77
77
  hasSnap: '启用滚动吸附,使每个子元素吸附到起始边缘。',
78
78
  padding: '滚动容器内的内联内边距,并设置匹配的 scroll-padding,使吸附点与内容边缘对齐。',
@@ -98,7 +98,7 @@ export const docsDense = {
98
98
  propDescriptions: {
99
99
  children: 'carousel items in horizontal scroll',
100
100
  gap: 'item spacing via spacing token scale',
101
- hasButtons: 'prev/next buttons on hover (desktop)',
101
+ hasButtons: 'prev/next buttons when content is scrollable',
102
102
  hasEdgeFade: 'gradient edge-fade mask on overflow',
103
103
  hasSnap: 'scroll-snap; children snap to start edge',
104
104
  padding: 'inline padding; scroll-padding keeps snap points on content edge',
@@ -38,6 +38,19 @@ describe('Carousel', () => {
38
38
  expect(region).toHaveAttribute('aria-roledescription', 'carousel');
39
39
  });
40
40
 
41
+ it('makes the scroll container keyboard-focusable', () => {
42
+ render(
43
+ <Carousel aria-label="Photos">
44
+ <div>Item</div>
45
+ </Carousel>,
46
+ );
47
+ // The inner scroll container overflows, so it must be reachable by
48
+ // keyboard (axe: scrollable-region-focusable).
49
+ const region = screen.getByRole('region', {name: 'Photos'});
50
+ const scroller = region.firstElementChild;
51
+ expect(scroller).toHaveAttribute('tabindex', '0');
52
+ });
53
+
41
54
  it('applies data-testid', () => {
42
55
  render(
43
56
  <Carousel data-testid="my-carousel">
@@ -318,6 +318,8 @@ export function Carousel({
318
318
  : null
319
319
  : null;
320
320
 
321
+ // Self-authored position styles (positioning: 'custom' below): a cover
322
+ // centered on the anchor, sized to it — direction-neutral by construction.
321
323
  const coverStyle: React.CSSProperties = {
322
324
  positionArea: 'center',
323
325
  width: 'anchor-size(width)',
@@ -340,6 +342,7 @@ export function Carousel({
340
342
  {...htmlProps}>
341
343
  <div
342
344
  ref={composedRef}
345
+ tabIndex={0}
343
346
  {...stylex.props(
344
347
  styles.scroller,
345
348
  gapStyles[gap],
@@ -397,8 +400,7 @@ export function Carousel({
397
400
  </div>
398
401
  </>,
399
402
  {
400
- placement: 'below',
401
- alignment: 'center',
403
+ positioning: 'custom',
402
404
  style: coverStyle,
403
405
  xstyle: styles.buttonOverlay,
404
406
  },
@@ -17,7 +17,7 @@ export const docs = {
17
17
  {className: 'astryx-chat-composer', visualProps: ['density']},
18
18
  {className: 'astryx-chat-composer-input'},
19
19
  {className: 'astryx-chat-composer-drawer', visualProps: ['collapsed']},
20
- {className: 'astryx-chat-message', visualProps: ['sender']},
20
+ {className: 'astryx-chat-message', visualProps: ['sender', 'density']},
21
21
  {
22
22
  className: 'astryx-chat-message-bubble',
23
23
  visualProps: ['sender', 'variant', 'density'],
@@ -2,6 +2,7 @@
2
2
 
3
3
  import {describe, it, expect, vi, afterEach} from 'vitest';
4
4
  import {render, screen, fireEvent} from '@testing-library/react';
5
+ import {ChatComposer} from './ChatComposer';
5
6
  import {ChatComposerInput} from './ChatComposerInput';
6
7
  import type {
7
8
  ChatComposerTrigger,
@@ -129,6 +130,29 @@ describe('ChatComposerInput', () => {
129
130
  fireEvent.keyDown(textbox, {key: 'Enter'});
130
131
  expect(onSubmit).not.toHaveBeenCalled();
131
132
  });
133
+
134
+ it('keeps parent submit flow when child onChange observes input changes', () => {
135
+ const onSubmit = vi.fn();
136
+ const onInputChange = vi.fn();
137
+ render(
138
+ <ChatComposer
139
+ onSubmit={onSubmit}
140
+ input={<ChatComposerInput onChange={onInputChange} />}
141
+ />,
142
+ );
143
+
144
+ const textbox = screen.getByRole('textbox');
145
+ textbox.textContent = 'hello world';
146
+ fireEvent.input(textbox);
147
+
148
+ expect(onInputChange).toHaveBeenLastCalledWith('hello world');
149
+
150
+ fireEvent.keyDown(textbox, {key: 'Enter'});
151
+
152
+ expect(onSubmit).toHaveBeenCalledWith('hello world');
153
+ expect(onInputChange).toHaveBeenLastCalledWith('');
154
+ expect(textbox.textContent).toBe('');
155
+ });
132
156
  });
133
157
 
134
158
  // Controlled-value sync used to overwrite `textContent` on every
@@ -345,7 +369,9 @@ describe('ChatComposerInput', () => {
345
369
  },
346
370
  });
347
371
 
348
- expect(textbox.querySelector('[data-astryx-token]')).not.toBeInTheDocument();
372
+ expect(
373
+ textbox.querySelector('[data-astryx-token]'),
374
+ ).not.toBeInTheDocument();
349
375
  expect(textbox.textContent).toBe(long);
350
376
  });
351
377
  });
@@ -43,10 +43,7 @@ import {
43
43
  } from '../theme/tokens.stylex';
44
44
  import {mergeProps} from '../utils';
45
45
  import {useTriggerMenu} from './useTriggerMenu';
46
- import {
47
- useChatComposerTokens,
48
- isCustomToken,
49
- } from './useChatComposerTokens';
46
+ import {useChatComposerTokens, isCustomToken} from './useChatComposerTokens';
50
47
  import {ensureCaretInside, insertTextAtCursor} from './chatComposerSelection';
51
48
  import {ChatPastedTextToken} from './ChatPastedTextToken';
52
49
  import {
@@ -283,12 +280,13 @@ function serialize(node: Node): string {
283
280
 
284
281
  export function ChatComposerInput(props: ChatComposerInputProps) {
285
282
  const composerCtx = useChatComposerContext();
283
+ const hasControlledValueProp = props.value !== undefined;
286
284
 
287
285
  const {
288
286
  ref,
289
287
  handleRef,
290
288
  value: controlledValue = composerCtx?.value,
291
- onChange = composerCtx?.onChange,
289
+ onChange: onChangeProp,
292
290
  placeholder = composerCtx?.placeholder ?? 'Type a message\u2026',
293
291
  maxRows = 8,
294
292
  triggers,
@@ -306,6 +304,21 @@ export function ChatComposerInput(props: ChatComposerInputProps) {
306
304
  ...rest
307
305
  } = props;
308
306
 
307
+ const composerOnChange = composerCtx?.onChange;
308
+ const onChange = useCallback(
309
+ (nextValue: string) => {
310
+ if (hasControlledValueProp) {
311
+ onChangeProp?.(nextValue);
312
+ return;
313
+ }
314
+ composerOnChange?.(nextValue);
315
+ if (onChangeProp !== composerOnChange) {
316
+ onChangeProp?.(nextValue);
317
+ }
318
+ },
319
+ [composerOnChange, hasControlledValueProp, onChangeProp],
320
+ );
321
+
309
322
  const editableRef = useRef<HTMLDivElement>(null);
310
323
  const selfRef = useRef<ChatComposerInputHandle>(null);
311
324
  const [isEmpty, setIsEmpty] = useState(true);
@@ -679,11 +692,7 @@ ChatComposerInput.displayName = 'ChatComposerInput';
679
692
  // Token element helper (for custom rendering in stories/consumers)
680
693
  // =============================================================================
681
694
 
682
- export function ChatComposerTokenElement({
683
- token,
684
- }: {
685
- token: ChatComposerToken;
686
- }) {
695
+ export function ChatComposerTokenElement({token}: {token: ChatComposerToken}) {
687
696
  return (
688
697
  <span
689
698
  data-astryx-token=""
@@ -693,11 +702,7 @@ export function ChatComposerTokenElement({
693
702
  {isCustomToken(token) ? (
694
703
  token.render()
695
704
  ) : (
696
- <Badge
697
- label={token.label}
698
- variant={token.variant}
699
- icon={token.icon}
700
- />
705
+ <Badge label={token.label} variant={token.variant} icon={token.icon} />
701
706
  )}
702
707
  </span>
703
708
  );