@astryxdesign/core 0.4.5 → 0.4.6-canary.cea9ecd

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 (538) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/dist/Avatar/Avatar.d.ts +10 -5
  3. package/dist/Avatar/Avatar.d.ts.map +1 -1
  4. package/dist/Avatar/Avatar.js +139 -30
  5. package/dist/Avatar/AvatarStatusDot.d.ts +2 -1
  6. package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
  7. package/dist/Avatar/AvatarStatusDot.js +30 -4
  8. package/dist/Avatar/AvatarStatusLabelContext.d.ts +39 -0
  9. package/dist/Avatar/AvatarStatusLabelContext.d.ts.map +1 -0
  10. package/dist/Avatar/AvatarStatusLabelContext.js +41 -0
  11. package/dist/AvatarGroup/AvatarGroup.d.ts +3 -1
  12. package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
  13. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroupOverflow.js +15 -9
  15. package/dist/Blockquote/Blockquote.d.ts +4 -3
  16. package/dist/Blockquote/Blockquote.d.ts.map +1 -1
  17. package/dist/Blockquote/Blockquote.js +9 -10
  18. package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
  19. package/dist/BottomSheet/BottomSheetPanel.js +21 -5
  20. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  21. package/dist/Breadcrumbs/BreadcrumbItem.js +47 -34
  22. package/dist/Button/Button.d.ts.map +1 -1
  23. package/dist/Button/Button.js +7 -7
  24. package/dist/Calendar/Calendar.d.ts.map +1 -1
  25. package/dist/Calendar/Calendar.js +21 -12
  26. package/dist/Calendar/hooks/useCalendarNavigation.d.ts.map +1 -1
  27. package/dist/Calendar/hooks/useCalendarNavigation.js +8 -4
  28. package/dist/Calendar/styles.d.ts +2 -2
  29. package/dist/Calendar/styles.d.ts.map +1 -1
  30. package/dist/Calendar/styles.js +5 -5
  31. package/dist/Center/Center.d.ts +23 -1
  32. package/dist/Center/Center.d.ts.map +1 -1
  33. package/dist/Center/Center.js +12 -6
  34. package/dist/Chat/ChatComposer.d.ts.map +1 -1
  35. package/dist/Chat/ChatComposer.js +3 -3
  36. package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
  37. package/dist/Chat/ChatComposerDrawer.js +2 -2
  38. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  39. package/dist/Chat/ChatToolCalls.js +2 -2
  40. package/dist/Chat/useChatDictation.d.ts +1 -1
  41. package/dist/Chat/useChatDictation.d.ts.map +1 -1
  42. package/dist/Chat/useSpeechRecognition.d.ts +1 -1
  43. package/dist/Chat/useSpeechRecognition.d.ts.map +1 -1
  44. package/dist/Chat/useSpeechRecognition.js +4 -3
  45. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  46. package/dist/Chat/useTriggerMenu.js +2 -2
  47. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  48. package/dist/CheckboxInput/CheckboxInput.js +2 -2
  49. package/dist/Citation/Citation.d.ts.map +1 -1
  50. package/dist/Citation/Citation.js +5 -5
  51. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  52. package/dist/ClickableCard/ClickableCard.js +4 -4
  53. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  54. package/dist/CodeBlock/CodeBlock.js +1 -1
  55. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  56. package/dist/Collapsible/Collapsible.js +2 -2
  57. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  58. package/dist/CommandPalette/CommandPaletteItem.js +3 -3
  59. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  60. package/dist/ComplexSelector/ComplexSelector.js +6 -6
  61. package/dist/DateInput/DateInput.d.ts +31 -2
  62. package/dist/DateInput/DateInput.d.ts.map +1 -1
  63. package/dist/DateInput/DateInput.js +90 -22
  64. package/dist/DateInput/MonthScroller.d.ts +35 -0
  65. package/dist/DateInput/MonthScroller.d.ts.map +1 -0
  66. package/dist/DateInput/MonthScroller.js +658 -0
  67. package/dist/DateInput/MonthYearWheels.d.ts +24 -0
  68. package/dist/DateInput/MonthYearWheels.d.ts.map +1 -0
  69. package/dist/DateInput/MonthYearWheels.js +114 -0
  70. package/dist/DateInput/TouchDateField.d.ts +10 -0
  71. package/dist/DateInput/TouchDateField.d.ts.map +1 -0
  72. package/dist/DateInput/TouchDateField.js +810 -0
  73. package/dist/DateInput/Wheel.d.ts +41 -0
  74. package/dist/DateInput/Wheel.d.ts.map +1 -0
  75. package/dist/DateInput/Wheel.js +315 -0
  76. package/dist/DateInput/monthGeometry.d.ts +65 -0
  77. package/dist/DateInput/monthGeometry.d.ts.map +1 -0
  78. package/dist/DateInput/monthGeometry.js +98 -0
  79. package/dist/DateInput/tokens.stylex.d.ts +63 -0
  80. package/dist/DateInput/tokens.stylex.d.ts.map +1 -0
  81. package/dist/DateInput/tokens.stylex.js +74 -0
  82. package/dist/DateInput/useOwnScrollGesture.d.ts +41 -0
  83. package/dist/DateInput/useOwnScrollGesture.d.ts.map +1 -0
  84. package/dist/DateInput/useOwnScrollGesture.js +202 -0
  85. package/dist/DateInput/usePointerDragScroll.d.ts +15 -0
  86. package/dist/DateInput/usePointerDragScroll.d.ts.map +1 -0
  87. package/dist/DateInput/usePointerDragScroll.js +216 -0
  88. package/dist/DateInput/useScrollSettle.d.ts +26 -0
  89. package/dist/DateInput/useScrollSettle.d.ts.map +1 -0
  90. package/dist/DateInput/useScrollSettle.js +149 -0
  91. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  92. package/dist/DateRangeInput/DateRangeInput.js +17 -14
  93. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  94. package/dist/DateTimeInput/DateTimeInput.js +17 -14
  95. package/dist/Dialog/Dialog.d.ts.map +1 -1
  96. package/dist/Dialog/Dialog.js +3 -3
  97. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  98. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +2 -2
  99. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  100. package/dist/DropdownMenu/DropdownMenuItem.js +2 -2
  101. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  102. package/dist/DropdownMenu/DropdownMenuRadioItem.js +2 -2
  103. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  104. package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -2
  105. package/dist/Field/FieldLabel.d.ts.map +1 -1
  106. package/dist/Field/FieldLabel.js +4 -4
  107. package/dist/Field/InputClearButton.d.ts.map +1 -1
  108. package/dist/Field/InputClearButton.js +6 -0
  109. package/dist/Field/inputStyles.stylex.d.ts +1 -1
  110. package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
  111. package/dist/Field/inputStyles.stylex.js +5 -5
  112. package/dist/FileInput/FileInput.d.ts.map +1 -1
  113. package/dist/FileInput/FileInput.js +6 -6
  114. package/dist/HoverCard/HoverCard.d.ts +13 -3
  115. package/dist/HoverCard/HoverCard.d.ts.map +1 -1
  116. package/dist/HoverCard/HoverCard.js +2 -0
  117. package/dist/HoverCard/index.d.ts +1 -1
  118. package/dist/HoverCard/index.d.ts.map +1 -1
  119. package/dist/HoverCard/useHoverCard.d.ts +17 -2
  120. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  121. package/dist/HoverCard/useHoverCard.js +78 -9
  122. package/dist/InputGroup/InputGroup.js +1 -1
  123. package/dist/Item/Item.d.ts +9 -1
  124. package/dist/Item/Item.d.ts.map +1 -1
  125. package/dist/Item/Item.js +52 -14
  126. package/dist/Layer/index.d.ts +4 -2
  127. package/dist/Layer/index.d.ts.map +1 -1
  128. package/dist/Layer/index.js +2 -0
  129. package/dist/Layer/useLayer.d.ts.map +1 -1
  130. package/dist/Layer/useLayer.js +3 -2
  131. package/dist/Layer/useTouchTrigger.d.ts +113 -0
  132. package/dist/Layer/useTouchTrigger.d.ts.map +1 -0
  133. package/dist/Layer/useTouchTrigger.js +241 -0
  134. package/dist/Layout/container.stylex.d.ts +4 -2
  135. package/dist/Layout/container.stylex.d.ts.map +1 -1
  136. package/dist/Layout/container.stylex.js +19 -11
  137. package/dist/Layout/index.d.ts +1 -0
  138. package/dist/Layout/index.d.ts.map +1 -1
  139. package/dist/Layout/index.js +4 -0
  140. package/dist/Layout/padding.stylex.d.ts +315 -12
  141. package/dist/Layout/padding.stylex.d.ts.map +1 -1
  142. package/dist/Layout/padding.stylex.js +389 -12
  143. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  144. package/dist/Lightbox/Lightbox.js +5 -4
  145. package/dist/Link/Link.d.ts.map +1 -1
  146. package/dist/Link/Link.js +6 -6
  147. package/dist/MetadataList/MetadataList.d.ts.map +1 -1
  148. package/dist/MetadataList/MetadataList.js +1 -1
  149. package/dist/MobileNav/MobileNav.d.ts +1 -0
  150. package/dist/MobileNav/MobileNav.d.ts.map +1 -1
  151. package/dist/MobileNav/MobileNav.js +24 -6
  152. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  153. package/dist/MultiSelector/MultiSelector.js +8 -8
  154. package/dist/NavItem/navItemStyles.stylex.d.ts +4 -4
  155. package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
  156. package/dist/NavItem/navItemStyles.stylex.js +4 -4
  157. package/dist/NavMenu/NavHeadingMenuItem.d.ts.map +1 -1
  158. package/dist/NavMenu/NavHeadingMenuItem.js +3 -3
  159. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  160. package/dist/NumberInput/NumberInput.js +36 -8
  161. package/dist/Outline/Outline.d.ts.map +1 -1
  162. package/dist/Outline/Outline.js +3 -3
  163. package/dist/Pagination/Pagination.d.ts.map +1 -1
  164. package/dist/Pagination/Pagination.js +2 -2
  165. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  166. package/dist/PowerSearch/PowerSearch.js +11 -12
  167. package/dist/PowerSearch/PowerSearchToken.d.ts.map +1 -1
  168. package/dist/PowerSearch/PowerSearchToken.js +3 -1
  169. package/dist/PowerSearch/formatFilterValue.d.ts +11 -2
  170. package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
  171. package/dist/PowerSearch/formatFilterValue.js +23 -8
  172. package/dist/RadioList/RadioListItem.d.ts +2 -2
  173. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  174. package/dist/RadioList/RadioListItem.js +70 -40
  175. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  176. package/dist/Resizable/ResizeHandle.js +7 -7
  177. package/dist/Section/Section.d.ts +36 -1
  178. package/dist/Section/Section.d.ts.map +1 -1
  179. package/dist/Section/Section.js +12 -2
  180. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  181. package/dist/SegmentedControl/SegmentedControlItem.js +7 -2
  182. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  183. package/dist/SelectableCard/SelectableCard.js +3 -3
  184. package/dist/Selector/Selector.d.ts +26 -1
  185. package/dist/Selector/Selector.d.ts.map +1 -1
  186. package/dist/Selector/Selector.js +93 -20
  187. package/dist/Selector/SelectorOption.d.ts +14 -1
  188. package/dist/Selector/SelectorOption.d.ts.map +1 -1
  189. package/dist/Selector/SelectorOption.js +6 -0
  190. package/dist/Selector/SelectorRowLayoutContext.d.ts +8 -0
  191. package/dist/Selector/SelectorRowLayoutContext.d.ts.map +1 -0
  192. package/dist/Selector/SelectorRowLayoutContext.js +27 -0
  193. package/dist/Selector/types.d.ts +1 -0
  194. package/dist/Selector/types.d.ts.map +1 -1
  195. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  196. package/dist/SideNav/SideNavHeading.js +4 -4
  197. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  198. package/dist/SideNav/SideNavItem.js +3 -3
  199. package/dist/Slider/Slider.d.ts.map +1 -1
  200. package/dist/Slider/Slider.js +7 -7
  201. package/dist/Stack/Stack.d.ts +23 -1
  202. package/dist/Stack/Stack.d.ts.map +1 -1
  203. package/dist/Stack/Stack.js +12 -6
  204. package/dist/Switch/Switch.d.ts.map +1 -1
  205. package/dist/Switch/Switch.js +2 -2
  206. package/dist/TabList/Tab.d.ts.map +1 -1
  207. package/dist/TabList/Tab.js +1 -1
  208. package/dist/TabList/TabMenu.d.ts.map +1 -1
  209. package/dist/TabList/TabMenu.js +3 -3
  210. package/dist/Table/TableRow.js +4 -4
  211. package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
  212. package/dist/Table/plugins/columnResize/useTableColumnResize.js +1 -1
  213. package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
  214. package/dist/Table/plugins/filtering/useTableFiltering.js +2 -2
  215. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  216. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +2 -2
  217. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  218. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +2 -2
  219. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  220. package/dist/Table/plugins/sortable/useTableSortable.js +1 -1
  221. package/dist/Table/plugins/sortable/useTableSortableState.d.ts +5 -3
  222. package/dist/Table/plugins/sortable/useTableSortableState.d.ts.map +1 -1
  223. package/dist/Table/plugins/sortable/useTableSortableState.js +12 -9
  224. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  225. package/dist/Table/plugins/tree/useTableTreeData.js +3 -3
  226. package/dist/TextArea/TextArea.js +1 -1
  227. package/dist/TextInput/TextInput.js +1 -1
  228. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  229. package/dist/Thumbnail/Thumbnail.js +3 -3
  230. package/dist/TimeInput/TimeInput.js +2 -2
  231. package/dist/Timestamp/Timestamp.d.ts.map +1 -1
  232. package/dist/Timestamp/Timestamp.js +6 -4
  233. package/dist/Timestamp/formatInstant.d.ts +3 -2
  234. package/dist/Timestamp/formatInstant.d.ts.map +1 -1
  235. package/dist/Timestamp/formatInstant.js +8 -8
  236. package/dist/Timestamp/tooltipEntries.d.ts +2 -1
  237. package/dist/Timestamp/tooltipEntries.d.ts.map +1 -1
  238. package/dist/Timestamp/tooltipEntries.js +5 -3
  239. package/dist/Toast/Toast.d.ts +4 -3
  240. package/dist/Toast/Toast.d.ts.map +1 -1
  241. package/dist/Toast/Toast.js +10 -7
  242. package/dist/Token/Token.d.ts.map +1 -1
  243. package/dist/Token/Token.js +6 -6
  244. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  245. package/dist/Tokenizer/Tokenizer.js +1 -1
  246. package/dist/Tooltip/Tooltip.d.ts +16 -3
  247. package/dist/Tooltip/Tooltip.d.ts.map +1 -1
  248. package/dist/Tooltip/Tooltip.js +2 -0
  249. package/dist/Tooltip/index.d.ts +1 -1
  250. package/dist/Tooltip/index.d.ts.map +1 -1
  251. package/dist/Tooltip/useTooltip.d.ts +21 -2
  252. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  253. package/dist/Tooltip/useTooltip.js +71 -13
  254. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  255. package/dist/TopNav/TopNavHeading.js +4 -4
  256. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  257. package/dist/TopNav/TopNavItem.js +3 -3
  258. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  259. package/dist/TopNav/TopNavMegaMenu.js +2 -2
  260. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  261. package/dist/TopNav/TopNavMegaMenuItem.js +2 -2
  262. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  263. package/dist/TopNav/TopNavMenu.js +4 -4
  264. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  265. package/dist/TreeList/TreeListItem.js +7 -7
  266. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  267. package/dist/Typeahead/BaseTypeahead.js +2 -2
  268. package/dist/Typeahead/Typeahead.d.ts.map +1 -1
  269. package/dist/Typeahead/Typeahead.js +1 -1
  270. package/dist/astryx.css +124 -62
  271. package/dist/hooks/containerReveal.stylex.d.ts.map +1 -1
  272. package/dist/hooks/containerReveal.stylex.js +18 -18
  273. package/dist/hooks/scrollbarGutter.d.ts +28 -0
  274. package/dist/hooks/scrollbarGutter.d.ts.map +1 -0
  275. package/dist/hooks/scrollbarGutter.js +103 -0
  276. package/dist/hooks/useAutoMediaMode.d.ts +31 -0
  277. package/dist/hooks/useAutoMediaMode.d.ts.map +1 -0
  278. package/dist/hooks/useAutoMediaMode.js +201 -0
  279. package/dist/hooks/useInputStatusIcon.d.ts.map +1 -1
  280. package/dist/hooks/useInputStatusIcon.js +1 -1
  281. package/dist/hooks/useListFocus.d.ts +5 -2
  282. package/dist/hooks/useListFocus.d.ts.map +1 -1
  283. package/dist/hooks/useListFocus.js +12 -6
  284. package/dist/hooks/useScrollLock.d.ts +4 -0
  285. package/dist/hooks/useScrollLock.d.ts.map +1 -1
  286. package/dist/hooks/useScrollLock.js +13 -1
  287. package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
  288. package/dist/i18n/InternationalizationContext.js +2 -0
  289. package/dist/i18n/index.d.ts +6 -0
  290. package/dist/i18n/index.d.ts.map +1 -1
  291. package/dist/i18n/index.js +6 -0
  292. package/dist/i18n/useCollator.d.ts +12 -0
  293. package/dist/i18n/useCollator.d.ts.map +1 -0
  294. package/dist/i18n/useCollator.js +40 -0
  295. package/dist/i18n/useLocale.d.ts +3 -0
  296. package/dist/i18n/useLocale.d.ts.map +1 -0
  297. package/dist/i18n/useLocale.js +31 -0
  298. package/dist/theme/MediaTheme.d.ts +25 -5
  299. package/dist/theme/MediaTheme.d.ts.map +1 -1
  300. package/dist/theme/MediaTheme.js +31 -6
  301. package/dist/theme/defineTheme.d.ts +5 -0
  302. package/dist/theme/defineTheme.d.ts.map +1 -1
  303. package/dist/theme/defineTheme.js +5 -0
  304. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  305. package/dist/theme/derivedVarRegistry.js +7 -0
  306. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  307. package/dist/theme/generateThemeRules.js +66 -5
  308. package/dist/theme/index.d.ts +1 -1
  309. package/dist/theme/index.d.ts.map +1 -1
  310. package/dist/theme/syntax/index.d.ts +6 -0
  311. package/dist/theme/syntax/index.d.ts.map +1 -1
  312. package/dist/theme/syntax/index.js +7 -2
  313. package/dist/utils/dateParser.d.ts +4 -3
  314. package/dist/utils/dateParser.d.ts.map +1 -1
  315. package/dist/utils/dateParser.js +8 -8
  316. package/dist/utils/index.d.ts +1 -1
  317. package/dist/utils/index.d.ts.map +1 -1
  318. package/dist/utils/index.js +1 -1
  319. package/dist/utils/plainDate.d.ts +5 -2
  320. package/dist/utils/plainDate.d.ts.map +1 -1
  321. package/dist/utils/plainDate.js +20 -4
  322. package/locales/en.json +28 -0
  323. package/locales/pseudo.json +21 -0
  324. package/package.json +3 -3
  325. package/src/Avatar/Avatar.doc.mjs +10 -6
  326. package/src/Avatar/Avatar.test.tsx +219 -1
  327. package/src/Avatar/Avatar.tsx +179 -37
  328. package/src/Avatar/AvatarStatusDot.tsx +30 -4
  329. package/src/Avatar/AvatarStatusLabelContext.ts +47 -0
  330. package/src/AvatarGroup/AvatarGroup.doc.mjs +10 -6
  331. package/src/AvatarGroup/AvatarGroup.test.tsx +62 -0
  332. package/src/AvatarGroup/AvatarGroup.tsx +3 -1
  333. package/src/AvatarGroup/AvatarGroupOverflow.tsx +31 -8
  334. package/src/Banner/Banner.doc.mjs +2 -0
  335. package/src/Blockquote/Blockquote.doc.mjs +30 -7
  336. package/src/Blockquote/Blockquote.test.tsx +34 -3
  337. package/src/Blockquote/Blockquote.tsx +11 -9
  338. package/src/BottomSheet/BottomSheet.doc.mjs +3 -3
  339. package/src/BottomSheet/BottomSheet.test.tsx +24 -0
  340. package/src/BottomSheet/BottomSheetPanel.test.tsx +91 -0
  341. package/src/BottomSheet/BottomSheetPanel.tsx +58 -3
  342. package/src/Breadcrumbs/BreadcrumbItem.tsx +36 -23
  343. package/src/Breadcrumbs/Breadcrumbs.doc.mjs +26 -2
  344. package/src/Breadcrumbs/Breadcrumbs.test.tsx +31 -0
  345. package/src/Button/Button.tsx +12 -9
  346. package/src/Calendar/Calendar.tsx +15 -9
  347. package/src/Calendar/hooks/useCalendarNavigation.ts +6 -4
  348. package/src/Calendar/styles.ts +8 -5
  349. package/src/Center/Center.doc.mjs +48 -0
  350. package/src/Center/Center.test.tsx +158 -0
  351. package/src/Center/Center.tsx +50 -9
  352. package/src/Chat/ChatComposer.tsx +11 -5
  353. package/src/Chat/ChatComposerDrawer.tsx +4 -1
  354. package/src/Chat/ChatToolCalls.tsx +13 -4
  355. package/src/Chat/{useChatDictation.test.ts → useChatDictation.test.tsx} +29 -14
  356. package/src/Chat/useChatDictation.ts +1 -1
  357. package/src/Chat/useSpeechRecognition.ts +5 -3
  358. package/src/Chat/useTriggerMenu.tsx +4 -1
  359. package/src/CheckboxInput/CheckboxInput.tsx +5 -2
  360. package/src/Citation/Citation.test.tsx +6 -1
  361. package/src/Citation/Citation.tsx +11 -5
  362. package/src/ClickableCard/ClickableCard.tsx +7 -4
  363. package/src/CodeBlock/CodeBlock.tsx +4 -1
  364. package/src/Collapsible/Collapsible.tsx +5 -2
  365. package/src/CommandPalette/CommandPaletteItem.tsx +6 -3
  366. package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -0
  367. package/src/ComplexSelector/ComplexSelector.tsx +14 -7
  368. package/src/DateInput/DateInput.test.tsx +17 -1
  369. package/src/DateInput/DateInput.tsx +93 -21
  370. package/src/DateInput/DateInputTouch.test.tsx +2582 -0
  371. package/src/DateInput/MonthScroller.tsx +878 -0
  372. package/src/DateInput/MonthYearWheels.tsx +147 -0
  373. package/src/DateInput/TouchDateField.tsx +1223 -0
  374. package/src/DateInput/Wheel.tsx +473 -0
  375. package/src/DateInput/monthGeometry.ts +118 -0
  376. package/src/DateInput/tokens.stylex.ts +99 -0
  377. package/src/DateInput/useOwnScrollGesture.ts +227 -0
  378. package/src/DateInput/usePointerDragScroll.ts +220 -0
  379. package/src/DateInput/useScrollSettle.ts +164 -0
  380. package/src/DateRangeInput/DateRangeInput.doc.mjs +1 -1
  381. package/src/DateRangeInput/DateRangeInput.tsx +31 -13
  382. package/src/DateTimeInput/DateTimeInput.tsx +25 -9
  383. package/src/Dialog/Dialog.test.tsx +24 -0
  384. package/src/Dialog/Dialog.tsx +3 -0
  385. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +5 -2
  386. package/src/DropdownMenu/DropdownMenuItem.tsx +5 -2
  387. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +5 -2
  388. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +5 -2
  389. package/src/Field/Field.doc.mjs +2 -0
  390. package/src/Field/FieldLabel.tsx +9 -3
  391. package/src/Field/InputClearButton.test.tsx +110 -3
  392. package/src/Field/InputClearButton.tsx +38 -0
  393. package/src/Field/inputStyles.stylex.ts +17 -13
  394. package/src/FileInput/FileInput.tsx +15 -8
  395. package/src/FormLayout/FormLayout.doc.mjs +1 -1
  396. package/src/HoverCard/HoverCard.doc.mjs +18 -0
  397. package/src/HoverCard/HoverCard.test.tsx +189 -0
  398. package/src/HoverCard/HoverCard.tsx +22 -2
  399. package/src/HoverCard/index.ts +1 -0
  400. package/src/HoverCard/useHoverCard.doc.mjs +2 -0
  401. package/src/HoverCard/useHoverCard.tsx +103 -7
  402. package/src/InputGroup/InputGroup.tsx +1 -1
  403. package/src/Item/Item.doc.mjs +1 -0
  404. package/src/Item/Item.test.tsx +50 -0
  405. package/src/Item/Item.tsx +54 -6
  406. package/src/Layer/index.ts +10 -0
  407. package/src/Layer/useLayer.tsx +13 -2
  408. package/src/Layer/useTouchTrigger.test.ts +70 -0
  409. package/src/Layer/useTouchTrigger.ts +366 -0
  410. package/src/Layout/Layout.doc.mjs +18 -0
  411. package/src/Layout/container.stylex.ts +11 -3
  412. package/src/Layout/index.ts +4 -0
  413. package/src/Layout/overlayPaddingReset.test.tsx +222 -0
  414. package/src/Layout/padding.stylex.ts +192 -12
  415. package/src/Lightbox/Lightbox.tsx +11 -3
  416. package/src/Link/Link.tsx +9 -6
  417. package/src/MetadataList/MetadataList.tsx +4 -1
  418. package/src/MobileNav/MobileNav.tsx +61 -5
  419. package/src/MobileNav/MobileNavEntryAnimation.test.tsx +212 -0
  420. package/src/MobileNav/MobileNavScrollbarGutter.test.tsx +109 -0
  421. package/src/MultiSelector/MultiSelector.test.tsx +1 -1
  422. package/src/MultiSelector/MultiSelector.tsx +26 -10
  423. package/src/NavItem/navItemStyles.stylex.ts +7 -4
  424. package/src/NavMenu/NavHeadingMenuItem.tsx +6 -3
  425. package/src/NumberInput/NumberInput.doc.mjs +24 -0
  426. package/src/NumberInput/NumberInput.test.tsx +138 -0
  427. package/src/NumberInput/NumberInput.tsx +47 -8
  428. package/src/Outline/Outline.tsx +5 -2
  429. package/src/Pagination/Pagination.tsx +5 -2
  430. package/src/Popover/Popover.test.tsx +27 -1
  431. package/src/PowerSearch/PowerSearch.tsx +17 -8
  432. package/src/PowerSearch/PowerSearchToken.tsx +3 -0
  433. package/src/PowerSearch/formatFilterValue.test.ts +22 -2
  434. package/src/PowerSearch/formatFilterValue.ts +31 -6
  435. package/src/RadioList/RadioList.doc.mjs +1 -1
  436. package/src/RadioList/RadioList.test.tsx +170 -2
  437. package/src/RadioList/RadioListItem.tsx +88 -53
  438. package/src/Resizable/ResizeHandle.test.tsx +22 -0
  439. package/src/Resizable/ResizeHandle.tsx +25 -7
  440. package/src/Section/Section.doc.mjs +55 -0
  441. package/src/Section/Section.test.tsx +201 -4
  442. package/src/Section/Section.tsx +69 -0
  443. package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
  444. package/src/SegmentedControl/SegmentedControlItem.tsx +15 -3
  445. package/src/SelectableCard/SelectableCard.tsx +6 -3
  446. package/src/Selector/Selector.doc.mjs +16 -2
  447. package/src/Selector/Selector.test.tsx +525 -1
  448. package/src/Selector/Selector.tsx +180 -25
  449. package/src/Selector/SelectorOption.doc.mjs +7 -0
  450. package/src/Selector/SelectorOption.tsx +21 -0
  451. package/src/Selector/SelectorRowLayoutContext.ts +32 -0
  452. package/src/Selector/types.ts +4 -4
  453. package/src/SideNav/SideNavHeading.tsx +14 -5
  454. package/src/SideNav/SideNavItem.tsx +9 -3
  455. package/src/Slider/Slider.tsx +25 -6
  456. package/src/Stack/Stack.doc.mjs +72 -0
  457. package/src/Stack/Stack.test.tsx +156 -0
  458. package/src/Stack/Stack.tsx +50 -8
  459. package/src/Switch/Switch.tsx +5 -2
  460. package/src/TabList/Tab.tsx +4 -1
  461. package/src/TabList/TabMenu.tsx +9 -3
  462. package/src/Table/TableRow.tsx +4 -4
  463. package/src/Table/plugins/columnResize/useTableColumnResize.tsx +6 -2
  464. package/src/Table/plugins/filtering/useTableFiltering.tsx +4 -1
  465. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +10 -3
  466. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +6 -3
  467. package/src/Table/plugins/sortable/useTableSortable.tsx +4 -1
  468. package/src/Table/plugins/sortable/useTableSortableState.test.tsx +34 -0
  469. package/src/Table/plugins/sortable/useTableSortableState.tsx +26 -23
  470. package/src/Table/plugins/tree/useTableTreeData.tsx +10 -4
  471. package/src/TextArea/TextArea.doc.mjs +1 -1
  472. package/src/TextArea/TextArea.tsx +1 -1
  473. package/src/TextInput/TextInput.tsx +1 -1
  474. package/src/Thumbnail/Thumbnail.tsx +9 -3
  475. package/src/TimeInput/TimeInput.tsx +1 -1
  476. package/src/Timestamp/Timestamp.test.tsx +27 -7
  477. package/src/Timestamp/Timestamp.tsx +8 -4
  478. package/src/Timestamp/formatInstant.ts +9 -7
  479. package/src/Timestamp/tooltipEntries.test.ts +11 -6
  480. package/src/Timestamp/tooltipEntries.ts +6 -2
  481. package/src/Toast/Toast.tsx +9 -7
  482. package/src/Token/Token.tsx +14 -5
  483. package/src/Tokenizer/Tokenizer.tsx +4 -1
  484. package/src/Tooltip/Tooltip.doc.mjs +18 -0
  485. package/src/Tooltip/Tooltip.test.tsx +254 -1
  486. package/src/Tooltip/Tooltip.tsx +22 -2
  487. package/src/Tooltip/index.ts +1 -0
  488. package/src/Tooltip/useTooltip.doc.mjs +2 -0
  489. package/src/Tooltip/useTooltip.tsx +99 -21
  490. package/src/TopNav/TopNavHeading.tsx +13 -4
  491. package/src/TopNav/TopNavItem.tsx +6 -3
  492. package/src/TopNav/TopNavMegaMenu.tsx +5 -2
  493. package/src/TopNav/TopNavMegaMenuItem.tsx +5 -2
  494. package/src/TopNav/TopNavMenu.tsx +10 -4
  495. package/src/TreeList/TreeListItem.tsx +22 -7
  496. package/src/Typeahead/BaseTypeahead.tsx +5 -2
  497. package/src/Typeahead/Typeahead.tsx +4 -1
  498. package/src/hooks/containerReveal.stylex.ts +54 -18
  499. package/src/hooks/scrollbarGutter.test.ts +167 -0
  500. package/src/hooks/scrollbarGutter.ts +121 -0
  501. package/src/hooks/useAutoMediaMode.test.ts +109 -0
  502. package/src/hooks/useAutoMediaMode.ts +233 -0
  503. package/src/hooks/useInputStatusIcon.tsx +4 -1
  504. package/src/hooks/useListFocus.doc.mjs +2 -2
  505. package/src/hooks/useListFocus.test.tsx +65 -3
  506. package/src/hooks/useListFocus.ts +15 -7
  507. package/src/hooks/useScrollLock.doc.mjs +4 -4
  508. package/src/hooks/useScrollLock.test.ts +73 -0
  509. package/src/hooks/useScrollLock.ts +14 -0
  510. package/src/i18n/InternationalizationContext.ts +2 -0
  511. package/src/i18n/__tests__/e2e-powersearch.test.tsx +37 -1
  512. package/src/i18n/__tests__/useCollator.test.tsx +115 -0
  513. package/src/i18n/__tests__/useLocale.test.tsx +52 -0
  514. package/src/i18n/index.ts +6 -0
  515. package/src/i18n/useCollator.doc.mjs +84 -0
  516. package/src/i18n/useCollator.ts +44 -0
  517. package/src/i18n/useLocale.doc.mjs +70 -0
  518. package/src/i18n/useLocale.ts +34 -0
  519. package/src/i18n/useTranslator.doc.mjs +1 -1
  520. package/src/reset.css +9 -2
  521. package/src/reset.test.ts +22 -0
  522. package/src/theme/MediaTheme.doc.mjs +23 -4
  523. package/src/theme/MediaTheme.dom.test.tsx +97 -0
  524. package/src/theme/MediaTheme.tsx +42 -7
  525. package/src/theme/defineTheme.test.ts +9 -3
  526. package/src/theme/defineTheme.ts +5 -0
  527. package/src/theme/derivedVarRegistry.test.ts +19 -5
  528. package/src/theme/derivedVarRegistry.ts +4 -0
  529. package/src/theme/generateThemeRules.test.ts +118 -0
  530. package/src/theme/generateThemeRules.ts +83 -5
  531. package/src/theme/index.ts +1 -1
  532. package/src/theme/syntax/index.ts +6 -2
  533. package/src/theme/syntax/serverSafeSyntax.test.ts +68 -0
  534. package/src/utils/dateParser.test.ts +20 -0
  535. package/src/utils/dateParser.ts +14 -7
  536. package/src/utils/index.ts +2 -0
  537. package/src/utils/plainDate.test.ts +6 -0
  538. package/src/utils/plainDate.ts +21 -4
