@react-md/core 6.4.0 → 6.5.1

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 (431) hide show
  1. package/dist/_a11y.scss +3 -1
  2. package/dist/_box-shadows.scss +20 -12
  3. package/dist/_core.scss +1 -1
  4. package/dist/_utils.scss +26 -11
  5. package/dist/app-bar/_app-bar.scss +3 -3
  6. package/dist/autocomplete/AutocompleteChip.js +2 -2
  7. package/dist/autocomplete/AutocompleteChip.js.map +1 -1
  8. package/dist/autocomplete/AutocompleteListboxChildren.js +1 -1
  9. package/dist/autocomplete/AutocompleteListboxChildren.js.map +1 -1
  10. package/dist/autocomplete/_autocomplete.scss +20 -16
  11. package/dist/autocomplete/useAutocomplete.js +4 -4
  12. package/dist/autocomplete/useAutocomplete.js.map +1 -1
  13. package/dist/autocomplete/utils.js +3 -3
  14. package/dist/autocomplete/utils.js.map +1 -1
  15. package/dist/avatar/_avatar.scss +2 -1
  16. package/dist/box/styles.js +2 -2
  17. package/dist/box/styles.js.map +1 -1
  18. package/dist/button/AsyncButton.js +1 -1
  19. package/dist/button/AsyncButton.js.map +1 -1
  20. package/dist/button/_button.scss +9 -5
  21. package/dist/card/_card.scss +6 -6
  22. package/dist/chip/Chip.js +1 -1
  23. package/dist/chip/Chip.js.map +1 -1
  24. package/dist/chip/_chip.scss +6 -6
  25. package/dist/cssUtils.d.ts +11 -6
  26. package/dist/cssUtils.js.map +1 -1
  27. package/dist/datetime/useTimeField.js +1 -1
  28. package/dist/datetime/useTimeField.js.map +1 -1
  29. package/dist/delegateEvent.js +9 -9
  30. package/dist/delegateEvent.js.map +1 -1
  31. package/dist/dialog/_dialog.scss +6 -6
  32. package/dist/divider/_divider.scss +6 -2
  33. package/dist/draggable/useDraggable.js +4 -4
  34. package/dist/draggable/useDraggable.js.map +1 -1
  35. package/dist/draggable/utils.js +1 -1
  36. package/dist/draggable/utils.js.map +1 -1
  37. package/dist/expansion-panel/ExpansionPanel.js +1 -1
  38. package/dist/expansion-panel/ExpansionPanel.js.map +1 -1
  39. package/dist/expansion-panel/useExpansionPanels.js +1 -1
  40. package/dist/expansion-panel/useExpansionPanels.js.map +1 -1
  41. package/dist/files/FileInput.js +1 -1
  42. package/dist/files/FileInput.js.map +1 -1
  43. package/dist/files/createAcceptFromExtensions.d.ts +5 -0
  44. package/dist/files/createAcceptFromExtensions.js +15 -0
  45. package/dist/files/createAcceptFromExtensions.js.map +1 -0
  46. package/dist/files/useFileUpload.js +45 -41
  47. package/dist/files/useFileUpload.js.map +1 -1
  48. package/dist/files/utils.js +14 -10
  49. package/dist/files/utils.js.map +1 -1
  50. package/dist/files/validation.js +7 -8
  51. package/dist/files/validation.js.map +1 -1
  52. package/dist/focus/useFocusContainer.js +1 -1
  53. package/dist/focus/useFocusContainer.js.map +1 -1
  54. package/dist/focus/utils.js +12 -7
  55. package/dist/focus/utils.js.map +1 -1
  56. package/dist/form/InputToggleIcon.js +5 -1
  57. package/dist/form/InputToggleIcon.js.map +1 -1
  58. package/dist/form/NativeSelect.js +1 -1
  59. package/dist/form/NativeSelect.js.map +1 -1
  60. package/dist/form/Select.d.ts +24 -0
  61. package/dist/form/Select.js +19 -8
  62. package/dist/form/Select.js.map +1 -1
  63. package/dist/form/SelectedOption.d.ts +1 -2
  64. package/dist/form/SelectedOption.js +2 -2
  65. package/dist/form/SelectedOption.js.map +1 -1
  66. package/dist/form/_input-toggle.scss +6 -5
  67. package/dist/form/_label.scss +2 -2
  68. package/dist/form/_legend.scss +22 -13
  69. package/dist/form/_slider.scss +7 -5
  70. package/dist/form/_switch.scss +7 -5
  71. package/dist/form/_text-field.scss +13 -11
  72. package/dist/form/formConfig.js +1 -1
  73. package/dist/form/formConfig.js.map +1 -1
  74. package/dist/form/inputToggleStyles.js +7 -1
  75. package/dist/form/inputToggleStyles.js.map +1 -1
  76. package/dist/form/legendStyles.d.ts +1 -1
  77. package/dist/form/legendStyles.js.map +1 -1
  78. package/dist/form/selectUtils.js +2 -2
  79. package/dist/form/selectUtils.js.map +1 -1
  80. package/dist/form/useCombobox.js +1 -0
  81. package/dist/form/useCombobox.js.map +1 -1
  82. package/dist/form/useFormReset.js +2 -2
  83. package/dist/form/useFormReset.js.map +1 -1
  84. package/dist/form/useNumberField.js +1 -1
  85. package/dist/form/useNumberField.js.map +1 -1
  86. package/dist/form/useResizingTextArea.js +4 -4
  87. package/dist/form/useResizingTextArea.js.map +1 -1
  88. package/dist/form/useSelectCombobox.js +1 -1
  89. package/dist/form/useSelectCombobox.js.map +1 -1
  90. package/dist/form/validation.js +1 -1
  91. package/dist/form/validation.js.map +1 -1
  92. package/dist/hoverMode/useHoverMode.js +8 -8
  93. package/dist/hoverMode/useHoverMode.js.map +1 -1
  94. package/dist/hoverMode/useHoverModeProvider.js +3 -3
  95. package/dist/hoverMode/useHoverModeProvider.js.map +1 -1
  96. package/dist/icon/config.js +3 -3
  97. package/dist/icon/config.js.map +1 -1
  98. package/dist/icon/materialConfig.js +1 -1
  99. package/dist/icon/materialConfig.js.map +1 -1
  100. package/dist/interaction/UserInteractionModeProvider.js +11 -10
  101. package/dist/interaction/UserInteractionModeProvider.js.map +1 -1
  102. package/dist/interaction/_interaction.scss +5 -3
  103. package/dist/interaction/utils.js +7 -3
  104. package/dist/interaction/utils.js.map +1 -1
  105. package/dist/layout/useExpandableLayout.js +3 -4
  106. package/dist/layout/useExpandableLayout.js.map +1 -1
  107. package/dist/layout/useMainTabIndex.js +1 -1
  108. package/dist/layout/useMainTabIndex.js.map +1 -1
  109. package/dist/list/ListItem.js +1 -1
  110. package/dist/list/ListItem.js.map +1 -1
  111. package/dist/media-queries/AppSizeProvider.js +1 -1
  112. package/dist/media-queries/AppSizeProvider.js.map +1 -1
  113. package/dist/media-queries/config.js +2 -2
  114. package/dist/media-queries/config.js.map +1 -1
  115. package/dist/media-queries/useMediaQuery.js +3 -3
  116. package/dist/media-queries/useMediaQuery.js.map +1 -1
  117. package/dist/menu/Menu.js +4 -4
  118. package/dist/menu/Menu.js.map +1 -1
  119. package/dist/menu/MenuItemButton.js +1 -1
  120. package/dist/menu/MenuItemButton.js.map +1 -1
  121. package/dist/menu/MenuItemFileInput.js +1 -1
  122. package/dist/menu/MenuItemFileInput.js.map +1 -1
  123. package/dist/menu/MenuWidget.js +2 -2
  124. package/dist/menu/MenuWidget.js.map +1 -1
  125. package/dist/movement/findMatchIndex.js +2 -2
  126. package/dist/movement/findMatchIndex.js.map +1 -1
  127. package/dist/movement/useKeyboardMovementProvider.js +2 -2
  128. package/dist/movement/useKeyboardMovementProvider.js.map +1 -1
  129. package/dist/movement/utils.js +12 -10
  130. package/dist/movement/utils.js.map +1 -1
  131. package/dist/navigation/getTableOfContentsHeadings.js +4 -3
  132. package/dist/navigation/getTableOfContentsHeadings.js.map +1 -1
  133. package/dist/navigation/useActiveHeadingId.js +9 -9
  134. package/dist/navigation/useActiveHeadingId.js.map +1 -1
  135. package/dist/navigation/useTableOfContentsHeadings.js +1 -1
  136. package/dist/navigation/useTableOfContentsHeadings.js.map +1 -1
  137. package/dist/navigation/utils.js +6 -5
  138. package/dist/navigation/utils.js.map +1 -1
  139. package/dist/portal/PortalContainerProvider.js +5 -3
  140. package/dist/portal/PortalContainerProvider.js.map +1 -1
  141. package/dist/positioning/getFixedPosition.js +2 -4
  142. package/dist/positioning/getFixedPosition.js.map +1 -1
  143. package/dist/positioning/useFixedPositioning.js +2 -2
  144. package/dist/positioning/useFixedPositioning.js.map +1 -1
  145. package/dist/positioning/utils.js +3 -3
  146. package/dist/positioning/utils.js.map +1 -1
  147. package/dist/scroll/getScrollbarWidth.js +4 -4
  148. package/dist/scroll/getScrollbarWidth.js.map +1 -1
  149. package/dist/searching/fuzzy.js +3 -2
  150. package/dist/searching/fuzzy.js.map +1 -1
  151. package/dist/searching/toSearchQuery.js +1 -1
  152. package/dist/searching/toSearchQuery.js.map +1 -1
  153. package/dist/searching/utils.js +1 -1
  154. package/dist/searching/utils.js.map +1 -1
  155. package/dist/snackbar/Toast.js +1 -1
  156. package/dist/snackbar/Toast.js.map +1 -1
  157. package/dist/snackbar/ToastContent.js +2 -2
  158. package/dist/snackbar/ToastContent.js.map +1 -1
  159. package/dist/snackbar/ToastManager.d.ts +1 -1
  160. package/dist/snackbar/ToastManager.js +11 -11
  161. package/dist/snackbar/ToastManager.js.map +1 -1
  162. package/dist/snackbar/_snackbar.scss +3 -3
  163. package/dist/spinbutton/useSpinButton.js +1 -1
  164. package/dist/spinbutton/useSpinButton.js.map +1 -1
  165. package/dist/spinbutton/utils/deselectNode.js +1 -1
  166. package/dist/spinbutton/utils/deselectNode.js.map +1 -1
  167. package/dist/spinbutton/utils/resolveInputEvent.js +1 -1
  168. package/dist/spinbutton/utils/resolveInputEvent.js.map +1 -1
  169. package/dist/spinbutton/utils/selectNode.js +1 -1
  170. package/dist/spinbutton/utils/selectNode.js.map +1 -1
  171. package/dist/storage/useStorage.js +8 -3
  172. package/dist/storage/useStorage.js.map +1 -1
  173. package/dist/table/useStickyTableSection.js +1 -1
  174. package/dist/table/useStickyTableSection.js.map +1 -1
  175. package/dist/tabs/TabList.js +2 -2
  176. package/dist/tabs/TabList.js.map +1 -1
  177. package/dist/tabs/_tabs.scss +5 -6
  178. package/dist/tabs/useMaxTabPanelHeight.js +4 -3
  179. package/dist/tabs/useMaxTabPanelHeight.js.map +1 -1
  180. package/dist/tabs/useTabList.js +1 -1
  181. package/dist/tabs/useTabList.js.map +1 -1
  182. package/dist/test-utils/jest-globals/match-media.d.ts +1 -1
  183. package/dist/test-utils/jest-globals/match-media.js +1 -1
  184. package/dist/test-utils/jest-globals/match-media.js.map +1 -1
  185. package/dist/test-utils/jest-globals/timers.js +1 -1
  186. package/dist/test-utils/jest-globals/timers.js.map +1 -1
  187. package/dist/test-utils/jest-globals/uploadMenuItemFileInput.js +1 -1
  188. package/dist/test-utils/jest-globals/uploadMenuItemFileInput.js.map +1 -1
  189. package/dist/test-utils/mocks/ResizeObserver.js +2 -2
  190. package/dist/test-utils/mocks/ResizeObserver.js.map +1 -1
  191. package/dist/test-utils/polyfills/IntersectionObserver.js +2 -2
  192. package/dist/test-utils/polyfills/IntersectionObserver.js.map +1 -1
  193. package/dist/test-utils/polyfills/ResizeObserver.js +2 -2
  194. package/dist/test-utils/polyfills/ResizeObserver.js.map +1 -1
  195. package/dist/test-utils/polyfills/TextDecoder.js +2 -2
  196. package/dist/test-utils/polyfills/TextDecoder.js.map +1 -1
  197. package/dist/test-utils/polyfills/TextEncoder.js +2 -2
  198. package/dist/test-utils/polyfills/TextEncoder.js.map +1 -1
  199. package/dist/test-utils/polyfills/matchMedia.js +2 -2
  200. package/dist/test-utils/polyfills/matchMedia.js.map +1 -1
  201. package/dist/test-utils/polyfills/offsetParent.js +2 -2
  202. package/dist/test-utils/polyfills/offsetParent.js.map +1 -1
  203. package/dist/test-utils/polyfills/scrollIntoView.js +1 -1
  204. package/dist/test-utils/polyfills/scrollIntoView.js.map +1 -1
  205. package/dist/test-utils/queries/select.js +2 -2
  206. package/dist/test-utils/queries/select.js.map +1 -1
  207. package/dist/test-utils/queries/slider.js +1 -1
  208. package/dist/test-utils/queries/slider.js.map +1 -1
  209. package/dist/test-utils/utils/createFileList.js +2 -0
  210. package/dist/test-utils/utils/createFileList.js.map +1 -1
  211. package/dist/test-utils/utils/createMatchMediaSpy.d.ts +1 -1
  212. package/dist/test-utils/utils/createMatchMediaSpy.js +3 -3
  213. package/dist/test-utils/utils/createMatchMediaSpy.js.map +1 -1
  214. package/dist/test-utils/vitest/match-media.d.ts +1 -1
  215. package/dist/test-utils/vitest/match-media.js +1 -1
  216. package/dist/test-utils/vitest/match-media.js.map +1 -1
  217. package/dist/test-utils/vitest/timers.js +1 -1
  218. package/dist/test-utils/vitest/timers.js.map +1 -1
  219. package/dist/test-utils/vitest/uploadMenuItemFileInput.js +1 -1
  220. package/dist/test-utils/vitest/uploadMenuItemFileInput.js.map +1 -1
  221. package/dist/theme/ThemeProvider.js +2 -2
  222. package/dist/theme/ThemeProvider.js.map +1 -1
  223. package/dist/theme/_a11y.scss +3 -1
  224. package/dist/theme/_theme.scss +16 -12
  225. package/dist/theme/getDerivedTheme.js +1 -1
  226. package/dist/theme/getDerivedTheme.js.map +1 -1
  227. package/dist/theme/useCSSVariables.js +5 -5
  228. package/dist/theme/useCSSVariables.js.map +1 -1
  229. package/dist/theme/useColorSchemeMetaTag.js +2 -2
  230. package/dist/theme/useColorSchemeMetaTag.js.map +1 -1
  231. package/dist/theme/useInlineCSSVariables.js +4 -3
  232. package/dist/theme/useInlineCSSVariables.js.map +1 -1
  233. package/dist/theme/utils.js +8 -8
  234. package/dist/theme/utils.js.map +1 -1
  235. package/dist/tooltip/useTooltip.js +7 -7
  236. package/dist/tooltip/useTooltip.js.map +1 -1
  237. package/dist/tooltip/useTooltipPosition.js +1 -1
  238. package/dist/tooltip/useTooltipPosition.js.map +1 -1
  239. package/dist/transition/useCarousel.js +2 -2
  240. package/dist/transition/useCarousel.js.map +1 -1
  241. package/dist/transition/useCollapseTransition.js +1 -1
  242. package/dist/transition/useCollapseTransition.js.map +1 -1
  243. package/dist/transition/useSkeletonPlaceholder.js +4 -4
  244. package/dist/transition/useSkeletonPlaceholder.js.map +1 -1
  245. package/dist/transition/useTransition.js +2 -2
  246. package/dist/transition/useTransition.js.map +1 -1
  247. package/dist/transition/utils.js +5 -5
  248. package/dist/transition/utils.js.map +1 -1
  249. package/dist/tree/TreeItem.js +1 -1
  250. package/dist/tree/TreeItem.js.map +1 -1
  251. package/dist/tree/useTreeItems.js +7 -5
  252. package/dist/tree/useTreeItems.js.map +1 -1
  253. package/dist/tree/useTreeMovement.js +1 -1
  254. package/dist/tree/useTreeMovement.js.map +1 -1
  255. package/dist/tree/utils.js +6 -9
  256. package/dist/tree/utils.js.map +1 -1
  257. package/dist/typography/HighlightText.js +2 -1
  258. package/dist/typography/HighlightText.js.map +1 -1
  259. package/dist/typography/SrOnly.js +7 -1
  260. package/dist/typography/SrOnly.js.map +1 -1
  261. package/dist/useDebouncedFunction.js +4 -4
  262. package/dist/useDebouncedFunction.js.map +1 -1
  263. package/dist/useDropzone.js +9 -9
  264. package/dist/useDropzone.js.map +1 -1
  265. package/dist/useEnsuredState.js +5 -5
  266. package/dist/useEnsuredState.js.map +1 -1
  267. package/dist/useIntersectionObserver.js +3 -3
  268. package/dist/useIntersectionObserver.js.map +1 -1
  269. package/dist/useIsomorphicLayoutEffect.js +1 -1
  270. package/dist/useIsomorphicLayoutEffect.js.map +1 -1
  271. package/dist/useOrientation.js +1 -1
  272. package/dist/useOrientation.js.map +1 -1
  273. package/dist/useReadonlySet.js +1 -1
  274. package/dist/useReadonlySet.js.map +1 -1
  275. package/dist/useResizeListener.js +2 -2
  276. package/dist/useResizeListener.js.map +1 -1
  277. package/dist/useResizeObserver.js +3 -4
  278. package/dist/useResizeObserver.js.map +1 -1
  279. package/dist/useThrottledFunction.js +3 -3
  280. package/dist/useThrottledFunction.js.map +1 -1
  281. package/dist/useWindowSize.js +1 -1
  282. package/dist/useWindowSize.js.map +1 -1
  283. package/dist/utils/alphaNumericSort.js +3 -1
  284. package/dist/utils/alphaNumericSort.js.map +1 -1
  285. package/dist/utils/bem.js +9 -12
  286. package/dist/utils/bem.js.map +1 -1
  287. package/dist/utils/getNumberOfDigits.js +1 -0
  288. package/dist/utils/getNumberOfDigits.js.map +1 -1
  289. package/dist/utils/getRangeDefaultValue.js +1 -1
  290. package/dist/utils/getRangeDefaultValue.js.map +1 -1
  291. package/dist/utils/nearest.js +2 -2
  292. package/dist/utils/nearest.js.map +1 -1
  293. package/dist/utils/parseCssLengthUnit.js +3 -3
  294. package/dist/utils/parseCssLengthUnit.js.map +1 -1
  295. package/dist/utils/trigonometry.js +1 -1
  296. package/dist/utils/trigonometry.js.map +1 -1
  297. package/dist/window-splitter/_window-splitter.scss +15 -17
  298. package/package.json +9 -7
  299. package/src/autocomplete/AutocompleteChip.tsx +2 -2
  300. package/src/autocomplete/AutocompleteListboxChildren.tsx +1 -1
  301. package/src/autocomplete/useAutocomplete.ts +4 -4
  302. package/src/autocomplete/utils.ts +3 -3
  303. package/src/box/styles.ts +2 -2
  304. package/src/button/AsyncButton.tsx +1 -3
  305. package/src/chip/Chip.tsx +1 -2
  306. package/src/cssUtils.ts +12 -6
  307. package/src/datetime/useTimeField.ts +1 -1
  308. package/src/delegateEvent.ts +9 -9
  309. package/src/draggable/useDraggable.ts +4 -4
  310. package/src/draggable/utils.ts +1 -1
  311. package/src/expansion-panel/ExpansionPanel.tsx +1 -1
  312. package/src/expansion-panel/useExpansionPanels.ts +1 -1
  313. package/src/files/FileInput.tsx +1 -1
  314. package/src/files/createAcceptFromExtensions.ts +18 -0
  315. package/src/files/useFileUpload.ts +36 -37
  316. package/src/files/utils.ts +15 -11
  317. package/src/files/validation.ts +7 -9
  318. package/src/focus/useFocusContainer.ts +1 -1
  319. package/src/focus/utils.ts +11 -6
  320. package/src/form/InputToggleIcon.tsx +5 -5
  321. package/src/form/NativeSelect.tsx +1 -1
  322. package/src/form/Select.tsx +58 -7
  323. package/src/form/SelectedOption.tsx +2 -4
  324. package/src/form/formConfig.ts +1 -1
  325. package/src/form/inputToggleStyles.ts +9 -4
  326. package/src/form/legendStyles.ts +1 -1
  327. package/src/form/selectUtils.ts +2 -2
  328. package/src/form/useCombobox.ts +1 -0
  329. package/src/form/useFormReset.ts +2 -2
  330. package/src/form/useNumberField.ts +1 -1
  331. package/src/form/useResizingTextArea.ts +5 -5
  332. package/src/form/useSelectCombobox.ts +1 -4
  333. package/src/form/validation.ts +1 -1
  334. package/src/hoverMode/useHoverMode.ts +9 -9
  335. package/src/hoverMode/useHoverModeProvider.ts +4 -4
  336. package/src/icon/config.tsx +3 -3
  337. package/src/icon/materialConfig.ts +1 -1
  338. package/src/interaction/UserInteractionModeProvider.tsx +11 -10
  339. package/src/interaction/utils.ts +3 -3
  340. package/src/layout/useExpandableLayout.ts +3 -4
  341. package/src/layout/useMainTabIndex.ts +1 -1
  342. package/src/list/ListItem.tsx +1 -1
  343. package/src/media-queries/AppSizeProvider.tsx +1 -1
  344. package/src/media-queries/config.ts +2 -2
  345. package/src/media-queries/useMediaQuery.ts +3 -3
  346. package/src/menu/Menu.tsx +4 -4
  347. package/src/menu/MenuItemButton.tsx +1 -1
  348. package/src/menu/MenuItemFileInput.tsx +1 -1
  349. package/src/menu/MenuWidget.tsx +6 -4
  350. package/src/movement/findMatchIndex.ts +2 -2
  351. package/src/movement/useKeyboardMovementProvider.ts +2 -2
  352. package/src/movement/utils.ts +15 -14
  353. package/src/navigation/getTableOfContentsHeadings.ts +4 -3
  354. package/src/navigation/useActiveHeadingId.ts +8 -8
  355. package/src/navigation/useTableOfContentsHeadings.ts +1 -1
  356. package/src/navigation/utils.ts +6 -5
  357. package/src/portal/PortalContainerProvider.tsx +5 -3
  358. package/src/positioning/getFixedPosition.ts +9 -6
  359. package/src/positioning/useFixedPositioning.ts +2 -2
  360. package/src/positioning/utils.ts +3 -3
  361. package/src/scroll/getScrollbarWidth.ts +4 -4
  362. package/src/searching/fuzzy.ts +7 -3
  363. package/src/searching/toSearchQuery.ts +1 -1
  364. package/src/searching/utils.ts +1 -1
  365. package/src/snackbar/Toast.tsx +1 -1
  366. package/src/snackbar/ToastContent.tsx +2 -2
  367. package/src/snackbar/ToastManager.ts +11 -12
  368. package/src/spinbutton/useSpinButton.ts +1 -1
  369. package/src/spinbutton/utils/deselectNode.ts +1 -1
  370. package/src/spinbutton/utils/resolveInputEvent.ts +1 -1
  371. package/src/spinbutton/utils/selectNode.ts +1 -1
  372. package/src/storage/useStorage.ts +7 -2
  373. package/src/table/useStickyTableSection.tsx +1 -1
  374. package/src/tabs/TabList.tsx +2 -2
  375. package/src/tabs/useMaxTabPanelHeight.ts +6 -3
  376. package/src/tabs/useTabList.ts +2 -2
  377. package/src/test-utils/jest-globals/match-media.ts +5 -2
  378. package/src/test-utils/jest-globals/timers.ts +1 -1
  379. package/src/test-utils/jest-globals/uploadMenuItemFileInput.ts +1 -1
  380. package/src/test-utils/mocks/ResizeObserver.ts +2 -2
  381. package/src/test-utils/polyfills/IntersectionObserver.ts +2 -2
  382. package/src/test-utils/polyfills/ResizeObserver.ts +2 -2
  383. package/src/test-utils/polyfills/TextDecoder.ts +2 -2
  384. package/src/test-utils/polyfills/TextEncoder.ts +2 -2
  385. package/src/test-utils/polyfills/matchMedia.ts +5 -2
  386. package/src/test-utils/polyfills/offsetParent.ts +2 -2
  387. package/src/test-utils/polyfills/scrollIntoView.ts +1 -1
  388. package/src/test-utils/queries/select.ts +2 -2
  389. package/src/test-utils/queries/slider.ts +1 -1
  390. package/src/test-utils/utils/createFileList.ts +2 -0
  391. package/src/test-utils/utils/createMatchMediaSpy.ts +4 -4
  392. package/src/test-utils/vitest/match-media.ts +2 -2
  393. package/src/test-utils/vitest/timers.ts +1 -1
  394. package/src/test-utils/vitest/uploadMenuItemFileInput.ts +1 -1
  395. package/src/theme/ThemeProvider.tsx +2 -2
  396. package/src/theme/getDerivedTheme.ts +1 -1
  397. package/src/theme/useCSSVariables.ts +5 -5
  398. package/src/theme/useColorSchemeMetaTag.ts +2 -2
  399. package/src/theme/useInlineCSSVariables.ts +6 -7
  400. package/src/theme/utils.ts +8 -8
  401. package/src/tooltip/useTooltip.ts +7 -7
  402. package/src/tooltip/useTooltipPosition.ts +1 -1
  403. package/src/transition/useCarousel.ts +2 -2
  404. package/src/transition/useCollapseTransition.ts +1 -1
  405. package/src/transition/useSkeletonPlaceholder.ts +4 -4
  406. package/src/transition/useTransition.ts +2 -2
  407. package/src/transition/utils.ts +5 -5
  408. package/src/tree/TreeItem.tsx +1 -1
  409. package/src/tree/useTreeItems.ts +5 -5
  410. package/src/tree/useTreeMovement.ts +1 -1
  411. package/src/tree/utils.ts +9 -9
  412. package/src/typography/HighlightText.tsx +4 -3
  413. package/src/typography/SrOnly.tsx +9 -2
  414. package/src/useDebouncedFunction.ts +5 -5
  415. package/src/useDropzone.ts +10 -10
  416. package/src/useEnsuredState.ts +5 -5
  417. package/src/useIntersectionObserver.ts +3 -3
  418. package/src/useIsomorphicLayoutEffect.ts +3 -3
  419. package/src/useOrientation.ts +1 -1
  420. package/src/useReadonlySet.ts +3 -1
  421. package/src/useResizeListener.ts +2 -2
  422. package/src/useResizeObserver.ts +3 -4
  423. package/src/useThrottledFunction.ts +4 -4
  424. package/src/useWindowSize.ts +1 -1
  425. package/src/utils/alphaNumericSort.ts +1 -1
  426. package/src/utils/bem.ts +15 -16
  427. package/src/utils/getNumberOfDigits.ts +1 -0
  428. package/src/utils/getRangeDefaultValue.ts +1 -1
  429. package/src/utils/nearest.ts +5 -2
  430. package/src/utils/parseCssLengthUnit.ts +5 -4
  431. package/src/utils/trigonometry.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/snackbar/ToastManager.ts"],"sourcesContent":["import { nanoid } from \"nanoid\";\n\nimport { type ConfigurableToastProps } from \"./Toast.js\";\n\n/**\n * @since 6.0.0\n */\nexport const DEFAULT_TOAST_VISIBLE_TIME = 5000;\n\n/**\n * - `\"normal\"` - the toast will be added to the end of the queue\n * - `\"next\"` - the toast will be inserted next-in-line in the queue, waiting\n * for the current visible toast to exit before being shown. If the toast does\n * not support duplicates, the existing toast will be moved instead and merged\n * with the toast.\n * - `\"replace\"` - if there is a currently visible toast, it will start the\n * leave transition and display the newly added toast instead.\n * - `\"immediate\"` - the same behavior as `\"replace\"` except that if there was a\n * currently visible toast, the toast will be shown again once the `\"immediate\"`\n * toast is hidden.\n *\n * @since 6.0.0 Renamed from `MessagePriority` to `ToastPriority`\n */\nexport type ToastPriority = \"normal\" | \"next\" | \"replace\" | \"immediate\";\n\n/**\n * - `\"allow\"` - toasts with the same `toastId` can be added into the queue, but\n * the leave timeout behavior might not work if multiple toasts can be shown\n * at the same time.\n * - `\"restart\"` - (default) toasts that have the same `toastId` as a toast\n * being shown will restart the exit timeout and update the toast with any\n * differences in the toast. If the toast is not currently being shown, a new\n * toast will not be added.\n * - `\"update\"` - toasts that have the same `toastId` will just update the toast\n * with the latest content while maintaining any existing timeouts\n *\n * @since 6.0.0 Renamed from `DuplicateBehavior`\n */\nexport type ToastDuplicateBehavior = \"allow\" | \"restart\" | \"update\";\n\n/**\n * @since 6.0.0\n */\nexport interface ToastMeta {\n /**\n * This will be `true` if the exit timeout has been paused either by hovering\n * the toast or the page has become inactive through blur or minimizing.\n */\n paused: boolean;\n\n /**\n * This will be `true` when the toast should be visible and `false` during the\n * exit animation.\n */\n visible: boolean;\n\n /**\n * The current toast's id which can be used with the:\n * - {@link ToastManager.removeToast}\n * - {@link ToastManager.startRemoveTimeout}\n * - {@link ToastManager.pauseRemoveTimeout}\n * - {@link ToastManager.resumeRemoveTimeout}\n */\n toastId: string;\n priority: ToastPriority;\n duplicates: ToastDuplicateBehavior;\n visibleTime: number | null;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface CreateToastOptions extends ConfigurableToastProps {\n /**\n * @defaultValue `nanoid()`\n */\n toastId?: string;\n\n /**\n * @see {@link ToastDuplicateBehavior}\n * @defaultValue `\"restart\"`\n */\n duplicates?: ToastDuplicateBehavior;\n\n /**\n * @see {@link ToastPriority}\n * @defaultValue `\"normal\"`\n */\n priority?: ToastPriority;\n\n /**\n * Set this to `null` to prevent the toast from automatically hiding,\n * otherwise set this to the number of milliseconds to remain visible.\n *\n * @see {@link DEFAULT_TOAST_VISIBLE_TIME}\n * @defaultValue `DEFAULT_TOAST_VISIBLE_TIME`\n */\n visibleTime?: number | null;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface QueuedToast extends ConfigurableToastProps, ToastMeta {}\n\n/**\n * @since 6.0.0\n */\nexport type ToastQueue = readonly Readonly<QueuedToast>[];\n\n/**\n * @since 6.0.0\n */\nexport type ToastCallback = (queue: ToastQueue) => void;\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport interface ToastVisibilityTimers {\n inactive: boolean;\n startTime: number;\n elapsedTime: number;\n exitTimeout?: number;\n}\n\n/**\n * @see {@link https://react-md.dev/components/snackbar | Snackbar Demos}\n * @see {@link ToastManagerProvider}\n * @since 6.0.0\n */\nexport class ToastManager {\n #queue: QueuedToast[];\n #timers: Map<string, ToastVisibilityTimers>;\n #listeners: ToastCallback[];\n\n constructor() {\n this.#queue = [];\n this.#timers = new Map();\n this.#listeners = [];\n\n // All of the class methods must be arrow functions to preserve the correct\n // `this` value. If they aren't arrow functions, I'd have to wrap each call\n // in an arrow function to work.\n //\n // i.e.\n // useSyncExternalStore(\n // (cb) => manager.subscribe(cb),\n // () => manager.getQueue(),\n // () => manager.getQueue(),\n // );\n }\n\n #emit = (): void => {\n // shallow clone to ensure react updates\n this.#queue = [...this.#queue];\n this.#listeners.forEach((callback) => {\n callback(this.#queue);\n });\n };\n\n #getToastIndex = (toastId: string | undefined): number => {\n if (!toastId) {\n return -1;\n }\n\n return this.#queue.findIndex((toast) => toast.toastId === toastId);\n };\n\n #getToast = (toastId: string | undefined): QueuedToast | undefined => {\n return this.#queue[this.#getToastIndex(toastId)];\n };\n\n /**\n * Starts the exit transition for the currently shown toast and adds the next\n * toast into the queue. This requires a manual call to `this.#emit()`\n * afterwards.\n */\n #addToastImmediately = (nextToast: QueuedToast): void => {\n const [current] = this.#queue;\n this.clearTimer(current.toastId);\n this.#queue[0] = {\n ...current,\n visible: false,\n };\n if (nextToast.priority === \"immediate\") {\n this.#queue.splice(1, 0, nextToast, current);\n } else {\n this.#queue.splice(1, 0, nextToast);\n }\n };\n\n /**\n * This calls `this.#emit()` if the toast was updated\n */\n #updateToast = (\n toastIdOrIndex: string | number,\n patch: Partial<QueuedToast>\n ): void => {\n const index =\n typeof toastIdOrIndex === \"number\"\n ? toastIdOrIndex\n : this.#getToastIndex(toastIdOrIndex);\n\n if (index === -1) {\n return;\n }\n\n this.#queue[index] = {\n ...this.#queue[index],\n ...patch,\n };\n this.#emit();\n };\n\n /**\n * This is just used to subscribe to changes in the {@link useToastQueue}.\n *\n * ```tsx\n * useSyncExternalStore(\n * toastManager.subscribe,\n * toastManager.getQueue,\n * toastManager.getQueue,\n * );\n * ```\n *\n * @internal\n */\n subscribe = (callback: ToastCallback): (() => void) => {\n this.#listeners.push(callback);\n\n return () => {\n this.#listeners = this.#listeners.filter((cb) => cb !== callback);\n };\n };\n\n /**\n * @see {@link subscribe}\n * @internal\n */\n getQueue = (): ToastQueue => {\n return this.#queue;\n };\n\n /**\n * Either adds the toast to the queue or updates an existing toast when using\n * an existing `toastId`.\n *\n * @example Adding toasts\n * ```tsx\n * // create a toast when the user is offline that will not disappear\n * addToast({ toastId: \"offline\", visibleTime: null });\n *\n * // add a new toast that displays `\"Toast\"` to the queue\n * addToast({ children: \"Toast!\" });\n *\n * // add an online toast notification. since these three use the same toast\n * // id, the hide timer will be reset each time\n * addToast({ toastId: \"online\" });\n * addToast({ toastId: \"online\" });\n * addToast({ toastId: \"online\" });\n *\n * // add a server error toast to the queue where the second one will be\n * // ignored\n * addToast({\n * toastId: \"ServerError\",\n * theme: \"error\",\n * duplicates: \"prevent\",\n * });\n * addToast({\n * toastId: \"ServerError\",\n * theme: \"error\",\n * duplicates: \"prevent\",\n * });\n *\n * // add a toast to the queue that has an action button that says \"Goodbye\"\n * addToast({\n * children: \"Hello, world!\",\n * action: \"Goodbye\",\n * });\n *\n * // add a toast to the queue that has an action button that says \"Goodbye\"\n * // and a custom click handler\n * addToast({\n * children: \"Hello, world!\",\n * action: {\n * onClick: () => {\n * logout();\n * },\n * children: \"Goodbye\",\n * },\n * });\n *\n * // add a toast to the queue that renders a react component in the content,\n * // a custom action button implementation (using `ToastActionButton`), and a\n * // close button\n * addToast({\n * children: <SomeCustomComponent />,\n * actionButton: <SomeCustomActionButton />,\n * closeButton: true,\n * });\n * ```\n */\n addToast = (toast: CreateToastOptions): void => {\n const {\n toastId = nanoid(),\n visibleTime = DEFAULT_TOAST_VISIBLE_TIME,\n role = visibleTime === null ? \"alert\" : \"status\",\n priority = \"normal\",\n duplicates = \"restart\",\n } = toast;\n\n const existingIndex = this.#getToastIndex(toast.toastId);\n if (existingIndex !== -1 && duplicates !== \"allow\") {\n const existingToast = this.#queue[existingIndex];\n const nextToast: QueuedToast = {\n ...existingToast,\n ...toast,\n };\n\n // reorder/move the existing toast to be the next item in the queue by:\n // - removing the toast from the queue\n // - inserting it into the next position with the updates\n if (priority === \"next\" && existingIndex > 1) {\n this.#queue.splice(existingIndex, 1);\n this.#queue.splice(1, 0, nextToast);\n this.#emit();\n return;\n }\n\n // only need to reorder the queue if it is not being shown\n if (\n (priority === \"replace\" || priority === \"immediate\") &&\n existingIndex !== 0\n ) {\n this.#queue.splice(existingIndex, 1);\n this.#addToastImmediately(nextToast);\n this.#emit();\n return;\n }\n\n const timers = this.#timers.get(toastId);\n if (existingToast.visible && duplicates === \"restart\" && timers) {\n this.#timers.set(toastId, { ...timers, elapsedTime: 0 });\n\n // wait for the next resume event instead. this _should_ only happen\n // when hovering a toast and another toast replaces it\n if (!nextToast.paused) {\n this.startRemoveTimeout(toastId);\n }\n }\n\n this.#updateToast(existingIndex, toast);\n return;\n }\n\n const nextToast: QueuedToast = {\n ...toast,\n role,\n paused: false,\n visible: true,\n toastId,\n priority,\n duplicates,\n visibleTime,\n };\n\n const queueSize = this.#queue.length;\n if (priority === \"next\" && queueSize > 1) {\n this.#queue.splice(1, 0, nextToast);\n } else if (\n (priority === \"replace\" || priority === \"immediate\") &&\n queueSize > 0\n ) {\n this.#addToastImmediately(nextToast);\n } else {\n this.#queue.push(nextToast);\n }\n\n this.#emit();\n };\n\n /**\n * Attempts to start the timeout for removing the toast when the `visibleTime`\n * is not null for a toast.\n *\n * @param toastId - The specific toastId to update\n */\n startRemoveTimeout = (toastId: string): void => {\n const toast = this.#getToast(toastId);\n if (!toast) {\n return;\n }\n\n const { visibleTime } = toast;\n if (visibleTime === null) {\n // Must manually be closed\n return;\n }\n\n const cached = this.#timers.get(toastId);\n const timers = (cached && { ...cached }) || {\n inactive: false,\n startTime: Date.now(),\n elapsedTime: 0,\n };\n window.clearTimeout(timers.exitTimeout);\n\n let duration = visibleTime;\n if (timers.elapsedTime) {\n duration -= timers.elapsedTime;\n }\n\n timers.inactive = false;\n timers.exitTimeout = window.setTimeout(() => {\n this.removeToast(toastId, true);\n }, duration);\n this.#timers.set(toastId, timers);\n };\n\n /**\n * Pauses the remove timeout for a specific toast normally with hover events\n * or the browser becoming inactive.\n *\n * @param toastId - The specific toastId to pause\n */\n pauseRemoveTimeout = (toastId: string): void => {\n const toast = this.#getToast(toastId);\n const cached = this.#timers.get(toastId);\n if (!toast || !cached || cached.inactive) {\n return;\n }\n\n window.clearTimeout(cached.exitTimeout);\n const timers = { ...cached };\n timers.inactive = true;\n timers.elapsedTime = Date.now() - timers.startTime + timers.elapsedTime;\n this.#timers.set(toastId, timers);\n this.#updateToast(toastId, { paused: true });\n };\n\n /**\n * Resumes the current remove timeout if it was paused by\n * {@link pauseRemoveTimeout}.\n *\n * @param toastId - The specific toastId to resume\n */\n resumeRemoveTimeout = (toastId: string): void => {\n const toastIndex = this.#getToastIndex(toastId);\n const timers = this.#timers.get(toastId);\n if (toastIndex === -1 || !timers?.startTime) {\n return;\n }\n\n timers.startTime = Date.now();\n this.#updateToast(toastIndex, { paused: false });\n this.startRemoveTimeout(toastId);\n };\n\n /**\n * Removes a toast by id from the queue without any exit animation.\n *\n * @param toastId - The specific {@link QueuedToast.toastId}\n * @param transition - Set this to `true` to remove the toast by the exit\n * transition instead of immediately.\n */\n removeToast = (toastId: string, transition: boolean): void => {\n const toastIndex = this.#getToastIndex(toastId);\n if (toastIndex === -1) {\n return;\n }\n\n if (transition) {\n this.clearTimer(toastId);\n this.#updateToast(toastIndex, { visible: false });\n return;\n }\n\n this.#queue.splice(toastIndex, 1);\n this.#emit();\n };\n\n /**\n * Clears any pending timers for the provided toast id. This should generally\n * be used in the `useEffect` cleanup effect for any custom toast renderer\n * implementations.\n *\n * @example\n * ```tsx\n * const { toastId } = toast;\n * const toastManager = useToastManager();\n *\n * useEffect(() => {\n * return () => {\n * toastManager.clearTimer(toastId):\n * }\n * }, [toastManager, toastId]);\n * ```\n */\n clearTimer = (toastId: string): void => {\n const timer = this.#timers.get(toastId);\n window.clearTimeout(timer?.exitTimeout);\n this.#timers.delete(toastId);\n };\n\n /**\n * Removes first toast from the queue without any exit animation. You most\n * likely want to use {@link removeToast} instead.\n */\n popToast = (): void => {\n this.#queue.pop();\n this.#emit();\n };\n\n /**\n * Removes all toasts from the queue. There will be no exit animation.\n *\n * @param disableEmit - Set this to `true` to disable emitting the empty queue.\n * Mostly used for tests.\n */\n clearToasts = (disableEmit = false): void => {\n this.#queue = [];\n this.#timers.forEach((meta) => {\n window.clearTimeout(meta.exitTimeout);\n });\n this.#timers.clear();\n if (!disableEmit) {\n this.#emit();\n }\n };\n}\n\n/**\n * The default toast manager for react-md apps that will allow toasts to be\n * added without setting up the {@link ToastManagerProvider}.\n *\n * @internal\n * @since 6.0.0\n */\nexport const toastManager = new ToastManager();\n\n/**\n * @see {@link ToastManager.addToast}\n * @since 6.0.0\n */\nexport const addToast: ToastManager[\"addToast\"] = (toast) => {\n toastManager.addToast(toast);\n};\n\n/**\n * @see {@link ToastManager.startRemoveTimeout}\n * @since 6.0.0\n */\nexport const startRemoveToastTimeout: ToastManager[\"startRemoveTimeout\"] = (\n toastId\n) => {\n toastManager.startRemoveTimeout(toastId);\n};\n\n/**\n * @see {@link ToastManager.popToast}\n * @since 6.0.0\n */\nexport const popToast: ToastManager[\"popToast\"] = () => {\n toastManager.popToast();\n};\n\n/**\n * @see {@link ToastManager.removeToast}\n * @since 6.0.0\n */\nexport const removeToast: ToastManager[\"removeToast\"] = (\n toastId,\n transition\n) => {\n toastManager.removeToast(toastId, transition);\n};\n\n/**\n * @see {@link ToastManager.clearToasts}\n * @since 6.0.0\n */\nexport const clearToasts = (): void => {\n toastManager.clearToasts();\n};\n"],"names":["nanoid","DEFAULT_TOAST_VISIBLE_TIME","ToastManager","forEach","callback","toastId","findIndex","toast","nextToast","current","clearTimer","visible","priority","splice","toastIdOrIndex","patch","index","subscribe","push","filter","cb","getQueue","addToast","visibleTime","role","duplicates","existingIndex","existingToast","timers","get","set","elapsedTime","paused","startRemoveTimeout","queueSize","length","cached","inactive","startTime","Date","now","window","clearTimeout","exitTimeout","duration","setTimeout","removeToast","pauseRemoveTimeout","resumeRemoveTimeout","toastIndex","transition","timer","delete","popToast","pop","clearToasts","disableEmit","meta","clear","Map","toastManager","startRemoveToastTimeout"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/snackbar/ToastManager.ts"],"sourcesContent":["import { nanoid } from \"nanoid\";\n\nimport { type ConfigurableToastProps } from \"./Toast.js\";\n\n/**\n * @since 6.0.0\n */\nexport const DEFAULT_TOAST_VISIBLE_TIME = 5000;\n\n/**\n * - `\"normal\"` - the toast will be added to the end of the queue\n * - `\"next\"` - the toast will be inserted next-in-line in the queue, waiting\n * for the current visible toast to exit before being shown. If the toast does\n * not support duplicates, the existing toast will be moved instead and merged\n * with the toast.\n * - `\"replace\"` - if there is a currently visible toast, it will start the\n * leave transition and display the newly added toast instead.\n * - `\"immediate\"` - the same behavior as `\"replace\"` except that if there was a\n * currently visible toast, the toast will be shown again once the `\"immediate\"`\n * toast is hidden.\n *\n * @since 6.0.0 Renamed from `MessagePriority` to `ToastPriority`\n */\nexport type ToastPriority = \"normal\" | \"next\" | \"replace\" | \"immediate\";\n\n/**\n * - `\"allow\"` - toasts with the same `toastId` can be added into the queue, but\n * the leave timeout behavior might not work if multiple toasts can be shown\n * at the same time.\n * - `\"restart\"` - (default) toasts that have the same `toastId` as a toast\n * being shown will restart the exit timeout and update the toast with any\n * differences in the toast. If the toast is not currently being shown, a new\n * toast will not be added.\n * - `\"update\"` - toasts that have the same `toastId` will just update the toast\n * with the latest content while maintaining any existing timeouts\n *\n * @since 6.0.0 Renamed from `DuplicateBehavior`\n */\nexport type ToastDuplicateBehavior = \"allow\" | \"restart\" | \"update\";\n\n/**\n * @since 6.0.0\n */\nexport interface ToastMeta {\n /**\n * This will be `true` if the exit timeout has been paused either by hovering\n * the toast or the page has become inactive through blur or minimizing.\n */\n paused: boolean;\n\n /**\n * This will be `true` when the toast should be visible and `false` during the\n * exit animation.\n */\n visible: boolean;\n\n /**\n * The current toast's id which can be used with the:\n * - {@link ToastManager.removeToast}\n * - {@link ToastManager.startRemoveTimeout}\n * - {@link ToastManager.pauseRemoveTimeout}\n * - {@link ToastManager.resumeRemoveTimeout}\n */\n toastId: string;\n priority: ToastPriority;\n duplicates: ToastDuplicateBehavior;\n visibleTime: number | null;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface CreateToastOptions extends ConfigurableToastProps {\n /**\n * @defaultValue `nanoid()`\n */\n toastId?: string;\n\n /**\n * @see {@link ToastDuplicateBehavior}\n * @defaultValue `\"restart\"`\n */\n duplicates?: ToastDuplicateBehavior;\n\n /**\n * @see {@link ToastPriority}\n * @defaultValue `\"normal\"`\n */\n priority?: ToastPriority;\n\n /**\n * Set this to `null` to prevent the toast from automatically hiding,\n * otherwise set this to the number of milliseconds to remain visible.\n *\n * @see {@link DEFAULT_TOAST_VISIBLE_TIME}\n * @defaultValue `DEFAULT_TOAST_VISIBLE_TIME`\n */\n visibleTime?: number | null;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface QueuedToast extends ConfigurableToastProps, ToastMeta {}\n\n/**\n * @since 6.0.0\n */\nexport type ToastQueue = readonly Readonly<QueuedToast>[];\n\n/**\n * @since 6.0.0\n */\nexport type ToastCallback = (queue: ToastQueue) => void;\n\n/**\n * @internal\n * @since 6.0.0\n */\nexport interface ToastVisibilityTimers {\n inactive: boolean;\n startTime: number;\n elapsedTime: number;\n exitTimeout?: NodeJS.Timeout;\n}\n\n/**\n * @see {@link https://react-md.dev/components/snackbar | Snackbar Demos}\n * @see {@link ToastManagerProvider}\n * @since 6.0.0\n */\nexport class ToastManager {\n #queue: QueuedToast[];\n #timers: Map<string, ToastVisibilityTimers>;\n #listeners: ToastCallback[];\n\n constructor() {\n this.#queue = [];\n this.#timers = new Map();\n this.#listeners = [];\n\n // All of the class methods must be arrow functions to preserve the correct\n // `this` value. If they aren't arrow functions, I'd have to wrap each call\n // in an arrow function to work.\n //\n // i.e.\n // useSyncExternalStore(\n // (cb) => manager.subscribe(cb),\n // () => manager.getQueue(),\n // () => manager.getQueue(),\n // );\n }\n\n #emit = (): void => {\n // shallow clone to ensure react updates\n this.#queue = [...this.#queue];\n for (const callback of this.#listeners) {\n callback(this.#queue);\n }\n };\n\n #getToastIndex = (toastId: string | undefined): number => {\n if (!toastId) {\n return -1;\n }\n\n return this.#queue.findIndex((toast) => toast.toastId === toastId);\n };\n\n #getToast = (toastId: string | undefined): QueuedToast | undefined => {\n return this.#queue[this.#getToastIndex(toastId)];\n };\n\n /**\n * Starts the exit transition for the currently shown toast and adds the next\n * toast into the queue. This requires a manual call to `this.#emit()`\n * afterwards.\n */\n #addToastImmediately = (nextToast: QueuedToast): void => {\n const [current] = this.#queue;\n this.clearTimer(current.toastId);\n this.#queue[0] = {\n ...current,\n visible: false,\n };\n if (nextToast.priority === \"immediate\") {\n this.#queue.splice(1, 0, nextToast, current);\n } else {\n this.#queue.splice(1, 0, nextToast);\n }\n };\n\n /**\n * This calls `this.#emit()` if the toast was updated\n */\n #updateToast = (\n toastIdOrIndex: string | number,\n patch: Partial<QueuedToast>\n ): void => {\n const index =\n typeof toastIdOrIndex === \"number\"\n ? toastIdOrIndex\n : this.#getToastIndex(toastIdOrIndex);\n\n if (index === -1) {\n return;\n }\n\n this.#queue[index] = {\n ...this.#queue[index],\n ...patch,\n };\n this.#emit();\n };\n\n /**\n * This is just used to subscribe to changes in the {@link useToastQueue}.\n *\n * ```tsx\n * useSyncExternalStore(\n * toastManager.subscribe,\n * toastManager.getQueue,\n * toastManager.getQueue,\n * );\n * ```\n *\n * @internal\n */\n subscribe = (callback: ToastCallback): (() => void) => {\n this.#listeners.push(callback);\n\n return () => {\n this.#listeners = this.#listeners.filter((cb) => cb !== callback);\n };\n };\n\n /**\n * @see {@link subscribe}\n * @internal\n */\n getQueue = (): ToastQueue => {\n return this.#queue;\n };\n\n /**\n * Either adds the toast to the queue or updates an existing toast when using\n * an existing `toastId`.\n *\n * @example Adding toasts\n * ```tsx\n * // create a toast when the user is offline that will not disappear\n * addToast({ toastId: \"offline\", visibleTime: null });\n *\n * // add a new toast that displays `\"Toast\"` to the queue\n * addToast({ children: \"Toast!\" });\n *\n * // add an online toast notification. since these three use the same toast\n * // id, the hide timer will be reset each time\n * addToast({ toastId: \"online\" });\n * addToast({ toastId: \"online\" });\n * addToast({ toastId: \"online\" });\n *\n * // add a server error toast to the queue where the second one will be\n * // ignored\n * addToast({\n * toastId: \"ServerError\",\n * theme: \"error\",\n * duplicates: \"prevent\",\n * });\n * addToast({\n * toastId: \"ServerError\",\n * theme: \"error\",\n * duplicates: \"prevent\",\n * });\n *\n * // add a toast to the queue that has an action button that says \"Goodbye\"\n * addToast({\n * children: \"Hello, world!\",\n * action: \"Goodbye\",\n * });\n *\n * // add a toast to the queue that has an action button that says \"Goodbye\"\n * // and a custom click handler\n * addToast({\n * children: \"Hello, world!\",\n * action: {\n * onClick: () => {\n * logout();\n * },\n * children: \"Goodbye\",\n * },\n * });\n *\n * // add a toast to the queue that renders a react component in the content,\n * // a custom action button implementation (using `ToastActionButton`), and a\n * // close button\n * addToast({\n * children: <SomeCustomComponent />,\n * actionButton: <SomeCustomActionButton />,\n * closeButton: true,\n * });\n * ```\n */\n addToast = (toast: CreateToastOptions): void => {\n const {\n toastId = nanoid(),\n visibleTime = DEFAULT_TOAST_VISIBLE_TIME,\n role = visibleTime === null ? \"alert\" : \"status\",\n priority = \"normal\",\n duplicates = \"restart\",\n } = toast;\n\n const existingIndex = this.#getToastIndex(toast.toastId);\n if (existingIndex !== -1 && duplicates !== \"allow\") {\n const existingToast = this.#queue[existingIndex];\n const nextToast: QueuedToast = {\n ...existingToast,\n ...toast,\n };\n\n // reorder/move the existing toast to be the next item in the queue by:\n // - removing the toast from the queue\n // - inserting it into the next position with the updates\n if (priority === \"next\" && existingIndex > 1) {\n this.#queue.splice(existingIndex, 1);\n this.#queue.splice(1, 0, nextToast);\n this.#emit();\n return;\n }\n\n // only need to reorder the queue if it is not being shown\n if (\n (priority === \"replace\" || priority === \"immediate\") &&\n existingIndex !== 0\n ) {\n this.#queue.splice(existingIndex, 1);\n this.#addToastImmediately(nextToast);\n this.#emit();\n return;\n }\n\n const timers = this.#timers.get(toastId);\n if (existingToast.visible && duplicates === \"restart\" && timers) {\n this.#timers.set(toastId, { ...timers, elapsedTime: 0 });\n\n // wait for the next resume event instead. this _should_ only happen\n // when hovering a toast and another toast replaces it\n if (!nextToast.paused) {\n this.startRemoveTimeout(toastId);\n }\n }\n\n this.#updateToast(existingIndex, toast);\n return;\n }\n\n const nextToast: QueuedToast = {\n ...toast,\n role,\n paused: false,\n visible: true,\n toastId,\n priority,\n duplicates,\n visibleTime,\n };\n\n const queueSize = this.#queue.length;\n if (priority === \"next\" && queueSize > 1) {\n this.#queue.splice(1, 0, nextToast);\n } else if (\n (priority === \"replace\" || priority === \"immediate\") &&\n queueSize > 0\n ) {\n this.#addToastImmediately(nextToast);\n } else {\n this.#queue.push(nextToast);\n }\n\n this.#emit();\n };\n\n /**\n * Attempts to start the timeout for removing the toast when the `visibleTime`\n * is not null for a toast.\n *\n * @param toastId - The specific toastId to update\n */\n startRemoveTimeout = (toastId: string): void => {\n const toast = this.#getToast(toastId);\n if (!toast) {\n return;\n }\n\n const { visibleTime } = toast;\n if (visibleTime === null) {\n // Must manually be closed\n return;\n }\n\n const cached = this.#timers.get(toastId);\n const timers = (cached && { ...cached }) || {\n inactive: false,\n startTime: Date.now(),\n elapsedTime: 0,\n };\n globalThis.clearTimeout(timers.exitTimeout);\n\n let duration = visibleTime;\n if (timers.elapsedTime) {\n duration -= timers.elapsedTime;\n }\n\n timers.inactive = false;\n timers.exitTimeout = globalThis.setTimeout(() => {\n this.removeToast(toastId, true);\n }, duration);\n this.#timers.set(toastId, timers);\n };\n\n /**\n * Pauses the remove timeout for a specific toast normally with hover events\n * or the browser becoming inactive.\n *\n * @param toastId - The specific toastId to pause\n */\n pauseRemoveTimeout = (toastId: string): void => {\n const toast = this.#getToast(toastId);\n const cached = this.#timers.get(toastId);\n if (!toast || !cached || cached.inactive) {\n return;\n }\n\n globalThis.clearTimeout(cached.exitTimeout);\n const timers = { ...cached, inactive: true };\n timers.elapsedTime = Date.now() - timers.startTime + timers.elapsedTime;\n this.#timers.set(toastId, timers);\n this.#updateToast(toastId, { paused: true });\n };\n\n /**\n * Resumes the current remove timeout if it was paused by\n * {@link pauseRemoveTimeout}.\n *\n * @param toastId - The specific toastId to resume\n */\n resumeRemoveTimeout = (toastId: string): void => {\n const toastIndex = this.#getToastIndex(toastId);\n const timers = this.#timers.get(toastId);\n if (toastIndex === -1 || !timers?.startTime) {\n return;\n }\n\n timers.startTime = Date.now();\n this.#updateToast(toastIndex, { paused: false });\n this.startRemoveTimeout(toastId);\n };\n\n /**\n * Removes a toast by id from the queue without any exit animation.\n *\n * @param toastId - The specific {@link QueuedToast.toastId}\n * @param transition - Set this to `true` to remove the toast by the exit\n * transition instead of immediately.\n */\n removeToast = (toastId: string, transition: boolean): void => {\n const toastIndex = this.#getToastIndex(toastId);\n if (toastIndex === -1) {\n return;\n }\n\n if (transition) {\n this.clearTimer(toastId);\n this.#updateToast(toastIndex, { visible: false });\n return;\n }\n\n this.#queue.splice(toastIndex, 1);\n this.#emit();\n };\n\n /**\n * Clears any pending timers for the provided toast id. This should generally\n * be used in the `useEffect` cleanup effect for any custom toast renderer\n * implementations.\n *\n * @example\n * ```tsx\n * const { toastId } = toast;\n * const toastManager = useToastManager();\n *\n * useEffect(() => {\n * return () => {\n * toastManager.clearTimer(toastId):\n * }\n * }, [toastManager, toastId]);\n * ```\n */\n clearTimer = (toastId: string): void => {\n const timer = this.#timers.get(toastId);\n globalThis.clearTimeout(timer?.exitTimeout);\n this.#timers.delete(toastId);\n };\n\n /**\n * Removes first toast from the queue without any exit animation. You most\n * likely want to use {@link removeToast} instead.\n */\n popToast = (): void => {\n this.#queue.pop();\n this.#emit();\n };\n\n /**\n * Removes all toasts from the queue. There will be no exit animation.\n *\n * @param disableEmit - Set this to `true` to disable emitting the empty queue.\n * Mostly used for tests.\n */\n clearToasts = (disableEmit = false): void => {\n this.#queue = [];\n for (const [, meta] of this.#timers) {\n globalThis.clearTimeout(meta.exitTimeout);\n }\n this.#timers.clear();\n if (!disableEmit) {\n this.#emit();\n }\n };\n}\n\n/**\n * The default toast manager for react-md apps that will allow toasts to be\n * added without setting up the {@link ToastManagerProvider}.\n *\n * @internal\n * @since 6.0.0\n */\nexport const toastManager = new ToastManager();\n\n/**\n * @see {@link ToastManager.addToast}\n * @since 6.0.0\n */\nexport const addToast: ToastManager[\"addToast\"] = (toast) => {\n toastManager.addToast(toast);\n};\n\n/**\n * @see {@link ToastManager.startRemoveTimeout}\n * @since 6.0.0\n */\nexport const startRemoveToastTimeout: ToastManager[\"startRemoveTimeout\"] = (\n toastId\n) => {\n toastManager.startRemoveTimeout(toastId);\n};\n\n/**\n * @see {@link ToastManager.popToast}\n * @since 6.0.0\n */\nexport const popToast: ToastManager[\"popToast\"] = () => {\n toastManager.popToast();\n};\n\n/**\n * @see {@link ToastManager.removeToast}\n * @since 6.0.0\n */\nexport const removeToast: ToastManager[\"removeToast\"] = (\n toastId,\n transition\n) => {\n toastManager.removeToast(toastId, transition);\n};\n\n/**\n * @see {@link ToastManager.clearToasts}\n * @since 6.0.0\n */\nexport const clearToasts = (): void => {\n toastManager.clearToasts();\n};\n"],"names":["nanoid","DEFAULT_TOAST_VISIBLE_TIME","ToastManager","callback","toastId","findIndex","toast","nextToast","current","clearTimer","visible","priority","splice","toastIdOrIndex","patch","index","subscribe","push","filter","cb","getQueue","addToast","visibleTime","role","duplicates","existingIndex","existingToast","timers","get","set","elapsedTime","paused","startRemoveTimeout","queueSize","length","cached","inactive","startTime","Date","now","globalThis","clearTimeout","exitTimeout","duration","setTimeout","removeToast","pauseRemoveTimeout","resumeRemoveTimeout","toastIndex","transition","timer","delete","popToast","pop","clearToasts","disableEmit","meta","clear","Map","toastManager","startRemoveToastTimeout"],"mappings":"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"}
