@astryxdesign/core 0.3.0 → 0.4.0

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 (551) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/dist/AlertDialog/AlertDialog.d.ts +10 -2
  3. package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
  4. package/dist/AlertDialog/AlertDialog.js +22 -3
  5. package/dist/AppShell/AppShell.d.ts +2 -2
  6. package/dist/AppShell/AppShell.d.ts.map +1 -1
  7. package/dist/AppShell/AppShell.js +40 -9
  8. package/dist/AspectRatio/AspectRatio.d.ts +13 -0
  9. package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
  10. package/dist/AspectRatio/AspectRatio.js +9 -0
  11. package/dist/Avatar/Avatar.d.ts.map +1 -1
  12. package/dist/Avatar/Avatar.js +33 -20
  13. package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
  14. package/dist/AvatarGroup/AvatarGroupOverflow.js +2 -3
  15. package/dist/Banner/Banner.d.ts.map +1 -1
  16. package/dist/Banner/Banner.js +15 -14
  17. package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
  18. package/dist/Breadcrumbs/BreadcrumbItem.js +21 -8
  19. package/dist/Breadcrumbs/index.d.ts +2 -1
  20. package/dist/Breadcrumbs/index.d.ts.map +1 -1
  21. package/dist/Breadcrumbs/index.js +1 -0
  22. package/dist/Button/Button.d.ts.map +1 -1
  23. package/dist/Button/Button.js +11 -15
  24. package/dist/Calendar/Calendar.d.ts.map +1 -1
  25. package/dist/Calendar/Calendar.js +2 -1
  26. package/dist/Calendar/styles.d.ts +0 -2
  27. package/dist/Calendar/styles.d.ts.map +1 -1
  28. package/dist/Calendar/styles.js +0 -2
  29. package/dist/Carousel/Carousel.d.ts.map +1 -1
  30. package/dist/Carousel/Carousel.js +8 -12
  31. package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
  32. package/dist/Chat/ChatDictationButton.js +2 -1
  33. package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
  34. package/dist/Chat/ChatLayoutScrollButton.js +3 -1
  35. package/dist/Chat/ChatSendButton.d.ts.map +1 -1
  36. package/dist/Chat/ChatSendButton.js +4 -3
  37. package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
  38. package/dist/Chat/ChatToolCalls.js +17 -17
  39. package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
  40. package/dist/Chat/useTriggerMenu.js +2 -6
  41. package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
  42. package/dist/CheckboxInput/CheckboxInput.js +36 -125
  43. package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
  44. package/dist/ClickableCard/ClickableCard.js +3 -11
  45. package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
  46. package/dist/CodeBlock/CodeBlock.js +84 -67
  47. package/dist/Collapsible/Collapsible.d.ts.map +1 -1
  48. package/dist/Collapsible/Collapsible.js +35 -15
  49. package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -1
  50. package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
  51. package/dist/CommandPalette/CommandPaletteItem.js +6 -3
  52. package/dist/CommandPalette/CommandPaletteList.js +1 -1
  53. package/dist/ComplexSelector/ComplexSelector.d.ts +1 -1
  54. package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
  55. package/dist/ComplexSelector/ComplexSelector.js +35 -33
  56. package/dist/ContextMenu/ContextMenu.d.ts +2 -2
  57. package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
  58. package/dist/ContextMenu/ContextMenu.js +1 -1
  59. package/dist/ContextMenu/index.d.ts +2 -1
  60. package/dist/ContextMenu/index.d.ts.map +1 -1
  61. package/dist/ContextMenu/index.js +1 -0
  62. package/dist/DateInput/DateInput.d.ts +9 -2
  63. package/dist/DateInput/DateInput.d.ts.map +1 -1
  64. package/dist/DateInput/DateInput.js +24 -23
  65. package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
  66. package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
  67. package/dist/DateRangeInput/DateRangeInput.js +11 -16
  68. package/dist/DateTimeInput/DateTimeInput.d.ts +9 -1
  69. package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
  70. package/dist/DateTimeInput/DateTimeInput.js +22 -17
  71. package/dist/Dialog/Dialog.d.ts.map +1 -1
  72. package/dist/Dialog/Dialog.js +4 -4
  73. package/dist/DropdownMenu/DropdownMenu.d.ts +33 -8
  74. package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
  75. package/dist/DropdownMenu/DropdownMenu.js +62 -20
  76. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +8 -11
  77. package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
  78. package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +32 -31
  79. package/dist/DropdownMenu/DropdownMenuDivider.d.ts +25 -0
  80. package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -0
  81. package/dist/DropdownMenu/DropdownMenuDivider.js +66 -0
  82. package/dist/DropdownMenu/DropdownMenuItem.d.ts +15 -2
  83. package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
  84. package/dist/DropdownMenu/DropdownMenuItem.js +20 -8
  85. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +5 -5
  86. package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
  87. package/dist/DropdownMenu/DropdownMenuRadioItem.js +24 -67
  88. package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
  89. package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -8
  90. package/dist/DropdownMenu/index.d.ts +2 -1
  91. package/dist/DropdownMenu/index.d.ts.map +1 -1
  92. package/dist/DropdownMenu/index.js +4 -0
  93. package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
  94. package/dist/DropdownMenu/renderDropdownItems.js +35 -27
  95. package/dist/EmptyState/EmptyState.d.ts.map +1 -1
  96. package/dist/EmptyState/EmptyState.js +9 -5
  97. package/dist/Field/InputClearButton.d.ts +16 -3
  98. package/dist/Field/InputClearButton.d.ts.map +1 -1
  99. package/dist/Field/InputClearButton.js +15 -4
  100. package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
  101. package/dist/HoverCard/useHoverCard.js +3 -19
  102. package/dist/Indicator/CheckIndicator.d.ts +25 -0
  103. package/dist/Indicator/CheckIndicator.d.ts.map +1 -0
  104. package/dist/Indicator/CheckIndicator.js +155 -0
  105. package/dist/Indicator/CheckboxIndicator.d.ts +22 -0
  106. package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -0
  107. package/dist/Indicator/CheckboxIndicator.js +173 -0
  108. package/dist/Indicator/RadioIndicator.d.ts +23 -0
  109. package/dist/Indicator/RadioIndicator.d.ts.map +1 -0
  110. package/dist/Indicator/RadioIndicator.js +137 -0
  111. package/dist/Indicator/index.d.ts +24 -0
  112. package/dist/Indicator/index.d.ts.map +1 -0
  113. package/dist/Indicator/index.js +26 -0
  114. package/dist/Indicator/indicator.markers.stylex.d.ts +16 -0
  115. package/dist/Indicator/indicator.markers.stylex.d.ts.map +1 -0
  116. package/dist/Indicator/indicator.markers.stylex.js +21 -0
  117. package/dist/Indicator/indicatorRegistry.d.ts +71 -0
  118. package/dist/Indicator/indicatorRegistry.d.ts.map +1 -0
  119. package/dist/Indicator/indicatorRegistry.js +93 -0
  120. package/dist/Indicator/types.d.ts +167 -0
  121. package/dist/Indicator/types.d.ts.map +1 -0
  122. package/dist/Indicator/types.js +1 -0
  123. package/dist/Indicator/useIndicator.d.ts +18 -0
  124. package/dist/Indicator/useIndicator.d.ts.map +1 -0
  125. package/dist/Indicator/useIndicator.js +30 -0
  126. package/dist/Item/Item.d.ts.map +1 -1
  127. package/dist/Item/Item.js +4 -8
  128. package/dist/Layer/useLayer.d.ts +14 -0
  129. package/dist/Layer/useLayer.d.ts.map +1 -1
  130. package/dist/Layer/useLayer.js +25 -2
  131. package/dist/Lightbox/Lightbox.d.ts.map +1 -1
  132. package/dist/Lightbox/Lightbox.js +56 -53
  133. package/dist/Link/Link.d.ts.map +1 -1
  134. package/dist/Link/Link.js +4 -5
  135. package/dist/MobileNav/MobileNav.js +8 -8
  136. package/dist/MoreMenu/MoreMenu.d.ts +14 -1
  137. package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
  138. package/dist/MoreMenu/MoreMenu.js +4 -0
  139. package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
  140. package/dist/MultiSelector/MultiSelector.js +78 -75
  141. package/dist/NumberInput/NumberInput.d.ts +27 -1
  142. package/dist/NumberInput/NumberInput.d.ts.map +1 -1
  143. package/dist/NumberInput/NumberInput.js +230 -42
  144. package/dist/Outline/Outline.d.ts.map +1 -1
  145. package/dist/Outline/Outline.js +2 -3
  146. package/dist/Pagination/Pagination.d.ts.map +1 -1
  147. package/dist/Pagination/Pagination.js +61 -63
  148. package/dist/Popover/Popover.d.ts.map +1 -1
  149. package/dist/Popover/Popover.js +6 -8
  150. package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
  151. package/dist/PowerSearch/PowerSearch.js +1 -1
  152. package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
  153. package/dist/PowerSearch/PowerSearchEditPopover.js +7 -0
  154. package/dist/ProgressBar/ProgressBar.d.ts +11 -4
  155. package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
  156. package/dist/ProgressBar/ProgressBar.js +96 -6
  157. package/dist/RadioList/RadioListItem.d.ts.map +1 -1
  158. package/dist/RadioList/RadioListItem.js +29 -84
  159. package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
  160. package/dist/Resizable/ResizeHandle.js +2 -3
  161. package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
  162. package/dist/SegmentedControl/SegmentedControlItem.js +2 -3
  163. package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
  164. package/dist/SelectableCard/SelectableCard.js +3 -11
  165. package/dist/Selector/Selector.d.ts +2 -1
  166. package/dist/Selector/Selector.d.ts.map +1 -1
  167. package/dist/Selector/Selector.js +164 -94
  168. package/dist/Selector/hooks.d.ts +18 -6
  169. package/dist/Selector/hooks.d.ts.map +1 -1
  170. package/dist/Selector/hooks.js +57 -40
  171. package/dist/SideNav/SideNav.d.ts.map +1 -1
  172. package/dist/SideNav/SideNav.js +1 -1
  173. package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
  174. package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
  175. package/dist/SideNav/SideNavCollapseButton.js +29 -14
  176. package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
  177. package/dist/SideNav/SideNavHeading.js +56 -20
  178. package/dist/SideNav/SideNavItem.d.ts.map +1 -1
  179. package/dist/SideNav/SideNavItem.js +28 -22
  180. package/dist/Stack/stack.stylex.d.ts +3 -3
  181. package/dist/Switch/Switch.js +11 -10
  182. package/dist/TabList/Tab.d.ts.map +1 -1
  183. package/dist/TabList/Tab.js +2 -3
  184. package/dist/TabList/TabMenu.d.ts.map +1 -1
  185. package/dist/TabList/TabMenu.js +41 -19
  186. package/dist/Table/BaseTable.d.ts.map +1 -1
  187. package/dist/Table/BaseTable.js +8 -0
  188. package/dist/Table/index.d.ts +1 -1
  189. package/dist/Table/index.d.ts.map +1 -1
  190. package/dist/Table/index.js +1 -1
  191. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
  192. package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
  193. package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +22 -18
  194. package/dist/Table/plugins/rowExpansion/index.d.ts +1 -1
  195. package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -1
  196. package/dist/Table/plugins/rowExpansion/index.js +1 -1
  197. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +41 -76
  198. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
  199. package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +94 -345
  200. package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
  201. package/dist/Table/plugins/sortable/useTableSortable.js +23 -4
  202. package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
  203. package/dist/Table/plugins/tree/useTableTreeData.js +29 -33
  204. package/dist/Table/tableContextMenu.d.ts.map +1 -1
  205. package/dist/Table/tableContextMenu.js +2 -1
  206. package/dist/Table/types.d.ts +11 -0
  207. package/dist/Table/types.d.ts.map +1 -1
  208. package/dist/TextArea/TextArea.d.ts +10 -1
  209. package/dist/TextArea/TextArea.d.ts.map +1 -1
  210. package/dist/TextArea/TextArea.js +16 -6
  211. package/dist/TextInput/TextInput.d.ts +10 -1
  212. package/dist/TextInput/TextInput.d.ts.map +1 -1
  213. package/dist/TextInput/TextInput.js +13 -19
  214. package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
  215. package/dist/Thumbnail/Thumbnail.js +32 -26
  216. package/dist/TimeInput/TimeInput.d.ts.map +1 -1
  217. package/dist/TimeInput/TimeInput.js +7 -15
  218. package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -1
  219. package/dist/Timestamp/TimestampHoverCard.js +16 -34
  220. package/dist/Token/Token.d.ts.map +1 -1
  221. package/dist/Token/Token.js +20 -11
  222. package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
  223. package/dist/Tokenizer/Tokenizer.js +4 -2
  224. package/dist/Tooltip/useTooltip.d.ts.map +1 -1
  225. package/dist/Tooltip/useTooltip.js +3 -19
  226. package/dist/TopNav/TopNav.d.ts.map +1 -1
  227. package/dist/TopNav/TopNav.js +6 -5
  228. package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
  229. package/dist/TopNav/TopNavHeading.js +54 -16
  230. package/dist/TopNav/TopNavItem.d.ts.map +1 -1
  231. package/dist/TopNav/TopNavItem.js +3 -9
  232. package/dist/TopNav/TopNavMegaMenu.d.ts +7 -0
  233. package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
  234. package/dist/TopNav/TopNavMegaMenu.js +146 -60
  235. package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
  236. package/dist/TopNav/TopNavMegaMenuItem.js +22 -3
  237. package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
  238. package/dist/TopNav/TopNavMenu.js +83 -38
  239. package/dist/TreeList/TreeList.d.ts.map +1 -1
  240. package/dist/TreeList/TreeList.js +13 -0
  241. package/dist/TreeList/TreeListBranches.d.ts +1 -1
  242. package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
  243. package/dist/TreeList/TreeListBranches.js +14 -4
  244. package/dist/TreeList/TreeListItem.d.ts +11 -1
  245. package/dist/TreeList/TreeListItem.d.ts.map +1 -1
  246. package/dist/TreeList/TreeListItem.js +57 -30
  247. package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
  248. package/dist/Typeahead/BaseTypeahead.js +16 -8
  249. package/dist/astryx.css +74 -85
  250. package/dist/astryx.umd.js +56 -56
  251. package/dist/astryx.umd.js.map +4 -4
  252. package/dist/hooks/containerReveal.stylex.d.ts +61 -0
  253. package/dist/hooks/containerReveal.stylex.d.ts.map +1 -0
  254. package/dist/hooks/containerReveal.stylex.js +63 -0
  255. package/dist/hooks/index.d.ts +3 -0
  256. package/dist/hooks/index.d.ts.map +1 -1
  257. package/dist/hooks/index.js +2 -0
  258. package/dist/hooks/useClipboard.d.ts +59 -0
  259. package/dist/hooks/useClipboard.d.ts.map +1 -0
  260. package/dist/hooks/useClipboard.js +106 -0
  261. package/dist/hooks/useContainerReveal.d.ts +14 -8
  262. package/dist/hooks/useContainerReveal.d.ts.map +1 -1
  263. package/dist/hooks/useContainerReveal.js +28 -69
  264. package/dist/hooks/useIndicatorFocusRing.d.ts +28 -0
  265. package/dist/hooks/useIndicatorFocusRing.d.ts.map +1 -0
  266. package/dist/hooks/useIndicatorFocusRing.js +96 -0
  267. package/dist/hooks/useLongPress.d.ts.map +1 -1
  268. package/dist/hooks/useLongPress.js +12 -2
  269. package/dist/hooks/useScrollLock.d.ts.map +1 -1
  270. package/dist/hooks/useScrollLock.js +33 -18
  271. package/dist/hooks/useStreamingText.d.ts +18 -3
  272. package/dist/hooks/useStreamingText.d.ts.map +1 -1
  273. package/dist/hooks/useStreamingText.js +47 -7
  274. package/dist/hooks/useTreeFocus.d.ts.map +1 -1
  275. package/dist/hooks/useTreeFocus.js +9 -3
  276. package/dist/hooks/useTypeahead.d.ts +3 -2
  277. package/dist/hooks/useTypeahead.d.ts.map +1 -1
  278. package/dist/hooks/useTypeahead.js +19 -7
  279. package/dist/index.d.ts +1 -0
  280. package/dist/index.d.ts.map +1 -1
  281. package/dist/index.js +1 -0
  282. package/dist/theme/defineTheme.d.ts +16 -0
  283. package/dist/theme/defineTheme.d.ts.map +1 -1
  284. package/dist/theme/defineTheme.js +8 -0
  285. package/dist/theme/derivedVarRegistry.d.ts +8 -0
  286. package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
  287. package/dist/theme/derivedVarRegistry.js +14 -13
  288. package/dist/theme/expandColorScale.d.ts +3 -1
  289. package/dist/theme/expandColorScale.d.ts.map +1 -1
  290. package/dist/theme/expandColorScale.js +17 -7
  291. package/dist/theme/expandTypeScale.d.ts.map +1 -1
  292. package/dist/theme/expandTypeScale.js +17 -0
  293. package/dist/theme/generateThemeRules.d.ts.map +1 -1
  294. package/dist/theme/generateThemeRules.js +11 -0
  295. package/dist/theme/index.d.ts +1 -0
  296. package/dist/theme/index.d.ts.map +1 -1
  297. package/dist/utils/focusOutline.stylex.d.ts +107 -0
  298. package/dist/utils/focusOutline.stylex.d.ts.map +1 -0
  299. package/dist/utils/focusOutline.stylex.js +130 -0
  300. package/dist/utils/focusReturn.d.ts +24 -0
  301. package/dist/utils/focusReturn.d.ts.map +1 -0
  302. package/dist/utils/focusReturn.js +29 -0
  303. package/dist/utils/index.d.ts +1 -0
  304. package/dist/utils/index.d.ts.map +1 -1
  305. package/dist/utils/index.js +1 -0
  306. package/dist/utils/mergeRefs.d.ts.map +1 -1
  307. package/dist/utils/mergeRefs.js +7 -5
  308. package/dist/utils/rtlStyles.d.ts +2 -2
  309. package/dist/utils/rtlStyles.js +2 -2
  310. package/dist/utils/themeProps.d.ts +20 -1
  311. package/dist/utils/themeProps.d.ts.map +1 -1
  312. package/dist/utils/themeProps.js +8 -2
  313. package/locales/en.json +12 -0
  314. package/locales/pseudo.json +9 -0
  315. package/package.json +7 -2
  316. package/src/AlertDialog/AlertDialog.doc.mjs +16 -3
  317. package/src/AlertDialog/AlertDialog.test.tsx +208 -1
  318. package/src/AlertDialog/AlertDialog.tsx +21 -3
  319. package/src/AppShell/AppShell.doc.mjs +11 -0
  320. package/src/AppShell/AppShell.test.tsx +139 -0
  321. package/src/AppShell/AppShell.tsx +32 -22
  322. package/src/AspectRatio/AspectRatio.doc.mjs +27 -3
  323. package/src/AspectRatio/AspectRatio.test.tsx +30 -0
  324. package/src/AspectRatio/AspectRatio.tsx +13 -0
  325. package/src/Avatar/Avatar.doc.mjs +2 -13
  326. package/src/Avatar/Avatar.test.tsx +33 -8
  327. package/src/Avatar/Avatar.tsx +52 -50
  328. package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -9
  329. package/src/Banner/Banner.tsx +9 -6
  330. package/src/Breadcrumbs/BreadcrumbItem.tsx +16 -6
  331. package/src/Breadcrumbs/index.ts +5 -1
  332. package/src/Button/Button.tsx +21 -41
  333. package/src/Calendar/Calendar.tsx +2 -1
  334. package/src/Calendar/styles.ts +0 -8
  335. package/src/Carousel/Carousel.doc.mjs +3 -0
  336. package/src/Carousel/Carousel.tsx +10 -6
  337. package/src/Chat/Chat.doc.mjs +2 -0
  338. package/src/Chat/ChatDictationButton.tsx +7 -1
  339. package/src/Chat/ChatLayoutScrollButton.test.tsx +22 -0
  340. package/src/Chat/ChatLayoutScrollButton.tsx +8 -1
  341. package/src/Chat/ChatSendButton.tsx +2 -3
  342. package/src/Chat/ChatToolCalls.test.tsx +35 -0
  343. package/src/Chat/ChatToolCalls.tsx +36 -16
  344. package/src/Chat/useTriggerMenu.tsx +2 -5
  345. package/src/CheckboxInput/CheckboxInput.doc.mjs +4 -2
  346. package/src/CheckboxInput/CheckboxInput.test.tsx +115 -0
  347. package/src/CheckboxInput/CheckboxInput.tsx +45 -202
  348. package/src/ClickableCard/ClickableCard.tsx +6 -11
  349. package/src/CodeBlock/CodeBlock.doc.mjs +3 -0
  350. package/src/CodeBlock/CodeBlock.test.tsx +91 -0
  351. package/src/CodeBlock/CodeBlock.tsx +57 -80
  352. package/src/Collapsible/Collapsible.tsx +22 -18
  353. package/src/CommandPalette/CommandPalette.test.tsx +29 -0
  354. package/src/CommandPalette/CommandPaletteItem.tsx +7 -4
  355. package/src/CommandPalette/CommandPaletteList.tsx +2 -2
  356. package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
  357. package/src/ComplexSelector/ComplexSelector.test.tsx +64 -0
  358. package/src/ComplexSelector/ComplexSelector.tsx +46 -29
  359. package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
  360. package/src/ContextMenu/ContextMenu.test.tsx +41 -0
  361. package/src/ContextMenu/ContextMenu.tsx +3 -3
  362. package/src/ContextMenu/index.ts +5 -1
  363. package/src/DateInput/DateInput.doc.mjs +18 -3
  364. package/src/DateInput/DateInput.test.tsx +93 -11
  365. package/src/DateInput/DateInput.tsx +41 -19
  366. package/src/DateRangeInput/DateRangeInput.doc.mjs +10 -2
  367. package/src/DateRangeInput/DateRangeInput.test.tsx +110 -14
  368. package/src/DateRangeInput/DateRangeInput.tsx +24 -12
  369. package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -2
  370. package/src/DateTimeInput/DateTimeInput.test.tsx +75 -0
  371. package/src/DateTimeInput/DateTimeInput.tsx +35 -8
  372. package/src/Dialog/Dialog.tsx +2 -9
  373. package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -9
  374. package/src/DropdownMenu/DropdownMenu.test.tsx +534 -4
  375. package/src/DropdownMenu/DropdownMenu.tsx +113 -52
  376. package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +27 -30
  377. package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +34 -0
  378. package/src/DropdownMenu/DropdownMenuDivider.tsx +81 -0
  379. package/src/DropdownMenu/DropdownMenuItem.doc.mjs +39 -4
  380. package/src/DropdownMenu/DropdownMenuItem.tsx +48 -10
  381. package/src/DropdownMenu/DropdownMenuRadioItem.tsx +30 -76
  382. package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +25 -19
  383. package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +44 -14
  384. package/src/DropdownMenu/DropdownMenuSubMenu.tsx +1 -5
  385. package/src/DropdownMenu/index.ts +8 -1
  386. package/src/DropdownMenu/renderDropdownItems.tsx +33 -34
  387. package/src/EmptyState/EmptyState.doc.mjs +4 -0
  388. package/src/EmptyState/EmptyState.test.tsx +62 -0
  389. package/src/EmptyState/EmptyState.tsx +16 -6
  390. package/src/Field/Field.doc.mjs +1 -0
  391. package/src/Field/InputClearButton.test.tsx +117 -0
  392. package/src/Field/InputClearButton.tsx +30 -3
  393. package/src/HoverCard/useHoverCard.tsx +2 -23
  394. package/src/Icon/Icon.doc.mjs +2 -1
  395. package/src/Indicator/CheckIndicator.tsx +174 -0
  396. package/src/Indicator/CheckboxIndicator.tsx +257 -0
  397. package/src/Indicator/Indicator.doc.mjs +344 -0
  398. package/src/Indicator/Indicator.test.tsx +393 -0
  399. package/src/Indicator/RadioIndicator.tsx +206 -0
  400. package/src/Indicator/index.ts +45 -0
  401. package/src/Indicator/indicator.markers.stylex.ts +19 -0
  402. package/src/Indicator/indicatorRegistry.test.tsx +106 -0
  403. package/src/Indicator/indicatorRegistry.ts +120 -0
  404. package/src/Indicator/types.ts +186 -0
  405. package/src/Indicator/useIndicator.ts +39 -0
  406. package/src/Item/Item.doc.mjs +1 -1
  407. package/src/Item/Item.tsx +7 -14
  408. package/src/Layer/useLayer.doc.mjs +2 -2
  409. package/src/Layer/useLayer.test.tsx +85 -0
  410. package/src/Layer/useLayer.tsx +39 -1
  411. package/src/Lightbox/Lightbox.doc.mjs +1 -1
  412. package/src/Lightbox/Lightbox.tsx +43 -38
  413. package/src/Link/Link.tsx +4 -11
  414. package/src/MobileNav/MobileNav.tsx +3 -3
  415. package/src/MoreMenu/MoreMenu.doc.mjs +31 -0
  416. package/src/MoreMenu/MoreMenu.test.tsx +68 -1
  417. package/src/MoreMenu/MoreMenu.tsx +19 -0
  418. package/src/MultiSelector/MultiSelector.doc.mjs +9 -1
  419. package/src/MultiSelector/MultiSelector.test.tsx +255 -16
  420. package/src/MultiSelector/MultiSelector.tsx +103 -99
  421. package/src/NumberInput/NumberInput.doc.mjs +265 -50
  422. package/src/NumberInput/NumberInput.test.tsx +726 -21
  423. package/src/NumberInput/NumberInput.tsx +353 -59
  424. package/src/Outline/Outline.tsx +2 -5
  425. package/src/Pagination/Pagination.doc.mjs +1 -1
  426. package/src/Pagination/Pagination.test.tsx +22 -7
  427. package/src/Pagination/Pagination.tsx +38 -35
  428. package/src/Popover/Popover.tsx +6 -7
  429. package/src/PowerSearch/PowerSearch.tsx +1 -1
  430. package/src/PowerSearch/PowerSearchEditPopover.test.tsx +42 -0
  431. package/src/PowerSearch/PowerSearchEditPopover.tsx +7 -0
  432. package/src/ProgressBar/ProgressBar.doc.mjs +27 -5
  433. package/src/ProgressBar/ProgressBar.test.tsx +224 -1
  434. package/src/ProgressBar/ProgressBar.tsx +124 -22
  435. package/src/RadioList/RadioList.doc.mjs +4 -2
  436. package/src/RadioList/RadioListItem.tsx +31 -130
  437. package/src/Resizable/ResizeHandle.tsx +2 -9
  438. package/src/SegmentedControl/SegmentedControlItem.tsx +2 -9
  439. package/src/SelectableCard/SelectableCard.tsx +4 -9
  440. package/src/Selector/Selector.doc.mjs +7 -4
  441. package/src/Selector/Selector.test.tsx +935 -25
  442. package/src/Selector/Selector.tsx +189 -106
  443. package/src/Selector/hooks.ts +77 -50
  444. package/src/SideNav/SideNav.test.tsx +46 -0
  445. package/src/SideNav/SideNav.tsx +1 -0
  446. package/src/SideNav/SideNavCollapseButton.tsx +15 -10
  447. package/src/SideNav/SideNavHeading.tsx +48 -10
  448. package/src/SideNav/SideNavItem.tsx +20 -12
  449. package/src/Stack/Stack.doc.mjs +110 -0
  450. package/src/StatusDot/StatusDot.doc.mjs +12 -3
  451. package/src/Switch/Switch.test.tsx +32 -0
  452. package/src/Switch/Switch.tsx +8 -8
  453. package/src/TabList/Tab.tsx +2 -9
  454. package/src/TabList/TabMenu.tsx +14 -21
  455. package/src/Table/BaseTable.tsx +11 -0
  456. package/src/Table/index.ts +1 -4
  457. package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +30 -14
  458. package/src/Table/plugins/rowExpansion/index.ts +1 -4
  459. package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +125 -175
  460. package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +115 -458
  461. package/src/Table/plugins/sortable/useTableSortable.tsx +2 -6
  462. package/src/Table/plugins/tree/useTableTreeData.tsx +43 -24
  463. package/src/Table/tableContextMenu.test.tsx +27 -0
  464. package/src/Table/tableContextMenu.tsx +1 -0
  465. package/src/Table/types.ts +11 -0
  466. package/src/Table/useTableGroupedRows.doc.mjs +1 -1
  467. package/src/Table/useTableRowExpansion.doc.mjs +43 -66
  468. package/src/TextArea/TextArea.doc.mjs +42 -2
  469. package/src/TextArea/TextArea.test.tsx +219 -0
  470. package/src/TextArea/TextArea.tsx +34 -7
  471. package/src/TextInput/TextInput.doc.mjs +18 -2
  472. package/src/TextInput/TextInput.test.tsx +189 -0
  473. package/src/TextInput/TextInput.tsx +25 -31
  474. package/src/Thumbnail/Thumbnail.tsx +2 -9
  475. package/src/TimeInput/TimeInput.doc.mjs +2 -2
  476. package/src/TimeInput/TimeInput.test.tsx +30 -3
  477. package/src/TimeInput/TimeInput.tsx +9 -26
  478. package/src/Timestamp/Timestamp.doc.mjs +4 -3
  479. package/src/Timestamp/TimestampHoverCard.tsx +13 -35
  480. package/src/Token/Token.tsx +5 -28
  481. package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
  482. package/src/Tokenizer/Tokenizer.test.tsx +45 -3
  483. package/src/Tokenizer/Tokenizer.tsx +10 -2
  484. package/src/Tooltip/useTooltip.tsx +2 -23
  485. package/src/TopNav/TopNav.tsx +1 -3
  486. package/src/TopNav/TopNavHeading.tsx +42 -13
  487. package/src/TopNav/TopNavItem.tsx +3 -21
  488. package/src/TopNav/TopNavMegaMenu.test.tsx +433 -33
  489. package/src/TopNav/TopNavMegaMenu.tsx +118 -53
  490. package/src/TopNav/TopNavMegaMenuItem.tsx +2 -9
  491. package/src/TopNav/TopNavMenu.tsx +34 -37
  492. package/src/TreeList/TreeList.doc.mjs +5 -0
  493. package/src/TreeList/TreeList.test.tsx +206 -7
  494. package/src/TreeList/TreeList.tsx +22 -0
  495. package/src/TreeList/TreeListBranches.tsx +25 -2
  496. package/src/TreeList/TreeListItem.tsx +89 -52
  497. package/src/Typeahead/BaseTypeahead.tsx +19 -6
  498. package/src/Typeahead/Typeahead.doc.mjs +1 -0
  499. package/src/Typeahead/Typeahead.test.tsx +76 -3
  500. package/src/hooks/containerReveal.stylex.ts +102 -0
  501. package/src/hooks/index.ts +4 -0
  502. package/src/hooks/useClipboard.doc.mjs +87 -0
  503. package/src/hooks/useClipboard.test.tsx +151 -0
  504. package/src/hooks/useClipboard.ts +135 -0
  505. package/src/hooks/useContainerReveal.doc.mjs +7 -7
  506. package/src/hooks/useContainerReveal.test.tsx +42 -62
  507. package/src/hooks/useContainerReveal.ts +36 -91
  508. package/src/hooks/useImageMode.test.ts +1 -1
  509. package/src/hooks/useIndicatorFocusRing.tsx +120 -0
  510. package/src/hooks/useLongPress.test.tsx +18 -0
  511. package/src/hooks/useLongPress.ts +12 -2
  512. package/src/hooks/useScrollLock.test.ts +72 -0
  513. package/src/hooks/useScrollLock.ts +51 -19
  514. package/src/hooks/useStreamingText.test.ts +46 -1
  515. package/src/hooks/useStreamingText.ts +49 -7
  516. package/src/hooks/useTreeFocus.test.tsx +50 -0
  517. package/src/hooks/useTreeFocus.ts +14 -3
  518. package/src/hooks/useTypeahead.test.tsx +150 -0
  519. package/src/hooks/useTypeahead.ts +24 -9
  520. package/src/i18n/InternationalizationProvider.doc.mjs +7 -2
  521. package/src/index.ts +1 -0
  522. package/src/theme/defineTheme.ts +24 -0
  523. package/src/theme/derivedVarRegistry.test.ts +21 -1
  524. package/src/theme/derivedVarRegistry.ts +19 -6
  525. package/src/theme/expandColorScale.test.ts +14 -0
  526. package/src/theme/expandColorScale.ts +24 -9
  527. package/src/theme/expandTypeScale.test.ts +43 -0
  528. package/src/theme/expandTypeScale.ts +17 -0
  529. package/src/theme/generateThemeRules.test.ts +61 -20
  530. package/src/theme/generateThemeRules.ts +11 -0
  531. package/src/theme/index.ts +13 -0
  532. package/src/utils/focusOutline.stylex.ts +163 -0
  533. package/src/utils/focusReturn.test.ts +42 -0
  534. package/src/utils/focusReturn.ts +31 -0
  535. package/src/utils/index.ts +1 -0
  536. package/src/utils/mergeRefs.test.ts +48 -0
  537. package/src/utils/mergeRefs.ts +12 -6
  538. package/src/utils/rtlStyles.ts +2 -2
  539. package/src/utils/themeProps.ts +26 -4
  540. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts +0 -9
  541. package/dist/CheckboxInput/checkbox.markers.stylex.d.ts.map +0 -1
  542. package/dist/CheckboxInput/checkbox.markers.stylex.js +0 -14
  543. package/dist/RadioList/radio.markers.stylex.d.ts +0 -7
  544. package/dist/RadioList/radio.markers.stylex.d.ts.map +0 -1
  545. package/dist/RadioList/radio.markers.stylex.js +0 -12
  546. package/dist/hooks/containerReveal.pool.stylex.d.ts +0 -303
  547. package/dist/hooks/containerReveal.pool.stylex.d.ts.map +0 -1
  548. package/dist/hooks/containerReveal.pool.stylex.js +0 -292
  549. package/src/CheckboxInput/checkbox.markers.stylex.ts +0 -12
  550. package/src/RadioList/radio.markers.stylex.ts +0 -10
  551. package/src/hooks/containerReveal.pool.stylex.ts +0 -571
