@astryxdesign/core 0.1.5 → 0.1.6-canary.02f2602

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 (564) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +2 -0
  3. package/dist/AlertDialog/AlertDialog.d.ts +1 -1
  4. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  5. package/dist/AlertDialog/AlertDialog.js +21 -18
  6. package/dist/AlertDialog/useImperativeAlertDialog.d.ts +0 -2
  7. package/dist/AlertDialog/useImperativeAlertDialog.d.ts.map +1 -1
  8. package/dist/AlertDialog/useImperativeAlertDialog.js +3 -5
  9. package/dist/AppShell/AppShell.d.ts.map +1 -1
  10. package/dist/AppShell/AppShell.js +55 -53
  11. package/dist/AspectRatio/AspectRatio.js +5 -5
  12. package/dist/Avatar/Avatar.js +19 -19
  13. package/dist/Avatar/AvatarStatusDot.js +5 -5
  14. package/dist/AvatarGroup/AvatarGroup.d.ts +1 -1
  15. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  16. package/dist/AvatarGroup/AvatarGroup.js +9 -6
  17. package/dist/AvatarGroup/AvatarGroupOverflow.js +5 -5
  18. package/dist/Badge/Badge.js +3 -3
  19. package/dist/Banner/Banner.d.ts.map +1 -1
  20. package/dist/Banner/Banner.js +32 -30
  21. package/dist/Blockquote/Blockquote.js +7 -7
  22. package/dist/Breadcrumbs/BreadcrumbItem.js +17 -17
  23. package/dist/Breadcrumbs/Breadcrumbs.d.ts +1 -1
  24. package/dist/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
  25. package/dist/Breadcrumbs/Breadcrumbs.js +11 -8
  26. package/dist/Button/Button.d.ts.map +1 -1
  27. package/dist/Button/Button.js +53 -23
  28. package/dist/ButtonGroup/ButtonGroup.d.ts +20 -5
  29. package/dist/ButtonGroup/ButtonGroup.d.ts.map +1 -1
  30. package/dist/ButtonGroup/ButtonGroup.js +34 -18
  31. package/dist/Calendar/Calendar.d.ts.map +1 -1
  32. package/dist/Calendar/Calendar.js +51 -48
  33. package/dist/Card/Card.js +3 -3
  34. package/dist/Carousel/Carousel.d.ts +1 -1
  35. package/dist/Carousel/Carousel.d.ts.map +1 -1
  36. package/dist/Carousel/Carousel.js +27 -24
  37. package/dist/Center/Center.js +3 -3
  38. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  39. package/dist/Chat/ChatComposer.js +27 -24
  40. package/dist/Chat/ChatComposerDrawer.d.ts +1 -1
  41. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  42. package/dist/Chat/ChatComposerDrawer.js +23 -16
  43. package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
  44. package/dist/Chat/ChatComposerInput.js +20 -16
  45. package/dist/Chat/ChatDictationButton.js +10 -10
  46. package/dist/Chat/ChatLayout.d.ts +1 -11
  47. package/dist/Chat/ChatLayout.d.ts.map +1 -1
  48. package/dist/Chat/ChatLayout.js +23 -21
  49. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  50. package/dist/Chat/ChatLayoutScrollButton.js +13 -11
  51. package/dist/Chat/ChatMessage.d.ts +1 -1
  52. package/dist/Chat/ChatMessage.d.ts.map +1 -1
  53. package/dist/Chat/ChatMessage.js +20 -14
  54. package/dist/Chat/ChatMessageBubble.d.ts +1 -1
  55. package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
  56. package/dist/Chat/ChatMessageBubble.js +10 -8
  57. package/dist/Chat/ChatMessageList.d.ts +1 -1
  58. package/dist/Chat/ChatMessageList.d.ts.map +1 -1
  59. package/dist/Chat/ChatMessageList.js +17 -15
  60. package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
  61. package/dist/Chat/ChatMessageMetadata.js +24 -19
  62. package/dist/Chat/ChatPastedTextToken.d.ts.map +1 -1
  63. package/dist/Chat/ChatPastedTextToken.js +16 -14
  64. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  65. package/dist/Chat/ChatSendButton.js +6 -4
  66. package/dist/Chat/ChatSystemMessage.js +11 -11
  67. package/dist/Chat/ChatTokenizedText.js +8 -8
  68. package/dist/Chat/ChatToolCalls.js +73 -73
  69. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  70. package/dist/Chat/useSpeechRecognition.js +4 -2
  71. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  72. package/dist/Chat/useTriggerMenu.js +19 -17
  73. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  74. package/dist/CheckboxInput/CheckboxInput.js +26 -24
  75. package/dist/CheckboxList/CheckboxList.d.ts +1 -1
  76. package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
  77. package/dist/CheckboxList/CheckboxList.js +12 -10
  78. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  79. package/dist/CheckboxList/CheckboxListItem.js +8 -6
  80. package/dist/Citation/Citation.d.ts.map +1 -1
  81. package/dist/Citation/Citation.js +20 -12
  82. package/dist/ClickableCard/ClickableCard.js +6 -6
  83. package/dist/Code/Code.js +3 -3
  84. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  85. package/dist/CodeBlock/CodeBlock.js +114 -96
  86. package/dist/Collapsible/Collapsible.js +11 -11
  87. package/dist/Collapsible/CollapsibleGroup.js +7 -7
  88. package/dist/CommandPalette/CommandPalette.d.ts +1 -1
  89. package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
  90. package/dist/CommandPalette/CommandPalette.js +39 -34
  91. package/dist/CommandPalette/CommandPaletteEmpty.js +3 -3
  92. package/dist/CommandPalette/CommandPaletteFooter.js +16 -16
  93. package/dist/CommandPalette/CommandPaletteGroup.js +5 -5
  94. package/dist/CommandPalette/CommandPaletteInput.d.ts +1 -1
  95. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  96. package/dist/CommandPalette/CommandPaletteInput.js +17 -14
  97. package/dist/CommandPalette/CommandPaletteItem.js +3 -3
  98. package/dist/CommandPalette/CommandPaletteList.d.ts +1 -1
  99. package/dist/CommandPalette/CommandPaletteList.d.ts.map +1 -1
  100. package/dist/CommandPalette/CommandPaletteList.js +7 -4
  101. package/dist/ContextMenu/ContextMenu.d.ts +1 -1
  102. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  103. package/dist/ContextMenu/ContextMenu.js +14 -11
  104. package/dist/DateInput/DateInput.d.ts +1 -1
  105. package/dist/DateInput/DateInput.d.ts.map +1 -1
  106. package/dist/DateInput/DateInput.js +28 -23
  107. package/dist/DateRangeInput/DateRangeInput.d.ts +1 -1
  108. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  109. package/dist/DateRangeInput/DateRangeInput.js +32 -27
  110. package/dist/DateTimeInput/DateTimeInput.d.ts +1 -1
  111. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  112. package/dist/DateTimeInput/DateTimeInput.js +41 -33
  113. package/dist/Dialog/Dialog.js +9 -9
  114. package/dist/Dialog/DialogHeader.d.ts.map +1 -1
  115. package/dist/Dialog/DialogHeader.js +20 -18
  116. package/dist/Dialog/useImperativeDialog.js +3 -3
  117. package/dist/Divider/Divider.js +7 -7
  118. package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
  119. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  120. package/dist/DropdownMenu/DropdownMenu.js +21 -15
  121. package/dist/DropdownMenu/DropdownMenuItem.js +3 -3
  122. package/dist/DropdownMenu/renderDropdownItems.js +10 -10
  123. package/dist/EmptyState/EmptyState.d.ts +4 -1
  124. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  125. package/dist/EmptyState/EmptyState.js +9 -9
  126. package/dist/Field/Field.js +17 -17
  127. package/dist/Field/FieldLabel.js +15 -15
  128. package/dist/Field/InputClearButton.js +5 -5
  129. package/dist/FieldStatus/FieldStatus.js +3 -3
  130. package/dist/FileInput/FileInput.d.ts.map +1 -1
  131. package/dist/FileInput/FileInput.js +34 -30
  132. package/dist/FormLayout/FormLayout.js +5 -5
  133. package/dist/Grid/Grid.js +3 -3
  134. package/dist/Grid/GridSpan.js +3 -3
  135. package/dist/HStack/HStack.js +3 -3
  136. package/dist/Heading/Heading.js +10 -10
  137. package/dist/HoverCard/HoverCard.js +9 -9
  138. package/dist/HoverCard/useHoverCard.js +3 -3
  139. package/dist/Icon/Icon.js +11 -11
  140. package/dist/Icon/defaultIcons.js +116 -116
  141. package/dist/IconButton/IconButton.js +3 -3
  142. package/dist/InputGroup/InputGroup.js +9 -9
  143. package/dist/InputGroup/InputGroupText.js +3 -3
  144. package/dist/Item/Item.js +17 -17
  145. package/dist/Kbd/Kbd.js +5 -5
  146. package/dist/Layer/LayerProvider.js +7 -7
  147. package/dist/Layer/useLayer.js +5 -5
  148. package/dist/Layout/Layout.js +21 -21
  149. package/dist/Layout/LayoutContent.js +3 -3
  150. package/dist/Layout/LayoutFooter.js +5 -5
  151. package/dist/Layout/LayoutHeader.js +5 -5
  152. package/dist/Layout/LayoutPanel.js +3 -3
  153. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  154. package/dist/Lightbox/Lightbox.js +35 -33
  155. package/dist/Lightbox/useLightbox.d.ts +0 -1
  156. package/dist/Lightbox/useLightbox.d.ts.map +1 -1
  157. package/dist/Lightbox/useLightbox.js +3 -4
  158. package/dist/Link/Link.d.ts +5 -3
  159. package/dist/Link/Link.d.ts.map +1 -1
  160. package/dist/Link/Link.js +47 -18
  161. package/dist/Link/LinkProvider.js +3 -3
  162. package/dist/Link/useLinkify.js +3 -3
  163. package/dist/List/List.js +11 -11
  164. package/dist/List/ListItem.js +11 -11
  165. package/dist/Markdown/Markdown.d.ts.map +1 -1
  166. package/dist/Markdown/Markdown.js +111 -109
  167. package/dist/MetadataList/MetadataList.js +10 -10
  168. package/dist/MetadataList/MetadataListItem.js +15 -15
  169. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  170. package/dist/MobileNav/MobileNav.js +19 -17
  171. package/dist/MobileNav/MobileNavToggle.d.ts +1 -1
  172. package/dist/MobileNav/MobileNavToggle.d.ts.map +1 -1
  173. package/dist/MobileNav/MobileNavToggle.js +9 -6
  174. package/dist/MoreMenu/MoreMenu.d.ts +1 -1
  175. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  176. package/dist/MoreMenu/MoreMenu.js +7 -4
  177. package/dist/MultiSelector/MultiSelector.d.ts +1 -1
  178. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  179. package/dist/MultiSelector/MultiSelector.js +69 -62
  180. package/dist/NavIcon/NavIcon.js +3 -3
  181. package/dist/NavMenu/NavHeadingMenu.js +5 -5
  182. package/dist/NavMenu/NavHeadingMenuItem.js +8 -8
  183. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  184. package/dist/NumberInput/NumberInput.js +21 -17
  185. package/dist/Outline/Outline.d.ts +1 -1
  186. package/dist/Outline/Outline.d.ts.map +1 -1
  187. package/dist/Outline/Outline.js +19 -16
  188. package/dist/OverflowList/OverflowList.js +8 -8
  189. package/dist/Overlay/Overlay.js +3 -3
  190. package/dist/Overlay/OverlayScrim.js +5 -5
  191. package/dist/Overlay/useOverlay.d.ts +0 -3
  192. package/dist/Overlay/useOverlay.d.ts.map +1 -1
  193. package/dist/Overlay/useOverlay.js +3 -6
  194. package/dist/Pagination/Pagination.d.ts +1 -1
  195. package/dist/Pagination/Pagination.d.ts.map +1 -1
  196. package/dist/Pagination/Pagination.js +73 -46
  197. package/dist/Popover/Popover.js +16 -16
  198. package/dist/Popover/usePopover.d.ts.map +1 -1
  199. package/dist/Popover/usePopover.js +11 -8
  200. package/dist/PowerSearch/PowerSearch.d.ts +1 -1
  201. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  202. package/dist/PowerSearch/PowerSearch.js +95 -85
  203. package/dist/PowerSearch/PowerSearchEditPopover.d.ts +1 -1
  204. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  205. package/dist/PowerSearch/PowerSearchEditPopover.js +109 -103
  206. package/dist/PowerSearch/PowerSearchFilterEditor.js +3 -3
  207. package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
  208. package/dist/PowerSearch/PowerSearchToken.js +12 -8
  209. package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
  210. package/dist/PowerSearch/PowerSearchValueEditor.js +88 -75
  211. package/dist/PowerSearch/formatFilterValue.d.ts +2 -1
  212. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  213. package/dist/PowerSearch/formatFilterValue.js +19 -9
  214. package/dist/PowerSearch/index.d.ts +2 -1
  215. package/dist/PowerSearch/index.d.ts.map +1 -1
  216. package/dist/PowerSearch/index.js +1 -0
  217. package/dist/PowerSearch/resolveOperatorLabel.d.ts +23 -0
  218. package/dist/PowerSearch/resolveOperatorLabel.d.ts.map +1 -0
  219. package/dist/PowerSearch/resolveOperatorLabel.js +28 -0
  220. package/dist/PowerSearch/types.d.ts +28 -2
  221. package/dist/PowerSearch/types.d.ts.map +1 -1
  222. package/dist/PowerSearch/usePowerSearchConfig.d.ts.map +1 -1
  223. package/dist/PowerSearch/usePowerSearchConfig.js +27 -27
  224. package/dist/PowerSearch/usePowerSearchSource.d.ts.map +1 -1
  225. package/dist/PowerSearch/usePowerSearchSource.js +15 -8
  226. package/dist/ProgressBar/ProgressBar.js +13 -13
  227. package/dist/RadioList/RadioList.js +7 -7
  228. package/dist/RadioList/RadioListItem.js +18 -18
  229. package/dist/Resizable/ResizeHandle.d.ts +1 -1
  230. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  231. package/dist/Resizable/ResizeHandle.js +10 -7
  232. package/dist/Section/Section.js +5 -5
  233. package/dist/SegmentedControl/SegmentedControl.js +5 -5
  234. package/dist/SegmentedControl/SegmentedControlItem.js +7 -7
  235. package/dist/SelectableCard/SelectableCard.js +5 -5
  236. package/dist/Selector/Selector.d.ts.map +1 -1
  237. package/dist/Selector/Selector.js +57 -51
  238. package/dist/Selector/SelectorOption.js +3 -3
  239. package/dist/SideNav/SideNav.d.ts.map +1 -1
  240. package/dist/SideNav/SideNav.js +38 -36
  241. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  242. package/dist/SideNav/SideNavCollapseButton.js +8 -6
  243. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  244. package/dist/SideNav/SideNavHeading.js +92 -90
  245. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  246. package/dist/SideNav/SideNavItem.js +49 -43
  247. package/dist/SideNav/SideNavSection.js +14 -14
  248. package/dist/Skeleton/Skeleton.js +3 -3
  249. package/dist/Slider/Slider.js +23 -23
  250. package/dist/Spinner/Spinner.js +9 -9
  251. package/dist/StatusDot/StatusDot.js +5 -5
  252. package/dist/Switch/Switch.d.ts.map +1 -1
  253. package/dist/Switch/Switch.js +29 -27
  254. package/dist/TabList/Tab.js +18 -18
  255. package/dist/TabList/TabList.d.ts +1 -1
  256. package/dist/TabList/TabList.d.ts.map +1 -1
  257. package/dist/TabList/TabList.js +9 -6
  258. package/dist/TabList/TabMenu.js +23 -23
  259. package/dist/Table/BaseTable.d.ts.map +1 -1
  260. package/dist/Table/BaseTable.js +39 -37
  261. package/dist/Table/Table.d.ts.map +1 -1
  262. package/dist/Table/Table.js +10 -8
  263. package/dist/Table/TableBody.js +3 -3
  264. package/dist/Table/TableCell.js +3 -3
  265. package/dist/Table/TableFooter.js +3 -3
  266. package/dist/Table/TableHeader.js +3 -3
  267. package/dist/Table/TableHeaderCell.js +3 -3
  268. package/dist/Table/TableRow.js +5 -5
  269. package/dist/Table/index.d.ts +4 -0
  270. package/dist/Table/index.d.ts.map +1 -1
  271. package/dist/Table/index.js +2 -0
  272. package/dist/Table/plugins/columnResize/useTableColumnResize.js +9 -9
  273. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  274. package/dist/Table/plugins/filtering/useTableFiltering.js +127 -90
  275. package/dist/Table/plugins/groupedRows/index.d.ts +3 -0
  276. package/dist/Table/plugins/groupedRows/index.d.ts.map +1 -0
  277. package/dist/Table/plugins/groupedRows/index.js +3 -0
  278. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +78 -0
  279. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -0
  280. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +257 -0
  281. package/dist/Table/plugins/pagination/useTablePagination.d.ts.map +1 -1
  282. package/dist/Table/plugins/pagination/useTablePagination.js +12 -9
  283. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +1 -1
  284. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  285. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +30 -28
  286. package/dist/Table/plugins/rowIndex/index.d.ts +3 -0
  287. package/dist/Table/plugins/rowIndex/index.d.ts.map +1 -0
  288. package/dist/Table/plugins/rowIndex/index.js +3 -0
  289. package/dist/Table/plugins/rowIndex/useTableRowIndex.d.ts +50 -0
  290. package/dist/Table/plugins/rowIndex/useTableRowIndex.d.ts.map +1 -0
  291. package/dist/Table/plugins/rowIndex/useTableRowIndex.js +91 -0
  292. package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
  293. package/dist/Table/plugins/selection/useTableSelection.js +23 -20
  294. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  295. package/dist/Table/plugins/sortable/useTableSortable.js +23 -21
  296. package/dist/Table/tableContextMenu.js +9 -9
  297. package/dist/Text/Text.js +10 -10
  298. package/dist/TextArea/TextArea.js +14 -14
  299. package/dist/TextInput/TextInput.d.ts.map +1 -1
  300. package/dist/TextInput/TextInput.js +20 -16
  301. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  302. package/dist/Thumbnail/Thumbnail.js +37 -31
  303. package/dist/TimeInput/TimeInput.d.ts +1 -1
  304. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  305. package/dist/TimeInput/TimeInput.js +28 -23
  306. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  307. package/dist/Timestamp/Timestamp.js +29 -14
  308. package/dist/Toast/Toast.d.ts.map +1 -1
  309. package/dist/Toast/Toast.js +17 -15
  310. package/dist/Toast/ToastViewport.d.ts.map +1 -1
  311. package/dist/Toast/ToastViewport.js +14 -12
  312. package/dist/Toast/useToast.js +4 -4
  313. package/dist/ToggleButton/ToggleButton.js +12 -12
  314. package/dist/ToggleButton/ToggleButtonGroup.js +5 -5
  315. package/dist/Token/Token.d.ts.map +1 -1
  316. package/dist/Token/Token.js +29 -23
  317. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  318. package/dist/Tokenizer/Tokenizer.js +33 -31
  319. package/dist/Toolbar/Toolbar.js +18 -18
  320. package/dist/Tooltip/Tooltip.js +11 -11
  321. package/dist/Tooltip/useTooltip.js +3 -3
  322. package/dist/TopNav/TopNav.d.ts +2 -1
  323. package/dist/TopNav/TopNav.d.ts.map +1 -1
  324. package/dist/TopNav/TopNav.js +36 -33
  325. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  326. package/dist/TopNav/TopNavHeading.js +72 -70
  327. package/dist/TopNav/TopNavItem.js +5 -5
  328. package/dist/TopNav/TopNavMegaMenu.js +30 -30
  329. package/dist/TopNav/TopNavMegaMenuFeaturedCard.js +10 -10
  330. package/dist/TopNav/TopNavMegaMenuItem.js +16 -16
  331. package/dist/TopNav/TopNavMenu.js +32 -32
  332. package/dist/TreeList/TreeList.d.ts.map +1 -1
  333. package/dist/TreeList/TreeList.js +13 -9
  334. package/dist/TreeList/TreeListBranches.js +11 -11
  335. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  336. package/dist/TreeList/TreeListItem.js +37 -31
  337. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  338. package/dist/Typeahead/BaseTypeahead.js +26 -22
  339. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  340. package/dist/Typeahead/Typeahead.js +15 -13
  341. package/dist/Typeahead/TypeaheadItem.js +10 -10
  342. package/dist/VStack/VStack.js +3 -3
  343. package/dist/VisuallyHidden/VisuallyHidden.d.ts +1 -3
  344. package/dist/VisuallyHidden/VisuallyHidden.d.ts.map +1 -1
  345. package/dist/VisuallyHidden/VisuallyHidden.js +1 -3
  346. package/dist/astryx.css +20 -2
  347. package/dist/astryx.umd.js +66 -64
  348. package/dist/astryx.umd.js.map +4 -4
  349. package/dist/authoring/doc.d.ts +145 -0
  350. package/dist/authoring/doc.d.ts.map +1 -0
  351. package/dist/authoring/doc.js +100 -0
  352. package/dist/authoring/index.d.ts +29 -0
  353. package/dist/authoring/index.d.ts.map +1 -0
  354. package/dist/authoring/index.js +28 -0
  355. package/dist/authoring/integration.d.ts +35 -0
  356. package/dist/authoring/integration.d.ts.map +1 -0
  357. package/dist/authoring/integration.js +30 -0
  358. package/dist/authoring/template.d.ts +66 -0
  359. package/dist/authoring/template.d.ts.map +1 -0
  360. package/dist/authoring/template.js +55 -0
  361. package/dist/config.d.ts +80 -0
  362. package/dist/config.d.ts.map +1 -0
  363. package/dist/config.js +40 -0
  364. package/dist/hooks/useKeyboardHint.js +9 -9
  365. package/dist/i18n/InternationalizationContext.d.ts +12 -0
  366. package/dist/i18n/InternationalizationContext.d.ts.map +1 -0
  367. package/dist/i18n/InternationalizationContext.js +29 -0
  368. package/dist/i18n/InternationalizationProvider.d.ts +62 -0
  369. package/dist/i18n/InternationalizationProvider.d.ts.map +1 -0
  370. package/dist/i18n/InternationalizationProvider.js +44 -0
  371. package/dist/i18n/index.d.ts +24 -0
  372. package/dist/i18n/index.d.ts.map +1 -0
  373. package/dist/i18n/index.js +21 -0
  374. package/dist/i18n/resolve.d.ts +22 -0
  375. package/dist/i18n/resolve.d.ts.map +1 -0
  376. package/dist/i18n/resolve.js +141 -0
  377. package/dist/i18n/translator.d.ts +25 -0
  378. package/dist/i18n/translator.d.ts.map +1 -0
  379. package/dist/i18n/translator.js +1 -0
  380. package/dist/i18n/types.d.ts +47 -0
  381. package/dist/i18n/types.d.ts.map +1 -0
  382. package/dist/i18n/types.js +1 -0
  383. package/dist/i18n/useTranslator.d.ts +15 -0
  384. package/dist/i18n/useTranslator.d.ts.map +1 -0
  385. package/dist/i18n/useTranslator.js +39 -0
  386. package/dist/index.d.ts +1 -0
  387. package/dist/index.d.ts.map +1 -1
  388. package/dist/index.js +3 -0
  389. package/dist/theme/MediaTheme.js +3 -3
  390. package/dist/theme/Theme.js +7 -7
  391. package/dist/theme/syntax/SyntaxTheme.js +5 -5
  392. package/locales/en.json +746 -0
  393. package/locales/pseudo.json +560 -0
  394. package/package.json +24 -3
  395. package/src/AlertDialog/AlertDialog.doc.mjs +5 -0
  396. package/src/AlertDialog/AlertDialog.tsx +4 -1
  397. package/src/AlertDialog/useImperativeAlertDialog.tsx +0 -2
  398. package/src/AppShell/AppShell.doc.mjs +8 -2
  399. package/src/AppShell/AppShell.tsx +3 -1
  400. package/src/AvatarGroup/AvatarGroup.tsx +4 -1
  401. package/src/Banner/Banner.tsx +10 -5
  402. package/src/Breadcrumbs/Breadcrumbs.tsx +4 -1
  403. package/src/Button/Button.tsx +34 -4
  404. package/src/ButtonGroup/ButtonGroup.test.tsx +386 -2
  405. package/src/ButtonGroup/ButtonGroup.tsx +27 -11
  406. package/src/Calendar/Calendar.tsx +8 -5
  407. package/src/Card/Card.doc.mjs +3 -3
  408. package/src/Carousel/Carousel.tsx +10 -7
  409. package/src/Chat/ChatComposer.tsx +5 -1
  410. package/src/Chat/ChatComposerDrawer.tsx +9 -2
  411. package/src/Chat/ChatComposerInput.tsx +10 -4
  412. package/src/Chat/ChatLayout.tsx +5 -12
  413. package/src/Chat/ChatLayoutScrollButton.tsx +4 -2
  414. package/src/Chat/ChatMessage.tsx +5 -1
  415. package/src/Chat/ChatMessageBubble.tsx +2 -0
  416. package/src/Chat/ChatMessageList.doc.mjs +1 -1
  417. package/src/Chat/ChatMessageList.tsx +2 -0
  418. package/src/Chat/ChatMessageMetadata.tsx +15 -9
  419. package/src/Chat/ChatPastedTextToken.tsx +3 -1
  420. package/src/Chat/ChatSendButton.tsx +3 -1
  421. package/src/Chat/ChatToolCalls.doc.mjs +1 -1
  422. package/src/Chat/useSpeechRecognition.ts +11 -2
  423. package/src/Chat/useTriggerMenu.tsx +4 -2
  424. package/src/CheckboxInput/CheckboxInput.test.tsx +16 -0
  425. package/src/CheckboxInput/CheckboxInput.tsx +4 -2
  426. package/src/CheckboxList/CheckboxList.doc.mjs +6 -1
  427. package/src/CheckboxList/CheckboxList.tsx +2 -0
  428. package/src/CheckboxList/CheckboxListItem.tsx +7 -1
  429. package/src/Citation/Citation.tsx +4 -2
  430. package/src/ClickableCard/ClickableCard.doc.mjs +1 -1
  431. package/src/CodeBlock/CodeBlock.tsx +91 -40
  432. package/src/Collapsible/Collapsible.doc.mjs +3 -3
  433. package/src/CommandPalette/CommandPalette.tsx +10 -3
  434. package/src/CommandPalette/CommandPaletteInput.test.tsx +1 -1
  435. package/src/CommandPalette/CommandPaletteInput.tsx +5 -1
  436. package/src/CommandPalette/CommandPaletteList.tsx +4 -1
  437. package/src/ContextMenu/ContextMenu.tsx +4 -1
  438. package/src/DateInput/DateInput.doc.mjs +2 -2
  439. package/src/DateInput/DateInput.tsx +13 -5
  440. package/src/DateRangeInput/DateRangeInput.doc.mjs +7 -7
  441. package/src/DateRangeInput/DateRangeInput.tsx +14 -6
  442. package/src/DateTimeInput/DateTimeInput.doc.mjs +2 -2
  443. package/src/DateTimeInput/DateTimeInput.tsx +17 -7
  444. package/src/Dialog/DialogHeader.tsx +4 -2
  445. package/src/DropdownMenu/DropdownMenu.tsx +12 -8
  446. package/src/EmptyState/EmptyState.doc.mjs +3 -3
  447. package/src/EmptyState/EmptyState.tsx +4 -1
  448. package/src/Field/Field.doc.mjs +2 -2
  449. package/src/FileInput/FileInput.tsx +3 -1
  450. package/src/Grid/Grid.doc.mjs +5 -5
  451. package/src/InputGroup/InputGroup.doc.mjs +1 -1
  452. package/src/Layer/useLayer.doc.mjs +2 -2
  453. package/src/Lightbox/Lightbox.doc.mjs +7 -2
  454. package/src/Lightbox/Lightbox.tsx +6 -4
  455. package/src/Lightbox/useLightbox.tsx +0 -1
  456. package/src/Link/Link.test.tsx +74 -2
  457. package/src/Link/Link.tsx +48 -3
  458. package/src/Markdown/Markdown.tsx +12 -4
  459. package/src/MobileNav/MobileNav.tsx +4 -2
  460. package/src/MobileNav/MobileNavToggle.tsx +5 -3
  461. package/src/MoreMenu/MoreMenu.tsx +4 -1
  462. package/src/MultiSelector/MultiSelector.tsx +14 -5
  463. package/src/NumberInput/NumberInput.tsx +3 -1
  464. package/src/Outline/Outline.tsx +4 -1
  465. package/src/OverflowList/OverflowList.doc.mjs +2 -2
  466. package/src/Overlay/useOverlay.tsx +0 -3
  467. package/src/Pagination/Pagination.tsx +35 -12
  468. package/src/Popover/usePopover.tsx +6 -1
  469. package/src/PowerSearch/PowerSearch.doc.mjs +9 -4
  470. package/src/PowerSearch/PowerSearch.tsx +22 -10
  471. package/src/PowerSearch/PowerSearchEditPopover.tsx +27 -20
  472. package/src/PowerSearch/PowerSearchToken.tsx +17 -6
  473. package/src/PowerSearch/PowerSearchValueEditor.tsx +34 -21
  474. package/src/PowerSearch/formatFilterValue.test.ts +282 -0
  475. package/src/PowerSearch/formatFilterValue.ts +21 -8
  476. package/src/PowerSearch/index.ts +5 -0
  477. package/src/PowerSearch/resolveOperatorLabel.ts +34 -0
  478. package/src/PowerSearch/types.ts +33 -9
  479. package/src/PowerSearch/usePowerSearchConfig.ts +59 -27
  480. package/src/PowerSearch/usePowerSearchSource.ts +17 -8
  481. package/src/RadioList/RadioList.doc.mjs +1 -1
  482. package/src/Resizable/ResizeHandle.tsx +4 -1
  483. package/src/Section/Section.doc.mjs +4 -4
  484. package/src/SelectableCard/SelectableCard.doc.mjs +1 -1
  485. package/src/Selector/Selector.tsx +11 -6
  486. package/src/SideNav/SideNav.tsx +4 -2
  487. package/src/SideNav/SideNavCollapseButton.tsx +3 -1
  488. package/src/SideNav/SideNavHeading.tsx +5 -3
  489. package/src/SideNav/SideNavItem.tsx +3 -1
  490. package/src/Slider/Slider.doc.mjs +2 -2
  491. package/src/Stack/Stack.doc.mjs +10 -10
  492. package/src/Switch/Switch.doc.mjs +2 -2
  493. package/src/Switch/Switch.test.tsx +16 -0
  494. package/src/Switch/Switch.tsx +4 -2
  495. package/src/TabList/TabList.tsx +4 -1
  496. package/src/Table/BaseTable.tsx +8 -1
  497. package/src/Table/Table.doc.mjs +1 -1
  498. package/src/Table/Table.tsx +3 -1
  499. package/src/Table/index.ts +7 -0
  500. package/src/Table/plugins/filtering/useTableFiltering.tsx +31 -30
  501. package/src/Table/plugins/groupedRows/index.ts +7 -0
  502. package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +231 -0
  503. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +351 -0
  504. package/src/Table/plugins/pagination/useTablePagination.tsx +4 -1
  505. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +8 -4
  506. package/src/Table/plugins/rowIndex/index.ts +4 -0
  507. package/src/Table/plugins/rowIndex/useTableRowIndex.test.tsx +132 -0
  508. package/src/Table/plugins/rowIndex/useTableRowIndex.tsx +114 -0
  509. package/src/Table/plugins/selection/useTableSelection.tsx +6 -7
  510. package/src/Table/plugins/sortable/useTableSortable.tsx +8 -5
  511. package/src/Table/useTableFiltering.doc.mjs +2 -2
  512. package/src/Table/useTableGroupedRows.doc.mjs +71 -0
  513. package/src/Table/useTableRowIndex.doc.mjs +50 -0
  514. package/src/Table/useTableSortable.doc.mjs +11 -11
  515. package/src/Text/Text.doc.mjs +2 -2
  516. package/src/TextInput/TextInput.tsx +3 -1
  517. package/src/Thumbnail/Thumbnail.tsx +4 -2
  518. package/src/TimeInput/TimeInput.doc.mjs +2 -2
  519. package/src/TimeInput/TimeInput.tsx +6 -2
  520. package/src/Timestamp/Timestamp.doc.mjs +4 -4
  521. package/src/Timestamp/Timestamp.test.tsx +120 -7
  522. package/src/Timestamp/Timestamp.tsx +21 -1
  523. package/src/Toast/Toast.tsx +3 -1
  524. package/src/Toast/ToastViewport.tsx +3 -1
  525. package/src/Token/Token.tsx +4 -2
  526. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  527. package/src/Tokenizer/Tokenizer.tsx +4 -4
  528. package/src/Toolbar/Toolbar.doc.mjs +1 -1
  529. package/src/TopNav/TopNav.doc.mjs +1 -0
  530. package/src/TopNav/TopNav.test.tsx +30 -0
  531. package/src/TopNav/TopNav.tsx +6 -4
  532. package/src/TopNav/TopNavHeading.tsx +5 -3
  533. package/src/TreeList/TreeList.tsx +5 -1
  534. package/src/TreeList/TreeListItem.tsx +6 -1
  535. package/src/Typeahead/BaseTypeahead.tsx +11 -4
  536. package/src/Typeahead/Typeahead.doc.mjs +1 -1
  537. package/src/Typeahead/Typeahead.tsx +3 -1
  538. package/src/VisuallyHidden/VisuallyHidden.tsx +1 -3
  539. package/src/authoring/doc.ts +166 -0
  540. package/src/authoring/index.test.ts +52 -0
  541. package/src/authoring/index.ts +50 -0
  542. package/src/authoring/integration.ts +42 -0
  543. package/src/authoring/template.ts +74 -0
  544. package/src/config.test.ts +16 -0
  545. package/src/config.ts +92 -0
  546. package/src/docPropLiterals.test.ts +902 -0
  547. package/src/hooks/useHotkeys.doc.mjs +5 -5
  548. package/src/i18n/InternationalizationContext.ts +39 -0
  549. package/src/i18n/InternationalizationProvider.doc.mjs +72 -0
  550. package/src/i18n/InternationalizationProvider.tsx +83 -0
  551. package/src/i18n/__tests__/e2e-pagination.test.tsx +172 -0
  552. package/src/i18n/__tests__/e2e-powersearch.test.tsx +130 -0
  553. package/src/i18n/__tests__/resolve.test.ts +284 -0
  554. package/src/i18n/index.ts +32 -0
  555. package/src/i18n/resolve.ts +165 -0
  556. package/src/i18n/translator.ts +31 -0
  557. package/src/i18n/types.ts +53 -0
  558. package/src/i18n/useTranslator.doc.mjs +46 -0
  559. package/src/i18n/useTranslator.ts +50 -0
  560. package/src/index.ts +3 -0
  561. package/dist/NavItem/index.d.ts +0 -9
  562. package/dist/NavItem/index.d.ts.map +0 -1
  563. package/dist/NavItem/index.js +0 -10
  564. package/src/NavItem/index.ts +0 -11