@@ -152,10 +152,10 @@ $light-theme-color: a11y.contrast-color($light-theme-background-color) !default;
152
152
 
153
153
  /// The background-color to use in the dark theme.
154
154
  /// @type Color
155
+ // prettier-ignore
155
156
  $dark-theme-background-color: if(
156
- theme.$disable-dark-elevation,
157
- $light-theme-background-color,
158
- map.get(theme.$dark-elevation-colors, $elevation)
157
+ sass(theme.$disable-dark-elevation): $light-theme-background-color;
158
+ else: map.get(theme.$dark-elevation-colors, $elevation)
159
159
  ) !default;
160
160
 
161
161
  /// The text color to use in the dark theme.
@@ -24,7 +24,7 @@ import { selectNode } from "./utils/selectNode.js";
24
24
  // trigger a noop setValue when `value` and `onValueChange` are provided
25
25
  // since `onValueChange is always called with `setValue
26
26
  let propSetValue;
27
- if (typeof propValue !== "undefined" && options.onValueChange) {
27
+ if (propValue !== undefined && options.onValueChange) {
28
28
  propSetValue = noop;
29
29
  }
30
30
  const [value, setValue] = useEnsuredState({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/spinbutton/useSpinButton.ts"],"sourcesContent":["\"use client\";\n\nimport { type Dispatch, useCallback, useRef, useState } from \"react\";\n\nimport { tryToSubmitRelatedForm } from \"../form/utils.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useEnsuredState } from \"../useEnsuredState.js\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect.js\";\nimport { withinRange } from \"../utils/withinRange.js\";\nimport { useSpinButtonGroup } from \"./SpinButtonGroupProvider.js\";\nimport {\n defaultGetSpinButtonTextContent,\n defaultSpinButtonGetValueText,\n} from \"./defaults.js\";\nimport {\n type SpinButtonChangeEvent,\n type SpinButtonChangeEventOptions,\n type SpinButtonImplementation,\n type SpinButtonOptions,\n type SpinButtonValue,\n} from \"./types.js\";\nimport { deselectNode } from \"./utils/deselectNode.js\";\nimport { resolveInputEvent } from \"./utils/resolveInputEvent.js\";\nimport { selectNode } from \"./utils/selectNode.js\";\n\n/**\n * @since 6.4.0\n */\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 6.4.0\n */\nexport function useSpinButton<E extends HTMLElement = HTMLDivElement>(\n options: SpinButtonOptions<E>\n): SpinButtonImplementation<E> {\n const {\n id: propId,\n ref: propRef,\n min,\n max,\n step = 1,\n minDigits,\n maxDigits,\n form,\n readOnly,\n disabled,\n required,\n error,\n onBlur = noop,\n onFocus = noop,\n onInput = noop,\n onClick = noop,\n onKeyDown = noop,\n fallback,\n mappings,\n value: propValue,\n onValueChange = noop,\n defaultValue = null,\n getValueText = defaultSpinButtonGetValueText,\n getTextContent = defaultGetSpinButtonTextContent,\n placeholderChar,\n defaultKeyboardValue,\n } = options;\n const id = useEnsuredId(propId, \"spinbutton\");\n\n // trigger a noop setValue when `value` and `onValueChange` are provided\n // since `onValueChange is always called with `setValue\n let propSetValue: Dispatch<SpinButtonValue> | undefined;\n if (typeof propValue !== \"undefined\" && options.onValueChange) {\n propSetValue = noop;\n }\n\n const [value, setValue] = useEnsuredState({\n value: propValue,\n setValue: propSetValue,\n defaultValue,\n });\n\n const focused = useRef(false);\n const typedCount = useRef(0);\n const prevText = useRef(\"\");\n const [nodeRef, nodeRefCallback] = useEnsuredRef(propRef);\n const { focusNext } = useSpinButtonGroup();\n const [keyboardValue] = useState(defaultKeyboardValue);\n\n // NOTE: I might be able to get rid of this since I don't remember why it was\n // added maybe for controlled fields? I'll have to see when I get to the\n // date/time components again\n useIsomorphicLayoutEffect(() => {\n const node = nodeRef.current;\n if (!focused.current || !node) {\n return;\n }\n\n prevText.current = node.textContent || \"\";\n selectNode(node);\n }, [nodeRef, value]);\n\n const updateValue = useCallback(\n (options: SpinButtonChangeEventOptions<E>) => {\n setValue(options.value);\n onValueChange(options);\n if (options.reason === \"typed-to-completion\") {\n focusNext();\n }\n },\n [focusNext, onValueChange, setValue]\n );\n const increment = useCallback(\n (event: SpinButtonChangeEvent<E>) => {\n let nextValue: SpinButtonValue =\n value ?? keyboardValue ?? min ?? max ?? 0;\n nextValue = withinRange({ min, max, value: nextValue + step });\n\n // this actually means both min and max are a number\n if (nextValue === value && typeof min === \"number\") {\n nextValue = min;\n }\n\n updateValue({\n event,\n reason: \"change\",\n value: nextValue,\n });\n },\n [keyboardValue, max, min, step, updateValue, value]\n );\n const decrement = useCallback(\n (event: SpinButtonChangeEvent<E>) => {\n let nextValue: SpinButtonValue =\n value ?? keyboardValue ?? max ?? min ?? 0;\n nextValue = withinRange({ min, max, value: nextValue - step });\n\n // this actually means both min and max are a number\n if (nextValue === value && typeof max === \"number\") {\n nextValue = max;\n }\n\n updateValue({\n event,\n reason: \"change\",\n value: nextValue,\n });\n },\n [keyboardValue, max, min, step, updateValue, value]\n );\n\n return {\n value,\n setValue,\n spinButtonRef: nodeRef,\n spinButtonProps: {\n \"aria-readonly\": readOnly || undefined,\n \"aria-disabled\": disabled || undefined,\n \"aria-invalid\": error || undefined,\n \"aria-required\": required || undefined,\n \"aria-valuemin\": min,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value === null ? undefined : value,\n \"aria-valuetext\": getValueText(value),\n id,\n ref: nodeRefCallback,\n role: \"spinbutton\",\n autoCapitalize: \"none\",\n autoCorrect: \"off\",\n spellCheck: false,\n inputMode: \"numeric\",\n contentEditable: !disabled || undefined,\n suppressContentEditableWarning: true,\n tabIndex: disabled ? undefined : 0,\n onBlur: (event) => {\n onBlur(event);\n\n focused.current = false;\n deselectNode(event.currentTarget);\n },\n onFocus: (event) => {\n onFocus(event);\n\n if (disabled) {\n return;\n }\n\n focused.current = true;\n typedCount.current = 0;\n selectNode(event.currentTarget);\n },\n onKeyDown: (event) => {\n onKeyDown(event);\n\n if (disabled || (readOnly && event.key !== \"Enter\")) {\n return;\n }\n\n const setValue = (nextValue: number): void =>\n updateValue({ value: nextValue, event, reason: \"change\" });\n\n let stop = false;\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowLeft\":\n // `event.stopPropagation()` should not be called here since the\n // parent `useSpinButtonGroup` keyboard event handler should\n // still be called to handle advancing to the next spinbutton in\n // the group. Only the default cursor movement needs to be disabled\n // instead.\n event.preventDefault();\n break;\n case \"ArrowUp\":\n stop = true;\n increment(event);\n break;\n case \"ArrowDown\":\n stop = true;\n decrement(event);\n break;\n case \"Home\":\n stop = true;\n if (typeof min === \"number\") {\n setValue(min);\n }\n break;\n case \"End\":\n stop = true;\n if (typeof max === \"number\") {\n setValue(max);\n }\n break;\n case \"Enter\":\n stop = true;\n tryToSubmitRelatedForm(event, form);\n }\n\n if (stop) {\n event.preventDefault();\n event.stopPropagation();\n typedCount.current = 0;\n }\n },\n onClick: (event) => {\n onClick(event);\n\n event.preventDefault();\n if (disabled) {\n return;\n }\n\n focused.current = true;\n typedCount.current = 0;\n selectNode(event.currentTarget);\n },\n onInput: (event) => {\n onInput(event);\n\n const node = event.currentTarget;\n // if the input event is fired while readOnly or disabled, ignore it\n // and set it back to the previous state\n if (readOnly || disabled) {\n node.textContent = prevText.current;\n selectNode(node);\n return;\n }\n\n const { reason, nextValue } = resolveInputEvent({\n min,\n max,\n text: node.textContent || \"\",\n mappings,\n maxDigits,\n prevText: prevText.current,\n prevValue: value,\n typedCount: typedCount.current,\n });\n\n if (\n reason === \"change\" ||\n reason === \"cleared\" ||\n reason === \"typed-to-completion\"\n ) {\n typedCount.current = 0;\n } else if (reason !== \"ignored\") {\n typedCount.current++;\n }\n\n node.textContent = getTextContent({\n min,\n max,\n minDigits,\n maxDigits,\n value: nextValue,\n fallback,\n placeholderChar,\n });\n prevText.current = node.textContent;\n selectNode(node);\n\n if (reason !== \"ignored\" && reason !== \"placeholder-digit\") {\n updateValue({\n event,\n value: nextValue,\n reason,\n });\n }\n },\n },\n };\n}\n"],"names":["useCallback","useRef","useState","tryToSubmitRelatedForm","useEnsuredId","useEnsuredRef","useEnsuredState","useIsomorphicLayoutEffect","withinRange","useSpinButtonGroup","defaultGetSpinButtonTextContent","defaultSpinButtonGetValueText","deselectNode","resolveInputEvent","selectNode","noop","useSpinButton","options","id","propId","ref","propRef","min","max","step","minDigits","maxDigits","form","readOnly","disabled","required","error","onBlur","onFocus","onInput","onClick","onKeyDown","fallback","mappings","value","propValue","onValueChange","defaultValue","getValueText","getTextContent","placeholderChar","defaultKeyboardValue","propSetValue","setValue","focused","typedCount","prevText","nodeRef","nodeRefCallback","focusNext","keyboardValue","node","current","textContent","updateValue","reason","increment","event","nextValue","decrement","spinButtonRef","spinButtonProps","undefined","role","autoCapitalize","autoCorrect","spellCheck","inputMode","contentEditable","suppressContentEditableWarning","tabIndex","currentTarget","key","stop","preventDefault","stopPropagation","text","prevValue"],"mappings":"AAAA;AAEA,SAAwBA,WAAW,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAErE,SAASC,sBAAsB,QAAQ,mBAAmB;AAC1D,SAASC,YAAY,QAAQ,qBAAqB;AAClD,SAASC,aAAa,QAAQ,sBAAsB;AACpD,SAASC,eAAe,QAAQ,wBAAwB;AACxD,SAASC,yBAAyB,QAAQ,kCAAkC;AAC5E,SAASC,WAAW,QAAQ,0BAA0B;AACtD,SAASC,kBAAkB,QAAQ,+BAA+B;AAClE,SACEC,+BAA+B,EAC/BC,6BAA6B,QACxB,gBAAgB;AAQvB,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,iBAAiB,QAAQ,+BAA+B;AACjE,SAASC,UAAU,QAAQ,wBAAwB;AAEnD;;CAEC,GACD,MAAMC,OAAO;AACX,aAAa;AACf;AAEA;;CAEC,GACD,OAAO,SAASC,cACdC,OAA6B;IAE7B,MAAM,EACJC,IAAIC,MAAM,EACVC,KAAKC,OAAO,EACZC,GAAG,EACHC,GAAG,EACHC,OAAO,CAAC,EACRC,SAAS,EACTC,SAAS,EACTC,IAAI,EACJC,QAAQ,EACRC,QAAQ,EACRC,QAAQ,EACRC,KAAK,EACLC,SAASjB,IAAI,EACbkB,UAAUlB,IAAI,EACdmB,UAAUnB,IAAI,EACdoB,UAAUpB,IAAI,EACdqB,YAAYrB,IAAI,EAChBsB,QAAQ,EACRC,QAAQ,EACRC,OAAOC,SAAS,EAChBC,gBAAgB1B,IAAI,EACpB2B,eAAe,IAAI,EACnBC,eAAehC,6BAA6B,EAC5CiC,iBAAiBlC,+BAA+B,EAChDmC,eAAe,EACfC,oBAAoB,EACrB,GAAG7B;IACJ,MAAMC,KAAKd,aAAae,QAAQ;IAEhC,wEAAwE;IACxE,wDAAwD;IACxD,IAAI4B;IACJ,IAAI,OAAOP,cAAc,eAAevB,QAAQwB,aAAa,EAAE;QAC7DM,eAAehC;IACjB;IAEA,MAAM,CAACwB,OAAOS,SAAS,GAAG1C,gBAAgB;QACxCiC,OAAOC;QACPQ,UAAUD;QACVL;IACF;IAEA,MAAMO,UAAUhD,OAAO;IACvB,MAAMiD,aAAajD,OAAO;IAC1B,MAAMkD,WAAWlD,OAAO;IACxB,MAAM,CAACmD,SAASC,gBAAgB,GAAGhD,cAAcgB;IACjD,MAAM,EAAEiC,SAAS,EAAE,GAAG7C;IACtB,MAAM,CAAC8C,cAAc,GAAGrD,SAAS4C;IAEjC,6EAA6E;IAC7E,wEAAwE;IACxE,6BAA6B;IAC7BvC,0BAA0B;QACxB,MAAMiD,OAAOJ,QAAQK,OAAO;QAC5B,IAAI,CAACR,QAAQQ,OAAO,IAAI,CAACD,MAAM;YAC7B;QACF;QAEAL,SAASM,OAAO,GAAGD,KAAKE,WAAW,IAAI;QACvC5C,WAAW0C;IACb,GAAG;QAACJ;QAASb;KAAM;IAEnB,MAAMoB,cAAc3D,YAClB,CAACiB;QACC+B,SAAS/B,QAAQsB,KAAK;QACtBE,cAAcxB;QACd,IAAIA,QAAQ2C,MAAM,KAAK,uBAAuB;YAC5CN;QACF;IACF,GACA;QAACA;QAAWb;QAAeO;KAAS;IAEtC,MAAMa,YAAY7D,YAChB,CAAC8D;QACC,IAAIC,YACFxB,SAASgB,iBAAiBjC,OAAOC,OAAO;QAC1CwC,YAAYvD,YAAY;YAAEc;YAAKC;YAAKgB,OAAOwB,YAAYvC;QAAK;QAE5D,oDAAoD;QACpD,IAAIuC,cAAcxB,SAAS,OAAOjB,QAAQ,UAAU;YAClDyC,YAAYzC;QACd;QAEAqC,YAAY;YACVG;YACAF,QAAQ;YACRrB,OAAOwB;QACT;IACF,GACA;QAACR;QAAehC;QAAKD;QAAKE;QAAMmC;QAAapB;KAAM;IAErD,MAAMyB,YAAYhE,YAChB,CAAC8D;QACC,IAAIC,YACFxB,SAASgB,iBAAiBhC,OAAOD,OAAO;QAC1CyC,YAAYvD,YAAY;YAAEc;YAAKC;YAAKgB,OAAOwB,YAAYvC;QAAK;QAE5D,oDAAoD;QACpD,IAAIuC,cAAcxB,SAAS,OAAOhB,QAAQ,UAAU;YAClDwC,YAAYxC;QACd;QAEAoC,YAAY;YACVG;YACAF,QAAQ;YACRrB,OAAOwB;QACT;IACF,GACA;QAACR;QAAehC;QAAKD;QAAKE;QAAMmC;QAAapB;KAAM;IAGrD,OAAO;QACLA;QACAS;QACAiB,eAAeb;QACfc,iBAAiB;YACf,iBAAiBtC,YAAYuC;YAC7B,iBAAiBtC,YAAYsC;YAC7B,gBAAgBpC,SAASoC;YACzB,iBAAiBrC,YAAYqC;YAC7B,iBAAiB7C;YACjB,iBAAiBC;YACjB,iBAAiBgB,UAAU,OAAO4B,YAAY5B;YAC9C,kBAAkBI,aAAaJ;YAC/BrB;YACAE,KAAKiC;YACLe,MAAM;YACNC,gBAAgB;YAChBC,aAAa;YACbC,YAAY;YACZC,WAAW;YACXC,iBAAiB,CAAC5C,YAAYsC;YAC9BO,gCAAgC;YAChCC,UAAU9C,WAAWsC,YAAY;YACjCnC,QAAQ,CAAC8B;gBACP9B,OAAO8B;gBAEPb,QAAQQ,OAAO,GAAG;gBAClB7C,aAAakD,MAAMc,aAAa;YAClC;YACA3C,SAAS,CAAC6B;gBACR7B,QAAQ6B;gBAER,IAAIjC,UAAU;oBACZ;gBACF;gBAEAoB,QAAQQ,OAAO,GAAG;gBAClBP,WAAWO,OAAO,GAAG;gBACrB3C,WAAWgD,MAAMc,aAAa;YAChC;YACAxC,WAAW,CAAC0B;gBACV1B,UAAU0B;gBAEV,IAAIjC,YAAaD,YAAYkC,MAAMe,GAAG,KAAK,SAAU;oBACnD;gBACF;gBAEA,MAAM7B,WAAW,CAACe,YAChBJ,YAAY;wBAAEpB,OAAOwB;wBAAWD;wBAAOF,QAAQ;oBAAS;gBAE1D,IAAIkB,OAAO;gBACX,OAAQhB,MAAMe,GAAG;oBACf,KAAK;oBACL,KAAK;wBACH,gEAAgE;wBAChE,4DAA4D;wBAC5D,gEAAgE;wBAChE,mEAAmE;wBACnE,WAAW;wBACXf,MAAMiB,cAAc;wBACpB;oBACF,KAAK;wBACHD,OAAO;wBACPjB,UAAUC;wBACV;oBACF,KAAK;wBACHgB,OAAO;wBACPd,UAAUF;wBACV;oBACF,KAAK;wBACHgB,OAAO;wBACP,IAAI,OAAOxD,QAAQ,UAAU;4BAC3B0B,SAAS1B;wBACX;wBACA;oBACF,KAAK;wBACHwD,OAAO;wBACP,IAAI,OAAOvD,QAAQ,UAAU;4BAC3ByB,SAASzB;wBACX;wBACA;oBACF,KAAK;wBACHuD,OAAO;wBACP3E,uBAAuB2D,OAAOnC;gBAClC;gBAEA,IAAImD,MAAM;oBACRhB,MAAMiB,cAAc;oBACpBjB,MAAMkB,eAAe;oBACrB9B,WAAWO,OAAO,GAAG;gBACvB;YACF;YACAtB,SAAS,CAAC2B;gBACR3B,QAAQ2B;gBAERA,MAAMiB,cAAc;gBACpB,IAAIlD,UAAU;oBACZ;gBACF;gBAEAoB,QAAQQ,OAAO,GAAG;gBAClBP,WAAWO,OAAO,GAAG;gBACrB3C,WAAWgD,MAAMc,aAAa;YAChC;YACA1C,SAAS,CAAC4B;gBACR5B,QAAQ4B;gBAER,MAAMN,OAAOM,MAAMc,aAAa;gBAChC,oEAAoE;gBACpE,wCAAwC;gBACxC,IAAIhD,YAAYC,UAAU;oBACxB2B,KAAKE,WAAW,GAAGP,SAASM,OAAO;oBACnC3C,WAAW0C;oBACX;gBACF;gBAEA,MAAM,EAAEI,MAAM,EAAEG,SAAS,EAAE,GAAGlD,kBAAkB;oBAC9CS;oBACAC;oBACA0D,MAAMzB,KAAKE,WAAW,IAAI;oBAC1BpB;oBACAZ;oBACAyB,UAAUA,SAASM,OAAO;oBAC1ByB,WAAW3C;oBACXW,YAAYA,WAAWO,OAAO;gBAChC;gBAEA,IACEG,WAAW,YACXA,WAAW,aACXA,WAAW,uBACX;oBACAV,WAAWO,OAAO,GAAG;gBACvB,OAAO,IAAIG,WAAW,WAAW;oBAC/BV,WAAWO,OAAO;gBACpB;gBAEAD,KAAKE,WAAW,GAAGd,eAAe;oBAChCtB;oBACAC;oBACAE;oBACAC;oBACAa,OAAOwB;oBACP1B;oBACAQ;gBACF;gBACAM,SAASM,OAAO,GAAGD,KAAKE,WAAW;gBACnC5C,WAAW0C;gBAEX,IAAII,WAAW,aAAaA,WAAW,qBAAqB;oBAC1DD,YAAY;wBACVG;wBACAvB,OAAOwB;wBACPH;oBACF;gBACF;YACF;QACF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/spinbutton/useSpinButton.ts"],"sourcesContent":["\"use client\";\n\nimport { type Dispatch, useCallback, useRef, useState } from \"react\";\n\nimport { tryToSubmitRelatedForm } from \"../form/utils.js\";\nimport { useEnsuredId } from \"../useEnsuredId.js\";\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useEnsuredState } from \"../useEnsuredState.js\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect.js\";\nimport { withinRange } from \"../utils/withinRange.js\";\nimport { useSpinButtonGroup } from \"./SpinButtonGroupProvider.js\";\nimport {\n defaultGetSpinButtonTextContent,\n defaultSpinButtonGetValueText,\n} from \"./defaults.js\";\nimport {\n type SpinButtonChangeEvent,\n type SpinButtonChangeEventOptions,\n type SpinButtonImplementation,\n type SpinButtonOptions,\n type SpinButtonValue,\n} from \"./types.js\";\nimport { deselectNode } from \"./utils/deselectNode.js\";\nimport { resolveInputEvent } from \"./utils/resolveInputEvent.js\";\nimport { selectNode } from \"./utils/selectNode.js\";\n\n/**\n * @since 6.4.0\n */\nconst noop = (): void => {\n // do nothing\n};\n\n/**\n * @since 6.4.0\n */\nexport function useSpinButton<E extends HTMLElement = HTMLDivElement>(\n options: SpinButtonOptions<E>\n): SpinButtonImplementation<E> {\n const {\n id: propId,\n ref: propRef,\n min,\n max,\n step = 1,\n minDigits,\n maxDigits,\n form,\n readOnly,\n disabled,\n required,\n error,\n onBlur = noop,\n onFocus = noop,\n onInput = noop,\n onClick = noop,\n onKeyDown = noop,\n fallback,\n mappings,\n value: propValue,\n onValueChange = noop,\n defaultValue = null,\n getValueText = defaultSpinButtonGetValueText,\n getTextContent = defaultGetSpinButtonTextContent,\n placeholderChar,\n defaultKeyboardValue,\n } = options;\n const id = useEnsuredId(propId, \"spinbutton\");\n\n // trigger a noop setValue when `value` and `onValueChange` are provided\n // since `onValueChange is always called with `setValue\n let propSetValue: Dispatch<SpinButtonValue> | undefined;\n if (propValue !== undefined && options.onValueChange) {\n propSetValue = noop;\n }\n\n const [value, setValue] = useEnsuredState({\n value: propValue,\n setValue: propSetValue,\n defaultValue,\n });\n\n const focused = useRef(false);\n const typedCount = useRef(0);\n const prevText = useRef(\"\");\n const [nodeRef, nodeRefCallback] = useEnsuredRef(propRef);\n const { focusNext } = useSpinButtonGroup();\n const [keyboardValue] = useState(defaultKeyboardValue);\n\n // NOTE: I might be able to get rid of this since I don't remember why it was\n // added maybe for controlled fields? I'll have to see when I get to the\n // date/time components again\n useIsomorphicLayoutEffect(() => {\n const node = nodeRef.current;\n if (!focused.current || !node) {\n return;\n }\n\n prevText.current = node.textContent || \"\";\n selectNode(node);\n }, [nodeRef, value]);\n\n const updateValue = useCallback(\n (options: SpinButtonChangeEventOptions<E>) => {\n setValue(options.value);\n onValueChange(options);\n if (options.reason === \"typed-to-completion\") {\n focusNext();\n }\n },\n [focusNext, onValueChange, setValue]\n );\n const increment = useCallback(\n (event: SpinButtonChangeEvent<E>) => {\n let nextValue: SpinButtonValue =\n value ?? keyboardValue ?? min ?? max ?? 0;\n nextValue = withinRange({ min, max, value: nextValue + step });\n\n // this actually means both min and max are a number\n if (nextValue === value && typeof min === \"number\") {\n nextValue = min;\n }\n\n updateValue({\n event,\n reason: \"change\",\n value: nextValue,\n });\n },\n [keyboardValue, max, min, step, updateValue, value]\n );\n const decrement = useCallback(\n (event: SpinButtonChangeEvent<E>) => {\n let nextValue: SpinButtonValue =\n value ?? keyboardValue ?? max ?? min ?? 0;\n nextValue = withinRange({ min, max, value: nextValue - step });\n\n // this actually means both min and max are a number\n if (nextValue === value && typeof max === \"number\") {\n nextValue = max;\n }\n\n updateValue({\n event,\n reason: \"change\",\n value: nextValue,\n });\n },\n [keyboardValue, max, min, step, updateValue, value]\n );\n\n return {\n value,\n setValue,\n spinButtonRef: nodeRef,\n spinButtonProps: {\n \"aria-readonly\": readOnly || undefined,\n \"aria-disabled\": disabled || undefined,\n \"aria-invalid\": error || undefined,\n \"aria-required\": required || undefined,\n \"aria-valuemin\": min,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value === null ? undefined : value,\n \"aria-valuetext\": getValueText(value),\n id,\n ref: nodeRefCallback,\n role: \"spinbutton\",\n autoCapitalize: \"none\",\n autoCorrect: \"off\",\n spellCheck: false,\n inputMode: \"numeric\",\n contentEditable: !disabled || undefined,\n suppressContentEditableWarning: true,\n tabIndex: disabled ? undefined : 0,\n onBlur: (event) => {\n onBlur(event);\n\n focused.current = false;\n deselectNode(event.currentTarget);\n },\n onFocus: (event) => {\n onFocus(event);\n\n if (disabled) {\n return;\n }\n\n focused.current = true;\n typedCount.current = 0;\n selectNode(event.currentTarget);\n },\n onKeyDown: (event) => {\n onKeyDown(event);\n\n if (disabled || (readOnly && event.key !== \"Enter\")) {\n return;\n }\n\n const setValue = (nextValue: number): void =>\n updateValue({ value: nextValue, event, reason: \"change\" });\n\n let stop = false;\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowLeft\":\n // `event.stopPropagation()` should not be called here since the\n // parent `useSpinButtonGroup` keyboard event handler should\n // still be called to handle advancing to the next spinbutton in\n // the group. Only the default cursor movement needs to be disabled\n // instead.\n event.preventDefault();\n break;\n case \"ArrowUp\":\n stop = true;\n increment(event);\n break;\n case \"ArrowDown\":\n stop = true;\n decrement(event);\n break;\n case \"Home\":\n stop = true;\n if (typeof min === \"number\") {\n setValue(min);\n }\n break;\n case \"End\":\n stop = true;\n if (typeof max === \"number\") {\n setValue(max);\n }\n break;\n case \"Enter\":\n stop = true;\n tryToSubmitRelatedForm(event, form);\n }\n\n if (stop) {\n event.preventDefault();\n event.stopPropagation();\n typedCount.current = 0;\n }\n },\n onClick: (event) => {\n onClick(event);\n\n event.preventDefault();\n if (disabled) {\n return;\n }\n\n focused.current = true;\n typedCount.current = 0;\n selectNode(event.currentTarget);\n },\n onInput: (event) => {\n onInput(event);\n\n const node = event.currentTarget;\n // if the input event is fired while readOnly or disabled, ignore it\n // and set it back to the previous state\n if (readOnly || disabled) {\n node.textContent = prevText.current;\n selectNode(node);\n return;\n }\n\n const { reason, nextValue } = resolveInputEvent({\n min,\n max,\n text: node.textContent || \"\",\n mappings,\n maxDigits,\n prevText: prevText.current,\n prevValue: value,\n typedCount: typedCount.current,\n });\n\n if (\n reason === \"change\" ||\n reason === \"cleared\" ||\n reason === \"typed-to-completion\"\n ) {\n typedCount.current = 0;\n } else if (reason !== \"ignored\") {\n typedCount.current++;\n }\n\n node.textContent = getTextContent({\n min,\n max,\n minDigits,\n maxDigits,\n value: nextValue,\n fallback,\n placeholderChar,\n });\n prevText.current = node.textContent;\n selectNode(node);\n\n if (reason !== \"ignored\" && reason !== \"placeholder-digit\") {\n updateValue({\n event,\n value: nextValue,\n reason,\n });\n }\n },\n },\n };\n}\n"],"names":["useCallback","useRef","useState","tryToSubmitRelatedForm","useEnsuredId","useEnsuredRef","useEnsuredState","useIsomorphicLayoutEffect","withinRange","useSpinButtonGroup","defaultGetSpinButtonTextContent","defaultSpinButtonGetValueText","deselectNode","resolveInputEvent","selectNode","noop","useSpinButton","options","id","propId","ref","propRef","min","max","step","minDigits","maxDigits","form","readOnly","disabled","required","error","onBlur","onFocus","onInput","onClick","onKeyDown","fallback","mappings","value","propValue","onValueChange","defaultValue","getValueText","getTextContent","placeholderChar","defaultKeyboardValue","propSetValue","undefined","setValue","focused","typedCount","prevText","nodeRef","nodeRefCallback","focusNext","keyboardValue","node","current","textContent","updateValue","reason","increment","event","nextValue","decrement","spinButtonRef","spinButtonProps","role","autoCapitalize","autoCorrect","spellCheck","inputMode","contentEditable","suppressContentEditableWarning","tabIndex","currentTarget","key","stop","preventDefault","stopPropagation","text","prevValue"],"mappings":"AAAA;AAEA,SAAwBA,WAAW,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAErE,SAASC,sBAAsB,QAAQ,mBAAmB;AAC1D,SAASC,YAAY,QAAQ,qBAAqB;AAClD,SAASC,aAAa,QAAQ,sBAAsB;AACpD,SAASC,eAAe,QAAQ,wBAAwB;AACxD,SAASC,yBAAyB,QAAQ,kCAAkC;AAC5E,SAASC,WAAW,QAAQ,0BAA0B;AACtD,SAASC,kBAAkB,QAAQ,+BAA+B;AAClE,SACEC,+BAA+B,EAC/BC,6BAA6B,QACxB,gBAAgB;AAQvB,SAASC,YAAY,QAAQ,0BAA0B;AACvD,SAASC,iBAAiB,QAAQ,+BAA+B;AACjE,SAASC,UAAU,QAAQ,wBAAwB;AAEnD;;CAEC,GACD,MAAMC,OAAO;AACX,aAAa;AACf;AAEA;;CAEC,GACD,OAAO,SAASC,cACdC,OAA6B;IAE7B,MAAM,EACJC,IAAIC,MAAM,EACVC,KAAKC,OAAO,EACZC,GAAG,EACHC,GAAG,EACHC,OAAO,CAAC,EACRC,SAAS,EACTC,SAAS,EACTC,IAAI,EACJC,QAAQ,EACRC,QAAQ,EACRC,QAAQ,EACRC,KAAK,EACLC,SAASjB,IAAI,EACbkB,UAAUlB,IAAI,EACdmB,UAAUnB,IAAI,EACdoB,UAAUpB,IAAI,EACdqB,YAAYrB,IAAI,EAChBsB,QAAQ,EACRC,QAAQ,EACRC,OAAOC,SAAS,EAChBC,gBAAgB1B,IAAI,EACpB2B,eAAe,IAAI,EACnBC,eAAehC,6BAA6B,EAC5CiC,iBAAiBlC,+BAA+B,EAChDmC,eAAe,EACfC,oBAAoB,EACrB,GAAG7B;IACJ,MAAMC,KAAKd,aAAae,QAAQ;IAEhC,wEAAwE;IACxE,wDAAwD;IACxD,IAAI4B;IACJ,IAAIP,cAAcQ,aAAa/B,QAAQwB,aAAa,EAAE;QACpDM,eAAehC;IACjB;IAEA,MAAM,CAACwB,OAAOU,SAAS,GAAG3C,gBAAgB;QACxCiC,OAAOC;QACPS,UAAUF;QACVL;IACF;IAEA,MAAMQ,UAAUjD,OAAO;IACvB,MAAMkD,aAAalD,OAAO;IAC1B,MAAMmD,WAAWnD,OAAO;IACxB,MAAM,CAACoD,SAASC,gBAAgB,GAAGjD,cAAcgB;IACjD,MAAM,EAAEkC,SAAS,EAAE,GAAG9C;IACtB,MAAM,CAAC+C,cAAc,GAAGtD,SAAS4C;IAEjC,6EAA6E;IAC7E,wEAAwE;IACxE,6BAA6B;IAC7BvC,0BAA0B;QACxB,MAAMkD,OAAOJ,QAAQK,OAAO;QAC5B,IAAI,CAACR,QAAQQ,OAAO,IAAI,CAACD,MAAM;YAC7B;QACF;QAEAL,SAASM,OAAO,GAAGD,KAAKE,WAAW,IAAI;QACvC7C,WAAW2C;IACb,GAAG;QAACJ;QAASd;KAAM;IAEnB,MAAMqB,cAAc5D,YAClB,CAACiB;QACCgC,SAAShC,QAAQsB,KAAK;QACtBE,cAAcxB;QACd,IAAIA,QAAQ4C,MAAM,KAAK,uBAAuB;YAC5CN;QACF;IACF,GACA;QAACA;QAAWd;QAAeQ;KAAS;IAEtC,MAAMa,YAAY9D,YAChB,CAAC+D;QACC,IAAIC,YACFzB,SAASiB,iBAAiBlC,OAAOC,OAAO;QAC1CyC,YAAYxD,YAAY;YAAEc;YAAKC;YAAKgB,OAAOyB,YAAYxC;QAAK;QAE5D,oDAAoD;QACpD,IAAIwC,cAAczB,SAAS,OAAOjB,QAAQ,UAAU;YAClD0C,YAAY1C;QACd;QAEAsC,YAAY;YACVG;YACAF,QAAQ;YACRtB,OAAOyB;QACT;IACF,GACA;QAACR;QAAejC;QAAKD;QAAKE;QAAMoC;QAAarB;KAAM;IAErD,MAAM0B,YAAYjE,YAChB,CAAC+D;QACC,IAAIC,YACFzB,SAASiB,iBAAiBjC,OAAOD,OAAO;QAC1C0C,YAAYxD,YAAY;YAAEc;YAAKC;YAAKgB,OAAOyB,YAAYxC;QAAK;QAE5D,oDAAoD;QACpD,IAAIwC,cAAczB,SAAS,OAAOhB,QAAQ,UAAU;YAClDyC,YAAYzC;QACd;QAEAqC,YAAY;YACVG;YACAF,QAAQ;YACRtB,OAAOyB;QACT;IACF,GACA;QAACR;QAAejC;QAAKD;QAAKE;QAAMoC;QAAarB;KAAM;IAGrD,OAAO;QACLA;QACAU;QACAiB,eAAeb;QACfc,iBAAiB;YACf,iBAAiBvC,YAAYoB;YAC7B,iBAAiBnB,YAAYmB;YAC7B,gBAAgBjB,SAASiB;YACzB,iBAAiBlB,YAAYkB;YAC7B,iBAAiB1B;YACjB,iBAAiBC;YACjB,iBAAiBgB,UAAU,OAAOS,YAAYT;YAC9C,kBAAkBI,aAAaJ;YAC/BrB;YACAE,KAAKkC;YACLc,MAAM;YACNC,gBAAgB;YAChBC,aAAa;YACbC,YAAY;YACZC,WAAW;YACXC,iBAAiB,CAAC5C,YAAYmB;YAC9B0B,gCAAgC;YAChCC,UAAU9C,WAAWmB,YAAY;YACjChB,QAAQ,CAAC+B;gBACP/B,OAAO+B;gBAEPb,QAAQQ,OAAO,GAAG;gBAClB9C,aAAamD,MAAMa,aAAa;YAClC;YACA3C,SAAS,CAAC8B;gBACR9B,QAAQ8B;gBAER,IAAIlC,UAAU;oBACZ;gBACF;gBAEAqB,QAAQQ,OAAO,GAAG;gBAClBP,WAAWO,OAAO,GAAG;gBACrB5C,WAAWiD,MAAMa,aAAa;YAChC;YACAxC,WAAW,CAAC2B;gBACV3B,UAAU2B;gBAEV,IAAIlC,YAAaD,YAAYmC,MAAMc,GAAG,KAAK,SAAU;oBACnD;gBACF;gBAEA,MAAM5B,WAAW,CAACe,YAChBJ,YAAY;wBAAErB,OAAOyB;wBAAWD;wBAAOF,QAAQ;oBAAS;gBAE1D,IAAIiB,OAAO;gBACX,OAAQf,MAAMc,GAAG;oBACf,KAAK;oBACL,KAAK;wBACH,gEAAgE;wBAChE,4DAA4D;wBAC5D,gEAAgE;wBAChE,mEAAmE;wBACnE,WAAW;wBACXd,MAAMgB,cAAc;wBACpB;oBACF,KAAK;wBACHD,OAAO;wBACPhB,UAAUC;wBACV;oBACF,KAAK;wBACHe,OAAO;wBACPb,UAAUF;wBACV;oBACF,KAAK;wBACHe,OAAO;wBACP,IAAI,OAAOxD,QAAQ,UAAU;4BAC3B2B,SAAS3B;wBACX;wBACA;oBACF,KAAK;wBACHwD,OAAO;wBACP,IAAI,OAAOvD,QAAQ,UAAU;4BAC3B0B,SAAS1B;wBACX;wBACA;oBACF,KAAK;wBACHuD,OAAO;wBACP3E,uBAAuB4D,OAAOpC;gBAClC;gBAEA,IAAImD,MAAM;oBACRf,MAAMgB,cAAc;oBACpBhB,MAAMiB,eAAe;oBACrB7B,WAAWO,OAAO,GAAG;gBACvB;YACF;YACAvB,SAAS,CAAC4B;gBACR5B,QAAQ4B;gBAERA,MAAMgB,cAAc;gBACpB,IAAIlD,UAAU;oBACZ;gBACF;gBAEAqB,QAAQQ,OAAO,GAAG;gBAClBP,WAAWO,OAAO,GAAG;gBACrB5C,WAAWiD,MAAMa,aAAa;YAChC;YACA1C,SAAS,CAAC6B;gBACR7B,QAAQ6B;gBAER,MAAMN,OAAOM,MAAMa,aAAa;gBAChC,oEAAoE;gBACpE,wCAAwC;gBACxC,IAAIhD,YAAYC,UAAU;oBACxB4B,KAAKE,WAAW,GAAGP,SAASM,OAAO;oBACnC5C,WAAW2C;oBACX;gBACF;gBAEA,MAAM,EAAEI,MAAM,EAAEG,SAAS,EAAE,GAAGnD,kBAAkB;oBAC9CS;oBACAC;oBACA0D,MAAMxB,KAAKE,WAAW,IAAI;oBAC1BrB;oBACAZ;oBACA0B,UAAUA,SAASM,OAAO;oBAC1BwB,WAAW3C;oBACXY,YAAYA,WAAWO,OAAO;gBAChC;gBAEA,IACEG,WAAW,YACXA,WAAW,aACXA,WAAW,uBACX;oBACAV,WAAWO,OAAO,GAAG;gBACvB,OAAO,IAAIG,WAAW,WAAW;oBAC/BV,WAAWO,OAAO;gBACpB;gBAEAD,KAAKE,WAAW,GAAGf,eAAe;oBAChCtB;oBACAC;oBACAE;oBACAC;oBACAa,OAAOyB;oBACP3B;oBACAQ;gBACF;gBACAO,SAASM,OAAO,GAAGD,KAAKE,WAAW;gBACnC7C,WAAW2C;gBAEX,IAAII,WAAW,aAAaA,WAAW,qBAAqB;oBAC1DD,YAAY;wBACVG;wBACAxB,OAAOyB;wBACPH;oBACF;gBACF;YACF;QACF;IACF;AACF"}
