@react-md/core 6.3.3 → 6.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 (456) hide show
  1. package/dist/CoreProviders.d.ts +1 -0
  2. package/dist/CoreProviders.js.map +1 -1
  3. package/dist/_base.scss +3 -0
  4. package/dist/_core.scss +1 -0
  5. package/dist/_utils.scss +15 -7
  6. package/dist/app-bar/AppBar.js.map +1 -1
  7. package/dist/app-bar/AppBarTitle.js.map +1 -1
  8. package/dist/autocomplete/AutocompleteListboxChildren.js.map +1 -1
  9. package/dist/autocomplete/types.js.map +1 -1
  10. package/dist/autocomplete/utils.js.map +1 -1
  11. package/dist/avatar/Avatar.js.map +1 -1
  12. package/dist/box/_box.scss +20 -1
  13. package/dist/box/styles.d.ts +39 -0
  14. package/dist/box/styles.js +39 -0
  15. package/dist/box/styles.js.map +1 -1
  16. package/dist/button/Button.js.map +1 -1
  17. package/dist/button/FloatingActionButton.js.map +1 -1
  18. package/dist/card/Card.js.map +1 -1
  19. package/dist/card/CardContent.js.map +1 -1
  20. package/dist/card/ClickableCard.js.map +1 -1
  21. package/dist/chip/Chip.js.map +1 -1
  22. package/dist/datetime/NativeDateField.js.map +1 -1
  23. package/dist/datetime/NativeTimeField.js.map +1 -1
  24. package/dist/datetime/useDateField.js.map +1 -1
  25. package/dist/datetime/useTimeField.js.map +1 -1
  26. package/dist/dialog/Dialog.js.map +1 -1
  27. package/dist/dialog/DialogContainer.js.map +1 -1
  28. package/dist/dialog/DialogContent.js.map +1 -1
  29. package/dist/dialog/DialogFooter.js.map +1 -1
  30. package/dist/divider/Divider.js.map +1 -1
  31. package/dist/draggable/useDraggable.js.map +1 -1
  32. package/dist/draggable/utils.js.map +1 -1
  33. package/dist/expansion-panel/ExpansionPanelHeader.js.map +1 -1
  34. package/dist/files/FileInput.js.map +1 -1
  35. package/dist/files/useFileUpload.js.map +1 -1
  36. package/dist/files/validation.js.map +1 -1
  37. package/dist/focus/useFocusContainer.js.map +1 -1
  38. package/dist/form/Fieldset.d.ts +19 -0
  39. package/dist/form/Fieldset.js +22 -2
  40. package/dist/form/Fieldset.js.map +1 -1
  41. package/dist/form/FormMessageContainer.js.map +1 -1
  42. package/dist/form/FormMessageCounter.js.map +1 -1
  43. package/dist/form/InputToggle.js.map +1 -1
  44. package/dist/form/Legend.d.ts +27 -5
  45. package/dist/form/Legend.js +39 -6
  46. package/dist/form/Legend.js.map +1 -1
  47. package/dist/form/Listbox.js.map +1 -1
  48. package/dist/form/ListboxProvider.js.map +1 -1
  49. package/dist/form/NativeSelect.js.map +1 -1
  50. package/dist/form/Password.js.map +1 -1
  51. package/dist/form/ResizingTextAreaWrapper.js.map +1 -1
  52. package/dist/form/Select.js.map +1 -1
  53. package/dist/form/Slider.js.map +1 -1
  54. package/dist/form/SliderContainer.js.map +1 -1
  55. package/dist/form/SliderThumb.js.map +1 -1
  56. package/dist/form/SliderTrack.js.map +1 -1
  57. package/dist/form/SliderValueMarks.js.map +1 -1
  58. package/dist/form/Switch.js.map +1 -1
  59. package/dist/form/TextArea.js.map +1 -1
  60. package/dist/form/TextField.js.map +1 -1
  61. package/dist/form/TextFieldContainer.js.map +1 -1
  62. package/dist/form/_fieldset.scss +7 -0
  63. package/dist/form/_legend.scss +68 -0
  64. package/dist/form/_text-field.scss +39 -4
  65. package/dist/form/fieldsetStyles.d.ts +6 -1
  66. package/dist/form/fieldsetStyles.js +3 -2
  67. package/dist/form/fieldsetStyles.js.map +1 -1
  68. package/dist/form/inputToggleStyles.js.map +1 -1
  69. package/dist/form/labelStyles.d.ts +1 -1
  70. package/dist/form/labelStyles.js +1 -1
  71. package/dist/form/labelStyles.js.map +1 -1
  72. package/dist/form/legendStyles.d.ts +83 -0
  73. package/dist/form/legendStyles.js +25 -0
  74. package/dist/form/legendStyles.js.map +1 -0
  75. package/dist/form/selectUtils.js.map +1 -1
  76. package/dist/form/textFieldContainerStyles.js.map +1 -1
  77. package/dist/form/types.d.ts +28 -6
  78. package/dist/form/types.js.map +1 -1
  79. package/dist/form/useCheckboxGroup.js.map +1 -1
  80. package/dist/form/useCombobox.js.map +1 -1
  81. package/dist/form/useNumberField.js +16 -19
  82. package/dist/form/useNumberField.js.map +1 -1
  83. package/dist/form/useRangeSlider.js.map +1 -1
  84. package/dist/form/useSlider.js.map +1 -1
  85. package/dist/form/useTextField.d.ts +1 -1
  86. package/dist/form/useTextField.js.map +1 -1
  87. package/dist/hoverMode/useHoverMode.js.map +1 -1
  88. package/dist/icon/FontIcon.js.map +1 -1
  89. package/dist/icon/IconRotator.js.map +1 -1
  90. package/dist/icon/MaterialIcon.js.map +1 -1
  91. package/dist/icon/MaterialSymbol.js.map +1 -1
  92. package/dist/icon/SVGIcon.js.map +1 -1
  93. package/dist/icon/config.d.ts +0 -1
  94. package/dist/icon/config.js +10 -7
  95. package/dist/icon/config.js.map +1 -1
  96. package/dist/icon/materialConfig.js.map +1 -1
  97. package/dist/icon/styles.js.map +1 -1
  98. package/dist/interaction/UserInteractionModeProvider.js +6 -4
  99. package/dist/interaction/UserInteractionModeProvider.js.map +1 -1
  100. package/dist/interaction/types.js.map +1 -1
  101. package/dist/interaction/useElementInteraction.js.map +1 -1
  102. package/dist/layout/LayoutAppBar.d.ts +6 -6
  103. package/dist/layout/LayoutAppBar.js +6 -6
  104. package/dist/layout/LayoutAppBar.js.map +1 -1
  105. package/dist/layout/LayoutNav.js.map +1 -1
  106. package/dist/layout/LayoutWindowSplitter.js.map +1 -1
  107. package/dist/layout/Main.js.map +1 -1
  108. package/dist/layout/useExpandableLayout.js +43 -0
  109. package/dist/layout/useExpandableLayout.js.map +1 -1
  110. package/dist/layout/useHorizontalLayoutTransition.js.map +1 -1
  111. package/dist/layout/useLayoutTree.js.map +1 -1
  112. package/dist/layout/useLayoutWindowSplitter.js.map +1 -1
  113. package/dist/layout/useResizableLayout.js.map +1 -1
  114. package/dist/link/Link.js.map +1 -1
  115. package/dist/link/SkipToMainContent.js +19 -21
  116. package/dist/link/SkipToMainContent.js.map +1 -1
  117. package/dist/list/List.js.map +1 -1
  118. package/dist/list/ListItem.js.map +1 -1
  119. package/dist/list/ListItemAddon.js.map +1 -1
  120. package/dist/list/ListItemLink.js.map +1 -1
  121. package/dist/list/ListSubheader.js.map +1 -1
  122. package/dist/list/getListItemHeight.js.map +1 -1
  123. package/dist/list/listItemStyles.js.map +1 -1
  124. package/dist/list/types.js.map +1 -1
  125. package/dist/media-queries/AppSizeProvider.d.ts +2 -0
  126. package/dist/media-queries/AppSizeProvider.js +3 -2
  127. package/dist/media-queries/AppSizeProvider.js.map +1 -1
  128. package/dist/media-queries/appSize.d.ts +3 -0
  129. package/dist/media-queries/appSize.js +3 -1
  130. package/dist/media-queries/appSize.js.map +1 -1
  131. package/dist/media-queries/config.d.ts +11 -0
  132. package/dist/media-queries/config.js +26 -0
  133. package/dist/media-queries/config.js.map +1 -0
  134. package/dist/menu/DropdownMenu.js.map +1 -1
  135. package/dist/menu/Menu.js.map +1 -1
  136. package/dist/menu/MenuItemButton.js.map +1 -1
  137. package/dist/menu/MenuItemFileInput.js.map +1 -1
  138. package/dist/menu/MenuItemInputToggle.js.map +1 -1
  139. package/dist/menu/MenuItemSeparator.js.map +1 -1
  140. package/dist/menu/MenuVisibilityProvider.js.map +1 -1
  141. package/dist/menu/MenuWidget.js.map +1 -1
  142. package/dist/menu/useContextMenu.js.map +1 -1
  143. package/dist/movement/types.d.ts +28 -3
  144. package/dist/movement/types.js.map +1 -1
  145. package/dist/movement/useKeyboardMovementProvider.js +96 -47
  146. package/dist/movement/useKeyboardMovementProvider.js.map +1 -1
  147. package/dist/navigation/CollapsibleNavGroup.js.map +1 -1
  148. package/dist/navigation/NavItem.js.map +1 -1
  149. package/dist/navigation/NavItemButton.js.map +1 -1
  150. package/dist/navigation/NavItemLink.js.map +1 -1
  151. package/dist/navigation/getTableOfContentsHeadings.js.map +1 -1
  152. package/dist/navigation/types.js.map +1 -1
  153. package/dist/overlay/Overlay.js.map +1 -1
  154. package/dist/positioning/createHorizontalPosition.js.map +1 -1
  155. package/dist/positioning/createVerticalPosition.js.map +1 -1
  156. package/dist/positioning/useFixedPositioning.js.map +1 -1
  157. package/dist/progress/CircularProgress.js.map +1 -1
  158. package/dist/progress/LinearProgress.js.map +1 -1
  159. package/dist/progress/linearProgressStyles.js.map +1 -1
  160. package/dist/responsive-item/ResponsiveItem.js.map +1 -1
  161. package/dist/responsive-item/ResponsiveItemOverlay.js.map +1 -1
  162. package/dist/searching/caseInsensitive.js.map +1 -1
  163. package/dist/segmented-button/SegmentedButton.js.map +1 -1
  164. package/dist/segmented-button/SegmentedButtonContainer.js.map +1 -1
  165. package/dist/segmented-button/segmentedButtonStyles.js.map +1 -1
  166. package/dist/sheet/Sheet.js.map +1 -1
  167. package/dist/snackbar/Toast.js.map +1 -1
  168. package/dist/spinbutton/SpinButton.d.ts +16 -0
  169. package/dist/spinbutton/SpinButton.js +55 -0
  170. package/dist/spinbutton/SpinButton.js.map +1 -0
  171. package/dist/spinbutton/SpinButtonGroupProvider.d.ts +17 -0
  172. package/dist/spinbutton/SpinButtonGroupProvider.js +19 -0
  173. package/dist/spinbutton/SpinButtonGroupProvider.js.map +1 -0
  174. package/dist/spinbutton/defaults.d.ts +9 -0
  175. package/dist/spinbutton/defaults.js +25 -0
  176. package/dist/spinbutton/defaults.js.map +1 -0
  177. package/dist/spinbutton/types.d.ts +324 -0
  178. package/dist/spinbutton/types.js +5 -0
  179. package/dist/spinbutton/types.js.map +1 -0
  180. package/dist/spinbutton/useSpinButton.d.ts +5 -0
  181. package/dist/spinbutton/useSpinButton.js +260 -0
  182. package/dist/spinbutton/useSpinButton.js.map +1 -0
  183. package/dist/spinbutton/useSpinButtonGroupProvider.d.ts +27 -0
  184. package/dist/spinbutton/useSpinButtonGroupProvider.js +49 -0
  185. package/dist/spinbutton/useSpinButtonGroupProvider.js.map +1 -0
  186. package/dist/spinbutton/utils/deselectNode.d.ts +5 -0
  187. package/dist/spinbutton/utils/deselectNode.js +17 -0
  188. package/dist/spinbutton/utils/deselectNode.js.map +1 -0
  189. package/dist/spinbutton/utils/resolveInputEvent.d.ts +30 -0
  190. package/dist/spinbutton/utils/resolveInputEvent.js +53 -0
  191. package/dist/spinbutton/utils/resolveInputEvent.js.map +1 -0
  192. package/dist/spinbutton/utils/selectNode.d.ts +5 -0
  193. package/dist/spinbutton/utils/selectNode.js +15 -0
  194. package/dist/spinbutton/utils/selectNode.js.map +1 -0
  195. package/dist/table/StickyTableSection.js.map +1 -1
  196. package/dist/table/Table.js.map +1 -1
  197. package/dist/table/TableBody.js.map +1 -1
  198. package/dist/table/TableCellContent.js.map +1 -1
  199. package/dist/table/TableCheckbox.js.map +1 -1
  200. package/dist/table/TableFooter.js.map +1 -1
  201. package/dist/table/TableHeader.js.map +1 -1
  202. package/dist/table/TableRadio.js.map +1 -1
  203. package/dist/table/TableRow.js.map +1 -1
  204. package/dist/table/useStickyTableSection.js.map +1 -1
  205. package/dist/tabs/SimpleTabPanel.js.map +1 -1
  206. package/dist/tabs/SimpleTabPanels.js.map +1 -1
  207. package/dist/tabs/Tab.js.map +1 -1
  208. package/dist/tabs/TabList.js.map +1 -1
  209. package/dist/tabs/TabListScrollButton.js.map +1 -1
  210. package/dist/tabs/useMaxTabPanelHeight.js.map +1 -1
  211. package/dist/test-utils/data-testid.js.map +1 -1
  212. package/dist/test-utils/mocks/match-media.js +5 -5
  213. package/dist/test-utils/mocks/match-media.js.map +1 -1
  214. package/dist/test-utils/vitest/timers.d.ts +1 -1
  215. package/dist/test-utils/vitest/timers.js +1 -1
  216. package/dist/test-utils/vitest/timers.js.map +1 -1
  217. package/dist/tooltip/Tooltip.js.map +1 -1
  218. package/dist/tooltip/TooltipHoverModeProvider.js.map +1 -1
  219. package/dist/tooltip/useTooltip.js.map +1 -1
  220. package/dist/transition/CSSTransition.js.map +1 -1
  221. package/dist/transition/Collapse.js.map +1 -1
  222. package/dist/transition/CrossFade.js.map +1 -1
  223. package/dist/transition/ScaleTransition.js.map +1 -1
  224. package/dist/transition/SkeletonPlaceholder.js.map +1 -1
  225. package/dist/transition/Slide.js.map +1 -1
  226. package/dist/transition/SlideContainer.js.map +1 -1
  227. package/dist/transition/types.js.map +1 -1
  228. package/dist/transition/useCollapseTransition.js.map +1 -1
  229. package/dist/transition/useCrossFadeTransition.js.map +1 -1
  230. package/dist/transition/useMaxWidthTransition.js.map +1 -1
  231. package/dist/transition/useScaleTransition.js.map +1 -1
  232. package/dist/transition/useSkeletonPlaceholder.js.map +1 -1
  233. package/dist/tree/Tree.js.map +1 -1
  234. package/dist/tree/TreeItem.js.map +1 -1
  235. package/dist/tree/TreeProvider.js.map +1 -1
  236. package/dist/tree/styles.js.map +1 -1
  237. package/dist/tree/types.js.map +1 -1
  238. package/dist/tree/useTreeMovement.js.map +1 -1
  239. package/dist/typography/HighlightTextMark.js.map +1 -1
  240. package/dist/typography/Mark.js.map +1 -1
  241. package/dist/typography/TextContainer.js.map +1 -1
  242. package/dist/typography/Typography.js.map +1 -1
  243. package/dist/typography/_typography.scss +0 -1
  244. package/dist/useElementSize.js.map +1 -1
  245. package/dist/useIntersectionObserver.js.map +1 -1
  246. package/dist/useMutationObserver.js.map +1 -1
  247. package/dist/useWindowSize.js.map +1 -1
  248. package/dist/utils/getNumberOfDigits.d.ts +7 -0
  249. package/dist/utils/getNumberOfDigits.js +11 -0
  250. package/dist/utils/getNumberOfDigits.js.map +1 -0
  251. package/dist/utils/nearest.js +2 -1
  252. package/dist/utils/nearest.js.map +1 -1
  253. package/dist/utils/useDevEffect.d.ts +7 -0
  254. package/dist/utils/useDevEffect.js +8 -0
  255. package/dist/utils/useDevEffect.js.map +1 -0
  256. package/dist/window-splitter/WindowSplitter.js +3 -2
  257. package/dist/window-splitter/WindowSplitter.js.map +1 -1
  258. package/dist/window-splitter/_window-splitter.scss +60 -12
  259. package/dist/window-splitter/styles.d.ts +9 -0
  260. package/dist/window-splitter/styles.js +3 -2
  261. package/dist/window-splitter/styles.js.map +1 -1
  262. package/dist/window-splitter/useWindowSplitter.js.map +1 -1
  263. package/package.json +38 -30
  264. package/src/CoreProviders.tsx +1 -0
  265. package/src/app-bar/AppBar.tsx +1 -2
  266. package/src/app-bar/AppBarTitle.tsx +1 -2
  267. package/src/autocomplete/AutocompleteListboxChildren.tsx +3 -1
  268. package/src/autocomplete/types.ts +24 -19
  269. package/src/autocomplete/utils.ts +9 -6
  270. package/src/avatar/Avatar.tsx +2 -1
  271. package/src/box/styles.ts +39 -0
  272. package/src/button/Button.tsx +2 -1
  273. package/src/button/FloatingActionButton.tsx +2 -1
  274. package/src/card/Card.tsx +2 -1
  275. package/src/card/CardContent.tsx +1 -2
  276. package/src/card/ClickableCard.tsx +1 -2
  277. package/src/chip/Chip.tsx +2 -1
  278. package/src/datetime/NativeDateField.tsx +2 -1
  279. package/src/datetime/NativeTimeField.tsx +2 -1
  280. package/src/datetime/useDateField.ts +13 -8
  281. package/src/datetime/useTimeField.ts +13 -8
  282. package/src/dialog/Dialog.tsx +2 -1
  283. package/src/dialog/DialogContainer.tsx +1 -2
  284. package/src/dialog/DialogContent.tsx +1 -2
  285. package/src/dialog/DialogFooter.tsx +1 -2
  286. package/src/divider/Divider.tsx +1 -2
  287. package/src/draggable/useDraggable.ts +4 -4
  288. package/src/draggable/utils.ts +4 -2
  289. package/src/expansion-panel/ExpansionPanelHeader.tsx +1 -2
  290. package/src/files/FileInput.tsx +2 -1
  291. package/src/files/useFileUpload.ts +6 -6
  292. package/src/files/validation.ts +1 -2
  293. package/src/focus/useFocusContainer.ts +4 -4
  294. package/src/form/Fieldset.tsx +25 -3
  295. package/src/form/FormMessageContainer.tsx +1 -2
  296. package/src/form/FormMessageCounter.tsx +1 -2
  297. package/src/form/InputToggle.tsx +3 -3
  298. package/src/form/Legend.tsx +55 -10
  299. package/src/form/Listbox.tsx +1 -2
  300. package/src/form/ListboxProvider.ts +3 -2
  301. package/src/form/NativeSelect.tsx +2 -1
  302. package/src/form/Password.tsx +4 -2
  303. package/src/form/ResizingTextAreaWrapper.tsx +1 -2
  304. package/src/form/Select.tsx +2 -1
  305. package/src/form/Slider.tsx +2 -1
  306. package/src/form/SliderContainer.tsx +1 -2
  307. package/src/form/SliderThumb.tsx +6 -3
  308. package/src/form/SliderTrack.tsx +2 -1
  309. package/src/form/SliderValueMarks.tsx +1 -2
  310. package/src/form/Switch.tsx +2 -1
  311. package/src/form/TextArea.tsx +1 -2
  312. package/src/form/TextField.tsx +2 -1
  313. package/src/form/TextFieldContainer.tsx +1 -2
  314. package/src/form/fieldsetStyles.ts +18 -3
  315. package/src/form/inputToggleStyles.ts +4 -2
  316. package/src/form/labelStyles.ts +1 -1
  317. package/src/form/legendStyles.ts +132 -0
  318. package/src/form/selectUtils.ts +3 -2
  319. package/src/form/textFieldContainerStyles.ts +1 -2
  320. package/src/form/types.ts +35 -17
  321. package/src/form/useCheckboxGroup.ts +3 -2
  322. package/src/form/useCombobox.ts +8 -3
  323. package/src/form/useNumberField.ts +36 -35
  324. package/src/form/useRangeSlider.ts +1 -2
  325. package/src/form/useSlider.ts +1 -2
  326. package/src/form/useTextField.ts +9 -4
  327. package/src/hoverMode/useHoverMode.ts +4 -8
  328. package/src/icon/FontIcon.tsx +1 -2
  329. package/src/icon/IconRotator.tsx +1 -2
  330. package/src/icon/MaterialIcon.tsx +2 -1
  331. package/src/icon/MaterialSymbol.tsx +2 -1
  332. package/src/icon/SVGIcon.tsx +1 -2
  333. package/src/icon/config.tsx +10 -7
  334. package/src/icon/materialConfig.ts +1 -2
  335. package/src/icon/styles.ts +1 -2
  336. package/src/interaction/UserInteractionModeProvider.tsx +9 -4
  337. package/src/interaction/types.ts +1 -2
  338. package/src/interaction/useElementInteraction.tsx +3 -2
  339. package/src/layout/LayoutAppBar.tsx +6 -6
  340. package/src/layout/LayoutNav.tsx +2 -1
  341. package/src/layout/LayoutWindowSplitter.tsx +2 -1
  342. package/src/layout/Main.tsx +1 -2
  343. package/src/layout/useExpandableLayout.ts +63 -5
  344. package/src/layout/useHorizontalLayoutTransition.ts +1 -2
  345. package/src/layout/useLayoutTree.ts +2 -2
  346. package/src/layout/useLayoutWindowSplitter.ts +6 -6
  347. package/src/layout/useResizableLayout.ts +3 -6
  348. package/src/link/Link.tsx +1 -2
  349. package/src/link/SkipToMainContent.tsx +20 -23
  350. package/src/list/List.tsx +1 -2
  351. package/src/list/ListItem.tsx +2 -1
  352. package/src/list/ListItemAddon.tsx +2 -1
  353. package/src/list/ListItemLink.tsx +2 -1
  354. package/src/list/ListSubheader.tsx +1 -2
  355. package/src/list/getListItemHeight.ts +8 -9
  356. package/src/list/listItemStyles.ts +1 -2
  357. package/src/list/types.ts +1 -2
  358. package/src/media-queries/AppSizeProvider.tsx +8 -10
  359. package/src/media-queries/appSize.ts +3 -0
  360. package/src/media-queries/config.ts +41 -0
  361. package/src/menu/DropdownMenu.tsx +4 -5
  362. package/src/menu/Menu.tsx +2 -1
  363. package/src/menu/MenuItemButton.tsx +1 -2
  364. package/src/menu/MenuItemFileInput.tsx +2 -1
  365. package/src/menu/MenuItemInputToggle.tsx +3 -3
  366. package/src/menu/MenuItemSeparator.tsx +2 -1
  367. package/src/menu/MenuVisibilityProvider.tsx +4 -2
  368. package/src/menu/MenuWidget.tsx +1 -2
  369. package/src/menu/useContextMenu.ts +4 -2
  370. package/src/movement/types.ts +52 -13
  371. package/src/movement/useKeyboardMovementProvider.ts +77 -38
  372. package/src/navigation/CollapsibleNavGroup.tsx +1 -2
  373. package/src/navigation/NavItem.tsx +1 -2
  374. package/src/navigation/NavItemButton.tsx +2 -1
  375. package/src/navigation/NavItemLink.tsx +2 -1
  376. package/src/navigation/getTableOfContentsHeadings.ts +1 -2
  377. package/src/navigation/types.ts +1 -2
  378. package/src/overlay/Overlay.tsx +2 -1
  379. package/src/positioning/createHorizontalPosition.ts +10 -12
  380. package/src/positioning/createVerticalPosition.ts +10 -11
  381. package/src/positioning/useFixedPositioning.ts +6 -3
  382. package/src/progress/CircularProgress.tsx +2 -1
  383. package/src/progress/LinearProgress.tsx +2 -1
  384. package/src/progress/linearProgressStyles.ts +1 -2
  385. package/src/responsive-item/ResponsiveItem.tsx +1 -2
  386. package/src/responsive-item/ResponsiveItemOverlay.tsx +2 -1
  387. package/src/searching/caseInsensitive.ts +2 -4
  388. package/src/segmented-button/SegmentedButton.tsx +2 -1
  389. package/src/segmented-button/SegmentedButtonContainer.tsx +2 -1
  390. package/src/segmented-button/segmentedButtonStyles.ts +1 -2
  391. package/src/sheet/Sheet.tsx +1 -2
  392. package/src/snackbar/Toast.tsx +2 -1
  393. package/src/spinbutton/SpinButton.tsx +98 -0
  394. package/src/spinbutton/SpinButtonGroupProvider.tsx +32 -0
  395. package/src/spinbutton/defaults.ts +45 -0
  396. package/src/spinbutton/types.ts +413 -0
  397. package/src/spinbutton/useSpinButton.ts +311 -0
  398. package/src/spinbutton/useSpinButtonGroupProvider.ts +104 -0
  399. package/src/spinbutton/utils/deselectNode.ts +17 -0
  400. package/src/spinbutton/utils/resolveInputEvent.ts +112 -0
  401. package/src/spinbutton/utils/selectNode.ts +15 -0
  402. package/src/table/StickyTableSection.tsx +2 -1
  403. package/src/table/Table.tsx +1 -2
  404. package/src/table/TableBody.tsx +2 -1
  405. package/src/table/TableCellContent.tsx +1 -2
  406. package/src/table/TableCheckbox.tsx +1 -2
  407. package/src/table/TableFooter.tsx +1 -2
  408. package/src/table/TableHeader.tsx +1 -2
  409. package/src/table/TableRadio.tsx +1 -2
  410. package/src/table/TableRow.tsx +1 -2
  411. package/src/table/useStickyTableSection.tsx +1 -2
  412. package/src/tabs/SimpleTabPanel.tsx +2 -1
  413. package/src/tabs/SimpleTabPanels.tsx +2 -1
  414. package/src/tabs/Tab.tsx +3 -6
  415. package/src/tabs/TabList.tsx +2 -1
  416. package/src/tabs/TabListScrollButton.tsx +1 -2
  417. package/src/tabs/useMaxTabPanelHeight.ts +7 -4
  418. package/src/test-utils/data-testid.ts +1 -2
  419. package/src/test-utils/mocks/match-media.ts +5 -10
  420. package/src/test-utils/vitest/timers.ts +1 -1
  421. package/src/tooltip/Tooltip.tsx +2 -1
  422. package/src/tooltip/TooltipHoverModeProvider.tsx +1 -2
  423. package/src/tooltip/useTooltip.ts +9 -5
  424. package/src/transition/CSSTransition.tsx +2 -1
  425. package/src/transition/Collapse.tsx +4 -2
  426. package/src/transition/CrossFade.tsx +2 -1
  427. package/src/transition/ScaleTransition.tsx +2 -1
  428. package/src/transition/SkeletonPlaceholder.tsx +1 -2
  429. package/src/transition/Slide.tsx +2 -1
  430. package/src/transition/SlideContainer.tsx +1 -2
  431. package/src/transition/types.ts +15 -16
  432. package/src/transition/useCollapseTransition.ts +6 -5
  433. package/src/transition/useCrossFadeTransition.ts +3 -2
  434. package/src/transition/useMaxWidthTransition.ts +1 -2
  435. package/src/transition/useScaleTransition.ts +3 -2
  436. package/src/transition/useSkeletonPlaceholder.ts +1 -2
  437. package/src/tree/Tree.tsx +2 -1
  438. package/src/tree/TreeItem.tsx +2 -1
  439. package/src/tree/TreeProvider.tsx +4 -4
  440. package/src/tree/styles.ts +1 -2
  441. package/src/tree/types.ts +1 -2
  442. package/src/tree/useTreeMovement.ts +1 -2
  443. package/src/typography/HighlightTextMark.tsx +1 -2
  444. package/src/typography/Mark.tsx +1 -2
  445. package/src/typography/TextContainer.tsx +1 -2
  446. package/src/typography/Typography.tsx +1 -2
  447. package/src/useElementSize.ts +7 -4
  448. package/src/useIntersectionObserver.ts +3 -2
  449. package/src/useMutationObserver.ts +3 -2
  450. package/src/useWindowSize.ts +4 -2
  451. package/src/utils/getNumberOfDigits.ts +18 -0
  452. package/src/utils/nearest.ts +2 -1
  453. package/src/utils/useDevEffect.ts +9 -0
  454. package/src/window-splitter/WindowSplitter.tsx +5 -2
  455. package/src/window-splitter/styles.ts +13 -2
  456. package/src/window-splitter/useWindowSplitter.ts +3 -1
