@react-md/core 6.3.4 → 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 (450) 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/button/Button.js.map +1 -1
  13. package/dist/button/FloatingActionButton.js.map +1 -1
  14. package/dist/card/Card.js.map +1 -1
  15. package/dist/card/CardContent.js.map +1 -1
  16. package/dist/card/ClickableCard.js.map +1 -1
  17. package/dist/chip/Chip.js.map +1 -1
  18. package/dist/datetime/NativeDateField.js.map +1 -1
  19. package/dist/datetime/NativeTimeField.js.map +1 -1
  20. package/dist/datetime/useDateField.js.map +1 -1
  21. package/dist/datetime/useTimeField.js.map +1 -1
  22. package/dist/dialog/Dialog.js.map +1 -1
  23. package/dist/dialog/DialogContainer.js.map +1 -1
  24. package/dist/dialog/DialogContent.js.map +1 -1
  25. package/dist/dialog/DialogFooter.js.map +1 -1
  26. package/dist/divider/Divider.js.map +1 -1
  27. package/dist/draggable/useDraggable.js.map +1 -1
  28. package/dist/draggable/utils.js.map +1 -1
  29. package/dist/expansion-panel/ExpansionPanelHeader.js.map +1 -1
  30. package/dist/files/FileInput.js.map +1 -1
  31. package/dist/files/useFileUpload.js.map +1 -1
  32. package/dist/files/validation.js.map +1 -1
  33. package/dist/focus/useFocusContainer.js.map +1 -1
  34. package/dist/form/Fieldset.d.ts +19 -0
  35. package/dist/form/Fieldset.js +22 -2
  36. package/dist/form/Fieldset.js.map +1 -1
  37. package/dist/form/FormMessageContainer.js.map +1 -1
  38. package/dist/form/FormMessageCounter.js.map +1 -1
  39. package/dist/form/InputToggle.js.map +1 -1
  40. package/dist/form/Legend.d.ts +27 -5
  41. package/dist/form/Legend.js +39 -6
  42. package/dist/form/Legend.js.map +1 -1
  43. package/dist/form/Listbox.js.map +1 -1
  44. package/dist/form/ListboxProvider.js.map +1 -1
  45. package/dist/form/NativeSelect.js.map +1 -1
  46. package/dist/form/Password.js.map +1 -1
  47. package/dist/form/ResizingTextAreaWrapper.js.map +1 -1
  48. package/dist/form/Select.js.map +1 -1
  49. package/dist/form/Slider.js.map +1 -1
  50. package/dist/form/SliderContainer.js.map +1 -1
  51. package/dist/form/SliderThumb.js.map +1 -1
  52. package/dist/form/SliderTrack.js.map +1 -1
  53. package/dist/form/SliderValueMarks.js.map +1 -1
  54. package/dist/form/Switch.js.map +1 -1
  55. package/dist/form/TextArea.js.map +1 -1
  56. package/dist/form/TextField.js.map +1 -1
  57. package/dist/form/TextFieldContainer.js.map +1 -1
  58. package/dist/form/_fieldset.scss +7 -0
  59. package/dist/form/_legend.scss +68 -0
  60. package/dist/form/_text-field.scss +39 -4
  61. package/dist/form/fieldsetStyles.d.ts +6 -1
  62. package/dist/form/fieldsetStyles.js +3 -2
  63. package/dist/form/fieldsetStyles.js.map +1 -1
  64. package/dist/form/inputToggleStyles.js.map +1 -1
  65. package/dist/form/labelStyles.d.ts +1 -1
  66. package/dist/form/labelStyles.js +1 -1
  67. package/dist/form/labelStyles.js.map +1 -1
  68. package/dist/form/legendStyles.d.ts +83 -0
  69. package/dist/form/legendStyles.js +25 -0
  70. package/dist/form/legendStyles.js.map +1 -0
  71. package/dist/form/selectUtils.js.map +1 -1
  72. package/dist/form/textFieldContainerStyles.js.map +1 -1
  73. package/dist/form/types.d.ts +28 -6
  74. package/dist/form/types.js.map +1 -1
  75. package/dist/form/useCheckboxGroup.js.map +1 -1
  76. package/dist/form/useCombobox.js.map +1 -1
  77. package/dist/form/useNumberField.js +16 -19
  78. package/dist/form/useNumberField.js.map +1 -1
  79. package/dist/form/useRangeSlider.js.map +1 -1
  80. package/dist/form/useSlider.js.map +1 -1
  81. package/dist/form/useTextField.js.map +1 -1
  82. package/dist/hoverMode/useHoverMode.js.map +1 -1
  83. package/dist/icon/FontIcon.js.map +1 -1
  84. package/dist/icon/IconRotator.js.map +1 -1
  85. package/dist/icon/MaterialIcon.js.map +1 -1
  86. package/dist/icon/MaterialSymbol.js.map +1 -1
  87. package/dist/icon/SVGIcon.js.map +1 -1
  88. package/dist/icon/config.d.ts +0 -1
  89. package/dist/icon/config.js +10 -7
  90. package/dist/icon/config.js.map +1 -1
  91. package/dist/icon/materialConfig.js.map +1 -1
  92. package/dist/icon/styles.js.map +1 -1
  93. package/dist/interaction/UserInteractionModeProvider.js +6 -4
  94. package/dist/interaction/UserInteractionModeProvider.js.map +1 -1
  95. package/dist/interaction/types.js.map +1 -1
  96. package/dist/interaction/useElementInteraction.js.map +1 -1
  97. package/dist/layout/LayoutAppBar.d.ts +6 -6
  98. package/dist/layout/LayoutAppBar.js +6 -6
  99. package/dist/layout/LayoutAppBar.js.map +1 -1
  100. package/dist/layout/LayoutNav.js.map +1 -1
  101. package/dist/layout/LayoutWindowSplitter.js.map +1 -1
  102. package/dist/layout/Main.js.map +1 -1
  103. package/dist/layout/useExpandableLayout.js +43 -0
  104. package/dist/layout/useExpandableLayout.js.map +1 -1
  105. package/dist/layout/useHorizontalLayoutTransition.js.map +1 -1
  106. package/dist/layout/useLayoutTree.js.map +1 -1
  107. package/dist/layout/useLayoutWindowSplitter.js.map +1 -1
  108. package/dist/layout/useResizableLayout.js.map +1 -1
  109. package/dist/link/Link.js.map +1 -1
  110. package/dist/link/SkipToMainContent.js +19 -21
  111. package/dist/link/SkipToMainContent.js.map +1 -1
  112. package/dist/list/List.js.map +1 -1
  113. package/dist/list/ListItem.js.map +1 -1
  114. package/dist/list/ListItemAddon.js.map +1 -1
  115. package/dist/list/ListItemLink.js.map +1 -1
  116. package/dist/list/ListSubheader.js.map +1 -1
  117. package/dist/list/getListItemHeight.js.map +1 -1
  118. package/dist/list/listItemStyles.js.map +1 -1
  119. package/dist/list/types.js.map +1 -1
  120. package/dist/media-queries/AppSizeProvider.d.ts +2 -0
  121. package/dist/media-queries/AppSizeProvider.js +3 -2
  122. package/dist/media-queries/AppSizeProvider.js.map +1 -1
  123. package/dist/media-queries/appSize.d.ts +3 -0
  124. package/dist/media-queries/appSize.js +3 -1
  125. package/dist/media-queries/appSize.js.map +1 -1
  126. package/dist/media-queries/config.d.ts +11 -0
  127. package/dist/media-queries/config.js +26 -0
  128. package/dist/media-queries/config.js.map +1 -0
  129. package/dist/menu/DropdownMenu.js.map +1 -1
  130. package/dist/menu/Menu.js.map +1 -1
  131. package/dist/menu/MenuItemButton.js.map +1 -1
  132. package/dist/menu/MenuItemFileInput.js.map +1 -1
  133. package/dist/menu/MenuItemInputToggle.js.map +1 -1
  134. package/dist/menu/MenuItemSeparator.js.map +1 -1
  135. package/dist/menu/MenuVisibilityProvider.js.map +1 -1
  136. package/dist/menu/MenuWidget.js.map +1 -1
  137. package/dist/menu/useContextMenu.js.map +1 -1
  138. package/dist/movement/types.d.ts +28 -3
  139. package/dist/movement/types.js.map +1 -1
  140. package/dist/movement/useKeyboardMovementProvider.js +96 -47
  141. package/dist/movement/useKeyboardMovementProvider.js.map +1 -1
  142. package/dist/navigation/CollapsibleNavGroup.js.map +1 -1
  143. package/dist/navigation/NavItem.js.map +1 -1
  144. package/dist/navigation/NavItemButton.js.map +1 -1
  145. package/dist/navigation/NavItemLink.js.map +1 -1
  146. package/dist/navigation/getTableOfContentsHeadings.js.map +1 -1
  147. package/dist/navigation/types.js.map +1 -1
  148. package/dist/overlay/Overlay.js.map +1 -1
  149. package/dist/positioning/createHorizontalPosition.js.map +1 -1
  150. package/dist/positioning/createVerticalPosition.js.map +1 -1
  151. package/dist/positioning/useFixedPositioning.js.map +1 -1
  152. package/dist/progress/CircularProgress.js.map +1 -1
  153. package/dist/progress/LinearProgress.js.map +1 -1
  154. package/dist/progress/linearProgressStyles.js.map +1 -1
  155. package/dist/responsive-item/ResponsiveItem.js.map +1 -1
  156. package/dist/responsive-item/ResponsiveItemOverlay.js.map +1 -1
  157. package/dist/searching/caseInsensitive.js.map +1 -1
  158. package/dist/segmented-button/SegmentedButton.js.map +1 -1
  159. package/dist/segmented-button/SegmentedButtonContainer.js.map +1 -1
  160. package/dist/segmented-button/segmentedButtonStyles.js.map +1 -1
  161. package/dist/sheet/Sheet.js.map +1 -1
  162. package/dist/snackbar/Toast.js.map +1 -1
  163. package/dist/spinbutton/SpinButton.d.ts +16 -0
  164. package/dist/spinbutton/SpinButton.js +55 -0
  165. package/dist/spinbutton/SpinButton.js.map +1 -0
  166. package/dist/spinbutton/SpinButtonGroupProvider.d.ts +17 -0
  167. package/dist/spinbutton/SpinButtonGroupProvider.js +19 -0
  168. package/dist/spinbutton/SpinButtonGroupProvider.js.map +1 -0
  169. package/dist/spinbutton/defaults.d.ts +9 -0
  170. package/dist/spinbutton/defaults.js +25 -0
  171. package/dist/spinbutton/defaults.js.map +1 -0
  172. package/dist/spinbutton/types.d.ts +324 -0
  173. package/dist/spinbutton/types.js +5 -0
  174. package/dist/spinbutton/types.js.map +1 -0
  175. package/dist/spinbutton/useSpinButton.d.ts +5 -0
  176. package/dist/spinbutton/useSpinButton.js +260 -0
  177. package/dist/spinbutton/useSpinButton.js.map +1 -0
  178. package/dist/spinbutton/useSpinButtonGroupProvider.d.ts +27 -0
  179. package/dist/spinbutton/useSpinButtonGroupProvider.js +49 -0
  180. package/dist/spinbutton/useSpinButtonGroupProvider.js.map +1 -0
  181. package/dist/spinbutton/utils/deselectNode.d.ts +5 -0
  182. package/dist/spinbutton/utils/deselectNode.js +17 -0
  183. package/dist/spinbutton/utils/deselectNode.js.map +1 -0
  184. package/dist/spinbutton/utils/resolveInputEvent.d.ts +30 -0
  185. package/dist/spinbutton/utils/resolveInputEvent.js +53 -0
  186. package/dist/spinbutton/utils/resolveInputEvent.js.map +1 -0
  187. package/dist/spinbutton/utils/selectNode.d.ts +5 -0
  188. package/dist/spinbutton/utils/selectNode.js +15 -0
  189. package/dist/spinbutton/utils/selectNode.js.map +1 -0
  190. package/dist/table/StickyTableSection.js.map +1 -1
  191. package/dist/table/Table.js.map +1 -1
  192. package/dist/table/TableBody.js.map +1 -1
  193. package/dist/table/TableCellContent.js.map +1 -1
  194. package/dist/table/TableCheckbox.js.map +1 -1
  195. package/dist/table/TableFooter.js.map +1 -1
  196. package/dist/table/TableHeader.js.map +1 -1
  197. package/dist/table/TableRadio.js.map +1 -1
  198. package/dist/table/TableRow.js.map +1 -1
  199. package/dist/table/useStickyTableSection.js.map +1 -1
  200. package/dist/tabs/SimpleTabPanel.js.map +1 -1
  201. package/dist/tabs/SimpleTabPanels.js.map +1 -1
  202. package/dist/tabs/Tab.js.map +1 -1
  203. package/dist/tabs/TabList.js.map +1 -1
  204. package/dist/tabs/TabListScrollButton.js.map +1 -1
  205. package/dist/tabs/useMaxTabPanelHeight.js.map +1 -1
  206. package/dist/test-utils/data-testid.js.map +1 -1
  207. package/dist/test-utils/mocks/match-media.js +5 -5
  208. package/dist/test-utils/mocks/match-media.js.map +1 -1
  209. package/dist/test-utils/vitest/timers.d.ts +1 -1
  210. package/dist/test-utils/vitest/timers.js +1 -1
  211. package/dist/test-utils/vitest/timers.js.map +1 -1
  212. package/dist/tooltip/Tooltip.js.map +1 -1
  213. package/dist/tooltip/TooltipHoverModeProvider.js.map +1 -1
  214. package/dist/tooltip/useTooltip.js.map +1 -1
  215. package/dist/transition/CSSTransition.js.map +1 -1
  216. package/dist/transition/Collapse.js.map +1 -1
  217. package/dist/transition/CrossFade.js.map +1 -1
  218. package/dist/transition/ScaleTransition.js.map +1 -1
  219. package/dist/transition/SkeletonPlaceholder.js.map +1 -1
  220. package/dist/transition/Slide.js.map +1 -1
  221. package/dist/transition/SlideContainer.js.map +1 -1
  222. package/dist/transition/types.js.map +1 -1
  223. package/dist/transition/useCollapseTransition.js.map +1 -1
  224. package/dist/transition/useCrossFadeTransition.js.map +1 -1
  225. package/dist/transition/useMaxWidthTransition.js.map +1 -1
  226. package/dist/transition/useScaleTransition.js.map +1 -1
  227. package/dist/transition/useSkeletonPlaceholder.js.map +1 -1
  228. package/dist/tree/Tree.js.map +1 -1
  229. package/dist/tree/TreeItem.js.map +1 -1
  230. package/dist/tree/TreeProvider.js.map +1 -1
  231. package/dist/tree/styles.js.map +1 -1
  232. package/dist/tree/types.js.map +1 -1
  233. package/dist/tree/useTreeMovement.js.map +1 -1
  234. package/dist/typography/HighlightTextMark.js.map +1 -1
  235. package/dist/typography/Mark.js.map +1 -1
  236. package/dist/typography/TextContainer.js.map +1 -1
  237. package/dist/typography/Typography.js.map +1 -1
  238. package/dist/typography/_typography.scss +0 -1
  239. package/dist/useElementSize.js.map +1 -1
  240. package/dist/useIntersectionObserver.js.map +1 -1
  241. package/dist/useMutationObserver.js.map +1 -1
  242. package/dist/useWindowSize.js.map +1 -1
  243. package/dist/utils/getNumberOfDigits.d.ts +7 -0
  244. package/dist/utils/getNumberOfDigits.js +11 -0
  245. package/dist/utils/getNumberOfDigits.js.map +1 -0
  246. package/dist/utils/nearest.js +2 -1
  247. package/dist/utils/nearest.js.map +1 -1
  248. package/dist/utils/useDevEffect.d.ts +7 -0
  249. package/dist/utils/useDevEffect.js +8 -0
  250. package/dist/utils/useDevEffect.js.map +1 -0
  251. package/dist/window-splitter/WindowSplitter.js +3 -2
  252. package/dist/window-splitter/WindowSplitter.js.map +1 -1
  253. package/dist/window-splitter/_window-splitter.scss +60 -12
  254. package/dist/window-splitter/styles.d.ts +9 -0
  255. package/dist/window-splitter/styles.js +3 -2
  256. package/dist/window-splitter/styles.js.map +1 -1
  257. package/dist/window-splitter/useWindowSplitter.js.map +1 -1
  258. package/package.json +37 -29
  259. package/src/CoreProviders.tsx +1 -0
  260. package/src/app-bar/AppBar.tsx +1 -2
  261. package/src/app-bar/AppBarTitle.tsx +1 -2
  262. package/src/autocomplete/AutocompleteListboxChildren.tsx +3 -1
  263. package/src/autocomplete/types.ts +24 -19
  264. package/src/autocomplete/utils.ts +9 -6
  265. package/src/avatar/Avatar.tsx +2 -1
  266. package/src/button/Button.tsx +2 -1
  267. package/src/button/FloatingActionButton.tsx +2 -1
  268. package/src/card/Card.tsx +2 -1
  269. package/src/card/CardContent.tsx +1 -2
  270. package/src/card/ClickableCard.tsx +1 -2
  271. package/src/chip/Chip.tsx +2 -1
  272. package/src/datetime/NativeDateField.tsx +2 -1
  273. package/src/datetime/NativeTimeField.tsx +2 -1
  274. package/src/datetime/useDateField.ts +13 -8
  275. package/src/datetime/useTimeField.ts +13 -8
  276. package/src/dialog/Dialog.tsx +2 -1
  277. package/src/dialog/DialogContainer.tsx +1 -2
  278. package/src/dialog/DialogContent.tsx +1 -2
  279. package/src/dialog/DialogFooter.tsx +1 -2
  280. package/src/divider/Divider.tsx +1 -2
  281. package/src/draggable/useDraggable.ts +4 -4
  282. package/src/draggable/utils.ts +4 -2
  283. package/src/expansion-panel/ExpansionPanelHeader.tsx +1 -2
  284. package/src/files/FileInput.tsx +2 -1
  285. package/src/files/useFileUpload.ts +6 -6
  286. package/src/files/validation.ts +1 -2
  287. package/src/focus/useFocusContainer.ts +4 -4
  288. package/src/form/Fieldset.tsx +25 -3
  289. package/src/form/FormMessageContainer.tsx +1 -2
  290. package/src/form/FormMessageCounter.tsx +1 -2
  291. package/src/form/InputToggle.tsx +3 -3
  292. package/src/form/Legend.tsx +55 -10
  293. package/src/form/Listbox.tsx +1 -2
  294. package/src/form/ListboxProvider.ts +3 -2
  295. package/src/form/NativeSelect.tsx +2 -1
  296. package/src/form/Password.tsx +4 -2
  297. package/src/form/ResizingTextAreaWrapper.tsx +1 -2
  298. package/src/form/Select.tsx +2 -1
  299. package/src/form/Slider.tsx +2 -1
  300. package/src/form/SliderContainer.tsx +1 -2
  301. package/src/form/SliderThumb.tsx +6 -3
  302. package/src/form/SliderTrack.tsx +2 -1
  303. package/src/form/SliderValueMarks.tsx +1 -2
  304. package/src/form/Switch.tsx +2 -1
  305. package/src/form/TextArea.tsx +1 -2
  306. package/src/form/TextField.tsx +2 -1
  307. package/src/form/TextFieldContainer.tsx +1 -2
  308. package/src/form/fieldsetStyles.ts +18 -3
  309. package/src/form/inputToggleStyles.ts +4 -2
  310. package/src/form/labelStyles.ts +1 -1
  311. package/src/form/legendStyles.ts +132 -0
  312. package/src/form/selectUtils.ts +3 -2
  313. package/src/form/textFieldContainerStyles.ts +1 -2
  314. package/src/form/types.ts +35 -17
  315. package/src/form/useCheckboxGroup.ts +3 -2
  316. package/src/form/useCombobox.ts +8 -3
  317. package/src/form/useNumberField.ts +36 -35
  318. package/src/form/useRangeSlider.ts +1 -2
  319. package/src/form/useSlider.ts +1 -2
  320. package/src/form/useTextField.ts +8 -3
  321. package/src/hoverMode/useHoverMode.ts +4 -8
  322. package/src/icon/FontIcon.tsx +1 -2
  323. package/src/icon/IconRotator.tsx +1 -2
  324. package/src/icon/MaterialIcon.tsx +2 -1
  325. package/src/icon/MaterialSymbol.tsx +2 -1
  326. package/src/icon/SVGIcon.tsx +1 -2
  327. package/src/icon/config.tsx +10 -7
  328. package/src/icon/materialConfig.ts +1 -2
  329. package/src/icon/styles.ts +1 -2
  330. package/src/interaction/UserInteractionModeProvider.tsx +9 -4
  331. package/src/interaction/types.ts +1 -2
  332. package/src/interaction/useElementInteraction.tsx +3 -2
  333. package/src/layout/LayoutAppBar.tsx +6 -6
  334. package/src/layout/LayoutNav.tsx +2 -1
  335. package/src/layout/LayoutWindowSplitter.tsx +2 -1
  336. package/src/layout/Main.tsx +1 -2
  337. package/src/layout/useExpandableLayout.ts +63 -5
  338. package/src/layout/useHorizontalLayoutTransition.ts +1 -2
  339. package/src/layout/useLayoutTree.ts +2 -2
  340. package/src/layout/useLayoutWindowSplitter.ts +6 -6
  341. package/src/layout/useResizableLayout.ts +3 -6
  342. package/src/link/Link.tsx +1 -2
  343. package/src/link/SkipToMainContent.tsx +20 -23
  344. package/src/list/List.tsx +1 -2
  345. package/src/list/ListItem.tsx +2 -1
  346. package/src/list/ListItemAddon.tsx +2 -1
  347. package/src/list/ListItemLink.tsx +2 -1
  348. package/src/list/ListSubheader.tsx +1 -2
  349. package/src/list/getListItemHeight.ts +8 -9
  350. package/src/list/listItemStyles.ts +1 -2
  351. package/src/list/types.ts +1 -2
  352. package/src/media-queries/AppSizeProvider.tsx +8 -10
  353. package/src/media-queries/appSize.ts +3 -0
  354. package/src/media-queries/config.ts +41 -0
  355. package/src/menu/DropdownMenu.tsx +4 -5
  356. package/src/menu/Menu.tsx +2 -1
  357. package/src/menu/MenuItemButton.tsx +1 -2
  358. package/src/menu/MenuItemFileInput.tsx +2 -1
  359. package/src/menu/MenuItemInputToggle.tsx +3 -3
  360. package/src/menu/MenuItemSeparator.tsx +2 -1
  361. package/src/menu/MenuVisibilityProvider.tsx +4 -2
  362. package/src/menu/MenuWidget.tsx +1 -2
  363. package/src/menu/useContextMenu.ts +4 -2
  364. package/src/movement/types.ts +52 -13
  365. package/src/movement/useKeyboardMovementProvider.ts +77 -38
  366. package/src/navigation/CollapsibleNavGroup.tsx +1 -2
  367. package/src/navigation/NavItem.tsx +1 -2
  368. package/src/navigation/NavItemButton.tsx +2 -1
  369. package/src/navigation/NavItemLink.tsx +2 -1
  370. package/src/navigation/getTableOfContentsHeadings.ts +1 -2
  371. package/src/navigation/types.ts +1 -2
  372. package/src/overlay/Overlay.tsx +2 -1
  373. package/src/positioning/createHorizontalPosition.ts +10 -12
  374. package/src/positioning/createVerticalPosition.ts +10 -11
  375. package/src/positioning/useFixedPositioning.ts +6 -3
  376. package/src/progress/CircularProgress.tsx +2 -1
  377. package/src/progress/LinearProgress.tsx +2 -1
  378. package/src/progress/linearProgressStyles.ts +1 -2
  379. package/src/responsive-item/ResponsiveItem.tsx +1 -2
  380. package/src/responsive-item/ResponsiveItemOverlay.tsx +2 -1
  381. package/src/searching/caseInsensitive.ts +2 -4
  382. package/src/segmented-button/SegmentedButton.tsx +2 -1
  383. package/src/segmented-button/SegmentedButtonContainer.tsx +2 -1
  384. package/src/segmented-button/segmentedButtonStyles.ts +1 -2
  385. package/src/sheet/Sheet.tsx +1 -2
  386. package/src/snackbar/Toast.tsx +2 -1
  387. package/src/spinbutton/SpinButton.tsx +98 -0
  388. package/src/spinbutton/SpinButtonGroupProvider.tsx +32 -0
  389. package/src/spinbutton/defaults.ts +45 -0
  390. package/src/spinbutton/types.ts +413 -0
  391. package/src/spinbutton/useSpinButton.ts +311 -0
  392. package/src/spinbutton/useSpinButtonGroupProvider.ts +104 -0
  393. package/src/spinbutton/utils/deselectNode.ts +17 -0
  394. package/src/spinbutton/utils/resolveInputEvent.ts +112 -0
  395. package/src/spinbutton/utils/selectNode.ts +15 -0
  396. package/src/table/StickyTableSection.tsx +2 -1
  397. package/src/table/Table.tsx +1 -2
  398. package/src/table/TableBody.tsx +2 -1
  399. package/src/table/TableCellContent.tsx +1 -2
  400. package/src/table/TableCheckbox.tsx +1 -2
  401. package/src/table/TableFooter.tsx +1 -2
  402. package/src/table/TableHeader.tsx +1 -2
  403. package/src/table/TableRadio.tsx +1 -2
  404. package/src/table/TableRow.tsx +1 -2
  405. package/src/table/useStickyTableSection.tsx +1 -2
  406. package/src/tabs/SimpleTabPanel.tsx +2 -1
  407. package/src/tabs/SimpleTabPanels.tsx +2 -1
  408. package/src/tabs/Tab.tsx +3 -6
  409. package/src/tabs/TabList.tsx +2 -1
  410. package/src/tabs/TabListScrollButton.tsx +1 -2
  411. package/src/tabs/useMaxTabPanelHeight.ts +7 -4
  412. package/src/test-utils/data-testid.ts +1 -2
  413. package/src/test-utils/mocks/match-media.ts +5 -10
  414. package/src/test-utils/vitest/timers.ts +1 -1
  415. package/src/tooltip/Tooltip.tsx +2 -1
  416. package/src/tooltip/TooltipHoverModeProvider.tsx +1 -2
  417. package/src/tooltip/useTooltip.ts +9 -5
  418. package/src/transition/CSSTransition.tsx +2 -1
  419. package/src/transition/Collapse.tsx +4 -2
  420. package/src/transition/CrossFade.tsx +2 -1
  421. package/src/transition/ScaleTransition.tsx +2 -1
  422. package/src/transition/SkeletonPlaceholder.tsx +1 -2
  423. package/src/transition/Slide.tsx +2 -1
  424. package/src/transition/SlideContainer.tsx +1 -2
  425. package/src/transition/types.ts +15 -16
  426. package/src/transition/useCollapseTransition.ts +6 -5
  427. package/src/transition/useCrossFadeTransition.ts +3 -2
  428. package/src/transition/useMaxWidthTransition.ts +1 -2
  429. package/src/transition/useScaleTransition.ts +3 -2
  430. package/src/transition/useSkeletonPlaceholder.ts +1 -2
  431. package/src/tree/Tree.tsx +2 -1
  432. package/src/tree/TreeItem.tsx +2 -1
  433. package/src/tree/TreeProvider.tsx +4 -4
  434. package/src/tree/styles.ts +1 -2
  435. package/src/tree/types.ts +1 -2
  436. package/src/tree/useTreeMovement.ts +1 -2
  437. package/src/typography/HighlightTextMark.tsx +1 -2
  438. package/src/typography/Mark.tsx +1 -2
  439. package/src/typography/TextContainer.tsx +1 -2
  440. package/src/typography/Typography.tsx +1 -2
  441. package/src/useElementSize.ts +7 -4
  442. package/src/useIntersectionObserver.ts +3 -2
  443. package/src/useMutationObserver.ts +3 -2
  444. package/src/useWindowSize.ts +4 -2
  445. package/src/utils/getNumberOfDigits.ts +18 -0
  446. package/src/utils/nearest.ts +2 -1
  447. package/src/utils/useDevEffect.ts +9 -0
  448. package/src/window-splitter/WindowSplitter.tsx +5 -2
  449. package/src/window-splitter/styles.ts +13 -2
  450. package/src/window-splitter/useWindowSplitter.ts +3 -1