@@ -2,7 +2,7 @@
2
2
  * @since 6.4.0
3
3
  * @internal
4
4
  */ export function deselectNode(node) {
5
- const selection = window.getSelection();
5
+ const selection = globalThis.getSelection();
6
6
  if (!selection) {
7
7
  return;
8
8
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/spinbutton/utils/deselectNode.ts"],"sourcesContent":["/**\n * @since 6.4.0\n * @internal\n */\nexport function deselectNode(node: Node): void {\n const selection = window.getSelection();\n if (!selection) {\n return;\n }\n\n for (let i = 0; i < selection.rangeCount; i++) {\n const range = selection.getRangeAt(i);\n if (range.startContainer.contains(node)) {\n selection.removeRange(range);\n }\n }\n}\n"],"names":["deselectNode","node","selection","window","getSelection","i","rangeCount","range","getRangeAt","startContainer","contains","removeRange"],"mappings":"AAAA;;;CAGC,GACD,OAAO,SAASA,aAAaC,IAAU;IACrC,MAAMC,YAAYC,OAAOC,YAAY;IACrC,IAAI,CAACF,WAAW;QACd;IACF;IAEA,IAAK,IAAIG,IAAI,GAAGA,IAAIH,UAAUI,UAAU,EAAED,IAAK;QAC7C,MAAME,QAAQL,UAAUM,UAAU,CAACH;QACnC,IAAIE,MAAME,cAAc,CAACC,QAAQ,CAACT,OAAO;YACvCC,UAAUS,WAAW,CAACJ;QACxB;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/spinbutton/utils/deselectNode.ts"],"sourcesContent":["/**\n * @since 6.4.0\n * @internal\n */\nexport function deselectNode(node: Node): void {\n const selection = globalThis.getSelection();\n if (!selection) {\n return;\n }\n\n for (let i = 0; i < selection.rangeCount; i++) {\n const range = selection.getRangeAt(i);\n if (range.startContainer.contains(node)) {\n selection.removeRange(range);\n }\n }\n}\n"],"names":["deselectNode","node","selection","globalThis","getSelection","i","rangeCount","range","getRangeAt","startContainer","contains","removeRange"],"mappings":"AAAA;;;CAGC,GACD,OAAO,SAASA,aAAaC,IAAU;IACrC,MAAMC,YAAYC,WAAWC,YAAY;IACzC,IAAI,CAACF,WAAW;QACd;IACF;IAEA,IAAK,IAAIG,IAAI,GAAGA,IAAIH,UAAUI,UAAU,EAAED,IAAK;QAC7C,MAAME,QAAQL,UAAUM,UAAU,CAACH;QACnC,IAAIE,MAAME,cAAc,CAACC,QAAQ,CAACT,OAAO;YACvCC,UAAUS,WAAW,CAACJ;QACxB;IACF;AACF"}
@@ -32,7 +32,7 @@ import { getNumberOfDigits } from "../../utils/getNumberOfDigits.js";
32
32
  };
33
33
  }
