@mantine/hooks 9.0.1 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/index.cjs +8 -0
- package/cjs/use-click-outside/use-click-outside.cjs +11 -8
- package/cjs/use-click-outside/use-click-outside.cjs.map +1 -1
- package/cjs/use-clipboard/use-clipboard.cjs +13 -6
- package/cjs/use-clipboard/use-clipboard.cjs.map +1 -1
- package/cjs/use-collapse/use-collapse.cjs +1 -1
- package/cjs/use-collapse/use-collapse.cjs.map +1 -1
- package/cjs/use-collapse/use-horizontal-collapse.cjs +4 -3
- package/cjs/use-collapse/use-horizontal-collapse.cjs.map +1 -1
- package/cjs/use-counter/use-counter.cjs +12 -3
- package/cjs/use-counter/use-counter.cjs.map +1 -1
- package/cjs/use-debounced-callback/use-debounced-callback.cjs +28 -4
- package/cjs/use-debounced-callback/use-debounced-callback.cjs.map +1 -1
- package/cjs/use-debounced-state/use-debounced-state.cjs +1 -1
- package/cjs/use-debounced-state/use-debounced-state.cjs.map +1 -1
- package/cjs/use-debounced-value/use-debounced-value.cjs +22 -2
- package/cjs/use-debounced-value/use-debounced-value.cjs.map +1 -1
- package/cjs/use-event-listener/use-event-listener.cjs.map +1 -1
- package/cjs/use-favicon/use-favicon.cjs +3 -1
- package/cjs/use-favicon/use-favicon.cjs.map +1 -1
- package/cjs/use-fetch/use-fetch.cjs +7 -4
- package/cjs/use-fetch/use-fetch.cjs.map +1 -1
- package/cjs/use-file-dialog/use-file-dialog.cjs +1 -0
- package/cjs/use-file-dialog/use-file-dialog.cjs.map +1 -1
- package/cjs/use-floating-window/use-floating-window.cjs +33 -36
- package/cjs/use-floating-window/use-floating-window.cjs.map +1 -1
- package/cjs/use-focus-trap/use-focus-trap.cjs +12 -9
- package/cjs/use-focus-trap/use-focus-trap.cjs.map +1 -1
- package/cjs/use-fullscreen/use-fullscreen.cjs +3 -1
- package/cjs/use-fullscreen/use-fullscreen.cjs.map +1 -1
- package/cjs/use-headroom/use-headroom.cjs +4 -1
- package/cjs/use-headroom/use-headroom.cjs.map +1 -1
- package/cjs/use-hotkeys/parse-hotkey.cjs +1 -2
- package/cjs/use-hotkeys/parse-hotkey.cjs.map +1 -1
- package/cjs/use-hover/use-hover.cjs +1 -0
- package/cjs/use-hover/use-hover.cjs.map +1 -1
- package/cjs/use-in-viewport/use-in-viewport.cjs +11 -7
- package/cjs/use-in-viewport/use-in-viewport.cjs.map +1 -1
- package/cjs/use-interval/use-interval.cjs +15 -6
- package/cjs/use-interval/use-interval.cjs.map +1 -1
- package/cjs/use-local-storage/create-storage.cjs +1 -1
- package/cjs/use-local-storage/create-storage.cjs.map +1 -1
- package/cjs/use-long-press/use-long-press.cjs +6 -2
- package/cjs/use-long-press/use-long-press.cjs.map +1 -1
- package/cjs/use-mask/use-mask.cjs +457 -0
- package/cjs/use-mask/use-mask.cjs.map +1 -0
- package/cjs/use-mouse/use-mouse.cjs +2 -2
- package/cjs/use-mouse/use-mouse.cjs.map +1 -1
- package/cjs/use-move/use-move.cjs +8 -0
- package/cjs/use-move/use-move.cjs.map +1 -1
- package/cjs/use-orientation/use-orientation.cjs +8 -2
- package/cjs/use-orientation/use-orientation.cjs.map +1 -1
- package/cjs/use-os/use-os.cjs +1 -1
- package/cjs/use-os/use-os.cjs.map +1 -1
- package/cjs/use-radial-move/use-radial-move.cjs +4 -4
- package/cjs/use-radial-move/use-radial-move.cjs.map +1 -1
- package/cjs/use-roving-index/use-roving-index.cjs +200 -0
- package/cjs/use-roving-index/use-roving-index.cjs.map +1 -0
- package/cjs/use-scroll-direction/use-scroll-direction.cjs +7 -7
- package/cjs/use-scroll-direction/use-scroll-direction.cjs.map +1 -1
- package/cjs/use-scroll-into-view/use-scroll-into-view.cjs +14 -4
- package/cjs/use-scroll-into-view/use-scroll-into-view.cjs.map +1 -1
- package/cjs/use-scroll-spy/use-scroll-spy.cjs +7 -3
- package/cjs/use-scroll-spy/use-scroll-spy.cjs.map +1 -1
- package/cjs/use-scroller/use-scroller.cjs +3 -3
- package/cjs/use-scroller/use-scroller.cjs.map +1 -1
- package/cjs/use-set/use-set.cjs +6 -1
- package/cjs/use-set/use-set.cjs.map +1 -1
- package/cjs/use-throttled-callback/use-throttled-callback.cjs +3 -1
- package/cjs/use-throttled-callback/use-throttled-callback.cjs.map +1 -1
- package/cjs/use-timeout/use-timeout.cjs +3 -1
- package/cjs/use-timeout/use-timeout.cjs.map +1 -1
- package/cjs/use-viewport-size/use-viewport-size.cjs +3 -3
- package/cjs/use-viewport-size/use-viewport-size.cjs.map +1 -1
- package/cjs/use-window-scroll/use-window-scroll.cjs +2 -2
- package/cjs/use-window-scroll/use-window-scroll.cjs.map +1 -1
- package/esm/index.mjs +3 -1
- package/esm/use-click-outside/use-click-outside.mjs +11 -8
- package/esm/use-click-outside/use-click-outside.mjs.map +1 -1
- package/esm/use-clipboard/use-clipboard.mjs +14 -7
- package/esm/use-clipboard/use-clipboard.mjs.map +1 -1
- package/esm/use-collapse/use-collapse.mjs +1 -1
- package/esm/use-collapse/use-collapse.mjs.map +1 -1
- package/esm/use-collapse/use-horizontal-collapse.mjs +5 -4
- package/esm/use-collapse/use-horizontal-collapse.mjs.map +1 -1
- package/esm/use-counter/use-counter.mjs +12 -3
- package/esm/use-counter/use-counter.mjs.map +1 -1
- package/esm/use-debounced-callback/use-debounced-callback.mjs +28 -4
- package/esm/use-debounced-callback/use-debounced-callback.mjs.map +1 -1
- package/esm/use-debounced-state/use-debounced-state.mjs +1 -1
- package/esm/use-debounced-state/use-debounced-state.mjs.map +1 -1
- package/esm/use-debounced-value/use-debounced-value.mjs +22 -2
- package/esm/use-debounced-value/use-debounced-value.mjs.map +1 -1
- package/esm/use-event-listener/use-event-listener.mjs.map +1 -1
- package/esm/use-favicon/use-favicon.mjs +3 -1
- package/esm/use-favicon/use-favicon.mjs.map +1 -1
- package/esm/use-fetch/use-fetch.mjs +7 -4
- package/esm/use-fetch/use-fetch.mjs.map +1 -1
- package/esm/use-file-dialog/use-file-dialog.mjs +1 -0
- package/esm/use-file-dialog/use-file-dialog.mjs.map +1 -1
- package/esm/use-floating-window/use-floating-window.mjs +33 -36
- package/esm/use-floating-window/use-floating-window.mjs.map +1 -1
- package/esm/use-focus-trap/use-focus-trap.mjs +12 -9
- package/esm/use-focus-trap/use-focus-trap.mjs.map +1 -1
- package/esm/use-fullscreen/use-fullscreen.mjs +3 -1
- package/esm/use-fullscreen/use-fullscreen.mjs.map +1 -1
- package/esm/use-headroom/use-headroom.mjs +4 -1
- package/esm/use-headroom/use-headroom.mjs.map +1 -1
- package/esm/use-hotkeys/parse-hotkey.mjs +1 -2
- package/esm/use-hotkeys/parse-hotkey.mjs.map +1 -1
- package/esm/use-hover/use-hover.mjs +1 -0
- package/esm/use-hover/use-hover.mjs.map +1 -1
- package/esm/use-in-viewport/use-in-viewport.mjs +11 -7
- package/esm/use-in-viewport/use-in-viewport.mjs.map +1 -1
- package/esm/use-interval/use-interval.mjs +15 -6
- package/esm/use-interval/use-interval.mjs.map +1 -1
- package/esm/use-local-storage/create-storage.mjs +1 -1
- package/esm/use-local-storage/create-storage.mjs.map +1 -1
- package/esm/use-long-press/use-long-press.mjs +6 -2
- package/esm/use-long-press/use-long-press.mjs.map +1 -1
- package/esm/use-mask/use-mask.mjs +453 -0
- package/esm/use-mask/use-mask.mjs.map +1 -0
- package/esm/use-mouse/use-mouse.mjs +2 -2
- package/esm/use-mouse/use-mouse.mjs.map +1 -1
- package/esm/use-move/use-move.mjs +8 -0
- package/esm/use-move/use-move.mjs.map +1 -1
- package/esm/use-orientation/use-orientation.mjs +8 -2
- package/esm/use-orientation/use-orientation.mjs.map +1 -1
- package/esm/use-os/use-os.mjs +1 -1
- package/esm/use-os/use-os.mjs.map +1 -1
- package/esm/use-radial-move/use-radial-move.mjs +5 -5
- package/esm/use-radial-move/use-radial-move.mjs.map +1 -1
- package/esm/use-roving-index/use-roving-index.mjs +200 -0
- package/esm/use-roving-index/use-roving-index.mjs.map +1 -0
- package/esm/use-scroll-direction/use-scroll-direction.mjs +7 -7
- package/esm/use-scroll-direction/use-scroll-direction.mjs.map +1 -1
- package/esm/use-scroll-into-view/use-scroll-into-view.mjs +15 -5
- package/esm/use-scroll-into-view/use-scroll-into-view.mjs.map +1 -1
- package/esm/use-scroll-spy/use-scroll-spy.mjs +8 -4
- package/esm/use-scroll-spy/use-scroll-spy.mjs.map +1 -1
- package/esm/use-scroller/use-scroller.mjs +3 -3
- package/esm/use-scroller/use-scroller.mjs.map +1 -1
- package/esm/use-set/use-set.mjs +6 -1
- package/esm/use-set/use-set.mjs.map +1 -1
- package/esm/use-throttled-callback/use-throttled-callback.mjs +3 -1
- package/esm/use-throttled-callback/use-throttled-callback.mjs.map +1 -1
- package/esm/use-timeout/use-timeout.mjs +3 -1
- package/esm/use-timeout/use-timeout.mjs.map +1 -1
- package/esm/use-viewport-size/use-viewport-size.mjs +3 -3
- package/esm/use-viewport-size/use-viewport-size.mjs.map +1 -1
- package/esm/use-window-scroll/use-window-scroll.mjs +2 -2
- package/esm/use-window-scroll/use-window-scroll.mjs.map +1 -1
- package/lib/index.d.mts +5 -1
- package/lib/index.d.ts +5 -1
- package/lib/use-click-outside/use-click-outside.d.ts +1 -1
- package/lib/use-collapse/use-horizontal-collapse.d.ts +5 -0
- package/lib/use-counter/use-counter.d.ts +1 -0
- package/lib/use-debounced-callback/use-debounced-callback.d.ts +4 -0
- package/lib/use-debounced-value/use-debounced-value.d.ts +6 -1
- package/lib/use-event-listener/use-event-listener.d.ts +1 -1
- package/lib/use-hotkeys/parse-hotkey.d.ts +4 -5
- package/lib/use-long-press/use-long-press.d.ts +1 -0
- package/lib/use-mask/use-mask.d.ts +60 -0
- package/lib/use-roving-index/use-roving-index.d.ts +49 -0
- package/lib/use-scroll-into-view/use-scroll-into-view.d.ts +4 -1
- package/package.json +1 -1
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { useWindowEvent } from "../use-window-event/use-window-event.mjs";
|
|
3
3
|
import { useReducedMotion } from "../use-reduced-motion/use-reduced-motion.mjs";
|
|
4
|
-
import { useCallback, useEffect, useRef } from "react";
|
|
4
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
5
5
|
//#region packages/@mantine/hooks/src/use-scroll-into-view/use-scroll-into-view.ts
|
|
6
|
-
function useScrollIntoView({ duration = 1250, axis = "y", onScrollFinish, easing = easeInOutQuad, offset = 0, cancelable = true, isList = false } = {}) {
|
|
6
|
+
function useScrollIntoView({ duration = 1250, axis = "y", onScrollFinish, onScrollCancel, easing = easeInOutQuad, offset = 0, cancelable = true, isList = false } = {}) {
|
|
7
7
|
const frameID = useRef(0);
|
|
8
8
|
const startTime = useRef(0);
|
|
9
9
|
const shouldStop = useRef(false);
|
|
10
|
+
const [scrolling, setScrolling] = useState(false);
|
|
10
11
|
const scrollableRef = useRef(null);
|
|
11
12
|
const targetRef = useRef(null);
|
|
12
13
|
const reducedMotion = useReducedMotion();
|
|
13
14
|
const cancel = () => {
|
|
14
|
-
if (frameID.current)
|
|
15
|
+
if (frameID.current) {
|
|
16
|
+
cancelAnimationFrame(frameID.current);
|
|
17
|
+
frameID.current = 0;
|
|
18
|
+
setScrolling(false);
|
|
19
|
+
}
|
|
15
20
|
};
|
|
16
21
|
const scrollIntoView = useCallback(({ alignment = "start" } = {}) => {
|
|
17
22
|
shouldStop.current = false;
|
|
@@ -28,6 +33,7 @@ function useScrollIntoView({ duration = 1250, axis = "y", onScrollFinish, easing
|
|
|
28
33
|
offset,
|
|
29
34
|
isList
|
|
30
35
|
}) - (scrollableRef.current ? 0 : start);
|
|
36
|
+
setScrolling(true);
|
|
31
37
|
function animateScroll() {
|
|
32
38
|
if (startTime.current === 0) startTime.current = performance.now();
|
|
33
39
|
const elapsed = performance.now() - startTime.current;
|
|
@@ -40,9 +46,11 @@ function useScrollIntoView({ duration = 1250, axis = "y", onScrollFinish, easing
|
|
|
40
46
|
});
|
|
41
47
|
if (!shouldStop.current && t < 1) frameID.current = requestAnimationFrame(animateScroll);
|
|
42
48
|
else {
|
|
43
|
-
typeof
|
|
49
|
+
if (shouldStop.current) typeof onScrollCancel === "function" && onScrollCancel();
|
|
50
|
+
else typeof onScrollFinish === "function" && onScrollFinish();
|
|
44
51
|
startTime.current = 0;
|
|
45
52
|
frameID.current = 0;
|
|
53
|
+
setScrolling(false);
|
|
46
54
|
cancel();
|
|
47
55
|
}
|
|
48
56
|
}
|
|
@@ -54,6 +62,7 @@ function useScrollIntoView({ duration = 1250, axis = "y", onScrollFinish, easing
|
|
|
54
62
|
isList,
|
|
55
63
|
offset,
|
|
56
64
|
onScrollFinish,
|
|
65
|
+
onScrollCancel,
|
|
57
66
|
reducedMotion
|
|
58
67
|
]);
|
|
59
68
|
const handleStop = () => {
|
|
@@ -71,7 +80,8 @@ function useScrollIntoView({ duration = 1250, axis = "y", onScrollFinish, easing
|
|
|
71
80
|
scrollableRef,
|
|
72
81
|
targetRef,
|
|
73
82
|
scrollIntoView,
|
|
74
|
-
cancel
|
|
83
|
+
cancel,
|
|
84
|
+
scrolling
|
|
75
85
|
};
|
|
76
86
|
}
|
|
77
87
|
function easeInOutQuad(t) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-scroll-into-view.mjs","names":[],"sources":["../../src/use-scroll-into-view/use-scroll-into-view.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { useReducedMotion } from '../use-reduced-motion/use-reduced-motion';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\ninterface UseScrollIntoViewAnimation {\n /** Target element alignment relatively to parent based on current axis */\n alignment?: 'start' | 'end' | 'center';\n}\n\nexport interface UseScrollIntoViewOptions {\n /** Callback fired after scroll */\n onScrollFinish?: () => void;\n\n /** Duration of scroll in milliseconds */\n duration?: number;\n\n /** Axis of scroll */\n axis?: 'x' | 'y';\n\n /** Custom mathematical easing function */\n easing?: (t: number) => number;\n\n /** Additional distance between nearest edge and element */\n offset?: number;\n\n /** Indicator if animation may be interrupted by user scrolling */\n cancelable?: boolean;\n\n /** Prevents content jumping in scrolling lists with multiple targets */\n isList?: boolean;\n}\n\nexport interface UseScrollIntoViewReturnValue<\n Target extends HTMLElement = any,\n Parent extends HTMLElement | null = null,\n> {\n scrollableRef: React.RefObject<Parent | null>;\n targetRef: React.RefObject<Target | null>;\n scrollIntoView: (params?: UseScrollIntoViewAnimation) => void;\n cancel: () => void;\n}\n\nexport function useScrollIntoView<\n Target extends HTMLElement = any,\n Parent extends HTMLElement | null = null,\n>({\n duration = 1250,\n axis = 'y',\n onScrollFinish,\n easing = easeInOutQuad,\n offset = 0,\n cancelable = true,\n isList = false,\n}: UseScrollIntoViewOptions = {}): UseScrollIntoViewReturnValue<Target, Parent> {\n const frameID = useRef(0);\n const startTime = useRef(0);\n const shouldStop = useRef(false);\n\n const scrollableRef = useRef<Parent | null>(null);\n const targetRef = useRef<Target | null>(null);\n\n const reducedMotion = useReducedMotion();\n\n const cancel = (): void => {\n if (frameID.current) {\n cancelAnimationFrame(frameID.current);\n }\n };\n\n const scrollIntoView = useCallback(\n ({ alignment = 'start' }: UseScrollIntoViewAnimation = {}) => {\n shouldStop.current = false;\n\n if (frameID.current) {\n cancel();\n }\n\n const start = getScrollStart({ parent: scrollableRef.current, axis }) ?? 0;\n\n const change =\n getRelativePosition({\n parent: scrollableRef.current,\n target: targetRef.current,\n axis,\n alignment,\n offset,\n isList,\n }) - (scrollableRef.current ? 0 : start);\n\n function animateScroll() {\n if (startTime.current === 0) {\n startTime.current = performance.now();\n }\n\n const now = performance.now();\n const elapsed = now - startTime.current;\n\n // Easing timing progress\n const t = reducedMotion || duration === 0 ? 1 : elapsed / duration;\n\n const distance = start + change * easing(t);\n\n setScrollParam({\n parent: scrollableRef.current,\n axis,\n distance,\n });\n\n if (!shouldStop.current && t < 1) {\n frameID.current = requestAnimationFrame(animateScroll);\n } else {\n typeof onScrollFinish === 'function' && onScrollFinish();\n startTime.current = 0;\n frameID.current = 0;\n cancel();\n }\n }\n animateScroll();\n },\n [axis, duration, easing, isList, offset, onScrollFinish, reducedMotion]\n );\n\n const handleStop = () => {\n if (cancelable) {\n shouldStop.current = true;\n }\n };\n\n /**\n * Detection of one of these events stops scroll animation\n * wheel - mouse wheel / touch pad\n * touchmove - any touchable device\n */\n\n useWindowEvent('wheel', handleStop, {\n passive: true,\n });\n\n useWindowEvent('touchmove', handleStop, {\n passive: true,\n });\n\n // Cleanup requestAnimationFrame\n useEffect(() => cancel, []);\n\n return {\n scrollableRef,\n targetRef,\n scrollIntoView,\n cancel,\n };\n}\n\n// ---------------------------------------------------\n// Helpers\n// ---------------------------------------------------\n\nfunction easeInOutQuad(t: number) {\n return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;\n}\n\nfunction getRelativePosition({ axis, target, parent, alignment, offset, isList }: any): number {\n if (!target || (!parent && typeof document === 'undefined')) {\n return 0;\n }\n const isCustomParent = !!parent;\n const parentElement = parent || document.body;\n const parentPosition = parentElement.getBoundingClientRect();\n const targetPosition = target.getBoundingClientRect();\n\n const getDiff = (property: 'top' | 'left'): number =>\n targetPosition[property] - parentPosition[property];\n\n if (axis === 'y') {\n const diff = getDiff('top');\n\n if (diff === 0) {\n return 0;\n }\n\n if (alignment === 'start') {\n const distance = diff - offset;\n const shouldScroll = distance <= targetPosition.height * (isList ? 0 : 1) || !isList;\n\n return shouldScroll ? distance : 0;\n }\n\n const parentHeight = isCustomParent ? parentPosition.height : window.innerHeight;\n\n if (alignment === 'end') {\n const distance = diff + offset - parentHeight + targetPosition.height;\n const shouldScroll = distance >= -targetPosition.height * (isList ? 0 : 1) || !isList;\n\n return shouldScroll ? distance : 0;\n }\n\n if (alignment === 'center') {\n return diff - parentHeight / 2 + targetPosition.height / 2;\n }\n\n return 0;\n }\n\n if (axis === 'x') {\n const diff = getDiff('left');\n\n if (diff === 0) {\n return 0;\n }\n\n if (alignment === 'start') {\n const distance = diff - offset;\n const shouldScroll = distance <= targetPosition.width || !isList;\n\n return shouldScroll ? distance : 0;\n }\n\n const parentWidth = isCustomParent ? parentPosition.width : window.innerWidth;\n\n if (alignment === 'end') {\n const distance = diff + offset - parentWidth + targetPosition.width;\n const shouldScroll = distance >= -targetPosition.width || !isList;\n\n return shouldScroll ? distance : 0;\n }\n\n if (alignment === 'center') {\n return diff - parentWidth / 2 + targetPosition.width / 2;\n }\n\n return 0;\n }\n\n return 0;\n}\n\nfunction getScrollStart({ axis, parent }: any) {\n if (!parent && typeof document === 'undefined') {\n return 0;\n }\n\n const method = axis === 'y' ? 'scrollTop' : 'scrollLeft';\n\n if (parent) {\n return parent[method];\n }\n\n const { body, documentElement } = document;\n\n // While one of it has a value the second is equal 0\n return body[method] + documentElement[method];\n}\n\nfunction setScrollParam({ axis, parent, distance }: any) {\n if (!parent && typeof document === 'undefined') {\n return;\n }\n\n const method = axis === 'y' ? 'scrollTop' : 'scrollLeft';\n\n if (parent) {\n parent[method] = distance;\n } else {\n const { body, documentElement } = document;\n body[method] = distance;\n documentElement[method] = distance;\n }\n}\n\nexport namespace useScrollIntoView {\n export type Options = UseScrollIntoViewOptions;\n export type ReturnValue<\n Target extends HTMLElement,\n Parent extends HTMLElement | null,\n > = UseScrollIntoViewReturnValue<Target, Parent>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"use-scroll-into-view.mjs","names":[],"sources":["../../src/use-scroll-into-view/use-scroll-into-view.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useReducedMotion } from '../use-reduced-motion/use-reduced-motion';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\ninterface UseScrollIntoViewAnimation {\n /** Target element alignment relatively to parent based on current axis */\n alignment?: 'start' | 'end' | 'center';\n}\n\nexport interface UseScrollIntoViewOptions {\n /** Callback fired after scroll */\n onScrollFinish?: () => void;\n\n /** Callback fired when scroll animation is canceled by user interaction */\n onScrollCancel?: () => void;\n\n /** Duration of scroll in milliseconds */\n duration?: number;\n\n /** Axis of scroll */\n axis?: 'x' | 'y';\n\n /** Custom mathematical easing function */\n easing?: (t: number) => number;\n\n /** Additional distance between nearest edge and element */\n offset?: number;\n\n /** Indicator if animation may be interrupted by user scrolling */\n cancelable?: boolean;\n\n /** Prevents content jumping in scrolling lists with multiple targets */\n isList?: boolean;\n}\n\nexport interface UseScrollIntoViewReturnValue<\n Target extends HTMLElement = any,\n Parent extends HTMLElement | null = null,\n> {\n scrollableRef: React.RefObject<Parent | null>;\n targetRef: React.RefObject<Target | null>;\n scrollIntoView: (params?: UseScrollIntoViewAnimation) => void;\n cancel: () => void;\n scrolling: boolean;\n}\n\nexport function useScrollIntoView<\n Target extends HTMLElement = any,\n Parent extends HTMLElement | null = null,\n>({\n duration = 1250,\n axis = 'y',\n onScrollFinish,\n onScrollCancel,\n easing = easeInOutQuad,\n offset = 0,\n cancelable = true,\n isList = false,\n}: UseScrollIntoViewOptions = {}): UseScrollIntoViewReturnValue<Target, Parent> {\n const frameID = useRef(0);\n const startTime = useRef(0);\n const shouldStop = useRef(false);\n const [scrolling, setScrolling] = useState(false);\n\n const scrollableRef = useRef<Parent | null>(null);\n const targetRef = useRef<Target | null>(null);\n\n const reducedMotion = useReducedMotion();\n\n const cancel = (): void => {\n if (frameID.current) {\n cancelAnimationFrame(frameID.current);\n frameID.current = 0;\n setScrolling(false);\n }\n };\n\n const scrollIntoView = useCallback(\n ({ alignment = 'start' }: UseScrollIntoViewAnimation = {}) => {\n shouldStop.current = false;\n\n if (frameID.current) {\n cancel();\n }\n\n const start = getScrollStart({ parent: scrollableRef.current, axis }) ?? 0;\n\n const change =\n getRelativePosition({\n parent: scrollableRef.current,\n target: targetRef.current,\n axis,\n alignment,\n offset,\n isList,\n }) - (scrollableRef.current ? 0 : start);\n\n setScrolling(true);\n\n function animateScroll() {\n if (startTime.current === 0) {\n startTime.current = performance.now();\n }\n\n const now = performance.now();\n const elapsed = now - startTime.current;\n\n // Easing timing progress\n const t = reducedMotion || duration === 0 ? 1 : elapsed / duration;\n\n const distance = start + change * easing(t);\n\n setScrollParam({\n parent: scrollableRef.current,\n axis,\n distance,\n });\n\n if (!shouldStop.current && t < 1) {\n frameID.current = requestAnimationFrame(animateScroll);\n } else {\n if (shouldStop.current) {\n typeof onScrollCancel === 'function' && onScrollCancel();\n } else {\n typeof onScrollFinish === 'function' && onScrollFinish();\n }\n startTime.current = 0;\n frameID.current = 0;\n setScrolling(false);\n cancel();\n }\n }\n animateScroll();\n },\n [axis, duration, easing, isList, offset, onScrollFinish, onScrollCancel, reducedMotion]\n );\n\n const handleStop = () => {\n if (cancelable) {\n shouldStop.current = true;\n }\n };\n\n /**\n * Detection of one of these events stops scroll animation\n * wheel - mouse wheel / touch pad\n * touchmove - any touchable device\n */\n\n useWindowEvent('wheel', handleStop, {\n passive: true,\n });\n\n useWindowEvent('touchmove', handleStop, {\n passive: true,\n });\n\n // Cleanup requestAnimationFrame\n useEffect(() => cancel, []);\n\n return {\n scrollableRef,\n targetRef,\n scrollIntoView,\n cancel,\n scrolling,\n };\n}\n\n// ---------------------------------------------------\n// Helpers\n// ---------------------------------------------------\n\nfunction easeInOutQuad(t: number) {\n return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;\n}\n\nfunction getRelativePosition({ axis, target, parent, alignment, offset, isList }: any): number {\n if (!target || (!parent && typeof document === 'undefined')) {\n return 0;\n }\n const isCustomParent = !!parent;\n const parentElement = parent || document.body;\n const parentPosition = parentElement.getBoundingClientRect();\n const targetPosition = target.getBoundingClientRect();\n\n const getDiff = (property: 'top' | 'left'): number =>\n targetPosition[property] - parentPosition[property];\n\n if (axis === 'y') {\n const diff = getDiff('top');\n\n if (diff === 0) {\n return 0;\n }\n\n if (alignment === 'start') {\n const distance = diff - offset;\n const shouldScroll = distance <= targetPosition.height * (isList ? 0 : 1) || !isList;\n\n return shouldScroll ? distance : 0;\n }\n\n const parentHeight = isCustomParent ? parentPosition.height : window.innerHeight;\n\n if (alignment === 'end') {\n const distance = diff + offset - parentHeight + targetPosition.height;\n const shouldScroll = distance >= -targetPosition.height * (isList ? 0 : 1) || !isList;\n\n return shouldScroll ? distance : 0;\n }\n\n if (alignment === 'center') {\n return diff - parentHeight / 2 + targetPosition.height / 2;\n }\n\n return 0;\n }\n\n if (axis === 'x') {\n const diff = getDiff('left');\n\n if (diff === 0) {\n return 0;\n }\n\n if (alignment === 'start') {\n const distance = diff - offset;\n const shouldScroll = distance <= targetPosition.width || !isList;\n\n return shouldScroll ? distance : 0;\n }\n\n const parentWidth = isCustomParent ? parentPosition.width : window.innerWidth;\n\n if (alignment === 'end') {\n const distance = diff + offset - parentWidth + targetPosition.width;\n const shouldScroll = distance >= -targetPosition.width || !isList;\n\n return shouldScroll ? distance : 0;\n }\n\n if (alignment === 'center') {\n return diff - parentWidth / 2 + targetPosition.width / 2;\n }\n\n return 0;\n }\n\n return 0;\n}\n\nfunction getScrollStart({ axis, parent }: any) {\n if (!parent && typeof document === 'undefined') {\n return 0;\n }\n\n const method = axis === 'y' ? 'scrollTop' : 'scrollLeft';\n\n if (parent) {\n return parent[method];\n }\n\n const { body, documentElement } = document;\n\n // While one of it has a value the second is equal 0\n return body[method] + documentElement[method];\n}\n\nfunction setScrollParam({ axis, parent, distance }: any) {\n if (!parent && typeof document === 'undefined') {\n return;\n }\n\n const method = axis === 'y' ? 'scrollTop' : 'scrollLeft';\n\n if (parent) {\n parent[method] = distance;\n } else {\n const { body, documentElement } = document;\n body[method] = distance;\n documentElement[method] = distance;\n }\n}\n\nexport namespace useScrollIntoView {\n export type Options = UseScrollIntoViewOptions;\n export type ReturnValue<\n Target extends HTMLElement,\n Parent extends HTMLElement | null,\n > = UseScrollIntoViewReturnValue<Target, Parent>;\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { randomId } from "../utils/random-id/random-id.mjs";
|
|
3
|
-
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useEffect, useEffectEvent, useRef, useState } from "react";
|
|
4
4
|
//#region packages/@mantine/hooks/src/use-scroll-spy/use-scroll-spy.ts
|
|
5
5
|
function getHeadingsData(headings, getDepth, getValue) {
|
|
6
6
|
const result = [];
|
|
@@ -39,9 +39,9 @@ function useScrollSpy({ selector = "h1, h2, h3, h4, h5, h6", getDepth = getDefau
|
|
|
39
39
|
const [initialized, setInitialized] = useState(false);
|
|
40
40
|
const [data, setData] = useState([]);
|
|
41
41
|
const headingsRef = useRef([]);
|
|
42
|
-
const handleScroll = () => {
|
|
42
|
+
const handleScroll = useEffectEvent(() => {
|
|
43
43
|
setActive(getActiveElement(headingsRef.current.map((d) => d.getNode().getBoundingClientRect()), offset));
|
|
44
|
-
};
|
|
44
|
+
});
|
|
45
45
|
const initialize = () => {
|
|
46
46
|
const headings = getHeadingsData(Array.from(document.querySelectorAll(selector)), getDepth, getValue);
|
|
47
47
|
headingsRef.current = headings;
|
|
@@ -54,7 +54,11 @@ function useScrollSpy({ selector = "h1, h2, h3, h4, h5, h6", getDepth = getDefau
|
|
|
54
54
|
const _scrollHost = scrollHost || window;
|
|
55
55
|
_scrollHost.addEventListener("scroll", handleScroll);
|
|
56
56
|
return () => _scrollHost.removeEventListener("scroll", handleScroll);
|
|
57
|
-
}, [
|
|
57
|
+
}, [
|
|
58
|
+
scrollHost,
|
|
59
|
+
selector,
|
|
60
|
+
offset
|
|
61
|
+
]);
|
|
58
62
|
return {
|
|
59
63
|
reinitialize: initialize,
|
|
60
64
|
active,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-scroll-spy.mjs","names":[],"sources":["../../src/use-scroll-spy/use-scroll-spy.ts"],"sourcesContent":["import { useEffect, useRef, useState } from 'react';\nimport { randomId } from '../utils';\n\nfunction getHeadingsData(\n headings: HTMLElement[],\n getDepth: (element: HTMLElement) => number,\n getValue: (element: HTMLElement) => string\n): UseScrollSpyHeadingData[] {\n const result: UseScrollSpyHeadingData[] = [];\n\n for (let i = 0; i < headings.length; i += 1) {\n const heading = headings[i];\n result.push({\n depth: getDepth(heading),\n value: getValue(heading),\n id: heading.id || randomId(),\n getNode: () => (heading.id ? document.getElementById(heading.id)! : heading),\n });\n }\n\n return result;\n}\n\nfunction getActiveElement(rects: DOMRect[], offset: number = 0) {\n if (rects.length === 0) {\n return -1;\n }\n\n const closest = rects.reduce(\n (acc, item, index) => {\n if (Math.abs(acc.position - offset) < Math.abs(item.y - offset)) {\n return acc;\n }\n\n return {\n index,\n position: item.y,\n };\n },\n { index: 0, position: rects[0].y }\n );\n\n return closest.index;\n}\n\nfunction getDefaultDepth(element: HTMLElement) {\n return Number(element.tagName[1]);\n}\n\nfunction getDefaultValue(element: HTMLElement) {\n return element.textContent || '';\n}\n\nexport interface UseScrollSpyHeadingData {\n /** Heading depth, 1-6 */\n depth: number;\n\n /** Heading text content value */\n value: string;\n\n /** Heading id */\n id: string;\n\n /** Function to get heading node */\n getNode: () => HTMLElement;\n}\n\nexport interface UseScrollSpyOptions {\n /** Selector to get headings, `'h1, h2, h3, h4, h5, h6'` by default */\n selector?: string;\n\n /** A function to retrieve depth of heading, by default depth is calculated based on tag name */\n getDepth?: (element: HTMLElement) => number;\n\n /** A function to retrieve heading value, by default `element.textContent` is used */\n getValue?: (element: HTMLElement) => string;\n\n /** Host element to attach scroll event listener, if not provided, `window` is used */\n scrollHost?: HTMLElement;\n\n /** Offset from the top of the viewport to use when determining the active heading, `0` by default */\n offset?: number;\n}\n\nexport interface UseScrollSpyReturnValue {\n /** Index of the active heading in the `data` array */\n active: number;\n\n /** Headings data. If not initialize, data is represented by an empty array. */\n data: UseScrollSpyHeadingData[];\n\n /** True if headings value have been retrieved from the DOM. */\n initialized: boolean;\n\n /** Function to update headings values after the parent component has mounted. */\n reinitialize: () => void;\n}\n\nexport function useScrollSpy({\n selector = 'h1, h2, h3, h4, h5, h6',\n getDepth = getDefaultDepth,\n getValue = getDefaultValue,\n offset = 0,\n scrollHost,\n}: UseScrollSpyOptions = {}): UseScrollSpyReturnValue {\n const [active, setActive] = useState(-1);\n const [initialized, setInitialized] = useState(false);\n const [data, setData] = useState<UseScrollSpyHeadingData[]>([]);\n const headingsRef = useRef<UseScrollSpyHeadingData[]>([]);\n\n const handleScroll = () => {\n setActive(\n getActiveElement(\n headingsRef.current.map((d) => d.getNode().getBoundingClientRect()),\n offset\n )\n );\n };\n\n const initialize = () => {\n const headings = getHeadingsData(\n Array.from(document.querySelectorAll(selector)),\n getDepth,\n getValue\n );\n headingsRef.current = headings;\n setInitialized(true);\n setData(headings);\n setActive(\n getActiveElement(\n headings.map((d) => d.getNode().getBoundingClientRect()),\n offset\n )\n );\n };\n\n useEffect(() => {\n initialize();\n const _scrollHost = scrollHost || window;\n _scrollHost.addEventListener('scroll', handleScroll);\n return () => _scrollHost.removeEventListener('scroll', handleScroll);\n }, [scrollHost]);\n\n return {\n reinitialize: initialize,\n active,\n initialized,\n data,\n };\n}\n\nexport namespace useScrollSpy {\n export type Options = UseScrollSpyOptions;\n export type ReturnValue = UseScrollSpyReturnValue;\n}\n"],"mappings":";;;;AAGA,SAAS,gBACP,UACA,UACA,UAC2B;CAC3B,MAAM,SAAoC,EAAE;AAE5C,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;EAC3C,MAAM,UAAU,SAAS;AACzB,SAAO,KAAK;GACV,OAAO,SAAS,QAAQ;GACxB,OAAO,SAAS,QAAQ;GACxB,IAAI,QAAQ,MAAM,UAAU;GAC5B,eAAgB,QAAQ,KAAK,SAAS,eAAe,QAAQ,GAAG,GAAI;GACrE,CAAC;;AAGJ,QAAO;;AAGT,SAAS,iBAAiB,OAAkB,SAAiB,GAAG;AAC9D,KAAI,MAAM,WAAW,EACnB,QAAO;AAiBT,QAdgB,MAAM,QACnB,KAAK,MAAM,UAAU;AACpB,MAAI,KAAK,IAAI,IAAI,WAAW,OAAO,GAAG,KAAK,IAAI,KAAK,IAAI,OAAO,CAC7D,QAAO;AAGT,SAAO;GACL;GACA,UAAU,KAAK;GAChB;IAEH;EAAE,OAAO;EAAG,UAAU,MAAM,GAAG;EAAG,CACnC,CAEc;;AAGjB,SAAS,gBAAgB,SAAsB;AAC7C,QAAO,OAAO,QAAQ,QAAQ,GAAG;;AAGnC,SAAS,gBAAgB,SAAsB;AAC7C,QAAO,QAAQ,eAAe;;AAgDhC,SAAgB,aAAa,EAC3B,WAAW,0BACX,WAAW,iBACX,WAAW,iBACX,SAAS,GACT,eACuB,EAAE,EAA2B;CACpD,MAAM,CAAC,QAAQ,aAAa,SAAS,GAAG;CACxC,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM;CACrD,MAAM,CAAC,MAAM,WAAW,SAAoC,EAAE,CAAC;CAC/D,MAAM,cAAc,OAAkC,EAAE,CAAC;CAEzD,MAAM,qBAAqB;
|
|
1
|
+
{"version":3,"file":"use-scroll-spy.mjs","names":[],"sources":["../../src/use-scroll-spy/use-scroll-spy.ts"],"sourcesContent":["import { useEffect, useEffectEvent, useRef, useState } from 'react';\nimport { randomId } from '../utils';\n\nfunction getHeadingsData(\n headings: HTMLElement[],\n getDepth: (element: HTMLElement) => number,\n getValue: (element: HTMLElement) => string\n): UseScrollSpyHeadingData[] {\n const result: UseScrollSpyHeadingData[] = [];\n\n for (let i = 0; i < headings.length; i += 1) {\n const heading = headings[i];\n result.push({\n depth: getDepth(heading),\n value: getValue(heading),\n id: heading.id || randomId(),\n getNode: () => (heading.id ? document.getElementById(heading.id)! : heading),\n });\n }\n\n return result;\n}\n\nfunction getActiveElement(rects: DOMRect[], offset: number = 0) {\n if (rects.length === 0) {\n return -1;\n }\n\n const closest = rects.reduce(\n (acc, item, index) => {\n if (Math.abs(acc.position - offset) < Math.abs(item.y - offset)) {\n return acc;\n }\n\n return {\n index,\n position: item.y,\n };\n },\n { index: 0, position: rects[0].y }\n );\n\n return closest.index;\n}\n\nfunction getDefaultDepth(element: HTMLElement) {\n return Number(element.tagName[1]);\n}\n\nfunction getDefaultValue(element: HTMLElement) {\n return element.textContent || '';\n}\n\nexport interface UseScrollSpyHeadingData {\n /** Heading depth, 1-6 */\n depth: number;\n\n /** Heading text content value */\n value: string;\n\n /** Heading id */\n id: string;\n\n /** Function to get heading node */\n getNode: () => HTMLElement;\n}\n\nexport interface UseScrollSpyOptions {\n /** Selector to get headings, `'h1, h2, h3, h4, h5, h6'` by default */\n selector?: string;\n\n /** A function to retrieve depth of heading, by default depth is calculated based on tag name */\n getDepth?: (element: HTMLElement) => number;\n\n /** A function to retrieve heading value, by default `element.textContent` is used */\n getValue?: (element: HTMLElement) => string;\n\n /** Host element to attach scroll event listener, if not provided, `window` is used */\n scrollHost?: HTMLElement;\n\n /** Offset from the top of the viewport to use when determining the active heading, `0` by default */\n offset?: number;\n}\n\nexport interface UseScrollSpyReturnValue {\n /** Index of the active heading in the `data` array */\n active: number;\n\n /** Headings data. If not initialize, data is represented by an empty array. */\n data: UseScrollSpyHeadingData[];\n\n /** True if headings value have been retrieved from the DOM. */\n initialized: boolean;\n\n /** Function to update headings values after the parent component has mounted. */\n reinitialize: () => void;\n}\n\nexport function useScrollSpy({\n selector = 'h1, h2, h3, h4, h5, h6',\n getDepth = getDefaultDepth,\n getValue = getDefaultValue,\n offset = 0,\n scrollHost,\n}: UseScrollSpyOptions = {}): UseScrollSpyReturnValue {\n const [active, setActive] = useState(-1);\n const [initialized, setInitialized] = useState(false);\n const [data, setData] = useState<UseScrollSpyHeadingData[]>([]);\n const headingsRef = useRef<UseScrollSpyHeadingData[]>([]);\n\n const handleScroll = useEffectEvent(() => {\n setActive(\n getActiveElement(\n headingsRef.current.map((d) => d.getNode().getBoundingClientRect()),\n offset\n )\n );\n });\n\n const initialize = () => {\n const headings = getHeadingsData(\n Array.from(document.querySelectorAll(selector)),\n getDepth,\n getValue\n );\n headingsRef.current = headings;\n setInitialized(true);\n setData(headings);\n setActive(\n getActiveElement(\n headings.map((d) => d.getNode().getBoundingClientRect()),\n offset\n )\n );\n };\n\n useEffect(() => {\n initialize();\n const _scrollHost = scrollHost || window;\n _scrollHost.addEventListener('scroll', handleScroll);\n return () => _scrollHost.removeEventListener('scroll', handleScroll);\n }, [scrollHost, selector, offset]);\n\n return {\n reinitialize: initialize,\n active,\n initialized,\n data,\n };\n}\n\nexport namespace useScrollSpy {\n export type Options = UseScrollSpyOptions;\n export type ReturnValue = UseScrollSpyReturnValue;\n}\n"],"mappings":";;;;AAGA,SAAS,gBACP,UACA,UACA,UAC2B;CAC3B,MAAM,SAAoC,EAAE;AAE5C,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK,GAAG;EAC3C,MAAM,UAAU,SAAS;AACzB,SAAO,KAAK;GACV,OAAO,SAAS,QAAQ;GACxB,OAAO,SAAS,QAAQ;GACxB,IAAI,QAAQ,MAAM,UAAU;GAC5B,eAAgB,QAAQ,KAAK,SAAS,eAAe,QAAQ,GAAG,GAAI;GACrE,CAAC;;AAGJ,QAAO;;AAGT,SAAS,iBAAiB,OAAkB,SAAiB,GAAG;AAC9D,KAAI,MAAM,WAAW,EACnB,QAAO;AAiBT,QAdgB,MAAM,QACnB,KAAK,MAAM,UAAU;AACpB,MAAI,KAAK,IAAI,IAAI,WAAW,OAAO,GAAG,KAAK,IAAI,KAAK,IAAI,OAAO,CAC7D,QAAO;AAGT,SAAO;GACL;GACA,UAAU,KAAK;GAChB;IAEH;EAAE,OAAO;EAAG,UAAU,MAAM,GAAG;EAAG,CACnC,CAEc;;AAGjB,SAAS,gBAAgB,SAAsB;AAC7C,QAAO,OAAO,QAAQ,QAAQ,GAAG;;AAGnC,SAAS,gBAAgB,SAAsB;AAC7C,QAAO,QAAQ,eAAe;;AAgDhC,SAAgB,aAAa,EAC3B,WAAW,0BACX,WAAW,iBACX,WAAW,iBACX,SAAS,GACT,eACuB,EAAE,EAA2B;CACpD,MAAM,CAAC,QAAQ,aAAa,SAAS,GAAG;CACxC,MAAM,CAAC,aAAa,kBAAkB,SAAS,MAAM;CACrD,MAAM,CAAC,MAAM,WAAW,SAAoC,EAAE,CAAC;CAC/D,MAAM,cAAc,OAAkC,EAAE,CAAC;CAEzD,MAAM,eAAe,qBAAqB;AACxC,YACE,iBACE,YAAY,QAAQ,KAAK,MAAM,EAAE,SAAS,CAAC,uBAAuB,CAAC,EACnE,OACD,CACF;GACD;CAEF,MAAM,mBAAmB;EACvB,MAAM,WAAW,gBACf,MAAM,KAAK,SAAS,iBAAiB,SAAS,CAAC,EAC/C,UACA,SACD;AACD,cAAY,UAAU;AACtB,iBAAe,KAAK;AACpB,UAAQ,SAAS;AACjB,YACE,iBACE,SAAS,KAAK,MAAM,EAAE,SAAS,CAAC,uBAAuB,CAAC,EACxD,OACD,CACF;;AAGH,iBAAgB;AACd,cAAY;EACZ,MAAM,cAAc,cAAc;AAClC,cAAY,iBAAiB,UAAU,aAAa;AACpD,eAAa,YAAY,oBAAoB,UAAU,aAAa;IACnE;EAAC;EAAY;EAAU;EAAO,CAAC;AAElC,QAAO;EACL,cAAc;EACd;EACA;EACA;EACD"}
|
|
@@ -21,10 +21,10 @@ function useScroller(options = {}) {
|
|
|
21
21
|
let newCanScrollStart;
|
|
22
22
|
let newCanScrollEnd;
|
|
23
23
|
if (isRtl) {
|
|
24
|
-
newCanScrollStart = scrollLeft <
|
|
25
|
-
newCanScrollEnd = scrollLeft > -(scrollWidth - clientWidth);
|
|
24
|
+
newCanScrollStart = scrollLeft < -1;
|
|
25
|
+
newCanScrollEnd = scrollLeft > -(scrollWidth - clientWidth) + 1;
|
|
26
26
|
} else {
|
|
27
|
-
newCanScrollStart = scrollLeft >
|
|
27
|
+
newCanScrollStart = scrollLeft > 1;
|
|
28
28
|
newCanScrollEnd = scrollLeft < scrollWidth - clientWidth - 1;
|
|
29
29
|
}
|
|
30
30
|
setCanScrollStart(newCanScrollStart);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-scroller.mjs","names":[],"sources":["../../src/use-scroller/use-scroller.ts"],"sourcesContent":["import { RefCallback, useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface UseScrollerOptions {\n /** Amount of pixels to scroll when calling scroll functions, `200` by default */\n scrollAmount?: number;\n\n /** Determines whether content can be scrolled by dragging with mouse, `true` by default */\n draggable?: boolean;\n\n /** Called when scroll state changes (canScrollStart or canScrollEnd) */\n onScrollStateChange?: (state: UseScrollerScrollState) => void;\n}\n\nexport interface UseScrollerScrollState {\n /** Whether content can be scrolled towards the start (left in LTR, right in RTL) */\n canScrollStart: boolean;\n\n /** Whether content can be scrolled towards the end (right in LTR, left in RTL) */\n canScrollEnd: boolean;\n}\n\nexport interface UseScrollerReturnValue<T extends HTMLElement = HTMLDivElement> {\n /** Ref callback to attach to the scrollable container element */\n ref: RefCallback<T | null>;\n\n /** Whether content can be scrolled towards the start */\n canScrollStart: boolean;\n\n /** Whether content can be scrolled towards the end */\n canScrollEnd: boolean;\n\n /** Scrolls towards the start direction */\n scrollStart: () => void;\n\n /** Scrolls towards the end direction */\n scrollEnd: () => void;\n\n /** `true` if the user is currently dragging the content */\n isDragging: boolean;\n\n /** Props to spread on the scrollable container for drag functionality */\n dragHandlers: {\n onMouseDown: (e: React.MouseEvent) => void;\n onMouseMove: (e: React.MouseEvent) => void;\n onMouseUp: () => void;\n onMouseLeave: () => void;\n };\n}\n\nexport function useScroller<T extends HTMLElement = HTMLDivElement>(\n options: UseScrollerOptions = {}\n): UseScrollerReturnValue<T> {\n const { scrollAmount = 200, draggable = true, onScrollStateChange } = options;\n\n const containerRef = useRef<T | null>(null);\n\n const [canScrollStart, setCanScrollStart] = useState(false);\n const [canScrollEnd, setCanScrollEnd] = useState(false);\n const [isDragging, setIsDragging] = useState(false);\n\n const isDraggingRef = useRef(false);\n const hasDraggedRef = useRef(false);\n const startX = useRef(0);\n const scrollLeftStart = useRef(0);\n\n const onScrollStateChangeRef = useRef(onScrollStateChange);\n onScrollStateChangeRef.current = onScrollStateChange;\n\n const updateScrollState = useCallback(() => {\n const container = containerRef.current;\n if (container) {\n const { scrollLeft, scrollWidth, clientWidth } = container;\n const isRtl = getComputedStyle(container).direction === 'rtl';\n\n let newCanScrollStart: boolean;\n let newCanScrollEnd: boolean;\n\n if (isRtl) {\n newCanScrollStart = scrollLeft <
|
|
1
|
+
{"version":3,"file":"use-scroller.mjs","names":[],"sources":["../../src/use-scroller/use-scroller.ts"],"sourcesContent":["import { RefCallback, useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface UseScrollerOptions {\n /** Amount of pixels to scroll when calling scroll functions, `200` by default */\n scrollAmount?: number;\n\n /** Determines whether content can be scrolled by dragging with mouse, `true` by default */\n draggable?: boolean;\n\n /** Called when scroll state changes (canScrollStart or canScrollEnd) */\n onScrollStateChange?: (state: UseScrollerScrollState) => void;\n}\n\nexport interface UseScrollerScrollState {\n /** Whether content can be scrolled towards the start (left in LTR, right in RTL) */\n canScrollStart: boolean;\n\n /** Whether content can be scrolled towards the end (right in LTR, left in RTL) */\n canScrollEnd: boolean;\n}\n\nexport interface UseScrollerReturnValue<T extends HTMLElement = HTMLDivElement> {\n /** Ref callback to attach to the scrollable container element */\n ref: RefCallback<T | null>;\n\n /** Whether content can be scrolled towards the start */\n canScrollStart: boolean;\n\n /** Whether content can be scrolled towards the end */\n canScrollEnd: boolean;\n\n /** Scrolls towards the start direction */\n scrollStart: () => void;\n\n /** Scrolls towards the end direction */\n scrollEnd: () => void;\n\n /** `true` if the user is currently dragging the content */\n isDragging: boolean;\n\n /** Props to spread on the scrollable container for drag functionality */\n dragHandlers: {\n onMouseDown: (e: React.MouseEvent) => void;\n onMouseMove: (e: React.MouseEvent) => void;\n onMouseUp: () => void;\n onMouseLeave: () => void;\n };\n}\n\nexport function useScroller<T extends HTMLElement = HTMLDivElement>(\n options: UseScrollerOptions = {}\n): UseScrollerReturnValue<T> {\n const { scrollAmount = 200, draggable = true, onScrollStateChange } = options;\n\n const containerRef = useRef<T | null>(null);\n\n const [canScrollStart, setCanScrollStart] = useState(false);\n const [canScrollEnd, setCanScrollEnd] = useState(false);\n const [isDragging, setIsDragging] = useState(false);\n\n const isDraggingRef = useRef(false);\n const hasDraggedRef = useRef(false);\n const startX = useRef(0);\n const scrollLeftStart = useRef(0);\n\n const onScrollStateChangeRef = useRef(onScrollStateChange);\n onScrollStateChangeRef.current = onScrollStateChange;\n\n const updateScrollState = useCallback(() => {\n const container = containerRef.current;\n if (container) {\n const { scrollLeft, scrollWidth, clientWidth } = container;\n const isRtl = getComputedStyle(container).direction === 'rtl';\n\n let newCanScrollStart: boolean;\n let newCanScrollEnd: boolean;\n\n if (isRtl) {\n newCanScrollStart = scrollLeft < -1;\n newCanScrollEnd = scrollLeft > -(scrollWidth - clientWidth) + 1;\n } else {\n newCanScrollStart = scrollLeft > 1;\n newCanScrollEnd = scrollLeft < scrollWidth - clientWidth - 1;\n }\n\n setCanScrollStart(newCanScrollStart);\n setCanScrollEnd(newCanScrollEnd);\n\n onScrollStateChangeRef.current?.({\n canScrollStart: newCanScrollStart,\n canScrollEnd: newCanScrollEnd,\n });\n }\n }, []);\n\n useEffect(() => {\n updateScrollState();\n const container = containerRef.current;\n if (container) {\n container.addEventListener('scroll', updateScrollState);\n const resizeObserver = new ResizeObserver(updateScrollState);\n resizeObserver.observe(container);\n return () => {\n container.removeEventListener('scroll', updateScrollState);\n resizeObserver.disconnect();\n };\n }\n return undefined;\n }, [updateScrollState]);\n\n const scroll = useCallback(\n (direction: 'start' | 'end') => {\n const container = containerRef.current;\n if (container) {\n const isRtl = getComputedStyle(container).direction === 'rtl';\n const amount = scrollAmount;\n const scrollBy = direction === 'end' ? amount : -amount;\n const adjustedScrollBy = isRtl ? -scrollBy : scrollBy;\n\n container.scrollBy({\n left: adjustedScrollBy,\n behavior: 'smooth',\n });\n }\n },\n [scrollAmount]\n );\n\n const scrollStart = useCallback(() => scroll('start'), [scroll]);\n const scrollEnd = useCallback(() => scroll('end'), [scroll]);\n\n const handleMouseDown = useCallback(\n (event: React.MouseEvent) => {\n if (!draggable) {\n return;\n }\n const container = containerRef.current;\n if (container) {\n isDraggingRef.current = true;\n hasDraggedRef.current = false;\n setIsDragging(true);\n startX.current = event.pageX - container.offsetLeft;\n scrollLeftStart.current = container.scrollLeft;\n container.style.cursor = 'grabbing';\n container.style.userSelect = 'none';\n }\n },\n [draggable]\n );\n\n const handleMouseMove = useCallback((event: React.MouseEvent) => {\n if (!isDraggingRef.current) {\n return;\n }\n event.preventDefault();\n const container = containerRef.current;\n if (container) {\n const x = event.pageX - container.offsetLeft;\n const walk = x - startX.current;\n if (Math.abs(walk) > 5) {\n hasDraggedRef.current = true;\n }\n container.scrollLeft = scrollLeftStart.current - walk;\n }\n }, []);\n\n const handleMouseUp = useCallback(() => {\n const wasDragged = hasDraggedRef.current;\n isDraggingRef.current = false;\n hasDraggedRef.current = false;\n setIsDragging(false);\n const container = containerRef.current;\n if (container) {\n container.style.cursor = '';\n container.style.userSelect = '';\n\n if (wasDragged) {\n const suppressClick = (event: MouseEvent) => {\n event.stopPropagation();\n event.preventDefault();\n container.removeEventListener('click', suppressClick, true);\n };\n container.addEventListener('click', suppressClick, true);\n }\n }\n }, []);\n\n const handleMouseLeave = useCallback(() => {\n if (isDraggingRef.current) {\n handleMouseUp();\n }\n }, [handleMouseUp]);\n\n const assignRef: RefCallback<T | null> = useCallback(\n (node) => {\n containerRef.current = node;\n if (node) {\n updateScrollState();\n }\n },\n [updateScrollState]\n );\n\n return {\n ref: assignRef,\n canScrollStart,\n canScrollEnd,\n scrollStart,\n scrollEnd,\n isDragging,\n dragHandlers: {\n onMouseDown: handleMouseDown,\n onMouseMove: handleMouseMove,\n onMouseUp: handleMouseUp,\n onMouseLeave: handleMouseLeave,\n },\n };\n}\n\nexport namespace useScroller {\n export type Options = UseScrollerOptions;\n export type ReturnValue<T extends HTMLElement = HTMLDivElement> = UseScrollerReturnValue<T>;\n export type ScrollState = UseScrollerScrollState;\n}\n"],"mappings":"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"}
|
package/esm/use-set/use-set.mjs
CHANGED
|
@@ -5,7 +5,12 @@ import { useRef } from "react";
|
|
|
5
5
|
function readonlySetLikeToSet(input) {
|
|
6
6
|
if (input instanceof Set) return input;
|
|
7
7
|
const result = /* @__PURE__ */ new Set();
|
|
8
|
-
|
|
8
|
+
const iterator = input.keys();
|
|
9
|
+
let next = iterator.next();
|
|
10
|
+
while (!next.done) {
|
|
11
|
+
result.add(next.value);
|
|
12
|
+
next = iterator.next();
|
|
13
|
+
}
|
|
9
14
|
return result;
|
|
10
15
|
}
|
|
11
16
|
function useSet(values) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-set.mjs","names":[],"sources":["../../src/use-set/use-set.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { useForceUpdate } from '../use-force-update/use-force-update';\n\nexport function readonlySetLikeToSet<T>(input: ReadonlySetLike<T>): Set<T> {\n if (input instanceof Set) {\n return input;\n }\n const result = new Set<T>();\n
|
|
1
|
+
{"version":3,"file":"use-set.mjs","names":[],"sources":["../../src/use-set/use-set.ts"],"sourcesContent":["import { useRef } from 'react';\nimport { useForceUpdate } from '../use-force-update/use-force-update';\n\nexport function readonlySetLikeToSet<T>(input: ReadonlySetLike<T>): Set<T> {\n if (input instanceof Set) {\n return input;\n }\n const result = new Set<T>();\n const iterator = input.keys();\n let next = iterator.next();\n while (!next.done) {\n result.add(next.value);\n next = iterator.next();\n }\n return result;\n}\n\nexport function useSet<T>(values?: T[]): Set<T> {\n const setRef = useRef(new Set(values));\n const forceUpdate = useForceUpdate();\n\n setRef.current.add = (...args) => {\n const res = Set.prototype.add.apply(setRef.current, args);\n forceUpdate();\n return res;\n };\n\n setRef.current.clear = (...args) => {\n Set.prototype.clear.apply(setRef.current, args);\n forceUpdate();\n };\n\n setRef.current.delete = (...args) => {\n const res = Set.prototype.delete.apply(setRef.current, args);\n forceUpdate();\n return res;\n };\n\n setRef.current.union = <U>(other: ReadonlySetLike<U>): Set<T | U> => {\n const result = new Set<T | U>(setRef.current as Set<T>);\n readonlySetLikeToSet(other).forEach((item) => result.add(item));\n return result;\n };\n\n setRef.current.intersection = <U>(other: ReadonlySetLike<U>): Set<T & U> => {\n const result = new Set<T & U>();\n const otherSet = readonlySetLikeToSet(other);\n setRef.current.forEach((item) => {\n if (otherSet.has(item as any)) {\n result.add(item as T & U);\n }\n });\n return result;\n };\n\n setRef.current.difference = <U>(other: ReadonlySetLike<U>): Set<T> => {\n const result = new Set<T>();\n const otherSet = readonlySetLikeToSet(other);\n setRef.current.forEach((item) => {\n if (!otherSet.has(item as any)) {\n result.add(item);\n }\n });\n return result;\n };\n\n setRef.current.symmetricDifference = <U>(other: ReadonlySetLike<U>): Set<T | U> => {\n const result = new Set<T | U>();\n const otherSet = readonlySetLikeToSet(other);\n\n setRef.current.forEach((item) => {\n if (!otherSet.has(item as any)) {\n result.add(item);\n }\n });\n\n otherSet.forEach((item) => {\n if (!setRef.current.has(item as any)) {\n result.add(item);\n }\n });\n\n return result;\n };\n\n return setRef.current;\n}\n"],"mappings":";;;;AAGA,SAAgB,qBAAwB,OAAmC;AACzE,KAAI,iBAAiB,IACnB,QAAO;CAET,MAAM,yBAAS,IAAI,KAAQ;CAC3B,MAAM,WAAW,MAAM,MAAM;CAC7B,IAAI,OAAO,SAAS,MAAM;AAC1B,QAAO,CAAC,KAAK,MAAM;AACjB,SAAO,IAAI,KAAK,MAAM;AACtB,SAAO,SAAS,MAAM;;AAExB,QAAO;;AAGT,SAAgB,OAAU,QAAsB;CAC9C,MAAM,SAAS,OAAO,IAAI,IAAI,OAAO,CAAC;CACtC,MAAM,cAAc,gBAAgB;AAEpC,QAAO,QAAQ,OAAO,GAAG,SAAS;EAChC,MAAM,MAAM,IAAI,UAAU,IAAI,MAAM,OAAO,SAAS,KAAK;AACzD,eAAa;AACb,SAAO;;AAGT,QAAO,QAAQ,SAAS,GAAG,SAAS;AAClC,MAAI,UAAU,MAAM,MAAM,OAAO,SAAS,KAAK;AAC/C,eAAa;;AAGf,QAAO,QAAQ,UAAU,GAAG,SAAS;EACnC,MAAM,MAAM,IAAI,UAAU,OAAO,MAAM,OAAO,SAAS,KAAK;AAC5D,eAAa;AACb,SAAO;;AAGT,QAAO,QAAQ,SAAY,UAA0C;EACnE,MAAM,SAAS,IAAI,IAAW,OAAO,QAAkB;AACvD,uBAAqB,MAAM,CAAC,SAAS,SAAS,OAAO,IAAI,KAAK,CAAC;AAC/D,SAAO;;AAGT,QAAO,QAAQ,gBAAmB,UAA0C;EAC1E,MAAM,yBAAS,IAAI,KAAY;EAC/B,MAAM,WAAW,qBAAqB,MAAM;AAC5C,SAAO,QAAQ,SAAS,SAAS;AAC/B,OAAI,SAAS,IAAI,KAAY,CAC3B,QAAO,IAAI,KAAc;IAE3B;AACF,SAAO;;AAGT,QAAO,QAAQ,cAAiB,UAAsC;EACpE,MAAM,yBAAS,IAAI,KAAQ;EAC3B,MAAM,WAAW,qBAAqB,MAAM;AAC5C,SAAO,QAAQ,SAAS,SAAS;AAC/B,OAAI,CAAC,SAAS,IAAI,KAAY,CAC5B,QAAO,IAAI,KAAK;IAElB;AACF,SAAO;;AAGT,QAAO,QAAQ,uBAA0B,UAA0C;EACjF,MAAM,yBAAS,IAAI,KAAY;EAC/B,MAAM,WAAW,qBAAqB,MAAM;AAE5C,SAAO,QAAQ,SAAS,SAAS;AAC/B,OAAI,CAAC,SAAS,IAAI,KAAY,CAC5B,QAAO,IAAI,KAAK;IAElB;AAEF,WAAS,SAAS,SAAS;AACzB,OAAI,CAAC,OAAO,QAAQ,IAAI,KAAY,CAClC,QAAO,IAAI,KAAK;IAElB;AAEF,SAAO;;AAGT,QAAO,OAAO"}
|
|
@@ -34,7 +34,9 @@ function useThrottledCallbackWithClearTimeout(callback, wait) {
|
|
|
34
34
|
return [throttled, clearTimeout];
|
|
35
35
|
}
|
|
36
36
|
function useThrottledCallback(callback, wait) {
|
|
37
|
-
|
|
37
|
+
const [throttled, clearTimeout] = useThrottledCallbackWithClearTimeout(callback, wait);
|
|
38
|
+
useEffect(() => clearTimeout, []);
|
|
39
|
+
return throttled;
|
|
38
40
|
}
|
|
39
41
|
//#endregion
|
|
40
42
|
export { useThrottledCallback, useThrottledCallbackWithClearTimeout };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-throttled-callback.mjs","names":[],"sources":["../../src/use-throttled-callback/use-throttled-callback.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { useCallbackRef } from '../utils';\n\nexport function useThrottledCallbackWithClearTimeout<T extends (...args: any[]) => any>(\n callback: T,\n wait: number\n) {\n const handleCallback = useCallbackRef(callback);\n const latestInArgsRef = useRef<Parameters<T>>(null);\n const latestOutArgsRef = useRef<Parameters<T>>(null);\n const active = useRef(true);\n const waitRef = useRef(wait);\n const timeoutRef = useRef<number>(-1);\n\n const clearTimeout = () => window.clearTimeout(timeoutRef.current);\n\n const callThrottledCallback = useCallback(\n (...args: Parameters<T>) => {\n handleCallback(...args);\n latestInArgsRef.current = args;\n latestOutArgsRef.current = args;\n active.current = false;\n },\n [handleCallback]\n );\n\n const timerCallback = useCallback(() => {\n if (latestInArgsRef.current && latestInArgsRef.current !== latestOutArgsRef.current) {\n callThrottledCallback(...latestInArgsRef.current);\n\n timeoutRef.current = window.setTimeout(timerCallback, waitRef.current);\n } else {\n active.current = true;\n }\n }, [callThrottledCallback]);\n\n const throttled = useCallback(\n (...args: Parameters<T>) => {\n if (active.current) {\n callThrottledCallback(...args);\n timeoutRef.current = window.setTimeout(timerCallback, waitRef.current);\n } else {\n latestInArgsRef.current = args;\n }\n },\n [callThrottledCallback, timerCallback]\n );\n\n useEffect(() => {\n waitRef.current = wait;\n }, [wait]);\n\n return [throttled, clearTimeout] as const;\n}\n\nexport function useThrottledCallback<T extends (...args: any[]) => any>(callback: T, wait: number) {\n
|
|
1
|
+
{"version":3,"file":"use-throttled-callback.mjs","names":[],"sources":["../../src/use-throttled-callback/use-throttled-callback.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { useCallbackRef } from '../utils';\n\nexport function useThrottledCallbackWithClearTimeout<T extends (...args: any[]) => any>(\n callback: T,\n wait: number\n) {\n const handleCallback = useCallbackRef(callback);\n const latestInArgsRef = useRef<Parameters<T>>(null);\n const latestOutArgsRef = useRef<Parameters<T>>(null);\n const active = useRef(true);\n const waitRef = useRef(wait);\n const timeoutRef = useRef<number>(-1);\n\n const clearTimeout = () => window.clearTimeout(timeoutRef.current);\n\n const callThrottledCallback = useCallback(\n (...args: Parameters<T>) => {\n handleCallback(...args);\n latestInArgsRef.current = args;\n latestOutArgsRef.current = args;\n active.current = false;\n },\n [handleCallback]\n );\n\n const timerCallback = useCallback(() => {\n if (latestInArgsRef.current && latestInArgsRef.current !== latestOutArgsRef.current) {\n callThrottledCallback(...latestInArgsRef.current);\n\n timeoutRef.current = window.setTimeout(timerCallback, waitRef.current);\n } else {\n active.current = true;\n }\n }, [callThrottledCallback]);\n\n const throttled = useCallback(\n (...args: Parameters<T>) => {\n if (active.current) {\n callThrottledCallback(...args);\n timeoutRef.current = window.setTimeout(timerCallback, waitRef.current);\n } else {\n latestInArgsRef.current = args;\n }\n },\n [callThrottledCallback, timerCallback]\n );\n\n useEffect(() => {\n waitRef.current = wait;\n }, [wait]);\n\n return [throttled, clearTimeout] as const;\n}\n\nexport function useThrottledCallback<T extends (...args: any[]) => any>(callback: T, wait: number) {\n const [throttled, clearTimeout] = useThrottledCallbackWithClearTimeout(callback, wait);\n useEffect(() => clearTimeout, []);\n return throttled;\n}\n"],"mappings":";;;;AAGA,SAAgB,qCACd,UACA,MACA;CACA,MAAM,iBAAiB,eAAe,SAAS;CAC/C,MAAM,kBAAkB,OAAsB,KAAK;CACnD,MAAM,mBAAmB,OAAsB,KAAK;CACpD,MAAM,SAAS,OAAO,KAAK;CAC3B,MAAM,UAAU,OAAO,KAAK;CAC5B,MAAM,aAAa,OAAe,GAAG;CAErC,MAAM,qBAAqB,OAAO,aAAa,WAAW,QAAQ;CAElE,MAAM,wBAAwB,aAC3B,GAAG,SAAwB;AAC1B,iBAAe,GAAG,KAAK;AACvB,kBAAgB,UAAU;AAC1B,mBAAiB,UAAU;AAC3B,SAAO,UAAU;IAEnB,CAAC,eAAe,CACjB;CAED,MAAM,gBAAgB,kBAAkB;AACtC,MAAI,gBAAgB,WAAW,gBAAgB,YAAY,iBAAiB,SAAS;AACnF,yBAAsB,GAAG,gBAAgB,QAAQ;AAEjD,cAAW,UAAU,OAAO,WAAW,eAAe,QAAQ,QAAQ;QAEtE,QAAO,UAAU;IAElB,CAAC,sBAAsB,CAAC;CAE3B,MAAM,YAAY,aACf,GAAG,SAAwB;AAC1B,MAAI,OAAO,SAAS;AAClB,yBAAsB,GAAG,KAAK;AAC9B,cAAW,UAAU,OAAO,WAAW,eAAe,QAAQ,QAAQ;QAEtE,iBAAgB,UAAU;IAG9B,CAAC,uBAAuB,cAAc,CACvC;AAED,iBAAgB;AACd,UAAQ,UAAU;IACjB,CAAC,KAAK,CAAC;AAEV,QAAO,CAAC,WAAW,aAAa;;AAGlC,SAAgB,qBAAwD,UAAa,MAAc;CACjG,MAAM,CAAC,WAAW,gBAAgB,qCAAqC,UAAU,KAAK;AACtF,iBAAgB,cAAc,EAAE,CAAC;AACjC,QAAO"}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { useCallbackRef } from "../utils/use-callback-ref/use-callback-ref.mjs";
|
|
2
3
|
import { useCallback, useEffect, useRef } from "react";
|
|
3
4
|
//#region packages/@mantine/hooks/src/use-timeout/use-timeout.ts
|
|
4
5
|
function useTimeout(callback, delay, options = { autoInvoke: false }) {
|
|
5
6
|
const timeoutRef = useRef(null);
|
|
7
|
+
const handleCallback = useCallbackRef(callback);
|
|
6
8
|
const start = useCallback((...args) => {
|
|
7
9
|
if (!timeoutRef.current) timeoutRef.current = window.setTimeout(() => {
|
|
8
|
-
|
|
10
|
+
handleCallback(...args);
|
|
9
11
|
timeoutRef.current = null;
|
|
10
12
|
}, delay);
|
|
11
13
|
}, [delay]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-timeout.mjs","names":[],"sources":["../../src/use-timeout/use-timeout.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\n\nexport interface UseTimeoutOptions {\n autoInvoke: boolean;\n}\n\nexport interface UseTimeoutReturnValue {\n start: (...args: any[]) => void;\n clear: () => void;\n}\n\nexport function useTimeout(\n callback: (...args: any[]) => void,\n delay: number,\n options: UseTimeoutOptions = { autoInvoke: false }\n): UseTimeoutReturnValue {\n const timeoutRef = useRef<number | null>(null);\n\n const start = useCallback(\n (...args: any[]) => {\n if (!timeoutRef.current) {\n timeoutRef.current = window.setTimeout(() => {\n
|
|
1
|
+
{"version":3,"file":"use-timeout.mjs","names":[],"sources":["../../src/use-timeout/use-timeout.ts"],"sourcesContent":["import { useCallback, useEffect, useRef } from 'react';\nimport { useCallbackRef } from '../utils';\n\nexport interface UseTimeoutOptions {\n autoInvoke: boolean;\n}\n\nexport interface UseTimeoutReturnValue {\n start: (...args: any[]) => void;\n clear: () => void;\n}\n\nexport function useTimeout(\n callback: (...args: any[]) => void,\n delay: number,\n options: UseTimeoutOptions = { autoInvoke: false }\n): UseTimeoutReturnValue {\n const timeoutRef = useRef<number | null>(null);\n const handleCallback = useCallbackRef(callback);\n\n const start = useCallback(\n (...args: any[]) => {\n if (!timeoutRef.current) {\n timeoutRef.current = window.setTimeout(() => {\n handleCallback(...args);\n timeoutRef.current = null;\n }, delay);\n }\n },\n [delay]\n );\n\n const clear = useCallback(() => {\n if (timeoutRef.current) {\n window.clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n }, []);\n\n useEffect(() => {\n if (options.autoInvoke) {\n start();\n }\n\n return clear;\n }, [clear, start]);\n\n return { start, clear };\n}\n\nexport namespace useTimeout {\n export type Options = UseTimeoutOptions;\n export type ReturnValue = UseTimeoutReturnValue;\n}\n"],"mappings":";;;;AAYA,SAAgB,WACd,UACA,OACA,UAA6B,EAAE,YAAY,OAAO,EAC3B;CACvB,MAAM,aAAa,OAAsB,KAAK;CAC9C,MAAM,iBAAiB,eAAe,SAAS;CAE/C,MAAM,QAAQ,aACX,GAAG,SAAgB;AAClB,MAAI,CAAC,WAAW,QACd,YAAW,UAAU,OAAO,iBAAiB;AAC3C,kBAAe,GAAG,KAAK;AACvB,cAAW,UAAU;KACpB,MAAM;IAGb,CAAC,MAAM,CACR;CAED,MAAM,QAAQ,kBAAkB;AAC9B,MAAI,WAAW,SAAS;AACtB,UAAO,aAAa,WAAW,QAAQ;AACvC,cAAW,UAAU;;IAEtB,EAAE,CAAC;AAEN,iBAAgB;AACd,MAAI,QAAQ,WACV,QAAO;AAGT,SAAO;IACN,CAAC,OAAO,MAAM,CAAC;AAElB,QAAO;EAAE;EAAO;EAAO"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useWindowEvent } from "../use-window-event/use-window-event.mjs";
|
|
3
3
|
import { useCallback, useEffect, useState } from "react";
|
|
4
4
|
//#region packages/@mantine/hooks/src/use-viewport-size/use-viewport-size.ts
|
|
5
|
-
const
|
|
5
|
+
const eventListenerOptions = { passive: true };
|
|
6
6
|
function useViewportSize() {
|
|
7
7
|
const [windowSize, setWindowSize] = useState({
|
|
8
8
|
width: 0,
|
|
@@ -14,8 +14,8 @@ function useViewportSize() {
|
|
|
14
14
|
height: window.innerHeight || 0
|
|
15
15
|
});
|
|
16
16
|
}, []);
|
|
17
|
-
useWindowEvent("resize", setSize,
|
|
18
|
-
useWindowEvent("orientationchange", setSize,
|
|
17
|
+
useWindowEvent("resize", setSize, eventListenerOptions);
|
|
18
|
+
useWindowEvent("orientationchange", setSize, eventListenerOptions);
|
|
19
19
|
useEffect(setSize, []);
|
|
20
20
|
return windowSize;
|
|
21
21
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-viewport-size.mjs","names":[],"sources":["../../src/use-viewport-size/use-viewport-size.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nconst
|
|
1
|
+
{"version":3,"file":"use-viewport-size.mjs","names":[],"sources":["../../src/use-viewport-size/use-viewport-size.ts"],"sourcesContent":["import { useCallback, useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nconst eventListenerOptions = {\n passive: true,\n};\n\nexport function useViewportSize() {\n const [windowSize, setWindowSize] = useState({\n width: 0,\n height: 0,\n });\n\n const setSize = useCallback(() => {\n setWindowSize({ width: window.innerWidth || 0, height: window.innerHeight || 0 });\n }, []);\n\n useWindowEvent('resize', setSize, eventListenerOptions);\n useWindowEvent('orientationchange', setSize, eventListenerOptions);\n useEffect(setSize, []);\n\n return windowSize;\n}\n"],"mappings":";;;;AAGA,MAAM,uBAAuB,EAC3B,SAAS,MACV;AAED,SAAgB,kBAAkB;CAChC,MAAM,CAAC,YAAY,iBAAiB,SAAS;EAC3C,OAAO;EACP,QAAQ;EACT,CAAC;CAEF,MAAM,UAAU,kBAAkB;AAChC,gBAAc;GAAE,OAAO,OAAO,cAAc;GAAG,QAAQ,OAAO,eAAe;GAAG,CAAC;IAChF,EAAE,CAAC;AAEN,gBAAe,UAAU,SAAS,qBAAqB;AACvD,gBAAe,qBAAqB,SAAS,qBAAqB;AAClE,WAAU,SAAS,EAAE,CAAC;AAEtB,QAAO"}
|
|
@@ -24,8 +24,8 @@ function useWindowScroll() {
|
|
|
24
24
|
x: 0,
|
|
25
25
|
y: 0
|
|
26
26
|
});
|
|
27
|
-
useWindowEvent("scroll", () => setPosition(getScrollPosition()));
|
|
28
|
-
useWindowEvent("resize", () => setPosition(getScrollPosition()));
|
|
27
|
+
useWindowEvent("scroll", () => setPosition(getScrollPosition()), { passive: true });
|
|
28
|
+
useWindowEvent("resize", () => setPosition(getScrollPosition()), { passive: true });
|
|
29
29
|
useEffect(() => {
|
|
30
30
|
setPosition(getScrollPosition());
|
|
31
31
|
}, []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-window-scroll.mjs","names":[],"sources":["../../src/use-window-scroll/use-window-scroll.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nexport interface UseWindowScrollPosition {\n x: number;\n y: number;\n}\n\nexport type UseWindowScrollTo = (position: Partial<UseWindowScrollPosition>) => void;\nexport type UseWindowScrollReturnValue = [UseWindowScrollPosition, UseWindowScrollTo];\n\nfunction getScrollPosition(): UseWindowScrollPosition {\n return typeof window !== 'undefined' ? { x: window.scrollX, y: window.scrollY } : { x: 0, y: 0 };\n}\n\nfunction scrollTo({ x, y }: Partial<UseWindowScrollPosition>) {\n if (typeof window !== 'undefined') {\n const scrollOptions: ScrollToOptions = { behavior: 'smooth' };\n\n if (typeof x === 'number') {\n scrollOptions.left = x;\n }\n\n if (typeof y === 'number') {\n scrollOptions.top = y;\n }\n\n window.scrollTo(scrollOptions);\n }\n}\n\nexport function useWindowScroll(): UseWindowScrollReturnValue {\n const [position, setPosition] = useState<UseWindowScrollPosition>({ x: 0, y: 0 });\n\n useWindowEvent('scroll', () => setPosition(getScrollPosition()));\n useWindowEvent('resize', () => setPosition(getScrollPosition()));\n\n useEffect(() => {\n setPosition(getScrollPosition());\n }, []);\n\n return [position, scrollTo] as const;\n}\n\nexport namespace useWindowScroll {\n export type Position = UseWindowScrollPosition;\n export type ScrollTo = UseWindowScrollTo;\n export type ReturnValue = UseWindowScrollReturnValue;\n}\n"],"mappings":";;;;AAWA,SAAS,oBAA6C;AACpD,QAAO,OAAO,WAAW,cAAc;EAAE,GAAG,OAAO;EAAS,GAAG,OAAO;EAAS,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG;;AAGlG,SAAS,SAAS,EAAE,GAAG,KAAuC;AAC5D,KAAI,OAAO,WAAW,aAAa;EACjC,MAAM,gBAAiC,EAAE,UAAU,UAAU;AAE7D,MAAI,OAAO,MAAM,SACf,eAAc,OAAO;AAGvB,MAAI,OAAO,MAAM,SACf,eAAc,MAAM;AAGtB,SAAO,SAAS,cAAc;;;AAIlC,SAAgB,kBAA8C;CAC5D,MAAM,CAAC,UAAU,eAAe,SAAkC;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC;AAEjF,gBAAe,gBAAgB,YAAY,mBAAmB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"use-window-scroll.mjs","names":[],"sources":["../../src/use-window-scroll/use-window-scroll.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useWindowEvent } from '../use-window-event/use-window-event';\n\nexport interface UseWindowScrollPosition {\n x: number;\n y: number;\n}\n\nexport type UseWindowScrollTo = (position: Partial<UseWindowScrollPosition>) => void;\nexport type UseWindowScrollReturnValue = [UseWindowScrollPosition, UseWindowScrollTo];\n\nfunction getScrollPosition(): UseWindowScrollPosition {\n return typeof window !== 'undefined' ? { x: window.scrollX, y: window.scrollY } : { x: 0, y: 0 };\n}\n\nfunction scrollTo({ x, y }: Partial<UseWindowScrollPosition>) {\n if (typeof window !== 'undefined') {\n const scrollOptions: ScrollToOptions = { behavior: 'smooth' };\n\n if (typeof x === 'number') {\n scrollOptions.left = x;\n }\n\n if (typeof y === 'number') {\n scrollOptions.top = y;\n }\n\n window.scrollTo(scrollOptions);\n }\n}\n\nexport function useWindowScroll(): UseWindowScrollReturnValue {\n const [position, setPosition] = useState<UseWindowScrollPosition>({ x: 0, y: 0 });\n\n useWindowEvent('scroll', () => setPosition(getScrollPosition()), { passive: true });\n useWindowEvent('resize', () => setPosition(getScrollPosition()), { passive: true });\n\n useEffect(() => {\n setPosition(getScrollPosition());\n }, []);\n\n return [position, scrollTo] as const;\n}\n\nexport namespace useWindowScroll {\n export type Position = UseWindowScrollPosition;\n export type ScrollTo = UseWindowScrollTo;\n export type ReturnValue = UseWindowScrollReturnValue;\n}\n"],"mappings":";;;;AAWA,SAAS,oBAA6C;AACpD,QAAO,OAAO,WAAW,cAAc;EAAE,GAAG,OAAO;EAAS,GAAG,OAAO;EAAS,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG;;AAGlG,SAAS,SAAS,EAAE,GAAG,KAAuC;AAC5D,KAAI,OAAO,WAAW,aAAa;EACjC,MAAM,gBAAiC,EAAE,UAAU,UAAU;AAE7D,MAAI,OAAO,MAAM,SACf,eAAc,OAAO;AAGvB,MAAI,OAAO,MAAM,SACf,eAAc,MAAM;AAGtB,SAAO,SAAS,cAAc;;;AAIlC,SAAgB,kBAA8C;CAC5D,MAAM,CAAC,UAAU,eAAe,SAAkC;EAAE,GAAG;EAAG,GAAG;EAAG,CAAC;AAEjF,gBAAe,gBAAgB,YAAY,mBAAmB,CAAC,EAAE,EAAE,SAAS,MAAM,CAAC;AACnF,gBAAe,gBAAgB,YAAY,mBAAmB,CAAC,EAAE,EAAE,SAAS,MAAM,CAAC;AAEnF,iBAAgB;AACd,cAAY,mBAAmB,CAAC;IAC/B,EAAE,CAAC;AAEN,QAAO,CAAC,UAAU,SAAS"}
|
package/lib/index.d.mts
CHANGED
|
@@ -77,13 +77,15 @@ export { useSelection } from './use-selection/use-selection.js';
|
|
|
77
77
|
export { useFloatingWindow } from './use-floating-window/use-floating-window.js';
|
|
78
78
|
export { useCollapse } from './use-collapse/use-collapse.js';
|
|
79
79
|
export { useHorizontalCollapse } from './use-collapse/use-horizontal-collapse.js';
|
|
80
|
+
export { useMask, formatMask, unformatMask, isMaskComplete, generatePattern, } from './use-mask/use-mask.js';
|
|
81
|
+
export { useRovingIndex } from './use-roving-index/use-roving-index.js';
|
|
80
82
|
export type { UseMediaQueryOptions } from './use-media-query/use-media-query';
|
|
81
83
|
export type { UseClipboardInput as UseClipboardOptions, UseClipboardReturnValue, } from './use-clipboard/use-clipboard';
|
|
82
84
|
export type { UseColorSchemeValue } from './use-color-scheme/use-color-scheme';
|
|
83
85
|
export type { UseCounterOptions, UseCounterHandlers, UseCounterReturnValue, } from './use-counter/use-counter';
|
|
84
86
|
export type { UseDebouncedCallbackOptions, UseDebouncedCallbackReturnValue, } from './use-debounced-callback/use-debounced-callback';
|
|
85
87
|
export type { UseDebouncedStateOptions, UseDebouncedStateReturnValue, } from './use-debounced-state/use-debounced-state';
|
|
86
|
-
export type { UseDebouncedValueOptions, UseDebouncedValueReturnValue, } from './use-debounced-value/use-debounced-value';
|
|
88
|
+
export type { UseDebouncedValueHandlers, UseDebouncedValueOptions, UseDebouncedValueReturnValue, } from './use-debounced-value/use-debounced-value';
|
|
87
89
|
export type { UseDisclosureOptions, UseDisclosureHandlers, UseDisclosureReturnValue, } from './use-disclosure/use-disclosure';
|
|
88
90
|
export type { EyeDropperOpenOptions, EyeDropperOpenReturnType, UseEyeDropperReturnValue, } from './use-eye-dropper/use-eye-dropper';
|
|
89
91
|
export type { UseFetchOptions, UseFetchReturnValue } from './use-fetch/use-fetch';
|
|
@@ -126,3 +128,5 @@ export type { UseSelectionHandlers, UseSelectionInput, UseSelectionReturnValue,
|
|
|
126
128
|
export type { UseElementSizeReturnValue, UseResizeObserverReturnValue, ObserverRect, } from './use-resize-observer/use-resize-observer';
|
|
127
129
|
export type { UseCollapseInput, UseCollapseReturnValue, UseCollapseState, } from './use-collapse/use-collapse';
|
|
128
130
|
export type { UseHorizontalCollapseInput, UseHorizontalCollapseReturnValue, UseHorizontalCollapseState, } from './use-collapse/use-horizontal-collapse';
|
|
131
|
+
export type { UseMaskOptions, UseMaskReturnValue, MaskState } from './use-mask/use-mask';
|
|
132
|
+
export type { UseRovingIndexInput, UseRovingIndexGetItemPropsInput, UseRovingIndexReturnValue, } from './use-roving-index/use-roving-index';
|
package/lib/index.d.ts
CHANGED
|
@@ -77,13 +77,15 @@ export { useSelection } from './use-selection/use-selection.js';
|
|
|
77
77
|
export { useFloatingWindow } from './use-floating-window/use-floating-window.js';
|
|
78
78
|
export { useCollapse } from './use-collapse/use-collapse.js';
|
|
79
79
|
export { useHorizontalCollapse } from './use-collapse/use-horizontal-collapse.js';
|
|
80
|
+
export { useMask, formatMask, unformatMask, isMaskComplete, generatePattern, } from './use-mask/use-mask.js';
|
|
81
|
+
export { useRovingIndex } from './use-roving-index/use-roving-index.js';
|
|
80
82
|
export type { UseMediaQueryOptions } from './use-media-query/use-media-query';
|
|
81
83
|
export type { UseClipboardInput as UseClipboardOptions, UseClipboardReturnValue, } from './use-clipboard/use-clipboard';
|
|
82
84
|
export type { UseColorSchemeValue } from './use-color-scheme/use-color-scheme';
|
|
83
85
|
export type { UseCounterOptions, UseCounterHandlers, UseCounterReturnValue, } from './use-counter/use-counter';
|
|
84
86
|
export type { UseDebouncedCallbackOptions, UseDebouncedCallbackReturnValue, } from './use-debounced-callback/use-debounced-callback';
|
|
85
87
|
export type { UseDebouncedStateOptions, UseDebouncedStateReturnValue, } from './use-debounced-state/use-debounced-state';
|
|
86
|
-
export type { UseDebouncedValueOptions, UseDebouncedValueReturnValue, } from './use-debounced-value/use-debounced-value';
|
|
88
|
+
export type { UseDebouncedValueHandlers, UseDebouncedValueOptions, UseDebouncedValueReturnValue, } from './use-debounced-value/use-debounced-value';
|
|
87
89
|
export type { UseDisclosureOptions, UseDisclosureHandlers, UseDisclosureReturnValue, } from './use-disclosure/use-disclosure';
|
|
88
90
|
export type { EyeDropperOpenOptions, EyeDropperOpenReturnType, UseEyeDropperReturnValue, } from './use-eye-dropper/use-eye-dropper';
|
|
89
91
|
export type { UseFetchOptions, UseFetchReturnValue } from './use-fetch/use-fetch';
|
|
@@ -126,3 +128,5 @@ export type { UseSelectionHandlers, UseSelectionInput, UseSelectionReturnValue,
|
|
|
126
128
|
export type { UseElementSizeReturnValue, UseResizeObserverReturnValue, ObserverRect, } from './use-resize-observer/use-resize-observer';
|
|
127
129
|
export type { UseCollapseInput, UseCollapseReturnValue, UseCollapseState, } from './use-collapse/use-collapse';
|
|
128
130
|
export type { UseHorizontalCollapseInput, UseHorizontalCollapseReturnValue, UseHorizontalCollapseState, } from './use-collapse/use-horizontal-collapse';
|
|
131
|
+
export type { UseMaskOptions, UseMaskReturnValue, MaskState } from './use-mask/use-mask';
|
|
132
|
+
export type { UseRovingIndexInput, UseRovingIndexGetItemPropsInput, UseRovingIndexReturnValue, } from './use-roving-index/use-roving-index';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
type EventType = MouseEvent | TouchEvent;
|
|
2
|
-
export declare function useClickOutside<T extends HTMLElement = any>(callback: (event: EventType) => void, events?: string[] | null, nodes?: (HTMLElement | null)[]): import("react").RefObject<T | null>;
|
|
2
|
+
export declare function useClickOutside<T extends HTMLElement = any>(callback: (event: EventType) => void, events?: string[] | null, nodes?: (HTMLElement | null)[], enabled?: boolean): import("react").RefObject<T | null>;
|
|
3
3
|
export {};
|
|
@@ -33,4 +33,9 @@ export interface UseHorizontalCollapseReturnValue {
|
|
|
33
33
|
getCollapseProps: (input?: GetHorizontalCollapsePropsInput) => GetHorizontalCollapsePropsReturnValue;
|
|
34
34
|
}
|
|
35
35
|
export declare function useHorizontalCollapse({ transitionDuration, transitionTimingFunction, onTransitionEnd, onTransitionStart, expanded, keepMounted, }: UseHorizontalCollapseInput): UseHorizontalCollapseReturnValue;
|
|
36
|
+
export declare namespace useHorizontalCollapse {
|
|
37
|
+
type Input = UseHorizontalCollapseInput;
|
|
38
|
+
type ReturnValue = UseHorizontalCollapseReturnValue;
|
|
39
|
+
type State = UseHorizontalCollapseState;
|
|
40
|
+
}
|
|
36
41
|
export {};
|
|
@@ -2,15 +2,19 @@ export interface UseDebouncedCallbackOptions {
|
|
|
2
2
|
delay: number;
|
|
3
3
|
flushOnUnmount?: boolean;
|
|
4
4
|
leading?: boolean;
|
|
5
|
+
maxWait?: number;
|
|
5
6
|
}
|
|
6
7
|
export type UseDebouncedCallbackReturnValue<T extends (...args: any[]) => any> = ((...args: Parameters<T>) => void) & {
|
|
7
8
|
flush: () => void;
|
|
8
9
|
cancel: () => void;
|
|
10
|
+
isPending: () => boolean;
|
|
9
11
|
};
|
|
10
12
|
export declare function useDebouncedCallback<T extends (...args: any[]) => any>(callback: T, options: number | UseDebouncedCallbackOptions): ((...args: Parameters<T>) => void) & {
|
|
11
13
|
flush: () => void;
|
|
12
14
|
cancel: () => void;
|
|
15
|
+
isPending: () => boolean;
|
|
13
16
|
_isFirstCall: boolean;
|
|
17
|
+
_hasPendingCallback: boolean;
|
|
14
18
|
};
|
|
15
19
|
export declare namespace useDebouncedCallback {
|
|
16
20
|
type Options = UseDebouncedCallbackOptions;
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
export interface UseDebouncedValueOptions {
|
|
2
2
|
leading?: boolean;
|
|
3
3
|
}
|
|
4
|
-
export
|
|
4
|
+
export interface UseDebouncedValueHandlers {
|
|
5
|
+
cancel: () => void;
|
|
6
|
+
flush: () => void;
|
|
7
|
+
}
|
|
8
|
+
export type UseDebouncedValueReturnValue<T> = [T, () => void, UseDebouncedValueHandlers];
|
|
5
9
|
export declare function useDebouncedValue<T = any>(value: T, wait: number, options?: UseDebouncedValueOptions): UseDebouncedValueReturnValue<T>;
|
|
6
10
|
export declare namespace useDebouncedValue {
|
|
11
|
+
type Handlers = UseDebouncedValueHandlers;
|
|
7
12
|
type Options = UseDebouncedValueOptions;
|
|
8
13
|
type ReturnValue<T> = UseDebouncedValueReturnValue<T>;
|
|
9
14
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = any>(type: K, listener: (this:
|
|
1
|
+
export declare function useEventListener<K extends keyof HTMLElementEventMap, T extends HTMLElement = any>(type: K, listener: (this: T, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): React.RefCallback<T | null>;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface KeyboardModifiers {
|
|
2
2
|
alt: boolean;
|
|
3
3
|
ctrl: boolean;
|
|
4
4
|
meta: boolean;
|
|
5
5
|
mod: boolean;
|
|
6
6
|
shift: boolean;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export type Hotkey = KeyboardModifiers & {
|
|
7
|
+
}
|
|
8
|
+
export interface Hotkey extends KeyboardModifiers {
|
|
10
9
|
key?: string;
|
|
11
|
-
}
|
|
10
|
+
}
|
|
12
11
|
type CheckHotkeyMatch = (event: KeyboardEvent) => boolean;
|
|
13
12
|
export declare function parseHotkey(hotkey: string): Hotkey;
|
|
14
13
|
export declare function getHotkeyMatcher(hotkey: string, usePhysicalKeys?: boolean): CheckHotkeyMatch;
|
|
@@ -15,6 +15,7 @@ export interface UseLongPressReturnValue {
|
|
|
15
15
|
onMouseLeave: (event: React.MouseEvent) => void;
|
|
16
16
|
onTouchStart: (event: React.TouchEvent) => void;
|
|
17
17
|
onTouchEnd: (event: React.TouchEvent) => void;
|
|
18
|
+
onTouchCancel: (event: React.TouchEvent) => void;
|
|
18
19
|
}
|
|
19
20
|
export declare function useLongPress(onLongPress: (event: React.MouseEvent | React.TouchEvent) => void, options?: UseLongPressOptions): UseLongPressReturnValue;
|
|
20
21
|
export declare namespace useLongPress {
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
export interface UseMaskOptions {
|
|
2
|
+
/** Mask pattern string or array of string literals and RegExp objects */
|
|
3
|
+
mask: string | Array<string | RegExp>;
|
|
4
|
+
/** Override or extend the default token map */
|
|
5
|
+
tokens?: Record<string, RegExp>;
|
|
6
|
+
/** Called before masking on each keystroke, can return overrides for mask options */
|
|
7
|
+
modify?: (value: string) => Partial<Pick<UseMaskOptions, 'mask' | 'tokens' | 'slotChar' | 'separate'>> | undefined;
|
|
8
|
+
/** When true, raw and display values are decoupled */
|
|
9
|
+
separate?: boolean;
|
|
10
|
+
/** Character displayed in unfilled slots, `"_"` by default */
|
|
11
|
+
slotChar?: string | null;
|
|
12
|
+
/** Show mask pattern even when field is empty and unfocused */
|
|
13
|
+
alwaysShowMask?: boolean;
|
|
14
|
+
/** Show mask placeholder on focus, `true` by default */
|
|
15
|
+
showMaskOnFocus?: boolean;
|
|
16
|
+
/** Transform each character before validation and insertion */
|
|
17
|
+
transform?: (char: string) => string;
|
|
18
|
+
/** Clear value on blur when mask is incomplete, `false` by default */
|
|
19
|
+
autoClear?: boolean;
|
|
20
|
+
/** Sets aria-invalid on the input */
|
|
21
|
+
invalid?: boolean;
|
|
22
|
+
/** Called on every change with raw and masked values */
|
|
23
|
+
onChangeRaw?: (rawValue: string, maskedValue: string) => void;
|
|
24
|
+
/** Called when all required mask slots are filled */
|
|
25
|
+
onComplete?: (maskedValue: string, rawValue: string) => void;
|
|
26
|
+
/** Escape hatch for advanced cursor/value manipulation */
|
|
27
|
+
beforeMaskedStateChange?: (states: {
|
|
28
|
+
previousState: MaskState;
|
|
29
|
+
currentState: MaskState;
|
|
30
|
+
nextState: MaskState;
|
|
31
|
+
}) => MaskState;
|
|
32
|
+
}
|
|
33
|
+
export interface MaskState {
|
|
34
|
+
value: string;
|
|
35
|
+
selection: {
|
|
36
|
+
start: number;
|
|
37
|
+
end: number;
|
|
38
|
+
} | null;
|
|
39
|
+
}
|
|
40
|
+
export interface UseMaskReturnValue {
|
|
41
|
+
/** Ref to attach to the input element */
|
|
42
|
+
ref: React.RefCallback<HTMLInputElement>;
|
|
43
|
+
/** Current masked display value */
|
|
44
|
+
value: string;
|
|
45
|
+
/** Current raw unmasked value */
|
|
46
|
+
rawValue: string;
|
|
47
|
+
/** Whether all required mask slots are filled */
|
|
48
|
+
isComplete: boolean;
|
|
49
|
+
/** Clear the input value and reset state */
|
|
50
|
+
reset: () => void;
|
|
51
|
+
}
|
|
52
|
+
export declare function formatMask(raw: string, options: UseMaskOptions): string;
|
|
53
|
+
export declare function unformatMask(masked: string, options: UseMaskOptions): string;
|
|
54
|
+
export declare function isMaskComplete(masked: string, options: UseMaskOptions): boolean;
|
|
55
|
+
export declare function generatePattern(mode: 'full' | 'full-inexact', options: UseMaskOptions): string;
|
|
56
|
+
export declare function useMask(options: UseMaskOptions): UseMaskReturnValue;
|
|
57
|
+
export declare namespace useMask {
|
|
58
|
+
type Options = UseMaskOptions;
|
|
59
|
+
type ReturnValue = UseMaskReturnValue;
|
|
60
|
+
}
|