@@ -14,15 +14,27 @@ declare module "react" {
14
14
  "--rmd-text-field-addon-spacing"?: string | number;
15
15
  "--rmd-text-field-addon-margin-top"?: string | number;
16
16
  "--rmd-text-field-addon-left-offset"?: string | number;
17
+ /** @since 6.4.0 */
18
+ "--rmd-text-field-base-height"?: string | number;
17
19
  "--rmd-text-field-height"?: string | number;
20
+ /** @since 6.4.0 */
21
+ "--rmd-text-field-dense-height"?: string | number;
22
+ /** @since 6.4.0 */
23
+ "--rmd-text-field-label-height"?: string | number;
24
+ /** @since 6.4.0 */
25
+ "--rmd-text-field-dense-label-height"?: string | number;
18
26
  "--rmd-text-field-padding-left"?: string | number;
19
27
  "--rmd-text-field-padding-right"?: string | number;
20
28
  "--rmd-text-field-padding-top"?: string | number;
21
29
  "--rmd-text-field-border-color"?: string;
30
+ /** @since 6.4.0 */
31
+ "--rmd-text-field-border-radius"?: string | number;
22
32
  "--rmd-text-field-hover-border-color"?: string;
23
33
  "--rmd-text-field-filled-color"?: string;
24
34
  "--rmd-text-field-filled-padding"?: string | number;
25
35
  "--rmd-text-field-outlined-padding"?: string | number;
36
+ /** @since 6.4.0 */
37
+ "--rmd-text-field-outlined-border-radius"?: string | number;
26
38
  "--rmd-text-field-underlined-padding"?: string | number;
27
39
  }
28
40
  }
@@ -79,18 +91,28 @@ export interface FormConfiguration extends Required<FormThemeOptions> {
79
91
  uncontrolledToggles: boolean;
80
92
  }
81
93
  /**
82
- * @since 6.0.0
94
+ * @since 6.4.0
83
95
  */