34
34
  let reason = "type";
35
- let nextValue = parseInt(prevText + text, 10);
35
+ let nextValue = Number.parseInt(prevText + text, 10);
36
36
  if (typeof minDigits === "number" && typedCount + 1 < minDigits) {
37
37
  reason = "placeholder-digit";
38
38
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/spinbutton/utils/resolveInputEvent.ts"],"sourcesContent":["import { type MinMaxRange } from \"../../types.js\";\nimport { getNumberOfDigits } from \"../../utils/getNumberOfDigits.js\";\nimport {\n type SpinButtonChangeReason,\n type SpinButtonCharacterValueMap,\n type SpinButtonValue,\n} from \"../types.js\";\n\n/**\n * @since 6.4.0\n * @internal\n */\ninterface ResolveInputEventOptions extends Partial<MinMaxRange> {\n text: string;\n mappings?: SpinButtonCharacterValueMap;\n minDigits?: number;\n maxDigits?: number;\n prevText: string;\n prevValue: SpinButtonValue;\n typedCount: number;\n}\n\ntype SpinButtonResolvedInputReason =\n | SpinButtonChangeReason\n | \"ignored\"\n | \"placeholder-digit\";\n\n/**\n * @since 6.4.0\n * @internal\n */\ninterface ResolveInputEvent {\n reason: SpinButtonResolvedInputReason;\n nextValue: SpinButtonValue;\n}\n\n/**\n * @since 6.4.0\n * @internal\n */\nexport function resolveInputEvent(\n options: ResolveInputEventOptions\n): ResolveInputEvent {\n const {\n min,\n max,\n minDigits = getNumberOfDigits(min),\n maxDigits = getNumberOfDigits(max),\n text,\n mappings,\n typedCount,\n prevValue,\n } = options;\n\n let { prevText } = options;\n if (typedCount === 0) {\n prevText = \"\";\n }\n\n if (!text) {\n return {\n reason: \"cleared\",\n nextValue: null,\n };\n }\n\n if (mappings) {\n const nextValue = mappings[text] ?? prevValue;\n\n let reason: SpinButtonResolvedInputReason = \"ignored\";\n if (typeof mappings[text] === \"number\") {\n reason = \"typed-to-completion\";\n }\n\n return {\n reason,\n nextValue,\n };\n }\n\n if (/[^0-9]/.test(text)) {\n return {\n reason: \"ignored\",\n nextValue: prevValue,\n };\n }\n\n let reason: SpinButtonResolvedInputReason = \"type\";\n let nextValue: SpinButtonValue = parseInt(prevText + text, 10);\n if (typeof minDigits === \"number\" && typedCount + 1 < minDigits) {\n reason = \"placeholder-digit\";\n }\n\n if (typeof max === \"number\" && nextValue > max) {\n nextValue = prevValue;\n }\n\n if (\n typeof nextValue === \"number\" &&\n // if typing a new value surpasses the number of digits allowed\n ((typeof maxDigits === \"number\" && typedCount + 1 >= maxDigits) ||\n // typing a new value would exceed the max value\n (typeof max === \"number\" && nextValue * 10 > max))\n ) {\n reason = \"typed-to-completion\";\n }\n\n return {\n reason,\n nextValue,\n };\n}\n"],"names":["getNumberOfDigits","resolveInputEvent","options","min","max","minDigits","maxDigits","text","mappings","typedCount","prevValue","prevText","reason","nextValue","test","parseInt"],"mappings":"AACA,SAASA,iBAAiB,QAAQ,mCAAmC;AAmCrE;;;CAGC,GACD,OAAO,SAASC,kBACdC,OAAiC;IAEjC,MAAM,EACJC,GAAG,EACHC,GAAG,EACHC,YAAYL,kBAAkBG,IAAI,EAClCG,YAAYN,kBAAkBI,IAAI,EAClCG,IAAI,EACJC,QAAQ,EACRC,UAAU,EACVC,SAAS,EACV,GAAGR;IAEJ,IAAI,EAAES,QAAQ,EAAE,GAAGT;IACnB,IAAIO,eAAe,GAAG;QACpBE,WAAW;IACb;IAEA,IAAI,CAACJ,MAAM;QACT,OAAO;YACLK,QAAQ;YACRC,WAAW;QACb;IACF;IAEA,IAAIL,UAAU;QACZ,MAAMK,YAAYL,QAAQ,CAACD,KAAK,IAAIG;QAEpC,IAAIE,SAAwC;QAC5C,IAAI,OAAOJ,QAAQ,CAACD,KAAK,KAAK,UAAU;YACtCK,SAAS;QACX;QAEA,OAAO;YACLA;YACAC;QACF;IACF;IAEA,IAAI,SAASC,IAAI,CAACP,OAAO;QACvB,OAAO;YACLK,QAAQ;YACRC,WAAWH;QACb;IACF;IAEA,IAAIE,SAAwC;IAC5C,IAAIC,YAA6BE,SAASJ,WAAWJ,MAAM;IAC3D,IAAI,OAAOF,cAAc,YAAYI,aAAa,IAAIJ,WAAW;QAC/DO,SAAS;IACX;IAEA,IAAI,OAAOR,QAAQ,YAAYS,YAAYT,KAAK;QAC9CS,YAAYH;IACd;IAEA,IACE,OAAOG,cAAc,YACrB,+DAA+D;IAC9D,CAAA,AAAC,OAAOP,cAAc,YAAYG,aAAa,KAAKH,aACnD,gDAAgD;IAC/C,OAAOF,QAAQ,YAAYS,YAAY,KAAKT,GAAG,GAClD;QACAQ,SAAS;IACX;IAEA,OAAO;QACLA;QACAC;IACF;AACF"}
1
+ {"version":3,"sources":["../../../src/spinbutton/utils/resolveInputEvent.ts"],"sourcesContent":["import { type MinMaxRange } from \"../../types.js\";\nimport { getNumberOfDigits } from \"../../utils/getNumberOfDigits.js\";\nimport {\n type SpinButtonChangeReason,\n type SpinButtonCharacterValueMap,\n type SpinButtonValue,\n} from \"../types.js\";\n\n/**\n * @since 6.4.0\n * @internal\n */\ninterface ResolveInputEventOptions extends Partial<MinMaxRange> {\n text: string;\n mappings?: SpinButtonCharacterValueMap;\n minDigits?: number;\n maxDigits?: number;\n prevText: string;\n prevValue: SpinButtonValue;\n typedCount: number;\n}\n\ntype SpinButtonResolvedInputReason =\n | SpinButtonChangeReason\n | \"ignored\"\n | \"placeholder-digit\";\n\n/**\n * @since 6.4.0\n * @internal\n */\ninterface ResolveInputEvent {\n reason: SpinButtonResolvedInputReason;\n nextValue: SpinButtonValue;\n}\n\n/**\n * @since 6.4.0\n * @internal\n */\nexport function resolveInputEvent(\n options: ResolveInputEventOptions\n): ResolveInputEvent {\n const {\n min,\n max,\n minDigits = getNumberOfDigits(min),\n maxDigits = getNumberOfDigits(max),\n text,\n mappings,\n typedCount,\n prevValue,\n } = options;\n\n let { prevText } = options;\n if (typedCount === 0) {\n prevText = \"\";\n }\n\n if (!text) {\n return {\n reason: \"cleared\",\n nextValue: null,\n };\n }\n\n if (mappings) {\n const nextValue = mappings[text] ?? prevValue;\n\n let reason: SpinButtonResolvedInputReason = \"ignored\";\n if (typeof mappings[text] === \"number\") {\n reason = \"typed-to-completion\";\n }\n\n return {\n reason,\n nextValue,\n };\n }\n\n if (/[^0-9]/.test(text)) {\n return {\n reason: \"ignored\",\n nextValue: prevValue,\n };\n }\n\n let reason: SpinButtonResolvedInputReason = \"type\";\n let nextValue: SpinButtonValue = Number.parseInt(prevText + text, 10);\n if (typeof minDigits === \"number\" && typedCount + 1 < minDigits) {\n reason = \"placeholder-digit\";\n }\n\n if (typeof max === \"number\" && nextValue > max) {\n nextValue = prevValue;\n }\n\n if (\n typeof nextValue === \"number\" &&\n // if typing a new value surpasses the number of digits allowed\n ((typeof maxDigits === \"number\" && typedCount + 1 >= maxDigits) ||\n // typing a new value would exceed the max value\n (typeof max === \"number\" && nextValue * 10 > max))\n ) {\n reason = \"typed-to-completion\";\n }\n\n return {\n reason,\n nextValue,\n };\n}\n"],"names":["getNumberOfDigits","resolveInputEvent","options","min","max","minDigits","maxDigits","text","mappings","typedCount","prevValue","prevText","reason","nextValue","test","Number","parseInt"],"mappings":"AACA,SAASA,iBAAiB,QAAQ,mCAAmC;AAmCrE;;;CAGC,GACD,OAAO,SAASC,kBACdC,OAAiC;IAEjC,MAAM,EACJC,GAAG,EACHC,GAAG,EACHC,YAAYL,kBAAkBG,IAAI,EAClCG,YAAYN,kBAAkBI,IAAI,EAClCG,IAAI,EACJC,QAAQ,EACRC,UAAU,EACVC,SAAS,EACV,GAAGR;IAEJ,IAAI,EAAES,QAAQ,EAAE,GAAGT;IACnB,IAAIO,eAAe,GAAG;QACpBE,WAAW;IACb;IAEA,IAAI,CAACJ,MAAM;QACT,OAAO;YACLK,QAAQ;YACRC,WAAW;QACb;IACF;IAEA,IAAIL,UAAU;QACZ,MAAMK,YAAYL,QAAQ,CAACD,KAAK,IAAIG;QAEpC,IAAIE,SAAwC;QAC5C,IAAI,OAAOJ,QAAQ,CAACD,KAAK,KAAK,UAAU;YACtCK,SAAS;QACX;QAEA,OAAO;YACLA;YACAC;QACF;IACF;IAEA,IAAI,SAASC,IAAI,CAACP,OAAO;QACvB,OAAO;YACLK,QAAQ;YACRC,WAAWH;QACb;IACF;IAEA,IAAIE,SAAwC;IAC5C,IAAIC,YAA6BE,OAAOC,QAAQ,CAACL,WAAWJ,MAAM;IAClE,IAAI,OAAOF,cAAc,YAAYI,aAAa,IAAIJ,WAAW;QAC/DO,SAAS;IACX;IAEA,IAAI,OAAOR,QAAQ,YAAYS,YAAYT,KAAK;QAC9CS,YAAYH;IACd;IAEA,IACE,OAAOG,cAAc,YACrB,+DAA+D;IAC9D,CAAA,AAAC,OAAOP,cAAc,YAAYG,aAAa,KAAKH,aACnD,gDAAgD;IAC/C,OAAOF,QAAQ,YAAYS,YAAY,KAAKT,GAAG,GAClD;QACAQ,SAAS;IACX;IAEA,OAAO;QACLA;QACAC;IACF;AACF"}
@@ -2,7 +2,7 @@
2
2
  * @since 6.4.0
