@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
@@ -27,10 +27,18 @@ export const docs = {
27
27
  states: ['disabled'],
28
28
  },
29
29
  {className: 'astryx-selector-option'},
30
+ {
31
+ className: 'astryx-selector-option-row',
32
+ visualProps: ['size'],
33
+ states: ['selected', 'disabled'],
34
+ },
30
35
  {className: 'astryx-selector-search'},
31
36
  {className: 'astryx-selector-section-heading'},
32
37
  {className: 'astryx-selector-empty-state'},
33
- {className: 'astryx-selector-clear-icon', deprecatedFor: 'input-clear-icon'},
38
+ {
39
+ className: 'astryx-selector-clear-icon',
40
+ deprecatedFor: 'input-clear-icon',
41
+ },
34
42
  {className: 'astryx-selector-indicator-icon', states: ['state']},
35
43
  {className: 'astryx-selector-check'},
36
44
  {className: 'astryx-selector-popup'},
@@ -48,7 +56,7 @@ export const docs = {
48
56
  name: 'options',
49
57
  type: 'SelectorOption[]',
50
58
  description:
51
- 'Array of items: strings, objects with value/label/icon/disabled, dividers ({type: "divider"}), or sections ({type: "section", title, items}).',
59
+ 'Array of items: strings, objects with value/label/description/icon/disabled, dividers ({type: "divider"}), or sections ({type: "section", title, items}).',
52
60
  required: true,
53
61
  },
54
62
  {
@@ -159,6 +167,12 @@ export const docs = {
159
167
  description:
160
168
  'Custom render function for each selectable option in the dropdown. Use this instead of JSX children; dividers and sections are rendered by the selector.',
161
169
  },
170
+ {
171
+ name: 'renderValue',
172
+ type: '(option: SelectorOptionData) => ReactNode',
173
+ description:
174
+ 'Custom render function for the selected option inside the closed trigger. The trigger is sized by padding, so it is the size token for a one-line value (28/32/36) and exactly one text line taller for a two-line one (48/52/56) — always on the 4px rhythm, always aligned with the buttons and inputs beside it. Inside an InputGroup the group owns the row height: a SelectorOption folds onto one line and ellipsizes, and any taller node is cut off at the row.',
175
+ },
162
176
  {
163
177
  name: 'indicatorPosition',
164
178
  type: "'start' | 'end'",
@@ -19,8 +19,11 @@ import {
19
19
  } from '@testing-library/react';
20
20
  import userEvent from '@testing-library/user-event';
21
21
  import {useState} from 'react';
22
+ import type {ReactNode} from 'react';
22
23
  import {Selector} from './Selector';
23
24
  import {SelectorOption} from './SelectorOption';
25
+ import {Item} from '../Item';
26
+ import type {SelectorOptionData} from './types';
24
27
  import {Icon} from '../Icon';
25
28
  import {RadioIndicator} from '../Indicator';
26
29
  import {InputGroup, InputGroupText} from '../InputGroup';
@@ -2337,7 +2340,7 @@ describe('Selector clear icon theme target', () => {
2337
2340
  expect(css).toContain('.astryx-selector-clear-icon {');
2338
2341
  expect(css).toContain('width: 12px');
2339
2342
  expect(css).toContain('height: 12px');
2340
- expect(css).toContain('.astryx-selector-clear-icon:hover {');
2343
+ expect(css).toContain('.astryx-selector-clear-icon:hover');
2341
2344
  expect(css).toContain('color: var(--color-icon-primary)');
2342
2345
  });
2343
2346
  });
@@ -2993,3 +2996,524 @@ describe('Selector popup theme target', () => {
2993
2996
  },
2994
2997
  );
2995
2998
  });
