@astryxdesign/core 0.7.1 → 0.7.2-canary.01eab6a

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 (331) hide show
  1. package/dist/AspectRatio/AspectRatio.d.ts +6 -8
  2. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  3. package/dist/AspectRatio/AspectRatio.js +44 -3
  4. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  5. package/dist/Breadcrumbs/BreadcrumbItem.js +5 -2
  6. package/dist/Button/Button.d.ts.map +1 -1
  7. package/dist/Button/Button.js +38 -14
  8. package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
  9. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  10. package/dist/CheckboxInput/CheckboxInput.js +3 -1
  11. package/dist/CheckboxList/CheckboxListItem.d.ts +9 -1
  12. package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
  13. package/dist/CheckboxList/CheckboxListItem.js +4 -2
  14. package/dist/CommandPalette/CommandPaletteInput.d.ts +1 -1
  15. package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
  16. package/dist/CommandPalette/CommandPaletteInput.js +37 -5
  17. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  18. package/dist/ContextMenu/ContextMenu.js +5 -2
  19. package/dist/Dialog/Dialog.d.ts.map +1 -1
  20. package/dist/Dialog/Dialog.js +20 -8
  21. package/dist/Drawer/Drawer.d.ts +191 -0
  22. package/dist/Drawer/Drawer.d.ts.map +1 -0
  23. package/dist/Drawer/Drawer.js +382 -0
  24. package/dist/Drawer/DrawerHeader.d.ts +85 -0
  25. package/dist/Drawer/DrawerHeader.d.ts.map +1 -0
  26. package/dist/Drawer/DrawerHeader.js +134 -0
  27. package/dist/Drawer/index.d.ts +11 -0
  28. package/dist/Drawer/index.d.ts.map +1 -0
  29. package/dist/Drawer/index.js +11 -0
  30. package/dist/Drawer/useDrawerDialogPresence.d.ts +42 -0
  31. package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -0
  32. package/dist/Drawer/useDrawerDialogPresence.js +236 -0
  33. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  34. package/dist/DropdownMenu/DropdownMenu.js +47 -4
  35. package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -0
  36. package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
  37. package/dist/DropdownMenu/DropdownMenuContext.js +21 -0
  38. package/dist/DropdownMenu/DropdownMenuDivider.d.ts +5 -3
  39. package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -1
  40. package/dist/DropdownMenu/DropdownMenuDivider.js +7 -3
  41. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  42. package/dist/DropdownMenu/DropdownMenuSubMenu.js +19 -8
  43. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  44. package/dist/EmptyState/EmptyState.js +4 -10
  45. package/dist/Field/Field.d.ts +1 -1
  46. package/dist/Field/Field.d.ts.map +1 -1
  47. package/dist/Field/Field.js +8 -4
  48. package/dist/Grid/GridSpan.d.ts.map +1 -1
  49. package/dist/Grid/GridSpan.js +1 -0
  50. package/dist/Heading/Heading.d.ts.map +1 -1
  51. package/dist/Heading/Heading.js +4 -2
  52. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  53. package/dist/HoverCard/useHoverCard.js +10 -2
  54. package/dist/Item/Item.d.ts +6 -2
  55. package/dist/Item/Item.d.ts.map +1 -1
  56. package/dist/Item/Item.js +19 -4
  57. package/dist/Layer/layerViewportInset.stylex.d.ts +6 -2
  58. package/dist/Layer/layerViewportInset.stylex.d.ts.map +1 -1
  59. package/dist/Layer/layerViewportInset.stylex.js +6 -2
  60. package/dist/Layer/useLayer.d.ts.map +1 -1
  61. package/dist/Layer/useLayer.js +13 -7
  62. package/dist/Layer/useLayerDismissal.d.ts +1 -1
  63. package/dist/Layer/useLayerDismissal.js +1 -1
  64. package/dist/Layout/container.stylex.d.ts +5 -5
  65. package/dist/Layout/container.stylex.js +4 -4
  66. package/dist/List/List.d.ts +46 -19
  67. package/dist/List/List.d.ts.map +1 -1
  68. package/dist/List/List.js +28 -10
  69. package/dist/List/ListContext.d.ts +8 -3
  70. package/dist/List/ListContext.d.ts.map +1 -1
  71. package/dist/List/ListContext.js +7 -2
  72. package/dist/List/ListItem.d.ts +13 -5
  73. package/dist/List/ListItem.d.ts.map +1 -1
  74. package/dist/List/ListItem.js +21 -8
  75. package/dist/List/index.d.ts +1 -1
  76. package/dist/List/index.d.ts.map +1 -1
  77. package/dist/Markdown/Markdown.d.ts.map +1 -1
  78. package/dist/Markdown/Markdown.js +8 -1
  79. package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -1
  80. package/dist/Markdown/plugins/frontmatter.js +7 -3
  81. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  82. package/dist/MetadataList/MetadataList.js +5 -1
  83. package/dist/MetadataList/MetadataListContext.d.ts +1 -1
  84. package/dist/MetadataList/MetadataListContext.d.ts.map +1 -1
  85. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  86. package/dist/MultiSelector/MultiSelector.js +22 -8
  87. package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +100 -2
  88. package/dist/MultiSelector/hooks.d.ts.map +1 -1
  89. package/dist/MultiSelector/hooks.js +3 -1
  90. package/dist/Pagination/Pagination.d.ts +8 -5
  91. package/dist/Pagination/Pagination.d.ts.map +1 -1
  92. package/dist/Pagination/Pagination.js +21 -8
  93. package/dist/Popover/Popover.js +2 -2
  94. package/dist/PowerSearch/PowerSearch.js +1 -1
  95. package/dist/RadioList/RadioList.d.ts +1 -1
  96. package/dist/RadioList/RadioList.d.ts.map +1 -1
  97. package/dist/RadioList/RadioList.js +6 -2
  98. package/dist/RadioList/RadioListItem.d.ts +9 -1
  99. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  100. package/dist/RadioList/RadioListItem.js +2 -0
  101. package/dist/Selector/hooks.d.ts.map +1 -1
  102. package/dist/Selector/hooks.js +6 -2
  103. package/dist/SideNav/SideNavItem.d.ts +8 -1
  104. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  105. package/dist/SideNav/SideNavItem.js +71 -9
  106. package/dist/Switch/Switch.d.ts +1 -1
  107. package/dist/Switch/Switch.d.ts.map +1 -1
  108. package/dist/Switch/Switch.js +13 -1
  109. package/dist/TabList/TabMenu.d.ts +2 -2
  110. package/dist/TabList/TabMenu.d.ts.map +1 -1
  111. package/dist/TabList/TabMenu.js +6 -3
  112. package/dist/Text/Text.d.ts.map +1 -1
  113. package/dist/Text/Text.js +4 -2
  114. package/dist/Text/useTruncation.d.ts +7 -5
  115. package/dist/Text/useTruncation.d.ts.map +1 -1
  116. package/dist/Text/useTruncation.js +16 -5
  117. package/dist/ToggleButton/ToggleButton.d.ts +3 -2
  118. package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
  119. package/dist/ToggleButton/ToggleButton.js +12 -1
  120. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  121. package/dist/Tooltip/useTooltip.js +11 -0
  122. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  123. package/dist/TopNav/TopNavMegaMenu.js +3 -3
  124. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  125. package/dist/TopNav/TopNavMenu.js +3 -3
  126. package/dist/TreeList/TreeList.d.ts.map +1 -1
  127. package/dist/TreeList/TreeList.js +1 -0
  128. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  129. package/dist/TreeList/TreeListBranches.js +2 -2
  130. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  131. package/dist/TreeList/TreeListItem.js +57 -9
  132. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  133. package/dist/Typeahead/BaseTypeahead.js +26 -0
  134. package/dist/astryx.css +47 -13
  135. package/dist/hooks/useEntryAnimation.d.ts +2 -1
  136. package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
  137. package/dist/hooks/useEntryAnimation.js +14 -12
  138. package/dist/hooks/useIsHydrating.d.ts +6 -0
  139. package/dist/hooks/useIsHydrating.d.ts.map +1 -0
  140. package/dist/hooks/useIsHydrating.js +30 -0
  141. package/dist/hooks/useMenuHover.d.ts.map +1 -1
  142. package/dist/hooks/useMenuHover.js +18 -13
  143. package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
  144. package/dist/i18n/generated-locales/en.generated.js +112 -1
  145. package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
  146. package/dist/i18n/generated-locales/pseudo.generated.js +112 -1
  147. package/dist/index.d.ts +1 -0
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +1 -0
  150. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  151. package/dist/theme/derivedVarRegistry.js +0 -3
  152. package/dist/utils/focusOutline.stylex.d.ts +4 -0
  153. package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
  154. package/dist/utils/focusOutline.stylex.js +4 -0
  155. package/dist/utils/plainDate.d.ts.map +1 -1
  156. package/dist/utils/plainDate.js +15 -9
  157. package/dist/utils/sharedMutationObserver.d.ts +21 -0
  158. package/dist/utils/sharedMutationObserver.d.ts.map +1 -0
  159. package/dist/utils/sharedMutationObserver.js +69 -0
  160. package/locales/en.json +444 -0
  161. package/locales/pseudo.json +333 -0
  162. package/package.json +9 -4
  163. package/src/AspectRatio/AspectRatio.test.tsx +44 -43
  164. package/src/AspectRatio/AspectRatio.tsx +38 -18
  165. package/src/AspectRatio/__tests__/AspectRatioFitLayers.a11y.browser.spec.ts +157 -0
  166. package/src/Avatar/Avatar.doc.mjs +5 -3
  167. package/src/AvatarGroup/AvatarGroup.doc.mjs +3 -2
  168. package/src/Breadcrumbs/BreadcrumbItem.tsx +4 -1
  169. package/src/Breadcrumbs/Breadcrumbs.test.tsx +30 -1
  170. package/src/Button/Button.doc.mjs +2 -2
  171. package/src/Button/Button.test.tsx +155 -9
  172. package/src/Button/Button.tsx +39 -16
  173. package/src/Button/__tests__/Button.a11y.known-failures.ts +1 -62
  174. package/src/Button/__tests__/Button.a11y.states.ts +0 -10
  175. package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +3 -1
  176. package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
  177. package/src/CheckboxInput/CheckboxInput.tsx +3 -1
  178. package/src/CheckboxList/CheckboxList.test.tsx +22 -0
  179. package/src/CheckboxList/CheckboxListItem.doc.mjs +16 -0
  180. package/src/CheckboxList/CheckboxListItem.tsx +10 -0
  181. package/src/CommandPalette/CommandPaletteInput.test.tsx +53 -4
  182. package/src/CommandPalette/CommandPaletteInput.tsx +33 -3
  183. package/src/CommandPalette/__tests__/CommandPaletteInputAudit.a11y.chromium.spec.ts +335 -0
  184. package/src/CommandPalette/__tests__/CommandPaletteItemAudit.a11y.chromium.spec.ts +292 -0
  185. package/src/ContextMenu/ContextMenu.doc.mjs +2 -3
  186. package/src/ContextMenu/ContextMenu.tsx +4 -1
  187. package/src/ContextMenu/__tests__/ContextMenuAudit.a11y.chromium.spec.ts +438 -0
  188. package/src/Dialog/Dialog.test.tsx +46 -0
  189. package/src/Dialog/Dialog.tsx +20 -7
  190. package/src/Dialog/__tests__/Dialog.a11y.known-failures.ts +0 -14
  191. package/src/Drawer/Drawer.doc.mjs +472 -0
  192. package/src/Drawer/Drawer.spec.md +357 -0
  193. package/src/Drawer/Drawer.test.tsx +1300 -0
  194. package/src/Drawer/Drawer.tsx +613 -0
  195. package/src/Drawer/DrawerDirection.test.tsx +127 -0
  196. package/src/Drawer/DrawerHeader.doc.mjs +293 -0
  197. package/src/Drawer/DrawerHeader.test.tsx +102 -0
  198. package/src/Drawer/DrawerHeader.tsx +235 -0
  199. package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +401 -0
  200. package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +297 -0
  201. package/src/Drawer/index.ts +13 -0
  202. package/src/Drawer/useDrawerDialogPresence.ts +284 -0
  203. package/src/DropdownMenu/DropdownMenu.test.tsx +62 -13
  204. package/src/DropdownMenu/DropdownMenu.tsx +47 -4
  205. package/src/DropdownMenu/DropdownMenuContext.tsx +24 -0
  206. package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +2 -2
  207. package/src/DropdownMenu/DropdownMenuDivider.spec.md +192 -0
  208. package/src/DropdownMenu/DropdownMenuDivider.tsx +9 -5
  209. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +185 -0
  210. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +19 -5
  211. package/src/DropdownMenu/__tests__/DropdownMenuDividerAudit.a11y.chromium.spec.ts +280 -0
  212. package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +145 -0
  213. package/src/DropdownMenu/__tests__/Menu.a11y.known-failures.ts +26 -0
  214. package/src/DropdownMenu/__tests__/Menu.a11y.renders.tsx +65 -0
  215. package/src/DropdownMenu/__tests__/Menu.a11y.states.ts +138 -0
  216. package/src/DropdownMenu/__tests__/Menu.a11y.test.tsx +136 -0
  217. package/src/EmptyState/EmptyState.doc.mjs +3 -2
  218. package/src/EmptyState/EmptyState.spec.md +189 -0
  219. package/src/EmptyState/EmptyState.test.tsx +74 -3
  220. package/src/EmptyState/EmptyState.tsx +4 -8
  221. package/src/Field/Field.doc.mjs +14 -8
  222. package/src/Field/Field.spec.md +217 -0
  223. package/src/Field/Field.test.tsx +60 -2
  224. package/src/Field/Field.tsx +17 -8
  225. package/src/Grid/GridSpan.tsx +3 -0
  226. package/src/Heading/Heading.test.tsx +57 -0
  227. package/src/Heading/Heading.tsx +6 -2
  228. package/src/HoverCard/HoverCard.test.tsx +58 -0
  229. package/src/HoverCard/useHoverCard.tsx +10 -2
  230. package/src/IconButton/IconButton.doc.mjs +2 -2
  231. package/src/IconButton/IconButton.test.tsx +3 -1
  232. package/src/Item/Item.doc.mjs +12 -8
  233. package/src/Item/Item.spec.md +226 -0
  234. package/src/Item/Item.test.tsx +61 -0
  235. package/src/Item/Item.tsx +40 -4
  236. package/src/Layer/layerViewportInset.source-build.test.mjs +90 -0
  237. package/src/Layer/layerViewportInset.stylex.ts +6 -2
  238. package/src/Layer/layerViewportInset.test.ts +1 -0
  239. package/src/Layer/useLayer.tsx +24 -13
  240. package/src/Layer/useLayerDismissal.ts +1 -1
  241. package/src/Layout/container.stylex.ts +6 -6
  242. package/src/List/List.doc.mjs +14 -1
  243. package/src/List/List.spec.md +129 -77
  244. package/src/List/List.test.tsx +163 -94
  245. package/src/List/List.tsx +74 -18
  246. package/src/List/ListContext.tsx +9 -3
  247. package/src/List/ListItem.doc.mjs +24 -5
  248. package/src/List/ListItem.tsx +56 -27
  249. package/src/List/index.ts +1 -1
  250. package/src/Markdown/Markdown.tsx +14 -1
  251. package/src/Markdown/plugins/frontmatter.test.tsx +25 -0
  252. package/src/Markdown/plugins/frontmatter.ts +7 -3
  253. package/src/MetadataList/MetadataList.doc.mjs +2 -2
  254. package/src/MetadataList/MetadataList.test.tsx +38 -0
  255. package/src/MetadataList/MetadataList.tsx +8 -1
  256. package/src/MetadataList/MetadataListContext.tsx +1 -1
  257. package/src/MultiSelector/MultiSelector.test.tsx +159 -0
  258. package/src/MultiSelector/MultiSelector.tsx +40 -7
  259. package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +112 -2
  260. package/src/MultiSelector/hooks.ts +3 -1
  261. package/src/MultiSelector/useMultiCombobox.doc.mjs +267 -0
  262. package/src/Pagination/Pagination.doc.mjs +7 -7
  263. package/src/Pagination/Pagination.spec.md +9 -9
  264. package/src/Pagination/Pagination.test.tsx +242 -0
  265. package/src/Pagination/Pagination.tsx +27 -11
  266. package/src/Popover/Popover.test.tsx +2 -2
  267. package/src/Popover/Popover.tsx +4 -4
  268. package/src/PowerSearch/PowerSearch.test.tsx +85 -0
  269. package/src/PowerSearch/PowerSearch.tsx +2 -2
  270. package/src/RadioList/RadioList.fr10.test.tsx +45 -2
  271. package/src/RadioList/RadioList.test.tsx +22 -0
  272. package/src/RadioList/RadioList.tsx +4 -1
  273. package/src/RadioList/RadioListItem.doc.mjs +16 -0
  274. package/src/RadioList/RadioListItem.tsx +10 -1
  275. package/src/Selector/hooks.ts +6 -2
  276. package/src/Selector/useCombobox.doc.mjs +237 -0
  277. package/src/SideNav/SideNav.test.tsx +179 -0
  278. package/src/SideNav/SideNavItem.doc.mjs +2 -2
  279. package/src/SideNav/SideNavItem.tsx +96 -17
  280. package/src/Slider/Slider.spec.md +39 -18
  281. package/src/Switch/Switch.test.tsx +49 -0
  282. package/src/Switch/Switch.tsx +11 -0
  283. package/src/TabList/TabList.spec.md +57 -44
  284. package/src/TabList/TabList.test.tsx +67 -0
  285. package/src/TabList/TabMenu.doc.mjs +4 -3
  286. package/src/TabList/TabMenu.tsx +7 -4
  287. package/src/Text/Text.test.tsx +57 -0
  288. package/src/Text/Text.tsx +6 -2
  289. package/src/Text/useTruncation.test.tsx +69 -0
  290. package/src/Text/useTruncation.ts +16 -5
  291. package/src/TimeInput/TimeInput.fr10.test.tsx +15 -0
  292. package/src/ToggleButton/ToggleButton.test.tsx +95 -0
  293. package/src/ToggleButton/ToggleButton.tsx +12 -1
  294. package/src/Tokenizer/Tokenizer.test.tsx +54 -1
  295. package/src/Tooltip/Tooltip.test.tsx +31 -0
  296. package/src/Tooltip/useTooltip.test.tsx +13 -0
  297. package/src/Tooltip/useTooltip.tsx +11 -0
  298. package/src/TopNav/TopNavMegaMenu.test.tsx +22 -0
  299. package/src/TopNav/TopNavMegaMenu.tsx +7 -3
  300. package/src/TopNav/TopNavMenu.test.tsx +19 -0
  301. package/src/TopNav/TopNavMenu.tsx +11 -3
  302. package/src/TreeList/TreeList.doc.mjs +1 -0
  303. package/src/TreeList/TreeList.spec.md +29 -17
  304. package/src/TreeList/TreeList.test.tsx +327 -6
  305. package/src/TreeList/TreeList.tsx +5 -1
  306. package/src/TreeList/TreeListBranches.tsx +6 -0
  307. package/src/TreeList/TreeListItem.tsx +88 -13
  308. package/src/Typeahead/BaseTypeahead.tsx +26 -0
  309. package/src/Typeahead/Typeahead.test.tsx +260 -2
  310. package/src/docPropLiterals.test.ts +36 -10
  311. package/src/hooks/useEntryAnimation.doc.mjs +4 -4
  312. package/src/hooks/useEntryAnimation.ssr.test.tsx +143 -0
  313. package/src/hooks/useEntryAnimation.ts +15 -16
  314. package/src/hooks/useIsHydrating.test.tsx +70 -0
  315. package/src/hooks/useIsHydrating.ts +31 -0
  316. package/src/hooks/useMenuHover.ts +18 -13
  317. package/src/i18n/InternationalizationProvider.doc.mjs +8 -0
  318. package/src/i18n/InternationalizationProvider.spec.md +252 -0
  319. package/src/i18n/__tests__/InternationalizationProvider.test.tsx +128 -0
  320. package/src/i18n/generated-locales/en.generated.ts +121 -0
  321. package/src/i18n/generated-locales/pseudo.generated.ts +121 -0
  322. package/src/i18n/useTranslator.test.tsx +37 -0
  323. package/src/index.ts +1 -0
  324. package/src/reset.css +0 -29
  325. package/src/theme/derivedVarRegistry.test.ts +7 -3
  326. package/src/theme/derivedVarRegistry.ts +0 -3
  327. package/src/utils/focusOutline.stylex.ts +4 -0
  328. package/src/utils/plainDate.test.ts +37 -1
  329. package/src/utils/plainDate.ts +15 -5
  330. package/src/utils/sharedMutationObserver.test.ts +53 -0
  331. package/src/utils/sharedMutationObserver.ts +78 -0