3
3
  * @internal
4
4
  */ export function selectNode(node) {
5
- const selection = window.getSelection();
5
+ const selection = globalThis.getSelection();
6
6
  if (!selection) {
7
7
  return;
8
8
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/spinbutton/utils/selectNode.ts"],"sourcesContent":["/**\n * @since 6.4.0\n * @internal\n */\nexport function selectNode(node: Node): void {\n const selection = window.getSelection();\n if (!selection) {\n return;\n }\n\n const range = document.createRange();\n range.selectNodeContents(node);\n selection.removeAllRanges();\n selection.addRange(range);\n}\n"],"names":["selectNode","node","selection","window","getSelection","range","document","createRange","selectNodeContents","removeAllRanges","addRange"],"mappings":"AAAA;;;CAGC,GACD,OAAO,SAASA,WAAWC,IAAU;IACnC,MAAMC,YAAYC,OAAOC,YAAY;IACrC,IAAI,CAACF,WAAW;QACd;IACF;IAEA,MAAMG,QAAQC,SAASC,WAAW;IAClCF,MAAMG,kBAAkB,CAACP;IACzBC,UAAUO,eAAe;IACzBP,UAAUQ,QAAQ,CAACL;AACrB"}
1
+ {"version":3,"sources":["../../../src/spinbutton/utils/selectNode.ts"],"sourcesContent":["/**\n * @since 6.4.0\n * @internal\n */\nexport function selectNode(node: Node): void {\n const selection = globalThis.getSelection();\n if (!selection) {\n return;\n }\n\n const range = document.createRange();\n range.selectNodeContents(node);\n selection.removeAllRanges();\n selection.addRange(range);\n}\n"],"names":["selectNode","node","selection","globalThis","getSelection","range","document","createRange","selectNodeContents","removeAllRanges","addRange"],"mappings":"AAAA;;;CAGC,GACD,OAAO,SAASA,WAAWC,IAAU;IACnC,MAAMC,YAAYC,WAAWC,YAAY;IACzC,IAAI,CAACF,WAAW;QACd;IACF;IAEA,MAAMG,QAAQC,SAASC,WAAW;IAClCF,MAAMG,kBAAkB,CAACP;IACzBC,UAAUO,eAAe;IACzBP,UAAUQ,QAAQ,CAACL;AACrB"}
@@ -164,7 +164,12 @@ import { getItemFromStorage, removeItemFromStorage, setItemInStorage } from "./u
164
164
  const setValue = useCallback((valueOrDispatcher)=>{
165
165
  const { key, manual, storage, serializer } = config.current;
166
166
  setStoredValue((prevValue)=>{
167
- const nextValue = valueOrDispatcher instanceof Function ? valueOrDispatcher(prevValue) : valueOrDispatcher;
167
+ const nextValue = // this has to still use `instanceof` because of the T generic. Using
168
+ // `T extends ...` restricts the types too much if providing a
169
+ // `defaultValue`
170
+ //
171
+ // eslint-disable-next-line unicorn/no-instanceof-builtins
172
+ valueOrDispatcher instanceof Function ? valueOrDispatcher(prevValue) : valueOrDispatcher;
168
173
  if (!manual && nextValue !== prevValue) {
169
174
  setItemInStorage({
170
175
  key,
@@ -230,9 +235,9 @@ import { getItemFromStorage, removeItemFromStorage, setItemInStorage } from "./u
230
235
  }));
231
236
  }
232
237
  };
233
- window.addEventListener("storage", callback);
238
+ globalThis.addEventListener("storage", callback);
234
239
  return ()=>{
235
- window.removeEventListener("storage", callback);
240
+ globalThis.removeEventListener("storage", callback);
236
241
  };
237
242
  }, [
238
243
  key
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/storage/useStorage.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { useSsr } from \"../SsrProvider.js\";\nimport { type UseStateSetter } from \"../types.js\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect.js\";\nimport { getStorageSerializers } from \"./internalUtils.js\";\nimport { type StorageImplementation, type StorageOptions } from \"./types.js\";\nimport {\n getItemFromStorage,\n removeItemFromStorage,\n setItemInStorage,\n} from \"./utils.js\";\n\n/**\n * The `useStorage` hook can be used to read and write from `localStorage`\n * (default) or `sessionStorage`. The default behavior will automatically sync\n * the value across tabs using the `StorageEvent`.\n *\n * @example Simple Example\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useStorage } from \"@react-md/core/storage/useStorage\";\n * import { type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { value, setValue } = useStorage({\n * key: \"savedSearch\",\n * defaultValue: \"\",\n * });\n *\n * return (\n * <TextField\n * label=\"Search\"\n * placeholder=\"Search...\"\n * type=\"search\"\n * value={value}\n * onChange={(event) => {\n * setValue(event.currentTarget.value)\n * }}\n * />\n * );\n * }\n * ```\n *\n * @example Type-safe Objects\n * ```tsx\n * import { useStorage } from \"@react-md/core/storage/useStorage\";\n * import { type ReactElement } from \"react\";\n *\n * interface ExpectedSchema {\n * label: string;\n * value: string;\n * // others\n * }\n *\n * function Example(): ReactElement {\n * const { value, setValue } = useStorage<ExpectedSchema | null>({\n * key: \"someKey\",\n * defaultValue: null,\n *\n * // this is optional: you can create a custom deserializer to validate\n * // the stored value to prevent people manually updating local storage in\n * // the dev tools\n * deserializer(item) {\n * const parsed = JSON.parse(item):\n * const { label, value } = parsed;\n * if (typeof label !== 'string' || typeof value !== 'string') {\n * return null;\n * }\n *\n * return { label, value };\n * }\n * });\n *\n * // do something\n * // value will be `ExpectedSchema | null`\n * }\n * ```\n *\n * @example Manual Persistence\n * ```tsx\n * import { Button } from \"@react-md/core/button/Button\";\n * import { Checkbox } from \"@react-md/core/form/Checkbox\";\n * import { Form } from \"@react-md/core/form/Form\";\n * import { useStorage } from \"@react-md/core/storage/useStorage\";\n * import { type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { value, setValue, remove, persist } = useStorage({\n * key: \"someKey\",\n * manual: true,\n * defaultValue: false,\n * });\n *\n * return (\n * <Form\n * onSubmit={() => {\n * // current value will be saved into local storage\n * persist();\n * }}\n * onReset={() => {\n * // \"someKey\" will be removed from local storage\n * remove();\n * }}\n * >\n * <Checkbox\n * label=\"Allow cookies\"\n * checked={value}\n * onChange={(event) =>\n * setValue(event.currentTarget.checked);\n * }\n * />\n * <Button type=\"reset\">Decline</Button>\n * <Button type=\"submit\">Save</Button>\n * </Form>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/hooks/use-storage | useStorage Demos}\n * @see https://developer.mozilla.org/en-US/docs/Web/API/StorageEvent\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage\n * @since 6.0.0\n */\nexport function useStorage<T>(\n options: StorageOptions<T>\n): StorageImplementation<T> {\n const {\n key,\n defaultValue,\n manual,\n storage = globalThis.localStorage,\n } = options;\n\n const [initialValue] = useState(defaultValue);\n const { serializer, deserializer } = useMemo(\n () =>\n getStorageSerializers({\n raw: options.raw,\n serializer: options.serializer,\n deserializer: options.deserializer,\n initialValue,\n }),\n [initialValue, options.deserializer, options.raw, options.serializer]\n );\n\n const ssr = useSsr();\n const [value, setStoredValue] = useState<T>(() => {\n if (ssr) {\n return initialValue;\n }\n\n return getItemFromStorage({\n key,\n storage,\n fallback: initialValue,\n deserializer,\n });\n });\n\n const config = useRef({\n key,\n value,\n manual,\n storage,\n serializer,\n deserializer,\n defaultValue: initialValue,\n } as const);\n useIsomorphicLayoutEffect(() => {\n config.current = {\n key,\n value,\n manual,\n storage,\n serializer,\n deserializer,\n defaultValue: initialValue,\n };\n });\n\n const setValue = useCallback<UseStateSetter<T>>((valueOrDispatcher) => {\n const { key, manual, storage, serializer } = config.current;\n\n setStoredValue((prevValue) => {\n const nextValue =\n valueOrDispatcher instanceof Function\n ? valueOrDispatcher(prevValue)\n : valueOrDispatcher;\n\n if (!manual && nextValue !== prevValue) {\n setItemInStorage({\n key,\n value: nextValue,\n storage,\n serializer,\n });\n }\n\n return nextValue;\n });\n }, []);\n\n const remove = useCallback(() => {\n removeItemFromStorage(config.current);\n }, []);\n\n const persist = useCallback(() => {\n setItemInStorage(config.current);\n }, []);\n\n // make sure to sync the value in local storage\n useEffect(() => {\n const { value, manual, storage, serializer } = config.current;\n if (ssr || !key || !value || manual || !storage) {\n return;\n }\n\n setItemInStorage({\n key,\n value,\n storage,\n serializer,\n });\n }, [key, ssr]);\n useEffect(() => {\n const { defaultValue, storage, deserializer, manual } = config.current;\n if (manual || !ssr) {\n return;\n }\n\n // do not want to trigger the emit behavior for rehydration\n setStoredValue(\n getItemFromStorage({\n key,\n storage,\n fallback: defaultValue,\n deserializer,\n })\n );\n }, [key, ssr]);\n\n // update the value if another tab changed the local storage value\n useEffect(() => {\n if (!key) {\n return;\n }\n\n const callback = (event: StorageEvent): void => {\n const { storage, defaultValue, deserializer } = config.current;\n if (event.key === key && event.storageArea === storage) {\n setStoredValue(\n getItemFromStorage({\n key,\n storage,\n fallback: defaultValue,\n deserializer,\n })\n );\n }\n };\n\n window.addEventListener(\"storage\", callback);\n return () => {\n window.removeEventListener(\"storage\", callback);\n };\n }, [key]);\n\n return {\n value,\n setValue,\n remove,\n persist,\n };\n}\n"],"names":["useCallback","useEffect","useMemo","useRef","useState","useSsr","useIsomorphicLayoutEffect","getStorageSerializers","getItemFromStorage","removeItemFromStorage","setItemInStorage","useStorage","options","key","defaultValue","manual","storage","globalThis","localStorage","initialValue","serializer","deserializer","raw","ssr","value","setStoredValue","fallback","config","current","setValue","valueOrDispatcher","prevValue","nextValue","Function","remove","persist","callback","event","storageArea","window","addEventListener","removeEventListener"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/storage/useStorage.ts"],"sourcesContent":["\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\n\nimport { useSsr } from \"../SsrProvider.js\";\nimport { type UseStateSetter } from \"../types.js\";\nimport { useIsomorphicLayoutEffect } from \"../useIsomorphicLayoutEffect.js\";\nimport { getStorageSerializers } from \"./internalUtils.js\";\nimport { type StorageImplementation, type StorageOptions } from \"./types.js\";\nimport {\n getItemFromStorage,\n removeItemFromStorage,\n setItemInStorage,\n} from \"./utils.js\";\n\n/**\n * The `useStorage` hook can be used to read and write from `localStorage`\n * (default) or `sessionStorage`. The default behavior will automatically sync\n * the value across tabs using the `StorageEvent`.\n *\n * @example Simple Example\n * ```tsx\n * import { TextField } from \"@react-md/core/form/TextField\";\n * import { useStorage } from \"@react-md/core/storage/useStorage\";\n * import { type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { value, setValue } = useStorage({\n * key: \"savedSearch\",\n * defaultValue: \"\",\n * });\n *\n * return (\n * <TextField\n * label=\"Search\"\n * placeholder=\"Search...\"\n * type=\"search\"\n * value={value}\n * onChange={(event) => {\n * setValue(event.currentTarget.value)\n * }}\n * />\n * );\n * }\n * ```\n *\n * @example Type-safe Objects\n * ```tsx\n * import { useStorage } from \"@react-md/core/storage/useStorage\";\n * import { type ReactElement } from \"react\";\n *\n * interface ExpectedSchema {\n * label: string;\n * value: string;\n * // others\n * }\n *\n * function Example(): ReactElement {\n * const { value, setValue } = useStorage<ExpectedSchema | null>({\n * key: \"someKey\",\n * defaultValue: null,\n *\n * // this is optional: you can create a custom deserializer to validate\n * // the stored value to prevent people manually updating local storage in\n * // the dev tools\n * deserializer(item) {\n * const parsed = JSON.parse(item):\n * const { label, value } = parsed;\n * if (typeof label !== 'string' || typeof value !== 'string') {\n * return null;\n * }\n *\n * return { label, value };\n * }\n * });\n *\n * // do something\n * // value will be `ExpectedSchema | null`\n * }\n * ```\n *\n * @example Manual Persistence\n * ```tsx\n * import { Button } from \"@react-md/core/button/Button\";\n * import { Checkbox } from \"@react-md/core/form/Checkbox\";\n * import { Form } from \"@react-md/core/form/Form\";\n * import { useStorage } from \"@react-md/core/storage/useStorage\";\n * import { type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { value, setValue, remove, persist } = useStorage({\n * key: \"someKey\",\n * manual: true,\n * defaultValue: false,\n * });\n *\n * return (\n * <Form\n * onSubmit={() => {\n * // current value will be saved into local storage\n * persist();\n * }}\n * onReset={() => {\n * // \"someKey\" will be removed from local storage\n * remove();\n * }}\n * >\n * <Checkbox\n * label=\"Allow cookies\"\n * checked={value}\n * onChange={(event) =>\n * setValue(event.currentTarget.checked);\n * }\n * />\n * <Button type=\"reset\">Decline</Button>\n * <Button type=\"submit\">Save</Button>\n * </Form>\n * );\n * }\n * ```\n *\n * @see {@link https://react-md.dev/hooks/use-storage | useStorage Demos}\n * @see https://developer.mozilla.org/en-US/docs/Web/API/StorageEvent\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage\n * @since 6.0.0\n */\nexport function useStorage<T>(\n options: StorageOptions<T>\n): StorageImplementation<T> {\n const {\n key,\n defaultValue,\n manual,\n storage = globalThis.localStorage,\n } = options;\n\n const [initialValue] = useState(defaultValue);\n const { serializer, deserializer } = useMemo(\n () =>\n getStorageSerializers({\n raw: options.raw,\n serializer: options.serializer,\n deserializer: options.deserializer,\n initialValue,\n }),\n [initialValue, options.deserializer, options.raw, options.serializer]\n );\n\n const ssr = useSsr();\n const [value, setStoredValue] = useState<T>(() => {\n if (ssr) {\n return initialValue;\n }\n\n return getItemFromStorage({\n key,\n storage,\n fallback: initialValue,\n deserializer,\n });\n });\n\n const config = useRef({\n key,\n value,\n manual,\n storage,\n serializer,\n deserializer,\n defaultValue: initialValue,\n } as const);\n useIsomorphicLayoutEffect(() => {\n config.current = {\n key,\n value,\n manual,\n storage,\n serializer,\n deserializer,\n defaultValue: initialValue,\n };\n });\n\n const setValue = useCallback<UseStateSetter<T>>((valueOrDispatcher) => {\n const { key, manual, storage, serializer } = config.current;\n\n setStoredValue((prevValue) => {\n const nextValue =\n // this has to still use `instanceof` because of the T generic. Using\n // `T extends ...` restricts the types too much if providing a\n // `defaultValue`\n //\n // eslint-disable-next-line unicorn/no-instanceof-builtins\n valueOrDispatcher instanceof Function\n ? valueOrDispatcher(prevValue)\n : valueOrDispatcher;\n\n if (!manual && nextValue !== prevValue) {\n setItemInStorage({\n key,\n value: nextValue,\n storage,\n serializer,\n });\n }\n\n return nextValue;\n });\n }, []);\n\n const remove = useCallback(() => {\n removeItemFromStorage(config.current);\n }, []);\n\n const persist = useCallback(() => {\n setItemInStorage(config.current);\n }, []);\n\n // make sure to sync the value in local storage\n useEffect(() => {\n const { value, manual, storage, serializer } = config.current;\n if (ssr || !key || !value || manual || !storage) {\n return;\n }\n\n setItemInStorage({\n key,\n value,\n storage,\n serializer,\n });\n }, [key, ssr]);\n useEffect(() => {\n const { defaultValue, storage, deserializer, manual } = config.current;\n if (manual || !ssr) {\n return;\n }\n\n // do not want to trigger the emit behavior for rehydration\n setStoredValue(\n getItemFromStorage({\n key,\n storage,\n fallback: defaultValue,\n deserializer,\n })\n );\n }, [key, ssr]);\n\n // update the value if another tab changed the local storage value\n useEffect(() => {\n if (!key) {\n return;\n }\n\n const callback = (event: StorageEvent): void => {\n const { storage, defaultValue, deserializer } = config.current;\n if (event.key === key && event.storageArea === storage) {\n setStoredValue(\n getItemFromStorage({\n key,\n storage,\n fallback: defaultValue,\n deserializer,\n })\n );\n }\n };\n\n globalThis.addEventListener(\"storage\", callback);\n return () => {\n globalThis.removeEventListener(\"storage\", callback);\n };\n }, [key]);\n\n return {\n value,\n setValue,\n remove,\n persist,\n };\n}\n"],"names":["useCallback","useEffect","useMemo","useRef","useState","useSsr","useIsomorphicLayoutEffect","getStorageSerializers","getItemFromStorage","removeItemFromStorage","setItemInStorage","useStorage","options","key","defaultValue","manual","storage","globalThis","localStorage","initialValue","serializer","deserializer","raw","ssr","value","setStoredValue","fallback","config","current","setValue","valueOrDispatcher","prevValue","nextValue","Function","remove","persist","callback","event","storageArea","addEventListener","removeEventListener"],"mappings":"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"}
@@ -46,7 +46,7 @@ import { useTableContainer } from "./TableContainerProvider.js";
46
46
  if (exists) {
47
47
  topOffset = section.offsetHeight - 1;
48
48
  } else {
49
- const top = parseFloat(window.getComputedStyle(section).top);
49
+ const top = Number.parseFloat(globalThis.getComputedStyle(section).top);
50
50
  topOffset = Number.isNaN(top) ? 1 : top + 1;
51
51
  }
52
52
  return `-${topOffset}px 0px 0px`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/table/useStickyTableSection.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ReactNode,\n type Ref,\n type RefCallback,\n useCallback,\n useState,\n} from \"react\";\n\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useIntersectionObserver } from \"../useIntersectionObserver.js\";\nimport { useTableContainer } from \"./TableContainerProvider.js\";\nimport {\n type IsStickyTableSectionActive,\n type TableStickySectionConfiguration,\n} from \"./types.js\";\n\n/**\n * @since 6.0.0\n */\nexport const isTableHeaderStickyActive: IsStickyTableSectionActive = (\n entry\n) => {\n return (\n entry.intersectionRatio < 1 &&\n entry.boundingClientRect.bottom <= window.innerHeight\n );\n};\n\n/**\n * @since 6.0.0\n */\nexport const isTableFooterStickyActive: IsStickyTableSectionActive = (\n entry,\n isInTableContainer\n) => {\n const { intersectionRatio, boundingClientRect, isIntersecting } = entry;\n if (isInTableContainer) {\n return !isIntersecting;\n }\n\n return intersectionRatio < 1 && boundingClientRect.top >= 0;\n};\n\n/** @since 6.0.0 */\nexport interface TableStickySectionOptions extends TableStickySectionConfiguration {\n ref?: Ref<HTMLTableSectionElement>;\n type: \"header\" | \"footer\";\n}\n\n/** @since 6.0.0 */\nexport interface TableStickySectionImplementation {\n tbody: ReactNode;\n targetRef: RefCallback<HTMLTableSectionElement>;\n sectionRef: RefCallback<HTMLTableSectionElement>;\n stickyActive: boolean;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport function useStickyTableSection(\n options: TableStickySectionOptions\n): TableStickySectionImplementation {\n const { ref, type, disableStickyStyles, stickyOptions } = options;\n\n const isHeader = type === \"header\";\n const isStickyActive =\n options.isStickyActive ??\n (isHeader ? isTableHeaderStickyActive : isTableFooterStickyActive);\n\n const [sectionRef, sectionRefCallback] = useEnsuredRef(ref);\n const { exists, containerRef } = useTableContainer();\n const [stickyActive, setStickyActive] = useState(false);\n const targetRef = useIntersectionObserver({\n ref: exists ? undefined : sectionRefCallback,\n root: containerRef,\n disabled: disableStickyStyles,\n threshold: exists ? 0 : 1,\n getRootMargin: useCallback(() => {\n const section = sectionRef.current;\n if (!isHeader) {\n const topOffset = exists && section ? section.offsetHeight - 1 : 1;\n\n return `0px 0px -${topOffset}px 0px`;\n }\n\n if (!section) {\n return;\n }\n\n let topOffset: number;\n if (exists) {\n topOffset = section.offsetHeight - 1;\n } else {\n const top = parseFloat(window.getComputedStyle(section).top);\n topOffset = Number.isNaN(top) ? 1 : top + 1;\n }\n\n return `-${topOffset}px 0px 0px`;\n }, [exists, isHeader, sectionRef]),\n onUpdate: useCallback(\n ([entry]) => {\n setStickyActive(isStickyActive(entry, exists));\n },\n [exists, isStickyActive]\n ),\n // allow the user defined sticky options to override the default behavior\n ...stickyOptions,\n });\n\n let tbody: ReactNode;\n if (exists && !disableStickyStyles) {\n // rendering a `<tbody>` since it is valid to have 0-many in a table\n // https://html.spec.whatwg.org/multipage/tables.html#the-table-element\n tbody = <tbody aria-hidden ref={targetRef} />;\n }\n\n return {\n tbody,\n targetRef,\n sectionRef: exists ? sectionRefCallback : targetRef,\n stickyActive,\n };\n}\n"],"names":["useCallback","useState","useEnsuredRef","useIntersectionObserver","useTableContainer","isTableHeaderStickyActive","entry","intersectionRatio","boundingClientRect","bottom","window","innerHeight","isTableFooterStickyActive","isInTableContainer","isIntersecting","top","useStickyTableSection","options","ref","type","disableStickyStyles","stickyOptions","isHeader","isStickyActive","sectionRef","sectionRefCallback","exists","containerRef","stickyActive","setStickyActive","targetRef","undefined","root","disabled","threshold","getRootMargin","section","current","topOffset","offsetHeight","parseFloat","getComputedStyle","Number","isNaN","onUpdate","tbody","aria-hidden"],"mappings":"AAAA;;AAEA,SAIEA,WAAW,EACXC,QAAQ,QACH,QAAQ;AAEf,SAASC,aAAa,QAAQ,sBAAsB;AACpD,SAASC,uBAAuB,QAAQ,gCAAgC;AACxE,SAASC,iBAAiB,QAAQ,8BAA8B;AAMhE;;CAEC,GACD,OAAO,MAAMC,4BAAwD,CACnEC;IAEA,OACEA,MAAMC,iBAAiB,GAAG,KAC1BD,MAAME,kBAAkB,CAACC,MAAM,IAAIC,OAAOC,WAAW;AAEzD,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMC,4BAAwD,CACnEN,OACAO;IAEA,MAAM,EAAEN,iBAAiB,EAAEC,kBAAkB,EAAEM,cAAc,EAAE,GAAGR;IAClE,IAAIO,oBAAoB;QACtB,OAAO,CAACC;IACV;IAEA,OAAOP,oBAAoB,KAAKC,mBAAmBO,GAAG,IAAI;AAC5D,EAAE;AAgBF;;;CAGC,GACD,OAAO,SAASC,sBACdC,OAAkC;IAElC,MAAM,EAAEC,GAAG,EAAEC,IAAI,EAAEC,mBAAmB,EAAEC,aAAa,EAAE,GAAGJ;IAE1D,MAAMK,WAAWH,SAAS;IAC1B,MAAMI,iBACJN,QAAQM,cAAc,IACrBD,CAAAA,WAAWjB,4BAA4BO,yBAAwB;IAElE,MAAM,CAACY,YAAYC,mBAAmB,GAAGvB,cAAcgB;IACvD,MAAM,EAAEQ,MAAM,EAAEC,YAAY,EAAE,GAAGvB;IACjC,MAAM,CAACwB,cAAcC,gBAAgB,GAAG5B,SAAS;IACjD,MAAM6B,YAAY3B,wBAAwB;QACxCe,KAAKQ,SAASK,YAAYN;QAC1BO,MAAML;QACNM,UAAUb;QACVc,WAAWR,SAAS,IAAI;QACxBS,eAAenC,YAAY;YACzB,MAAMoC,UAAUZ,WAAWa,OAAO;YAClC,IAAI,CAACf,UAAU;gBACb,MAAMgB,YAAYZ,UAAUU,UAAUA,QAAQG,YAAY,GAAG,IAAI;gBAEjE,OAAO,CAAC,SAAS,EAAED,UAAU,MAAM,CAAC;YACtC;YAEA,IAAI,CAACF,SAAS;gBACZ;YACF;YAEA,IAAIE;YACJ,IAAIZ,QAAQ;gBACVY,YAAYF,QAAQG,YAAY,GAAG;YACrC,OAAO;gBACL,MAAMxB,MAAMyB,WAAW9B,OAAO+B,gBAAgB,CAACL,SAASrB,GAAG;gBAC3DuB,YAAYI,OAAOC,KAAK,CAAC5B,OAAO,IAAIA,MAAM;YAC5C;YAEA,OAAO,CAAC,CAAC,EAAEuB,UAAU,UAAU,CAAC;QAClC,GAAG;YAACZ;YAAQJ;YAAUE;SAAW;QACjCoB,UAAU5C,YACR,CAAC,CAACM,MAAM;YACNuB,gBAAgBN,eAAejB,OAAOoB;QACxC,GACA;YAACA;YAAQH;SAAe;QAE1B,yEAAyE;QACzE,GAAGF,aAAa;IAClB;IAEA,IAAIwB;IACJ,IAAInB,UAAU,CAACN,qBAAqB;QAClC,oEAAoE;QACpE,uEAAuE;QACvEyB,sBAAQ,KAACA;YAAMC,aAAW;YAAC5B,KAAKY;;IAClC;IAEA,OAAO;QACLe;QACAf;QACAN,YAAYE,SAASD,qBAAqBK;QAC1CF;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/table/useStickyTableSection.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type ReactNode,\n type Ref,\n type RefCallback,\n useCallback,\n useState,\n} from \"react\";\n\nimport { useEnsuredRef } from \"../useEnsuredRef.js\";\nimport { useIntersectionObserver } from \"../useIntersectionObserver.js\";\nimport { useTableContainer } from \"./TableContainerProvider.js\";\nimport {\n type IsStickyTableSectionActive,\n type TableStickySectionConfiguration,\n} from \"./types.js\";\n\n/**\n * @since 6.0.0\n */\nexport const isTableHeaderStickyActive: IsStickyTableSectionActive = (\n entry\n) => {\n return (\n entry.intersectionRatio < 1 &&\n entry.boundingClientRect.bottom <= window.innerHeight\n );\n};\n\n/**\n * @since 6.0.0\n */\nexport const isTableFooterStickyActive: IsStickyTableSectionActive = (\n entry,\n isInTableContainer\n) => {\n const { intersectionRatio, boundingClientRect, isIntersecting } = entry;\n if (isInTableContainer) {\n return !isIntersecting;\n }\n\n return intersectionRatio < 1 && boundingClientRect.top >= 0;\n};\n\n/** @since 6.0.0 */\nexport interface TableStickySectionOptions extends TableStickySectionConfiguration {\n ref?: Ref<HTMLTableSectionElement>;\n type: \"header\" | \"footer\";\n}\n\n/** @since 6.0.0 */\nexport interface TableStickySectionImplementation {\n tbody: ReactNode;\n targetRef: RefCallback<HTMLTableSectionElement>;\n sectionRef: RefCallback<HTMLTableSectionElement>;\n stickyActive: boolean;\n}\n\n/**\n * @since 6.0.0\n * @internal\n */\nexport function useStickyTableSection(\n options: TableStickySectionOptions\n): TableStickySectionImplementation {\n const { ref, type, disableStickyStyles, stickyOptions } = options;\n\n const isHeader = type === \"header\";\n const isStickyActive =\n options.isStickyActive ??\n (isHeader ? isTableHeaderStickyActive : isTableFooterStickyActive);\n\n const [sectionRef, sectionRefCallback] = useEnsuredRef(ref);\n const { exists, containerRef } = useTableContainer();\n const [stickyActive, setStickyActive] = useState(false);\n const targetRef = useIntersectionObserver({\n ref: exists ? undefined : sectionRefCallback,\n root: containerRef,\n disabled: disableStickyStyles,\n threshold: exists ? 0 : 1,\n getRootMargin: useCallback(() => {\n const section = sectionRef.current;\n if (!isHeader) {\n const topOffset = exists && section ? section.offsetHeight - 1 : 1;\n\n return `0px 0px -${topOffset}px 0px`;\n }\n\n if (!section) {\n return;\n }\n\n let topOffset: number;\n if (exists) {\n topOffset = section.offsetHeight - 1;\n } else {\n const top = Number.parseFloat(globalThis.getComputedStyle(section).top);\n topOffset = Number.isNaN(top) ? 1 : top + 1;\n }\n\n return `-${topOffset}px 0px 0px`;\n }, [exists, isHeader, sectionRef]),\n onUpdate: useCallback(\n ([entry]) => {\n setStickyActive(isStickyActive(entry, exists));\n },\n [exists, isStickyActive]\n ),\n // allow the user defined sticky options to override the default behavior\n ...stickyOptions,\n });\n\n let tbody: ReactNode;\n if (exists && !disableStickyStyles) {\n // rendering a `<tbody>` since it is valid to have 0-many in a table\n // https://html.spec.whatwg.org/multipage/tables.html#the-table-element\n tbody = <tbody aria-hidden ref={targetRef} />;\n }\n\n return {\n tbody,\n targetRef,\n sectionRef: exists ? sectionRefCallback : targetRef,\n stickyActive,\n };\n}\n"],"names":["useCallback","useState","useEnsuredRef","useIntersectionObserver","useTableContainer","isTableHeaderStickyActive","entry","intersectionRatio","boundingClientRect","bottom","window","innerHeight","isTableFooterStickyActive","isInTableContainer","isIntersecting","top","useStickyTableSection","options","ref","type","disableStickyStyles","stickyOptions","isHeader","isStickyActive","sectionRef","sectionRefCallback","exists","containerRef","stickyActive","setStickyActive","targetRef","undefined","root","disabled","threshold","getRootMargin","section","current","topOffset","offsetHeight","Number","parseFloat","globalThis","getComputedStyle","isNaN","onUpdate","tbody","aria-hidden"],"mappings":"AAAA;;AAEA,SAIEA,WAAW,EACXC,QAAQ,QACH,QAAQ;AAEf,SAASC,aAAa,QAAQ,sBAAsB;AACpD,SAASC,uBAAuB,QAAQ,gCAAgC;AACxE,SAASC,iBAAiB,QAAQ,8BAA8B;AAMhE;;CAEC,GACD,OAAO,MAAMC,4BAAwD,CACnEC;IAEA,OACEA,MAAMC,iBAAiB,GAAG,KAC1BD,MAAME,kBAAkB,CAACC,MAAM,IAAIC,OAAOC,WAAW;AAEzD,EAAE;AAEF;;CAEC,GACD,OAAO,MAAMC,4BAAwD,CACnEN,OACAO;IAEA,MAAM,EAAEN,iBAAiB,EAAEC,kBAAkB,EAAEM,cAAc,EAAE,GAAGR;IAClE,IAAIO,oBAAoB;QACtB,OAAO,CAACC;IACV;IAEA,OAAOP,oBAAoB,KAAKC,mBAAmBO,GAAG,IAAI;AAC5D,EAAE;AAgBF;;;CAGC,GACD,OAAO,SAASC,sBACdC,OAAkC;IAElC,MAAM,EAAEC,GAAG,EAAEC,IAAI,EAAEC,mBAAmB,EAAEC,aAAa,EAAE,GAAGJ;IAE1D,MAAMK,WAAWH,SAAS;IAC1B,MAAMI,iBACJN,QAAQM,cAAc,IACrBD,CAAAA,WAAWjB,4BAA4BO,yBAAwB;IAElE,MAAM,CAACY,YAAYC,mBAAmB,GAAGvB,cAAcgB;IACvD,MAAM,EAAEQ,MAAM,EAAEC,YAAY,EAAE,GAAGvB;IACjC,MAAM,CAACwB,cAAcC,gBAAgB,GAAG5B,SAAS;IACjD,MAAM6B,YAAY3B,wBAAwB;QACxCe,KAAKQ,SAASK,YAAYN;QAC1BO,MAAML;QACNM,UAAUb;QACVc,WAAWR,SAAS,IAAI;QACxBS,eAAenC,YAAY;YACzB,MAAMoC,UAAUZ,WAAWa,OAAO;YAClC,IAAI,CAACf,UAAU;gBACb,MAAMgB,YAAYZ,UAAUU,UAAUA,QAAQG,YAAY,GAAG,IAAI;gBAEjE,OAAO,CAAC,SAAS,EAAED,UAAU,MAAM,CAAC;YACtC;YAEA,IAAI,CAACF,SAAS;gBACZ;YACF;YAEA,IAAIE;YACJ,IAAIZ,QAAQ;gBACVY,YAAYF,QAAQG,YAAY,GAAG;YACrC,OAAO;gBACL,MAAMxB,MAAMyB,OAAOC,UAAU,CAACC,WAAWC,gBAAgB,CAACP,SAASrB,GAAG;gBACtEuB,YAAYE,OAAOI,KAAK,CAAC7B,OAAO,IAAIA,MAAM;YAC5C;YAEA,OAAO,CAAC,CAAC,EAAEuB,UAAU,UAAU,CAAC;QAClC,GAAG;YAACZ;YAAQJ;YAAUE;SAAW;QACjCqB,UAAU7C,YACR,CAAC,CAACM,MAAM;YACNuB,gBAAgBN,eAAejB,OAAOoB;QACxC,GACA;YAACA;YAAQH;SAAe;QAE1B,yEAAyE;QACzE,GAAGF,aAAa;IAClB;IAEA,IAAIyB;IACJ,IAAIpB,UAAU,CAACN,qBAAqB;QAClC,oEAAoE;QACpE,uEAAuE;QACvE0B,sBAAQ,KAACA;YAAMC,aAAW;YAAC7B,KAAKY;;IAClC;IAEA,OAAO;QACLgB;QACAhB;QACAN,YAAYE,SAASD,qBAAqBK;QAC1CF;IACF;AACF"}