@@ -45,9 +45,15 @@ export const docs = {
45
45
  },
46
46
  {
47
47
  name: 'mobileNav',
48
+ // Kept as the bare `ReactNode`, not widened to the true
49
+ // `false | MobileNavConfig | ReactNode`: the docsite playground hides a
50
+ // prop by exact-matching the type string against UNSUPPORTED_PROP_TYPES,
51
+ // and widening drops that match. This prop's slotElements happen to hide
52
+ // it a second way today, but the hide should not rest on that
53
+ // coincidence. The legal values live in the description instead (#1645).
48
54
  type: 'ReactNode',
49
55
  description:
50
- 'Mobile navigation configuration. Accepts false (disable), config object (tune auto behavior), or ReactNode (full custom drawer).',
56
+ "Mobile navigation configuration. Accepts false (disable), a config object (tune auto behavior), or ReactNode (full custom drawer). The config object is {hasToggle?: boolean, isOpen?: boolean, onOpenChange?: (isOpen: boolean) => void, content?: ReactNode, breakpoint?: 'sm' | 'md' | 'lg' | 'none', defaultIsMobile?: boolean}; breakpoint defaults to 'md'.",
51
57
  slotElements: [{__element: 'MobileNav', props: {}}],
52
58
  },
53
59
  {
@@ -139,7 +145,7 @@ export const docsZh = {
139
145
  },
140
146
  {name: 'topNav', type: 'ReactNode', description: '顶部导航插槽,通常为 TopNav。'},
141
147
  {name: 'sideNav', type: 'ReactNode', description: '侧边导航插槽,通常为 SideNav。'},
142
- {name: 'mobileNav', type: 'ReactNode', description: '移动端导航配置。接受 false(禁用)、配置对象(调整自动行为)或 ReactNode(完全自定义抽屉)。'},
148
+ {name: 'mobileNav', type: 'ReactNode', description: "移动端导航配置。接受 false(禁用)、配置对象(调整自动行为)或 ReactNode(完全自定义抽屉)。配置对象为 {hasToggle?, isOpen?, onOpenChange?, content?, breakpoint?: 'sm' | 'md' | 'lg' | 'none', defaultIsMobile?};breakpoint 默认为 'md'。"},
143
149
  {name: 'banner', type: 'ReactNode', description: '横幅插槽,用于全局公告,放置在 topNav 上方。'},
144
150
  {
145
151
  name: 'height',
@@ -53,6 +53,7 @@ import {mergeProps, mergeRefs, isRenderable} from '../utils';
53
53
  import {useMediaQuery} from '../hooks/useMediaQuery';
54
54
  import {observeResize, unobserveResize} from '../utils/sharedResizeObserver';
55
55
  import {themeProps} from '../utils/themeProps';
56
+ import {useTranslator} from '../i18n';
56
57
 
57
58
  const HasActivity = typeof React.Activity !== 'undefined';
58
59
  const ActivityWrapper = HasActivity
@@ -472,6 +473,7 @@ export function AppShell({
472
473
  ref,
473
474
  ...rest
474
475
  }: AppShellProps) {
476
+ const t = useTranslator();
475
477
  // =========================================================================
476
478
  // Parse mobileNav prop — normalize to config, custom element, or disabled
477
479
  // =========================================================================
@@ -756,7 +758,7 @@ export function AppShell({
756
758
  <div
757
759
  {...stylex.props(styles.autoMobileTopBar)}
758
760
  role="navigation"
759
- aria-label="Mobile navigation">
761
+ aria-label={t('@astryx.appShell.mobileNavigation')}>
760
762
  <SideNavRenderContext value="topbar">
761
763
  {sideNav}
762
764
  </SideNavRenderContext>
@@ -25,6 +25,7 @@ import * as stylex from '@stylexjs/stylex';
25
25
  import {mergeProps} from '../utils';
26
26
  import {AvatarGroupContext} from './AvatarGroupContext';
27
27
  import {themeProps} from '../utils/themeProps';
28
+ import {useTranslator} from '../i18n';
28
29
 
29
30
  const OVERLAP_RATIO = 0.25;
30
31
 
@@ -76,13 +77,15 @@ export function AvatarGroup({
76
77
  children,
77
78
  size = 'small',
78
79
  'data-testid': testId,
79
- 'aria-label': ariaLabel = 'Avatars',
80
+ 'aria-label': ariaLabelFromProps,
80
81
  xstyle,
81
82
  className,
82
83
  style,
83
84
  ref,
84
85
  ...props
85
86
  }: AvatarGroupProps): ReactNode {
87
+ const t = useTranslator();
88
+ const ariaLabel = ariaLabelFromProps ?? t('@astryx.avatarGroup.label');
86
89
  const numericSize = resolveSize(size);
87
90
  const overlap = Math.round(numericSize * OVERLAP_RATIO);
88
91
 
@@ -50,6 +50,7 @@ import {
50
50
  import {mergeProps} from '../utils';
51
51
  import {edgeCompSlot} from '../Layout/edgeCompensation.stylex';
52
52
  import {themeProps} from '../utils/themeProps';
53
+ import {useTranslator} from '../i18n';
53
54
 
54
55
  // =============================================================================
55
56
  // Types
@@ -296,7 +297,10 @@ const styles = stylex.create({
296
297
  chevron: {
297
298
  display: 'inline-flex',
298
299
  transitionProperty: 'transform',
299
- transitionDuration: durationVars['--duration-fast'],
300
+ transitionDuration: {
301
+ default: durationVars['--duration-fast'],
302
+ '@media (prefers-reduced-motion: reduce)': '0s',
303
+ },
300
304
  transitionTimingFunction: easeVars['--ease-standard'],
301
305
  },
302
306
  chevronExpanded: {
@@ -385,6 +389,7 @@ export function Banner({
385
389
  ref,
386
390
  ...rest
387
391
  }: BannerProps) {
392
+ const t = useTranslator();
388
393
  const [isDismissed, setIsDismissed] = useState(false);
389
394
  const [isExpanded, setIsExpanded] = useState(defaultIsExpanded);
390
395
  // Links the expand/collapse toggle to the content region it shows/hides so
@@ -469,8 +474,8 @@ export function Banner({
469
474
  <Button
470
475
  variant="ghost"
471
476
  size="sm"
472
- label={isExpanded ? 'Collapse' : 'Expand'}
473
- tooltip={isExpanded ? 'Collapse' : 'Expand'}
477
+ label={isExpanded ? t('@astryx.banner.collapse') : t('@astryx.banner.expand')}
478
+ tooltip={isExpanded ? t('@astryx.banner.collapse') : t('@astryx.banner.expand')}
474
479
  icon={
475
480
  <span
476
481
  {...stylex.props(
@@ -490,8 +495,8 @@ export function Banner({
490
495
  <Button
491
496
  variant="ghost"
492
497
  size="sm"
493
- label="Dismiss"
494
- tooltip="Dismiss"
498
+ label={t('@astryx.banner.dismiss')}
499
+ tooltip={t('@astryx.banner.dismiss')}
495
500
  icon={<Icon icon="close" size="sm" color="inherit" />}
496
501
  onClick={handleDismiss}
497
502
  isIconOnly
@@ -22,6 +22,7 @@ import {spacingVars} from '../theme/tokens.stylex';
22
22
  import {mergeProps} from '../utils';
23
23
  import type {BaseProps} from '../BaseProps';
24
24
  import {themeProps} from '../utils/themeProps';
25
+ import {useTranslator} from '../i18n';
25
26
 
26
27
  // =============================================================================
27
28
  // Variant type
@@ -150,10 +151,12 @@ export function Breadcrumbs({
150
151
  xstyle,
151
152
  className,
152
153
  style,
153
- label = 'Breadcrumb',
154
+ label: labelFromProps,
154
155
  ref,
155
156
  ...rest
156
157
  }: BreadcrumbsProps) {
158
+ const t = useTranslator();
159
+ const label = labelFromProps ?? t('@astryx.breadcrumbs.label');
157
160
  const ctxValue = useMemo<BreadcrumbContextValue>(
158
161
  () => ({variant, separator}),
159
162
  [variant, separator],
@@ -434,6 +434,36 @@ const loadingStyles = stylex.create({
434
434
  },
435
435
  });
436
436
 
437
+ /**
438
+ * "I am the last member of the group" — the trailing end cap.
439
+ *
440
+ * NOT `:last-child`: several members render an invisible layer element AFTER
441
+ * their button (a tooltip'd Button returns button + layer; DropdownMenu returns
442
+ * trigger + popover). `useLayer` renders those inline rather than portaling
443
+ * them, so the layer — not the button — took the `:last-child` slot and the real
444
+ * trailing button silently kept square corners (#2508).
445
+ *
446
+ * Layers always carry the native `popover` attribute (useLayer.tsx), and a
447
+ * popover is never an in-flow member — it is `display: none` until shown, then
448
+ * promoted to the top layer. So "last member" is: no following element sibling
449
+ * that isn't a popover.
450
+ *
451
+ * Reading it the other way round — marking the *buttons* and testing for a
452
+ * marked sibling — is the trap: it silently reclassifies anything it doesn't
453
+ * recognise as "not a member", so a member wrapped in a `display: contents`
454
+ * wrapper (Tooltip, HoverCard) or a raw child would make the button BEFORE it
455
+ * round mid-group. Ignoring known layers keeps the predicate conservative: an
456
+ * unrecognised sibling still counts, exactly as `:last-child` did, so the worst
457
+ * case degrades to the old behaviour instead of a wrong corner.
458
+ *
459
+ * Kept as a same-file const: StyleX only statically evaluates a selector key
460
+ * from a const in the same file.
461
+ *
462
+ * The leading edge still uses `:first-child` — a member's button always precedes
463
+ * its own layer, so the first button is genuinely `:first-child`.
464
+ */
465
+ const IS_LAST_ITEM = ':not(:has(~ *:not([popover])))';
466
+
437
467
  const groupStyles = stylex.create({
438
468
  horizontal: {
439
469
  borderStartStartRadius: {
@@ -446,11 +476,11 @@ const groupStyles = stylex.create({
446
476
  },
447
477
  borderStartEndRadius: {
448
478
  default: 0,
449
- ':last-child': radiusVars['--radius-element'],
479
+ [IS_LAST_ITEM]: radiusVars['--radius-element'],
450
480
  },
451
481
  borderEndEndRadius: {
452
482
  default: 0,
453
- ':last-child': radiusVars['--radius-element'],
483
+ [IS_LAST_ITEM]: radiusVars['--radius-element'],
454
484
  },
455
485
  borderInlineStartWidth: {
456
486
  default: borderVars['--border-width'],
@@ -473,11 +503,11 @@ const groupStyles = stylex.create({
473
503
  },
474
504
  borderEndStartRadius: {
475
505
  default: 0,
476
- ':last-child': radiusVars['--radius-element'],
506
+ [IS_LAST_ITEM]: radiusVars['--radius-element'],
477
507
  },
478
508
  borderEndEndRadius: {
479
509
  default: 0,
480
- ':last-child': radiusVars['--radius-element'],
510
+ [IS_LAST_ITEM]: radiusVars['--radius-element'],
481
511
  },
482
512
  borderBlockStartWidth: {
483
513
  default: borderVars['--border-width'],
@@ -2,8 +2,10 @@
2
2
 
3
3
  /**
4
4
  * @file ButtonGroup.test.tsx
5
- * @input Uses vitest, @testing-library/react, ButtonGroup and Button components
6
- * @output Unit tests for ButtonGroup
5
+ * @input Uses vitest, @testing-library/react, @babel/core + @stylexjs/babel-plugin,
6
+ * ButtonGroup and Button components
7
+ * @output Unit tests for ButtonGroup, incl. the compiled-CSS contract for the
8
+ * trailing radius (#2508)
7
9
  * @position Testing; validates ButtonGroup component implementation
8
10
  *
9
11
  * SYNC: When ButtonGroup component changes, update tests to match new behavior
@@ -11,9 +13,16 @@
11
13
 
12
14
  import {describe, it, expect} from 'vitest';
13
15
  import {render, screen} from '@testing-library/react';
16
+ import {transformSync} from '@babel/core';
17
+ import stylexBabelPlugin from '@stylexjs/babel-plugin';
18
+ import {readFileSync} from 'node:fs';
19
+ import path from 'node:path';
14
20
  import {ButtonGroup} from './ButtonGroup';
15
21
  import {Button} from '../Button';
16
22
  import {IconButton} from '../IconButton';
23
+ import {DropdownMenu} from '../DropdownMenu';
24
+ import {Tooltip} from '../Tooltip';
25
+ import {HoverCard} from '../HoverCard';
17
26
 
18
27
  describe('ButtonGroup', () => {
19
28
  it('renders a group with aria-label', () => {
@@ -188,4 +197,379 @@ describe('ButtonGroup', () => {
188
197
  screen.getByRole('button', {name: 'More options'}),
189
198
  ).toBeInTheDocument();
190
199
  });
200
+
201
+ // ===========================================================================
202
+ // Trailing radius (issue #2508)
203
+ //
204
+ // The trailing end cap cannot be keyed off `:last-child`: members render an
205
+ // invisible layer AFTER their button (tooltip'd Button, DropdownMenu), and
206
+ // useLayer renders it inline rather than portaling it, so the layer steals the
207
+ // slot. See IS_LAST_ITEM in Button.tsx.
208
+ //
209
+ // HOW THESE TESTS CATCH THE BUG
210
+ // jsdom applies no StyleX CSS, so a DOM-only test cannot prove which rule
211
+ // wins — and a test that hand-copies the selector is a tautology (revert
212
+ // groupStyles to `:last-child` and it still passes). So the predicate is NOT
213
+ // hand-copied here: `compileButtonRules()` runs the REAL StyleX babel plugin
214
+ // over Button.tsx (same config as scripts/build-css.mjs) and reads the
215
+ // trailing-radius rule's selector straight out of the emitted CSS, then
216
+ // matches it against the real rendered DOM. Revert groupStyles to
217
+ // `:last-child` and these go red.
218
+ // ===========================================================================
219
+ describe('trailing radius (#2508)', () => {
220
+ /** The group members, in DOM order (excludes invisible layer siblings). */
221
+ const items = (group: HTMLElement): Element[] =>
222
+ Array.from(group.querySelectorAll(':scope > *:not([popover])'));
223
+
224
+ // -- Compiled CSS, read from the source -----------------------------------
225
+
226
+ /** One atomic StyleX rule, parsed out of the plugin's emitted CSS. */
227
+ type CompiledRule = {
228
+ /** Atomic class name, e.g. `xp0wexf`. */
229
+ className: string;
230
+ /** Selector text after the class, e.g. `:first-child`. '' if unconditional. */
231
+ condition: string;
232
+ /** CSS property, e.g. `border-start-end-radius`. */
233
+ property: string;
234
+ /** CSS value, e.g. `var(--radius-element)`. */
235
+ value: string;
236
+ /** The full compiled selector, e.g. `.xp0wexf:not(:has(~ [data-...]))`. */
237
+ selector: string;
238
+ };
239
+
240
+ /**
241
+ * Compiles Button.tsx with the real StyleX babel plugin and returns its
242
+ * atomic rules. This is the CSS the browser actually gets — the whole point
243
+ * is that the trailing-radius predicate comes from the SOURCE, never from a
244
+ * string retyped in this file.
245
+ */
246
+ function compileButtonRules(): CompiledRule[] {
247
+ const repoRoot = path.resolve(__dirname, '../../../..');
248
+ const buttonSrc = path.resolve(__dirname, '../Button/Button.tsx');
249
+
250
+ const result = transformSync(readFileSync(buttonSrc, 'utf8'), {
251
+ babelrc: false,
252
+ configFile: false,
253
+ filename: buttonSrc,
254
+ presets: [
255
+ ['@babel/preset-typescript', {isTSX: true, allExtensions: true}],
256
+ ['@babel/preset-react', {runtime: 'automatic'}],
257
+ ],
258
+ plugins: [
259
+ [
260
+ stylexBabelPlugin,
261
+ {
262
+ dev: false,
263
+ runtimeInjection: false,
264
+ genConditionalClasses: true,
265
+ treeshakeCompensation: true,
266
+ unstable_moduleResolution: {type: 'commonJS', rootDir: repoRoot},
267
+ },
268
+ ],
269
+ ],
270
+ });
271
+
272
+ const rules =
273
+ (result?.metadata as {stylex?: [string, {ltr: string}, number][]})
274
+ ?.stylex ?? [];
275
+
276
+ return rules.flatMap(([, {ltr}]) => {
277
+ // Plain atomic rules only: `.cls<condition>{prop:value}`. @media-wrapped
278
+ // rules are irrelevant to the radius contract.
279
+ const parsed = /^\.([\w-]+)([^{]*)\{([\w-]+):(.+)\}$/.exec(ltr);
280
+ if (!parsed) {
281
+ return [];
282
+ }
283
+ const [, className, condition, property, value] = parsed;
284
+ return [
285
+ {
286
+ className,
287
+ condition,
288
+ property,
289
+ value,
290
+ selector: `.${className}${condition}`,
291
+ },
292
+ ];
293
+ });
294
+ }
295
+
296
+ const COMPILED = compileButtonRules();
297
+
298
+ /** A rounded (non-zero) corner is exactly this value in the compiled CSS. */
299
+ const ROUNDED = 'var(--radius-element)';
300
+
301
+ /** The two corners on the group's trailing edge — pure geometry. */
302
+ const TRAILING_CORNERS = {
303
+ horizontal: ['border-end-end-radius', 'border-start-end-radius'],
304
+ vertical: ['border-end-end-radius', 'border-end-start-radius'],
305
+ } as const;
306
+
307
+ /** The two corners on the group's leading edge — pure geometry. */
308
+ const LEADING_CORNERS = {
309
+ horizontal: ['border-end-start-radius', 'border-start-start-radius'],
310
+ vertical: ['border-start-end-radius', 'border-start-start-radius'],
311
+ } as const;
312
+
313
+ type Orientation = keyof typeof TRAILING_CORNERS;
314
+
315
+ /**
316
+ * The compiled rules that ROUND `corners` and are actually applied to `el`
317
+ * (its class list carries them). StyleX emits the `default: 0` class and the
318
+ * conditional class on every member, so this returns the same rules for any
319
+ * member of the group — which rule *wins* is decided by the selector, and
320
+ * that is what the tests below assert against the DOM.
321
+ */
322
+ const roundingRules = (
323
+ el: Element,
324
+ corners: ReadonlyArray<string>,
325
+ ): CompiledRule[] =>
326
+ COMPILED.filter(
327
+ rule =>
328
+ corners.includes(rule.property) &&
329
+ rule.value === ROUNDED &&
330
+ el.classList.contains(rule.className),
331
+ );
332
+
333
+ /** The compiled selectors that round `el`'s trailing corners. */
334
+ const trailingRoundingSelectors = (
335
+ el: Element,
336
+ orientation: Orientation,
337
+ ): string[] => {
338
+ const rules = roundingRules(el, TRAILING_CORNERS[orientation]);
339
+ // Guard against a vacuous pass: both trailing corners must be accounted
340
+ // for, or the assertions below would be quantifying over an empty set.
341
+ expect(rules.map(rule => rule.property).sort()).toEqual([
342
+ ...TRAILING_CORNERS[orientation],
343
+ ]);
344
+ return rules.map(rule => rule.selector);
345
+ };
346
+
347
+ /** Does the compiled CSS actually round `el`'s trailing corners? */
348
+ const hasRoundedTrailingCorners = (
349
+ el: Element,
350
+ orientation: Orientation = 'horizontal',
351
+ ): boolean =>
352
+ trailingRoundingSelectors(el, orientation).every(selector =>
353
+ el.matches(selector),
354
+ );
355
+
356
+ // -- The compiled CSS contract --------------------------------------------
357
+
358
+ it.each(['horizontal', 'vertical'] as const)(
359
+ 'keys the trailing radius off layer-skipping, not :last-child (%s)',
360
+ orientation => {
361
+ render(
362
+ <ButtonGroup label="Actions" orientation={orientation}>
363
+ <Button label="Save" />
364
+ </ButtonGroup>,
365
+ );
366
+
367
+ const save = screen.getByRole('button', {name: 'Save'});
368
+ const selectors = trailingRoundingSelectors(save, orientation);
369
+
370
+ for (const selector of selectors) {
371
+ // `:last-child` is the bug: an inline layer element steals the slot.
372
+ expect(selector).not.toContain(':last-child');
373
+ // `[popover]` must survive compilation *verbatim*. StyleX only
374
+ // statically evaluates a selector key from a same-file const; from a
375
+ // .stylex.ts file it compiles to a mangled selector like `[x13pbwiz]`
376
+ // that matches nothing in the DOM.
377
+ expect(selector).toContain('[popover]');
378
+ }
379
+ },
380
+ );
381
+
382
+ it.each(['horizontal', 'vertical'] as const)(
383
+ 'still rounds the leading corners off :first-child (%s)',
384
+ orientation => {
385
+ render(
386
+ <ButtonGroup label="Actions" orientation={orientation}>
387
+ <Button label="Save" />
388
+ <Button label="More" tooltip="More options" />
389
+ </ButtonGroup>,
390
+ );
391
+
392
+ const save = screen.getByRole('button', {name: 'Save'});
393
+ const more = screen.getByRole('button', {name: 'More'});
394
+ const rules = roundingRules(save, LEADING_CORNERS[orientation]);
395
+
396
+ expect(rules.map(rule => rule.property).sort()).toEqual([
397
+ ...LEADING_CORNERS[orientation],
398
+ ]);
399
+ for (const {condition, selector} of rules) {
400
+ // The leading edge is genuinely safe on :first-child — a member's
401
+ // button always precedes its own layer.
402
+ expect(condition).toBe(':first-child');
403
+ expect(save.matches(selector)).toBe(true);
404
+ expect(more.matches(selector)).toBe(false);
405
+ }
406
+ },
407
+ );
408
+
409
+ // -- The compiled CSS, matched against the real DOM ------------------------
410
+
411
+ it.each(['horizontal', 'vertical'] as const)(
412
+ 'rounds a tooltip’d trailing Button, whose layer follows it in the DOM (%s)',
413
+ orientation => {
414
+ render(
415
+ <ButtonGroup label="Actions" orientation={orientation}>
416
+ <Button label="Save" />
417
+ <Button label="More" tooltip="More options" />
418
+ </ButtonGroup>,
419
+ );
420
+
421
+ const group = screen.getByRole('group');
422
+ const save = screen.getByRole('button', {name: 'Save'});
423
+ const more = screen.getByRole('button', {name: 'More'});
424
+
425
+ // Precondition: the tooltip layer really is an inline DOM sibling that
426
+ // follows the button — this is exactly what broke `:last-child`.
427
+ expect(more).not.toBe(group.lastElementChild);
428
+ expect(items(group).at(-1)).toBe(more);
429
+
430
+ expect(hasRoundedTrailingCorners(more, orientation)).toBe(true);
431
+ expect(hasRoundedTrailingCorners(save, orientation)).toBe(false);
432
+ },
433
+ );
434
+
435
+ it.each(['horizontal', 'vertical'] as const)(
436
+ 'rounds a trailing DropdownMenu trigger, whose popover follows it (%s)',
437
+ orientation => {
438
+ render(
439
+ <ButtonGroup label="Approve action" orientation={orientation}>
440
+ <Button label="Allow once" variant="primary" />
441
+ <DropdownMenu
442
+ button={{label: 'Allow options', variant: 'primary'}}
443
+ items={[{label: 'Always allow'}]}
444
+ />
445
+ </ButtonGroup>,
446
+ );
447
+
448
+ const group = screen.getByRole('group');
449
+ const allow = screen.getByRole('button', {name: 'Allow once'});
450
+ const trigger = screen.getByRole('button', {name: 'Allow options'});
451
+
452
+ // The popover surface is an inline sibling after the trigger.
453
+ expect(trigger).not.toBe(group.lastElementChild);
454
+ expect(items(group).at(-1)).toBe(trigger);
455
+
456
+ expect(hasRoundedTrailingCorners(trigger, orientation)).toBe(true);
457
+ expect(hasRoundedTrailingCorners(allow, orientation)).toBe(false);
458
+ },
459
+ );
460
+
461
+ it('rounds a trailing link (<a>) member with a tooltip', () => {
462
+ render(
463
+ <ButtonGroup label="Actions">
464
+ <Button label="Save" />
465
+ <Button label="Docs" href="https://example.com" tooltip="Open docs" />
466
+ </ButtonGroup>,
467
+ );
468
+
469
+ const group = screen.getByRole('group');
470
+ const link = screen.getByRole('link', {name: 'Docs'});
471
+
472
+ expect(link.tagName).toBe('A');
473
+ expect(link).not.toBe(group.lastElementChild);
474
+ expect(items(group).at(-1)).toBe(link);
475
+
476
+ expect(hasRoundedTrailingCorners(link)).toBe(true);
477
+ });
478
+
479
+ it('rounds only the last member (first/middle/last)', () => {
480
+ render(
481
+ <ButtonGroup label="Actions">
482
+ <Button label="First" />
483
+ <Button label="Middle" tooltip="Middle tip" />
484
+ <DropdownMenu
485
+ button={{label: 'Last'}}
486
+ items={[{label: 'An option'}]}
487
+ />
488
+ </ButtonGroup>,
489
+ );
490
+
491
+ const group = screen.getByRole('group');
492
+ const [first, middle, last] = items(group);
493
+
494
+ expect([first, middle, last].map(el => el.textContent)).toEqual([
495
+ 'First',
496
+ 'Middle',
497
+ 'Last',
498
+ ]);
499
+
500
+ // Middle has a tooltip layer after it, but a *marked* sibling follows too,
501
+ // so it must NOT take the trailing radius.
502
+ expect(hasRoundedTrailingCorners(first)).toBe(false);
503
+ expect(hasRoundedTrailingCorners(middle)).toBe(false);
504
+ expect(hasRoundedTrailingCorners(last)).toBe(true);
505
+ });
506
+
507
+ it('rounds both edges of a lone tooltip’d member', () => {
508
+ render(
509
+ <ButtonGroup label="Actions">
510
+ <Button label="Only" tooltip="The only one" />
511
+ </ButtonGroup>,
512
+ );
513
+
514
+ const only = screen.getByRole('button', {name: 'Only'});
515
+
516
+ // Leading edge is unaffected: a member's button always precedes its layer.
517
+ expect(only.matches(':first-child')).toBe(true);
518
+ expect(hasRoundedTrailingCorners(only)).toBe(true);
519
+ });
520
+
521
+ // -- Members the group does not recognise ---------------------------------
522
+ //
523
+ // The trailing predicate must stay CONSERVATIVE: a sibling the group does
524
+ // not understand is still a member. Otherwise the button BEFORE it wrongly
525
+ // takes the trailing radius and renders as a rounded notch mid-group —
526
+ // worse than the bug being fixed, because it is silent and visual.
527
+
528
+ it('does not round the preceding button when a Tooltip-wrapped member follows', () => {
529
+ render(
530
+ <ButtonGroup label="Actions">
531
+ <Button label="Save" />
532
+ <Tooltip content="Rich tip">
533
+ <Button label="More" />
534
+ </Tooltip>
535
+ </ButtonGroup>,
536
+ );
537
+
538
+ const save = screen.getByRole('button', {name: 'Save'});
539
+
540
+ // Tooltip wraps element children in a `display: contents` <div>, so the
541
+ // inner Button is a DESCENDANT of the wrapper, not a DOM sibling of Save.
542
+ expect(hasRoundedTrailingCorners(save)).toBe(false);
543
+ });
544
+
545
+ it('does not round the preceding button when a HoverCard-wrapped member follows', () => {
546
+ render(
547
+ <ButtonGroup label="Actions">
548
+ <Button label="Save" />
549
+ <HoverCard content="Preview">
550
+ <Button label="More" />
551
+ </HoverCard>
552
+ </ButtonGroup>,
553
+ );
554
+
555
+ const save = screen.getByRole('button', {name: 'Save'});
556
+
557
+ // Button has no `hoverCard` prop, so wrapping is the ONLY way to put a
558
+ // HoverCard on a group button — this composition has no alternative.
559
+ expect(hasRoundedTrailingCorners(save)).toBe(false);
560
+ });
561
+
562
+ it('does not round the preceding button when a raw <button> follows', () => {
563
+ render(
564
+ <ButtonGroup label="Actions">
565
+ <Button label="Save" />
566
+ <button type="button">Custom</button>
567
+ </ButtonGroup>,
568
+ );
569
+
570
+ const save = screen.getByRole('button', {name: 'Save'});
571
+
572
+ expect(hasRoundedTrailingCorners(save)).toBe(false);
573
+ });
574
+ });
191
575
  });