@@ -50,12 +50,17 @@ import {mergeRefs} from '../utils';
50
50
  import {useSize} from '../SizeContext/SizeContext';
51
51
  import {useInternalConfig} from './useInternalConfig';
52
52
  import {usePowerSearchSource} from './usePowerSearchSource';
53
- import {formatFilterValue} from './formatFilterValue';
53
+ import {
54
+ formatFilterValue,
55
+ formatDateAbsoluteCompact,
56
+ } from './formatFilterValue';
54
57
  import {PowerSearchEditPopover} from './PowerSearchEditPopover';
55
58
  import {resolveOperatorLabel} from './resolveOperatorLabel';
56
59
  import {themeProps} from '../utils/themeProps';
57
60
  import {truncateCharacters} from '../utils/characters';
58
61
  import {useTranslator} from '../i18n';
62
+ import {useLocale} from '../i18n/useLocale';
63
+ import type {Locale} from '../i18n/types';
59
64
  import type {
60
65
  PowerSearchConfig,
61
66
  PowerSearchFilter,
@@ -131,10 +136,12 @@ function PowerSearchTokenValue({
131
136
  operatorValue,
132
137
  filterValue,
133
138
  maxLength,
139
+ locale,
134
140
  }: {
135
141
  operatorValue: OperatorValue;
136
142
  filterValue: FilterValue;
137
143
  maxLength: number;
144
+ locale: Locale;
138
145
  }) {
139
146
  switch (filterValue.type) {
140
147
  case 'empty':
@@ -276,12 +283,10 @@ function PowerSearchTokenValue({
276
283
  );
277
284
 
278
285
  case 'date_absolute': {
279
- const date = new Date(filterValue.unixSeconds * 1000);
280
- const formatted = new Intl.DateTimeFormat(undefined, {
281
- year: 'numeric',
282
- month: 'short',
283
- day: 'numeric',
284
- }).format(date);
286
+ const formatted = formatDateAbsoluteCompact(
287
+ filterValue.unixSeconds,
288
+ locale,
289
+ );
285
290
  return (
286
291
  <span {...stylex.props(tokenValueStyles.value)}>
287
292
  {truncateString(formatted, maxLength)}
@@ -556,6 +561,7 @@ export function PowerSearch({
556
561
  const config = useInternalConfig(configProp);
557
562
  const searchSource = usePowerSearchSource(config);
558
563
  const t = useTranslator();
564
+ const locale = useLocale();
559
565
  const label = labelFromProps ?? t('@astryx.powersearch.label');
560
566
  const placeholder =
561
567
  placeholderFromProps ?? t('@astryx.powersearch.placeholder');
@@ -625,6 +631,7 @@ export function PowerSearch({
625
631
  filter.value,
626
632
  maxTokenLength,
627
633
  t,
634
+ locale,
628
635
  timezoneID,
629
636
  )
630
637
  : '';
@@ -644,7 +651,7 @@ export function PowerSearch({
644
651
  },
645
652
  };
646
653
  });
647
- }, [filters, config, maxTokenLength, timezoneID, t]);
654
+ }, [filters, config, maxTokenLength, timezoneID, t, locale]);
648
655
 
649
656
  // Handle tokenizer onChange (field selected from typeahead)
650
657
  const handleTokenizerChange = useCallback(
@@ -820,6 +827,7 @@ export function PowerSearch({
820
827
  operatorValue={operator.value}
821
828
  filterValue={filter.value}
822
829
  maxLength={adjustedMaxLength}
830
+ locale={locale}
823
831
  />
824
832
  ) : undefined;
825
833
 
@@ -858,6 +866,7 @@ export function PowerSearch({
858
866
  config,
859
867
  configProp,
860
868
  maxTokenLength,
869
+ locale,
861
870
  size,
862
871
  isReadOnly,
863
872
  isDisabled,
@@ -13,6 +13,7 @@ import React from 'react';
13
13
  import * as stylex from '@stylexjs/stylex';
14
14
  import {Token} from '../Token';
15
15
  import {useTranslator} from '../i18n';
16
+ import {useLocale} from '../i18n/useLocale';
16
17
  import {fontWeightVars} from '../theme/tokens.stylex';
17
18
  import {formatFilterValue} from './formatFilterValue';
18
19
  import {resolveOperatorLabel} from './resolveOperatorLabel';
@@ -44,6 +45,7 @@ export function PowerSearchToken({
44
45
  }: PowerSearchTokenProps) {
45
46
  const config = useInternalConfig(configProp);
46
47
  const t = useTranslator();
48
+ const locale = useLocale();
47
49
 
48
50
  const fieldLabel = field.label;
49
51
  const resolvedOperatorLabel = resolveOperatorLabel(operator, t);
@@ -63,6 +65,7 @@ export function PowerSearchToken({
63
65
  filter.value,
64
66
  adjustedMaxLength,
65
67
  t,
68
+ locale,
66
69
  );
67
70
 
68
71
  const valueContent = valueStr ? (
@@ -31,7 +31,15 @@ const fmt = (
31
31
  maxLength = 20,
32
32
  timezoneID?: string,
33
33
  ): string =>
34
- formatFilterValue({} as never, operator, value, maxLength, t, timezoneID);
34
+ formatFilterValue(
35
+ {} as never,
36
+ operator,
37
+ value,
38
+ maxLength,
39
+ t,
40
+ 'en-US',
41
+ timezoneID,
42
+ );
35
43
 
36
44
  const ELLIPSIS = '…';
37
45
 
@@ -87,8 +95,20 @@ describe('formatFilterValue', () => {
87
95
  });
88
96
 
89
97
  describe('integer / float', () => {
98
+ it('formats the same number differently when the locale changes', () => {
99
+ const args = [
100
+ {} as never,
101
+ {type: 'float'} as OperatorValue,
102
+ {type: 'float', value: 1234.5} as FilterValue,
103
+ 40,
104
+ t,
105
+ ] as const;
106
+ expect(formatFilterValue(...args, 'en-US')).toBe('1,234.5');
107
+ expect(formatFilterValue(...args, 'de-DE')).toBe('1.234,5');
108
+ });
109
+
90
110
  it('formats an integer with locale grouping', () => {
91
- const expected = new Intl.NumberFormat().format(1234567);
111
+ const expected = new Intl.NumberFormat('en-US').format(1234567);
92
112
  expect(
93
113
  fmt({type: 'integer'}, {type: 'integer', value: 1234567}, 40),
94
114
  ).toBe(expected);
@@ -12,7 +12,7 @@
12
12
 
13
13
  import type {OperatorValue, FilterValue, EnumItem} from './types';
14
14
  import type {InternalConfig} from './useInternalConfig';
15
- import type {TranslatorFn} from '../i18n';
15
+ import type {Locale, TranslatorFn} from '../i18n';
16
16
  import {truncateCharacters} from '../utils/characters';
17
17
 
18
18
  function truncate(str: string, maxLength: number): string {
@@ -27,12 +27,16 @@ function formatEnumLabel(
27
27
  return item?.label ?? value;
28
28
  }
29
29
 
30
- function formatNumber(value: number, units?: string): string {
31
- const formatted = new Intl.NumberFormat().format(value);
30
+ function formatNumber(value: number, locale: Locale, units?: string): string {
31
+ const formatted = new Intl.NumberFormat(locale).format(value);
32
32
  return units ? `${formatted} ${units}` : formatted;
33
33
  }
34
34
 
35
- function formatDateAbsolute(unixSeconds: number, timezoneID?: string): string {
35
+ export function formatDateAbsolute(
36
+ unixSeconds: number,
37
+ locale: Locale,
38
+ timezoneID?: string,
39
+ ): string {
36
40
  const options: Intl.DateTimeFormatOptions = {
37
41
  year: 'numeric',
38
42
  month: 'short',
@@ -41,7 +45,25 @@ function formatDateAbsolute(unixSeconds: number, timezoneID?: string): string {
41
45
  minute: '2-digit',
42
46
  ...(timezoneID ? {timeZone: timezoneID} : {}),
43
47
  };
44
- return new Intl.DateTimeFormat(undefined, options).format(unixSeconds * 1000);
48
+ return new Intl.DateTimeFormat(locale, options).format(unixSeconds * 1000);
49
+ }
50
+
51
+ /**
52
+ * Compact date-only rendering (no time-of-day) for the token pill's inline
53
+ * value display, which has less room than the editor's full summary. Kept
54
+ * separate from {@link formatDateAbsolute} rather than reusing it with
55
+ * different options threaded through a param, since the two callers want
56
+ * genuinely different shapes, not a parameterization of the same one.
57
+ */
58
+ export function formatDateAbsoluteCompact(
59
+ unixSeconds: number,
60
+ locale: Locale,
61
+ ): string {
62
+ return new Intl.DateTimeFormat(locale, {
63
+ year: 'numeric',
64
+ month: 'short',
65
+ day: 'numeric',
66
+ }).format(unixSeconds * 1000);
45
67
  }
46
68
 
47
69
  function formatRelativeDate(value: string): string {
@@ -62,6 +84,7 @@ export function formatFilterValue(
62
84
  filterValue: FilterValue,
63
85
  maxLength: number,
64
86
  t: TranslatorFn,
87
+ locale: Locale,
65
88
  timezoneID?: string,
66
89
  ): string {
67
90
  switch (filterValue.type) {
@@ -74,12 +97,14 @@ export function formatFilterValue(
74
97
  case 'integer':
75
98
  return formatNumber(
76
99
  filterValue.value,
100
+ locale,
77
101
  operatorValue.type === 'integer' ? operatorValue.units : undefined,
78
102
  );
79
103
 
80
104
  case 'float':
81
105
  return formatNumber(
82
106
  filterValue.value,
107
+ locale,
83
108
  operatorValue.type === 'float' ? operatorValue.units : undefined,
84
109
  );
85
110
 
@@ -157,7 +182,7 @@ export function formatFilterValue(
157
182
 
158
183
  case 'date_absolute':
159
184
  return truncate(
160
- formatDateAbsolute(filterValue.unixSeconds, timezoneID),
185
+ formatDateAbsolute(filterValue.unixSeconds, locale, timezoneID),
161
186
  maxLength,
162
187
  );
163
188
 
@@ -11,7 +11,7 @@ export const docs = {
11
11
  theming: {
12
12
  targets: [
13
13
  {className: 'astryx-radio-list', visualProps: ['orientation', 'size']},
14
- {className: 'astryx-radio-list-item'},
14
+ {className: 'astryx-radio-list-item', visualProps: ['size'], states: ['selected', 'disabled']},
15
15
  {className: 'astryx-radio-indicator', visualProps: ['size'], states: ['checked', 'disabled']},
16
16
  {className: 'astryx-radio-indicator-dot', visualProps: ['size']},
17
17
  {className: 'astryx-radio', visualProps: ['size'], states: ['checked', 'disabled'], deprecatedFor: 'radio-indicator'},
@@ -116,6 +116,22 @@ describe('RadioList', () => {
116
116
  expect(handleChange).toHaveBeenCalledWith('b');
117
117
  });
118
118
 
119
+ it('calls onChange when clicking the description', async () => {
120
+ const user = userEvent.setup();
121
+ const handleChange = vi.fn();
122
+ render(
123
+ <RadioList label="Preference" value="a" onChange={handleChange}>
124
+ <RadioListItem label="Option A" value="a" description="First option" />
125
+ <RadioListItem label="Option B" value="b" description="Second option" />
126
+ </RadioList>,
127
+ );
128
+
129
+ // The whole row delegates surface clicks to the radio, so the description
130
+ // is a live target — not dead space as it was before.
131
+ await user.click(screen.getByText('Second option'));
132
+ expect(handleChange).toHaveBeenCalledWith('b');
133
+ });
134
+
119
135
  it('disables all radios when group isDisabled is true', () => {
120
136
  render(
121
137
  <RadioList label="Preference" value="" onChange={() => {}} isDisabled>
@@ -137,7 +153,13 @@ describe('RadioList', () => {
137
153
  </RadioList>,
138
154
  );
139
155
 
140
- await user.click(screen.getByLabelText('Option A'));
156
+ // userEvent honors `pointer-events: none`, so clicking the disabled row's
157
+ // delegate surface is genuinely blocked (it refuses and throws) rather than
158
+ // merely ignored by the handler — the guarantee this PR's delegation relies
159
+ // on.
160
+ await expect(user.click(screen.getByLabelText('Option A'))).rejects.toThrow(
161
+ /pointer-events/i,
162
+ );
141
163
  expect(handleChange).not.toHaveBeenCalled();
142
164
  });
143
165
 
@@ -162,7 +184,13 @@ describe('RadioList', () => {
162
184
  </RadioList>,
163
185
  );
164
186
 
165
- await user.click(screen.getByLabelText('Option A'));
187
+ // userEvent honors `pointer-events: none`, so clicking the disabled row's
188
+ // delegate surface is genuinely blocked (it refuses and throws) rather than
189
+ // merely ignored by the handler — the guarantee this PR's delegation relies
190
+ // on.
191
+ await expect(user.click(screen.getByLabelText('Option A'))).rejects.toThrow(
192
+ /pointer-events/i,
193
+ );
166
194
  expect(handleChange).not.toHaveBeenCalled();
167
195
  });
168
196
 
@@ -647,6 +675,146 @@ describe('RadioList', () => {
647
675
  expect(item).toHaveAttribute('aria-label', 'First option');
648
676
  });
649
677
  });
678
+
679
+ describe('radio-list-item theme target', () => {
680
+ it('renders astryx-radio-list-item, with its size, on every row', () => {
681
+ render(
682
+ <RadioList label="Preference" value="" onChange={() => {}} size="sm">
683
+ <RadioListItem label="Option A" value="a" data-testid="row-a" />
684
+ <RadioListItem label="Option B" value="b" data-testid="row-b" />
685
+ </RadioList>,
686
+ );
687
+ for (const testid of ['row-a', 'row-b']) {
688
+ const row = screen.getByTestId(testid);
689
+ expect(row).toHaveClass('astryx-radio-list-item');
690
+ expect(row).toHaveClass('sm');
691
+ expect(row).toHaveAttribute('data-size', 'sm');
692
+ }
693
+ });
694
+
695
+ it('carries the selected and disabled states a theme keys on', () => {
696
+ render(
697
+ <RadioList label="Preference" value="a" onChange={() => {}}>
698
+ <RadioListItem label="Option A" value="a" data-testid="selected" />
699
+ <RadioListItem label="Option B" value="b" data-testid="plain" />
700
+ <RadioListItem
701
+ label="Option C"
702
+ value="c"
703
+ isDisabled
704
+ data-testid="disabled"
705
+ />
706
+ </RadioList>,
707
+ );
708
+ const selected = screen.getByTestId('selected');
709
+ const plain = screen.getByTestId('plain');
710
+ const disabled = screen.getByTestId('disabled');
711
+
712
+ expect(selected).toHaveClass('selected');
713
+ expect(selected).toHaveAttribute('data-selected', 'selected');
714
+ expect(plain).not.toHaveClass('selected');
715
+ expect(plain).not.toHaveAttribute('data-selected');
716
+
717
+ expect(disabled).toHaveClass('disabled');
718
+ expect(disabled).toHaveAttribute('data-disabled', 'disabled');
719
+ expect(plain).not.toHaveAttribute('data-disabled');
720
+ });
721
+
722
+ it('rides the painting row element (astryx-item), not a bare layout wrapper', () => {
723
+ // The row target must sit on the element Item paints — the surface that
724
+ // renders hover, density padding, and radius — so a theme styling
725
+ // `radio-list-item`'s background/padding/borderRadius (and its `:hover`)
726
+ // actually takes effect. Converges with how ListItem lands `list-item`
727
+ // on the same element as `astryx-item`. The same element also carries
728
+ // the reflected `data-size`, proving the variant surface moved with it.
729
+ const {container} = render(
730
+ <RadioList label="Preference" value="" onChange={() => {}}>
731
+ <RadioListItem label="Option A" value="a" data-testid="row" />
732
+ </RadioList>,
733
+ );
734
+ const row = screen.getByTestId('row');
735
+ // A single element carries both the paint class and the theme target.
736
+ expect(row).toHaveClass('astryx-item');
737
+ expect(row).toHaveClass('astryx-radio-list-item');
738
+ expect(row).toHaveAttribute('data-size');
739
+ // No separate layout wrapper survives outside the painting row: the
740
+ // target-bearing element is the same one Item renders.
741
+ expect(
742
+ container.querySelectorAll('.astryx-radio-list-item'),
743
+ ).toHaveLength(1);
744
+ });
745
+
746
+ it('keeps the bare default row appearance: zeroed padding/radius, no default background', () => {
747
+ // The architectural win — the target rides the painting Item — must not
748
+ // change the DEFAULT look. The painting row zeroes Item's density
749
+ // padding, its radius, and its interactive hover/press background, so an
750
+ // unthemed RadioList renders as a flat surface (only the indicator tints
751
+ // on hover via `indicatorScope`). This matches the appearance before the
752
+ // target moved onto Item; a theme's `radio-list-item` overrides still win
753
+ // from the higher `astryx-theme` layer.
754
+ render(
755
+ <RadioList label="Preference" value="a" onChange={() => {}}>
756
+ <RadioListItem label="Selected" value="a" data-testid="selected" />
757
+ <RadioListItem label="Plain" value="b" data-testid="plain" />
758
+ </RadioList>,
759
+ );
760
+ const cssFor = (className: string): string => {
761
+ const rules: string[] = [];
762
+ const walk = (list: CSSRuleList) => {
763
+ for (const rule of Array.from(list)) {
764
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
765
+ const anyRule = rule as any;
766
+ if (anyRule.cssRules) {
767
+ walk(anyRule.cssRules);
768
+ }
769
+ if (
770
+ typeof anyRule.cssText === 'string' &&
771
+ anyRule.cssText.includes(`.${className}`)
772
+ ) {
773
+ rules.push(anyRule.cssText);
774
+ }
775
+ }
776
+ };
777
+ for (const sheet of Array.from(document.styleSheets)) {
778
+ try {
779
+ walk(sheet.cssRules);
780
+ } catch {
781
+ // cross-origin/inaccessible sheet — skip
782
+ }
783
+ }
784
+ return rules.join('\n');
785
+ };
786
+
787
+ const plain = screen.getByTestId('plain');
788
+ const atoms = plain.className
789
+ .split(/\s+/)
790
+ .filter(c => /^x[a-z0-9]+$/i.test(c));
791
+ const declarations = atoms.map(cssFor).join('\n');
792
+
793
+ // The bare-look declarations land on the painting row.
794
+ expect(declarations).toMatch(/padding-block:\s*0/);
795
+ expect(declarations).toMatch(/padding-inline:\s*0/);
796
+ expect(declarations).toMatch(/border-radius:\s*0/);
797
+ expect(declarations).toMatch(/background-color:\s*transparent/);
798
+
799
+ // No default full-row hover highlight: the flat transparent background
800
+ // replaces Item's interactive `:hover` overlay, so no hover rule paints
801
+ // the row's own background. (The indicator still tints via its scope.)
802
+ expect(declarations).not.toMatch(
803
+ /:hover[^{]*\{[^}]*background-color:\s*var\(--color-overlay-hover\)/,
804
+ );
805
+
806
+ // No default selected-row background: the selected row differs from the
807
+ // plain row only by state markers, not by a painted background class.
808
+ const selected = screen.getByTestId('selected');
809
+ const selectedAtoms = selected.className
810
+ .split(/\s+/)
811
+ .filter(c => /^x[a-z0-9]+$/i.test(c));
812
+ const selectedDecls = selectedAtoms.map(cssFor).join('\n');
813
+ expect(selectedDecls).not.toMatch(
814
+ /background-color:\s*var\(--color-accent-muted\)/,
815
+ );
816
+ });
817
+ });
650
818
  });
651
819
 
652
820
  // jsdom cannot emulate forced-colors rendering, so this asserts that the
@@ -4,7 +4,7 @@
4
4
 
5
5
  /**
6
6
  * @file RadioListItem.tsx
7
- * @input Uses React use, useId, RadioListContext
7
+ * @input Uses React use, useId, useRef, RadioListContext, Item
8
8
  * @output Exports RadioListItem component, RadioListItemProps
9
9
  * @position Core implementation; consumed by index.ts, tested by RadioList.test.tsx
10
10
  *
@@ -20,10 +20,10 @@
20
20
 
21
21
  import React, {use, useId, useRef, type ReactNode} from 'react';
22
22
  import * as stylex from '@stylexjs/stylex';
23
+ import type {StyleXStyles} from '@stylexjs/stylex';
23
24
  import type {BaseProps} from '../BaseProps';
24
- import {colorVars, spacingVars} from '../theme/tokens.stylex';
25
25
  import {RadioListContext} from './RadioList';
26
- import {mergeProps} from '../utils';
26
+ import {mergeProps, isRenderable} from '../utils';
27
27
  import {indicatorScope} from '../Indicator/indicator.markers.stylex';
28
28
  import {useIndicatorFocusRing} from '../hooks/useIndicatorFocusRing';
29
29
  import {useIndicator} from '../Indicator';
@@ -31,11 +31,6 @@ import {Item} from '../Item';
31
31
  import {themeProps} from '../utils/themeProps';
32
32
 
33
33
  const styles = stylex.create({
34
- container: {
35
- display: 'flex',
36
- alignItems: 'center',
37
- gap: spacingVars['--spacing-2'],
38
- },
39
34
  radioWrapper: {
40
35
  position: 'relative',
41
36
  display: 'flex',
@@ -49,7 +44,10 @@ const styles = stylex.create({
49
44
  margin: 0,
50
45
  padding: 0,
51
46
  opacity: 0,
52
- cursor: 'pointer',
47
+ cursor: {
48
+ default: 'pointer',
49
+ ':is(:disabled,[aria-disabled="true"])': 'default',
50
+ },
53
51
  zIndex: 1,
54
52
  minInlineSize: {
55
53
  default: null,
@@ -73,16 +71,12 @@ const styles = stylex.create({
73
71
  },
74
72
  },
75
73
  inputDisabled: {
76
- cursor: 'not-allowed',
74
+ cursor: 'default',
77
75
  },
78
76
  // Holds only the indicator, so the focus ring has one unambiguous target.
79
77
  indicatorSlot: {
80
78
  display: 'contents',
81
79
  },
82
- labelDisabled: {
83
- color: colorVars['--color-text-disabled'],
84
- cursor: 'not-allowed',
85
- },
86
80
  });
87
81
 
88
82
  const wrapperSizeStyles = stylex.create({
@@ -96,13 +90,23 @@ const wrapperSizeStyles = stylex.create({
96
90
  },
97
91
  });
98
92
 
99
- const embeddedStyles = stylex.create({
93
+ const rowStyles = stylex.create({
94
+ // The row's default appearance is a bare surface: no density padding, no
95
+ // radius, and no full-row background — only the indicator tints on hover
96
+ // (via `indicatorScope`). Item paints padding/radius/hover as an interactive
97
+ // row, so this neutralizes them at the component level. A theme's
98
+ // `radio-list-item` overrides still win: they land in `@layer astryx-theme`,
99
+ // above the component's base StyleX layer, so themes opt back into row
100
+ // padding/radius/hover/selected styling. `minWidth: 0` preserves label
101
+ // truncation now that the Item is the row's flex child.
100
102
  root: {
101
103
  paddingBlock: 0,
102
104
  paddingInline: 0,
103
105
  borderRadius: 0,
104
- flex: 1,
105
106
  minWidth: 0,
107
+ // Suppress Item's interactive hover/press background so the resting and
108
+ // hovered row look identical by default (a theme can restyle either).
109
+ backgroundColor: 'transparent',
106
110
  },
107
111
  });
108
112
 
@@ -159,6 +163,7 @@ export function RadioListItem({
159
163
  xstyle,
160
164
  className,
161
165
  style,
166
+ onClick,
162
167
  ...rest
163
168
  }: RadioListItemProps) {
164
169
  const context = use(RadioListContext);
@@ -185,16 +190,28 @@ export function RadioListItem({
185
190
  const indicatorRef = useRef<HTMLSpanElement>(null);
186
191
  const {focusProps} = useIndicatorFocusRing(indicatorRef, isDisabled);
187
192
 
193
+ // The radio is the row's single keyboard control and action. The row is an
194
+ // enlarged click/tap target that delegates surface clicks — the description
195
+ // and the empty hover area, not just the control and its label — to the
196
+ // input via Item's `interactiveRef` (useClickableContainer). This matches
197
+ // CheckboxListItem so the whole row is clickable, and keeps one tab stop per
198
+ // option (WCAG 4.1.2). The radio carries its accessible name via `aria-label`
199
+ // since the visible label is now a plain (non-`<label>`) text node — a real
200
+ // `<label htmlFor>` would double-fire under delegation.
201
+ const radioRef = useRef<HTMLInputElement>(null);
202
+
188
203
  const radioCircle = (
189
204
  <div
190
205
  {...stylex.props(styles.radioWrapper, wrapperSizeStyles[size])}
191
206
  {...focusProps}>
192
207
  <input
208
+ ref={radioRef}
193
209
  id={id}
194
210
  type="radio"
195
211
  name={context.name}
196
212
  value={value}
197
213
  checked={isChecked}
214
+ aria-label={label}
198
215
  disabled={isDisabled && !keepsFocusableForMessage}
199
216
  aria-disabled={keepsFocusableForMessage ? 'true' : undefined}
200
217
  // A focusable-disabled radio is not natively disabled, so detach it
@@ -208,6 +225,10 @@ export function RadioListItem({
208
225
  }
209
226
  context.onChange(value);
210
227
  }}
228
+ // A consumer onClick rides on the radio input itself, so it fires for
229
+ // both direct control clicks and row-surface clicks the row delegates
230
+ // to the input — the same routing CheckboxListItem uses.
231
+ onClick={onClick}
211
232
  aria-describedby={description ? descriptionID : undefined}
212
233
  {...stylex.props(
213
234
  styles.input,
@@ -225,50 +246,64 @@ export function RadioListItem({
225
246
  </div>
226
247
  );
227
248
 
228
- const mediaContent =
229
- startContent != null ? (
230
- <>
231
- {radioCircle}
232
- {startContent}
233
- </>
234
- ) : (
235
- radioCircle
236
- );
249
+ const mediaContent = isRenderable(startContent) ? (
250
+ <>
251
+ {radioCircle}
252
+ {startContent}
253
+ </>
254
+ ) : (
255
+ radioCircle
256
+ );
237
257
 
238
258
  return (
239
- <div
259
+ <Item
240
260
  ref={ref}
241
- {...mergeProps(
242
- themeProps('radio-list-item'),
243
- stylex.props(
244
- styles.container,
261
+ startContent={mediaContent}
262
+ // Delegate row-surface clicks (label text, description, and the empty
263
+ // hover area) to the radio input. The input stays the option's sole
264
+ // focusable control, so the row adds no second tab stop.
265
+ interactiveRef={radioRef}
266
+ isDisabled={isDisabled}
267
+ label={<span>{label}</span>}
268
+ description={
269
+ isRenderable(description) ? (
270
+ <span id={descriptionID}>{description}</span>
271
+ ) : undefined
272
+ }
273
+ endContent={endContent}
274
+ xstyle={
275
+ [
245
276
  // Hover reaches the radio visual through this ancestor marker rather
246
- // than props, so hovering the row tints the control.
277
+ // than props, so hovering the row tints the control. The marker rides
278
+ // the painting row element (Item), the same element that carries the
279
+ // theme target, so a theme's hover styling stays in step with the tint.
247
280
  !isDisabled && indicatorScope,
281
+ // Restore the bare default look: zero Item's padding/radius and its
282
+ // interactive hover/press background. Applied after Item's own base
283
+ // styles so it wins within the base layer; a `radio-list-item` theme
284
+ // still overrides it from the higher `astryx-theme` layer.
285
+ rowStyles.root,
248
286
  xstyle,
249
- ),
250
- className,
251
- style,
287
+ ] as StyleXStyles
288
+ }
289
+ {...mergeProps(
290
+ // One target for every row, carrying its size and runtime state so a
291
+ // theme can express "selected option at large" or restyle disabled
292
+ // rows without reaching for structural selectors. It lands on the
293
+ // element Item paints — the row surface — so a theme styling
294
+ // `radio-list-item`'s background/padding/borderRadius (and its
295
+ // `:hover`) actually takes effect from the `astryx-theme` layer, even
296
+ // though the component zeroes those by default. Converges with how
297
+ // ListItem lands `list-item` on the same element as `astryx-item`.
298
+ themeProps('radio-list-item', {
299
+ size,
300
+ selected: isChecked ? 'selected' : null,
301
+ disabled: isDisabled ? 'disabled' : null,
302
+ }),
303
+ {className, style},
252
304
  )}
253
- {...rest}>
254
- <Item
255
- startContent={mediaContent}
256
- label={
257
- <label
258
- htmlFor={id}
259
- {...stylex.props(isDisabled && styles.labelDisabled)}>
260
- {label}
261
- </label>
262
- }
263
- description={
264
- description != null ? (
265
- <span id={descriptionID}>{description}</span>
266
- ) : undefined
267
- }
268
- endContent={endContent}
269
- xstyle={embeddedStyles.root}
270
- />
271
- </div>
305
+ {...rest}
306
+ />
272
307
  );
273
308
  }
274
309