84
- export interface FormComponentStates {
85
- /** @defaultValue `false` */
86
- error?: boolean;
87
- /** @defaultValue `false` */
88
- active?: boolean;
96
+ export interface InteractableFormComponentStates {
89
97
  /** @defaultValue `false` */
90
98
  disabled?: boolean;
91
99
  /** @defaultValue `false` */
92
100
  readOnly?: boolean;
93
101
  }
102
+ /**
103
+ * @since 6.4.0
104
+ */
105
+ export interface EditableFormComponentStates extends InteractableFormComponentStates {
106
+ /** @defaultValue `false` */
107
+ error?: boolean;
108
+ }
109
+ /**
110
+ * @since 6.0.0
111
+ */
112
+ export interface FormComponentStates extends EditableFormComponentStates {
113
+ /** @defaultValue `false` */
114
+ active?: boolean;
115
+ }
94
116
  /**
95
117
  * @since 6.0.0
96
118
  * @see https://html.spec.whatwg.org/multipage/forms.html#autofill
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/types.ts"],"sourcesContent":["import {\n type CSSProperties,\n type HTMLAttributes,\n type InputHTMLAttributes,\n type LabelHTMLAttributes,\n type ReactNode,\n} from \"react\";\n\nimport { type PropsWithRef } from \"../types.js\";\n\ndeclare module \"react\" {\n interface CSSProperties {\n \"--rmd-form-active-color\"?: string;\n \"--rmd-form-focus-color\"?: string;\n\n // NOTE: The label properties are in this file since all label types are\n // in this file. If they are able to be moved to labelStyles or Label and\n // the compiled `.d.ts` includes the types from those files, this can be\n // moved.\n \"--rmd-label-floating-x\"?: string | number;\n \"--rmd-label-floating-y\"?: string | number;\n \"--rmd-label-floating-active-x\"?: string | number;\n \"--rmd-label-floating-active-y\"?: string | number;\n \"--rmd-label-active-padding\"?: string | number;\n \"--rmd-label-active-background-color\"?: string;\n\n // NOTE: The text field properties are in this file since there are no\n // typedefs included from `TextFieldContainer` or\n // `textFieldContainerStyles`.\n \"--rmd-text-field-addon-top\"?: string | number;\n \"--rmd-text-field-addon-spacing\"?: string | number;\n \"--rmd-text-field-addon-margin-top\"?: string | number;\n \"--rmd-text-field-addon-left-offset\"?: string | number;\n \"--rmd-text-field-height\"?: string | number;\n \"--rmd-text-field-padding-left\"?: string | number;\n \"--rmd-text-field-padding-right\"?: string | number;\n \"--rmd-text-field-padding-top\"?: string | number;\n \"--rmd-text-field-border-color\"?: string;\n \"--rmd-text-field-hover-border-color\"?: string;\n \"--rmd-text-field-filled-color\"?: string;\n \"--rmd-text-field-filled-padding\"?: string | number;\n \"--rmd-text-field-outlined-padding\"?: string | number;\n \"--rmd-text-field-underlined-padding\"?: string | number;\n }\n}\n\n/**\n * The supported themes for the `TextField`, `TextArea`, and `Select`\n * components.\n *\n * - \"none\" - display as an unstyled text field without any border or background\n * colors.\n * - \"underline\" - display with only an underline that gains the form active\n * color and animates from the left or right to the other side when the field\n * is focused.\n * - \"filled\" - an extension of the `\"underline\"` state that will also have a\n * slightly dark background applied.\n * - \"outline\" - outlines the entire text field in a border and applies the\n * active color as box shadow when the field is focused.\n */\nexport type FormTheme = \"none\" | \"underline\" | \"filled\" | \"outline\";\n\n/**\n * The direction that the underline should appear from when the theme is\n * `\"underline\"` or `\"filled\"`.\n */\nexport type FormUnderlineDirection = \"left\" | \"center\" | \"right\";\n\nexport interface FormThemeOptions {\n /**\n * The current theme type.\n *\n * @defaultValue `\"outline\"`\n */\n theme?: FormTheme;\n\n /**\n * The current underline direction.\n *\n * @defaultValue `\"left\"`\n */\n underlineDirection?: FormUnderlineDirection;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface FormConfiguration extends Required<FormThemeOptions> {\n /**\n * Set this to `false` if the `$disable-uncontrolled-input-toggles` variable\n * is set to `true` in the Sass configuration.\n *\n * Since the `checked` state only changes for the radio that has been clicked,\n * the previously checked radio would also be shown as checked with no way of\n * fixing it without controlling the radio component. When this flag is\n * enabled, the checked icons and state are handled through css instead of\n * `useState`.\n *\n * @defaultValue `true`\n */\n uncontrolledToggles: boolean;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface FormComponentStates {\n /** @defaultValue `false` */\n error?: boolean;\n\n /** @defaultValue `false` */\n active?: boolean;\n\n /** @defaultValue `false` */\n disabled?: boolean;\n\n /** @defaultValue `false` */\n readOnly?: boolean;\n}\n\n/**\n * @since 6.0.0\n * @see https://html.spec.whatwg.org/multipage/forms.html#autofill\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#values\n */\nexport type AutocompleteAttributeValue =\n | \"off\"\n | \"on\"\n | \"name\"\n | \"honorific-prefix\"\n | \"given-name\"\n | \"additional-name\"\n | \"family-name\"\n | \"honorific-suffix\"\n | \"nickname\"\n | \"email\"\n | \"username\"\n | \"new-password\"\n | \"current-password\"\n | \"one-time-code\"\n | \"organization-title\"\n | \"organization\"\n | \"street-address\"\n | \"address-line1\"\n | \"address-line2\"\n | \"address-line3\"\n | \"address-level1\"\n | \"address-level2\"\n | \"address-level3\"\n | \"address-level4\"\n | \"country\"\n | \"country-name\"\n | \"postal-code\"\n | \"cc-name\"\n | \"cc-given-name\"\n | \"cc-additional-name\"\n | \"cc-family-name\"\n | \"cc-number\"\n | \"cc-exp\"\n | \"cc-exp-month\"\n | \"cc-exp-year\"\n | \"cc-csc\"\n | \"cc-type\"\n | \"transaction-currency\"\n | \"transaction-amount\"\n | \"language\"\n | \"bday\"\n | \"bday-day\"\n | \"bday-month\"\n | \"bday-year\"\n | \"sex\"\n | \"tel\"\n | \"tel-country-code\"\n | \"tel-national\"\n | \"tek-area-code\"\n | \"tel-local\"\n | \"tel-extension\"\n | \"impp\"\n | \"url\"\n | \"photo\";\n\n/**\n * @since 6.0.0\n */\nexport interface UserAgentAutocompleteProps {\n /**\n * Set this to enable additional autocompletion suggestions for a user for\n * different form fields. Using this prop will update the\n * {@link UserAgentAutocompleteProps.name} and {@link autoComplete} to default to\n * this value.\n *\n * @example\n * ```tsx\n * <Form>\n * <TextField\n * label=\"Enter your credit card number\"\n * autoCompleteValue=\"cc-number\"\n * {...creditCardProps}\n * inputMode=\"number\"\n * />\n * <TextField\n * label=\"Name on card\"\n * autoCompleteValue=\"cc-name\"\n * {...creditCardNameProps}\n * />\n * <TextField\n * label=\"Security code\"\n * autoCompleteValue=\"cc-csc\"\n * {...securityCodeProps}\n * inputMode=\"number\"\n * />\n * <Button type=\"submit\">Submit</Button>\n * </Form>\n * ```\n *\n * @see https://html.spec.whatwg.org/multipage/forms.html#autofill\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#values\n * @see {@link AutocompleteAttributeValue}\n * @see {@link autoComplete}\n * @see {@link UserAgentAutocompleteProps.name}\n */\n autoCompleteValue?: AutocompleteAttributeValue;\n\n /**\n * @see {@link autoCompleteValue}\n * @defaultValue `autoCompleteValue`\n */\n autoComplete?: InputHTMLAttributes<HTMLInputElement>[\"autoComplete\"];\n\n /**\n * @see {@link autoCompleteValue}\n * @defaultValue `autoCompleteValue`\n */\n name?: string;\n}\n\nexport interface FormMessageClassNameOptions {\n className?: string;\n\n /**\n * Boolean if the message should gain the error state which changes the text\n * color to `red` by default.\n *\n * @defaultValue `false`\n */\n error?: boolean;\n\n /**\n * The current theme for the related text field. This is really only used to\n * match the current horizontal padding of the text field.\n *\n * @defaultValue `\"outline\"`\n */\n theme?: FormTheme;\n}\n\nexport interface FormMessageProps\n extends Omit<HTMLAttributes<HTMLDivElement>, \"minLength\" | \"maxLength\">,\n FormMessageClassNameOptions {\n /**\n * If this component is acting as a form-level error message handler, the role\n * should be updated to be `\"alert\"` for additional accessibility.\n *\n * Note: when creating a form-level error message handler, the messages should\n * no longer appear as the user types and instead once the user tries to\n * submit the form. Having an alert role disrupts normal screen reader\n * behavior by immediately reading changes in this element.\n *\n * @defaultValue `undefined`\n */\n role?: \"alert\";\n\n /**\n * Boolean if the children should no longer be wrapped in a `<p>` tag. This\n * should normally only be disabled if using a custom error message wrapper or\n * the counter behavior is not being used. To get correct alignments of the\n * message and counter, the `children` must be wrapped in some element and\n * cannot be plain test.\n *\n * Note: this will always be considered `true` if the `role` is set to\n * `\"alert\"`.\n *\n * @defaultValue `false`\n */\n disableWrap?: boolean;\n\n /**\n * Optional props to provide to inline counter.\n *\n * @since 6.3.0\n */\n counterProps?: PropsWithRef<HTMLAttributes<HTMLSpanElement>>;\n\n /**\n * Optional props to apply to the `<p>` tag that surrounds the `children`.\n * This will not be used if `role=\"alert\"` or `disableWrap={true}`.\n *\n * @since 6.3.0\n */\n messageProps?: PropsWithRef<HTMLAttributes<HTMLParagraphElement>>;\n\n /**\n * An optional style to apply to the `<p>` tag that surrounds the `children`.\n * This will not be used if `role=\"alert\"` or `disableWrap={true}`.\n */\n messageStyle?: CSSProperties;\n\n /**\n * An optional className to apply to the `<p>` tag that surrounds the\n * `children`. This will not be used if `role=\"alert\"` or\n * `disableWrap={true}`.\n */\n messageClassName?: string;\n}\n\n/**\n * Props that are used to automatically add a counter for the remaining letters\n * available for the text field. The counter will always be created to the right\n * of the optional message.\n *\n * The counter is really a simple string of: `${length} / ${maxLength}`.\n *\n * If you need additional customization, it is recommended to create your own\n * implementation such as:\n *\n * ```tsx\n * <FormMessage>\n * {errorMessage}\n * <MyCounter {...props} />\n * </FormMessage>\n * ```\n *\n * Note: this should not be used alongside form-level messages.\n *\n * @since 2.9.0 Renamed from `FormMessageCounterProps` to\n * `FormMessageInputLengthCounterProps` since a `FormMessageCounter` component\n * was added\n */\nexport interface FormMessageInputLengthCounterProps {\n /**\n * The current length of the value in the related text field.\n */\n length: number;\n\n /**\n * The max length allowed for the value in the related text field.\n */\n maxLength: number;\n\n /**\n * An optional style to apply to the counter wrapper element.\n */\n counterStyle?: CSSProperties;\n\n /**\n * An optional className to apply to the counter wrapper element.\n */\n counterClassName?: string;\n}\n\nexport interface FormMessageWithCounterProps\n extends FormMessageProps,\n FormMessageInputLengthCounterProps {}\n\n/**\n * @since 6.0.0\n */\nexport interface FormMessageWithoutCounterProps extends FormMessageProps {\n length?: never;\n maxLength?: never;\n counterStyle?: never;\n counterClassName?: never;\n}\n\nexport interface FormMessageContainerExtension {\n /**\n * If the extension doesn't actually want to render the `FormMessage`\n * component, these props are optional. It kind of eliminates the whole\n * purpose of this component though.\n */\n messageProps?: PropsWithRef<\n FormMessageProps & Partial<FormMessageInputLengthCounterProps>\n >;\n\n /**\n * Any props (and an optional ref) to provide to the `<div>` surrounding the\n * children and `FormMessage` component.\n *\n * Note: This will not be used if the `messageProps` are not provided since\n * only the `children` will be returned without the container.\n */\n messageContainerProps?: PropsWithRef<HTMLAttributes<HTMLDivElement>>;\n}\n\n/** @since 6.0.0 */\nexport interface LabelClassNameOptions {\n className?: string;\n\n /**\n * Set this to `true` to remove the `gap` style from the label.\n *\n * @see `$label-gap`\n * @defaultValue `false`\n */\n gap?: boolean;\n\n /**\n * Set this to `true` when the parent `TextFieldContainer` has the `dense`\n * spec enabled. This updates the floating styles to match the smaller height.\n *\n * @defaultValue `false`\n */\n dense?: boolean;\n\n /**\n * Set this to `true` to update the label's color to the error color.\n *\n * @see `$error-color`\n * @defaultValue `false`\n */\n error?: boolean;\n\n /**\n * Set this to `true` to update the label's color to the active color.\n *\n * @see `$active-color`\n * @defaultValue `false`\n */\n active?: boolean;\n\n /**\n * Set this to `true` if the label should gain `flex-direction: column`\n * styling.\n *\n * @defaultValue `false`\n */\n stacked?: boolean;\n\n /**\n * Set this to `true` to update the label's color to be the disabled color.\n *\n * @see `$disabled-color`\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * Set this to true when label can floating above an input, textarea, or\n * select inside of a `TextFieldContainer`.\n *\n * @defaultValue `false`\n */\n floating?: boolean;\n\n /**\n * Set this to true when label is currently floating above an input,\n * textarea, or selected inside of a `TextFieldContainer`.\n *\n * @see {@link active}\n * @defaultValue `active`\n */\n floatingActive?: boolean;\n\n /**\n * Set this to `true` to gain `flex-direction: row-reversed` styling. If the\n * {@link stacked} prop is also `true`, `flex-direction: column-reversed` will\n * be applied.\n *\n * @defaultValue `false`\n */\n reversed?: boolean;\n\n /**\n * @defaultValue `false`\n */\n inactive?: boolean;\n}\n\nexport interface LabelProps\n extends LabelHTMLAttributes<HTMLLabelElement>,\n LabelClassNameOptions {}\n\n/**\n * @since 6.0.0\n */\nexport interface ConfigurableTextFieldAddonProps\n extends HTMLAttributes<HTMLSpanElement> {\n /**\n * Boolean if the addon should be presentational only and prevent pointer\n * events.\n *\n * @defaultValue `false`\n */\n pointerEvents?: boolean;\n}\n\n/**\n * @since 6.0.0 Split props into `ConfigurableTextFieldAddonProps`\n */\nexport interface TextFieldAddonProps extends ConfigurableTextFieldAddonProps {\n /**\n * @defaultValue `false`\n */\n after?: boolean;\n\n /**\n * Set this to `true` if the addon should not be wrapped in a `<span>` with some\n * additional styles.\n *\n * @defaultValue `false`\n */\n disabled?: boolean;\n}\n\n/**\n * @since 6.0.0 Renamed the `leftChildren` / `rightChildren` props to\n * `leftAddon` / `rightAddon`. Renamed `isLeftAddon` / `isRightAddon` to\n * `disableLeftAddonStyles` / `disableRightAddonStyles`. Added\n * `leftAddonProps` / `rightAddonProps`. Removed `stretch`\n */\nexport interface TextFieldContainerOptions\n extends FormThemeOptions,\n FormComponentStates {\n /**\n * Set this to `true` to enable the dense spec which reduces the height.\n *\n * @defaultValue `false`\n */\n dense?: boolean;\n\n /**\n * Set this to `true` to change the style from `display: flex` to\n * `display: inline-flex`.\n *\n * @defaultValue `false`\n */\n inline?: boolean;\n\n /**\n * This should generally be an icon or a button that will be placed before the\n * `TextField` or `TextArea`.\n */\n leftAddon?: ReactNode;\n\n /**\n * Any additional props to pass to the `<span>` surrounding the {@link leftAddon}.\n *\n * @since 6.0.0\n */\n leftAddonProps?: PropsWithRef<ConfigurableTextFieldAddonProps>;\n\n /**\n * @see {@link TextFieldAddonProps.disabled}\n *\n * @defaultValue `false`\n */\n disableLeftAddonStyles?: boolean;\n\n /**\n * This should generally be an icon or a button that will be placed after the\n * `TextField` or `TextArea`.\n */\n rightAddon?: ReactNode;\n\n /**\n * Any additional props to pass to the `<span>` surrounding the {@link rightAddon}.\n *\n * @since 6.0.0\n */\n rightAddonProps?: PropsWithRef<ConfigurableTextFieldAddonProps>;\n\n /**\n * @see {@link TextFieldAddonProps.disabled}\n *\n * @defaultValue `false`\n */\n disableRightAddonStyles?: boolean;\n}\n\nexport interface FormFieldOptions\n extends TextFieldContainerOptions,\n FormMessageContainerExtension {\n /**\n * An optional floating label to use with the text field. A label is generally\n * recommended for accessibility, but can be omitted if an `aria-label` or\n * `aria-labelledby` is provided.\n */\n label?: ReactNode;\n\n /**\n * Any additional props and/or ref that should be passed to the `<label>`\n * element when a {@link label} is provided.\n *\n * @example\n * ```tsx\n * labelProps={{\n * ref: labelRef,\n * style: {},\n * className: \"some-custom-class-name\",\n * onClick: (event) => {\n * // do something\n * }\n * }}\n * ```\n */\n labelProps?: PropsWithRef<LabelProps>;\n\n /**\n * A convenience prop to apply a custom style to a label. This is equivalent\n * to:\n *\n * ```ts\n * labelProps={{\n * style: // some style here\n * }}\n * ```\n */\n labelStyle?: CSSProperties;\n\n /**\n * A convenience prop to apply a custom className to a label. This is\n * equivalent to:\n *\n * ```ts\n * labelProps={{\n * className: \"some-class-name\",\n * }}\n * ```\n */\n labelClassName?: string;\n}\n"],"names":[],"mappings":"AAmkBA,WAmDC"}
1
+ {"version":3,"sources":["../../src/form/types.ts"],"sourcesContent":["import {\n type CSSProperties,\n type HTMLAttributes,\n type InputHTMLAttributes,\n type LabelHTMLAttributes,\n type ReactNode,\n} from \"react\";\n\nimport { type PropsWithRef } from \"../types.js\";\n\ndeclare module \"react\" {\n interface CSSProperties {\n \"--rmd-form-active-color\"?: string;\n \"--rmd-form-focus-color\"?: string;\n\n // NOTE: The label properties are in this file since all label types are\n // in this file. If they are able to be moved to labelStyles or Label and\n // the compiled `.d.ts` includes the types from those files, this can be\n // moved.\n \"--rmd-label-floating-x\"?: string | number;\n \"--rmd-label-floating-y\"?: string | number;\n \"--rmd-label-floating-active-x\"?: string | number;\n \"--rmd-label-floating-active-y\"?: string | number;\n \"--rmd-label-active-padding\"?: string | number;\n \"--rmd-label-active-background-color\"?: string;\n\n // NOTE: The text field properties are in this file since there are no\n // typedefs included from `TextFieldContainer` or\n // `textFieldContainerStyles`.\n \"--rmd-text-field-addon-top\"?: string | number;\n \"--rmd-text-field-addon-spacing\"?: string | number;\n \"--rmd-text-field-addon-margin-top\"?: string | number;\n \"--rmd-text-field-addon-left-offset\"?: string | number;\n /** @since 6.4.0 */\n \"--rmd-text-field-base-height\"?: string | number;\n \"--rmd-text-field-height\"?: string | number;\n /** @since 6.4.0 */\n \"--rmd-text-field-dense-height\"?: string | number;\n /** @since 6.4.0 */\n \"--rmd-text-field-label-height\"?: string | number;\n /** @since 6.4.0 */\n \"--rmd-text-field-dense-label-height\"?: string | number;\n \"--rmd-text-field-padding-left\"?: string | number;\n \"--rmd-text-field-padding-right\"?: string | number;\n \"--rmd-text-field-padding-top\"?: string | number;\n \"--rmd-text-field-border-color\"?: string;\n /** @since 6.4.0 */\n \"--rmd-text-field-border-radius\"?: string | number;\n \"--rmd-text-field-hover-border-color\"?: string;\n \"--rmd-text-field-filled-color\"?: string;\n \"--rmd-text-field-filled-padding\"?: string | number;\n \"--rmd-text-field-outlined-padding\"?: string | number;\n /** @since 6.4.0 */\n \"--rmd-text-field-outlined-border-radius\"?: string | number;\n \"--rmd-text-field-underlined-padding\"?: string | number;\n }\n}\n\n/**\n * The supported themes for the `TextField`, `TextArea`, and `Select`\n * components.\n *\n * - \"none\" - display as an unstyled text field without any border or background\n * colors.\n * - \"underline\" - display with only an underline that gains the form active\n * color and animates from the left or right to the other side when the field\n * is focused.\n * - \"filled\" - an extension of the `\"underline\"` state that will also have a\n * slightly dark background applied.\n * - \"outline\" - outlines the entire text field in a border and applies the\n * active color as box shadow when the field is focused.\n */\nexport type FormTheme = \"none\" | \"underline\" | \"filled\" | \"outline\";\n\n/**\n * The direction that the underline should appear from when the theme is\n * `\"underline\"` or `\"filled\"`.\n */\nexport type FormUnderlineDirection = \"left\" | \"center\" | \"right\";\n\nexport interface FormThemeOptions {\n /**\n * The current theme type.\n *\n * @defaultValue `\"outline\"`\n */\n theme?: FormTheme;\n\n /**\n * The current underline direction.\n *\n * @defaultValue `\"left\"`\n */\n underlineDirection?: FormUnderlineDirection;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface FormConfiguration extends Required<FormThemeOptions> {\n /**\n * Set this to `false` if the `$disable-uncontrolled-input-toggles` variable\n * is set to `true` in the Sass configuration.\n *\n * Since the `checked` state only changes for the radio that has been clicked,\n * the previously checked radio would also be shown as checked with no way of\n * fixing it without controlling the radio component. When this flag is\n * enabled, the checked icons and state are handled through css instead of\n * `useState`.\n *\n * @defaultValue `true`\n */\n uncontrolledToggles: boolean;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface InteractableFormComponentStates {\n /** @defaultValue `false` */\n disabled?: boolean;\n\n /** @defaultValue `false` */\n readOnly?: boolean;\n}\n\n/**\n * @since 6.4.0\n */\nexport interface EditableFormComponentStates extends InteractableFormComponentStates {\n /** @defaultValue `false` */\n error?: boolean;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface FormComponentStates extends EditableFormComponentStates {\n /** @defaultValue `false` */\n active?: boolean;\n}\n\n/**\n * @since 6.0.0\n * @see https://html.spec.whatwg.org/multipage/forms.html#autofill\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#values\n */\nexport type AutocompleteAttributeValue =\n | \"off\"\n | \"on\"\n | \"name\"\n | \"honorific-prefix\"\n | \"given-name\"\n | \"additional-name\"\n | \"family-name\"\n | \"honorific-suffix\"\n | \"nickname\"\n | \"email\"\n | \"username\"\n | \"new-password\"\n | \"current-password\"\n | \"one-time-code\"\n | \"organization-title\"\n | \"organization\"\n | \"street-address\"\n | \"address-line1\"\n | \"address-line2\"\n | \"address-line3\"\n | \"address-level1\"\n | \"address-level2\"\n | \"address-level3\"\n | \"address-level4\"\n | \"country\"\n | \"country-name\"\n | \"postal-code\"\n | \"cc-name\"\n | \"cc-given-name\"\n | \"cc-additional-name\"\n | \"cc-family-name\"\n | \"cc-number\"\n | \"cc-exp\"\n | \"cc-exp-month\"\n | \"cc-exp-year\"\n | \"cc-csc\"\n | \"cc-type\"\n | \"transaction-currency\"\n | \"transaction-amount\"\n | \"language\"\n | \"bday\"\n | \"bday-day\"\n | \"bday-month\"\n | \"bday-year\"\n | \"sex\"\n | \"tel\"\n | \"tel-country-code\"\n | \"tel-national\"\n | \"tek-area-code\"\n | \"tel-local\"\n | \"tel-extension\"\n | \"impp\"\n | \"url\"\n | \"photo\";\n\n/**\n * @since 6.0.0\n */\nexport interface UserAgentAutocompleteProps {\n /**\n * Set this to enable additional autocompletion suggestions for a user for\n * different form fields. Using this prop will update the\n * {@link UserAgentAutocompleteProps.name} and {@link autoComplete} to default to\n * this value.\n *\n * @example\n * ```tsx\n * <Form>\n * <TextField\n * label=\"Enter your credit card number\"\n * autoCompleteValue=\"cc-number\"\n * {...creditCardProps}\n * inputMode=\"number\"\n * />\n * <TextField\n * label=\"Name on card\"\n * autoCompleteValue=\"cc-name\"\n * {...creditCardNameProps}\n * />\n * <TextField\n * label=\"Security code\"\n * autoCompleteValue=\"cc-csc\"\n * {...securityCodeProps}\n * inputMode=\"number\"\n * />\n * <Button type=\"submit\">Submit</Button>\n * </Form>\n * ```\n *\n * @see https://html.spec.whatwg.org/multipage/forms.html#autofill\n * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete#values\n * @see {@link AutocompleteAttributeValue}\n * @see {@link autoComplete}\n * @see {@link UserAgentAutocompleteProps.name}\n */\n autoCompleteValue?: AutocompleteAttributeValue;\n\n /**\n * @see {@link autoCompleteValue}\n * @defaultValue `autoCompleteValue`\n */\n autoComplete?: InputHTMLAttributes<HTMLInputElement>[\"autoComplete\"];\n\n /**\n * @see {@link autoCompleteValue}\n * @defaultValue `autoCompleteValue`\n */\n name?: string;\n}\n\nexport interface FormMessageClassNameOptions {\n className?: string;\n\n /**\n * Boolean if the message should gain the error state which changes the text\n * color to `red` by default.\n *\n * @defaultValue `false`\n */\n error?: boolean;\n\n /**\n * The current theme for the related text field. This is really only used to\n * match the current horizontal padding of the text field.\n *\n * @defaultValue `\"outline\"`\n */\n theme?: FormTheme;\n}\n\nexport interface FormMessageProps\n extends\n Omit<HTMLAttributes<HTMLDivElement>, \"minLength\" | \"maxLength\">,\n FormMessageClassNameOptions {\n /**\n * If this component is acting as a form-level error message handler, the role\n * should be updated to be `\"alert\"` for additional accessibility.\n *\n * Note: when creating a form-level error message handler, the messages should\n * no longer appear as the user types and instead once the user tries to\n * submit the form. Having an alert role disrupts normal screen reader\n * behavior by immediately reading changes in this element.\n *\n * @defaultValue `undefined`\n */\n role?: \"alert\";\n\n /**\n * Boolean if the children should no longer be wrapped in a `<p>` tag. This\n * should normally only be disabled if using a custom error message wrapper or\n * the counter behavior is not being used. To get correct alignments of the\n * message and counter, the `children` must be wrapped in some element and\n * cannot be plain test.\n *\n * Note: this will always be considered `true` if the `role` is set to\n * `\"alert\"`.\n *\n * @defaultValue `false`\n */\n disableWrap?: boolean;\n\n /**\n * Optional props to provide to inline counter.\n *\n * @since 6.3.0\n */\n counterProps?: PropsWithRef<HTMLAttributes<HTMLSpanElement>>;\n\n /**\n * Optional props to apply to the `<p>` tag that surrounds the `children`.\n * This will not be used if `role=\"alert\"` or `disableWrap={true}`.\n *\n * @since 6.3.0\n */\n messageProps?: PropsWithRef<HTMLAttributes<HTMLParagraphElement>>;\n\n /**\n * An optional style to apply to the `<p>` tag that surrounds the `children`.\n * This will not be used if `role=\"alert\"` or `disableWrap={true}`.\n */\n messageStyle?: CSSProperties;\n\n /**\n * An optional className to apply to the `<p>` tag that surrounds the\n * `children`. This will not be used if `role=\"alert\"` or\n * `disableWrap={true}`.\n */\n messageClassName?: string;\n}\n\n/**\n * Props that are used to automatically add a counter for the remaining letters\n * available for the text field. The counter will always be created to the right\n * of the optional message.\n *\n * The counter is really a simple string of: `${length} / ${maxLength}`.\n *\n * If you need additional customization, it is recommended to create your own\n * implementation such as:\n *\n * ```tsx\n * <FormMessage>\n * {errorMessage}\n * <MyCounter {...props} />\n * </FormMessage>\n * ```\n *\n * Note: this should not be used alongside form-level messages.\n *\n * @since 2.9.0 Renamed from `FormMessageCounterProps` to\n * `FormMessageInputLengthCounterProps` since a `FormMessageCounter` component\n * was added\n */\nexport interface FormMessageInputLengthCounterProps {\n /**\n * The current length of the value in the related text field.\n */\n length: number;\n\n /**\n * The max length allowed for the value in the related text field.\n */\n maxLength: number;\n\n /**\n * An optional style to apply to the counter wrapper element.\n */\n counterStyle?: CSSProperties;\n\n /**\n * An optional className to apply to the counter wrapper element.\n */\n counterClassName?: string;\n}\n\nexport interface FormMessageWithCounterProps\n extends FormMessageProps, FormMessageInputLengthCounterProps {}\n\n/**\n * @since 6.0.0\n */\nexport interface FormMessageWithoutCounterProps extends FormMessageProps {\n length?: never;\n maxLength?: never;\n counterStyle?: never;\n counterClassName?: never;\n}\n\nexport interface FormMessageContainerExtension {\n /**\n * If the extension doesn't actually want to render the `FormMessage`\n * component, these props are optional. It kind of eliminates the whole\n * purpose of this component though.\n */\n messageProps?: PropsWithRef<\n FormMessageProps & Partial<FormMessageInputLengthCounterProps>\n >;\n\n /**\n * Any props (and an optional ref) to provide to the `<div>` surrounding the\n * children and `FormMessage` component.\n *\n * Note: This will not be used if the `messageProps` are not provided since\n * only the `children` will be returned without the container.\n */\n messageContainerProps?: PropsWithRef<HTMLAttributes<HTMLDivElement>>;\n}\n\n/** @since 6.0.0 */\nexport interface LabelClassNameOptions {\n className?: string;\n\n /**\n * Set this to `true` to remove the `gap` style from the label.\n *\n * @see `$label-gap`\n * @defaultValue `false`\n */\n gap?: boolean;\n\n /**\n * Set this to `true` when the parent `TextFieldContainer` has the `dense`\n * spec enabled. This updates the floating styles to match the smaller height.\n *\n * @defaultValue `false`\n */\n dense?: boolean;\n\n /**\n * Set this to `true` to update the label's color to the error color.\n *\n * @see `$error-color`\n * @defaultValue `false`\n */\n error?: boolean;\n\n /**\n * Set this to `true` to update the label's color to the active color.\n *\n * @see `$active-color`\n * @defaultValue `false`\n */\n active?: boolean;\n\n /**\n * Set this to `true` if the label should gain `flex-direction: column`\n * styling.\n *\n * @defaultValue `false`\n */\n stacked?: boolean;\n\n /**\n * Set this to `true` to update the label's color to be the disabled color.\n *\n * @see `$disabled-color`\n * @defaultValue `false`\n */\n disabled?: boolean;\n\n /**\n * Set this to true when label can floating above an input, textarea, or\n * select inside of a `TextFieldContainer`.\n *\n * @defaultValue `false`\n */\n floating?: boolean;\n\n /**\n * Set this to true when label is currently floating above an input,\n * textarea, or selected inside of a `TextFieldContainer`.\n *\n * @see {@link active}\n * @defaultValue `active`\n */\n floatingActive?: boolean;\n\n /**\n * Set this to `true` to gain `flex-direction: row-reversed` styling. If the\n * {@link stacked} prop is also `true`, `flex-direction: column-reversed` will\n * be applied.\n *\n * @defaultValue `false`\n */\n reversed?: boolean;\n\n /**\n * @defaultValue `false`\n */\n inactive?: boolean;\n}\n\nexport interface LabelProps\n extends LabelHTMLAttributes<HTMLLabelElement>, LabelClassNameOptions {}\n\n/**\n * @since 6.0.0\n */\nexport interface ConfigurableTextFieldAddonProps extends HTMLAttributes<HTMLSpanElement> {\n /**\n * Boolean if the addon should be presentational only and prevent pointer\n * events.\n *\n * @defaultValue `false`\n */\n pointerEvents?: boolean;\n}\n\n/**\n * @since 6.0.0 Split props into `ConfigurableTextFieldAddonProps`\n */\nexport interface TextFieldAddonProps extends ConfigurableTextFieldAddonProps {\n /**\n * @defaultValue `false`\n */\n after?: boolean;\n\n /**\n * Set this to `true` if the addon should not be wrapped in a `<span>` with some\n * additional styles.\n *\n * @defaultValue `false`\n */\n disabled?: boolean;\n}\n\n/**\n * @since 6.0.0 Renamed the `leftChildren` / `rightChildren` props to\n * `leftAddon` / `rightAddon`. Renamed `isLeftAddon` / `isRightAddon` to\n * `disableLeftAddonStyles` / `disableRightAddonStyles`. Added\n * `leftAddonProps` / `rightAddonProps`. Removed `stretch`\n */\nexport interface TextFieldContainerOptions\n extends FormThemeOptions, FormComponentStates {\n /**\n * Set this to `true` to enable the dense spec which reduces the height.\n *\n * @defaultValue `false`\n */\n dense?: boolean;\n\n /**\n * Set this to `true` to change the style from `display: flex` to\n * `display: inline-flex`.\n *\n * @defaultValue `false`\n */\n inline?: boolean;\n\n /**\n * This should generally be an icon or a button that will be placed before the\n * `TextField` or `TextArea`.\n */\n leftAddon?: ReactNode;\n\n /**\n * Any additional props to pass to the `<span>` surrounding the {@link leftAddon}.\n *\n * @since 6.0.0\n */\n leftAddonProps?: PropsWithRef<ConfigurableTextFieldAddonProps>;\n\n /**\n * @see {@link TextFieldAddonProps.disabled}\n *\n * @defaultValue `false`\n */\n disableLeftAddonStyles?: boolean;\n\n /**\n * This should generally be an icon or a button that will be placed after the\n * `TextField` or `TextArea`.\n */\n rightAddon?: ReactNode;\n\n /**\n * Any additional props to pass to the `<span>` surrounding the {@link rightAddon}.\n *\n * @since 6.0.0\n */\n rightAddonProps?: PropsWithRef<ConfigurableTextFieldAddonProps>;\n\n /**\n * @see {@link TextFieldAddonProps.disabled}\n *\n * @defaultValue `false`\n */\n disableRightAddonStyles?: boolean;\n}\n\nexport interface FormFieldOptions\n extends TextFieldContainerOptions, FormMessageContainerExtension {\n /**\n * An optional floating label to use with the text field. A label is generally\n * recommended for accessibility, but can be omitted if an `aria-label` or\n * `aria-labelledby` is provided.\n */\n label?: ReactNode;\n\n /**\n * Any additional props and/or ref that should be passed to the `<label>`\n * element when a {@link label} is provided.\n *\n * @example\n * ```tsx\n * labelProps={{\n * ref: labelRef,\n * style: {},\n * className: \"some-custom-class-name\",\n * onClick: (event) => {\n * // do something\n * }\n * }}\n * ```\n */\n labelProps?: PropsWithRef<LabelProps>;\n\n /**\n * A convenience prop to apply a custom style to a label. This is equivalent\n * to:\n *\n * ```ts\n * labelProps={{\n * style: // some style here\n * }}\n * ```\n */\n labelStyle?: CSSProperties;\n\n /**\n * A convenience prop to apply a custom className to a label. This is\n * equivalent to:\n *\n * ```ts\n * labelProps={{\n * className: \"some-class-name\",\n * }}\n * ```\n */\n labelClassName?: string;\n}\n"],"names":[],"mappings":"AAslBA,WAkDC"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/useCheckboxGroup.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useRef } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { useReadonlySet } from \"../useReadonlySet.js\";\n\nconst EMPTY_LIST = [] as const;\n\n/** @since 6.0.0 */\nexport interface CheckboxGroupOptions<V> {\n /**\n * A `name` to apply to all the checkboxes within the group. This is required\n * if the {@link menu} option is set to `true`.\n */\n name?: string;\n\n /**\n * Set this to `true` if using the `MenuItemCheckbox` component instead of the\n * `Checkbox` so the correct props can be provided.\n *\n * @defaultValue `false`\n */\n menu?: boolean;\n\n /**\n * This prop **must** be defined to enable the indeterminate checkbox feature\n * from the hook and should be a list of all the possible checkbox values in\n * the group. This will be used to select all values when the indeterminate\n * checkbox is checked and determine if all the checkboxes have manually be\n * selected.\n *\n * @example Indeterminate Behavior\n * ```tsx\n * const OPTIONS = [\n * { label: \"First\", value: \"a\" },\n * { label: \"Second\", value: \"b\" },\n * { label: \"Third\", value: \"c\" },\n * ] as const;\n * const VALUES = OPTIONS.map(({ value }) => value) as const;\n *\n * const {\n * getCheckboxProps,\n * getIndeterminateProps,\n * checkedValues,\n * } = useCheckboxGroup({ name: \"group\", values: VALUES });\n * ```\n */\n values?: readonly V[];\n\n /**\n * Set this to a list of checkbox values that should be checked by default.\n *\n * @defaultValue `[]`\n */\n defaultCheckedValues?: UseStateInitializer<readonly V[]>;\n}\n\n/** @since 6.0.0 */\nexport interface CheckboxGroupImplementation<V extends string> {\n reset: () => void;\n checkedValues: ReadonlySet<V>;\n setCheckedValues: UseStateSetter<ReadonlySet<V>>;\n getCheckboxProps: (value: V) => {\n name: string;\n value: V;\n checked: boolean;\n onChange: () => void;\n };\n}\n\n/** @since 6.0.0 */\nexport interface IndeterminateCheckboxGroupImplementation<V extends string>\n extends CheckboxGroupImplementation<V> {\n getIndeterminateProps: () => {\n \"aria-checked\": \"mixed\" | undefined;\n name: string;\n checked: boolean;\n indeterminate: boolean;\n onChange: () => void;\n };\n}\n\n/** @since 6.0.0 */\nexport interface MenuItemCheckboxGroupImplementation<V extends string> {\n reset: () => void;\n checkedValues: ReadonlySet<V>;\n setCheckedValues: UseStateSetter<ReadonlySet<V>>;\n getCheckboxProps: (value: V) => {\n checked: boolean;\n onCheckedChange: () => void;\n };\n}\n\n/** @since 6.0.0 */\nexport interface IndeterminateMenuItemCheckboxGroupImplementation<\n V extends string,\n> extends MenuItemCheckboxGroupImplementation<V> {\n getIndeterminateProps: () => {\n \"aria-checked\": \"mixed\" | undefined;\n checked: boolean;\n indeterminate: boolean;\n onCheckedChange: () => void;\n };\n}\n\n/** @since 6.0.0 */\nexport interface CombinedCheckboxGroupReturnValue<V extends string> {\n reset: () => void;\n checkedValues: ReadonlySet<V>;\n setCheckedValues: UseStateSetter<ReadonlySet<V>>;\n getCheckboxProps: (value: V) => {\n name?: string;\n value?: V;\n checked: boolean;\n onChange?: () => void;\n onCheckedChange?: () => void;\n };\n getIndeterminateProps?: () => {\n \"aria-checked\": \"mixed\" | undefined;\n name?: string;\n checked: boolean;\n indeterminate: boolean;\n onChange?: () => void;\n onCheckedChange?: () => void;\n };\n}\n\n/**\n * @example Checkbox Group\n * ```tsx\n * const { getCheckboxProps, checkedValues } = useCheckboxGroup({ name: \"example\" });\n *\n * return (\n * <>\n * <Checkbox {...getCheckboxProps(\"a\")}>\n * First\n * </Checkbox>\n * <Checkbox {...getCheckboxProps(\"b\")}>\n * Second\n * </Checkbox>\n * <Checkbox {...getCheckboxProps(\"c\")}>\n * Third\n * </Checkbox>\n * </>\n * );\n * ```\n *\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V> & {\n menu?: false;\n name: string;\n values?: never;\n }\n): CheckboxGroupImplementation<V>;\n/**\n * @example Indeterminate Checkbox Group\n * ```tsx\n * const OPTIONS = [\n * { label: \"First\", value: \"a\" },\n * { label: \"Second\", value: \"b\" },\n * { label: \"Third\", value: \"c\" },\n * ] as const:\n * const VALUES = OPTIONS.map(({ value }) => value) as const;\n *\n * const {\n * getCheckboxProps,\n * getIndeterminateProps,\n * checkedValues\n * } = useCheckboxGroup({\n * name: \"example\",\n * values: VALUES,\n * });\n *\n * return (\n * <>\n * <Checkbox {...getIndeterminateProps()} label=\"Select all\" />\n * {VALUES.map(({ label, value }) => (\n * <Checkbox key={value} label={label} {...getCheckboxProps(value)} />\n * ))}\n * </>\n * );\n * ```\n *\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V> & {\n menu?: false;\n name: string;\n values: readonly V[];\n }\n): IndeterminateCheckboxGroupImplementation<V>;\n/**\n * @example MenuItemCheckbox Group\n * ```tsx\n * const { getCheckboxProps, checkedValues } = useCheckboxGroup({ menu: true });\n *\n * return (\n * <>\n * <MenuItemCheckbox {...getCheckboxProps(\"a\")}>\n * First\n * </MenuItemCheckbox>\n * <MenuItemCheckbox {...getCheckboxProps(\"b\")}>\n * Second\n * </MenuItemCheckbox>\n * <MenuItemCheckbox {...getCheckboxProps(\"c\")}>\n * Third\n * </MenuItemCheckbox>\n * </>\n * );\n * ```\n *\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V> & {\n menu: true;\n name?: never;\n values?: never;\n }\n): MenuItemCheckboxGroupImplementation<V>;\n/**\n * @example Indeterminate MenuItemCheckbox Group\n * ```tsx\n * const OPTIONS = [\n * { label: \"First\", value: \"a\" },\n * { label: \"Second\", value: \"b\" },\n * { label: \"Third\", value: \"c\" },\n * ] as const:\n * const VALUES = OPTIONS.map(({ value }) => value) as const;\n *\n * const { getCheckboxProps, getIndeterminateProps, checkedValues } = useCheckboxGroup({\n * menu: true,\n * values: VALUES,\n * });\n *\n * return (\n * <>\n * <MenuItemCheckbox {...getIndeterminateProps()}>\n * All\n * <MenuItemCheckbox>\n * {OPTIONS.map(({ label, value }) => (\n * <MenuItemCheckbox key={value} {...getCheckboxProps(value)}>\n * {label}\n * </MenuItemCheckbox>\n * ))}\n * </>\n * );\n * ```\n *\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V> & {\n menu: true;\n name?: never;\n values: readonly V[];\n }\n): IndeterminateMenuItemCheckboxGroupImplementation<V>;\n/**\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n * @internal\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V>\n): CombinedCheckboxGroupReturnValue<V> {\n const {\n name,\n menu = false,\n values,\n defaultCheckedValues = EMPTY_LIST,\n } = options;\n const {\n value: checkedValues,\n setValue: setCheckedValues,\n toggleValue,\n } = useReadonlySet({\n defaultValue: defaultCheckedValues,\n });\n const initial = useRef(checkedValues);\n\n let getIndeterminateProps: CombinedCheckboxGroupReturnValue<V>[\"getIndeterminateProps\"];\n if (values) {\n getIndeterminateProps = () => {\n const checked = checkedValues.size > 0;\n const indeterminate = checked && checkedValues.size < values.length;\n\n return {\n \"aria-checked\": indeterminate ? \"mixed\" : undefined,\n name,\n checked,\n indeterminate,\n [menu ? \"onCheckedChange\" : \"onChange\"]() {\n setCheckedValues((checkedValues) => {\n if (checkedValues.size === 0 || indeterminate) {\n return new Set(values);\n }\n\n return new Set();\n });\n },\n };\n };\n }\n\n return {\n reset: useCallback(() => {\n setCheckedValues(initial.current);\n }, [setCheckedValues]),\n checkedValues,\n setCheckedValues,\n getIndeterminateProps,\n getCheckboxProps(value) {\n return {\n name,\n value: menu ? undefined : value,\n checked: checkedValues.has(value),\n [menu ? \"onCheckedChange\" : \"onChange\"]() {\n toggleValue(value);\n },\n };\n },\n };\n}\n"],"names":["useCallback","useRef","useReadonlySet","EMPTY_LIST","useCheckboxGroup","options","name","menu","values","defaultCheckedValues","value","checkedValues","setValue","setCheckedValues","toggleValue","defaultValue","initial","getIndeterminateProps","checked","size","indeterminate","length","undefined","Set","reset","current","getCheckboxProps","has"],"mappings":"AAAA;AAEA,SAASA,WAAW,EAAEC,MAAM,QAAQ,QAAQ;AAG5C,SAASC,cAAc,QAAQ,uBAAuB;AAEtD,MAAMC,aAAa,EAAE;AAuQrB;;;;;CAKC,GACD,OAAO,SAASC,iBACdC,OAAgC;IAEhC,MAAM,EACJC,IAAI,EACJC,OAAO,KAAK,EACZC,MAAM,EACNC,uBAAuBN,UAAU,EAClC,GAAGE;IACJ,MAAM,EACJK,OAAOC,aAAa,EACpBC,UAAUC,gBAAgB,EAC1BC,WAAW,EACZ,GAAGZ,eAAe;QACjBa,cAAcN;IAChB;IACA,MAAMO,UAAUf,OAAOU;IAEvB,IAAIM;IACJ,IAAIT,QAAQ;QACVS,wBAAwB;YACtB,MAAMC,UAAUP,cAAcQ,IAAI,GAAG;YACrC,MAAMC,gBAAgBF,WAAWP,cAAcQ,IAAI,GAAGX,OAAOa,MAAM;YAEnE,OAAO;gBACL,gBAAgBD,gBAAgB,UAAUE;gBAC1ChB;gBACAY;gBACAE;gBACA,CAACb,OAAO,oBAAoB,WAAW;oBACrCM,iBAAiB,CAACF;wBAChB,IAAIA,cAAcQ,IAAI,KAAK,KAAKC,eAAe;4BAC7C,OAAO,IAAIG,IAAIf;wBACjB;wBAEA,OAAO,IAAIe;oBACb;gBACF;YACF;QACF;IACF;IAEA,OAAO;QACLC,OAAOxB,YAAY;YACjBa,iBAAiBG,QAAQS,OAAO;QAClC,GAAG;YAACZ;SAAiB;QACrBF;QACAE;QACAI;QACAS,kBAAiBhB,KAAK;YACpB,OAAO;gBACLJ;gBACAI,OAAOH,OAAOe,YAAYZ;gBAC1BQ,SAASP,cAAcgB,GAAG,CAACjB;gBAC3B,CAACH,OAAO,oBAAoB,WAAW;oBACrCO,YAAYJ;gBACd;YACF;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/form/useCheckboxGroup.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useRef } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { useReadonlySet } from \"../useReadonlySet.js\";\n\nconst EMPTY_LIST = [] as const;\n\n/** @since 6.0.0 */\nexport interface CheckboxGroupOptions<V> {\n /**\n * A `name` to apply to all the checkboxes within the group. This is required\n * if the {@link menu} option is set to `true`.\n */\n name?: string;\n\n /**\n * Set this to `true` if using the `MenuItemCheckbox` component instead of the\n * `Checkbox` so the correct props can be provided.\n *\n * @defaultValue `false`\n */\n menu?: boolean;\n\n /**\n * This prop **must** be defined to enable the indeterminate checkbox feature\n * from the hook and should be a list of all the possible checkbox values in\n * the group. This will be used to select all values when the indeterminate\n * checkbox is checked and determine if all the checkboxes have manually be\n * selected.\n *\n * @example Indeterminate Behavior\n * ```tsx\n * const OPTIONS = [\n * { label: \"First\", value: \"a\" },\n * { label: \"Second\", value: \"b\" },\n * { label: \"Third\", value: \"c\" },\n * ] as const;\n * const VALUES = OPTIONS.map(({ value }) => value) as const;\n *\n * const {\n * getCheckboxProps,\n * getIndeterminateProps,\n * checkedValues,\n * } = useCheckboxGroup({ name: \"group\", values: VALUES });\n * ```\n */\n values?: readonly V[];\n\n /**\n * Set this to a list of checkbox values that should be checked by default.\n *\n * @defaultValue `[]`\n */\n defaultCheckedValues?: UseStateInitializer<readonly V[]>;\n}\n\n/** @since 6.0.0 */\nexport interface CheckboxGroupImplementation<V extends string> {\n reset: () => void;\n checkedValues: ReadonlySet<V>;\n setCheckedValues: UseStateSetter<ReadonlySet<V>>;\n getCheckboxProps: (value: V) => {\n name: string;\n value: V;\n checked: boolean;\n onChange: () => void;\n };\n}\n\n/** @since 6.0.0 */\nexport interface IndeterminateCheckboxGroupImplementation<\n V extends string,\n> extends CheckboxGroupImplementation<V> {\n getIndeterminateProps: () => {\n \"aria-checked\": \"mixed\" | undefined;\n name: string;\n checked: boolean;\n indeterminate: boolean;\n onChange: () => void;\n };\n}\n\n/** @since 6.0.0 */\nexport interface MenuItemCheckboxGroupImplementation<V extends string> {\n reset: () => void;\n checkedValues: ReadonlySet<V>;\n setCheckedValues: UseStateSetter<ReadonlySet<V>>;\n getCheckboxProps: (value: V) => {\n checked: boolean;\n onCheckedChange: () => void;\n };\n}\n\n/** @since 6.0.0 */\nexport interface IndeterminateMenuItemCheckboxGroupImplementation<\n V extends string,\n> extends MenuItemCheckboxGroupImplementation<V> {\n getIndeterminateProps: () => {\n \"aria-checked\": \"mixed\" | undefined;\n checked: boolean;\n indeterminate: boolean;\n onCheckedChange: () => void;\n };\n}\n\n/** @since 6.0.0 */\nexport interface CombinedCheckboxGroupReturnValue<V extends string> {\n reset: () => void;\n checkedValues: ReadonlySet<V>;\n setCheckedValues: UseStateSetter<ReadonlySet<V>>;\n getCheckboxProps: (value: V) => {\n name?: string;\n value?: V;\n checked: boolean;\n onChange?: () => void;\n onCheckedChange?: () => void;\n };\n getIndeterminateProps?: () => {\n \"aria-checked\": \"mixed\" | undefined;\n name?: string;\n checked: boolean;\n indeterminate: boolean;\n onChange?: () => void;\n onCheckedChange?: () => void;\n };\n}\n\n/**\n * @example Checkbox Group\n * ```tsx\n * const { getCheckboxProps, checkedValues } = useCheckboxGroup({ name: \"example\" });\n *\n * return (\n * <>\n * <Checkbox {...getCheckboxProps(\"a\")}>\n * First\n * </Checkbox>\n * <Checkbox {...getCheckboxProps(\"b\")}>\n * Second\n * </Checkbox>\n * <Checkbox {...getCheckboxProps(\"c\")}>\n * Third\n * </Checkbox>\n * </>\n * );\n * ```\n *\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V> & {\n menu?: false;\n name: string;\n values?: never;\n }\n): CheckboxGroupImplementation<V>;\n/**\n * @example Indeterminate Checkbox Group\n * ```tsx\n * const OPTIONS = [\n * { label: \"First\", value: \"a\" },\n * { label: \"Second\", value: \"b\" },\n * { label: \"Third\", value: \"c\" },\n * ] as const:\n * const VALUES = OPTIONS.map(({ value }) => value) as const;\n *\n * const {\n * getCheckboxProps,\n * getIndeterminateProps,\n * checkedValues\n * } = useCheckboxGroup({\n * name: \"example\",\n * values: VALUES,\n * });\n *\n * return (\n * <>\n * <Checkbox {...getIndeterminateProps()} label=\"Select all\" />\n * {VALUES.map(({ label, value }) => (\n * <Checkbox key={value} label={label} {...getCheckboxProps(value)} />\n * ))}\n * </>\n * );\n * ```\n *\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V> & {\n menu?: false;\n name: string;\n values: readonly V[];\n }\n): IndeterminateCheckboxGroupImplementation<V>;\n/**\n * @example MenuItemCheckbox Group\n * ```tsx\n * const { getCheckboxProps, checkedValues } = useCheckboxGroup({ menu: true });\n *\n * return (\n * <>\n * <MenuItemCheckbox {...getCheckboxProps(\"a\")}>\n * First\n * </MenuItemCheckbox>\n * <MenuItemCheckbox {...getCheckboxProps(\"b\")}>\n * Second\n * </MenuItemCheckbox>\n * <MenuItemCheckbox {...getCheckboxProps(\"c\")}>\n * Third\n * </MenuItemCheckbox>\n * </>\n * );\n * ```\n *\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V> & {\n menu: true;\n name?: never;\n values?: never;\n }\n): MenuItemCheckboxGroupImplementation<V>;\n/**\n * @example Indeterminate MenuItemCheckbox Group\n * ```tsx\n * const OPTIONS = [\n * { label: \"First\", value: \"a\" },\n * { label: \"Second\", value: \"b\" },\n * { label: \"Third\", value: \"c\" },\n * ] as const:\n * const VALUES = OPTIONS.map(({ value }) => value) as const;\n *\n * const { getCheckboxProps, getIndeterminateProps, checkedValues } = useCheckboxGroup({\n * menu: true,\n * values: VALUES,\n * });\n *\n * return (\n * <>\n * <MenuItemCheckbox {...getIndeterminateProps()}>\n * All\n * <MenuItemCheckbox>\n * {OPTIONS.map(({ label, value }) => (\n * <MenuItemCheckbox key={value} {...getCheckboxProps(value)}>\n * {label}\n * </MenuItemCheckbox>\n * ))}\n * </>\n * );\n * ```\n *\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V> & {\n menu: true;\n name?: never;\n values: readonly V[];\n }\n): IndeterminateMenuItemCheckboxGroupImplementation<V>;\n/**\n * @see {@link https://react-md.dev/components/Checkbox | Checkbox Demos}\n * @see {@link https://react-md.dev/hooks/use-checkbox-group | useCheckboxGroup Demos}\n * @since 6.0.0\n * @internal\n */\nexport function useCheckboxGroup<V extends string>(\n options: CheckboxGroupOptions<V>\n): CombinedCheckboxGroupReturnValue<V> {\n const {\n name,\n menu = false,\n values,\n defaultCheckedValues = EMPTY_LIST,\n } = options;\n const {\n value: checkedValues,\n setValue: setCheckedValues,\n toggleValue,\n } = useReadonlySet({\n defaultValue: defaultCheckedValues,\n });\n const initial = useRef(checkedValues);\n\n let getIndeterminateProps: CombinedCheckboxGroupReturnValue<V>[\"getIndeterminateProps\"];\n if (values) {\n getIndeterminateProps = () => {\n const checked = checkedValues.size > 0;\n const indeterminate = checked && checkedValues.size < values.length;\n\n return {\n \"aria-checked\": indeterminate ? \"mixed\" : undefined,\n name,\n checked,\n indeterminate,\n [menu ? \"onCheckedChange\" : \"onChange\"]() {\n setCheckedValues((checkedValues) => {\n if (checkedValues.size === 0 || indeterminate) {\n return new Set(values);\n }\n\n return new Set();\n });\n },\n };\n };\n }\n\n return {\n reset: useCallback(() => {\n setCheckedValues(initial.current);\n }, [setCheckedValues]),\n checkedValues,\n setCheckedValues,\n getIndeterminateProps,\n getCheckboxProps(value) {\n return {\n name,\n value: menu ? undefined : value,\n checked: checkedValues.has(value),\n [menu ? \"onCheckedChange\" : \"onChange\"]() {\n toggleValue(value);\n },\n };\n },\n };\n}\n"],"names":["useCallback","useRef","useReadonlySet","EMPTY_LIST","useCheckboxGroup","options","name","menu","values","defaultCheckedValues","value","checkedValues","setValue","setCheckedValues","toggleValue","defaultValue","initial","getIndeterminateProps","checked","size","indeterminate","length","undefined","Set","reset","current","getCheckboxProps","has"],"mappings":"AAAA;AAEA,SAASA,WAAW,EAAEC,MAAM,QAAQ,QAAQ;AAG5C,SAASC,cAAc,QAAQ,uBAAuB;AAEtD,MAAMC,aAAa,EAAE;AAwQrB;;;;;CAKC,GACD,OAAO,SAASC,iBACdC,OAAgC;IAEhC,MAAM,EACJC,IAAI,EACJC,OAAO,KAAK,EACZC,MAAM,EACNC,uBAAuBN,UAAU,EAClC,GAAGE;IACJ,MAAM,EACJK,OAAOC,aAAa,EACpBC,UAAUC,gBAAgB,EAC1BC,WAAW,EACZ,GAAGZ,eAAe;QACjBa,cAAcN;IAChB;IACA,MAAMO,UAAUf,OAAOU;IAEvB,IAAIM;IACJ,IAAIT,QAAQ;QACVS,wBAAwB;YACtB,MAAMC,UAAUP,cAAcQ,IAAI,GAAG;YACrC,MAAMC,gBAAgBF,WAAWP,cAAcQ,IAAI,GAAGX,OAAOa,MAAM;YAEnE,OAAO;gBACL,gBAAgBD,gBAAgB,UAAUE;gBAC1ChB;gBACAY;gBACAE;gBACA,CAACb,OAAO,oBAAoB,WAAW;oBACrCM,iBAAiB,CAACF;wBAChB,IAAIA,cAAcQ,IAAI,KAAK,KAAKC,eAAe;4BAC7C,OAAO,IAAIG,IAAIf;wBACjB;wBAEA,OAAO,IAAIe;oBACb;gBACF;YACF;QACF;IACF;IAEA,OAAO;QACLC,OAAOxB,YAAY;YACjBa,iBAAiBG,QAAQS,OAAO;QAClC,GAAG;YAACZ;SAAiB;QACrBF;QACAE;QACAI;QACAS,kBAAiBhB,KAAK;YACpB,OAAO;gBACLJ;gBACAI,OAAOH,OAAOe,YAAYZ;gBAC1BQ,SAASP,cAAcgB,GAAG,CAACjB;gBAC3B,CAACH,OAAO,oBAAoB,WAAW;oBACrCO,YAAYJ;gBACd;YACF;QACF;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/useCombobox.ts"],"sourcesContent":["\"use client\";\n\nimport {\n type FocusEventHandler,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n type InputHTMLAttributes,\n type KeyboardEventHandler,\n type MouseEventHandler,\n type Ref,\n type RefCallback,\n type RefObject,\n useCallback,\n useRef,\n} from \"react\";\n\nimport { type MenuProps } from \"../menu/Menu.js\";\nimport { type MenuSheetConfigurableProps } from \"../menu/MenuSheet.js\";\nimport {\n type GetDefaultFocusedIndex,\n type GetFocusableElements,\n type KeyboardMovementExtensionData,\n type KeyboardMovementProviderImplementation,\n type KeyboardMovementProviderOptions,\n} from \"../movement/types.js\";\nimport { useKeyboardMovementProvider } from \"../movement/useKeyboardMovementProvider.js\";\nimport { BELOW_CENTER_ANCHOR } from \"../positioning/constants.js\";\nimport {\n type PositionAnchor,\n type PositionWidth,\n} from \"../positioning/types.js\";\nimport { getTransitionCallbacks } from \"../transition/getTransitionCallbacks.js\";\nimport { type TransitionCallbacks } from \"../transition/types.js\";\nimport {\n type NonNullMutableRef,\n type UseStateInitializer,\n type UseStateSetter,\n} from \"../types.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useEnsuredState } from \"../useEnsuredState.js\";\nimport { tryToSubmitRelatedForm } from \"./utils.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 6.0.0\n */\nexport const getNonDisabledOptions = (\n container: HTMLElement\n): readonly HTMLElement[] => [\n ...container.querySelectorAll<HTMLLIElement>(\n '[role=\"option\"]:not([aria-disabled])'\n ),\n];\n\n/**\n * @since 6.0.0\n */\nexport type SupportedComboboxPopup = \"listbox\" | \"grid\" | \"dialog\";\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxKeyboardMovementData<\n E extends HTMLElement = HTMLInputElement,\n> extends KeyboardMovementExtensionData<E> {\n show: () => void;\n hide: () => void;\n visible: boolean;\n\n /**\n * @since 6.3.0 Renamed from `focusLast` to `focusLastRef` to support the new\n * actions.\n */\n focusLastRef: NonNullMutableRef<boolean>;\n}\n\n/**\n * @since 6.0.0\n */\nexport type ExtendComboboxKeyDown<E extends HTMLElement = HTMLInputElement> = (\n movementData: ComboboxKeyboardMovementData<E>\n) => void;\n\n/**\n * @since 6.0.0\n */\nexport type ComboboxKeyboardMovementOptions<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n> = Pick<\n KeyboardMovementProviderOptions<ComboboxEl>,\n | \"onClick\"\n | \"onFocus\"\n | \"onKeyDown\"\n | \"disabled\"\n | \"loopable\"\n | \"searchable\"\n | \"onFocusChange\"\n | \"isNegativeOneAllowed\"\n>;\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxVisibilityOptions {\n /**\n * This can be used to control the popup's visibility and **must** be used\n * along with {@link setVisible}.\n */\n visible?: boolean;\n\n /**\n * Used to control the popup's visibility and should generally be a `useState`\n * setter.\n *\n * @example Controlling the Visibility\n * ```tsx\n * const [visible, setVisible] = useState(false);\n *\n * useCombobox({\n * visible,\n * setVisible,\n * });\n * ```\n */\n setVisible?: UseStateSetter<boolean>;\n\n /**\n * Set this to `true` to have the combobox's popup visible by default.\n *\n * @defaultValue `false`\n */\n defaultVisible?: UseStateInitializer<boolean>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ConfigurableComboboxOptions<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n PopupEl extends HTMLElement = HTMLElement,\n> extends ComboboxKeyboardMovementOptions<ComboboxEl>,\n ComboboxVisibilityOptions {\n /**\n * This is the {@link InputHTMLAttributes.form} attribute and is used to\n * attempt submitting a form when the enter key is pressed.\n */\n form?: string;\n\n /**\n * @defaultValue `\"combobox-popup-\" + useId()`\n */\n popupId?: string;\n popupRef?: Ref<PopupEl>;\n\n /**\n * @defaultValue `\"combobox-\" + useId()`\n */\n comboboxId?: string;\n comboboxRef?: Ref<ComboboxEl>;\n\n /**\n * @defaultValue `\"listbox\"`\n */\n popup?: \"listbox\" | \"grid\" | \"dialog\";\n\n /**\n * @defaultValue `false`\n */\n multiselect?: boolean;\n\n extendKeyDown?: ExtendComboboxKeyDown<ComboboxEl>;\n\n /**\n * @defaultValue {@link getNonDisabledOptions}\n */\n getFocusableElements?: GetFocusableElements;\n\n getDefaultFocusedIndex?: GetDefaultFocusedIndex;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxGetEnterDefaultFocusedIndexOptions {\n focusLast: boolean;\n focusables: readonly HTMLElement[];\n currentFocusIndex: number;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxOptions<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n PopupEl extends HTMLElement = HTMLElement,\n> extends ConfigurableComboboxOptions<ComboboxEl, PopupEl> {\n getEnterDefaultFocusedIndex: (\n options: ComboboxGetEnterDefaultFocusedIndexOptions\n ) => number;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxWidgetProps<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n> {\n \"aria-controls\": string;\n \"aria-disabled\": true | undefined;\n \"aria-expanded\": boolean;\n \"aria-haspopup\": SupportedComboboxPopup;\n id: string;\n ref: RefCallback<ComboboxEl>;\n role: \"combobox\";\n onClick: MouseEventHandler<ComboboxEl>;\n onFocus: FocusEventHandler<ComboboxEl>;\n onKeyDown: KeyboardEventHandler<ComboboxEl>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxWidgetPopupProps<\n PopupEl extends HTMLElement = HTMLElement,\n> {\n \"aria-multiselectable\": true | undefined;\n id: string;\n ref: RefCallback<PopupEl>;\n role: \"listbox\" | \"dialog\" | \"grid\";\n}\n\n/**\n * @since 6.0.0\n */\nexport type ComboboxTransitionCallbacks = Pick<\n TransitionCallbacks,\n \"onEntering\" | \"onEntered\" | \"onExiting\" | \"onExited\"\n>;\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxTransitionOptions extends ComboboxTransitionCallbacks {\n disableTransition?: boolean;\n}\n\n/**\n * @since 6.0.0\n */\nexport type ConfigurableComboboxMenuProps = Partial<\n Omit<MenuProps, \"visible\" | \"onRequestClose\" | keyof ComboboxWidgetPopupProps>\n>;\n\n/**\n * @since 6.0.0\n */\nexport interface ProvidedComboboxMenuProps<\n PopupEl extends HTMLElement = HTMLDivElement,\n> extends Required<ComboboxTransitionCallbacks>,\n ComboboxWidgetPopupProps<PopupEl> {\n visible: boolean;\n onRequestClose: () => void;\n /** @defaultValue `\"min\"` */\n width: PositionWidth;\n /** @defaultValue `BELOW_CENTER_ANCHOR` */\n anchor: PositionAnchor;\n fixedTo: RefObject<HTMLElement>;\n sheetProps: MenuSheetConfigurableProps &\n Required<ComboboxTransitionCallbacks>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxMenuProps<PopupEl extends HTMLElement = HTMLDivElement>\n extends Omit<ConfigurableComboboxMenuProps, keyof ProvidedComboboxMenuProps>,\n ProvidedComboboxMenuProps<PopupEl> {}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxImplementation<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n PopupEl extends HTMLElement = HTMLElement,\n> extends Omit<KeyboardMovementProviderImplementation<ComboboxEl>, \"nodeRef\"> {\n show: () => void;\n hide: () => void;\n visible: boolean;\n setVisible: UseStateSetter<boolean>;\n focusLast: NonNullMutableRef<boolean>;\n popupRef: RefObject<PopupEl>;\n popupProps: ComboboxWidgetPopupProps<PopupEl>;\n comboboxRef: RefObject<ComboboxEl>;\n comboboxProps: ComboboxWidgetProps<ComboboxEl>;\n /**\n * Since the combobox usually uses the `Menu` as a popup element, this is a\n * helper util to create the required props and merge any additional props\n * with reasonable defaults.\n */\n getMenuProps: (\n overrides?: ConfigurableComboboxMenuProps\n ) => ComboboxMenuProps<PopupEl>;\n}\n\n/**\n * @since 6.0.0\n */\nexport function useCombobox<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n PopupEl extends HTMLElement = HTMLElement,\n>(\n options: ComboboxOptions<ComboboxEl, PopupEl>\n): ComboboxImplementation<ComboboxEl, PopupEl> {\n const {\n form,\n popup = \"listbox\",\n onClick = noop,\n onFocus,\n onKeyDown,\n searchable,\n multiselect,\n isNegativeOneAllowed,\n loopable,\n disabled,\n visible: propVisible,\n setVisible: propSetVisible,\n defaultVisible = false,\n comboboxId: propComboboxId,\n comboboxRef: propComboboxRef,\n popupId: propPopupId,\n popupRef: propPopupRef,\n onFocusChange = noop,\n extendKeyDown = noop,\n getFocusableElements = getNonDisabledOptions,\n getEnterDefaultFocusedIndex,\n getDefaultFocusedIndex,\n } = options;\n\n const [visible, setVisible] = useEnsuredState({\n name: \"visible\",\n value: propVisible,\n setValue: propSetVisible,\n defaultValue: defaultVisible,\n });\n const show = useCallback(() => {\n setVisible(true);\n }, [setVisible]);\n const hide = useCallback(() => {\n setVisible(false);\n }, [setVisible]);\n\n const popupId = useEnsuredId(propPopupId, \"combobox-popup\");\n const comboboxId = useEnsuredId(propComboboxId, \"combobox\");\n const [popupRef, popupRefCallback] = useEnsuredRef(propPopupRef);\n const focusLastRef = useRef(false);\n const {\n nodeRef: comboboxRef,\n movementProps,\n movementContext,\n currentFocusIndex,\n activeDescendantId,\n setActiveDescendantId,\n } = useKeyboardMovementProvider<ComboboxEl>({\n ref: propComboboxRef,\n onFocus,\n onKeyDown,\n onClick(event) {\n onClick(event);\n if (disabled) {\n return;\n }\n\n show();\n },\n extendKeyDown(movementData) {\n extendKeyDown({\n ...movementData,\n show,\n hide,\n visible,\n focusLastRef,\n });\n const { event } = movementData;\n if (event.isPropagationStopped()) {\n return;\n }\n\n if (visible) {\n switch (event.key) {\n case \"Tab\":\n // do not stop propagation for tab so that shift+tab works correctly in dialogs\n hide();\n break;\n case \"Escape\":\n event.stopPropagation();\n hide();\n break;\n case \"Enter\":\n event.preventDefault();\n break;\n }\n\n // while visible, always use the default keyboard movement behavior\n return;\n }\n\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowDown\":\n event.preventDefault();\n event.stopPropagation();\n focusLastRef.current = event.key === \"ArrowUp\";\n show();\n break;\n case \"Enter\":\n tryToSubmitRelatedForm(event, form);\n break;\n }\n },\n disabled,\n loopable,\n searchable,\n onFocusChange,\n programmatic: true,\n includeDisabled: false,\n tabIndexBehavior: \"virtual\",\n getFocusableElements(container, programmatic) {\n const popup = popupRef.current;\n if (!popup) {\n return [];\n }\n\n return getFocusableElements(popup || container, programmatic);\n },\n isNegativeOneAllowed,\n getDefaultFocusedIndex,\n });\n\n const popupProps: ComboboxWidgetPopupProps<PopupEl> = {\n \"aria-multiselectable\": multiselect || undefined,\n id: popupId,\n ref: popupRefCallback,\n role: popup,\n };\n\n return {\n show,\n hide,\n visible,\n setVisible,\n focusLast: focusLastRef,\n popupRef,\n popupProps,\n comboboxRef,\n comboboxProps: {\n ...movementProps,\n \"aria-controls\": popupId,\n \"aria-disabled\": disabled || undefined,\n \"aria-expanded\": visible,\n \"aria-haspopup\": popup,\n id: comboboxId,\n role: \"combobox\",\n },\n movementProps,\n movementContext,\n currentFocusIndex,\n activeDescendantId,\n setActiveDescendantId,\n getMenuProps(props = {}) {\n const {\n sheetProps,\n disableTransition,\n onEnter,\n onEntering,\n onEntered = noop,\n onExited,\n onExiting,\n onExit,\n } = props;\n\n // Chrome does not trigger the scrollIntoView behavior correctly while\n // using a scale transition, so need to trigger this on the entered flow\n // to really make sure the item is in view. An alternative would be to\n // implement a custom scrollIntoView behavior again like the previous\n // versions of react-md, but this is less lines of code\n const attemptScroll = (): void => {\n const activeOption = document.getElementById(activeDescendantId);\n if (activeOption) {\n activeOption.scrollIntoView({ block: \"nearest\" });\n }\n };\n const onEnterOnce = (): void => {\n const popup = popupRef.current;\n if (!popup) {\n attemptScroll();\n return;\n }\n\n const focusables = getFocusableElements(popup, true);\n const index = getEnterDefaultFocusedIndex({\n focusLast: focusLastRef.current,\n focusables,\n currentFocusIndex: currentFocusIndex.current,\n });\n focusLastRef.current = false;\n currentFocusIndex.current = index;\n\n const option = focusables[index];\n if (!option) {\n return;\n }\n\n onFocusChange({\n index,\n element: option,\n });\n\n option.scrollIntoView({ block: \"nearest\" });\n setActiveDescendantId(option.id || \"\");\n };\n\n return {\n anchor: BELOW_CENTER_ANCHOR,\n width: \"min\",\n fixedTo: comboboxRef,\n ...props,\n ...popupProps,\n visible,\n onRequestClose: hide,\n ...getTransitionCallbacks({\n disableTransition,\n onEnter,\n onEntered: (appearing) => {\n onEntered(appearing);\n attemptScroll();\n },\n onEntering,\n onEnterOnce,\n onExit,\n onExiting,\n onExited,\n onExitOnce: () => {\n // since the menu is unmounted or set to hidden while not visible, need\n // to clear the aria-activedescendant and current focus index when\n // hiding\n currentFocusIndex.current = -1;\n setActiveDescendantId(\"\");\n },\n }),\n sheetProps: {\n ...sheetProps,\n ...getTransitionCallbacks({\n ...sheetProps,\n onEnterOnce,\n disableTransition:\n sheetProps?.disableTransition ?? disableTransition,\n }),\n },\n };\n },\n };\n}\n"],"names":["useCallback","useRef","useKeyboardMovementProvider","BELOW_CENTER_ANCHOR","getTransitionCallbacks","useEnsuredId","useEnsuredRef","useEnsuredState","tryToSubmitRelatedForm","noop","getNonDisabledOptions","container","querySelectorAll","useCombobox","options","form","popup","onClick","onFocus","onKeyDown","searchable","multiselect","isNegativeOneAllowed","loopable","disabled","visible","propVisible","setVisible","propSetVisible","defaultVisible","comboboxId","propComboboxId","comboboxRef","propComboboxRef","popupId","propPopupId","popupRef","propPopupRef","onFocusChange","extendKeyDown","getFocusableElements","getEnterDefaultFocusedIndex","getDefaultFocusedIndex","name","value","setValue","defaultValue","show","hide","popupRefCallback","focusLastRef","nodeRef","movementProps","movementContext","currentFocusIndex","activeDescendantId","setActiveDescendantId","ref","event","movementData","isPropagationStopped","key","stopPropagation","preventDefault","current","programmatic","includeDisabled","tabIndexBehavior","popupProps","undefined","id","role","focusLast","comboboxProps","getMenuProps","props","sheetProps","disableTransition","onEnter","onEntering","onEntered","onExited","onExiting","onExit","attemptScroll","activeOption","document","getElementById","scrollIntoView","block","onEnterOnce","focusables","index","option","element","anchor","width","fixedTo","onRequestClose","appearing","onExitOnce"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/form/useCombobox.ts"],"sourcesContent":["\"use client\";\n\nimport {\n type FocusEventHandler,\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n type InputHTMLAttributes,\n type KeyboardEventHandler,\n type MouseEventHandler,\n type Ref,\n type RefCallback,\n type RefObject,\n useCallback,\n useRef,\n} from \"react\";\n\nimport { type MenuProps } from \"../menu/Menu.js\";\nimport { type MenuSheetConfigurableProps } from \"../menu/MenuSheet.js\";\nimport {\n type GetDefaultFocusedIndex,\n type GetFocusableElements,\n type KeyboardMovementExtensionData,\n type KeyboardMovementProviderImplementation,\n type KeyboardMovementProviderOptions,\n} from \"../movement/types.js\";\nimport { useKeyboardMovementProvider } from \"../movement/useKeyboardMovementProvider.js\";\nimport { BELOW_CENTER_ANCHOR } from \"../positioning/constants.js\";\nimport {\n type PositionAnchor,\n type PositionWidth,\n} from \"../positioning/types.js\";\nimport { getTransitionCallbacks } from \"../transition/getTransitionCallbacks.js\";\nimport { type TransitionCallbacks } from \"../transition/types.js\";\nimport {\n type NonNullMutableRef,\n type UseStateInitializer,\n type UseStateSetter,\n} from \"../types.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useEnsuredState } from \"../useEnsuredState.js\";\nimport { tryToSubmitRelatedForm } from \"./utils.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 6.0.0\n */\nexport const getNonDisabledOptions = (\n container: HTMLElement\n): readonly HTMLElement[] => [\n ...container.querySelectorAll<HTMLLIElement>(\n '[role=\"option\"]:not([aria-disabled])'\n ),\n];\n\n/**\n * @since 6.0.0\n */\nexport type SupportedComboboxPopup = \"listbox\" | \"grid\" | \"dialog\";\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxKeyboardMovementData<\n E extends HTMLElement = HTMLInputElement,\n> extends KeyboardMovementExtensionData<E> {\n show: () => void;\n hide: () => void;\n visible: boolean;\n\n /**\n * @since 6.3.0 Renamed from `focusLast` to `focusLastRef` to support the new\n * actions.\n */\n focusLastRef: NonNullMutableRef<boolean>;\n}\n\n/**\n * @since 6.0.0\n */\nexport type ExtendComboboxKeyDown<E extends HTMLElement = HTMLInputElement> = (\n movementData: ComboboxKeyboardMovementData<E>\n) => void;\n\n/**\n * @since 6.0.0\n */\nexport type ComboboxKeyboardMovementOptions<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n> = Pick<\n KeyboardMovementProviderOptions<ComboboxEl>,\n | \"onClick\"\n | \"onFocus\"\n | \"onKeyDown\"\n | \"disabled\"\n | \"loopable\"\n | \"searchable\"\n | \"onFocusChange\"\n | \"isNegativeOneAllowed\"\n>;\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxVisibilityOptions {\n /**\n * This can be used to control the popup's visibility and **must** be used\n * along with {@link setVisible}.\n */\n visible?: boolean;\n\n /**\n * Used to control the popup's visibility and should generally be a `useState`\n * setter.\n *\n * @example Controlling the Visibility\n * ```tsx\n * const [visible, setVisible] = useState(false);\n *\n * useCombobox({\n * visible,\n * setVisible,\n * });\n * ```\n */\n setVisible?: UseStateSetter<boolean>;\n\n /**\n * Set this to `true` to have the combobox's popup visible by default.\n *\n * @defaultValue `false`\n */\n defaultVisible?: UseStateInitializer<boolean>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ConfigurableComboboxOptions<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n PopupEl extends HTMLElement = HTMLElement,\n>\n extends\n ComboboxKeyboardMovementOptions<ComboboxEl>,\n ComboboxVisibilityOptions {\n /**\n * This is the {@link InputHTMLAttributes.form} attribute and is used to\n * attempt submitting a form when the enter key is pressed.\n */\n form?: string;\n\n /**\n * @defaultValue `\"combobox-popup-\" + useId()`\n */\n popupId?: string;\n popupRef?: Ref<PopupEl>;\n\n /**\n * @defaultValue `\"combobox-\" + useId()`\n */\n comboboxId?: string;\n comboboxRef?: Ref<ComboboxEl>;\n\n /**\n * @defaultValue `\"listbox\"`\n */\n popup?: \"listbox\" | \"grid\" | \"dialog\";\n\n /**\n * @defaultValue `false`\n */\n multiselect?: boolean;\n\n extendKeyDown?: ExtendComboboxKeyDown<ComboboxEl>;\n\n /**\n * @defaultValue {@link getNonDisabledOptions}\n */\n getFocusableElements?: GetFocusableElements;\n\n getDefaultFocusedIndex?: GetDefaultFocusedIndex;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxGetEnterDefaultFocusedIndexOptions {\n focusLast: boolean;\n focusables: readonly HTMLElement[];\n currentFocusIndex: number;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxOptions<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n PopupEl extends HTMLElement = HTMLElement,\n> extends ConfigurableComboboxOptions<ComboboxEl, PopupEl> {\n getEnterDefaultFocusedIndex: (\n options: ComboboxGetEnterDefaultFocusedIndexOptions\n ) => number;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxWidgetProps<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n> {\n \"aria-controls\": string;\n \"aria-disabled\": true | undefined;\n \"aria-expanded\": boolean;\n \"aria-haspopup\": SupportedComboboxPopup;\n id: string;\n ref: RefCallback<ComboboxEl>;\n role: \"combobox\";\n onClick: MouseEventHandler<ComboboxEl>;\n onFocus: FocusEventHandler<ComboboxEl>;\n onKeyDown: KeyboardEventHandler<ComboboxEl>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxWidgetPopupProps<\n PopupEl extends HTMLElement = HTMLElement,\n> {\n \"aria-multiselectable\": true | undefined;\n id: string;\n ref: RefCallback<PopupEl>;\n role: \"listbox\" | \"dialog\" | \"grid\";\n}\n\n/**\n * @since 6.0.0\n */\nexport type ComboboxTransitionCallbacks = Pick<\n TransitionCallbacks,\n \"onEntering\" | \"onEntered\" | \"onExiting\" | \"onExited\"\n>;\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxTransitionOptions extends ComboboxTransitionCallbacks {\n disableTransition?: boolean;\n}\n\n/**\n * @since 6.0.0\n */\nexport type ConfigurableComboboxMenuProps = Partial<\n Omit<MenuProps, \"visible\" | \"onRequestClose\" | keyof ComboboxWidgetPopupProps>\n>;\n\n/**\n * @since 6.0.0\n */\nexport interface ProvidedComboboxMenuProps<\n PopupEl extends HTMLElement = HTMLDivElement,\n>\n extends\n Required<ComboboxTransitionCallbacks>,\n ComboboxWidgetPopupProps<PopupEl> {\n visible: boolean;\n onRequestClose: () => void;\n /** @defaultValue `\"min\"` */\n width: PositionWidth;\n /** @defaultValue `BELOW_CENTER_ANCHOR` */\n anchor: PositionAnchor;\n fixedTo: RefObject<HTMLElement>;\n sheetProps: MenuSheetConfigurableProps &\n Required<ComboboxTransitionCallbacks>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxMenuProps<PopupEl extends HTMLElement = HTMLDivElement>\n extends\n Omit<ConfigurableComboboxMenuProps, keyof ProvidedComboboxMenuProps>,\n ProvidedComboboxMenuProps<PopupEl> {}\n\n/**\n * @since 6.0.0\n */\nexport interface ComboboxImplementation<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n PopupEl extends HTMLElement = HTMLElement,\n> extends Omit<KeyboardMovementProviderImplementation<ComboboxEl>, \"nodeRef\"> {\n show: () => void;\n hide: () => void;\n visible: boolean;\n setVisible: UseStateSetter<boolean>;\n focusLast: NonNullMutableRef<boolean>;\n popupRef: RefObject<PopupEl>;\n popupProps: ComboboxWidgetPopupProps<PopupEl>;\n comboboxRef: RefObject<ComboboxEl>;\n comboboxProps: ComboboxWidgetProps<ComboboxEl>;\n /**\n * Since the combobox usually uses the `Menu` as a popup element, this is a\n * helper util to create the required props and merge any additional props\n * with reasonable defaults.\n */\n getMenuProps: (\n overrides?: ConfigurableComboboxMenuProps\n ) => ComboboxMenuProps<PopupEl>;\n}\n\n/**\n * @since 6.0.0\n */\nexport function useCombobox<\n ComboboxEl extends HTMLElement = HTMLInputElement,\n PopupEl extends HTMLElement = HTMLElement,\n>(\n options: ComboboxOptions<ComboboxEl, PopupEl>\n): ComboboxImplementation<ComboboxEl, PopupEl> {\n const {\n form,\n popup = \"listbox\",\n onClick = noop,\n onFocus,\n onKeyDown,\n searchable,\n multiselect,\n isNegativeOneAllowed,\n loopable,\n disabled,\n visible: propVisible,\n setVisible: propSetVisible,\n defaultVisible = false,\n comboboxId: propComboboxId,\n comboboxRef: propComboboxRef,\n popupId: propPopupId,\n popupRef: propPopupRef,\n onFocusChange = noop,\n extendKeyDown = noop,\n getFocusableElements = getNonDisabledOptions,\n getEnterDefaultFocusedIndex,\n getDefaultFocusedIndex,\n } = options;\n\n const [visible, setVisible] = useEnsuredState({\n name: \"visible\",\n value: propVisible,\n setValue: propSetVisible,\n defaultValue: defaultVisible,\n });\n const show = useCallback(() => {\n setVisible(true);\n }, [setVisible]);\n const hide = useCallback(() => {\n setVisible(false);\n }, [setVisible]);\n\n const popupId = useEnsuredId(propPopupId, \"combobox-popup\");\n const comboboxId = useEnsuredId(propComboboxId, \"combobox\");\n const [popupRef, popupRefCallback] = useEnsuredRef(propPopupRef);\n const focusLastRef = useRef(false);\n const {\n nodeRef: comboboxRef,\n movementProps,\n movementContext,\n currentFocusIndex,\n activeDescendantId,\n setActiveDescendantId,\n } = useKeyboardMovementProvider<ComboboxEl>({\n ref: propComboboxRef,\n onFocus,\n onKeyDown,\n onClick(event) {\n onClick(event);\n if (disabled) {\n return;\n }\n\n show();\n },\n extendKeyDown(movementData) {\n extendKeyDown({\n ...movementData,\n show,\n hide,\n visible,\n focusLastRef,\n });\n const { event } = movementData;\n if (event.isPropagationStopped()) {\n return;\n }\n\n if (visible) {\n switch (event.key) {\n case \"Tab\":\n // do not stop propagation for tab so that shift+tab works correctly in dialogs\n hide();\n break;\n case \"Escape\":\n event.stopPropagation();\n hide();\n break;\n case \"Enter\":\n event.preventDefault();\n break;\n }\n\n // while visible, always use the default keyboard movement behavior\n return;\n }\n\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowDown\":\n event.preventDefault();\n event.stopPropagation();\n focusLastRef.current = event.key === \"ArrowUp\";\n show();\n break;\n case \"Enter\":\n tryToSubmitRelatedForm(event, form);\n break;\n }\n },\n disabled,\n loopable,\n searchable,\n onFocusChange,\n programmatic: true,\n includeDisabled: false,\n tabIndexBehavior: \"virtual\",\n getFocusableElements(container, programmatic) {\n const popup = popupRef.current;\n if (!popup) {\n return [];\n }\n\n return getFocusableElements(popup || container, programmatic);\n },\n isNegativeOneAllowed,\n getDefaultFocusedIndex,\n });\n\n const popupProps: ComboboxWidgetPopupProps<PopupEl> = {\n \"aria-multiselectable\": multiselect || undefined,\n id: popupId,\n ref: popupRefCallback,\n role: popup,\n };\n\n return {\n show,\n hide,\n visible,\n setVisible,\n focusLast: focusLastRef,\n popupRef,\n popupProps,\n comboboxRef,\n comboboxProps: {\n ...movementProps,\n \"aria-controls\": popupId,\n \"aria-disabled\": disabled || undefined,\n \"aria-expanded\": visible,\n \"aria-haspopup\": popup,\n id: comboboxId,\n role: \"combobox\",\n },\n movementProps,\n movementContext,\n currentFocusIndex,\n activeDescendantId,\n setActiveDescendantId,\n getMenuProps(props = {}) {\n const {\n sheetProps,\n disableTransition,\n onEnter,\n onEntering,\n onEntered = noop,\n onExited,\n onExiting,\n onExit,\n } = props;\n\n // Chrome does not trigger the scrollIntoView behavior correctly while\n // using a scale transition, so need to trigger this on the entered flow\n // to really make sure the item is in view. An alternative would be to\n // implement a custom scrollIntoView behavior again like the previous\n // versions of react-md, but this is less lines of code\n const attemptScroll = (): void => {\n const activeOption = document.getElementById(activeDescendantId);\n if (activeOption) {\n activeOption.scrollIntoView({ block: \"nearest\" });\n }\n };\n const onEnterOnce = (): void => {\n const popup = popupRef.current;\n if (!popup) {\n attemptScroll();\n return;\n }\n\n const focusables = getFocusableElements(popup, true);\n const index = getEnterDefaultFocusedIndex({\n focusLast: focusLastRef.current,\n focusables,\n currentFocusIndex: currentFocusIndex.current,\n });\n focusLastRef.current = false;\n currentFocusIndex.current = index;\n\n const option = focusables[index];\n if (!option) {\n return;\n }\n\n onFocusChange({\n index,\n element: option,\n });\n\n option.scrollIntoView({ block: \"nearest\" });\n setActiveDescendantId(option.id || \"\");\n };\n\n return {\n anchor: BELOW_CENTER_ANCHOR,\n width: \"min\",\n fixedTo: comboboxRef,\n ...props,\n ...popupProps,\n visible,\n onRequestClose: hide,\n ...getTransitionCallbacks({\n disableTransition,\n onEnter,\n onEntered: (appearing) => {\n onEntered(appearing);\n attemptScroll();\n },\n onEntering,\n onEnterOnce,\n onExit,\n onExiting,\n onExited,\n onExitOnce: () => {\n // since the menu is unmounted or set to hidden while not visible, need\n // to clear the aria-activedescendant and current focus index when\n // hiding\n currentFocusIndex.current = -1;\n setActiveDescendantId(\"\");\n },\n }),\n sheetProps: {\n ...sheetProps,\n ...getTransitionCallbacks({\n ...sheetProps,\n onEnterOnce,\n disableTransition:\n sheetProps?.disableTransition ?? disableTransition,\n }),\n },\n };\n },\n };\n}\n"],"names":["useCallback","useRef","useKeyboardMovementProvider","BELOW_CENTER_ANCHOR","getTransitionCallbacks","useEnsuredId","useEnsuredRef","useEnsuredState","tryToSubmitRelatedForm","noop","getNonDisabledOptions","container","querySelectorAll","useCombobox","options","form","popup","onClick","onFocus","onKeyDown","searchable","multiselect","isNegativeOneAllowed","loopable","disabled","visible","propVisible","setVisible","propSetVisible","defaultVisible","comboboxId","propComboboxId","comboboxRef","propComboboxRef","popupId","propPopupId","popupRef","propPopupRef","onFocusChange","extendKeyDown","getFocusableElements","getEnterDefaultFocusedIndex","getDefaultFocusedIndex","name","value","setValue","defaultValue","show","hide","popupRefCallback","focusLastRef","nodeRef","movementProps","movementContext","currentFocusIndex","activeDescendantId","setActiveDescendantId","ref","event","movementData","isPropagationStopped","key","stopPropagation","preventDefault","current","programmatic","includeDisabled","tabIndexBehavior","popupProps","undefined","id","role","focusLast","comboboxProps","getMenuProps","props","sheetProps","disableTransition","onEnter","onEntering","onEntered","onExited","onExiting","onExit","attemptScroll","activeOption","document","getElementById","scrollIntoView","block","onEnterOnce","focusables","index","option","element","anchor","width","fixedTo","onRequestClose","appearing","onExitOnce"],"mappings":"AAAA;AAEA,SASEA,WAAW,EACXC,MAAM,QACD,QAAQ;AAWf,SAASC,2BAA2B,QAAQ,6CAA6C;AACzF,SAASC,mBAAmB,QAAQ,8BAA8B;AAKlE,SAASC,sBAAsB,QAAQ,0CAA0C;AAOjF,SAASC,YAAY,QAAQ,qBAAqB;AAClD,SAASC,aAAa,QAAQ,sBAAsB;AACpD,SAASC,eAAe,QAAQ,wBAAwB;AACxD,SAASC,sBAAsB,QAAQ,aAAa;AAEpD,MAAMC,OAAO;AACX,aAAa;AACf;AAEA;;CAEC,GACD,OAAO,MAAMC,wBAAwB,CACnCC,YAC2B;WACxBA,UAAUC,gBAAgB,CAC3B;KAEH,CAAC;AAiQF;;CAEC,GACD,OAAO,SAASC,YAIdC,OAA6C;IAE7C,MAAM,EACJC,IAAI,EACJC,QAAQ,SAAS,EACjBC,UAAUR,IAAI,EACdS,OAAO,EACPC,SAAS,EACTC,UAAU,EACVC,WAAW,EACXC,oBAAoB,EACpBC,QAAQ,EACRC,QAAQ,EACRC,SAASC,WAAW,EACpBC,YAAYC,cAAc,EAC1BC,iBAAiB,KAAK,EACtBC,YAAYC,cAAc,EAC1BC,aAAaC,eAAe,EAC5BC,SAASC,WAAW,EACpBC,UAAUC,YAAY,EACtBC,gBAAgB7B,IAAI,EACpB8B,gBAAgB9B,IAAI,EACpB+B,uBAAuB9B,qBAAqB,EAC5C+B,2BAA2B,EAC3BC,sBAAsB,EACvB,GAAG5B;IAEJ,MAAM,CAACW,SAASE,WAAW,GAAGpB,gBAAgB;QAC5CoC,MAAM;QACNC,OAAOlB;QACPmB,UAAUjB;QACVkB,cAAcjB;IAChB;IACA,MAAMkB,OAAO/C,YAAY;QACvB2B,WAAW;IACb,GAAG;QAACA;KAAW;IACf,MAAMqB,OAAOhD,YAAY;QACvB2B,WAAW;IACb,GAAG;QAACA;KAAW;IAEf,MAAMO,UAAU7B,aAAa8B,aAAa;IAC1C,MAAML,aAAazB,aAAa0B,gBAAgB;IAChD,MAAM,CAACK,UAAUa,iBAAiB,GAAG3C,cAAc+B;IACnD,MAAMa,eAAejD,OAAO;IAC5B,MAAM,EACJkD,SAASnB,WAAW,EACpBoB,aAAa,EACbC,eAAe,EACfC,iBAAiB,EACjBC,kBAAkB,EAClBC,qBAAqB,EACtB,GAAGtD,4BAAwC;QAC1CuD,KAAKxB;QACLf;QACAC;QACAF,SAAQyC,KAAK;YACXzC,QAAQyC;YACR,IAAIlC,UAAU;gBACZ;YACF;YAEAuB;QACF;QACAR,eAAcoB,YAAY;YACxBpB,cAAc;gBACZ,GAAGoB,YAAY;gBACfZ;gBACAC;gBACAvB;gBACAyB;YACF;YACA,MAAM,EAAEQ,KAAK,EAAE,GAAGC;YAClB,IAAID,MAAME,oBAAoB,IAAI;gBAChC;YACF;YAEA,IAAInC,SAAS;gBACX,OAAQiC,MAAMG,GAAG;oBACf,KAAK;wBACH,+EAA+E;wBAC/Eb;wBACA;oBACF,KAAK;wBACHU,MAAMI,eAAe;wBACrBd;wBACA;oBACF,KAAK;wBACHU,MAAMK,cAAc;wBACpB;gBACJ;gBAEA,mEAAmE;gBACnE;YACF;YAEA,OAAQL,MAAMG,GAAG;gBACf,KAAK;gBACL,KAAK;oBACHH,MAAMK,cAAc;oBACpBL,MAAMI,eAAe;oBACrBZ,aAAac,OAAO,GAAGN,MAAMG,GAAG,KAAK;oBACrCd;oBACA;gBACF,KAAK;oBACHvC,uBAAuBkD,OAAO3C;oBAC9B;YACJ;QACF;QACAS;QACAD;QACAH;QACAkB;QACA2B,cAAc;QACdC,iBAAiB;QACjBC,kBAAkB;QAClB3B,sBAAqB7B,SAAS,EAAEsD,YAAY;YAC1C,MAAMjD,QAAQoB,SAAS4B,OAAO;YAC9B,IAAI,CAAChD,OAAO;gBACV,OAAO,EAAE;YACX;YAEA,OAAOwB,qBAAqBxB,SAASL,WAAWsD;QAClD;QACA3C;QACAoB;IACF;IAEA,MAAM0B,aAAgD;QACpD,wBAAwB/C,eAAegD;QACvCC,IAAIpC;QACJuB,KAAKR;QACLsB,MAAMvD;IACR;IAEA,OAAO;QACL+B;QACAC;QACAvB;QACAE;QACA6C,WAAWtB;QACXd;QACAgC;QACApC;QACAyC,eAAe;YACb,GAAGrB,aAAa;YAChB,iBAAiBlB;YACjB,iBAAiBV,YAAY6C;YAC7B,iBAAiB5C;YACjB,iBAAiBT;YACjBsD,IAAIxC;YACJyC,MAAM;QACR;QACAnB;QACAC;QACAC;QACAC;QACAC;QACAkB,cAAaC,QAAQ,CAAC,CAAC;YACrB,MAAM,EACJC,UAAU,EACVC,iBAAiB,EACjBC,OAAO,EACPC,UAAU,EACVC,YAAYvE,IAAI,EAChBwE,QAAQ,EACRC,SAAS,EACTC,MAAM,EACP,GAAGR;YAEJ,sEAAsE;YACtE,wEAAwE;YACxE,sEAAsE;YACtE,qEAAqE;YACrE,uDAAuD;YACvD,MAAMS,gBAAgB;gBACpB,MAAMC,eAAeC,SAASC,cAAc,CAAChC;gBAC7C,IAAI8B,cAAc;oBAChBA,aAAaG,cAAc,CAAC;wBAAEC,OAAO;oBAAU;gBACjD;YACF;YACA,MAAMC,cAAc;gBAClB,MAAM1E,QAAQoB,SAAS4B,OAAO;gBAC9B,IAAI,CAAChD,OAAO;oBACVoE;oBACA;gBACF;gBAEA,MAAMO,aAAanD,qBAAqBxB,OAAO;gBAC/C,MAAM4E,QAAQnD,4BAA4B;oBACxC+B,WAAWtB,aAAac,OAAO;oBAC/B2B;oBACArC,mBAAmBA,kBAAkBU,OAAO;gBAC9C;gBACAd,aAAac,OAAO,GAAG;gBACvBV,kBAAkBU,OAAO,GAAG4B;gBAE5B,MAAMC,SAASF,UAAU,CAACC,MAAM;gBAChC,IAAI,CAACC,QAAQ;oBACX;gBACF;gBAEAvD,cAAc;oBACZsD;oBACAE,SAASD;gBACX;gBAEAA,OAAOL,cAAc,CAAC;oBAAEC,OAAO;gBAAU;gBACzCjC,sBAAsBqC,OAAOvB,EAAE,IAAI;YACrC;YAEA,OAAO;gBACLyB,QAAQ5F;gBACR6F,OAAO;gBACPC,SAASjE;gBACT,GAAG2C,KAAK;gBACR,GAAGP,UAAU;gBACb3C;gBACAyE,gBAAgBlD;gBAChB,GAAG5C,uBAAuB;oBACxByE;oBACAC;oBACAE,WAAW,CAACmB;wBACVnB,UAAUmB;wBACVf;oBACF;oBACAL;oBACAW;oBACAP;oBACAD;oBACAD;oBACAmB,YAAY;wBACV,uEAAuE;wBACvE,kEAAkE;wBAClE,SAAS;wBACT9C,kBAAkBU,OAAO,GAAG,CAAC;wBAC7BR,sBAAsB;oBACxB;gBACF,EAAE;gBACFoB,YAAY;oBACV,GAAGA,UAAU;oBACb,GAAGxE,uBAAuB;wBACxB,GAAGwE,UAAU;wBACbc;wBACAb,mBACED,YAAYC,qBAAqBA;oBACrC,EAAE;gBACJ;YACF;QACF;IACF;AACF"}
@@ -1,5 +1,6 @@
1
1
  "use client";