@@ -35,11 +35,11 @@ import { useTabList } from "./useTabList.js";
35
35
  return;
36
36
  }
37
37
  setAnimate(true);
38
- const timeout = window.setTimeout(()=>{
38
+ const timeout = globalThis.setTimeout(()=>{
39
39
  setAnimate(false);
40
40
  }, transitionDuration);
41
41
  return ()=>{
42
- window.clearTimeout(timeout);
42
+ globalThis.clearTimeout(timeout);
43
43
  };
44
44
  }, [
45
45
  activeIndex,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tabs/TabList.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type HTMLAttributes,\n forwardRef,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { KeyboardMovementProvider } from \"../movement/useKeyboardMovementProvider.js\";\nimport {\n type BaseTabListScrollButtonProps,\n TabListScrollButton,\n} from \"./TabListScrollButton.js\";\nimport { type GetTabListScrollToOptions } from \"./getTabListScrollToOptions.js\";\nimport { type TabListClassNameOptions, tabList } from \"./tabListStyles.js\";\nimport {\n type TabListActivationMode,\n type TabListScrollButtonsBehavior,\n} from \"./types.js\";\nimport { useTabList } from \"./useTabList.js\";\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { type useTabs } from \"./useTabs.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface TabListProps\n extends\n HTMLAttributes<HTMLDivElement>,\n Omit<TabListClassNameOptions, \"animate\" | \"indicator\"> {\n activeIndex: number;\n setActiveIndex: (nextActiveIndex: number) => void;\n\n /**\n * Set this to `true` to show a scrollbar when the number of tabs cause\n * overflow.\n *\n * @see {@link scrollButtons}\n * @defaultValue `false`\n */\n scrollbar?: boolean;\n\n /**\n * Set this to `true` to disable the active tab indicator from animating\n * when a new tab is selected.\n *\n * @defaultValue `false`\n */\n disableTransition?: boolean;\n\n /**\n * This should be equal to the `$tabs-transition-duration` variable.\n *\n * @defaultValue `150`\n */\n transitionDuration?: number;\n\n /**\n * @defaultValue `\"manual\"`\n * @see {@link TabListActivationMode}\n */\n activationMode?: TabListActivationMode;\n\n /**\n * @defaultValue `false`\n * @see {@link TabListScrollButtonsBehavior}\n */\n scrollButtons?: TabListScrollButtonsBehavior;\n\n /**\n * A convenience prop for the {@link BaseTabListScrollButtonProps.getScrollToOptions}\n * on {@link forwardScrollButtonProps} and {@link backwardScrollButtonProps}.\n */\n getScrollToOptions?: GetTabListScrollToOptions;\n\n /**\n * Any additional props that should be passed to the scroll forward button.\n *\n * @example\n * ```tsx\n * forwardScrollButtonProps={{\n * \"aria-label\": \"Scroll right\",\n * theme: \"primary\",\n * themeType: \"contained\",\n * className: styles.buttonContainer,\n * buttonProps: {\n * className: styles.button,\n * }\n * }}\n * ```\n */\n forwardScrollButtonProps?: BaseTabListScrollButtonProps;\n\n /**\n * Any additional props that should be passed to the scroll backward button.\n *\n * @example\n * ```tsx\n * forwardScrollButtonProps={{\n * \"aria-label\": \"Scroll left\",\n * theme: \"primary\",\n * themeType: \"contained\",\n * className: styles.buttonContainer,\n * buttonProps: {\n * className: styles.button,\n * }\n * }}\n * ```\n */\n backwardScrollButtonProps?: BaseTabListScrollButtonProps;\n}\n\n/**\n * **Client Component**\n *\n * @see {@link https://react-md.dev/components/tabs | Tabs Demos}\n * @see {@link useTabs} for example usage.\n * @since 6.0.0\n */\nexport const TabList = forwardRef<HTMLDivElement, TabListProps>(\n function TabList(props, ref) {\n const {\n style,\n onClick,\n onFocus,\n onKeyDown,\n className,\n children,\n activeIndex,\n setActiveIndex,\n activationMode = \"manual\",\n align = \"left\",\n padded = false,\n inline = false,\n vertical = false,\n scrollbar = false,\n scrollButtons = false,\n fullWidthTabs,\n disableTransition = false,\n transitionDuration = 150,\n getScrollToOptions,\n forwardScrollButtonProps,\n backwardScrollButtonProps,\n ...remaining\n } = props;\n\n const {\n elementProps,\n movementContext,\n backwardProps,\n forwardProps,\n showScrollButtons,\n } = useTabList({\n ref,\n style,\n onClick,\n onFocus,\n onKeyDown,\n vertical,\n activeIndex,\n setActiveIndex,\n activationMode,\n scrollButtons,\n disableTransition,\n });\n\n const prevActiveIndex = useRef(activeIndex);\n const [animate, setAnimate] = useState(false);\n useEffect(() => {\n const isSameIndex = activeIndex === prevActiveIndex.current;\n prevActiveIndex.current = activeIndex;\n if (disableTransition || isSameIndex) {\n return;\n }\n\n setAnimate(true);\n const timeout = window.setTimeout(() => {\n setAnimate(false);\n }, transitionDuration);\n\n return () => {\n window.clearTimeout(timeout);\n };\n }, [activeIndex, disableTransition, transitionDuration]);\n\n return (\n <KeyboardMovementProvider value={movementContext}>\n <div\n {...remaining}\n {...elementProps}\n role=\"tablist\"\n className={tabList({\n align,\n padded,\n inline,\n animate: !disableTransition && animate,\n vertical,\n scrollbar,\n indicator: !disableTransition,\n fullWidthTabs,\n className,\n })}\n >\n {showScrollButtons && (\n <TabListScrollButton\n getScrollToOptions={getScrollToOptions}\n {...backwardScrollButtonProps}\n {...backwardProps}\n />\n )}\n {children}\n {showScrollButtons && (\n <TabListScrollButton\n getScrollToOptions={getScrollToOptions}\n {...forwardScrollButtonProps}\n {...forwardProps}\n />\n )}\n </div>\n </KeyboardMovementProvider>\n );\n }\n);\n"],"names":["forwardRef","useEffect","useRef","useState","KeyboardMovementProvider","TabListScrollButton","tabList","useTabList","TabList","props","ref","style","onClick","onFocus","onKeyDown","className","children","activeIndex","setActiveIndex","activationMode","align","padded","inline","vertical","scrollbar","scrollButtons","fullWidthTabs","disableTransition","transitionDuration","getScrollToOptions","forwardScrollButtonProps","backwardScrollButtonProps","remaining","elementProps","movementContext","backwardProps","forwardProps","showScrollButtons","prevActiveIndex","animate","setAnimate","isSameIndex","current","timeout","window","setTimeout","clearTimeout","value","div","role","indicator"],"mappings":"AAAA;;AAEA,SAEEA,UAAU,EACVC,SAAS,EACTC,MAAM,EACNC,QAAQ,QACH,QAAQ;AAEf,SAASC,wBAAwB,QAAQ,6CAA6C;AACtF,SAEEC,mBAAmB,QACd,2BAA2B;AAElC,SAAuCC,OAAO,QAAQ,qBAAqB;AAK3E,SAASC,UAAU,QAAQ,kBAAkB;AA6F7C;;;;;;CAMC,GACD,OAAO,MAAMC,wBAAUR,WACrB,SAASQ,QAAQC,KAAK,EAAEC,GAAG;IACzB,MAAM,EACJC,KAAK,EACLC,OAAO,EACPC,OAAO,EACPC,SAAS,EACTC,SAAS,EACTC,QAAQ,EACRC,WAAW,EACXC,cAAc,EACdC,iBAAiB,QAAQ,EACzBC,QAAQ,MAAM,EACdC,SAAS,KAAK,EACdC,SAAS,KAAK,EACdC,WAAW,KAAK,EAChBC,YAAY,KAAK,EACjBC,gBAAgB,KAAK,EACrBC,aAAa,EACbC,oBAAoB,KAAK,EACzBC,qBAAqB,GAAG,EACxBC,kBAAkB,EAClBC,wBAAwB,EACxBC,yBAAyB,EACzB,GAAGC,WACJ,GAAGvB;IAEJ,MAAM,EACJwB,YAAY,EACZC,eAAe,EACfC,aAAa,EACbC,YAAY,EACZC,iBAAiB,EAClB,GAAG9B,WAAW;QACbG;QACAC;QACAC;QACAC;QACAC;QACAS;QACAN;QACAC;QACAC;QACAM;QACAE;IACF;IAEA,MAAMW,kBAAkBpC,OAAOe;IAC/B,MAAM,CAACsB,SAASC,WAAW,GAAGrC,SAAS;IACvCF,UAAU;QACR,MAAMwC,cAAcxB,gBAAgBqB,gBAAgBI,OAAO;QAC3DJ,gBAAgBI,OAAO,GAAGzB;QAC1B,IAAIU,qBAAqBc,aAAa;YACpC;QACF;QAEAD,WAAW;QACX,MAAMG,UAAUC,OAAOC,UAAU,CAAC;YAChCL,WAAW;QACb,GAAGZ;QAEH,OAAO;YACLgB,OAAOE,YAAY,CAACH;QACtB;IACF,GAAG;QAAC1B;QAAaU;QAAmBC;KAAmB;IAEvD,qBACE,KAACxB;QAAyB2C,OAAOb;kBAC/B,cAAA,MAACc;YACE,GAAGhB,SAAS;YACZ,GAAGC,YAAY;YAChBgB,MAAK;YACLlC,WAAWT,QAAQ;gBACjBc;gBACAC;gBACAC;gBACAiB,SAAS,CAACZ,qBAAqBY;gBAC/BhB;gBACAC;gBACA0B,WAAW,CAACvB;gBACZD;gBACAX;YACF;;gBAECsB,mCACC,KAAChC;oBACCwB,oBAAoBA;oBACnB,GAAGE,yBAAyB;oBAC5B,GAAGI,aAAa;;gBAGpBnB;gBACAqB,mCACC,KAAChC;oBACCwB,oBAAoBA;oBACnB,GAAGC,wBAAwB;oBAC3B,GAAGM,YAAY;;;;;AAM5B,GACA"}