@@ -0,0 +1,324 @@
1
+ import { type AriaAttributes, type FocusEvent, type FormEvent, type HTMLAttributes, type KeyboardEvent, type Ref, type RefObject } from "react";
2
+ import { type FormComponentStates } from "../form/types.js";
3
+ import { type MinMaxRange, type UseStateInitializer } from "../types.js";
4
+ /**
5
+ * @since 6.4.0
6
+ */
7
+ export type SpinButtonEventHandlers<E extends HTMLElement = HTMLDivElement> = Pick<HTMLAttributes<E>, "onInput" | "onClick" | "onFocus" | "onBlur" | "onKeyDown">;
8
+ /**
9
+ * @since 6.4.0
10
+ */
11
+ export type SpinButtonAriaAttributes = Pick<AriaAttributes, "aria-required" | "aria-invalid" | "aria-readonly" | "aria-disabled" | "aria-valuemin" | "aria-valuemax" | "aria-valuenow" | "aria-valuetext">;
12
+ /**
13
+ * This is a way to map a single character to a value within a spinbutton and
14
+ * was mostly added to support time inputs. The main example is:
15
+ *
16
+ * @example Day Period Mapping
17
+ * ```ts
18
+ * const AM_PM: SpinButtonCharacterValueMap = {
19
+ * a: 0,
20
+ * p: 1,
21
+ * };
22
+ * ```
23
+ *
24
+ * **If the mapping is provided, all other input events are ignored**.
25
+ *
26
+ * @since 6.4.0
27
+ */
28
+ export type SpinButtonCharacterValueMap = Readonly<Record<string, number>>;
29
+ /**
30
+ * @since 6.4.0
31
+ */
32
+ export type SpinButtonValue = number | null;
33
+ /**
34
+ * @since 6.4.0
35
+ */
36
+ export type SpinButtonGetValueText = (value: SpinButtonValue) => string | undefined;
37
+ /**
38
+ * @since 6.4.0
39
+ */
40
+ export type SpinButtonChangeEvent<E extends HTMLElement = HTMLDivElement> = FormEvent<E> | KeyboardEvent<E> | FocusEvent<E>;
41
+ /**
42
+ * @since 6.4.0
43
+ */
44
+ export type SpinButtonChangeReason = "change" | "type" | "typed-to-completion" | "cleared";
45
+ /**
46
+ * @since 6.4.0
47
+ */
48
+ export interface SpinButtonChangeEventOptions<E extends HTMLElement = HTMLDivElement> {
49
+ event: SpinButtonChangeEvent<E>;
50
+ value: SpinButtonValue;
51
+ reason: SpinButtonChangeReason;
52
+ }
53
+ /**
54
+ * This callback will be fired whenever the spinbutton value has changed.
55
+ *
56
+ * The `reason` will be "typed-to-completion"` when:
57
+ * - the `value` is not `null` and:
58
+ * - the user uses the `ArrowUp`, `ArrowDown`, `Home`, `End`, `PageUp`, or
59
+ * `PageDown` keys to change the value
60
+ * - the user has typed the max amount of digits based on the `max` value
61
+ *
62
+ * Examples with: `min=0` and `max=12`
63
+ * - `1` -> (1, false)
64
+ * - `Tab` or blur (1, true)
65
+ * - `1` -> (11, true)
66
+ * - `0` - (1, false)
67
+ * - `Tab` or blur (0, true)
68
+ * - `3` (3, true)
69
+ * - `3` -> (3, true)
70
+ * - there are no more characters that could have been typed
71
+ *
72
+ *
73
+ * @since 6.4.0
74
+ */
75
+ export type SpinButtonValueChange<E extends HTMLElement = HTMLDivElement> = (options: SpinButtonChangeEventOptions<E>) => void;
76
+ /**
77
+ * @since 6.4.0
78
+ */
79
+ export interface SpinButtonUnknownValueOptions<E extends HTMLElement = HTMLDivElement> {
80
+ value?: SpinButtonValue;
81
+ defaultValue?: UseStateInitializer<SpinButtonValue>;
82
+ onValueChange?: SpinButtonValueChange<E>;
83
+ }
84
+ /**
85
+ * @since 6.4.0
86
+ */
87
+ export interface SpinButtonControlledValueOptions<E extends HTMLElement = HTMLDivElement> {
88
+ value: SpinButtonValue;
89
+ defaultValue?: never;
90
+ onValueChange: SpinButtonValueChange<E>;
91
+ }
92
+ /**
93
+ * @since 6.4.0
94
+ */
95
+ export interface SpinButtonUncontrolledValueOptions<E extends HTMLElement = HTMLDivElement> {
96
+ value?: never;
97
+ defaultValue?: UseStateInitializer<SpinButtonValue>;
98
+ onValueChange?: SpinButtonValueChange<E>;
99
+ }
100
+ /**
101
+ * @since 6.4.0
102
+ */
103
+ export type SpinButtonValueOptions<E extends HTMLElement = HTMLDivElement> = SpinButtonControlledValueOptions<E> | SpinButtonUncontrolledValueOptions<E>;
104
+ /**
105
+ * @since 6.4.0
106
+ */
107
+ export interface SpinButtonDigitRangeOptions {
108
+ /**
109
+ * This is the minimum number of digits that should be shown in the spin
110
+ * button as the user is typing. If the current value is less than this
111
+ * value, the {@link placeholderChar} will be used as a `padStart` value.
112
+ *
113
+ * @example Get Text Content Example
114
+ * ```ts
115
+ * const textContent1 = getTextContent({
116
+ * value: null,
117
+ * fallback: "HH",
118
+ * placeholderChar: "0",
119
+ * });
120
+ * // ^ textContent1 === "HH"
121
+ *
122
+ * const textContent2 = getTextContent({
123
+ * value: 3,
124
+ * fallback: "HH",
125
+ * placeholderChar: "0",
126
+ * });
127
+ * // ^ textContent2 === "03"
128
+ *
129
+ * const textContent3 = getTextContent({
130
+ * value: 12,
131
+ * fallback: "HH",
132
+ * placeholderChar: "0",
133
+ * });
134
+ * // ^ textContent3 === "12"
135
+ * ```
136
+ *
137
+ * @example Year Example
138
+ * ```ts
139
+ * const textContent1 = getTextContent({
140
+ * value: null,
141
+ * fallback: "YYYY",
142
+ * minDigits: 4,
143
+ * });
144
+ * // ^ textContent1 === "YYYY"
145
+ *
146
+ * const textContent2 = getTextContent({
147
+ * value: 2,
148
+ * fallback: "YYYY",
149
+ * minDigits: 4,
150
+ * });
151
+ * // ^ textContent2 === "0002"
152
+ *
153
+ * const textContent3 = getTextContent({
154
+ * value: 200,
155
+ * fallback: "YYYY",
156
+ * minDigits: 4,
157
+ * });
158
+ * // ^ textContent3 === "0200"
159
+ *
160
+ * const textContent4 = getTextContent({
161
+ * value: 2025,
162
+ * fallback: "YYYY",
163
+ * minDigits: 4,
164
+ * });
165
+ * // ^ textContent4 === "2025"
166
+ * ```
167
+ *
168
+ * @see {@link SpinButtonTextPlaceholderOptions.placeholderChar}
169
+ * @defaultValue `fallback?.length ?? getNumberOfDigits(min)`
170
+ */
171
+ minDigits?: number;
172
+ /**
173
+ * This is the maximum number of digits that should be shown in the spin
174
+ * button as the user is typing and is used to determine if the user has
175
+ * `"typed-to-completion"`.
176
+ *
177
+ * @example Year Example
178
+ * ```tsx
179
+ * // this _could_ also be 9999
180
+ * const max = undefined;
181
+ * const maxDigits = 4;
182
+ *
183
+ * // if the current value is `null` and the user types `2`
184
+ * onValueChange({
185
+ * event,
186
+ * reason: "change",
187
+ * nextValue: 2,
188
+ * });
189
+ *
190
+ * // if the current value is `2` and the user types `0`
191
+ * onValueChange({
192
+ * event,
193
+ * reason: "change",
194
+ * nextValue: 20,
195
+ * });
196
+ *
197
+ * // if the current value is `20` and the user types `2`
198
+ * onValueChange({
199
+ * event,
200
+ * reason: "change",
201
+ * nextValue: 202,
202
+ * });
203
+ *
204
+ * // if the current value is `202` and the user types `5`:
205
+ * onValueChange({
206
+ * event,
207
+ * reason: "typed-to-completion",
208
+ * nextValue: 2025,
209
+ * });
210
+ * ```
211
+ *
212
+ * @defaultValue `getNumberOfDigits(max)`
213
+ */
214
+ maxDigits?: number;
215
+ }
216
+ /**
217
+ * @since 6.4.0
218
+ */
219
+ export interface SpinButtonRangeOptions extends Partial<MinMaxRange>, SpinButtonDigitRangeOptions {
220
+ }
221
+ /**
222
+ * @since 6.4.0
223
+ */
224
+ export interface SpinButtonTextPlaceholderOptions extends SpinButtonRangeOptions {
225
+ /**
226
+ * An optional fallback value to display when the spin button's value is
227
+ * `null`. For example: if the spin button is used to set the specific hour
228
+ * in a time field, set the fallback to `"HH"` to show that until the user
229
+ * has typed a value.
230
+ */
231
+ fallback?: string;
232
+ /**
233
+ * This is the character to use to fill the remaining number of digits to
234
+ * display in the spin button.
235
+ *
236
+ * @see {@link minDigits}
237
+ * @defaultValue `"0"`
238
+ */
239
+ placeholderChar?: string;
240
+ }
241
+ /**
242
+ * @since 6.4.0
243
+ */
244
+ export interface GetSpinButtonTextContentOptions extends SpinButtonTextPlaceholderOptions {
245
+ /**
246
+ * The current value in the spin button to convert to text. **This will be
247
+ * called with numbers outside of the allowed range**.
248
+ */
249
+ value: SpinButtonValue;
250
+ }
251
+ /**
252
+ * @since 6.4.0
253
+ */
254
+ export type GetSpinButtonTextContent = (options: GetSpinButtonTextContentOptions) => string;
255
+ /**
256
+ * @since 6.4.0
257
+ */
258
+ export type GetSpinButtonValueText = (value: SpinButtonValue) => string | undefined;
259
+ /**
260
+ * @since 6.4.0
261
+ */
262
+ export interface SpinButtonFormStates extends Omit<FormComponentStates, "active"> {
263
+ required?: boolean;
264
+ }
265
+ /**
266
+ * @since 6.4.0
267
+ */
268
+ export interface SpinButtonOptions<E extends HTMLElement = HTMLDivElement> extends SpinButtonEventHandlers<E>, SpinButtonUnknownValueOptions<E>, SpinButtonFormStates, SpinButtonTextPlaceholderOptions {
269
+ /**
270
+ * @defaultValue `"spinbutton-" + useId()`
271
+ */
272
+ id?: string;
273
+ ref?: Ref<E>;
274
+ form?: string;
275
+ /**
276
+ * The default value to use when the increment or decrement action is fired
277
+ * from the spinbutton through keyboard events before a value has been set.
278
+ * So when the increment action is fired, this will be
279
+ * `defaultKeyboardValue + 1`.
280
+ *
281
+ * @defaultValue `min ?? max ?? 0`
282
+ */
283
+ defaultKeyboardValue?: UseStateInitializer<number>;
284
+ /**
285
+ * NOTE: This isn't actually supported yet
286
+ *
287
+ * @defaultValue `1`
288
+ */
289
+ step?: number;
290
+ /** @see {@link SpinButtonCharacterValueMap} */
291
+ mappings?: SpinButtonCharacterValueMap;
292
+ /**
293
+ * Used to provide an `aria-valuenow` string for a specific value in the
294
+ * `SpinButton`.
295
+ *
296
+ * @defaultValue `(value) => value === null ? "No value selected" : undefined`
297
+ */
298
+ getValueText?: GetSpinButtonValueText;
299
+ getTextContent?: GetSpinButtonTextContent;
300
+ }
301
+ /**
302
+ * @since 6.4.0
303
+ */
304
+ export interface ProvidedSpinButtonProps<E extends HTMLElement = HTMLDivElement> extends Required<SpinButtonEventHandlers<E>>, SpinButtonAriaAttributes {
305
+ id: string;
306
+ ref: Ref<E>;
307
+ role: "spinbutton";
308
+ inputMode: "numeric";
309
+ spellCheck: boolean;
310
+ autoCapitalize: "none";
311
+ autoCorrect: "off";
312
+ tabIndex: number | undefined;
313
+ contentEditable: boolean | undefined;
314
+ suppressContentEditableWarning: boolean;
315
+ }
316
+ /**
317
+ * @since 6.4.0
318
+ */
319
+ export interface SpinButtonImplementation<E extends HTMLElement = HTMLDivElement> {
320
+ value: SpinButtonValue;
321
+ setValue: (value: SpinButtonValue) => void;
322
+ spinButtonRef: RefObject<E>;
323
+ spinButtonProps: Readonly<ProvidedSpinButtonProps<E>>;
324
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * @since 6.4.0
3
+ */ export { };
4
+
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/spinbutton/types.ts"],"sourcesContent":["import {\n type AriaAttributes,\n type FocusEvent,\n type FormEvent,\n type HTMLAttributes,\n type KeyboardEvent,\n type Ref,\n type RefObject,\n} from \"react\";\n\nimport { type FormComponentStates } from \"../form/types.js\";\nimport { type MinMaxRange, type UseStateInitializer } from \"../types.js\";\n\n/**\n * @since 6.4.0\n */\nexport type SpinButtonEventHandlers<E extends HTMLElement = HTMLDivElement> =\n Pick<\n HTMLAttributes<E>,\n \"onInput\" | \"onClick\" | \"onFocus\" | \"onBlur\" | \"onKeyDown\"\n >;\n\n/**\n * @since 6.4.0\n */\nexport type SpinButtonAriaAttributes = Pick<\n AriaAttributes,\n | \"aria-required\"\n | \"aria-invalid\"\n | \"aria-readonly\"\n | \"aria-disabled\"\n | \"aria-valuemin\"\n | \"aria-valuemax\"\n | \"aria-valuenow\"\n | \"aria-valuetext\"\n>;\n\n/**\n * This is a way to map a single character to a value within a spinbutton and\n * was mostly added to support time inputs. The main example is:\n *\n * @example Day Period Mapping\n * ```ts\n * const AM_PM: SpinButtonCharacterValueMap = {\n * a: 0,\n * p: 1,\n * };\n * ```\n *\n * **If the mapping is provided, all other input events are ignored**.\n *\n * @since 6.4.0\n */\nexport type SpinButtonCharacterValueMap = Readonly<Record<string, number>>;\n\n/**\n * @since 6.4.0\n */\nexport type SpinButtonValue = number | null;\n\n/**\n * @since 6.4.0\n */\nexport type SpinButtonGetValueText = (\n value: SpinButtonValue\n) => string | undefined;\n\n/**\n * @since 6.4.0\n */\nexport type SpinButtonChangeEvent<E extends HTMLElement = HTMLDivElement> =\n | FormEvent<E>\n | KeyboardEvent<E>\n | FocusEvent<E>;\n\n/**\n * @since 6.4.0\n */\nexport type SpinButtonChangeReason =\n | \"change\"\n | \"type\"\n | \"typed-to-completion\"\n | \"cleared\";\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonChangeEventOptions<\n E extends HTMLElement = HTMLDivElement,\n> {\n event: SpinButtonChangeEvent<E>;\n value: SpinButtonValue;\n reason: SpinButtonChangeReason;\n}\n\n/**\n * This callback will be fired whenever the spinbutton value has changed.\n *\n * The `reason` will be \"typed-to-completion\"` when:\n * - the `value` is not `null` and:\n * - the user uses the `ArrowUp`, `ArrowDown`, `Home`, `End`, `PageUp`, or\n * `PageDown` keys to change the value\n * - the user has typed the max amount of digits based on the `max` value\n *\n * Examples with: `min=0` and `max=12`\n * - `1` -> (1, false)\n * - `Tab` or blur (1, true)\n * - `1` -> (11, true)\n * - `0` - (1, false)\n * - `Tab` or blur (0, true)\n * - `3` (3, true)\n * - `3` -> (3, true)\n * - there are no more characters that could have been typed\n *\n *\n * @since 6.4.0\n */\nexport type SpinButtonValueChange<E extends HTMLElement = HTMLDivElement> = (\n options: SpinButtonChangeEventOptions<E>\n) => void;\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonUnknownValueOptions<\n E extends HTMLElement = HTMLDivElement,\n> {\n value?: SpinButtonValue;\n defaultValue?: UseStateInitializer<SpinButtonValue>;\n onValueChange?: SpinButtonValueChange<E>;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonControlledValueOptions<\n E extends HTMLElement = HTMLDivElement,\n> {\n value: SpinButtonValue;\n defaultValue?: never;\n onValueChange: SpinButtonValueChange<E>;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonUncontrolledValueOptions<\n E extends HTMLElement = HTMLDivElement,\n> {\n value?: never;\n defaultValue?: UseStateInitializer<SpinButtonValue>;\n onValueChange?: SpinButtonValueChange<E>;\n}\n\n/**\n * @since 6.4.0\n */\nexport type SpinButtonValueOptions<E extends HTMLElement = HTMLDivElement> =\n | SpinButtonControlledValueOptions<E>\n | SpinButtonUncontrolledValueOptions<E>;\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonDigitRangeOptions {\n /**\n * This is the minimum number of digits that should be shown in the spin\n * button as the user is typing. If the current value is less than this\n * value, the {@link placeholderChar} will be used as a `padStart` value.\n *\n * @example Get Text Content Example\n * ```ts\n * const textContent1 = getTextContent({\n * value: null,\n * fallback: \"HH\",\n * placeholderChar: \"0\",\n * });\n * // ^ textContent1 === \"HH\"\n *\n * const textContent2 = getTextContent({\n * value: 3,\n * fallback: \"HH\",\n * placeholderChar: \"0\",\n * });\n * // ^ textContent2 === \"03\"\n *\n * const textContent3 = getTextContent({\n * value: 12,\n * fallback: \"HH\",\n * placeholderChar: \"0\",\n * });\n * // ^ textContent3 === \"12\"\n * ```\n *\n * @example Year Example\n * ```ts\n * const textContent1 = getTextContent({\n * value: null,\n * fallback: \"YYYY\",\n * minDigits: 4,\n * });\n * // ^ textContent1 === \"YYYY\"\n *\n * const textContent2 = getTextContent({\n * value: 2,\n * fallback: \"YYYY\",\n * minDigits: 4,\n * });\n * // ^ textContent2 === \"0002\"\n *\n * const textContent3 = getTextContent({\n * value: 200,\n * fallback: \"YYYY\",\n * minDigits: 4,\n * });\n * // ^ textContent3 === \"0200\"\n *\n * const textContent4 = getTextContent({\n * value: 2025,\n * fallback: \"YYYY\",\n * minDigits: 4,\n * });\n * // ^ textContent4 === \"2025\"\n * ```\n *\n * @see {@link SpinButtonTextPlaceholderOptions.placeholderChar}\n * @defaultValue `fallback?.length ?? getNumberOfDigits(min)`\n */\n minDigits?: number;\n\n /**\n * This is the maximum number of digits that should be shown in the spin\n * button as the user is typing and is used to determine if the user has\n * `\"typed-to-completion\"`.\n *\n * @example Year Example\n * ```tsx\n * // this _could_ also be 9999\n * const max = undefined;\n * const maxDigits = 4;\n *\n * // if the current value is `null` and the user types `2`\n * onValueChange({\n * event,\n * reason: \"change\",\n * nextValue: 2,\n * });\n *\n * // if the current value is `2` and the user types `0`\n * onValueChange({\n * event,\n * reason: \"change\",\n * nextValue: 20,\n * });\n *\n * // if the current value is `20` and the user types `2`\n * onValueChange({\n * event,\n * reason: \"change\",\n * nextValue: 202,\n * });\n *\n * // if the current value is `202` and the user types `5`:\n * onValueChange({\n * event,\n * reason: \"typed-to-completion\",\n * nextValue: 2025,\n * });\n * ```\n *\n * @defaultValue `getNumberOfDigits(max)`\n */\n maxDigits?: number;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonRangeOptions\n extends Partial<MinMaxRange>, SpinButtonDigitRangeOptions {}\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonTextPlaceholderOptions extends SpinButtonRangeOptions {\n /**\n * An optional fallback value to display when the spin button's value is\n * `null`. For example: if the spin button is used to set the specific hour\n * in a time field, set the fallback to `\"HH\"` to show that until the user\n * has typed a value.\n */\n fallback?: string;\n\n /**\n * This is the character to use to fill the remaining number of digits to\n * display in the spin button.\n *\n * @see {@link minDigits}\n * @defaultValue `\"0\"`\n */\n placeholderChar?: string;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface GetSpinButtonTextContentOptions extends SpinButtonTextPlaceholderOptions {\n /**\n * The current value in the spin button to convert to text. **This will be\n * called with numbers outside of the allowed range**.\n */\n value: SpinButtonValue;\n}\n\n/**\n * @since 6.4.0\n */\nexport type GetSpinButtonTextContent = (\n options: GetSpinButtonTextContentOptions\n) => string;\n\n/**\n * @since 6.4.0\n */\nexport type GetSpinButtonValueText = (\n value: SpinButtonValue\n) => string | undefined;\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonFormStates extends Omit<\n FormComponentStates,\n \"active\"\n> {\n required?: boolean;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonOptions<E extends HTMLElement = HTMLDivElement>\n extends\n SpinButtonEventHandlers<E>,\n SpinButtonUnknownValueOptions<E>,\n SpinButtonFormStates,\n SpinButtonTextPlaceholderOptions {\n /**\n * @defaultValue `\"spinbutton-\" + useId()`\n */\n id?: string;\n ref?: Ref<E>;\n form?: string;\n\n /**\n * The default value to use when the increment or decrement action is fired\n * from the spinbutton through keyboard events before a value has been set.\n * So when the increment action is fired, this will be\n * `defaultKeyboardValue + 1`.\n *\n * @defaultValue `min ?? max ?? 0`\n */\n defaultKeyboardValue?: UseStateInitializer<number>;\n\n /**\n * NOTE: This isn't actually supported yet\n *\n * @defaultValue `1`\n */\n step?: number;\n\n /** @see {@link SpinButtonCharacterValueMap} */\n mappings?: SpinButtonCharacterValueMap;\n\n /**\n * Used to provide an `aria-valuenow` string for a specific value in the\n * `SpinButton`.\n *\n * @defaultValue `(value) => value === null ? \"No value selected\" : undefined`\n */\n getValueText?: GetSpinButtonValueText;\n\n getTextContent?: GetSpinButtonTextContent;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface ProvidedSpinButtonProps<E extends HTMLElement = HTMLDivElement>\n extends Required<SpinButtonEventHandlers<E>>, SpinButtonAriaAttributes {\n id: string;\n ref: Ref<E>;\n role: \"spinbutton\";\n inputMode: \"numeric\";\n spellCheck: boolean;\n autoCapitalize: \"none\";\n autoCorrect: \"off\";\n tabIndex: number | undefined;\n contentEditable: boolean | undefined;\n suppressContentEditableWarning: boolean;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface SpinButtonImplementation<\n E extends HTMLElement = HTMLDivElement,\n> {\n value: SpinButtonValue;\n setValue: (value: SpinButtonValue) => void;\n spinButtonRef: RefObject<E>;\n spinButtonProps: Readonly<ProvidedSpinButtonProps<E>>;\n}\n"],"names":[],"mappings":"AAkZA;;CAEC,GACD,WAOC"}
@@ -0,0 +1,5 @@
1
+ import { type SpinButtonImplementation, type SpinButtonOptions } from "./types.js";
2
+ /**
3
+ * @since 6.4.0
4
+ */
5
+ export declare function useSpinButton<E extends HTMLElement = HTMLDivElement>(options: SpinButtonOptions<E>): SpinButtonImplementation<E>;
@@ -0,0 +1,260 @@
1
+ "use client";
2
+ import { useCallback, useRef, useState } from "react";
3
+ import { tryToSubmitRelatedForm } from "../form/utils.js";
4
+ import { useEnsuredId } from "../useEnsuredId.js";
5
+ import { useEnsuredRef } from "../useEnsuredRef.js";
6
+ import { useEnsuredState } from "../useEnsuredState.js";
7
+ import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect.js";
8
+ import { withinRange } from "../utils/withinRange.js";
9
+ import { useSpinButtonGroup } from "./SpinButtonGroupProvider.js";
10
+ import { defaultGetSpinButtonTextContent, defaultSpinButtonGetValueText } from "./defaults.js";
11
+ import { deselectNode } from "./utils/deselectNode.js";
12
+ import { resolveInputEvent } from "./utils/resolveInputEvent.js";
13
+ import { selectNode } from "./utils/selectNode.js";
14
+ /**
15
+ * @since 6.4.0
16
+ */ const noop = ()=>{
17
+ // do nothing
18
+ };
19
+ /**
20
+ * @since 6.4.0
21
+ */ export function useSpinButton(options) {
22
+ const { id: propId, ref: propRef, min, max, step = 1, minDigits, maxDigits, form, readOnly, disabled, required, error, onBlur = noop, onFocus = noop, onInput = noop, onClick = noop, onKeyDown = noop, fallback, mappings, value: propValue, onValueChange = noop, defaultValue = null, getValueText = defaultSpinButtonGetValueText, getTextContent = defaultGetSpinButtonTextContent, placeholderChar, defaultKeyboardValue } = options;
23
+ const id = useEnsuredId(propId, "spinbutton");
24
+ // trigger a noop setValue when `value` and `onValueChange` are provided
25
+ // since `onValueChange is always called with `setValue
26
+ let propSetValue;
27
+ if (typeof propValue !== "undefined" && options.onValueChange) {
28
+ propSetValue = noop;
29
+ }
30
+ const [value, setValue] = useEnsuredState({
31
+ value: propValue,
32
+ setValue: propSetValue,
33
+ defaultValue
34
+ });
35
+ const focused = useRef(false);
36
+ const typedCount = useRef(0);
37
+ const prevText = useRef("");
38
+ const [nodeRef, nodeRefCallback] = useEnsuredRef(propRef);
39
+ const { focusNext } = useSpinButtonGroup();
40
+ const [keyboardValue] = useState(defaultKeyboardValue);
41
+ // NOTE: I might be able to get rid of this since I don't remember why it was
42
+ // added maybe for controlled fields? I'll have to see when I get to the
43
+ // date/time components again
44
+ useIsomorphicLayoutEffect(()=>{
45
+ const node = nodeRef.current;
46
+ if (!focused.current || !node) {
47
+ return;
48
+ }
49
+ prevText.current = node.textContent || "";
50
+ selectNode(node);
51
+ }, [
52
+ nodeRef,
53
+ value
54
+ ]);
55
+ const updateValue = useCallback((options)=>{
56
+ setValue(options.value);
57
+ onValueChange(options);
58
+ if (options.reason === "typed-to-completion") {
59
+ focusNext();
60
+ }
61
+ }, [
62
+ focusNext,
63
+ onValueChange,
64
+ setValue
65
+ ]);
66
+ const increment = useCallback((event)=>{
67
+ let nextValue = value ?? keyboardValue ?? min ?? max ?? 0;
68
+ nextValue = withinRange({
69
+ min,
70
+ max,
71
+ value: nextValue + step
72
+ });
73
+ // this actually means both min and max are a number
74
+ if (nextValue === value && typeof min === "number") {
75
+ nextValue = min;
76
+ }
77
+ updateValue({
78
+ event,
79
+ reason: "change",
80
+ value: nextValue
81
+ });
82
+ }, [
83
+ keyboardValue,
84
+ max,
85
+ min,
86
+ step,
87
+ updateValue,
88
+ value
89
+ ]);
90
+ const decrement = useCallback((event)=>{
91
+ let nextValue = value ?? keyboardValue ?? max ?? min ?? 0;
92
+ nextValue = withinRange({
93
+ min,
94
+ max,
95
+ value: nextValue - step
96
+ });
97
+ // this actually means both min and max are a number
98
+ if (nextValue === value && typeof max === "number") {
99
+ nextValue = max;
100
+ }
101
+ updateValue({
102
+ event,
103
+ reason: "change",
104
+ value: nextValue
105
+ });
106
+ }, [
107
+ keyboardValue,
108
+ max,
109
+ min,
110
+ step,
111
+ updateValue,
112
+ value
113
+ ]);
114
+ return {
115
+ value,
116
+ setValue,
117
+ spinButtonRef: nodeRef,
118
+ spinButtonProps: {
119
+ "aria-readonly": readOnly || undefined,
120
+ "aria-disabled": disabled || undefined,
121
+ "aria-invalid": error || undefined,
122
+ "aria-required": required || undefined,
123
+ "aria-valuemin": min,
124
+ "aria-valuemax": max,
125
+ "aria-valuenow": value === null ? undefined : value,
126
+ "aria-valuetext": getValueText(value),
127
+ id,
128
+ ref: nodeRefCallback,
129
+ role: "spinbutton",
130
+ autoCapitalize: "none",
131
+ autoCorrect: "off",
132
+ spellCheck: false,
133
+ inputMode: "numeric",
134
+ contentEditable: !disabled || undefined,
135
+ suppressContentEditableWarning: true,
136
+ tabIndex: disabled ? undefined : 0,
137
+ onBlur: (event)=>{
138
+ onBlur(event);
139
+ focused.current = false;
140
+ deselectNode(event.currentTarget);
141
+ },
142
+ onFocus: (event)=>{
143
+ onFocus(event);
144
+ if (disabled) {
145
+ return;
146
+ }
147
+ focused.current = true;
148
+ typedCount.current = 0;
149
+ selectNode(event.currentTarget);
150
+ },
151
+ onKeyDown: (event)=>{
152
+ onKeyDown(event);
153
+ if (disabled || readOnly && event.key !== "Enter") {
154
+ return;
155
+ }
156
+ const setValue = (nextValue)=>updateValue({
157
+ value: nextValue,
158
+ event,
159
+ reason: "change"
160
+ });
161
+ let stop = false;
162
+ switch(event.key){
163
+ case "ArrowRight":
164
+ case "ArrowLeft":
165
+ // `event.stopPropagation()` should not be called here since the
166
+ // parent `useSpinButtonGroup` keyboard event handler should
167
+ // still be called to handle advancing to the next spinbutton in
168
+ // the group. Only the default cursor movement needs to be disabled
169
+ // instead.
170
+ event.preventDefault();
171
+ break;
172
+ case "ArrowUp":
173
+ stop = true;
174
+ increment(event);
175
+ break;
176
+ case "ArrowDown":
177
+ stop = true;
178
+ decrement(event);
179
+ break;
180
+ case "Home":
181
+ stop = true;
182
+ if (typeof min === "number") {
183
+ setValue(min);
184
+ }
185
+ break;
186
+ case "End":
187
+ stop = true;
188
+ if (typeof max === "number") {
189
+ setValue(max);
190
+ }
191
+ break;
192
+ case "Enter":
193
+ stop = true;
194
+ tryToSubmitRelatedForm(event, form);
195
+ }
196
+ if (stop) {
197
+ event.preventDefault();
198
+ event.stopPropagation();
199
+ typedCount.current = 0;
200
+ }
201
+ },
202
+ onClick: (event)=>{
203
+ onClick(event);
204
+ event.preventDefault();
205
+ if (disabled) {
206
+ return;
207
+ }
208
+ focused.current = true;
209
+ typedCount.current = 0;
210
+ selectNode(event.currentTarget);
211
+ },
212
+ onInput: (event)=>{
213
+ onInput(event);
214
+ const node = event.currentTarget;
215
+ // if the input event is fired while readOnly or disabled, ignore it
216
+ // and set it back to the previous state
217
+ if (readOnly || disabled) {
218
+ node.textContent = prevText.current;
219
+ selectNode(node);
220
+ return;
221
+ }
222
+ const { reason, nextValue } = resolveInputEvent({
223
+ min,
224
+ max,
225
+ text: node.textContent || "",
226
+ mappings,
227
+ maxDigits,
228
+ prevText: prevText.current,
229
+ prevValue: value,
230
+ typedCount: typedCount.current
231
+ });
232
+ if (reason === "change" || reason === "cleared" || reason === "typed-to-completion") {
233
+ typedCount.current = 0;
234
+ } else if (reason !== "ignored") {
235
+ typedCount.current++;
236
+ }
237
+ node.textContent = getTextContent({
238
+ min,
239
+ max,
240
+ minDigits,
241
+ maxDigits,
242
+ value: nextValue,
243
+ fallback,
244
+ placeholderChar
245
+ });
246
+ prevText.current = node.textContent;
247
+ selectNode(node);
248
+ if (reason !== "ignored" && reason !== "placeholder-digit") {
249
+ updateValue({
250
+ event,
251
+ value: nextValue,
252
+ reason
253
+ });
254
+ }
255
+ }
256
+ }
257
+ };
258
+ }
259
+
260
+ //# sourceMappingURL=useSpinButton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/spinbutton/useSpinButton.ts"],"sourcesContent":["\"use client\";\n\nimport { type Dispatch, useCallback, useRef, useState } from \"react\";\n\nimport { tryToSubmitRelatedForm } from \"../form/utils.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useEnsuredState } from \"../useEnsuredState.js\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect.js\";\nimport { withinRange } from \"../utils/withinRange.js\";\nimport { useSpinButtonGroup } from \"./SpinButtonGroupProvider.js\";\nimport {\n defaultGetSpinButtonTextContent,\n defaultSpinButtonGetValueText,\n} from \"./defaults.js\";\nimport {\n type SpinButtonChangeEvent,\n type SpinButtonChangeEventOptions,\n type SpinButtonImplementation,\n type SpinButtonOptions,\n type SpinButtonValue,\n} from \"./types.js\";\nimport { deselectNode } from \"./utils/deselectNode.js\";\nimport { resolveInputEvent } from \"./utils/resolveInputEvent.js\";\nimport { selectNode } from \"./utils/selectNode.js\";\n\n/**\n * @since 6.4.0\n */\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 6.4.0\n */\nexport function useSpinButton<E extends HTMLElement = HTMLDivElement>(\n options: SpinButtonOptions<E>\n): SpinButtonImplementation<E> {\n const {\n id: propId,\n ref: propRef,\n min,\n max,\n step = 1,\n minDigits,\n maxDigits,\n form,\n readOnly,\n disabled,\n required,\n error,\n onBlur = noop,\n onFocus = noop,\n onInput = noop,\n onClick = noop,\n onKeyDown = noop,\n fallback,\n mappings,\n value: propValue,\n onValueChange = noop,\n defaultValue = null,\n getValueText = defaultSpinButtonGetValueText,\n getTextContent = defaultGetSpinButtonTextContent,\n placeholderChar,\n defaultKeyboardValue,\n } = options;\n const id = useEnsuredId(propId, \"spinbutton\");\n\n // trigger a noop setValue when `value` and `onValueChange` are provided\n // since `onValueChange is always called with `setValue\n let propSetValue: Dispatch<SpinButtonValue> | undefined;\n if (typeof propValue !== \"undefined\" && options.onValueChange) {\n propSetValue = noop;\n }\n\n const [value, setValue] = useEnsuredState({\n value: propValue,\n setValue: propSetValue,\n defaultValue,\n });\n\n const focused = useRef(false);\n const typedCount = useRef(0);\n const prevText = useRef(\"\");\n const [nodeRef, nodeRefCallback] = useEnsuredRef(propRef);\n const { focusNext } = useSpinButtonGroup();\n const [keyboardValue] = useState(defaultKeyboardValue);\n\n // NOTE: I might be able to get rid of this since I don't remember why it was\n // added maybe for controlled fields? I'll have to see when I get to the\n // date/time components again\n useIsomorphicLayoutEffect(() => {\n const node = nodeRef.current;\n if (!focused.current || !node) {\n return;\n }\n\n prevText.current = node.textContent || \"\";\n selectNode(node);\n }, [nodeRef, value]);\n\n const updateValue = useCallback(\n (options: SpinButtonChangeEventOptions<E>) => {\n setValue(options.value);\n onValueChange(options);\n if (options.reason === \"typed-to-completion\") {\n focusNext();\n }\n },\n [focusNext, onValueChange, setValue]\n );\n const increment = useCallback(\n (event: SpinButtonChangeEvent<E>) => {\n let nextValue: SpinButtonValue =\n value ?? keyboardValue ?? min ?? max ?? 0;\n nextValue = withinRange({ min, max, value: nextValue + step });\n\n // this actually means both min and max are a number\n if (nextValue === value && typeof min === \"number\") {\n nextValue = min;\n }\n\n updateValue({\n event,\n reason: \"change\",\n value: nextValue,\n });\n },\n [keyboardValue, max, min, step, updateValue, value]\n );\n const decrement = useCallback(\n (event: SpinButtonChangeEvent<E>) => {\n let nextValue: SpinButtonValue =\n value ?? keyboardValue ?? max ?? min ?? 0;\n nextValue = withinRange({ min, max, value: nextValue - step });\n\n // this actually means both min and max are a number\n if (nextValue === value && typeof max === \"number\") {\n nextValue = max;\n }\n\n updateValue({\n event,\n reason: \"change\",\n value: nextValue,\n });\n },\n [keyboardValue, max, min, step, updateValue, value]\n );\n\n return {\n value,\n setValue,\n spinButtonRef: nodeRef,\n spinButtonProps: {\n \"aria-readonly\": readOnly || undefined,\n \"aria-disabled\": disabled || undefined,\n \"aria-invalid\": error || undefined,\n \"aria-required\": required || undefined,\n \"aria-valuemin\": min,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value === null ? undefined : value,\n \"aria-valuetext\": getValueText(value),\n id,\n ref: nodeRefCallback,\n role: \"spinbutton\",\n autoCapitalize: \"none\",\n autoCorrect: \"off\",\n spellCheck: false,\n inputMode: \"numeric\",\n contentEditable: !disabled || undefined,\n suppressContentEditableWarning: true,\n tabIndex: disabled ? undefined : 0,\n onBlur: (event) => {\n onBlur(event);\n\n focused.current = false;\n deselectNode(event.currentTarget);\n },\n onFocus: (event) => {\n onFocus(event);\n\n if (disabled) {\n return;\n }\n\n focused.current = true;\n typedCount.current = 0;\n selectNode(event.currentTarget);\n },\n onKeyDown: (event) => {\n onKeyDown(event);\n\n if (disabled || (readOnly && event.key !== \"Enter\")) {\n return;\n }\n\n const setValue = (nextValue: number): void =>\n updateValue({ value: nextValue, event, reason: \"change\" });\n\n let stop = false;\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowLeft\":\n // `event.stopPropagation()` should not be called here since the\n // parent `useSpinButtonGroup` keyboard event handler should\n // still be called to handle advancing to the next spinbutton in\n // the group. Only the default cursor movement needs to be disabled\n // instead.\n event.preventDefault();\n break;\n case \"ArrowUp\":\n stop = true;\n increment(event);\n break;\n case \"ArrowDown\":\n stop = true;\n decrement(event);\n break;\n case \"Home\":\n stop = true;\n if (typeof min === \"number\") {\n setValue(min);\n }\n break;\n case \"End\":\n stop = true;\n if (typeof max === \"number\") {\n setValue(max);\n }\n break;\n case \"Enter\":\n stop = true;\n tryToSubmitRelatedForm(event, form);\n }\n\n if (stop) {\n event.preventDefault();\n event.stopPropagation();\n typedCount.current = 0;\n }\n },\n onClick: (event) => {\n onClick(event);\n\n event.preventDefault();\n if (disabled) {\n return;\n }\n\n focused.current = true;\n typedCount.current = 0;\n selectNode(event.currentTarget);\n },\n onInput: (event) => {\n onInput(event);\n\n const node = event.currentTarget;\n // if the input event is fired while readOnly or disabled, ignore it\n // and set it back to the previous state\n if (readOnly || disabled) {\n node.textContent = prevText.current;\n selectNode(node);\n return;\n }\n\n const { reason, nextValue } = resolveInputEvent({\n min,\n max,\n text: node.textContent || \"\",\n mappings,\n maxDigits,\n prevText: prevText.current,\n prevValue: value,\n typedCount: typedCount.current,\n });\n\n if (\n reason === \"change\" ||\n reason === \"cleared\" ||\n reason === \"typed-to-completion\"\n ) {\n typedCount.current = 0;\n } else if (reason !== \"ignored\") {\n typedCount.current++;\n }\n\n node.textContent = getTextContent({\n min,\n max,\n minDigits,\n maxDigits,\n value: nextValue,\n fallback,\n placeholderChar,\n });\n prevText.current = node.textContent;\n selectNode(node);\n\n if (reason !== \"ignored\" && reason !== \"placeholder-digit\") {\n updateValue({\n event,\n value: nextValue,\n reason,\n });\n }\n },\n },\n };\n}\n"],"names":["useCallback","useRef","useState","tryToSubmitRelatedForm","useEnsuredId","useEnsuredRef","useEnsuredState","useIsomorphicLayoutEffect","withinRange","useSpinButtonGroup","defaultGetSpinButtonTextContent","defaultSpinButtonGetValueText","deselectNode","resolveInputEvent","selectNode","noop","useSpinButton","options","id","propId","ref","propRef","min","max","step","minDigits","maxDigits","form","readOnly","disabled","required","error","onBlur","onFocus","onInput","onClick","onKeyDown","fallback","mappings","value","propValue","onValueChange","defaultValue","getValueText","getTextContent","placeholderChar","defaultKeyboardValue","propSetValue","setValue","focused","typedCount","prevText","nodeRef","nodeRefCallback","focusNext","keyboardValue","node","current","textContent","updateValue","reason","increment","event","nextValue","decrement","spinButtonRef","spinButtonProps","undefined","role","autoCapitalize","autoCorrect","spellCheck","inputMode","contentEditable","suppressContentEditableWarning","tabIndex","currentTarget","key","stop","preventDefault","stopPropagation","text","prevValue"],"mappings":"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"}