@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
@@ -73,21 +73,21 @@ describe('NumberInput', () => {
73
73
  expect(screen.getByPlaceholderText('Enter number')).toBeInTheDocument();
74
74
  });
75
75
 
76
- it('displays controlled value as number', () => {
76
+ it('displays the controlled value as editable text', () => {
77
77
  render(<NumberInput label="Quantity" value={456} onChange={() => {}} />);
78
- expect(screen.getByRole('spinbutton')).toHaveValue(456);
78
+ expect(screen.getByRole('spinbutton')).toHaveValue('456');
79
79
  });
80
80
 
81
- it('displays null for null value', () => {
81
+ it('displays an empty string for a null value', () => {
82
82
  render(<NumberInput label="Quantity" value={null} onChange={() => {}} />);
83
- expect(screen.getByRole('spinbutton')).toHaveValue(null);
83
+ expect(screen.getByRole('spinbutton')).toHaveValue('');
84
84
  });
85
85
 
86
- it('displays null for undefined value', () => {
86
+ it('displays an empty string for an undefined value', () => {
87
87
  render(
88
88
  <NumberInput label="Quantity" value={undefined} onChange={() => {}} />,
89
89
  );
90
- expect(screen.getByRole('spinbutton')).toHaveValue(null);
90
+ expect(screen.getByRole('spinbutton')).toHaveValue('');
91
91
  });
92
92
 
93
93
  it('forwards ref correctly', () => {
@@ -198,31 +198,127 @@ describe('NumberInput', () => {
198
198
  expect(container.querySelector('svg')).not.toBeInTheDocument();
199
199
  });
200
200
 
201
- describe('native number input attributes', () => {
202
- it('sets min attribute', () => {
201
+ describe('text-backed spinbutton attributes', () => {
202
+ it('uses a text input with decimal input mode by default', () => {
203
+ render(<NumberInput label="Price" value={5} onChange={() => {}} />);
204
+ const input = screen.getByRole('spinbutton');
205
+ expect(input).toHaveAttribute('type', 'text');
206
+ expect(input).toHaveAttribute('inputmode', 'decimal');
207
+ });
208
+
209
+ it('uses numeric input mode for integer-only values', () => {
210
+ render(
211
+ <NumberInput
212
+ label="Count"
213
+ value={5}
214
+ onChange={() => {}}
215
+ isIntegerOnly
216
+ />,
217
+ );
218
+ expect(screen.getByRole('spinbutton')).toHaveAttribute(
219
+ 'inputmode',
220
+ 'numeric',
221
+ );
222
+ });
223
+
224
+ it('exposes the minimum through spinbutton ARIA', () => {
203
225
  render(
204
226
  <NumberInput label="Age" value={null} onChange={() => {}} min={0} />,
205
227
  );
206
- expect(screen.getByRole('spinbutton')).toHaveAttribute('min', '0');
228
+ expect(screen.getByRole('spinbutton')).toHaveAttribute(
229
+ 'aria-valuemin',
230
+ '0',
231
+ );
207
232
  });
208
233
 
209
- it('sets max attribute', () => {
234
+ it('exposes the maximum through spinbutton ARIA', () => {
210
235
  render(
211
236
  <NumberInput label="Age" value={null} onChange={() => {}} max={120} />,
212
237
  );
213
- expect(screen.getByRole('spinbutton')).toHaveAttribute('max', '120');
238
+ expect(screen.getByRole('spinbutton')).toHaveAttribute(
239
+ 'aria-valuemax',
240
+ '120',
241
+ );
242
+ });
243
+
244
+ it('exposes the current value through spinbutton ARIA', () => {
245
+ render(<NumberInput label="Age" value={42} onChange={() => {}} />);
246
+ expect(screen.getByRole('spinbutton')).toHaveAttribute(
247
+ 'aria-valuenow',
248
+ '42',
249
+ );
250
+ });
251
+ });
252
+
253
+ describe('formatted display values', () => {
254
+ it('shows the formatted value at rest and exposes it to assistive technology', () => {
255
+ render(
256
+ <NumberInput
257
+ label="Revenue"
258
+ value={1234}
259
+ onChange={() => {}}
260
+ formatValue={number => `$${number.toLocaleString('en-US')}`}
261
+ />,
262
+ );
263
+ const input = screen.getByRole('spinbutton');
264
+ expect(input).toHaveValue('$1,234');
265
+ expect(input).toHaveAttribute('aria-valuetext', '$1,234');
266
+ expect(input).toHaveAttribute('aria-valuenow', '1234');
267
+ });
268
+
269
+ it('shows the raw numeric value while focused and restores formatting on blur', () => {
270
+ render(
271
+ <NumberInput
272
+ label="Revenue"
273
+ value={1234}
274
+ onChange={() => {}}
275
+ formatValue={number => `$${number.toLocaleString('en-US')}`}
276
+ />,
277
+ );
278
+ const input = screen.getByRole('spinbutton');
279
+
280
+ fireEvent.focus(input);
281
+ expect(input).toHaveValue('1234');
282
+
283
+ fireEvent.blur(input);
284
+ expect(input).toHaveValue('$1,234');
214
285
  });
215
286
 
216
- it('sets step attribute', () => {
287
+ it('preserves invalid pending text while focused, then restores the formatted true value', () => {
288
+ const onChange = vi.fn();
217
289
  render(
218
290
  <NumberInput
219
- label="Price"
291
+ label="Quantity"
292
+ value={3}
293
+ onChange={onChange}
294
+ isIntegerOnly
295
+ formatValue={number => `${number} items`}
296
+ />,
297
+ );
298
+ const input = screen.getByRole('spinbutton');
299
+
300
+ fireEvent.focus(input);
301
+ fireEvent.change(input, {target: {value: '3.5'}});
302
+ expect(input).toHaveValue('3.5');
303
+ expect(input).toHaveAttribute('aria-invalid', 'true');
304
+ expect(onChange).not.toHaveBeenCalledWith(3.5);
305
+
306
+ fireEvent.blur(input);
307
+ expect(input).toHaveValue('3 items');
308
+ });
309
+
310
+ it('does not call the formatter for an empty value', () => {
311
+ const formatValue = vi.fn((number: number) => String(number));
312
+ render(
313
+ <NumberInput
314
+ label="Quantity"
220
315
  value={null}
221
316
  onChange={() => {}}
222
- step={0.01}
317
+ formatValue={formatValue}
223
318
  />,
224
319
  );
225
- expect(screen.getByRole('spinbutton')).toHaveAttribute('step', '0.01');
320
+ expect(screen.getByRole('spinbutton')).toHaveValue('');
321
+ expect(formatValue).not.toHaveBeenCalled();
226
322
  });
227
323
  });
228
324
 
@@ -687,6 +783,239 @@ describe('NumberInput', () => {
687
783
  });
688
784
  });
689
785
 
786
+ describe('form participation', () => {
787
+ it('submits the value under htmlName', () => {
788
+ const {container} = render(
789
+ <form>
790
+ <NumberInput
791
+ label="Quantity"
792
+ htmlName="quantity"
793
+ value={42}
794
+ onChange={() => {}}
795
+ />
796
+ </form>,
797
+ );
798
+ const data = new FormData(container.querySelector('form')!);
799
+ expect(data.get('quantity')).toBe('42');
800
+ });
801
+
802
+ it('submits the raw number instead of the formatted display value', () => {
803
+ const {container} = render(
804
+ <form>
805
+ <NumberInput
806
+ label="Revenue"
807
+ htmlName="revenue"
808
+ value={1234}
809
+ onChange={() => {}}
810
+ formatValue={number => `$${number.toLocaleString('en-US')}`}
811
+ />
812
+ </form>,
813
+ );
814
+ const data = new FormData(container.querySelector('form')!);
815
+ expect(data.get('revenue')).toBe('1234');
816
+ });
817
+
818
+ it('is excluded from form data when disabled', () => {
819
+ const {container} = render(
820
+ <form>
821
+ <NumberInput
822
+ label="Quantity"
823
+ htmlName="quantity"
824
+ value={42}
825
+ onChange={() => {}}
826
+ isDisabled
827
+ />
828
+ </form>,
829
+ );
830
+ expect([
831
+ ...new FormData(container.querySelector('form')!).keys(),
832
+ ]).toEqual([]);
833
+ });
834
+
835
+ // Regression: a disabledMessage swaps the native `disabled` attribute for
836
+ // aria-disabled + readOnly so the reason stays focus-discoverable, but
837
+ // read-only fields still submit — the name has to be withheld too.
838
+ it('is excluded from form data when disabled, even with a disabledMessage', () => {
839
+ const {container} = render(
840
+ <form>
841
+ <NumberInput
842
+ label="Quantity"
843
+ htmlName="quantity"
844
+ value={42}
845
+ onChange={() => {}}
846
+ isDisabled
847
+ disabledMessage="Quantity is fixed by the contract"
848
+ />
849
+ </form>,
850
+ );
851
+ expect([
852
+ ...new FormData(container.querySelector('form')!).keys(),
853
+ ]).toEqual([]);
854
+ });
855
+ });
856
+
857
+ describe('isReadOnly', () => {
858
+ it('marks the input read-only', () => {
859
+ render(
860
+ <NumberInput
861
+ label="Quantity"
862
+ value={42}
863
+ onChange={() => {}}
864
+ isReadOnly
865
+ />,
866
+ );
867
+ expect(screen.getByRole('spinbutton')).toHaveAttribute('readonly');
868
+ });
869
+
870
+ it('still submits its value with the form', () => {
871
+ const {container} = render(
872
+ <form>
873
+ <NumberInput
874
+ label="Quantity"
875
+ htmlName="quantity"
876
+ value={42}
877
+ onChange={() => {}}
878
+ isReadOnly
879
+ />
880
+ </form>,
881
+ );
882
+ expect(
883
+ new FormData(container.querySelector('form')!).get('quantity'),
884
+ ).toBe('42');
885
+ });
886
+
887
+ it('does not call onChange when the user types', async () => {
888
+ const user = userEvent.setup();
889
+ const handleChange = vi.fn();
890
+ render(
891
+ <NumberInput
892
+ label="Quantity"
893
+ value={42}
894
+ onChange={handleChange}
895
+ isReadOnly
896
+ />,
897
+ );
898
+ await user.type(screen.getByRole('spinbutton'), '7');
899
+ expect(handleChange).not.toHaveBeenCalled();
900
+ });
901
+
902
+ it('stays focusable and is not disabled', async () => {
903
+ const user = userEvent.setup();
904
+ render(
905
+ <NumberInput
906
+ label="Quantity"
907
+ value={42}
908
+ onChange={() => {}}
909
+ isReadOnly
910
+ />,
911
+ );
912
+ const input = screen.getByRole('spinbutton');
913
+ expect(input).not.toBeDisabled();
914
+ await user.tab();
915
+ expect(input).toHaveFocus();
916
+ });
917
+
918
+ it('hides the clear button', () => {
919
+ render(
920
+ <NumberInput
921
+ label="Quantity"
922
+ value={42}
923
+ onChange={() => {}}
924
+ hasClear
925
+ isReadOnly
926
+ />,
927
+ );
928
+ expect(screen.queryByRole('button')).not.toBeInTheDocument();
929
+ });
930
+
931
+ it('does not step on ArrowUp or ArrowDown', async () => {
932
+ const user = userEvent.setup();
933
+ const handleChange = vi.fn();
934
+ render(
935
+ <NumberInput
936
+ label="Quantity"
937
+ value={42}
938
+ onChange={handleChange}
939
+ isReadOnly
940
+ />,
941
+ );
942
+ const input = screen.getByRole('spinbutton');
943
+ input.focus();
944
+ await user.keyboard('{ArrowUp}{ArrowDown}');
945
+ expect(handleChange).not.toHaveBeenCalled();
946
+ expect(input).toHaveValue('42');
947
+ });
948
+
949
+ it('leaves wheel scrolling to the page instead of stepping', () => {
950
+ const onScrollableWheel = vi.fn();
951
+ const handleChange = vi.fn();
952
+ render(
953
+ <div onWheel={onScrollableWheel}>
954
+ <NumberInput
955
+ label="Quantity"
956
+ value={42}
957
+ onChange={handleChange}
958
+ isReadOnly
959
+ />
960
+ </div>,
961
+ );
962
+ const input = screen.getByRole('spinbutton');
963
+ input.focus();
964
+ const event = new WheelEvent('wheel', {
965
+ bubbles: true,
966
+ cancelable: true,
967
+ deltaY: -100,
968
+ });
969
+ fireEvent(input, event);
970
+
971
+ expect(handleChange).not.toHaveBeenCalled();
972
+ expect(event.defaultPrevented).toBe(false);
973
+ expect(onScrollableWheel).toHaveBeenCalledTimes(1);
974
+ });
975
+
976
+ it('disables both number steppers', () => {
977
+ const handleChange = vi.fn();
978
+ render(
979
+ <NumberInput
980
+ label="Quantity"
981
+ value={42}
982
+ onChange={handleChange}
983
+ hasNumberSteppers
984
+ isReadOnly
985
+ />,
986
+ );
987
+ const increment = screen.getByRole('button', {
988
+ name: 'Increment Quantity',
989
+ });
990
+ expect(increment).toBeDisabled();
991
+ expect(
992
+ screen.getByRole('button', {name: 'Decrement Quantity'}),
993
+ ).toBeDisabled();
994
+
995
+ fireEvent.click(increment);
996
+ expect(handleChange).not.toHaveBeenCalled();
997
+ });
998
+
999
+ it('lets isDisabled win when both are set', () => {
1000
+ const {container} = render(
1001
+ <form>
1002
+ <NumberInput
1003
+ label="Quantity"
1004
+ htmlName="quantity"
1005
+ value={42}
1006
+ onChange={() => {}}
1007
+ isReadOnly
1008
+ isDisabled
1009
+ />
1010
+ </form>,
1011
+ );
1012
+ expect(screen.getByRole('spinbutton')).toBeDisabled();
1013
+ expect([
1014
+ ...new FormData(container.querySelector('form')!).keys(),
1015
+ ]).toEqual([]);
1016
+ });
1017
+ });
1018
+
690
1019
  describe('autoComplete prop', () => {
691
1020
  it('sets autocomplete attribute when autoComplete is provided', () => {
692
1021
  render(
@@ -996,29 +1325,405 @@ describe('NumberInput statusVariant forwarding', () => {
996
1325
  'detached',
997
1326
  );
998
1327
  });
1328
+ });
1329
+
1330
+ describe('NumberInput stepping', () => {
1331
+ it('increments with ArrowUp and decrements with ArrowDown', () => {
1332
+ const onChange = vi.fn();
1333
+ render(<NumberInput label="Amount" value={5} onChange={onChange} />);
1334
+ const input = screen.getByRole('spinbutton');
1335
+
1336
+ fireEvent.keyDown(input, {key: 'ArrowUp'});
1337
+ expect(onChange).toHaveBeenLastCalledWith(6);
1338
+
1339
+ fireEvent.keyDown(input, {key: 'ArrowDown'});
1340
+ expect(onChange).toHaveBeenLastCalledWith(4);
1341
+ });
1342
+
1343
+ it('lets onKeyDown cancel keyboard stepping', () => {
1344
+ const onChange = vi.fn();
1345
+ const onKeyDown = vi.fn((event: React.KeyboardEvent<HTMLInputElement>) =>
1346
+ event.preventDefault(),
1347
+ );
1348
+ render(
1349
+ <NumberInput
1350
+ label="Amount"
1351
+ value={5}
1352
+ onChange={onChange}
1353
+ onKeyDown={onKeyDown}
1354
+ />,
1355
+ );
1356
+ fireEvent.keyDown(screen.getByRole('spinbutton'), {key: 'ArrowUp'});
1357
+
1358
+ expect(onKeyDown).toHaveBeenCalledTimes(1);
1359
+ expect(onChange).not.toHaveBeenCalled();
1360
+ });
1361
+
1362
+ it('uses decimal-safe step arithmetic', () => {
1363
+ const onChange = vi.fn();
1364
+ render(
1365
+ <NumberInput label="Amount" value={0.2} onChange={onChange} step={0.1} />,
1366
+ );
1367
+ fireEvent.keyDown(screen.getByRole('spinbutton'), {key: 'ArrowUp'});
1368
+ expect(onChange).toHaveBeenCalledWith(0.3);
1369
+ });
1370
+
1371
+ it('aligns an off-step value in the requested direction', () => {
1372
+ const onChange = vi.fn();
1373
+ render(
1374
+ <NumberInput
1375
+ label="Amount"
1376
+ value={0.25}
1377
+ onChange={onChange}
1378
+ step={0.1}
1379
+ />,
1380
+ );
1381
+ const input = screen.getByRole('spinbutton');
1382
+
1383
+ fireEvent.keyDown(input, {key: 'ArrowUp'});
1384
+ expect(onChange).toHaveBeenLastCalledWith(0.3);
1385
+
1386
+ fireEvent.keyDown(input, {key: 'ArrowDown'});
1387
+ expect(onChange).toHaveBeenLastCalledWith(0.2);
1388
+ });
1389
+
1390
+ it('starts an empty value at the relevant boundary', () => {
1391
+ const onChange = vi.fn();
1392
+ const {rerender} = render(
1393
+ <NumberInput label="Amount" value={null} onChange={onChange} min={2} />,
1394
+ );
1395
+ fireEvent.keyDown(screen.getByRole('spinbutton'), {key: 'ArrowUp'});
1396
+ expect(onChange).toHaveBeenLastCalledWith(2);
1397
+
1398
+ rerender(
1399
+ <NumberInput label="Amount" value={null} onChange={onChange} max={8} />,
1400
+ );
1401
+ fireEvent.keyDown(screen.getByRole('spinbutton'), {key: 'ArrowDown'});
1402
+ expect(onChange).toHaveBeenLastCalledWith(8);
1403
+ });
1404
+
1405
+ it('keeps generated values integral when isIntegerOnly is set', () => {
1406
+ const onChange = vi.fn();
1407
+ render(
1408
+ <NumberInput
1409
+ label="Amount"
1410
+ value={null}
1411
+ onChange={onChange}
1412
+ min={2.5}
1413
+ isIntegerOnly
1414
+ />,
1415
+ );
1416
+ fireEvent.keyDown(screen.getByRole('spinbutton'), {key: 'ArrowUp'});
1417
+ expect(onChange).toHaveBeenCalledWith(3);
1418
+ });
1419
+
1420
+ it('does not step past min or max', () => {
1421
+ const onChange = vi.fn();
1422
+ const {rerender} = render(
1423
+ <NumberInput
1424
+ label="Amount"
1425
+ value={10}
1426
+ onChange={onChange}
1427
+ min={0}
1428
+ max={10}
1429
+ />,
1430
+ );
1431
+ fireEvent.keyDown(screen.getByRole('spinbutton'), {key: 'ArrowUp'});
1432
+ expect(onChange).not.toHaveBeenCalled();
1433
+
1434
+ rerender(
1435
+ <NumberInput
1436
+ label="Amount"
1437
+ value={0}
1438
+ onChange={onChange}
1439
+ min={0}
1440
+ max={10}
1441
+ />,
1442
+ );
1443
+ fireEvent.keyDown(screen.getByRole('spinbutton'), {key: 'ArrowDown'});
1444
+ expect(onChange).not.toHaveBeenCalled();
1445
+ });
999
1446
 
1000
- it('stops wheel propagation while focused so ancestor containers do not scroll', () => {
1447
+ it('allows wheel stepping by default and consumes the focused gesture', () => {
1001
1448
  const onScrollableWheel = vi.fn();
1449
+ const onChange = vi.fn();
1002
1450
  render(
1003
1451
  <div onWheel={onScrollableWheel}>
1004
- <NumberInput label="Amount" value={5} onChange={() => {}} />
1452
+ <NumberInput label="Amount" value={5} onChange={onChange} />
1005
1453
  </div>,
1006
1454
  );
1007
1455
  const input = screen.getByRole('spinbutton');
1008
1456
  input.focus();
1009
- fireEvent.wheel(input, {deltaY: 100});
1457
+ const event = new WheelEvent('wheel', {
1458
+ bubbles: true,
1459
+ cancelable: true,
1460
+ deltaY: -100,
1461
+ });
1462
+ fireEvent(input, event);
1463
+
1464
+ expect(onChange).toHaveBeenCalledWith(6);
1465
+ expect(event.defaultPrevented).toBe(true);
1010
1466
  expect(onScrollableWheel).not.toHaveBeenCalled();
1011
1467
  });
1012
1468
 
1013
- it('does not stop wheel propagation when the input is not focused', () => {
1469
+ it('leaves wheel scrolling alone when isWheelEnabled is false', () => {
1470
+ const onScrollableWheel = vi.fn();
1471
+ const onChange = vi.fn();
1472
+ render(
1473
+ <div onWheel={onScrollableWheel}>
1474
+ <NumberInput
1475
+ label="Amount"
1476
+ value={5}
1477
+ onChange={onChange}
1478
+ isWheelEnabled={false}
1479
+ />
1480
+ </div>,
1481
+ );
1482
+ const input = screen.getByRole('spinbutton');
1483
+ input.focus();
1484
+ const event = new WheelEvent('wheel', {
1485
+ bubbles: true,
1486
+ cancelable: true,
1487
+ deltaY: -100,
1488
+ });
1489
+ fireEvent(input, event);
1490
+
1491
+ expect(onChange).not.toHaveBeenCalled();
1492
+ expect(event.defaultPrevented).toBe(false);
1493
+ expect(onScrollableWheel).toHaveBeenCalledTimes(1);
1494
+ });
1495
+
1496
+ it('updates the wheel listener when isWheelEnabled changes', () => {
1497
+ const onScrollableWheel = vi.fn();
1498
+ const onChange = vi.fn();
1499
+ const {rerender} = render(
1500
+ <div onWheel={onScrollableWheel}>
1501
+ <NumberInput
1502
+ label="Amount"
1503
+ value={5}
1504
+ onChange={onChange}
1505
+ isWheelEnabled={false}
1506
+ />
1507
+ </div>,
1508
+ );
1509
+ const input = screen.getByRole('spinbutton');
1510
+ input.focus();
1511
+
1512
+ rerender(
1513
+ <div onWheel={onScrollableWheel}>
1514
+ <NumberInput
1515
+ label="Amount"
1516
+ value={5}
1517
+ onChange={onChange}
1518
+ isWheelEnabled
1519
+ />
1520
+ </div>,
1521
+ );
1522
+ fireEvent.wheel(input, {deltaY: -100});
1523
+ expect(onChange).toHaveBeenCalledWith(6);
1524
+ expect(onScrollableWheel).not.toHaveBeenCalled();
1525
+
1526
+ onChange.mockClear();
1527
+ rerender(
1528
+ <div onWheel={onScrollableWheel}>
1529
+ <NumberInput
1530
+ label="Amount"
1531
+ value={5}
1532
+ onChange={onChange}
1533
+ isWheelEnabled={false}
1534
+ />
1535
+ </div>,
1536
+ );
1537
+ fireEvent.wheel(input, {deltaY: -100});
1538
+ expect(onChange).not.toHaveBeenCalled();
1539
+ expect(onScrollableWheel).toHaveBeenCalledTimes(1);
1540
+ });
1541
+
1542
+ it('leaves wheel scrolling alone when the input is not focused', () => {
1543
+ const onScrollableWheel = vi.fn();
1544
+ const onChange = vi.fn();
1545
+ render(
1546
+ <div onWheel={onScrollableWheel}>
1547
+ <NumberInput label="Amount" value={5} onChange={onChange} />
1548
+ </div>,
1549
+ );
1550
+ const input = screen.getByRole('spinbutton');
1551
+ const event = new WheelEvent('wheel', {
1552
+ bubbles: true,
1553
+ cancelable: true,
1554
+ deltaY: 100,
1555
+ });
1556
+ fireEvent(input, event);
1557
+
1558
+ expect(onChange).not.toHaveBeenCalled();
1559
+ expect(event.defaultPrevented).toBe(false);
1560
+ expect(onScrollableWheel).toHaveBeenCalledTimes(1);
1561
+ });
1562
+
1563
+ it('leaves modified wheel gestures alone', () => {
1564
+ const onScrollableWheel = vi.fn();
1565
+ const onChange = vi.fn();
1566
+ render(
1567
+ <div onWheel={onScrollableWheel}>
1568
+ <NumberInput label="Amount" value={5} onChange={onChange} />
1569
+ </div>,
1570
+ );
1571
+ const input = screen.getByRole('spinbutton');
1572
+ input.focus();
1573
+ fireEvent.wheel(input, {deltaY: -100, ctrlKey: true});
1574
+
1575
+ expect(onChange).not.toHaveBeenCalled();
1576
+ expect(onScrollableWheel).toHaveBeenCalledTimes(1);
1577
+ });
1578
+
1579
+ it('leaves wheel scrolling alone when the input is aria-disabled', () => {
1014
1580
  const onScrollableWheel = vi.fn();
1581
+ const onChange = vi.fn();
1015
1582
  render(
1016
1583
  <div onWheel={onScrollableWheel}>
1017
- <NumberInput label="Amount" value={5} onChange={() => {}} />
1584
+ <NumberInput
1585
+ label="Amount"
1586
+ value={5}
1587
+ onChange={onChange}
1588
+ isDisabled
1589
+ disabledMessage="This value is locked"
1590
+ />
1018
1591
  </div>,
1019
1592
  );
1020
1593
  const input = screen.getByRole('spinbutton');
1021
- fireEvent.wheel(input, {deltaY: 100});
1594
+ input.focus();
1595
+ fireEvent.wheel(input, {deltaY: -100});
1596
+
1597
+ expect(onChange).not.toHaveBeenCalled();
1022
1598
  expect(onScrollableWheel).toHaveBeenCalledTimes(1);
1023
1599
  });
1600
+
1601
+ describe('hasNumberSteppers', () => {
1602
+ it('does not show stepper buttons by default', () => {
1603
+ render(<NumberInput label="Quantity" value={5} onChange={() => {}} />);
1604
+ expect(
1605
+ screen.queryByRole('button', {name: 'Increment Quantity'}),
1606
+ ).not.toBeInTheDocument();
1607
+ expect(
1608
+ screen.queryByRole('button', {name: 'Decrement Quantity'}),
1609
+ ).not.toBeInTheDocument();
1610
+ });
1611
+
1612
+ it('shows localized increment and decrement buttons when enabled', () => {
1613
+ render(
1614
+ <NumberInput
1615
+ label="Quantity"
1616
+ value={5}
1617
+ onChange={() => {}}
1618
+ hasNumberSteppers
1619
+ />,
1620
+ );
1621
+ expect(
1622
+ screen.getByRole('button', {name: 'Increment Quantity'}),
1623
+ ).toHaveAttribute('tabindex', '-1');
1624
+ expect(
1625
+ screen.getByRole('button', {name: 'Decrement Quantity'}),
1626
+ ).toHaveAttribute('tabindex', '-1');
1627
+ });
1628
+
1629
+ it('steps the value and returns focus to the input', () => {
1630
+ const onChange = vi.fn();
1631
+ render(
1632
+ <NumberInput
1633
+ label="Quantity"
1634
+ value={5}
1635
+ onChange={onChange}
1636
+ hasNumberSteppers
1637
+ />,
1638
+ );
1639
+ const input = screen.getByRole('spinbutton');
1640
+
1641
+ fireEvent.click(screen.getByRole('button', {name: 'Increment Quantity'}));
1642
+ expect(onChange).toHaveBeenLastCalledWith(6);
1643
+ expect(input).toHaveFocus();
1644
+
1645
+ fireEvent.click(screen.getByRole('button', {name: 'Decrement Quantity'}));
1646
+ expect(onChange).toHaveBeenLastCalledWith(4);
1647
+ expect(input).toHaveFocus();
1648
+ });
1649
+
1650
+ it('disables only the stepper at the reached boundary', () => {
1651
+ render(
1652
+ <NumberInput
1653
+ label="Quantity"
1654
+ value={10}
1655
+ onChange={() => {}}
1656
+ min={0}
1657
+ max={10}
1658
+ hasNumberSteppers
1659
+ />,
1660
+ );
1661
+ expect(
1662
+ screen.getByRole('button', {name: 'Increment Quantity'}),
1663
+ ).toBeDisabled();
1664
+ expect(
1665
+ screen.getByRole('button', {name: 'Decrement Quantity'}),
1666
+ ).not.toBeDisabled();
1667
+ });
1668
+
1669
+ it('disables both steppers with the input', () => {
1670
+ render(
1671
+ <NumberInput
1672
+ label="Quantity"
1673
+ value={5}
1674
+ onChange={() => {}}
1675
+ hasNumberSteppers
1676
+ isDisabled
1677
+ />,
1678
+ );
1679
+ expect(
1680
+ screen.getByRole('button', {name: 'Increment Quantity'}),
1681
+ ).toBeDisabled();
1682
+ expect(
1683
+ screen.getByRole('button', {name: 'Decrement Quantity'}),
1684
+ ).toBeDisabled();
1685
+ });
1686
+ });
1687
+ });
1688
+
1689
+ describe('NumberInput disabled theme state', () => {
1690
+ it('reflects disabled on the root target so themes can gate paint on it', () => {
1691
+ const {container} = render(
1692
+ <NumberInput
1693
+ label="Quantity"
1694
+ value={null}
1695
+ onChange={() => {}}
1696
+ isDisabled
1697
+ />,
1698
+ );
1699
+ const root = container.querySelector('.astryx-number-input');
1700
+ expect(root).toHaveAttribute('data-disabled', 'disabled');
1701
+ expect(root).toHaveClass('disabled');
1702
+ });
1703
+
1704
+ it('omits data-disabled when enabled, like status does', () => {
1705
+ const {container} = render(
1706
+ <NumberInput label="Quantity" value={null} onChange={() => {}} />,
1707
+ );
1708
+ const root = container.querySelector('.astryx-number-input');
1709
+ expect(root).not.toHaveAttribute('data-disabled');
1710
+ });
1711
+ });
1712
+
1713
+ describe('NumberInput readonly theme state', () => {
1714
+ it('reflects readonly on the root target so themes can gate paint on it', () => {
1715
+ const {container} = render(
1716
+ <NumberInput label="Qty" value={1} onChange={() => {}} isReadOnly />,
1717
+ );
1718
+ const root = container.querySelector('.astryx-number-input');
1719
+ expect(root).toHaveAttribute('data-readonly', 'readonly');
1720
+ });
1721
+
1722
+ it('omits data-readonly when editable', () => {
1723
+ const {container} = render(
1724
+ <NumberInput label="Qty" value={1} onChange={() => {}} />,
1725
+ );
1726
+ const root = container.querySelector('.astryx-number-input');
1727
+ expect(root).not.toHaveAttribute('data-readonly');
1728
+ });
1024
1729
  });