2
2
  import { useCallback, useRef, useState } from "react";
3
+ import { useIsomorphicLayoutEffect } from "../useIsomorphicLayoutEffect.js";
3
4
  import { withinRange } from "../utils/withinRange.js";
4
5
  import { useFormReset } from "./useFormReset.js";
5
6
  import { useTextField } from "./useTextField.js";
@@ -74,6 +75,19 @@ const noop = ()=>{
74
75
  }
75
76
  }
76
77
  });
78
+ const { error, errorMessage } = remaining;
79
+ const prevState = useRef({
80
+ error,
81
+ errorMessage,
82
+ value: number
83
+ });
84
+ useIsomorphicLayoutEffect(()=>{
85
+ prevState.current = {
86
+ error,
87
+ errorMessage,
88
+ value: number
89
+ };
90
+ });
77
91
  const reset = useCallback(()=>{
78
92
  resetTextField();
79
93
  setNumber(initial.current);
@@ -81,25 +95,8 @@ const noop = ()=>{
81
95
  resetTextField
82
96
  ]);
83
97
  const setState = useCallback((nextState)=>{
84
- if (typeof nextState === "function") {
85
- setNumber((prevNumber)=>{
86
- let nextNumber = prevNumber;
87
- setTextFieldState((prevState)=>{
88
- const updated = nextState({
89
- ...prevState,
90
- value: prevNumber
91
- });
92
- nextNumber = updated.value;
93
- return {
94
- ...updated,
95
- value: `${nextNumber ?? ""}`
96
- };
97
- });
98
- return nextNumber;
99
- });
100
- return;
101
- }
102
- const { value, error, errorMessage } = nextState;
98
+ const resolvedNextState = typeof nextState === "function" ? nextState(prevState.current) : nextState;
99
+ const { value, error, errorMessage } = resolvedNextState;
103
100
  setNumber(value);
104
101
  setTextFieldState({
105
102
  value: `${value ?? ""}`,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/useNumberField.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { withinRange } from \"../utils/withinRange.js\";\nimport { useFormReset } from \"./useFormReset.js\";\nimport {\n type ProvidedTextFieldMessageProps,\n type ProvidedTextFieldProps,\n type TextFieldHookOptions,\n type TextFieldHookState,\n type TextFieldImplementation,\n type ValidatedTextFieldImplementation,\n useTextField,\n} from \"./useTextField.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/** @since 2.5.0 */\nexport interface NumberFieldConstraints {\n /**\n * An optional min value for the number field.\n */\n min?: number;\n\n /**\n * An optional max value for the number field.\n */\n max?: number;\n\n /**\n * An optional step amount to use.\n *\n * Note: The `min` and `max` values must be divisible by this value when any\n * are defined.\n */\n step?: number;\n}\n\n/**\n * @since 2.5.0\n * @since 6.0.0\n * - Removed `updateOnChange` in favor of `updateValue`\n * - Renamed `fixOnBlur` to `updateValueOnBlur`\n */\nexport interface NumberFieldHookOptions\n extends Omit<TextFieldHookOptions, \"defaultValue\" | \"isNumber\">,\n NumberFieldConstraints {\n /**\n * @defaultValue `undefined`\n */\n defaultValue?: UseStateInitializer<number>;\n\n /**\n * This controls the behavior for the `value` returned by this hook. If you\n * need access to the current value immediately as the user types to update\n * other components, keep this as the default of `\"change\"`. Otherwise, set\n * this to `\"blur\"`.\n *\n * @example Deferring Updates on Blur\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * defaultValue: 0,\n * updateValue: \"blur\",\n * });\n *\n * const result = useMemo(() => someExpensiveComputation(value), [value]);\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @defaultValue `\"change\"`\n */\n updateValue?: \"blur\" | \"change\";\n\n /**\n * This option is used to update the `number` value and text field value to be\n * within the `min` and `max` range or just format the text field value when\n * the input is blurred. This update will only be applied if the text field\n * contains a valid number. Using `min = 0` and `max = 10`:\n *\n * | text value | updated value |\n * | ---------- | ------------- |\n * | 000001 | 1 |\n * | -1 | 0 |\n * | 20 | 10 |\n * | -12 | 0 |\n * | --1 | --1 |\n * | fjdka | fjdka |\n *\n *\n * Set this to `false` if no changed should be applied and force the user to\n * fix any min/max errors manually and maintain weird formatting.\n *\n * @defaultValue `true`\n * @since 6.0.0 This was renamed from `fixOnBlur` and removed the\n * `\"min\"` and `\"max\"` behavior.\n */\n updateValueOnBlur?: boolean;\n}\n\n/** @since 6.0.0 */\nexport interface NumberFieldHookState\n extends Omit<TextFieldHookState, \"value\"> {\n value: number | undefined;\n}\n\n/** @since 2.5.6 */\nexport interface ProvidedNumberFieldProps\n extends ProvidedTextFieldProps,\n NumberFieldConstraints {\n type: \"number\";\n}\n\n/** @since 2.5.6 */\nexport interface ProvidedNumberFieldMessageProps\n extends ProvidedTextFieldMessageProps,\n NumberFieldConstraints {\n type: \"number\";\n}\n\n/** @since 6.0.0 */\nexport interface NumberFieldImplementation\n extends Omit<TextFieldImplementation, \"value\" | \"setState\"> {\n value: number | undefined;\n setState: UseStateSetter<NumberFieldHookState>;\n fieldProps: ProvidedNumberFieldProps;\n}\n\n/** @since 6.0.0 */\nexport interface NumberFieldWithMessageImplementation\n extends NumberFieldImplementation {\n fieldProps: ProvidedNumberFieldMessageProps;\n}\n\n/** @since 6.0.0 */\nexport interface ValidatedNumberFieldImplementation\n extends Omit<ValidatedTextFieldImplementation, \"value\" | \"setState\"> {\n value: number | undefined;\n setState: UseStateSetter<NumberFieldHookState>;\n fieldProps: ProvidedNumberFieldProps | ProvidedNumberFieldMessageProps;\n}\n\n/**\n * @example Enforce Number Value and No Error Messages\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * defaultValue: 0,\n * disableMessage: true,\n * });\n *\n * // this is safe since `value` will always be a number even if there is a\n * // validation error. since the min and max options were provided as well,\n * // number will be between that range as well.\n * const computed = value * 10;\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @see {@link useTextField}\n * @see {@link useNumberField} overrides for other examples.\n * ```\n */\nexport function useNumberField(\n options: NumberFieldHookOptions & {\n disableMessage: true;\n defaultValue: UseStateInitializer<number>;\n }\n): NumberFieldImplementation & {\n value: number;\n setState: UseStateSetter<NumberFieldHookState & { value: number }>;\n};\n\n/**\n * @example No Error Messages\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * disableMessage: true,\n * });\n *\n * // `value` will be `undefined` until the user enters a valid value once\n * // there is a valid value, `value` will be a `number`. So this might cause\n * // `computed` to be `NaN | number`\n * //\n * // const computed = value * 10;\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @see {@link useTextField}\n * @see {@link useNumberField} overrides for other examples.\n */\nexport function useNumberField(\n options: NumberFieldHookOptions & { disableMessage: true }\n): NumberFieldImplementation;\n\n/**\n * @example Enforce Number Value\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * defaultValue: 0,\n * });\n *\n * // this is safe since `value` will always be a number even if there is a\n * // validation error. since the min and max options were provided as well,\n * // number will be between that range as well.\n * const computed = value * 10;\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @example Enforce Number Value and Deferring Updates\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * defaultValue: 0,\n * updateValue: \"blur\",\n * });\n *\n * // the `value` will only be updated whenever the `TextField` is blurred.\n * // This is helpful if the `value` is used in expensive computations or\n * // updates that do not need to be updated as the user types\n * const computed = value * 10;\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @see {@link useTextField}\n * @see {@link useNumberField} overrides for other examples.\n */\nexport function useNumberField(\n options: NumberFieldHookOptions & {\n defaultValue: UseStateInitializer<number>;\n }\n): NumberFieldWithMessageImplementation & {\n value: number;\n setState: UseStateSetter<NumberFieldHookState & { value: number }>;\n};\n\n/**\n * The `useNumberField` hook is used to control the state of a `TextField` or\n * `<input type=\"number\">`\n *\n * @example Default Implementation\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * name: \"someName\",\n * });\n *\n * // `value` will be `undefined` until the user enters a valid value once\n * // there is a valid value, `value` will be a `number`. So this might cause\n * // `computed` to be `NaN | number`\n * //\n * // const computed = value * 10;\n *\n * // whenever there is an error, an error message will be displayed below the\n * // `TextField`\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @example Adding Constraints\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * name: \"someName\",\n * min: 0,\n * max: 100,\n * step: 2,\n * required: true,\n * });\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation\n * @see {@link https://react-md.dev/components/text-field#number | Number TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-number-field | useNumberField Demos}\n * @see {@link useTextField}\n */\nexport function useNumberField(\n options: NumberFieldHookOptions\n): NumberFieldWithMessageImplementation;\n\n/**\n * @internal\n * @see {@link https://react-md.dev/components/text-field#number | Number TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-number-field | useNumberField Demos}\n * @see {@link useTextField}\n * @see {@link useNumberField} overrides for other examples.\n */\nexport function useNumberField(\n options: NumberFieldHookOptions\n): ValidatedNumberFieldImplementation {\n const {\n min,\n max,\n step,\n form,\n onBlur = noop,\n onChange = noop,\n updateValue = \"change\",\n updateValueOnBlur = true,\n disableReset,\n defaultValue,\n ...textOptions\n } = options;\n\n const [number, setNumber] = useState(defaultValue);\n const initial = useRef(number);\n const {\n value: _value,\n reset: resetTextField,\n fieldRef,\n fieldProps,\n setState: setTextFieldState,\n ...remaining\n } = useTextField({\n ...textOptions,\n isNumber: true,\n defaultValue: `${number ?? \"\"}`,\n disableReset: true,\n onBlur(event) {\n onBlur(event);\n if (event.isPropagationStopped()) {\n return;\n }\n\n const input = event.currentTarget;\n input.setCustomValidity(\"\");\n input.checkValidity();\n if (\n !updateValueOnBlur ||\n // do nothing else since it's a weird value like: `\"--0\"` which causes\n // the value to be `\"\"` and `numberAsValue` to be `NaN`\n input.validity.badInput\n ) {\n return;\n }\n\n let value = input.valueAsNumber;\n if (input.value === \"\" && typeof initial.current === \"number\") {\n value = min ?? initial.current;\n }\n\n // can't have both rangeUnderflow and rangeOverflow at the same time, so\n // it's \"safe\" to always provide both\n value = withinRange({ min, max, value });\n if (!Number.isNaN(value)) {\n setNumber(value);\n input.value = `${value}`;\n } else if (typeof initial.current === \"undefined\") {\n setNumber(undefined);\n }\n },\n onChange(event) {\n onChange(event);\n if (event.isPropagationStopped() || updateValue === \"blur\") {\n return;\n }\n\n const input = event.currentTarget;\n input.checkValidity();\n const value = withinRange({\n min,\n max,\n value: event.currentTarget.valueAsNumber,\n });\n if (\n !input.validity.valid &&\n !input.validity.rangeUnderflow &&\n !input.validity.rangeOverflow\n ) {\n return;\n }\n\n if (!Number.isNaN(value)) {\n setNumber(value);\n } else if (initial.current === undefined) {\n setNumber(undefined);\n }\n },\n });\n\n const reset = useCallback(() => {\n resetTextField();\n setNumber(initial.current);\n }, [resetTextField]);\n const setState = useCallback<UseStateSetter<NumberFieldHookState>>(\n (nextState) => {\n if (typeof nextState === \"function\") {\n setNumber((prevNumber) => {\n let nextNumber: number | undefined = prevNumber;\n setTextFieldState((prevState) => {\n const updated = nextState({\n ...prevState,\n value: prevNumber,\n });\n\n nextNumber = updated.value;\n\n return {\n ...updated,\n value: `${nextNumber ?? \"\"}`,\n };\n });\n\n return nextNumber;\n });\n return;\n }\n\n const { value, error, errorMessage } = nextState;\n setNumber(value);\n setTextFieldState({\n value: `${value ?? \"\"}`,\n error,\n errorMessage,\n });\n },\n [setTextFieldState]\n );\n\n useFormReset({\n form,\n elementRef: fieldRef,\n onReset: disableReset ? undefined : reset,\n });\n\n return {\n ...remaining,\n reset,\n value: number,\n setState,\n fieldRef,\n fieldProps: {\n ...fieldProps,\n min,\n max,\n step,\n type: \"number\",\n },\n };\n}\n"],"names":["useCallback","useRef","useState","withinRange","useFormReset","useTextField","noop","useNumberField","options","min","max","step","form","onBlur","onChange","updateValue","updateValueOnBlur","disableReset","defaultValue","textOptions","number","setNumber","initial","value","_value","reset","resetTextField","fieldRef","fieldProps","setState","setTextFieldState","remaining","isNumber","event","isPropagationStopped","input","currentTarget","setCustomValidity","checkValidity","validity","badInput","valueAsNumber","current","Number","isNaN","undefined","valid","rangeUnderflow","rangeOverflow","nextState","prevNumber","nextNumber","prevState","updated","error","errorMessage","elementRef","onReset","type"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/form/useNumberField.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useRef, useState } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect.js\";\nimport { withinRange } from \"../utils/withinRange.js\";\nimport { useFormReset } from \"./useFormReset.js\";\nimport {\n type ProvidedTextFieldMessageProps,\n type ProvidedTextFieldProps,\n type TextFieldHookOptions,\n type TextFieldHookState,\n type TextFieldImplementation,\n type ValidatedTextFieldImplementation,\n useTextField,\n} from \"./useTextField.js\";\n\nconst noop = (): void => {\n // do nothing\n};\n\n/** @since 2.5.0 */\nexport interface NumberFieldConstraints {\n /**\n * An optional min value for the number field.\n */\n min?: number;\n\n /**\n * An optional max value for the number field.\n */\n max?: number;\n\n /**\n * An optional step amount to use.\n *\n * Note: The `min` and `max` values must be divisible by this value when any\n * are defined.\n */\n step?: number;\n}\n\n/**\n * @since 2.5.0\n * @since 6.0.0\n * - Removed `updateOnChange` in favor of `updateValue`\n * - Renamed `fixOnBlur` to `updateValueOnBlur`\n */\nexport interface NumberFieldHookOptions\n extends\n Omit<TextFieldHookOptions, \"defaultValue\" | \"isNumber\">,\n NumberFieldConstraints {\n /**\n * @defaultValue `undefined`\n */\n defaultValue?: UseStateInitializer<number>;\n\n /**\n * This controls the behavior for the `value` returned by this hook. If you\n * need access to the current value immediately as the user types to update\n * other components, keep this as the default of `\"change\"`. Otherwise, set\n * this to `\"blur\"`.\n *\n * @example Deferring Updates on Blur\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * defaultValue: 0,\n * updateValue: \"blur\",\n * });\n *\n * const result = useMemo(() => someExpensiveComputation(value), [value]);\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @defaultValue `\"change\"`\n */\n updateValue?: \"blur\" | \"change\";\n\n /**\n * This option is used to update the `number` value and text field value to be\n * within the `min` and `max` range or just format the text field value when\n * the input is blurred. This update will only be applied if the text field\n * contains a valid number. Using `min = 0` and `max = 10`:\n *\n * | text value | updated value |\n * | ---------- | ------------- |\n * | 000001 | 1 |\n * | -1 | 0 |\n * | 20 | 10 |\n * | -12 | 0 |\n * | --1 | --1 |\n * | fjdka | fjdka |\n *\n *\n * Set this to `false` if no changed should be applied and force the user to\n * fix any min/max errors manually and maintain weird formatting.\n *\n * @defaultValue `true`\n * @since 6.0.0 This was renamed from `fixOnBlur` and removed the\n * `\"min\"` and `\"max\"` behavior.\n */\n updateValueOnBlur?: boolean;\n}\n\n/** @since 6.0.0 */\nexport interface NumberFieldHookState extends Omit<\n TextFieldHookState,\n \"value\"\n> {\n value: number | undefined;\n}\n\n/** @since 2.5.6 */\nexport interface ProvidedNumberFieldProps\n extends ProvidedTextFieldProps, NumberFieldConstraints {\n type: \"number\";\n}\n\n/** @since 2.5.6 */\nexport interface ProvidedNumberFieldMessageProps\n extends ProvidedTextFieldMessageProps, NumberFieldConstraints {\n type: \"number\";\n}\n\n/** @since 6.0.0 */\nexport interface NumberFieldImplementation extends Omit<\n TextFieldImplementation,\n \"value\" | \"setState\"\n> {\n value: number | undefined;\n setState: UseStateSetter<NumberFieldHookState>;\n fieldProps: ProvidedNumberFieldProps;\n}\n\n/** @since 6.0.0 */\nexport interface NumberFieldWithMessageImplementation extends NumberFieldImplementation {\n fieldProps: ProvidedNumberFieldMessageProps;\n}\n\n/** @since 6.0.0 */\nexport interface ValidatedNumberFieldImplementation extends Omit<\n ValidatedTextFieldImplementation,\n \"value\" | \"setState\"\n> {\n value: number | undefined;\n setState: UseStateSetter<NumberFieldHookState>;\n fieldProps: ProvidedNumberFieldProps | ProvidedNumberFieldMessageProps;\n}\n\n/**\n * @example Enforce Number Value and No Error Messages\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * defaultValue: 0,\n * disableMessage: true,\n * });\n *\n * // this is safe since `value` will always be a number even if there is a\n * // validation error. since the min and max options were provided as well,\n * // number will be between that range as well.\n * const computed = value * 10;\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @see {@link useTextField}\n * @see {@link useNumberField} overrides for other examples.\n * ```\n */\nexport function useNumberField(\n options: NumberFieldHookOptions & {\n disableMessage: true;\n defaultValue: UseStateInitializer<number>;\n }\n): NumberFieldImplementation & {\n value: number;\n setState: UseStateSetter<NumberFieldHookState & { value: number }>;\n};\n\n/**\n * @example No Error Messages\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * disableMessage: true,\n * });\n *\n * // `value` will be `undefined` until the user enters a valid value once\n * // there is a valid value, `value` will be a `number`. So this might cause\n * // `computed` to be `NaN | number`\n * //\n * // const computed = value * 10;\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @see {@link useTextField}\n * @see {@link useNumberField} overrides for other examples.\n */\nexport function useNumberField(\n options: NumberFieldHookOptions & { disableMessage: true }\n): NumberFieldImplementation;\n\n/**\n * @example Enforce Number Value\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * defaultValue: 0,\n * });\n *\n * // this is safe since `value` will always be a number even if there is a\n * // validation error. since the min and max options were provided as well,\n * // number will be between that range as well.\n * const computed = value * 10;\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @example Enforce Number Value and Deferring Updates\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * min: 0,\n * max: 100,\n * name: \"someName\",\n * defaultValue: 0,\n * updateValue: \"blur\",\n * });\n *\n * // the `value` will only be updated whenever the `TextField` is blurred.\n * // This is helpful if the `value` is used in expensive computations or\n * // updates that do not need to be updated as the user types\n * const computed = value * 10;\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @see {@link useTextField}\n * @see {@link useNumberField} overrides for other examples.\n */\nexport function useNumberField(\n options: NumberFieldHookOptions & {\n defaultValue: UseStateInitializer<number>;\n }\n): NumberFieldWithMessageImplementation & {\n value: number;\n setState: UseStateSetter<NumberFieldHookState & { value: number }>;\n};\n\n/**\n * The `useNumberField` hook is used to control the state of a `TextField` or\n * `<input type=\"number\">`\n *\n * @example Default Implementation\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * name: \"someName\",\n * });\n *\n * // `value` will be `undefined` until the user enters a valid value once\n * // there is a valid value, `value` will be a `number`. So this might cause\n * // `computed` to be `NaN | number`\n * //\n * // const computed = value * 10;\n *\n * // whenever there is an error, an error message will be displayed below the\n * // `TextField`\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @example Adding Constraints\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useNumberField } from \"@react-md/core/form/useNumberField\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { fieldProps, value } = useNumberField({\n * name: \"someName\",\n * min: 0,\n * max: 100,\n * step: 2,\n * required: true,\n * });\n *\n * return <TextField {...fieldProps} label=\"Label\" />;\n * }\n * ```\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation\n * @see {@link https://react-md.dev/components/text-field#number | Number TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-number-field | useNumberField Demos}\n * @see {@link useTextField}\n */\nexport function useNumberField(\n options: NumberFieldHookOptions\n): NumberFieldWithMessageImplementation;\n\n/**\n * @internal\n * @see {@link https://react-md.dev/components/text-field#number | Number TextField Demos}\n * @see {@link https://react-md.dev/hooks/use-number-field | useNumberField Demos}\n * @see {@link useTextField}\n * @see {@link useNumberField} overrides for other examples.\n */\nexport function useNumberField(\n options: NumberFieldHookOptions\n): ValidatedNumberFieldImplementation {\n const {\n min,\n max,\n step,\n form,\n onBlur = noop,\n onChange = noop,\n updateValue = \"change\",\n updateValueOnBlur = true,\n disableReset,\n defaultValue,\n ...textOptions\n } = options;\n\n const [number, setNumber] = useState(defaultValue);\n const initial = useRef(number);\n const {\n value: _value,\n reset: resetTextField,\n fieldRef,\n fieldProps,\n setState: setTextFieldState,\n ...remaining\n } = useTextField({\n ...textOptions,\n isNumber: true,\n defaultValue: `${number ?? \"\"}`,\n disableReset: true,\n onBlur(event) {\n onBlur(event);\n if (event.isPropagationStopped()) {\n return;\n }\n\n const input = event.currentTarget;\n input.setCustomValidity(\"\");\n input.checkValidity();\n if (\n !updateValueOnBlur ||\n // do nothing else since it's a weird value like: `\"--0\"` which causes\n // the value to be `\"\"` and `numberAsValue` to be `NaN`\n input.validity.badInput\n ) {\n return;\n }\n\n let value = input.valueAsNumber;\n if (input.value === \"\" && typeof initial.current === \"number\") {\n value = min ?? initial.current;\n }\n\n // can't have both rangeUnderflow and rangeOverflow at the same time, so\n // it's \"safe\" to always provide both\n value = withinRange({ min, max, value });\n if (!Number.isNaN(value)) {\n setNumber(value);\n input.value = `${value}`;\n } else if (typeof initial.current === \"undefined\") {\n setNumber(undefined);\n }\n },\n onChange(event) {\n onChange(event);\n if (event.isPropagationStopped() || updateValue === \"blur\") {\n return;\n }\n\n const input = event.currentTarget;\n input.checkValidity();\n const value = withinRange({\n min,\n max,\n value: event.currentTarget.valueAsNumber,\n });\n if (\n !input.validity.valid &&\n !input.validity.rangeUnderflow &&\n !input.validity.rangeOverflow\n ) {\n return;\n }\n\n if (!Number.isNaN(value)) {\n setNumber(value);\n } else if (initial.current === undefined) {\n setNumber(undefined);\n }\n },\n });\n\n const { error, errorMessage } = remaining;\n const prevState = useRef({\n error,\n errorMessage,\n value: number,\n } satisfies NumberFieldHookState);\n useIsomorphicLayoutEffect(() => {\n prevState.current = {\n error,\n errorMessage,\n value: number,\n };\n });\n const reset = useCallback(() => {\n resetTextField();\n setNumber(initial.current);\n }, [resetTextField]);\n const setState = useCallback<UseStateSetter<NumberFieldHookState>>(\n (nextState) => {\n const resolvedNextState =\n typeof nextState === \"function\"\n ? nextState(prevState.current)\n : nextState;\n\n const { value, error, errorMessage } = resolvedNextState;\n setNumber(value);\n setTextFieldState({\n value: `${value ?? \"\"}`,\n error,\n errorMessage,\n });\n },\n [setTextFieldState]\n );\n\n useFormReset({\n form,\n elementRef: fieldRef,\n onReset: disableReset ? undefined : reset,\n });\n\n return {\n ...remaining,\n reset,\n value: number,\n setState,\n fieldRef,\n fieldProps: {\n ...fieldProps,\n min,\n max,\n step,\n type: \"number\",\n },\n };\n}\n"],"names":["useCallback","useRef","useState","useIsomorphicLayoutEffect","withinRange","useFormReset","useTextField","noop","useNumberField","options","min","max","step","form","onBlur","onChange","updateValue","updateValueOnBlur","disableReset","defaultValue","textOptions","number","setNumber","initial","value","_value","reset","resetTextField","fieldRef","fieldProps","setState","setTextFieldState","remaining","isNumber","event","isPropagationStopped","input","currentTarget","setCustomValidity","checkValidity","validity","badInput","valueAsNumber","current","Number","isNaN","undefined","valid","rangeUnderflow","rangeOverflow","error","errorMessage","prevState","nextState","resolvedNextState","elementRef","onReset","type"],"mappings":"AAAA;AAEA,SAASA,WAAW,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAGtD,SAASC,yBAAyB,QAAQ,kCAAkC;AAC5E,SAASC,WAAW,QAAQ,0BAA0B;AACtD,SAASC,YAAY,QAAQ,oBAAoB;AACjD,SAOEC,YAAY,QACP,oBAAoB;AAE3B,MAAMC,OAAO;AACX,aAAa;AACf;AAsUA;;;;;;CAMC,GACD,OAAO,SAASC,eACdC,OAA+B;IAE/B,MAAM,EACJC,GAAG,EACHC,GAAG,EACHC,IAAI,EACJC,IAAI,EACJC,SAASP,IAAI,EACbQ,WAAWR,IAAI,EACfS,cAAc,QAAQ,EACtBC,oBAAoB,IAAI,EACxBC,YAAY,EACZC,YAAY,EACZ,GAAGC,aACJ,GAAGX;IAEJ,MAAM,CAACY,QAAQC,UAAU,GAAGpB,SAASiB;IACrC,MAAMI,UAAUtB,OAAOoB;IACvB,MAAM,EACJG,OAAOC,MAAM,EACbC,OAAOC,cAAc,EACrBC,QAAQ,EACRC,UAAU,EACVC,UAAUC,iBAAiB,EAC3B,GAAGC,WACJ,GAAG1B,aAAa;QACf,GAAGc,WAAW;QACda,UAAU;QACVd,cAAc,GAAGE,UAAU,IAAI;QAC/BH,cAAc;QACdJ,QAAOoB,KAAK;YACVpB,OAAOoB;YACP,IAAIA,MAAMC,oBAAoB,IAAI;gBAChC;YACF;YAEA,MAAMC,QAAQF,MAAMG,aAAa;YACjCD,MAAME,iBAAiB,CAAC;YACxBF,MAAMG,aAAa;YACnB,IACE,CAACtB,qBACD,sEAAsE;YACtE,uDAAuD;YACvDmB,MAAMI,QAAQ,CAACC,QAAQ,EACvB;gBACA;YACF;YAEA,IAAIjB,QAAQY,MAAMM,aAAa;YAC/B,IAAIN,MAAMZ,KAAK,KAAK,MAAM,OAAOD,QAAQoB,OAAO,KAAK,UAAU;gBAC7DnB,QAAQd,OAAOa,QAAQoB,OAAO;YAChC;YAEA,wEAAwE;YACxE,qCAAqC;YACrCnB,QAAQpB,YAAY;gBAAEM;gBAAKC;gBAAKa;YAAM;YACtC,IAAI,CAACoB,OAAOC,KAAK,CAACrB,QAAQ;gBACxBF,UAAUE;gBACVY,MAAMZ,KAAK,GAAG,GAAGA,OAAO;YAC1B,OAAO,IAAI,OAAOD,QAAQoB,OAAO,KAAK,aAAa;gBACjDrB,UAAUwB;YACZ;QACF;QACA/B,UAASmB,KAAK;YACZnB,SAASmB;YACT,IAAIA,MAAMC,oBAAoB,MAAMnB,gBAAgB,QAAQ;gBAC1D;YACF;YAEA,MAAMoB,QAAQF,MAAMG,aAAa;YACjCD,MAAMG,aAAa;YACnB,MAAMf,QAAQpB,YAAY;gBACxBM;gBACAC;gBACAa,OAAOU,MAAMG,aAAa,CAACK,aAAa;YAC1C;YACA,IACE,CAACN,MAAMI,QAAQ,CAACO,KAAK,IACrB,CAACX,MAAMI,QAAQ,CAACQ,cAAc,IAC9B,CAACZ,MAAMI,QAAQ,CAACS,aAAa,EAC7B;gBACA;YACF;YAEA,IAAI,CAACL,OAAOC,KAAK,CAACrB,QAAQ;gBACxBF,UAAUE;YACZ,OAAO,IAAID,QAAQoB,OAAO,KAAKG,WAAW;gBACxCxB,UAAUwB;YACZ;QACF;IACF;IAEA,MAAM,EAAEI,KAAK,EAAEC,YAAY,EAAE,GAAGnB;IAChC,MAAMoB,YAAYnD,OAAO;QACvBiD;QACAC;QACA3B,OAAOH;IACT;IACAlB,0BAA0B;QACxBiD,UAAUT,OAAO,GAAG;YAClBO;YACAC;YACA3B,OAAOH;QACT;IACF;IACA,MAAMK,QAAQ1B,YAAY;QACxB2B;QACAL,UAAUC,QAAQoB,OAAO;IAC3B,GAAG;QAAChB;KAAe;IACnB,MAAMG,WAAW9B,YACf,CAACqD;QACC,MAAMC,oBACJ,OAAOD,cAAc,aACjBA,UAAUD,UAAUT,OAAO,IAC3BU;QAEN,MAAM,EAAE7B,KAAK,EAAE0B,KAAK,EAAEC,YAAY,EAAE,GAAGG;QACvChC,UAAUE;QACVO,kBAAkB;YAChBP,OAAO,GAAGA,SAAS,IAAI;YACvB0B;YACAC;QACF;IACF,GACA;QAACpB;KAAkB;IAGrB1B,aAAa;QACXQ;QACA0C,YAAY3B;QACZ4B,SAAStC,eAAe4B,YAAYpB;IACtC;IAEA,OAAO;QACL,GAAGM,SAAS;QACZN;QACAF,OAAOH;QACPS;QACAF;QACAC,YAAY;YACV,GAAGA,UAAU;YACbnB;YACAC;YACAC;YACA6C,MAAM;QACR;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/useRangeSlider.ts"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { type SliderValueOptions } from \"./useSlider.js\";\n\n/**\n * @since 2.5.0\n * @since 6.0.0 Updated to use labeled tuple.\n */\nexport type RangeSliderValue = readonly [minValue: number, maxValue: number];\n\n/**\n * @since 6.0.0\n */\nexport interface RangeSliderState {\n rangeValue: RangeSliderValue;\n setRangeValue: UseStateSetter<RangeSliderValue>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface RangeSliderOptions extends SliderValueOptions {\n /** @defaultValue `[min, max]` */\n defaultValue?: UseStateInitializer<RangeSliderValue>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface RangeSliderImplementation\n extends Required<SliderValueOptions>,\n RangeSliderState {}\n\n/**\n * @example Range Slider Example\n * ```tsx\n * import { Fieldset } from \"@react-md/core/form/Fieldset\";\n * import { Form } from \"@react-md/core/form/Form\";\n * import { Legend } from \"@react-md/core/form/Legend\";\n * import { Slider } from \"@react-md/core/form/Slider\";\n * import { useRangeSlider } from \"@react-md/core/form/useRangeSlider\";\n * import type { ReactElement } from \"react\";\n * import { useId } from \"react\";\n *\n * function Example(): ReactElement {\n * const slider = useRangeSlider({\n * // these are the defaults and can be changed\n * min: 0,\n * max: 100,\n * step: 1,\n * defaultValue: [0, 100],\n * });\n *\n * // if you need access to the current value or manually change the value\n * // yourself.\n * const { rangeValue, setRangeValue } = slider;\n * const [minPrice, maxPrice] = rangeValue;\n *\n * return (\n * <Form>\n * <Fieldset>\n * <Legend>Price Range</Legend>\n * <Slider {...slider} />\n * </Fieldset>\n * </Form>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/slider | Slider Demos}\n * @see The `Slider` component for additional examples.\n * @since 2.5.0\n * @since 6.0.0 Now returns an object instead of an ordered tuple and only\n * return the `rangeValue` and `setRangeValue` instead of all the slider\n * functionality. In addition, the hook only accepts a single object argument.\n */\nexport function useRangeSlider(\n options: RangeSliderOptions = {}\n): RangeSliderImplementation {\n const { min = 0, max = 100, step = 1, defaultValue } = options;\n const [rangeValue, setRangeValue] = useState<RangeSliderValue>(\n defaultValue ?? [min, max]\n );\n\n return {\n min,\n max,\n step,\n rangeValue,\n setRangeValue,\n };\n}\n"],"names":["useState","useRangeSlider","options","min","max","step","defaultValue","rangeValue","setRangeValue"],"mappings":"AAAA;AAEA,SAASA,QAAQ,QAAQ,QAAQ;AAkCjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CC,GACD,OAAO,SAASC,eACdC,UAA8B,CAAC,CAAC;IAEhC,MAAM,EAAEC,MAAM,CAAC,EAAEC,MAAM,GAAG,EAAEC,OAAO,CAAC,EAAEC,YAAY,EAAE,GAAGJ;IACvD,MAAM,CAACK,YAAYC,cAAc,GAAGR,SAClCM,gBAAgB;QAACH;QAAKC;KAAI;IAG5B,OAAO;QACLD;QACAC;QACAC;QACAE;QACAC;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/form/useRangeSlider.ts"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { type SliderValueOptions } from \"./useSlider.js\";\n\n/**\n * @since 2.5.0\n * @since 6.0.0 Updated to use labeled tuple.\n */\nexport type RangeSliderValue = readonly [minValue: number, maxValue: number];\n\n/**\n * @since 6.0.0\n */\nexport interface RangeSliderState {\n rangeValue: RangeSliderValue;\n setRangeValue: UseStateSetter<RangeSliderValue>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface RangeSliderOptions extends SliderValueOptions {\n /** @defaultValue `[min, max]` */\n defaultValue?: UseStateInitializer<RangeSliderValue>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface RangeSliderImplementation\n extends Required<SliderValueOptions>, RangeSliderState {}\n\n/**\n * @example Range Slider Example\n * ```tsx\n * import { Fieldset } from \"@react-md/core/form/Fieldset\";\n * import { Form } from \"@react-md/core/form/Form\";\n * import { Legend } from \"@react-md/core/form/Legend\";\n * import { Slider } from \"@react-md/core/form/Slider\";\n * import { useRangeSlider } from \"@react-md/core/form/useRangeSlider\";\n * import type { ReactElement } from \"react\";\n * import { useId } from \"react\";\n *\n * function Example(): ReactElement {\n * const slider = useRangeSlider({\n * // these are the defaults and can be changed\n * min: 0,\n * max: 100,\n * step: 1,\n * defaultValue: [0, 100],\n * });\n *\n * // if you need access to the current value or manually change the value\n * // yourself.\n * const { rangeValue, setRangeValue } = slider;\n * const [minPrice, maxPrice] = rangeValue;\n *\n * return (\n * <Form>\n * <Fieldset>\n * <Legend>Price Range</Legend>\n * <Slider {...slider} />\n * </Fieldset>\n * </Form>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/slider | Slider Demos}\n * @see The `Slider` component for additional examples.\n * @since 2.5.0\n * @since 6.0.0 Now returns an object instead of an ordered tuple and only\n * return the `rangeValue` and `setRangeValue` instead of all the slider\n * functionality. In addition, the hook only accepts a single object argument.\n */\nexport function useRangeSlider(\n options: RangeSliderOptions = {}\n): RangeSliderImplementation {\n const { min = 0, max = 100, step = 1, defaultValue } = options;\n const [rangeValue, setRangeValue] = useState<RangeSliderValue>(\n defaultValue ?? [min, max]\n );\n\n return {\n min,\n max,\n step,\n rangeValue,\n setRangeValue,\n };\n}\n"],"names":["useState","useRangeSlider","options","min","max","step","defaultValue","rangeValue","setRangeValue"],"mappings":"AAAA;AAEA,SAASA,QAAQ,QAAQ,QAAQ;AAiCjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CC,GACD,OAAO,SAASC,eACdC,UAA8B,CAAC,CAAC;IAEhC,MAAM,EAAEC,MAAM,CAAC,EAAEC,MAAM,GAAG,EAAEC,OAAO,CAAC,EAAEC,YAAY,EAAE,GAAGJ;IACvD,MAAM,CAACK,YAAYC,cAAc,GAAGR,SAClCM,gBAAgB;QAACH;QAAKC;KAAI;IAG5B,OAAO;QACLD;QACAC;QACAC;QACAE;QACAC;IACF;AACF"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/form/useSlider.ts"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { getRangeDefaultValue } from \"../utils/getRangeDefaultValue.js\";\n\n/**\n * @since 2.5.0\n */\nexport interface SliderValueOptions {\n /**\n * The min value for the slider.\n *\n * @defaultValue `0`\n */\n min?: number;\n\n /**\n * The max value for the slider.\n *\n * @defaultValue `100`\n */\n max?: number;\n\n /**\n * A positive number representing the value to \"jump\" while incrementing or\n * decrementing the slider's value. This should normally stay as the default\n * value of `1`, but can also be decimal values if needed.\n *\n * @defaultValue `1`\n */\n step?: number;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface SliderState {\n value: number;\n setValue: UseStateSetter<number>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface SliderImplementation\n extends Required<SliderValueOptions>,\n SliderState {}\n\n/**\n * @since 6.0.0\n */\nexport interface SliderOptions extends SliderValueOptions {\n /** @defaultValue `(max - min ) / 2` */\n defaultValue?: UseStateInitializer<number>;\n}\n\n/**\n * @example Simple Example\n * ```tsx\n * import { Form } from \"@react-md/core/form/Form\";\n * import { Slider } from \"@react-md/core/form/Slider\";\n * import { useSlider } from \"@react-md/core/form/useSlider\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const slider = useSlider({\n * // these are the defaults and can be changed\n * min: 0,\n * max: 100,\n * step: 1,\n * defaultValue: 50,\n * });\n *\n * // if you need access to the current value or manually change the value\n * // yourself.\n * const { value, setValue } = slider;\n *\n * return (\n * <Form>\n * <Slider {...slider} aria-label=\"Volume\" />\n * </Form>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/slider | Slider Demos}\n * @see The `Slider` component for additional examples.\n * @since 2.5.0\n * @since 6.0.0 Now returns an object instead of an ordered tuple and only\n * return the `value` and `setValue` instead of all the slider functionality. In\n * addition, the hook only accepts a single object argument.\n */\nexport function useSlider(options: SliderOptions = {}): SliderImplementation {\n const { min = 0, max = 100, step = 1, defaultValue } = options;\n const [value, setValue] = useState(\n getRangeDefaultValue({\n min,\n max,\n step,\n defaultValue,\n })\n );\n\n return {\n min,\n max,\n step,\n value,\n setValue,\n };\n}\n"],"names":["useState","getRangeDefaultValue","useSlider","options","min","max","step","defaultValue","value","setValue"],"mappings":"AAAA;AAEA,SAASA,QAAQ,QAAQ,QAAQ;AAGjC,SAASC,oBAAoB,QAAQ,mCAAmC;AAqDxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCC,GACD,OAAO,SAASC,UAAUC,UAAyB,CAAC,CAAC;IACnD,MAAM,EAAEC,MAAM,CAAC,EAAEC,MAAM,GAAG,EAAEC,OAAO,CAAC,EAAEC,YAAY,EAAE,GAAGJ;IACvD,MAAM,CAACK,OAAOC,SAAS,GAAGT,SACxBC,qBAAqB;QACnBG;QACAC;QACAC;QACAC;IACF;IAGF,OAAO;QACLH;QACAC;QACAC;QACAE;QACAC;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/form/useSlider.ts"],"sourcesContent":["\"use client\";\n\nimport { useState } from \"react\";\n\nimport { type UseStateInitializer, type UseStateSetter } from \"../types.js\";\nimport { getRangeDefaultValue } from \"../utils/getRangeDefaultValue.js\";\n\n/**\n * @since 2.5.0\n */\nexport interface SliderValueOptions {\n /**\n * The min value for the slider.\n *\n * @defaultValue `0`\n */\n min?: number;\n\n /**\n * The max value for the slider.\n *\n * @defaultValue `100`\n */\n max?: number;\n\n /**\n * A positive number representing the value to \"jump\" while incrementing or\n * decrementing the slider's value. This should normally stay as the default\n * value of `1`, but can also be decimal values if needed.\n *\n * @defaultValue `1`\n */\n step?: number;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface SliderState {\n value: number;\n setValue: UseStateSetter<number>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface SliderImplementation\n extends Required<SliderValueOptions>, SliderState {}\n\n/**\n * @since 6.0.0\n */\nexport interface SliderOptions extends SliderValueOptions {\n /** @defaultValue `(max - min ) / 2` */\n defaultValue?: UseStateInitializer<number>;\n}\n\n/**\n * @example Simple Example\n * ```tsx\n * import { Form } from \"@react-md/core/form/Form\";\n * import { Slider } from \"@react-md/core/form/Slider\";\n * import { useSlider } from \"@react-md/core/form/useSlider\";\n * import type { ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const slider = useSlider({\n * // these are the defaults and can be changed\n * min: 0,\n * max: 100,\n * step: 1,\n * defaultValue: 50,\n * });\n *\n * // if you need access to the current value or manually change the value\n * // yourself.\n * const { value, setValue } = slider;\n *\n * return (\n * <Form>\n * <Slider {...slider} aria-label=\"Volume\" />\n * </Form>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/components/slider | Slider Demos}\n * @see The `Slider` component for additional examples.\n * @since 2.5.0\n * @since 6.0.0 Now returns an object instead of an ordered tuple and only\n * return the `value` and `setValue` instead of all the slider functionality. In\n * addition, the hook only accepts a single object argument.\n */\nexport function useSlider(options: SliderOptions = {}): SliderImplementation {\n const { min = 0, max = 100, step = 1, defaultValue } = options;\n const [value, setValue] = useState(\n getRangeDefaultValue({\n min,\n max,\n step,\n defaultValue,\n })\n );\n\n return {\n min,\n max,\n step,\n value,\n setValue,\n };\n}\n"],"names":["useState","getRangeDefaultValue","useSlider","options","min","max","step","defaultValue","value","setValue"],"mappings":"AAAA;AAEA,SAASA,QAAQ,QAAQ,QAAQ;AAGjC,SAASC,oBAAoB,QAAQ,mCAAmC;AAoDxE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmCC,GACD,OAAO,SAASC,UAAUC,UAAyB,CAAC,CAAC;IACnD,MAAM,EAAEC,MAAM,CAAC,EAAEC,MAAM,GAAG,EAAEC,OAAO,CAAC,EAAEC,YAAY,EAAE,GAAGJ;IACvD,MAAM,CAACK,OAAOC,SAAS,GAAGT,SACxBC,qBAAqB;QACnBG;QACAC;QACAC;QACAC;IACF;IAGF,OAAO;QACLH;QACAC;QACAC;QACAE;QACAC;IACF;AACF"}