2999
+
3000
+ describe('Selector option-row theme target', () => {
3001
+ const ROW_OPTIONS = ['Apple', 'Banana', 'Orange'];
3002
+
3003
+ it('renders astryx-selector-option-row, with its size, on every dropdown row', async () => {
3004
+ const user = userEvent.setup();
3005
+ render(
3006
+ <Selector
3007
+ label="Fruit"
3008
+ options={ROW_OPTIONS}
3009
+ value=""
3010
+ onChange={() => {}}
3011
+ size="lg"
3012
+ />,
3013
+ );
3014
+ await user.click(screen.getByRole('combobox'));
3015
+ const options = screen.getAllByRole('option', h);
3016
+ expect(options).toHaveLength(3);
3017
+ for (const option of options) {
3018
+ expect(option).toHaveClass('astryx-selector-option-row');
3019
+ expect(option).toHaveClass('lg');
3020
+ expect(option).toHaveAttribute('data-size', 'lg');
3021
+ }
3022
+ });
3023
+
3024
+ it('reflects the selected state on the row target', async () => {
3025
+ const user = userEvent.setup();
3026
+ render(
3027
+ <Selector
3028
+ label="Fruit"
3029
+ options={ROW_OPTIONS}
3030
+ value="Banana"
3031
+ onChange={() => {}}
3032
+ />,
3033
+ );
3034
+ await user.click(screen.getByRole('combobox'));
3035
+ const selected = screen.getByRole('option', {name: 'Banana', ...h});
3036
+ expect(selected).toHaveClass('astryx-selector-option-row');
3037
+ expect(selected).toHaveAttribute('data-selected', 'selected');
3038
+ });
3039
+
3040
+ it('leaves the state attributes off an unselected, enabled row', async () => {
3041
+ const user = userEvent.setup();
3042
+ render(
3043
+ <Selector
3044
+ label="Fruit"
3045
+ options={ROW_OPTIONS}
3046
+ value="Banana"
3047
+ onChange={() => {}}
3048
+ />,
3049
+ );
3050
+ await user.click(screen.getByRole('combobox'));
3051
+ const plain = screen.getByRole('option', {name: 'Apple', ...h});
3052
+ expect(plain).toHaveClass('astryx-selector-option-row');
3053
+ // themeProps emits the data-* only when the state is truthy, so a theme's
3054
+ // `.selected` / `.disabled` rules never touch a plain row.
3055
+ expect(plain).not.toHaveAttribute('data-selected');
3056
+ expect(plain).not.toHaveAttribute('data-disabled');
3057
+ });
3058
+
3059
+ it('reflects the disabled state on the row target', async () => {
3060
+ const user = userEvent.setup();
3061
+ render(
3062
+ <Selector
3063
+ label="Fruit"
3064
+ options={[{value: 'Apple', disabled: true}, 'Banana']}
3065
+ value=""
3066
+ onChange={() => {}}
3067
+ />,
3068
+ );
3069
+ await user.click(screen.getByRole('combobox'));
3070
+ const disabled = screen.getByRole('option', {name: 'Apple', ...h});
3071
+ expect(disabled).toHaveClass('astryx-selector-option-row');
3072
+ expect(disabled).toHaveAttribute('data-disabled', 'disabled');
3073
+ });
3074
+
3075
+ it('keeps the row target when renderOption replaces the content', async () => {
3076
+ const user = userEvent.setup();
3077
+ render(
3078
+ <Selector
3079
+ label="Fruit"
3080
+ options={ROW_OPTIONS}
3081
+ value=""
3082
+ onChange={() => {}}
3083
+ renderOption={option => (
3084
+ <span data-testid="custom-row">{option.label ?? option.value}</span>
3085
+ )}
3086
+ />,
3087
+ );
3088
+ await user.click(screen.getByRole('combobox'));
3089
+ const option = screen.getAllByRole('option', h)[0];
3090
+ // The row owns the padding/density, so custom content is inset the same as
3091
+ // the default row — one row override reaches both.
3092
+ expect(option).toHaveClass('astryx-selector-option-row');
3093
+ expect(within(option).getByTestId('custom-row')).toHaveTextContent('Apple');
3094
+ });
3095
+
3096
+ it('exposes the row target, its states and its size to defineTheme', () => {
3097
+ // jsdom cannot resolve the @layer cascade, so the generated CSS is what
3098
+ // proves a theme can reach the row (padding, state, per-size density).
3099
+ const theme = defineTheme({
3100
+ name: 'selector-option-row-target-test',
3101
+ components: {
3102
+ 'selector-option-row': {
3103
+ base: {padding: 'var(--spacing-2)', borderRadius: '8px'},
3104
+ selected: {backgroundColor: 'var(--color-background-muted)'},
3105
+ disabled: {opacity: '0.5'},
3106
+ 'size:md': {padding: 'var(--spacing-2)'},
3107
+ },
3108
+ },
3109
+ });
3110
+ const css = generateThemeTestCSS(theme);
3111
+ expect(css).toContain('.astryx-selector-option-row {');
3112
+ expect(css).toContain('.astryx-selector-option-row.selected');
3113
+ expect(css).toContain('.astryx-selector-option-row.disabled');
3114
+ expect(css).toContain('.astryx-selector-option-row.md');
3115
+ });
3116
+ });
3117
+
3118
+ describe('Selector option descriptions and trigger value', () => {
3119
+ const LOCK = <span data-testid="lock-glyph" />;
3120
+ const GLOBE = <span data-testid="globe-glyph" />;
3121
+ const VISIBILITY = [
3122
+ {
3123
+ value: 'private',
3124
+ label: 'Private',
3125
+ icon: LOCK,
3126
+ description: 'Only members can access this space.',
3127
+ },
3128
+ {
3129
+ value: 'public',
3130
+ label: 'Public',
3131
+ icon: GLOBE,
3132
+ description: 'Anyone at the company can join.',
3133
+ },
3134
+ ];
3135
+
3136
+ it('renders an option description in the dropdown row', () => {
3137
+ render(
3138
+ <Selector
3139
+ label="Visibility"
3140
+ options={VISIBILITY}
3141
+ value="private"
3142
+ onChange={() => {}}
3143
+ isDefaultOpen
3144
+ />,
3145
+ );
3146
+
3147
+ const [row] = screen.getAllByRole('option', {hidden: true});
3148
+ expect(row).toHaveTextContent('Private');
3149
+ expect(row).toHaveTextContent('Only members can access this space.');
3150
+ });
3151
+
3152
+ it('keeps the description out of the closed trigger by default', () => {
3153
+ render(
3154
+ <Selector
3155
+ label="Visibility"
3156
+ options={VISIBILITY}
3157
+ value="private"
3158
+ onChange={() => {}}
3159
+ />,
3160
+ );
3161
+
3162
+ const trigger = screen.getByRole('combobox');
3163
+ expect(trigger).toHaveTextContent('Private');
3164
+ expect(trigger).not.toHaveTextContent(
3165
+ 'Only members can access this space.',
3166
+ );
3167
+ });
3168
+
3169
+ it("renders the selected option's icon in the closed trigger", () => {
3170
+ render(
3171
+ <Selector
3172
+ label="Visibility"
3173
+ options={VISIBILITY}
3174
+ value="private"
3175
+ onChange={() => {}}
3176
+ />,
3177
+ );
3178
+
3179
+ const trigger = screen.getByRole('combobox');
3180
+ expect(within(trigger).getByTestId('lock-glyph')).toBeInTheDocument();
3181
+ expect(
3182
+ within(trigger).queryByTestId('globe-glyph'),
3183
+ ).not.toBeInTheDocument();
3184
+ });
3185
+
3186
+ it('renders no option icon while showing the placeholder', () => {
3187
+ render(
3188
+ <Selector
3189
+ label="Visibility"
3190
+ options={VISIBILITY}
3191
+ value={undefined}
3192
+ onChange={() => {}}
3193
+ placeholder="Choose..."
3194
+ />,
3195
+ );
3196
+
3197
+ const trigger = screen.getByRole('combobox');
3198
+ expect(trigger).toHaveTextContent('Choose...');
3199
+ expect(within(trigger).queryByTestId('lock-glyph')).not.toBeInTheDocument();
3200
+ });
3201
+
3202
+ it('lets startIcon win over the selected option icon', () => {
3203
+ render(
3204
+ <Selector
3205
+ label="Visibility"
3206
+ options={VISIBILITY}
3207
+ value="private"
3208
+ onChange={() => {}}
3209
+ startIcon={<span data-testid="pinned-icon" />}
3210
+ />,
3211
+ );
3212
+
3213
+ // One leading glyph in the trigger, not two.
3214
+ expect(screen.getByTestId('pinned-icon')).toBeInTheDocument();
3215
+ expect(
3216
+ within(screen.getByRole('combobox')).queryByTestId('lock-glyph'),
3217
+ ).not.toBeInTheDocument();
3218
+ });
3219
+
3220
+ it('renders the selected option through renderValue', () => {
3221
+ render(
3222
+ <Selector
3223
+ label="Visibility"
3224
+ options={VISIBILITY}
3225
+ value="private"
3226
+ onChange={() => {}}
3227
+ renderValue={option => (
3228
+ <SelectorOption
3229
+ icon={option.icon}
3230
+ label={option.label ?? option.value}
3231
+ description={option.description}
3232
+ />
3233
+ )}
3234
+ />,
3235
+ );
3236
+
3237
+ const trigger = screen.getByRole('combobox');
3238
+ expect(trigger).toHaveTextContent('Private');
3239
+ expect(trigger).toHaveTextContent('Only members can access this space.');
3240
+ expect(within(trigger).getByTestId('lock-glyph')).toBeInTheDocument();
3241
+ });
3242
+
3243
+ it('sizes the trigger from what renderValue draws, not from it being passed', () => {
3244
+ // The regression this guards: keying the height off `renderValue != null`
3245
+ // handed a one-line custom value a taller control than the same value in
3246
+ // the default trigger, so `size` quietly stopped meaning its token. The
3247
+ // trigger carries one set of sizing classes for every case — a one-line
3248
+ // value measures the token, and only a second line of content adds a
3249
+ // second line of height.
3250
+ const triggerSizing = () =>
3251
+ new Set(
3252
+ (screen.getByRole('combobox').parentElement?.className ?? '')
3253
+ .split(' ')
3254
+ .filter(Boolean),
3255
+ );
3256
+
3257
+ const plain = render(
3258
+ <Selector
3259
+ label="Visibility"
3260
+ options={VISIBILITY}
3261
+ value="private"
3262
+ onChange={() => {}}
3263
+ />,
3264
+ );
3265
+ const defaultSizing = triggerSizing();
3266
+ plain.unmount();
3267
+
3268
+ const oneLine = render(
3269
+ <Selector
3270
+ label="Visibility"
3271
+ options={VISIBILITY}
3272
+ value="private"
3273
+ onChange={() => {}}
3274
+ renderValue={option => <span>{option.label}</span>}
3275
+ />,
3276
+ );
3277
+ expect(triggerSizing()).toEqual(defaultSizing);
3278
+ oneLine.unmount();
3279
+
3280
+ render(
3281
+ <Selector
3282
+ label="Visibility"
3283
+ options={VISIBILITY}
3284
+ value="private"
3285
+ onChange={() => {}}
3286
+ renderValue={option => (
3287
+ <SelectorOption
3288
+ icon={option.icon}
3289
+ label={option.label ?? option.value}
3290
+ description={option.description}
3291
+ />
3292
+ )}
3293
+ />,
3294
+ );
3295
+ expect(triggerSizing()).toEqual(defaultSizing);
3296
+ });
3297
+
3298
+ it("follows the caller's SelectorOption layout, but folds inline in a group", () => {
3299
+ // The trigger has no layout prop: the SelectorOption the caller renders
3300
+ // decides, and the trigger's padding sizes it to whatever that draws. The
3301
+ // one exception is an InputGroup, which pins the row height — the value
3302
+ // box is clamped to it, so a stacked row would lose its second line at the
3303
+ // cut. Folding inline keeps the description visible instead.
3304
+ const renderValue = (option: SelectorOptionData) => (
3305
+ <SelectorOption
3306
+ icon={option.icon}
3307
+ label={option.label ?? option.value}
3308
+ description={option.description}
3309
+ />
3310
+ );
3311
+ const classesOf = (label: HTMLElement) =>
3312
+ new Set((label.parentElement?.className ?? '').split(' '));
3313
+ const triggerClasses = () =>
3314
+ classesOf(within(screen.getByRole('combobox')).getByText('Private'));
3315
+
3316
+ const stackedRef = render(<Item label="Private" description="Why" />);
3317
+ const stackedClasses = classesOf(screen.getByText('Private'));
3318
+ stackedRef.unmount();
3319
+
3320
+ const inlineRef = render(
3321
+ <Item label="Private" description="Why" layout="inline" />,
3322
+ );
3323
+ const inlineOnly = [...classesOf(screen.getByText('Private'))].filter(
3324
+ c => c !== '' && !stackedClasses.has(c),
3325
+ );
3326
+ inlineRef.unmount();
3327
+ expect(inlineOnly.length).toBeGreaterThan(0);
3328
+
3329
+ const standalone = render(
3330
+ <Selector
3331
+ label="Visibility"
3332
+ options={VISIBILITY}
3333
+ value="private"
3334
+ onChange={() => {}}
3335
+ renderValue={renderValue}
3336
+ />,
3337
+ );
3338
+ expect(inlineOnly.some(c => triggerClasses().has(c))).toBe(false);
3339
+ standalone.unmount();
3340
+
3341
+ render(
3342
+ <InputGroup label="Space settings">
3343
+ <Selector
3344
+ label="Visibility"
3345
+ options={VISIBILITY}
3346
+ value="private"
3347
+ onChange={() => {}}
3348
+ renderValue={renderValue}
3349
+ />
3350
+ </InputGroup>,
3351
+ );
3352
+ expect(inlineOnly.every(c => triggerClasses().has(c))).toBe(true);
3353
+ });
3354
+
3355
+ it('clamps the trigger value box in a group, whatever renderValue draws', () => {
3356
+ // The hole this guards: the one-line fold a group imposes used to reach
3357
+ // only SelectorOption, which reads the row-layout context. Any other node
3358
+ // ignored it and bled through the trigger's border, over the rows above
3359
+ // and below the group. The clamp is on the trigger's own value box, so it
3360
+ // cannot depend on what the value is.
3361
+ const valueBox = () => {
3362
+ const box = screen.getByRole('combobox').firstElementChild;
3363
+ return new Set((box?.className ?? '').split(' ').filter(Boolean));
3364
+ };
3365
+ const grouped = (
3366
+ renderValue: (option: SelectorOptionData) => ReactNode,
3367
+ ) => (
3368
+ <InputGroup label="Space settings">
3369
+ <Selector
3370
+ label="Visibility"
3371
+ options={VISIBILITY}
3372
+ value="private"
3373
+ onChange={() => {}}
3374
+ renderValue={renderValue}
3375
+ />
3376
+ </InputGroup>
3377
+ );
3378
+
3379
+ const standalone = render(
3380
+ <Selector
3381
+ label="Visibility"
3382
+ options={VISIBILITY}
3383
+ value="private"
3384
+ onChange={() => {}}
3385
+ renderValue={option => <span>{option.label}</span>}
3386
+ />,
3387
+ );
3388
+ const unclamped = valueBox();
3389
+ standalone.unmount();
3390
+
3391
+ const withOption = render(
3392
+ grouped(option => (
3393
+ <SelectorOption
3394
+ icon={option.icon}
3395
+ label={option.label ?? option.value}
3396
+ description={option.description}
3397
+ />
3398
+ )),
3399
+ );
3400
+ const clamped = valueBox();
3401
+ expect(clamped).not.toEqual(unclamped);
3402
+ withOption.unmount();
3403
+
3404
+ // A row the Selector knows nothing about, and a bare element: same box.
3405
+ const withItem = render(
3406
+ grouped(option => (
3407
+ <Item
3408
+ label={option.label ?? option.value}
3409
+ description={option.description}
3410
+ />
3411
+ )),
3412
+ );
3413
+ expect(valueBox()).toEqual(clamped);
3414
+ withItem.unmount();
3415
+
3416
+ render(
3417
+ grouped(option => (
3418
+ <div>
3419
+ <div>{option.label}</div>
3420
+ <div>{option.description}</div>
3421
+ </div>
3422
+ )),
3423
+ );
3424
+ expect(valueBox()).toEqual(clamped);
3425
+ });
3426
+
3427
+ it('does not let a control sized above its group grow the row', () => {
3428
+ // The group's height is the row, so inside one the trigger drops the floor
3429
+ // its own `size` would otherwise assert: <InputGroup size="md"> with a
3430
+ // <Selector size="lg"> stays the group's 32px. The size still reaches the
3431
+ // theme (the trigger keeps its `size` marker class); what it no longer
3432
+ // does is set a height. Standalone, the two sizes still differ.
3433
+ const triggerSizing = () =>
3434
+ new Set(
3435
+ (screen.getByRole('combobox').parentElement?.className ?? '')
3436
+ .split(' ')
3437
+ .filter(Boolean),
3438
+ );
3439
+ // What changes between the two sizes. StyleX keeps a debug class per style
3440
+ // object even where every declaration in it lost, and the theme keeps its
3441
+ // own `size` marker; the atomic classes are what carry the geometry.
3442
+ const geometryDiff = (a: Set<string>, b: Set<string>) => {
3443
+ const atomic = (classes: Set<string>) =>
3444
+ [...classes].filter(c => !c.includes('__') && c !== 'md' && c !== 'lg');
3445
+ return [...atomic(a), ...atomic(b)].filter(c => !(a.has(c) && b.has(c)));
3446
+ };
3447
+ const selector = (size: 'md' | 'lg') => (
3448
+ <Selector
3449
+ label="Visibility"
3450
+ size={size}
3451
+ options={VISIBILITY}
3452
+ value="private"
3453
+ onChange={() => {}}
3454
+ />
3455
+ );
3456
+
3457
+ const standaloneMd = render(selector('md'));
3458
+ const standaloneMdSizing = triggerSizing();
3459
+ standaloneMd.unmount();
3460
+
3461
+ const standaloneLg = render(selector('lg'));
3462
+ expect(geometryDiff(standaloneMdSizing, triggerSizing())).not.toEqual([]);
3463
+ standaloneLg.unmount();
3464
+
3465
+ const groupedMd = render(
3466
+ <InputGroup label="Space settings" size="md">
3467
+ {selector('md')}
3468
+ </InputGroup>,
3469
+ );
3470
+ const groupedMdSizing = triggerSizing();
3471
+ groupedMd.unmount();
3472
+
3473
+ render(
3474
+ <InputGroup label="Space settings" size="md">
3475
+ {selector('lg')}
3476
+ </InputGroup>,
3477
+ );
3478
+ expect(geometryDiff(groupedMdSizing, triggerSizing())).toEqual([]);
3479
+ });
3480
+
3481
+ it('does not call renderValue for the placeholder', () => {
3482
+ const renderValue = vi.fn(() => <span>custom</span>);
3483
+ render(
3484
+ <Selector
3485
+ label="Visibility"
3486
+ options={VISIBILITY}
3487
+ value={undefined}
3488
+ onChange={() => {}}
3489
+ placeholder="Choose..."
3490
+ renderValue={renderValue}
3491
+ />,
3492
+ );
3493
+
3494
+ expect(renderValue).not.toHaveBeenCalled();
3495
+ expect(screen.getByRole('combobox')).toHaveTextContent('Choose...');
3496
+ });
3497
+
3498
+ it('matches type-ahead on the label, not the description', () => {
3499
+ // "Anyone" starts the public description; typing "a" must not select it.
3500
+ function Harness() {
3501
+ const [value, setValue] = useState<string | undefined>(undefined);
3502
+ return (
3503
+ <Selector
3504
+ label="Visibility"
3505
+ options={VISIBILITY}
3506
+ value={value}
3507
+ onChange={setValue}
3508
+ />
3509
+ );
3510
+ }
3511
+ render(<Harness />);
3512
+
3513
+ const trigger = screen.getByRole('combobox');
3514
+ trigger.focus();
3515
+ type('pu', trigger);
3516
+ expect(trigger).toHaveTextContent('Public');
3517
+ expect(trigger).not.toHaveTextContent('Anyone at the company can join.');
3518
+ });
3519
+ });