1
+ {"version":3,"sources":["../../src/tabs/TabList.tsx"],"sourcesContent":["\"use client\";\n\nimport {\n type HTMLAttributes,\n forwardRef,\n useEffect,\n useRef,\n useState,\n} from \"react\";\n\nimport { KeyboardMovementProvider } from \"../movement/useKeyboardMovementProvider.js\";\nimport {\n type BaseTabListScrollButtonProps,\n TabListScrollButton,\n} from \"./TabListScrollButton.js\";\nimport { type GetTabListScrollToOptions } from \"./getTabListScrollToOptions.js\";\nimport { type TabListClassNameOptions, tabList } from \"./tabListStyles.js\";\nimport {\n type TabListActivationMode,\n type TabListScrollButtonsBehavior,\n} from \"./types.js\";\nimport { useTabList } from \"./useTabList.js\";\n// eslint-disable-next-line @typescript-eslint/no-unused-vars\nimport { type useTabs } from \"./useTabs.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface TabListProps\n extends\n HTMLAttributes<HTMLDivElement>,\n Omit<TabListClassNameOptions, \"animate\" | \"indicator\"> {\n activeIndex: number;\n setActiveIndex: (nextActiveIndex: number) => void;\n\n /**\n * Set this to `true` to show a scrollbar when the number of tabs cause\n * overflow.\n *\n * @see {@link scrollButtons}\n * @defaultValue `false`\n */\n scrollbar?: boolean;\n\n /**\n * Set this to `true` to disable the active tab indicator from animating\n * when a new tab is selected.\n *\n * @defaultValue `false`\n */\n disableTransition?: boolean;\n\n /**\n * This should be equal to the `$tabs-transition-duration` variable.\n *\n * @defaultValue `150`\n */\n transitionDuration?: number;\n\n /**\n * @defaultValue `\"manual\"`\n * @see {@link TabListActivationMode}\n */\n activationMode?: TabListActivationMode;\n\n /**\n * @defaultValue `false`\n * @see {@link TabListScrollButtonsBehavior}\n */\n scrollButtons?: TabListScrollButtonsBehavior;\n\n /**\n * A convenience prop for the {@link BaseTabListScrollButtonProps.getScrollToOptions}\n * on {@link forwardScrollButtonProps} and {@link backwardScrollButtonProps}.\n */\n getScrollToOptions?: GetTabListScrollToOptions;\n\n /**\n * Any additional props that should be passed to the scroll forward button.\n *\n * @example\n * ```tsx\n * forwardScrollButtonProps={{\n * \"aria-label\": \"Scroll right\",\n * theme: \"primary\",\n * themeType: \"contained\",\n * className: styles.buttonContainer,\n * buttonProps: {\n * className: styles.button,\n * }\n * }}\n * ```\n */\n forwardScrollButtonProps?: BaseTabListScrollButtonProps;\n\n /**\n * Any additional props that should be passed to the scroll backward button.\n *\n * @example\n * ```tsx\n * forwardScrollButtonProps={{\n * \"aria-label\": \"Scroll left\",\n * theme: \"primary\",\n * themeType: \"contained\",\n * className: styles.buttonContainer,\n * buttonProps: {\n * className: styles.button,\n * }\n * }}\n * ```\n */\n backwardScrollButtonProps?: BaseTabListScrollButtonProps;\n}\n\n/**\n * **Client Component**\n *\n * @see {@link https://react-md.dev/components/tabs | Tabs Demos}\n * @see {@link useTabs} for example usage.\n * @since 6.0.0\n */\nexport const TabList = forwardRef<HTMLDivElement, TabListProps>(\n function TabList(props, ref) {\n const {\n style,\n onClick,\n onFocus,\n onKeyDown,\n className,\n children,\n activeIndex,\n setActiveIndex,\n activationMode = \"manual\",\n align = \"left\",\n padded = false,\n inline = false,\n vertical = false,\n scrollbar = false,\n scrollButtons = false,\n fullWidthTabs,\n disableTransition = false,\n transitionDuration = 150,\n getScrollToOptions,\n forwardScrollButtonProps,\n backwardScrollButtonProps,\n ...remaining\n } = props;\n\n const {\n elementProps,\n movementContext,\n backwardProps,\n forwardProps,\n showScrollButtons,\n } = useTabList({\n ref,\n style,\n onClick,\n onFocus,\n onKeyDown,\n vertical,\n activeIndex,\n setActiveIndex,\n activationMode,\n scrollButtons,\n disableTransition,\n });\n\n const prevActiveIndex = useRef(activeIndex);\n const [animate, setAnimate] = useState(false);\n useEffect(() => {\n const isSameIndex = activeIndex === prevActiveIndex.current;\n prevActiveIndex.current = activeIndex;\n if (disableTransition || isSameIndex) {\n return;\n }\n\n setAnimate(true);\n const timeout = globalThis.setTimeout(() => {\n setAnimate(false);\n }, transitionDuration);\n\n return () => {\n globalThis.clearTimeout(timeout);\n };\n }, [activeIndex, disableTransition, transitionDuration]);\n\n return (\n <KeyboardMovementProvider value={movementContext}>\n <div\n {...remaining}\n {...elementProps}\n role=\"tablist\"\n className={tabList({\n align,\n padded,\n inline,\n animate: !disableTransition && animate,\n vertical,\n scrollbar,\n indicator: !disableTransition,\n fullWidthTabs,\n className,\n })}\n >\n {showScrollButtons && (\n <TabListScrollButton\n getScrollToOptions={getScrollToOptions}\n {...backwardScrollButtonProps}\n {...backwardProps}\n />\n )}\n {children}\n {showScrollButtons && (\n <TabListScrollButton\n getScrollToOptions={getScrollToOptions}\n {...forwardScrollButtonProps}\n {...forwardProps}\n />\n )}\n </div>\n </KeyboardMovementProvider>\n );\n }\n);\n"],"names":["forwardRef","useEffect","useRef","useState","KeyboardMovementProvider","TabListScrollButton","tabList","useTabList","TabList","props","ref","style","onClick","onFocus","onKeyDown","className","children","activeIndex","setActiveIndex","activationMode","align","padded","inline","vertical","scrollbar","scrollButtons","fullWidthTabs","disableTransition","transitionDuration","getScrollToOptions","forwardScrollButtonProps","backwardScrollButtonProps","remaining","elementProps","movementContext","backwardProps","forwardProps","showScrollButtons","prevActiveIndex","animate","setAnimate","isSameIndex","current","timeout","globalThis","setTimeout","clearTimeout","value","div","role","indicator"],"mappings":"AAAA;;AAEA,SAEEA,UAAU,EACVC,SAAS,EACTC,MAAM,EACNC,QAAQ,QACH,QAAQ;AAEf,SAASC,wBAAwB,QAAQ,6CAA6C;AACtF,SAEEC,mBAAmB,QACd,2BAA2B;AAElC,SAAuCC,OAAO,QAAQ,qBAAqB;AAK3E,SAASC,UAAU,QAAQ,kBAAkB;AA6F7C;;;;;;CAMC,GACD,OAAO,MAAMC,wBAAUR,WACrB,SAASQ,QAAQC,KAAK,EAAEC,GAAG;IACzB,MAAM,EACJC,KAAK,EACLC,OAAO,EACPC,OAAO,EACPC,SAAS,EACTC,SAAS,EACTC,QAAQ,EACRC,WAAW,EACXC,cAAc,EACdC,iBAAiB,QAAQ,EACzBC,QAAQ,MAAM,EACdC,SAAS,KAAK,EACdC,SAAS,KAAK,EACdC,WAAW,KAAK,EAChBC,YAAY,KAAK,EACjBC,gBAAgB,KAAK,EACrBC,aAAa,EACbC,oBAAoB,KAAK,EACzBC,qBAAqB,GAAG,EACxBC,kBAAkB,EAClBC,wBAAwB,EACxBC,yBAAyB,EACzB,GAAGC,WACJ,GAAGvB;IAEJ,MAAM,EACJwB,YAAY,EACZC,eAAe,EACfC,aAAa,EACbC,YAAY,EACZC,iBAAiB,EAClB,GAAG9B,WAAW;QACbG;QACAC;QACAC;QACAC;QACAC;QACAS;QACAN;QACAC;QACAC;QACAM;QACAE;IACF;IAEA,MAAMW,kBAAkBpC,OAAOe;IAC/B,MAAM,CAACsB,SAASC,WAAW,GAAGrC,SAAS;IACvCF,UAAU;QACR,MAAMwC,cAAcxB,gBAAgBqB,gBAAgBI,OAAO;QAC3DJ,gBAAgBI,OAAO,GAAGzB;QAC1B,IAAIU,qBAAqBc,aAAa;YACpC;QACF;QAEAD,WAAW;QACX,MAAMG,UAAUC,WAAWC,UAAU,CAAC;YACpCL,WAAW;QACb,GAAGZ;QAEH,OAAO;YACLgB,WAAWE,YAAY,CAACH;QAC1B;IACF,GAAG;QAAC1B;QAAaU;QAAmBC;KAAmB;IAEvD,qBACE,KAACxB;QAAyB2C,OAAOb;kBAC/B,cAAA,MAACc;YACE,GAAGhB,SAAS;YACZ,GAAGC,YAAY;YAChBgB,MAAK;YACLlC,WAAWT,QAAQ;gBACjBc;gBACAC;gBACAC;gBACAiB,SAAS,CAACZ,qBAAqBY;gBAC/BhB;gBACAC;gBACA0B,WAAW,CAACvB;gBACZD;gBACAX;YACF;;gBAECsB,mCACC,KAAChC;oBACCwB,oBAAoBA;oBACnB,GAAGE,yBAAyB;oBAC5B,GAAGI,aAAa;;gBAGpBnB;gBACAqB,mCACC,KAAChC;oBACCwB,oBAAoBA;oBACnB,GAAGC,wBAAwB;oBAC3B,GAAGM,YAAY;;;;;AAM5B,GACA"}
@@ -368,12 +368,11 @@ $variables: (
368
368
  }