@@ -20,6 +20,7 @@ import {
20
20
  } from '@testing-library/react';
21
21
  import userEvent from '@testing-library/user-event';
22
22
  import {Pagination, generatePageRange} from './Pagination';
23
+ import {InternationalizationProvider} from '../i18n';
23
24
  import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
24
25
 
25
26
  afterEach(() => {
@@ -119,6 +120,28 @@ describe('Pagination', () => {
119
120
  ).toBeInTheDocument();
120
121
  });
121
122
 
123
+ it('does not introduce Stack theme targets around navigation controls', () => {
124
+ const {rerender} = render(
125
+ <Pagination page={3} onChange={() => {}} totalPages={5} />,
126
+ );
127
+ expect(
128
+ screen.getByRole('navigation').querySelector('.astryx-stack'),
129
+ ).toBeNull();
130
+
131
+ rerender(
132
+ <Pagination
133
+ page={3}
134
+ onChange={() => {}}
135
+ totalPages={5}
136
+ variant="compact"
137
+ hasFirstLast
138
+ />,
139
+ );
140
+ expect(
141
+ screen.getByRole('navigation').querySelector('.astryx-stack'),
142
+ ).toBeNull();
143
+ });
144
+
122
145
  it('gives the prev/next carets a hover tooltip matching their accessible name', () => {
123
146
  // The carets are icon-only, so sighted users need a visible label on
124
147
  // hover, not just the accessible name. The tooltip reuses the same
@@ -291,6 +314,225 @@ describe('Pagination', () => {
291
314
  );
292
315
  expect(screen.getByText('Page 3 of 10')).toBeInTheDocument();
293
316
  });
317
+
318
+ describe('first/last buttons', () => {
319
+ function navButtonNames(): string[] {
320
+ return within(screen.getByRole('navigation'))
321
+ .getAllByRole('button')
322
+ .map(button => button.getAttribute('aria-label') ?? '');
323
+ }
324
+
325
+ it('omits first/last when hasFirstLast is unset', () => {
326
+ render(
327
+ <Pagination
328
+ page={5}
329
+ onChange={() => {}}
330
+ totalPages={10}
331
+ variant="compact"
332
+ />,
333
+ );
334
+ expect(navButtonNames()).toEqual([
335
+ 'Go to previous page',
336
+ 'Go to next page',
337
+ ]);
338
+ });
339
+
340
+ it('omits first/last when hasFirstLast is false', () => {
341
+ render(
342
+ <Pagination
343
+ page={5}
344
+ onChange={() => {}}
345
+ totalPages={10}
346
+ variant="compact"
347
+ hasFirstLast={false}
348
+ />,
349
+ );
350
+ expect(navButtonNames()).toEqual([
351
+ 'Go to previous page',
352
+ 'Go to next page',
353
+ ]);
354
+ });
355
+
356
+ it('flanks prev/next with first/last when hasFirstLast is true', () => {
357
+ render(
358
+ <Pagination
359
+ page={5}
360
+ onChange={() => {}}
361
+ totalPages={10}
362
+ variant="compact"
363
+ hasFirstLast
364
+ />,
365
+ );
366
+ expect(navButtonNames()).toEqual([
367
+ 'Go to first page',
368
+ 'Go to previous page',
369
+ 'Go to next page',
370
+ 'Go to last page',
371
+ ]);
372
+ // The readout stays between prev and next.
373
+ const readout = within(screen.getByRole('navigation')).getByText(
374
+ 'Page 5 of 10',
375
+ );
376
+ const prev = screen.getByRole('button', {name: 'Go to previous page'});
377
+ const next = screen.getByRole('button', {name: 'Go to next page'});
378
+ expect(
379
+ prev.compareDocumentPosition(readout) &
380
+ Node.DOCUMENT_POSITION_FOLLOWING,
381
+ ).toBeTruthy();
382
+ expect(
383
+ next.compareDocumentPosition(readout) &
384
+ Node.DOCUMENT_POSITION_PRECEDING,
385
+ ).toBeTruthy();
386
+ // Compact never gains an editable box.
387
+ expect(screen.queryByRole('spinbutton')).not.toBeInTheDocument();
388
+ });
389
+
390
+ it('jumps to the first and last page through onChange and changeAction', async () => {
391
+ const user = userEvent.setup();
392
+ const onChange = vi.fn();
393
+ const changeAction = vi.fn();
394
+ render(
395
+ <Pagination
396
+ page={5}
397
+ onChange={onChange}
398
+ changeAction={changeAction}
399
+ totalItems={95}
400
+ pageSize={10}
401
+ variant="compact"
402
+ hasFirstLast
403
+ />,
404
+ );
405
+ await user.click(
406
+ screen.getByRole('button', {name: 'Go to first page'}),
407
+ );
408
+ expect(onChange).toHaveBeenLastCalledWith(1);
409
+ expect(changeAction).toHaveBeenLastCalledWith(1);
410
+ await waitFor(() => {
411
+ expect(politeRegion()).toHaveTextContent('Page 1 of 10');
412
+ });
413
+
414
+ await user.click(screen.getByRole('button', {name: 'Go to last page'}));
415
+ // 95 items at 10 per page is 10 pages.
416
+ expect(onChange).toHaveBeenLastCalledWith(10);
417
+ expect(changeAction).toHaveBeenLastCalledWith(10);
418
+ await waitFor(() => {
419
+ expect(politeRegion()).toHaveTextContent('Page 10 of 10');
420
+ });
421
+ });
422
+
423
+ it('disables first on the first page and last on the last page', () => {
424
+ const {rerender} = render(
425
+ <Pagination
426
+ page={1}
427
+ onChange={() => {}}
428
+ totalPages={10}
429
+ variant="compact"
430
+ hasFirstLast
431
+ />,
432
+ );
433
+ expect(
434
+ screen.getByRole('button', {name: 'Go to first page'}),
435
+ ).toBeDisabled();
436
+ expect(
437
+ screen.getByRole('button', {name: 'Go to last page'}),
438
+ ).not.toBeDisabled();
439
+
440
+ rerender(
441
+ <Pagination
442
+ page={10}
443
+ onChange={() => {}}
444
+ totalPages={10}
445
+ variant="compact"
446
+ hasFirstLast
447
+ />,
448
+ );
449
+ expect(
450
+ screen.getByRole('button', {name: 'Go to first page'}),
451
+ ).not.toBeDisabled();
452
+ expect(
453
+ screen.getByRole('button', {name: 'Go to last page'}),
454
+ ).toBeDisabled();
455
+ });
456
+
457
+ it('omits first/last when the total page count is unknown', async () => {
458
+ const user = userEvent.setup();
459
+ const onChange = vi.fn();
460
+ render(
461
+ <Pagination
462
+ page={2}
463
+ onChange={onChange}
464
+ hasMore
465
+ variant="compact"
466
+ hasFirstLast
467
+ />,
468
+ );
469
+ expect(navButtonNames()).toEqual([
470
+ 'Go to previous page',
471
+ 'Go to next page',
472
+ ]);
473
+ await user.click(screen.getByRole('button', {name: 'Go to next page'}));
474
+ expect(onChange).toHaveBeenLastCalledWith(3);
475
+ });
476
+
477
+ it('mirrors the first/last chevrons under RTL like prev/next', () => {
478
+ render(
479
+ <InternationalizationProvider locale="en" dir="rtl">
480
+ <div dir="rtl">
481
+ <Pagination
482
+ page={5}
483
+ onChange={() => {}}
484
+ totalPages={10}
485
+ variant="compact"
486
+ hasFirstLast
487
+ />
488
+ </div>
489
+ </InternationalizationProvider>,
490
+ );
491
+ // jsdom applies no CSS transforms, so assert the first/last icons carry
492
+ // every class the mirrored prev/next icons share (the mirror included).
493
+ const iconClasses = (name: string) =>
494
+ new Set(
495
+ screen
496
+ .getByRole('button', {name})
497
+ .querySelector('.astryx-icon')
498
+ ?.getAttribute('class')
499
+ ?.split(/\s+/) ?? [],
500
+ );
501
+ const prev = iconClasses('Go to previous page');
502
+ const shared = [...iconClasses('Go to next page')].filter(name =>
503
+ prev.has(name),
504
+ );
505
+ expect(shared.length).toBeGreaterThan(0);
506
+ for (const name of ['Go to first page', 'Go to last page']) {
507
+ const classes = iconClasses(name);
508
+ expect(shared.filter(c => !classes.has(c))).toEqual([]);
509
+ }
510
+ });
511
+ });
512
+ });
513
+
514
+ describe('hasFirstLast on other variants', () => {
515
+ it.each(['pages', 'count', 'dots', 'none'] as const)(
516
+ 'does not add first/last to the %s variant',
517
+ variant => {
518
+ render(
519
+ <Pagination
520
+ page={3}
521
+ onChange={() => {}}
522
+ totalItems={50}
523
+ pageSize={10}
524
+ variant={variant}
525
+ hasFirstLast
526
+ />,
527
+ );
528
+ expect(
529
+ screen.queryByRole('button', {name: 'Go to first page'}),
530
+ ).not.toBeInTheDocument();
531
+ expect(
532
+ screen.queryByRole('button', {name: 'Go to last page'}),
533
+ ).not.toBeInTheDocument();
534
+ },
535
+ );
294
536
  });