@@ -30,6 +30,7 @@ import * as stylex from '@stylexjs/stylex';
30
30
  import {
31
31
  colorVars,
32
32
  sizeVars,
33
+ spacingVars,
33
34
  radiusVars,
34
35
  typographyVars,
35
36
  typeScaleVars,
@@ -37,6 +38,7 @@ import {
37
38
  } from '../theme/tokens.stylex';
38
39
  import {
39
40
  Field,
41
+ InputClearButton,
40
42
  type InputStatus,
41
43
  inputWrapperStyles,
42
44
  inputStatusBorderStyles,
@@ -57,22 +59,8 @@ const styles = stylex.create({
57
59
  wrapper: {
58
60
  zIndex: 1,
59
61
  },
60
- clearButton: {
61
- display: 'flex',
62
- alignItems: 'center',
63
- justifyContent: 'center',
64
- padding: 0,
65
- margin: 0,
66
- borderWidth: 0,
67
- borderStyle: 'none',
68
- backgroundColor: 'transparent',
69
- cursor: 'pointer',
70
- borderRadius: radiusVars['--radius-element'],
71
- outline: {
72
- default: 'none',
73
- ':focus-visible': `${borderVars['--border-width']} solid ${colorVars['--color-accent']}`,
74
- },
75
- outlineOffset: 1,
62
+ wrapperWithNumberSteppers: {
63
+ paddingInlineEnd: 0,
76
64
  },
77
65
  input: {
78
66
  display: 'block',
@@ -81,18 +69,6 @@ const styles = stylex.create({
81
69
  borderWidth: 0,
82
70
  borderStyle: 'none',
83
71
  padding: 0,
84
- // Hide the browser's native number spinners; the component provides its own
85
- // affordances (keyboard entry, optional clear button) and the spinners
86
- // clash with the input's visual treatment and sizing.
87
- MozAppearance: 'textfield',
88
- '::-webkit-inner-spin-button': {
89
- WebkitAppearance: 'none',
90
- margin: 0,
91
- },
92
- '::-webkit-outer-spin-button': {
93
- WebkitAppearance: 'none',
94
- margin: 0,
95
- },
96
72
  fontFamily: typographyVars['--font-family-body'],
97
73
  fontSize: {
98
74
  default: typeScaleVars['--text-body-size'],
@@ -119,6 +95,56 @@ const styles = stylex.create({
119
95
  color: colorVars['--color-text-secondary'],
120
96
  flexShrink: 0,
121
97
  },
98
+ numberSteppers: {
99
+ alignSelf: 'stretch',
100
+ display: 'flex',
101
+ flexDirection: 'column',
102
+ flexShrink: 0,
103
+ width: spacingVars['--spacing-4'],
104
+ marginBlock: `calc(-1 * ${spacingVars['--spacing-1']})`,
105
+ borderInlineStartWidth: borderVars['--border-width'],
106
+ borderInlineStartStyle: 'solid',
107
+ borderInlineStartColor: colorVars['--color-border-emphasized'],
108
+ overflow: 'hidden',
109
+ borderStartEndRadius: radiusVars['--radius-element'],
110
+ borderEndEndRadius: radiusVars['--radius-element'],
111
+ },
112
+ numberStepperButton: {
113
+ boxSizing: 'border-box',
114
+ display: 'flex',
115
+ alignItems: 'center',
116
+ justifyContent: 'center',
117
+ flex: 1,
118
+ minHeight: 0,
119
+ padding: 0,
120
+ margin: 0,
121
+ borderWidth: 0,
122
+ borderStyle: 'none',
123
+ color: colorVars['--color-icon-secondary'],
124
+ backgroundColor: colorVars['--color-background-surface'],
125
+ backgroundImage: {
126
+ default: null,
127
+ ':hover': {
128
+ '@media (hover: hover)': `linear-gradient(${colorVars['--color-overlay-hover']}, ${colorVars['--color-overlay-hover']})`,
129
+ },
130
+ ':active': `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`,
131
+ },
132
+ cursor: 'pointer',
133
+ outline: 'none',
134
+ },
135
+ numberStepperButtonDisabled: {
136
+ color: colorVars['--color-icon-disabled'],
137
+ cursor: 'not-allowed',
138
+ backgroundImage: 'none',
139
+ },
140
+ decrementButton: {
141
+ borderBlockStartWidth: borderVars['--border-width'],
142
+ borderBlockStartStyle: 'solid',
143
+ borderBlockStartColor: colorVars['--color-border-emphasized'],
144
+ },
145
+ incrementIcon: {
146
+ transform: 'rotate(180deg)',
147
+ },
122
148
  });
123
149
 
124
150
  const sizeStyles = stylex.create({
@@ -183,6 +209,17 @@ interface NumberInputPropsBase extends Omit<
183
209
  * @default false
184
210
  */
185
211
  isDisabled?: boolean;
212
+ /**
213
+ * Whether the input is read-only.
214
+ * The value is shown at full opacity and still submits with the form, but
215
+ * cannot be edited. Unlike `isDisabled`, a read-only input is not dimmed and
216
+ * stays in the tab order — use it for a value the user should see and send
217
+ * but not change. Stepping is off in every form while read-only: arrow keys,
218
+ * the wheel, and the number steppers. `isDisabled` takes precedence when both
219
+ * are set.
220
+ * @default false
221
+ */
222
+ isReadOnly?: boolean;
186
223
  /**
187
224
  * Explains why the input is disabled. When set together with `isDisabled`,
188
225
  * the input shows a tooltip with this text on hover and keyboard focus, and
@@ -282,6 +319,21 @@ interface NumberInputPropsBase extends Omit<
282
319
  * @default 1
283
320
  */
284
321
  step?: number | null;
322
+ /**
323
+ * Formats the committed value while the input is not being edited.
324
+ * The raw numeric value is shown on focus so it remains editable.
325
+ */
326
+ formatValue?: (value: number) => string;
327
+ /**
328
+ * Whether scrolling the wheel over a focused input steps the value.
329
+ * @default true
330
+ */
331
+ isWheelEnabled?: boolean;
332
+ /**
333
+ * Whether to show increment and decrement buttons at the end of the input.
334
+ * @default false
335
+ */
336
+ hasNumberSteppers?: boolean;
285
337
  /**
286
338
  * Units text to display at the end of the input (e.g., "%" or "GB").
287
339
  */
@@ -373,6 +425,88 @@ function parseNumberInput(
373
425
  return num;
374
426
  }
375
427
 
428
+ type StepDirection = -1 | 1;
429
+
430
+ function getDecimalPlaces(value: number): number {
431
+ const [coefficient, exponentText] = String(value).toLowerCase().split('e');
432
+ const fractionLength = coefficient.split('.')[1]?.length ?? 0;
433
+ const exponent = exponentText == null ? 0 : Number(exponentText);
434
+ return Math.max(0, fractionLength - exponent);
435
+ }
436
+
437
+ function getEffectiveStep(
438
+ step: number | null | undefined,
439
+ isIntegerOnly: boolean,
440
+ ): number {
441
+ if (
442
+ step == null ||
443
+ !Number.isFinite(step) ||
444
+ step <= 0 ||
445
+ (isIntegerOnly && !Number.isInteger(step))
446
+ ) {
447
+ return 1;
448
+ }
449
+ return step;
450
+ }
451
+
452
+ function getSteppedValue({
453
+ currentValue,
454
+ direction,
455
+ min,
456
+ max,
457
+ step,
458
+ isIntegerOnly,
459
+ }: {
460
+ currentValue: number | null;
461
+ direction: StepDirection;
462
+ min?: number | null;
463
+ max?: number | null;
464
+ step?: number | null;
465
+ isIntegerOnly: boolean;
466
+ }): number | null {
467
+ const effectiveStep = getEffectiveStep(step, isIntegerOnly);
468
+ const stepBase =
469
+ min != null && (!isIntegerOnly || Number.isInteger(min)) ? min : 0;
470
+
471
+ let nextValue: number;
472
+ if (currentValue == null) {
473
+ nextValue = direction === 1 ? (min ?? 0) : (max ?? 0);
474
+ if (isIntegerOnly) {
475
+ nextValue =
476
+ direction === 1 ? Math.ceil(nextValue) : Math.floor(nextValue);
477
+ }
478
+ } else {
479
+ const stepPosition = (currentValue - stepBase) / effectiveStep;
480
+ const tolerance = Number.EPSILON * Math.max(1, Math.abs(stepPosition)) * 4;
481
+ const nextStepPosition =
482
+ direction === 1
483
+ ? Math.floor(stepPosition + tolerance) + 1
484
+ : Math.ceil(stepPosition - tolerance) - 1;
485
+ nextValue = stepBase + nextStepPosition * effectiveStep;
486
+ }
487
+
488
+ if (min != null) {
489
+ nextValue = Math.max(min, nextValue);
490
+ }
491
+ if (max != null) {
492
+ nextValue = Math.min(max, nextValue);
493
+ }
494
+
495
+ if (!Number.isFinite(nextValue)) {
496
+ return currentValue;
497
+ }
498
+
499
+ const precision = Math.min(
500
+ 12,
501
+ Math.max(getDecimalPlaces(effectiveStep), getDecimalPlaces(stepBase)),
502
+ );
503
+ const roundedValue = Number(nextValue.toFixed(precision));
504
+ if (isIntegerOnly && !Number.isInteger(roundedValue)) {
505
+ return currentValue;
506
+ }
507
+ return Object.is(roundedValue, -0) ? 0 : roundedValue;
508
+ }
509
+
376
510
  /**
377
511
  * A number input component for collecting numeric user input.
378
512
  * Only calls onChange when the entered value passes validation.
@@ -390,6 +524,7 @@ export function NumberInput({
390
524
  isOptional = false,
391
525
  isRequired = false,
392
526
  isDisabled = false,
527
+ isReadOnly = false,
393
528
  disabledMessage,
394
529
  startIcon,
395
530
  labelIcon,
@@ -406,6 +541,9 @@ export function NumberInput({
406
541
  min,
407
542
  max,
408
543
  step,
544
+ formatValue,
545
+ isWheelEnabled = true,
546
+ hasNumberSteppers = false,
409
547
  units,
410
548
  isIntegerOnly = false,
411
549
  onFocus,
@@ -433,6 +571,7 @@ export function NumberInput({
433
571
 
434
572
  // Pending input while user is typing (null = show formatted value)
435
573
  const [pendingInput, setPendingInput] = useState<string | null>(null);
574
+ const [isFocused, setIsFocused] = useState(false);
436
575
 
437
576
  // Disabled-reason tooltip. Disabled controls swallow pointer events, so the
438
577
  // tooltip listeners attach to the input container (which already exists) and
@@ -473,8 +612,15 @@ export function NumberInput({
473
612
  inputGroup,
474
613
  );
475
614
 
476
- // Display value: pending input if typing, otherwise the raw value
477
- // Note: With type="number", we can't use formatted display values
615
+ const formattedValue = useMemo(() => {
616
+ if (value == null) {
617
+ return '';
618
+ }
619
+ return formatValue?.(value) ?? String(value);
620
+ }, [formatValue, value]);
621
+
622
+ // Preserve pending text while editing. Otherwise show the formatted value
623
+ // at rest and the raw numeric value while focused so it remains editable.
478
624
  const displayValue = useMemo(() => {
479
625
  if (pendingInput !== null) {
480
626
  return pendingInput;
@@ -482,8 +628,8 @@ export function NumberInput({
482
628
  if (value == null) {
483
629
  return '';
484
630
  }
485
- return String(value);
486
- }, [pendingInput, value]);
631
+ return isFocused ? String(value) : formattedValue;
632
+ }, [formattedValue, isFocused, pendingInput, value]);
487
633
 
488
634
  // Check if current pending input is valid (for styling purposes)
489
635
  const isInputValid = useMemo(() => {
@@ -499,7 +645,7 @@ export function NumberInput({
499
645
  // Value can't change while showing a disabled message (the field is
500
646
  // read-only and non-native-disabled), but guard the handler too so the
501
647
  // pending value and onChange never fire.
502
- if (isDisabled) {
648
+ if (isDisabled || isReadOnly) {
503
649
  return;
504
650
  }
505
651
  const newValue = e.target.value;
@@ -511,12 +657,13 @@ export function NumberInput({
511
657
  onChange(parsed);
512
658
  }
513
659
  },
514
- [value, onChange, min, max, isIntegerOnly, isDisabled],
660
+ [value, onChange, min, max, isIntegerOnly, isDisabled, isReadOnly],
515
661
  );
516
662
 
517
663
  // Handle focus
518
664
  const handleFocus = useCallback(
519
665
  (e: FocusEvent<HTMLInputElement>) => {
666
+ setIsFocused(true);
520
667
  onFocus?.(e);
521
668
  },
522
669
  [onFocus],
@@ -546,14 +693,69 @@ export function NumberInput({
546
693
 
547
694
  // Clear pending input - display will revert to formatted value
548
695
  setPendingInput(null);
696
+ setIsFocused(false);
549
697
  onBlur?.(e);
550
698
  },
551
699
  [pendingInput, value, onChange, min, max, isIntegerOnly, onBlur, hasClear],
552
700
  );
553
701
 
702
+ const valueForStepping = useMemo(() => {
703
+ if (pendingInput === null) {
704
+ return value ?? null;
705
+ }
706
+ if (pendingInput.trim() === '') {
707
+ return null;
708
+ }
709
+ return (
710
+ parseNumberInput(pendingInput, {min, max, isIntegerOnly}) ?? value ?? null
711
+ );
712
+ }, [isIntegerOnly, max, min, pendingInput, value]);
713
+
714
+ const getNextValue = useCallback(
715
+ (direction: StepDirection) =>
716
+ getSteppedValue({
717
+ currentValue: valueForStepping,
718
+ direction,
719
+ min,
720
+ max,
721
+ step,
722
+ isIntegerOnly,
723
+ }),
724
+ [isIntegerOnly, max, min, step, valueForStepping],
725
+ );
726
+
727
+ const stepValue = useCallback(
728
+ (direction: StepDirection) => {
729
+ // A read-only field is not steppable by any route: keyboard, wheel, or
730
+ // the stepper buttons all land here.
731
+ if (isDisabled || isReadOnly) {
732
+ return;
733
+ }
734
+ const nextValue = getNextValue(direction);
735
+ if (nextValue == null) {
736
+ return;
737
+ }
738
+ setPendingInput(null);
739
+ if (nextValue !== value) {
740
+ onChange(nextValue);
741
+ }
742
+ },
743
+ [getNextValue, isDisabled, isReadOnly, onChange, value],
744
+ );
745
+
554
746
  // Handle keyboard events
555
747
  const handleKeyDown = useCallback(
556
748
  (e: KeyboardEvent<HTMLInputElement>) => {
749
+ const hasModifier = e.altKey || e.ctrlKey || e.metaKey || e.shiftKey;
750
+ if (!hasModifier && (e.key === 'ArrowUp' || e.key === 'ArrowDown')) {
751
+ onKeyDown?.(e);
752
+ if (e.defaultPrevented) {
753
+ return;
754
+ }
755
+ e.preventDefault();
756
+ stepValue(e.key === 'ArrowUp' ? 1 : -1);
757
+ return;
758
+ }
557
759
  if (e.key === 'Enter') {
558
760
  // Validate and commit on Enter
559
761
  if (pendingInput !== null) {
@@ -588,18 +790,52 @@ export function NumberInput({
588
790
  onEnter,
589
791
  onKeyDown,
590
792
  hasClear,
793
+ stepValue,
591
794
  ],
592
795
  );
593
796
 
594
- // While focused, a wheel gesture steps the value keep that gesture from
595
- // also bubbling up and scrolling an ancestor container (page, Dialog,
596
- // ScrollArea). When the input isn't focused the wheel isn't stepping the
597
- // value, so normal scrolling is left alone.
598
- const handleWheel = useCallback((e: React.WheelEvent<HTMLInputElement>) => {
599
- if (document.activeElement === e.currentTarget) {
600
- e.stopPropagation();
601
- }
602
- }, []);
797
+ // React's delegated wheel listener can be passive, so use a native,
798
+ // explicitly non-passive listener to prevent page scrolling only when this
799
+ // focused input is intentionally consuming the gesture to step its value.
800
+ const wheelListenerRef = useCallback(
801
+ (input: HTMLInputElement | null) => {
802
+ if (input == null || !isWheelEnabled) {
803
+ return;
804
+ }
805
+
806
+ const handleWheel = (event: WheelEvent) => {
807
+ // Bail before preventDefault so a read-only input never swallows the
808
+ // page scroll it cannot act on.
809
+ if (
810
+ document.activeElement !== input ||
811
+ isDisabled ||
812
+ isReadOnly ||
813
+ event.deltaY === 0 ||
814
+ event.altKey ||
815
+ event.ctrlKey ||
816
+ event.metaKey ||
817
+ event.shiftKey
818
+ ) {
819
+ return;
820
+ }
821
+ event.preventDefault();
822
+ event.stopPropagation();
823
+ stepValue(event.deltaY < 0 ? 1 : -1);
824
+ };
825
+
826
+ input.addEventListener('wheel', handleWheel, {passive: false});
827
+ return () => input.removeEventListener('wheel', handleWheel);
828
+ },
829
+ [isDisabled, isReadOnly, isWheelEnabled, stepValue],
830
+ );
831
+
832
+ const mergedInputRef = useMemo(
833
+ () => mergeRefs(ref, inputRef, wheelListenerRef),
834
+ [ref, wheelListenerRef],
835
+ );
836
+
837
+ const canIncrement = getNextValue(1) !== valueForStepping;
838
+ const canDecrement = getNextValue(-1) !== valueForStepping;
603
839
 
604
840
  // Handle clear button click
605
841
  const handleClear = useCallback(() => {
@@ -630,10 +866,16 @@ export function NumberInput({
630
866
  onClick={handleWrapperClick}
631
867
  onMouseUp={handleWrapperMouseUp}
632
868
  {...mergeProps(
633
- themeProps('number-input', {size, status: status?.type ?? null}),
869
+ themeProps('number-input', {
870
+ size,
871
+ status: status?.type ?? null,
872
+ disabled: isDisabled ? 'disabled' : null,
873
+ readonly: isReadOnly ? 'readonly' : null,
874
+ }),
634
875
  stylex.props(
635
876
  inputWrapperStyles.base,
636
877
  styles.wrapper,
878
+ hasNumberSteppers && styles.wrapperWithNumberSteppers,
637
879
  sizeStyles[size],
638
880
  isDisabled && inputWrapperStyles.disabled,
639
881
  status && inputStatusBorderStyles[status.type],
@@ -649,29 +891,33 @@ export function NumberInput({
649
891
  {inputGroup && <VisuallyHidden id={inputLabelID}>{label}</VisuallyHidden>}
650
892
  <input
651
893
  {...rest}
652
- ref={mergeRefs(ref, inputRef)}
894
+ ref={mergedInputRef}
653
895
  id={id}
654
- name={htmlName}
655
- type="number"
896
+ name={isDisabled || formatValue ? undefined : htmlName}
897
+ type="text"
898
+ inputMode={isIntegerOnly ? 'numeric' : 'decimal'}
899
+ role="spinbutton"
656
900
  autoComplete={autoComplete}
657
901
  value={displayValue}
658
902
  onChange={handleInputChange}
659
903
  onFocus={handleFocus}
660
904
  onBlur={handleBlur}
661
905
  onKeyDown={handleKeyDown}
662
- onWheel={handleWheel}
663
906
  placeholder={placeholder}
664
907
  // With a disabledMessage the input keeps focusability via aria-disabled
665
908
  // so the reason is focus-discoverable; readOnly + the handler guards
666
909
  // keep the value from changing.
667
910
  disabled={isDisabled && !showsDisabledMessage}
668
911
  aria-disabled={showsDisabledMessage ? 'true' : undefined}
669
- readOnly={showsDisabledMessage || undefined}
912
+ readOnly={isReadOnly || showsDisabledMessage || undefined}
670
913
  autoFocus={hasAutoFocus}
671
914
  data-autofocus={hasAutoFocus || undefined}
672
- min={min ?? undefined}
673
- max={max ?? undefined}
674
- step={step ?? undefined}
915
+ aria-valuemin={min ?? undefined}
916
+ aria-valuemax={max ?? undefined}
917
+ aria-valuenow={value ?? undefined}
918
+ aria-valuetext={
919
+ value == null || !formatValue ? undefined : formattedValue
920
+ }
675
921
  aria-describedby={ariaDescribedBy}
676
922
  aria-required={isRequired === true ? 'true' : undefined}
677
923
  aria-invalid={
@@ -684,6 +930,13 @@ export function NumberInput({
684
930
  !isInputValid && styles.inputInvalid,
685
931
  )}
686
932
  />
933
+ {formatValue && htmlName && !isDisabled && (
934
+ <input
935
+ type="hidden"
936
+ name={htmlName}
937
+ value={value == null ? '' : String(value)}
938
+ />
939
+ )}
687
940
  {units && (
688
941
  <span id={unitsID} {...stylex.props(styles.units)}>
689
942
  {units}
@@ -697,16 +950,57 @@ export function NumberInput({
697
950
  <VisuallyHidden as="div" role="alert" aria-live="assertive">
698
951
  {!isInputValid ? 'Invalid number' : ''}
699
952
  </VisuallyHidden>
700
- {hasClear && value != null && !isDisabled && (
701
- <button
702
- type="button"
953
+ {hasClear && value != null && !isDisabled && !isReadOnly && (
954
+ <InputClearButton
955
+ label={t('@astryx.numberInput.clearLabel', {label})}
703
956
  onClick={handleClear}
704
- aria-label={t('@astryx.numberInput.clearLabel', {label})}
705
- {...stylex.props(styles.clearButton)}>
706
- <Icon icon="close" size="sm" color="secondary" />
707
- </button>
957
+ />
708
958
  )}
709
959
  {statusIcon}
960
+ {hasNumberSteppers && (
961
+ <div {...stylex.props(styles.numberSteppers)}>
962
+ <button
963
+ type="button"
964
+ tabIndex={-1}
965
+ disabled={isDisabled || isReadOnly || !canIncrement}
966
+ aria-label={t('@astryx.numberInput.incrementLabel', {label})}
967
+ onPointerDown={event => event.preventDefault()}
968
+ onClick={() => {
969
+ inputRef.current?.focus();
970
+ stepValue(1);
971
+ }}
972
+ {...stylex.props(
973
+ styles.numberStepperButton,
974
+ (isDisabled || isReadOnly || !canIncrement) &&
975
+ styles.numberStepperButtonDisabled,
976
+ )}>
977
+ <Icon
978
+ icon="chevronDown"
979
+ size="xsm"
980
+ color="inherit"
981
+ xstyle={styles.incrementIcon}
982
+ />
983
+ </button>
984
+ <button
985
+ type="button"
986
+ tabIndex={-1}
987
+ disabled={isDisabled || isReadOnly || !canDecrement}
988
+ aria-label={t('@astryx.numberInput.decrementLabel', {label})}
989
+ onPointerDown={event => event.preventDefault()}
990
+ onClick={() => {
991
+ inputRef.current?.focus();
992
+ stepValue(-1);
993
+ }}
994
+ {...stylex.props(
995
+ styles.numberStepperButton,
996
+ styles.decrementButton,
997
+ (isDisabled || isReadOnly || !canDecrement) &&
998
+ styles.numberStepperButtonDisabled,
999
+ )}>
1000
+ <Icon icon="chevronDown" size="xsm" color="inherit" />
1001
+ </button>
1002
+ </div>
1003
+ )}
710
1004
  </div>
711
1005
  );
712
1006
 
@@ -42,6 +42,7 @@ import type {BaseProps} from '../BaseProps';
42
42
  import {useScrollSpy} from './useScrollSpy';
43
43
  import type {OutlineItem} from './types';
44
44
  import {themeProps} from '../utils/themeProps';
45
+ import {focusOutlineProps} from '../utils/focusOutline.stylex';
45
46
  import {useTranslator} from '../i18n';
46
47
 
47
48
  export type {OutlineItem} from './types';
@@ -211,10 +212,6 @@ const styles = stylex.create({
211
212
  ':active': {
212
213
  backgroundColor: colorVars['--color-overlay-pressed'],
213
214
  },
214
- ':focus-visible': {
215
- outline: `2px solid ${colorVars['--color-accent']}`,
216
- outlineOffset: 2,
217
- },
218
215
  },
219
216
  activeLink: {
220
217
  color: colorVars['--color-text-primary'],
@@ -473,7 +470,7 @@ export function Outline({
473
470
  active: isActive ? 'active' : null,
474
471
  level: item.level,
475
472
  }),
476
- stylex.props(
473
+ focusOutlineProps.focusVisible(
477
474
  styles.link,
478
475
  densityStyles[density],
479
476
  getIndentStyle(item.level),
@@ -66,7 +66,7 @@ export const docs = {
66
66
  name: 'variant',
67
67
  type: "'pages' | 'count' | 'compact' | 'dots' | 'input' | 'none'",
68
68
  description:
69
- "Visual variant controlling what appears between prev/next buttons. 'pages' shows page number buttons with ellipsis, 'count' shows 'X-Y of Z' text, 'compact' shows 'Page X of Y', 'dots' shows dot indicators, 'input' shows an editable page-number box with a leading label 'Page [ n ] / N' flanked by first/last buttons by default (the box needs a known total to clamp against, so it is disabled in cursor/hasMore mode), 'none' shows just prev/next buttons.",
69
+ "Visual variant controlling what appears between prev/next buttons. 'pages' shows page number buttons with ellipsis, 'count' shows 'X-Y of Z' text, 'compact' shows 'Page X of Y', 'dots' shows dot indicators, 'input' shows an editable page-number box with a leading label ('Page [ n ] / N') flanked by first/last buttons by default (the box needs a known total to clamp against, so it is disabled in cursor/hasMore mode), 'none' shows just prev/next buttons.",
70
70
  default: "'pages'",
71
71
  },
72
72
  {