369
369
 
370
370
  @include utils.rtl {
371
- $button-selector: "&__button" +
372
- if(
373
- $disable-tablist-scroll-button-vertical,
374
- "",
375
- ":where(:not(.rmd-tablist-button__button--v))"
376
- );
371
+ $button-selector: "&__button";
372
+ @if not $disable-tablist-scroll-button-vertical {
373
+ $button-selector: $button-selector +
374
+ ":where(:not(.rmd-tablist-button__button--v))";
375
+ }
377
376
 
378
377
  &--left {
379
378
  left: auto;
@@ -66,15 +66,16 @@ import { getTabPanelRoleOnly } from "./utils.js";
66
66
  const { height } = element.style;
67
67
  element.style.height = "";
68
68
  const panels = getTabPanelRoleOnly(element);
69
- const maxHeight = panels.reduce((maxHeight, panel)=>{
69
+ let maxHeight = 0;
70
+ for (const panel of panels){
70
71
  let { scrollHeight } = panel;
71
72
  if (panel.classList.contains(DISPLAY_NONE_CLASS)) {
72
73
  panel.classList.toggle(DISPLAY_NONE_CLASS);
73
74
  ({ scrollHeight } = panel);
74
75
  panel.classList.toggle(DISPLAY_NONE_CLASS);
75
76
  }
76
- return Math.max(maxHeight, scrollHeight);
77
- }, 0);
77
+ maxHeight = Math.max(maxHeight, scrollHeight);
78
+ }
78
79
  element.style.height = height;
79
80
  // don't set the height to 0 since it usually means a calculation issue
80
81
  setHeight((prevHeight)=>maxHeight <= 0 ? prevHeight : maxHeight);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/tabs/useMaxTabPanelHeight.ts"],"sourcesContent":["import { type CSSProperties, type Ref, useCallback, useState } from \"react\";\n\nimport { type UseStateInitializer } from \"../types.js\";\nimport { useResizeObserver } from \"../useResizeObserver.js\";\nimport { DISPLAY_NONE_CLASS } from \"../utils/isElementVisible.js\";\nimport {\n type ProvidedTabPanelsProps,\n type TabsImplementation,\n} from \"./useTabs.js\";\nimport { getTabPanelRoleOnly } from \"./utils.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface MaxTabPanelHeightOptions<E extends HTMLElement> extends Pick<\n TabsImplementation,\n \"getTabPanelsProps\"\n> {\n ref?: Ref<E>;\n style?: CSSProperties;\n\n /**\n * @defaultValue `undefined`\n */\n defaultHeight?: UseStateInitializer<string | number>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ProvidedMaxTabPanelsHeightProps<\n E extends HTMLElement,\n> extends ProvidedTabPanelsProps<E> {\n style: CSSProperties;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface MaxTabPanelHeightImplementation<E extends HTMLElement> {\n getMaxTabPanelHeightProps: (\n style?: CSSProperties\n ) => ProvidedMaxTabPanelsHeightProps<E>;\n}\n\n/**\n * The `useMaxTabPanelHeight` hook can be used to enforce the tab panels to\n * have the same height so content does not shift below the tab panels by\n * calculating the height of all tabs and setting the height to the largest\n * value.\n *\n * If a maximum height should be used, set it through CSS and scrollbars will\n * appear in each tab panel.\n *\n * @example Main Usage\n * ```tsx\n * import { Tab } from \"@react-md/core/tabs/Tab\";\n * import { TabList } from \"@react-md/core/tabs/TabList\";\n * import { useMaxTabPanelHeight } from \"@react-md/core/tabs/useMaxTabPanelHeight\";\n * import { useTabs } from \"@react-md/core/tabs/useTabs\";\n * import { Slide } from \"@react-md/core/transition/Slide\";\n * import { SlideContainer } from \"@react-md/core/transition/SlideContainer\";\n * import { Typography } from \"@react-md/core/typography/Typography\";\n * import { type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { getTabProps, getTabListProps, getTabPanelProps, getTabPanelsProps } =\n * useTabs();\n * const { getMaxTabPanelHeightProps } = useMaxTabPanelHeight({\n * getTabPanelsProps,\n * });\n *\n * return (\n * <>\n * <TabList {...getTabListProps()}>\n * <Tab {...getTabProps(0)}>Tab 1</Tab>\n * <Tab {...getTabProps(1)}>Tab 2</Tab>\n * <Tab {...getTabProps(2)}>Tab 3</Tab>\n * </TabList>\n * <SlideContainer {...getMaxTabPanelHeightProps()}>\n * <Slide {...getTabPanelProps(0)}>\n * <Tab1Content />\n * </Slide>\n * <Slide {...getTabPanelProps(1)}>\n * <Tab2Content />\n * </Slide>\n * <Slide {...getTabPanelProps(2)}>\n * <Tab3Content />\n * </Slide>\n * </SlideContainer>\n * </>\n * );\n * }\n * ```\n *\n * NOTE: This will **not work** when dynamically rendering the active tab panel\n * by enabling the `temporary` prop on the `Slide` or custom behavior.\n *\n * @since 6.0.0\n */\nexport function useMaxTabPanelHeight<E extends HTMLElement = HTMLDivElement>(\n options: MaxTabPanelHeightOptions<E>\n): MaxTabPanelHeightImplementation<E> {\n const { ref, style, defaultHeight, getTabPanelsProps } = options;\n\n const [height, setHeight] = useState(defaultHeight);\n const panelRef = useResizeObserver({\n ref,\n onUpdate: useCallback((entry) => {\n const element = entry.target as HTMLElement;\n const { height } = element.style;\n element.style.height = \"\";\n const panels = getTabPanelRoleOnly(element);\n const maxHeight = panels.reduce((maxHeight, panel) => {\n let { scrollHeight } = panel;\n if (panel.classList.contains(DISPLAY_NONE_CLASS)) {\n panel.classList.toggle(DISPLAY_NONE_CLASS);\n ({ scrollHeight } = panel);\n panel.classList.toggle(DISPLAY_NONE_CLASS);\n }\n\n return Math.max(maxHeight, scrollHeight);\n }, 0);\n element.style.height = height;\n\n // don't set the height to 0 since it usually means a calculation issue\n setHeight((prevHeight) => (maxHeight <= 0 ? prevHeight : maxHeight));\n }, []),\n });\n\n return {\n getMaxTabPanelHeightProps: (moreStyle) => ({\n ...getTabPanelsProps(panelRef),\n style: {\n height,\n ...style,\n ...moreStyle,\n },\n }),\n };\n}\n"],"names":["useCallback","useState","useResizeObserver","DISPLAY_NONE_CLASS","getTabPanelRoleOnly","useMaxTabPanelHeight","options","ref","style","defaultHeight","getTabPanelsProps","height","setHeight","panelRef","onUpdate","entry","element","target","panels","maxHeight","reduce","panel","scrollHeight","classList","contains","toggle","Math","max","prevHeight","getMaxTabPanelHeightProps","moreStyle"],"mappings":"AAAA,SAAuCA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AAG5E,SAASC,iBAAiB,QAAQ,0BAA0B;AAC5D,SAASC,kBAAkB,QAAQ,+BAA+B;AAKlE,SAASC,mBAAmB,QAAQ,aAAa;AAoCjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDC,GACD,OAAO,SAASC,qBACdC,OAAoC;IAEpC,MAAM,EAAEC,GAAG,EAAEC,KAAK,EAAEC,aAAa,EAAEC,iBAAiB,EAAE,GAAGJ;IAEzD,MAAM,CAACK,QAAQC,UAAU,GAAGX,SAASQ;IACrC,MAAMI,WAAWX,kBAAkB;QACjCK;QACAO,UAAUd,YAAY,CAACe;YACrB,MAAMC,UAAUD,MAAME,MAAM;YAC5B,MAAM,EAAEN,MAAM,EAAE,GAAGK,QAAQR,KAAK;YAChCQ,QAAQR,KAAK,CAACG,MAAM,GAAG;YACvB,MAAMO,SAASd,oBAAoBY;YACnC,MAAMG,YAAYD,OAAOE,MAAM,CAAC,CAACD,WAAWE;gBAC1C,IAAI,EAAEC,YAAY,EAAE,GAAGD;gBACvB,IAAIA,MAAME,SAAS,CAACC,QAAQ,CAACrB,qBAAqB;oBAChDkB,MAAME,SAAS,CAACE,MAAM,CAACtB;oBACtB,CAAA,EAAEmB,YAAY,EAAE,GAAGD,KAAI;oBACxBA,MAAME,SAAS,CAACE,MAAM,CAACtB;gBACzB;gBAEA,OAAOuB,KAAKC,GAAG,CAACR,WAAWG;YAC7B,GAAG;YACHN,QAAQR,KAAK,CAACG,MAAM,GAAGA;YAEvB,uEAAuE;YACvEC,UAAU,CAACgB,aAAgBT,aAAa,IAAIS,aAAaT;QAC3D,GAAG,EAAE;IACP;IAEA,OAAO;QACLU,2BAA2B,CAACC,YAAe,CAAA;gBACzC,GAAGpB,kBAAkBG,SAAS;gBAC9BL,OAAO;oBACLG;oBACA,GAAGH,KAAK;oBACR,GAAGsB,SAAS;gBACd;YACF,CAAA;IACF;AACF"}
1
+ {"version":3,"sources":["../../src/tabs/useMaxTabPanelHeight.ts"],"sourcesContent":["import { type CSSProperties, type Ref, useCallback, useState } from \"react\";\n\nimport { type UseStateInitializer } from \"../types.js\";\nimport { useResizeObserver } from \"../useResizeObserver.js\";\nimport { DISPLAY_NONE_CLASS } from \"../utils/isElementVisible.js\";\nimport {\n type ProvidedTabPanelsProps,\n type TabsImplementation,\n} from \"./useTabs.js\";\nimport { getTabPanelRoleOnly } from \"./utils.js\";\n\n/**\n * @since 6.0.0\n */\nexport interface MaxTabPanelHeightOptions<E extends HTMLElement> extends Pick<\n TabsImplementation,\n \"getTabPanelsProps\"\n> {\n ref?: Ref<E>;\n style?: CSSProperties;\n\n /**\n * @defaultValue `undefined`\n */\n defaultHeight?: UseStateInitializer<string | number>;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface ProvidedMaxTabPanelsHeightProps<\n E extends HTMLElement,\n> extends ProvidedTabPanelsProps<E> {\n style: CSSProperties;\n}\n\n/**\n * @since 6.0.0\n */\nexport interface MaxTabPanelHeightImplementation<E extends HTMLElement> {\n getMaxTabPanelHeightProps: (\n style?: CSSProperties\n ) => ProvidedMaxTabPanelsHeightProps<E>;\n}\n\n/**\n * The `useMaxTabPanelHeight` hook can be used to enforce the tab panels to\n * have the same height so content does not shift below the tab panels by\n * calculating the height of all tabs and setting the height to the largest\n * value.\n *\n * If a maximum height should be used, set it through CSS and scrollbars will\n * appear in each tab panel.\n *\n * @example Main Usage\n * ```tsx\n * import { Tab } from \"@react-md/core/tabs/Tab\";\n * import { TabList } from \"@react-md/core/tabs/TabList\";\n * import { useMaxTabPanelHeight } from \"@react-md/core/tabs/useMaxTabPanelHeight\";\n * import { useTabs } from \"@react-md/core/tabs/useTabs\";\n * import { Slide } from \"@react-md/core/transition/Slide\";\n * import { SlideContainer } from \"@react-md/core/transition/SlideContainer\";\n * import { Typography } from \"@react-md/core/typography/Typography\";\n * import { type ReactElement } from \"react\";\n *\n * function Example(): ReactElement {\n * const { getTabProps, getTabListProps, getTabPanelProps, getTabPanelsProps } =\n * useTabs();\n * const { getMaxTabPanelHeightProps } = useMaxTabPanelHeight({\n * getTabPanelsProps,\n * });\n *\n * return (\n * <>\n * <TabList {...getTabListProps()}>\n * <Tab {...getTabProps(0)}>Tab 1</Tab>\n * <Tab {...getTabProps(1)}>Tab 2</Tab>\n * <Tab {...getTabProps(2)}>Tab 3</Tab>\n * </TabList>\n * <SlideContainer {...getMaxTabPanelHeightProps()}>\n * <Slide {...getTabPanelProps(0)}>\n * <Tab1Content />\n * </Slide>\n * <Slide {...getTabPanelProps(1)}>\n * <Tab2Content />\n * </Slide>\n * <Slide {...getTabPanelProps(2)}>\n * <Tab3Content />\n * </Slide>\n * </SlideContainer>\n * </>\n * );\n * }\n * ```\n *\n * NOTE: This will **not work** when dynamically rendering the active tab panel\n * by enabling the `temporary` prop on the `Slide` or custom behavior.\n *\n * @since 6.0.0\n */\nexport function useMaxTabPanelHeight<E extends HTMLElement = HTMLDivElement>(\n options: MaxTabPanelHeightOptions<E>\n): MaxTabPanelHeightImplementation<E> {\n const { ref, style, defaultHeight, getTabPanelsProps } = options;\n\n const [height, setHeight] = useState(defaultHeight);\n const panelRef = useResizeObserver({\n ref,\n onUpdate: useCallback((entry) => {\n const element = entry.target as HTMLElement;\n const { height } = element.style;\n element.style.height = \"\";\n const panels = getTabPanelRoleOnly(element);\n\n let maxHeight = 0;\n for (const panel of panels) {\n let { scrollHeight } = panel;\n if (panel.classList.contains(DISPLAY_NONE_CLASS)) {\n panel.classList.toggle(DISPLAY_NONE_CLASS);\n ({ scrollHeight } = panel);\n panel.classList.toggle(DISPLAY_NONE_CLASS);\n }\n\n maxHeight = Math.max(maxHeight, scrollHeight);\n }\n\n element.style.height = height;\n\n // don't set the height to 0 since it usually means a calculation issue\n setHeight((prevHeight) => (maxHeight <= 0 ? prevHeight : maxHeight));\n }, []),\n });\n\n return {\n getMaxTabPanelHeightProps: (moreStyle) => ({\n ...getTabPanelsProps(panelRef),\n style: {\n height,\n ...style,\n ...moreStyle,\n },\n }),\n };\n}\n"],"names":["useCallback","useState","useResizeObserver","DISPLAY_NONE_CLASS","getTabPanelRoleOnly","useMaxTabPanelHeight","options","ref","style","defaultHeight","getTabPanelsProps","height","setHeight","panelRef","onUpdate","entry","element","target","panels","maxHeight","panel","scrollHeight","classList","contains","toggle","Math","max","prevHeight","getMaxTabPanelHeightProps","moreStyle"],"mappings":"AAAA,SAAuCA,WAAW,EAAEC,QAAQ,QAAQ,QAAQ;AAG5E,SAASC,iBAAiB,QAAQ,0BAA0B;AAC5D,SAASC,kBAAkB,QAAQ,+BAA+B;AAKlE,SAASC,mBAAmB,QAAQ,aAAa;AAoCjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDC,GACD,OAAO,SAASC,qBACdC,OAAoC;IAEpC,MAAM,EAAEC,GAAG,EAAEC,KAAK,EAAEC,aAAa,EAAEC,iBAAiB,EAAE,GAAGJ;IAEzD,MAAM,CAACK,QAAQC,UAAU,GAAGX,SAASQ;IACrC,MAAMI,WAAWX,kBAAkB;QACjCK;QACAO,UAAUd,YAAY,CAACe;YACrB,MAAMC,UAAUD,MAAME,MAAM;YAC5B,MAAM,EAAEN,MAAM,EAAE,GAAGK,QAAQR,KAAK;YAChCQ,QAAQR,KAAK,CAACG,MAAM,GAAG;YACvB,MAAMO,SAASd,oBAAoBY;YAEnC,IAAIG,YAAY;YAChB,KAAK,MAAMC,SAASF,OAAQ;gBAC1B,IAAI,EAAEG,YAAY,EAAE,GAAGD;gBACvB,IAAIA,MAAME,SAAS,CAACC,QAAQ,CAACpB,qBAAqB;oBAChDiB,MAAME,SAAS,CAACE,MAAM,CAACrB;oBACtB,CAAA,EAAEkB,YAAY,EAAE,GAAGD,KAAI;oBACxBA,MAAME,SAAS,CAACE,MAAM,CAACrB;gBACzB;gBAEAgB,YAAYM,KAAKC,GAAG,CAACP,WAAWE;YAClC;YAEAL,QAAQR,KAAK,CAACG,MAAM,GAAGA;YAEvB,uEAAuE;YACvEC,UAAU,CAACe,aAAgBR,aAAa,IAAIQ,aAAaR;QAC3D,GAAG,EAAE;IACP;IAEA,OAAO;QACLS,2BAA2B,CAACC,YAAe,CAAA;gBACzC,GAAGnB,kBAAkBG,SAAS;gBAC9BL,OAAO;oBACLG;oBACA,GAAGH,KAAK;oBACR,GAAGqB,SAAS;gBACd;YACF,CAAA;IACF;AACF"}
@@ -82,7 +82,7 @@ const noop = ()=>{
82
82
  }
83
83
  const clickedTab = event.target.closest("[role='tab']");
84
84
  const tabs = getTabRoleOnly(event.currentTarget);
85
- const i = tabs.findIndex((tab)=>tab === clickedTab);
85
+ const i = clickedTab ? tabs.indexOf(clickedTab) : -1;
86
86
  if (i !== -1) {
87
87
  setActiveIndex(i);
88
88
  }