295
537
 
296
538
  // ---------------------------------------------------------------------------
@@ -5,9 +5,10 @@
5
5
  /**
6
6
  * @file Pagination.tsx
7
7
  * @input Uses React, StyleX, Button, Icon, Selector, Text; page number buttons delegate to Button.
8
+ * Compact first/last buttons cancel the inside control gap with logical token margins.
8
9
  * Prev/next and first/last chevrons mirror under RTL via the shared rtlStyles.mirror
9
- * (CSS scaleX), not a JS direction read. The input variant uses the chevronsLeft/chevronsRight
10
- * (first/last) icons.
10
+ * (CSS scaleX), not a JS direction read. The input and compact variants use the
11
+ * chevronsLeft/chevronsRight (first/last) icons.
11
12
  * @output Exports Pagination component, PaginationProps, PaginationVariant, PaginationSize types
12
13
  * @position Core implementation; consumed by index.ts, tested by Pagination.test.tsx
13
14
  *
@@ -105,7 +106,8 @@ export interface PaginationProps extends Omit<
105
106
  * Visual variant controlling what appears between prev/next buttons.
106
107
  * - pages: Page number buttons with ellipsis (default)
107
108
  * - count: "X–Y of Z" text
108
- * - compact: "Page X of Y" text
109
+ * - compact: "Page X of Y" text. First/last buttons are opt-in (see
110
+ * hasFirstLast).
109
111
  * - dots: Dot indicators
110
112
  * - input: An editable number box rendering "Page [ n ] / N". The leading
111
113
  * noun is controlled by `pageLabel`. First/last double-chevron buttons
@@ -122,9 +124,11 @@ export interface PaginationProps extends Omit<
122
124
  pageLabel?: string;
123
125
  /**
124
126
  * Whether to show first/last («/») double-chevron buttons flanking
125
- * prev/next. Only applies to the `input` variant; other variants ignore it.
126
- * The last button needs a known total — it is omitted when the page count is
127
- * unknown (cursor/hasMore pagination). @default true
127
+ * prev/next. Applies to the `input` variant (shown unless false) and the
128
+ * `compact` variant (shown only when true); other variants ignore it.
129
+ * The last button needs a known total — both are omitted when the page count
130
+ * is unknown (cursor/hasMore pagination).
131
+ * @default true for `input`, false for `compact`
128
132
  */
129
133
  hasFirstLast?: boolean;
130
134
  /**
@@ -181,6 +185,12 @@ const styles = stylex.create({
181
185
  alignItems: 'center',
182
186
  gap: spacingVars['--spacing-1'],
183
187
  },
188
+ compactFirst: {
189
+ marginInlineEnd: `calc(-1 * ${spacingVars['--spacing-1']})`,
190
+ },
191
+ compactLast: {
192
+ marginInlineStart: `calc(-1 * ${spacingVars['--spacing-1']})`,
193
+ },
184
194
  ellipsis: {
185
195
  display: 'inline-flex',
186
196
  alignItems: 'center',
@@ -369,7 +379,7 @@ export function Pagination({
369
379
  onPageSizeChange,
370
380
  variant = 'pages',
371
381
  pageLabel,
372
- hasFirstLast = true,
382
+ hasFirstLast: hasFirstLastProp,
373
383
  step: stepProp = 1,
374
384
  siblingCount = 1,
375
385
  size = 'md',
@@ -572,10 +582,14 @@ export function Pagination({
572
582
  const buttonSize = size === 'sm' ? 'sm' : 'md';
573
583
  const isSm = size === 'sm';
574
584
 
575
- // First/last buttons only exist in the input variant, and only when the page
576
- // count is known (they'd have no target otherwise).
577
- const showFirstLast =
578
- hasFirstLast && variant === 'input' && computedTotalPages != null;
585
+ // First/last buttons are on by default in the input variant and opt-in for
586
+ // compact; other variants never render them. They also need a known page
587
+ // count (the last button would have no target otherwise).
588
+ const hasFirstLast =
589
+ variant === 'input'
590
+ ? (hasFirstLastProp ?? true)
591
+ : variant === 'compact' && hasFirstLastProp === true;
592
+ const showFirstLast = hasFirstLast && computedTotalPages != null;
579
593
 
580
594
  const renderIndicator = () => {
581
595
  switch (variant) {
@@ -819,6 +833,7 @@ export function Pagination({
819
833
  onClick={handleFirst}
820
834
  isDisabled={isDisabled || !hasPrevious}
821
835
  isIconOnly
836
+ xstyle={variant === 'compact' && styles.compactFirst}
822
837
  />
823
838
  )}
824
839
 
@@ -874,6 +889,7 @@ export function Pagination({
874
889
  onClick={handleLast}
875
890
  isDisabled={isDisabled || !hasNext}
876
891
  isIconOnly
892
+ xstyle={variant === 'compact' && styles.compactLast}
877
893
  />
878
894
  )}
879
895
  </div>
@@ -280,10 +280,10 @@ describe('Popover', () => {
280
280
  'utf8',
281
281
  );
282
282
  expect(popoverSource).toMatch(
283
- /surfaceViewportFit:[\s\S]*?maxInlineSize: stylex\.firstThatWorks\(\s*layerViewportInset\.maxInlineSize/,
283
+ /surfaceViewportFit:[\s\S]*?maxInlineSize: stylex\.firstThatWorks\(\s*`calc\(\$\{layerViewportInset\.maxInlineSize\}\)`/,
284
284
  );
285
285
  expect(popoverSource).toMatch(
286
- /surfaceViewportFit:[\s\S]*?maxBlockSize: stylex\.firstThatWorks\(\s*layerViewportInset\.maxBlockSize/,
286
+ /surfaceViewportFit:[\s\S]*?maxBlockSize: stylex\.firstThatWorks\(\s*`calc\(\$\{layerViewportInset\.maxBlockSize\}\)`/,
287
287
  );
288
288
  expect(popoverSource).not.toMatch(/safe-area-inset|calc\(100%/);
289
289
  expect(surface?.className).not.toContain(
@@ -272,12 +272,12 @@ const styles = stylex.create({
272
272
  surfaceViewportFit: {
273
273
  boxSizing: 'border-box',
274
274
  maxInlineSize: stylex.firstThatWorks(
275
- layerViewportInset.maxInlineSize,
276
- layerViewportInset.maxInlineSizeFallback,
275
+ `calc(${layerViewportInset.maxInlineSize})`,
276
+ `calc(${layerViewportInset.maxInlineSizeFallback})`,
277
277
  ),
278
278
  maxBlockSize: stylex.firstThatWorks(
279
- layerViewportInset.maxBlockSize,
280
- layerViewportInset.maxBlockSizeFallback,
279
+ `calc(${layerViewportInset.maxBlockSize})`,
280
+ `calc(${layerViewportInset.maxBlockSizeFallback})`,
281
281
  ),
282
282
  },
283
283
  surfaceScrollable: {
@@ -165,6 +165,91 @@ describe('PowerSearch', () => {
165
165
  expect(screen.getByRole('combobox')).toHaveFocus();
166
166
  });
167
167
 
168
+ it('clears all added filters when the clear button is clicked', async () => {
169
+ const user = userEvent.setup();
170
+ render(<PowerSearchWrapper config={config} />);
171
+ const input = screen.getByRole('combobox', {name: 'Search'});
172
+ await user.type(input, 'status open');
173
+ await user.click(
174
+ await screen.findByRole('option', {name: 'Status is Open', hidden: true}),
175
+ );
176
+ await user.type(input, 'title login');
177
+ await user.click(
178
+ await screen.findByRole('option', {
179
+ name: 'Title contains "login"',
180
+ hidden: true,
181
+ }),
182
+ );
183
+
184
+ await user.type(input, 'status closed');
185
+ await user.click(
186
+ await screen.findByRole('option', {
187
+ name: 'Status is Closed',
188
+ hidden: true,
189
+ }),
190
+ );
191
+
192
+ expect(screen.getAllByRole('button', {name: /^Remove /})).toHaveLength(3);
193
+
194
+ await user.click(screen.getByRole('button', {name: 'Clear all'}));
195
+
196
+ expect(screen.queryAllByRole('button', {name: /^Remove /})).toHaveLength(0);
197
+ expect(
198
+ screen.queryByRole('button', {name: 'Clear all'}),
199
+ ).not.toBeInTheDocument();
200
+ });
201
+
202
+ it('clicking the remove button on a filter removes only that filter', async () => {
203
+ const user = userEvent.setup();
204
+ render(<PowerSearchWrapper config={config} />);
205
+ const input = screen.getByRole('combobox', {name: 'Search'});
206
+ await user.type(input, 'status open');
207
+ await user.click(
208
+ await screen.findByRole('option', {name: 'Status is Open', hidden: true}),
209
+ );
210
+ await user.type(input, 'title login');
211
+ await user.click(
212
+ await screen.findByRole('option', {
213
+ name: 'Title contains "login"',
214
+ hidden: true,
215
+ }),
216
+ );
217
+
218
+ expect(screen.getAllByRole('button', {name: /^Remove /})).toHaveLength(2);
219
+
220
+ await user.click(
221
+ screen.getAllByRole('button', {name: 'Remove Status: is'})[0],
222
+ );
223
+
224
+ expect(screen.getAllByRole('button', {name: /^Remove /})).toHaveLength(1);
225
+ expect(screen.getByText('login')).toBeInTheDocument();
226
+ });
227
+
228
+ it('Backspace on an empty input removes only the last filter', async () => {
229
+ const user = userEvent.setup();
230
+ render(<PowerSearchWrapper config={config} />);
231
+ const input = screen.getByRole('combobox', {name: 'Search'});
232
+ await user.type(input, 'status open');
233
+ await user.click(
234
+ await screen.findByRole('option', {name: 'Status is Open', hidden: true}),
235
+ );
236
+ await user.type(input, 'title login');
237
+ await user.click(
238
+ await screen.findByRole('option', {
239
+ name: 'Title contains "login"',
240
+ hidden: true,
241
+ }),
242
+ );
243
+
244
+ expect(screen.getAllByRole('button', {name: /^Remove /})).toHaveLength(2);
245
+
246
+ await user.click(input);
247
+ await user.keyboard('{Backspace}');
248
+
249
+ expect(screen.getAllByRole('button', {name: /^Remove /})).toHaveLength(1);
250
+ expect(screen.getByText('Open')).toBeInTheDocument();
251
+ });
252
+
168
253
  describe('token value truncation (#4759)', () => {
169
254
  it('truncates token values by characters, not code units', () => {
170
255
  const truncConfig: PowerSearchConfig = {
@@ -733,8 +733,8 @@ export function PowerSearch({
733
733
  } else if (change.type === 'remove' && change.item) {
734
734
  const auxData = change.item.auxiliaryData as PowerSearchAuxData;
735
735
  if (auxData?.filterIndex != null) {
736
- const newFilters = filters.filter(
737
- (_, i) => i !== auxData.filterIndex,
736
+ const newFilters = filters.filter((_, i) =>
737
+ _items.some(item => item.auxiliaryData?.filterIndex === i),
738
738
  );
739
739
  onChange(newFilters, 'remove', auxData.filterIndex);
740
740
  }
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) Meta Platforms, Inc. and affiliates.
2
2
 
3
- import {describe, it} from 'vitest';
4
- import {screen} from '@testing-library/react';
3
+ import {describe, it, expect} from 'vitest';
4
+ import {render, screen} from '@testing-library/react';
5
5
  import {expectFieldInputProps} from '../Field/fieldInputFamily.testing';
6
6
  import {describeFieldInputParts} from '../Field/fieldInputFamily.render-testing';
7
7
  import {RadioList, type RadioListProps} from './RadioList';
@@ -22,3 +22,46 @@ describeFieldInputParts('RadioList', {
22
22
  getControl: () => screen.getByRole('radiogroup'),
23
23
  inGroup: false,
24
24
  });
25
+
26
+ describe('RadioList FR10 details', () => {
27
+ it("names the radiogroup by its label and then a caller's aria-labelledby", () => {
28
+ render(
29
+ <>
30
+ <span id="caller-name">Billing</span>
31
+ <RadioList
32
+ label="Plan"
33
+ value="a"
34
+ onChange={() => {}}
35
+ aria-labelledby="caller-name">
36
+ <RadioListItem label="A" value="a" />
37
+ </RadioList>
38
+ </>,
39
+ );
40
+ const group = screen.getByRole('radiogroup');
41
+ const ids = group.getAttribute('aria-labelledby')?.split(' ');
42
+ expect(ids).toHaveLength(2);
43
+ expect(document.getElementById(ids?.[0] ?? '')?.textContent).toContain(
44
+ 'Plan',
45
+ );
46
+ expect(ids?.[1]).toBe('caller-name');
47
+ expect(screen.getByRole('radiogroup', {name: 'Plan Billing'})).toBe(group);
48
+ });
49
+
50
+ it('puts hidden, inert, and dir on the radiogroup', () => {
51
+ render(
52
+ <RadioList
53
+ label="Plan"
54
+ value="a"
55
+ onChange={() => {}}
56
+ hidden
57
+ inert
58
+ dir="rtl">
59
+ <RadioListItem label="A" value="a" />
60
+ </RadioList>,
61
+ );
62
+ const group = document.querySelector<HTMLElement>('[role="radiogroup"]');
63
+ expect(group).toHaveAttribute('hidden');
64
+ expect(group).toHaveAttribute('inert');
65
+ expect(group).toHaveAttribute('dir', 'rtl');
66
+ });
67
+ });
@@ -524,6 +524,28 @@ describe('RadioList', () => {
524
524
  });
525
525
 
526
526
  describe('RadioListItem rest forwarding', () => {
527
+ it('forwards align to its Item row unchanged', () => {
528
+ render(
529
+ <RadioList label="Preference" value="" onChange={() => {}}>
530
+ <RadioListItem label="Option A" value="a" data-testid="item-a" />
531
+ <RadioListItem
532
+ label="Option B"
533
+ value="b"
534
+ align="first-line"
535
+ data-testid="item-b"
536
+ />
537
+ </RadioList>,
538
+ );
539
+ expect(screen.getByTestId('item-a')).toHaveAttribute(
540
+ 'data-align',
541
+ 'center',
542
+ );
543
+ expect(screen.getByTestId('item-b')).toHaveAttribute(
544
+ 'data-align',
545
+ 'first-line',
546
+ );
547
+ });
548
+
527
549
  it('forwards data-testid, id, and aria-* to the item root element', () => {
528
550
  render(
529
551
  <RadioList label="Preference" value="" onChange={() => {}}>
@@ -31,6 +31,7 @@ import type {InputStatus} from '../Field/types';
31
31
  import {useTooltip} from '../Tooltip';
32
32
  import {useResolvedRequired} from '../hooks/useResolvedRequired';
33
33
  import {composeEventHandlers, mergeProps} from '../utils';
34
+ import {joinAriaIDs} from '../utils/inputAria';
34
35
  import {
35
36
  type FieldInputBaseProps,
36
37
  useFieldInputStyling,
@@ -216,6 +217,7 @@ export function RadioList({
216
217
  htmlName,
217
218
  children,
218
219
  onFocus,
220
+ 'aria-labelledby': ariaLabelledByProp,
219
221
  'aria-describedby': ariaDescribedByProp,
220
222
  ...restProps
221
223
  }: RadioListProps) {
@@ -399,7 +401,8 @@ export function RadioList({
399
401
  disabledMessageTooltip.ref(el);
400
402
  }}
401
403
  role="radiogroup"
402
- aria-labelledby={labelID}
404
+ // A caller aria-labelledby names the group together with its label.
405
+ aria-labelledby={joinAriaIDs(labelID, ariaLabelledByProp)}
403
406
  onFocus={composeEventHandlers(handleFocus, onFocus)}
404
407
  aria-describedby={
405
408
  [
@@ -43,6 +43,13 @@ export const docs = {
43
43
  description:
44
44
  'Secondary content displayed below the label. Links and buttons keep their own click behaviour — the row only delegates clicks from its non-interactive surface to the radio.',
45
45
  },
46
+ {
47
+ name: 'align',
48
+ type: "'center' | 'start' | 'first-line'",
49
+ description:
50
+ 'Vertical alignment of the start and end content against the label, passed through to Item unchanged. `first-line` keeps a small mark (a radio) level with the first line of a wrapped label. See Item.align.',
51
+ default: "'center'",
52
+ },
46
53
  {
47
54
  name: 'isDisabled',
48
55
  type: 'boolean',
@@ -117,6 +124,13 @@ export const docsZh = {
117
124
  description:
118
125
  '显示在标签下方的次要内容。链接和按钮保留自身的点击行为——整行仅将非交互区域的点击委派给单选框。',
119
126
  },
127
+ {
128
+ name: 'align',
129
+ type: "'center' | 'start' | 'first-line'",
130
+ description:
131
+ '起始和结束内容相对于标签的垂直对齐方式,原样传递给 Item。`first-line` 让小标记(单选按钮)与换行标签的第一行保持水平。参见 Item.align。',
132
+ default: "'center'",
133
+ },
120
134
  {
121
135
  name: 'isDisabled',
122
136
  type: 'boolean',
@@ -142,6 +156,8 @@ export const docsDense = {
142
156
  displayName: 'Radio List Item',
143
157
  description: 'Individual radio item w/ label, description, content slots.',
144
158
  propDescriptions: {
159
+ align:
160
+ "Start/end content alignment, passed to Item: 'center' (default), 'start', or 'first-line' (centered on the label's first line).",
145
161
  label:
146
162
  'Primary label. String or ReactNode; nested controls keep their behavior.',
147
163
  'aria-label':
@@ -29,7 +29,7 @@ import {indicatorScope} from '../Indicator/indicator.markers.stylex';
29
29
  import {useIndicatorFocusRing} from '../hooks/useIndicatorFocusRing';
30
30
  import {usePressFeedback} from '../hooks/usePressFeedback';
31
31
  import {useIndicator} from '../Indicator';
32
- import {Item} from '../Item';
32
+ import {Item, type ItemAlign} from '../Item';
33
33
  import {themeProps} from '../utils/themeProps';
34
34
 
35
35
  // The touch press's paint, declared by the shared overlay styles on the
@@ -156,6 +156,13 @@ const rowStyles = stylex.create({
156
156
 
157
157
  export interface RadioListItemProps extends BaseProps<HTMLDivElement> {
158
158
  ref?: React.Ref<HTMLDivElement>;
159
+ /**
160
+ * Vertical alignment of the start and end content against the label,
161
+ * forwarded to Item. Use `first-line` to keep the radio level with the
162
+ * first line of a wrapped label.
163
+ * @default 'center'
164
+ */
165
+ align?: ItemAlign;
159
166
  /**
160
167
  * Primary label for the radio item.
161
168
  *
@@ -232,6 +239,7 @@ export function RadioListItem({
232
239
  isDisabled: isItemDisabled = false,
233
240
  startContent,
234
241
  endContent,
242
+ align,
235
243
  xstyle,
236
244
  className,
237
245
  style,
@@ -366,6 +374,7 @@ export function RadioListItem({
366
374
  ) : undefined
367
375
  }
368
376
  endContent={endContent}
377
+ align={align}
369
378
  xstyle={
370
379
  [
371
380
  // Hover reaches the radio visual through this ancestor marker rather