@1money/hooks 0.1.2 → 0.1.4
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/es/index.d.ts +6 -0
- package/es/index.js +5 -0
- package/es/useDebouncedCallback/index.d.ts +21 -0
- package/es/useDebouncedCallback/index.js +45 -0
- package/es/useDebouncedValue/index.d.ts +13 -0
- package/es/useDebouncedValue/index.js +36 -0
- package/es/useInterval/index.d.ts +22 -0
- package/es/useInterval/index.js +40 -0
- package/es/useLatest/index.d.ts +1 -0
- package/es/useQueryState/index.d.ts +16 -5
- package/es/useQueryState/index.js +30 -53
- package/es/useThrottledCallback/index.d.ts +21 -0
- package/es/useThrottledCallback/index.js +74 -0
- package/es/useTimeout/index.d.ts +14 -0
- package/es/useTimeout/index.js +36 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +15 -0
- package/lib/useDebouncedCallback/index.d.ts +21 -0
- package/lib/useDebouncedCallback/index.js +58 -0
- package/lib/useDebouncedValue/index.d.ts +13 -0
- package/lib/useDebouncedValue/index.js +35 -0
- package/lib/useInterval/index.d.ts +22 -0
- package/lib/useInterval/index.js +60 -0
- package/lib/useLatest/index.d.ts +1 -0
- package/lib/useQueryState/index.d.ts +16 -5
- package/lib/useQueryState/index.js +9 -31
- package/lib/useThrottledCallback/index.d.ts +21 -0
- package/lib/useThrottledCallback/index.js +81 -0
- package/lib/useTimeout/index.d.ts +14 -0
- package/lib/useTimeout/index.js +56 -0
- package/package.json +33 -1
package/es/index.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
export { default as useControlledState } from './useControlledState';
|
|
2
|
+
export { default as useDebouncedValue } from './useDebouncedValue';
|
|
3
|
+
export { default as useDebouncedCallback } from './useDebouncedCallback';
|
|
4
|
+
export { default as useThrottledCallback } from './useThrottledCallback';
|
|
2
5
|
export { default as useEventCallback } from './useEventCallback';
|
|
3
6
|
export { default as useLatest } from './useLatest';
|
|
4
7
|
export { default as useLayoutEffect } from './useLayoutEffect';
|
|
5
8
|
export { default as useMemoizedFn } from './useMemoizedFn';
|
|
9
|
+
export { default as useInterval } from './useInterval';
|
|
10
|
+
export type { UseIntervalOptions } from './useInterval';
|
|
11
|
+
export { default as useTimeout } from './useTimeout';
|
|
6
12
|
export { default as usePrevious } from './usePrevious';
|
|
7
13
|
export { default as useSafeState } from './useSafeState';
|
|
8
14
|
export { default as useSyncState } from './useSyncState';
|
package/es/index.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
// Hooks
|
|
2
2
|
export { default as useControlledState } from "./useControlledState";
|
|
3
|
+
export { default as useDebouncedValue } from "./useDebouncedValue";
|
|
4
|
+
export { default as useDebouncedCallback } from "./useDebouncedCallback";
|
|
5
|
+
export { default as useThrottledCallback } from "./useThrottledCallback";
|
|
3
6
|
export { default as useEventCallback } from "./useEventCallback";
|
|
4
7
|
export { default as useLatest } from "./useLatest";
|
|
5
8
|
export { default as useLayoutEffect } from "./useLayoutEffect";
|
|
6
9
|
export { default as useMemoizedFn } from "./useMemoizedFn";
|
|
10
|
+
export { default as useInterval } from "./useInterval";
|
|
11
|
+
export { default as useTimeout } from "./useTimeout";
|
|
7
12
|
export { default as usePrevious } from "./usePrevious";
|
|
8
13
|
export { default as useSafeState } from "./useSafeState";
|
|
9
14
|
export { default as useSyncState } from "./useSyncState";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Callback<T extends unknown[]> = (...args: T) => void;
|
|
2
|
+
/**
|
|
3
|
+
* A hook that returns a debounced wrapper around a
|
|
4
|
+
* callback. Calling `run` resets a `delay` ms timer;
|
|
5
|
+
* the callback only fires once calls stop for `delay`
|
|
6
|
+
* ms, always with the most recent arguments. The latest
|
|
7
|
+
* `callback` body is invoked, so it never goes stale and
|
|
8
|
+
* needs no dependency array. The pending call is
|
|
9
|
+
* cancelled automatically on unmount, or manually via
|
|
10
|
+
* `cancel`.
|
|
11
|
+
*
|
|
12
|
+
* @param callback The function to debounce
|
|
13
|
+
* @param delay The debounce delay in ms (default 300)
|
|
14
|
+
* @returns `{ run, cancel }` — debounced runner and a
|
|
15
|
+
* canceller for any pending call
|
|
16
|
+
*/
|
|
17
|
+
export default function useDebouncedCallback<T extends unknown[]>(callback: Callback<T>, delay?: number): {
|
|
18
|
+
run: (...args: T) => void;
|
|
19
|
+
cancel: () => void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import useLatest from "../useLatest";
|
|
3
|
+
/**
|
|
4
|
+
* A hook that returns a debounced wrapper around a
|
|
5
|
+
* callback. Calling `run` resets a `delay` ms timer;
|
|
6
|
+
* the callback only fires once calls stop for `delay`
|
|
7
|
+
* ms, always with the most recent arguments. The latest
|
|
8
|
+
* `callback` body is invoked, so it never goes stale and
|
|
9
|
+
* needs no dependency array. The pending call is
|
|
10
|
+
* cancelled automatically on unmount, or manually via
|
|
11
|
+
* `cancel`.
|
|
12
|
+
*
|
|
13
|
+
* @param callback The function to debounce
|
|
14
|
+
* @param delay The debounce delay in ms (default 300)
|
|
15
|
+
* @returns `{ run, cancel }` — debounced runner and a
|
|
16
|
+
* canceller for any pending call
|
|
17
|
+
*/
|
|
18
|
+
export default function useDebouncedCallback(callback) {
|
|
19
|
+
var delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300;
|
|
20
|
+
var callbackRef = useLatest(callback);
|
|
21
|
+
var timerRef = useRef(null);
|
|
22
|
+
var cancel = useCallback(function () {
|
|
23
|
+
if (timerRef.current !== null) {
|
|
24
|
+
clearTimeout(timerRef.current);
|
|
25
|
+
timerRef.current = null;
|
|
26
|
+
}
|
|
27
|
+
}, []);
|
|
28
|
+
var run = useCallback(function () {
|
|
29
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
30
|
+
args[_key] = arguments[_key];
|
|
31
|
+
}
|
|
32
|
+
cancel();
|
|
33
|
+
timerRef.current = setTimeout(function () {
|
|
34
|
+
timerRef.current = null;
|
|
35
|
+
callbackRef.current.apply(callbackRef, args);
|
|
36
|
+
}, delay);
|
|
37
|
+
}, [delay, cancel, callbackRef]);
|
|
38
|
+
useEffect(function () {
|
|
39
|
+
return cancel;
|
|
40
|
+
}, [cancel]);
|
|
41
|
+
return {
|
|
42
|
+
run: run,
|
|
43
|
+
cancel: cancel
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A hook that returns a debounced copy of a value. The
|
|
3
|
+
* returned value only updates after `delay` ms have
|
|
4
|
+
* passed without `value` changing, which is handy for
|
|
5
|
+
* search inputs, resize handlers and other rapidly
|
|
6
|
+
* changing values you don't want to react to on every
|
|
7
|
+
* keystroke.
|
|
8
|
+
*
|
|
9
|
+
* @param value The value to debounce
|
|
10
|
+
* @param delay The debounce delay in ms (default 300)
|
|
11
|
+
* @returns The latest value, debounced by `delay`
|
|
12
|
+
*/
|
|
13
|
+
export default function useDebouncedValue<T>(value: T, delay?: number): T;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
|
2
|
+
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
|
+
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
+
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
|
+
import { useEffect, useState } from 'react';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A hook that returns a debounced copy of a value. The
|
|
11
|
+
* returned value only updates after `delay` ms have
|
|
12
|
+
* passed without `value` changing, which is handy for
|
|
13
|
+
* search inputs, resize handlers and other rapidly
|
|
14
|
+
* changing values you don't want to react to on every
|
|
15
|
+
* keystroke.
|
|
16
|
+
*
|
|
17
|
+
* @param value The value to debounce
|
|
18
|
+
* @param delay The debounce delay in ms (default 300)
|
|
19
|
+
* @returns The latest value, debounced by `delay`
|
|
20
|
+
*/
|
|
21
|
+
export default function useDebouncedValue(value) {
|
|
22
|
+
var delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300;
|
|
23
|
+
var _useState = useState(value),
|
|
24
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
25
|
+
debounced = _useState2[0],
|
|
26
|
+
setDebounced = _useState2[1];
|
|
27
|
+
useEffect(function () {
|
|
28
|
+
var timer = setTimeout(function () {
|
|
29
|
+
setDebounced(value);
|
|
30
|
+
}, delay);
|
|
31
|
+
return function () {
|
|
32
|
+
return clearTimeout(timer);
|
|
33
|
+
};
|
|
34
|
+
}, [value, delay]);
|
|
35
|
+
return debounced;
|
|
36
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface UseIntervalOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Run the callback once immediately when the interval
|
|
4
|
+
* starts, in addition to every `delay` ms after.
|
|
5
|
+
*/
|
|
6
|
+
immediate?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A hook that runs a callback on a fixed interval. The
|
|
10
|
+
* latest `fn` is always invoked, so it never goes stale
|
|
11
|
+
* and needs no dependency array. Pass `undefined`, `null`
|
|
12
|
+
* or a negative `delay` to pause the interval. The timer
|
|
13
|
+
* is cleared automatically on unmount or when `delay`
|
|
14
|
+
* changes, and can be stopped early via the returned
|
|
15
|
+
* `clear` function.
|
|
16
|
+
*
|
|
17
|
+
* @param fn The callback to run each interval
|
|
18
|
+
* @param delay Interval in ms; nullish/negative pauses it
|
|
19
|
+
* @param options `{ immediate }` to also fire on start
|
|
20
|
+
* @returns A `clear` function that stops the interval
|
|
21
|
+
*/
|
|
22
|
+
export default function useInterval(fn: () => void, delay?: number | null, options?: UseIntervalOptions): () => void;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import useLatest from "../useLatest";
|
|
3
|
+
/**
|
|
4
|
+
* A hook that runs a callback on a fixed interval. The
|
|
5
|
+
* latest `fn` is always invoked, so it never goes stale
|
|
6
|
+
* and needs no dependency array. Pass `undefined`, `null`
|
|
7
|
+
* or a negative `delay` to pause the interval. The timer
|
|
8
|
+
* is cleared automatically on unmount or when `delay`
|
|
9
|
+
* changes, and can be stopped early via the returned
|
|
10
|
+
* `clear` function.
|
|
11
|
+
*
|
|
12
|
+
* @param fn The callback to run each interval
|
|
13
|
+
* @param delay Interval in ms; nullish/negative pauses it
|
|
14
|
+
* @param options `{ immediate }` to also fire on start
|
|
15
|
+
* @returns A `clear` function that stops the interval
|
|
16
|
+
*/
|
|
17
|
+
export default function useInterval(fn, delay, options) {
|
|
18
|
+
var immediate = options === null || options === void 0 ? void 0 : options.immediate;
|
|
19
|
+
var fnRef = useLatest(fn);
|
|
20
|
+
var timerRef = useRef(null);
|
|
21
|
+
var clear = useCallback(function () {
|
|
22
|
+
if (timerRef.current !== null) {
|
|
23
|
+
clearInterval(timerRef.current);
|
|
24
|
+
timerRef.current = null;
|
|
25
|
+
}
|
|
26
|
+
}, []);
|
|
27
|
+
useEffect(function () {
|
|
28
|
+
if (delay === undefined || delay === null || delay < 0) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (immediate) {
|
|
32
|
+
fnRef.current();
|
|
33
|
+
}
|
|
34
|
+
timerRef.current = setInterval(function () {
|
|
35
|
+
fnRef.current();
|
|
36
|
+
}, delay);
|
|
37
|
+
return clear;
|
|
38
|
+
}, [delay, immediate, clear, fnRef]);
|
|
39
|
+
return clear;
|
|
40
|
+
}
|
package/es/useLatest/index.d.ts
CHANGED
|
@@ -42,13 +42,24 @@ export declare const queryJson: Parser<unknown>;
|
|
|
42
42
|
* parameter, so it survives refreshes and is
|
|
43
43
|
* shareable via the link.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
45
|
+
* Reading is reactive via Next's `useSearchParams`;
|
|
46
|
+
* writing goes through the native
|
|
47
|
+
* `history.pushState/replaceState`, which the Next.js
|
|
48
|
+
* App Router intercepts and syncs back into
|
|
49
|
+
* `useSearchParams` *without* a server round-trip (no
|
|
50
|
+
* route re-render, no scroll-to-top). Because the
|
|
51
|
+
* value is reactive, using it as a SWR/React Query key
|
|
50
52
|
* makes dependent requests refetch automatically.
|
|
51
53
|
*
|
|
54
|
+
* Constraints (inherited from `useSearchParams`):
|
|
55
|
+
* - Next.js App Router only; the calling component
|
|
56
|
+
* must be a Client Component (`'use client'`).
|
|
57
|
+
* - On statically rendered routes, wrap the consumer
|
|
58
|
+
* in `<Suspense>`; otherwise that subtree opts into
|
|
59
|
+
* client-side rendering. During prerender the param
|
|
60
|
+
* reads as absent, so `value` falls back to
|
|
61
|
+
* `defaultValue ?? null`.
|
|
62
|
+
*
|
|
52
63
|
* @param key The query parameter name
|
|
53
64
|
* @param options Parsing, serialization and history
|
|
54
65
|
* behaviour
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
5
|
-
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
6
|
-
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
|
7
|
-
import { useState, useEffect } from 'react';
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useSearchParams } from 'next/navigation';
|
|
8
4
|
import useMemoizedFn from "../useMemoizedFn";
|
|
9
5
|
|
|
10
6
|
/** Turn a raw query string into a typed value. */
|
|
@@ -32,30 +28,29 @@ export var queryJson = function queryJson(value) {
|
|
|
32
28
|
};
|
|
33
29
|
var isBrowser = typeof window !== 'undefined';
|
|
34
30
|
|
|
35
|
-
/**
|
|
36
|
-
* Subscribers re-read the URL when any instance
|
|
37
|
-
* mutates it. `history.pushState/replaceState` do
|
|
38
|
-
* not emit `popstate`, so we notify manually.
|
|
39
|
-
*/
|
|
40
|
-
var listeners = new Set();
|
|
41
|
-
var emit = function emit() {
|
|
42
|
-
listeners.forEach(function (fn) {
|
|
43
|
-
return fn();
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
|
|
47
31
|
/**
|
|
48
32
|
* Sync a piece of React state with a URL query
|
|
49
33
|
* parameter, so it survives refreshes and is
|
|
50
34
|
* shareable via the link.
|
|
51
35
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
36
|
+
* Reading is reactive via Next's `useSearchParams`;
|
|
37
|
+
* writing goes through the native
|
|
38
|
+
* `history.pushState/replaceState`, which the Next.js
|
|
39
|
+
* App Router intercepts and syncs back into
|
|
40
|
+
* `useSearchParams` *without* a server round-trip (no
|
|
41
|
+
* route re-render, no scroll-to-top). Because the
|
|
42
|
+
* value is reactive, using it as a SWR/React Query key
|
|
57
43
|
* makes dependent requests refetch automatically.
|
|
58
44
|
*
|
|
45
|
+
* Constraints (inherited from `useSearchParams`):
|
|
46
|
+
* - Next.js App Router only; the calling component
|
|
47
|
+
* must be a Client Component (`'use client'`).
|
|
48
|
+
* - On statically rendered routes, wrap the consumer
|
|
49
|
+
* in `<Suspense>`; otherwise that subtree opts into
|
|
50
|
+
* client-side rendering. During prerender the param
|
|
51
|
+
* reads as absent, so `value` falls back to
|
|
52
|
+
* `defaultValue ?? null`.
|
|
53
|
+
*
|
|
59
54
|
* @param key The query parameter name
|
|
60
55
|
* @param options Parsing, serialization and history
|
|
61
56
|
* behaviour
|
|
@@ -77,43 +72,26 @@ function useQueryState(key) {
|
|
|
77
72
|
defaultValue = options.defaultValue,
|
|
78
73
|
_options$history = options.history,
|
|
79
74
|
history = _options$history === void 0 ? 'replace' : _options$history;
|
|
80
|
-
var
|
|
81
|
-
if (!isBrowser) {
|
|
82
|
-
return defaultValue !== null && defaultValue !== void 0 ? defaultValue : null;
|
|
83
|
-
}
|
|
84
|
-
var params = new URLSearchParams(window.location.search);
|
|
85
|
-
var raw = params.get(key);
|
|
75
|
+
var parse = function parse(raw) {
|
|
86
76
|
if (raw === null) {
|
|
87
77
|
return defaultValue !== null && defaultValue !== void 0 ? defaultValue : null;
|
|
88
78
|
}
|
|
89
79
|
return parser ? parser(raw) : raw;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
var handler = function handler() {
|
|
97
|
-
return setValue(read());
|
|
98
|
-
};
|
|
99
|
-
listeners.add(handler);
|
|
100
|
-
window.addEventListener('popstate', handler);
|
|
101
|
-
// Resync in case the URL changed between the
|
|
102
|
-
// initial render and this effect running.
|
|
103
|
-
handler();
|
|
104
|
-
return function () {
|
|
105
|
-
listeners.delete(handler);
|
|
106
|
-
window.removeEventListener('popstate', handler);
|
|
107
|
-
};
|
|
108
|
-
// `read` is stable via useMemoizedFn.
|
|
109
|
-
}, [key, read]);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// Reactive read. Next re-renders consumers when the
|
|
83
|
+
// URL changes (including our own history writes).
|
|
84
|
+
var searchParams = useSearchParams();
|
|
85
|
+
var value = parse(searchParams.get(key));
|
|
110
86
|
var set = useMemoizedFn(function (next) {
|
|
111
87
|
if (!isBrowser) {
|
|
112
88
|
return;
|
|
113
89
|
}
|
|
114
|
-
|
|
115
|
-
|
|
90
|
+
// Build from the live URL (not the captured
|
|
91
|
+
// `searchParams`) so consecutive writes in one
|
|
92
|
+
// tick see each other's result.
|
|
116
93
|
var params = new URLSearchParams(window.location.search);
|
|
94
|
+
var resolved = typeof next === 'function' ? next(parse(params.get(key))) : next;
|
|
117
95
|
if (resolved === null || resolved === undefined) {
|
|
118
96
|
params.delete(key);
|
|
119
97
|
} else {
|
|
@@ -126,7 +104,6 @@ function useQueryState(key) {
|
|
|
126
104
|
} else {
|
|
127
105
|
window.history.replaceState(null, '', url);
|
|
128
106
|
}
|
|
129
|
-
emit();
|
|
130
107
|
});
|
|
131
108
|
return [value, set];
|
|
132
109
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Callback<T extends unknown[]> = (...args: T) => void;
|
|
2
|
+
/**
|
|
3
|
+
* A hook that returns a throttled wrapper around a
|
|
4
|
+
* callback. `run` fires immediately on the leading edge,
|
|
5
|
+
* then at most once per `delay` ms; the final call made
|
|
6
|
+
* during a throttled window is flushed on the trailing
|
|
7
|
+
* edge with its latest arguments. The most recent
|
|
8
|
+
* `callback` body is always used, so it never goes stale.
|
|
9
|
+
* Any pending trailing call is cancelled on unmount, or
|
|
10
|
+
* manually via `cancel`.
|
|
11
|
+
*
|
|
12
|
+
* @param callback The function to throttle
|
|
13
|
+
* @param delay The throttle window in ms (default 300)
|
|
14
|
+
* @returns `{ run, cancel }` — throttled runner and a
|
|
15
|
+
* canceller for any pending trailing call
|
|
16
|
+
*/
|
|
17
|
+
export default function useThrottledCallback<T extends unknown[]>(callback: Callback<T>, delay?: number): {
|
|
18
|
+
run: (...args: T) => void;
|
|
19
|
+
cancel: () => void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
2
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
3
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
4
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
5
|
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
6
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
|
7
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
8
|
+
import useLatest from "../useLatest";
|
|
9
|
+
/**
|
|
10
|
+
* A hook that returns a throttled wrapper around a
|
|
11
|
+
* callback. `run` fires immediately on the leading edge,
|
|
12
|
+
* then at most once per `delay` ms; the final call made
|
|
13
|
+
* during a throttled window is flushed on the trailing
|
|
14
|
+
* edge with its latest arguments. The most recent
|
|
15
|
+
* `callback` body is always used, so it never goes stale.
|
|
16
|
+
* Any pending trailing call is cancelled on unmount, or
|
|
17
|
+
* manually via `cancel`.
|
|
18
|
+
*
|
|
19
|
+
* @param callback The function to throttle
|
|
20
|
+
* @param delay The throttle window in ms (default 300)
|
|
21
|
+
* @returns `{ run, cancel }` — throttled runner and a
|
|
22
|
+
* canceller for any pending trailing call
|
|
23
|
+
*/
|
|
24
|
+
export default function useThrottledCallback(callback) {
|
|
25
|
+
var delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 300;
|
|
26
|
+
var callbackRef = useLatest(callback);
|
|
27
|
+
var lastRunRef = useRef(0);
|
|
28
|
+
var timerRef = useRef(null);
|
|
29
|
+
var lastArgsRef = useRef(null);
|
|
30
|
+
var cancel = useCallback(function () {
|
|
31
|
+
if (timerRef.current !== null) {
|
|
32
|
+
clearTimeout(timerRef.current);
|
|
33
|
+
timerRef.current = null;
|
|
34
|
+
}
|
|
35
|
+
lastArgsRef.current = null;
|
|
36
|
+
lastRunRef.current = 0;
|
|
37
|
+
}, []);
|
|
38
|
+
var run = useCallback(function () {
|
|
39
|
+
var now = Date.now();
|
|
40
|
+
var remaining = delay - (now - lastRunRef.current);
|
|
41
|
+
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
42
|
+
args[_key] = arguments[_key];
|
|
43
|
+
}
|
|
44
|
+
lastArgsRef.current = args;
|
|
45
|
+
if (remaining <= 0) {
|
|
46
|
+
if (timerRef.current !== null) {
|
|
47
|
+
clearTimeout(timerRef.current);
|
|
48
|
+
timerRef.current = null;
|
|
49
|
+
}
|
|
50
|
+
lastRunRef.current = now;
|
|
51
|
+
lastArgsRef.current = null;
|
|
52
|
+
callbackRef.current.apply(callbackRef, args);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (timerRef.current === null) {
|
|
56
|
+
timerRef.current = setTimeout(function () {
|
|
57
|
+
lastRunRef.current = Date.now();
|
|
58
|
+
timerRef.current = null;
|
|
59
|
+
if (lastArgsRef.current) {
|
|
60
|
+
var pending = lastArgsRef.current;
|
|
61
|
+
lastArgsRef.current = null;
|
|
62
|
+
callbackRef.current.apply(callbackRef, _toConsumableArray(pending));
|
|
63
|
+
}
|
|
64
|
+
}, remaining);
|
|
65
|
+
}
|
|
66
|
+
}, [delay, callbackRef]);
|
|
67
|
+
useEffect(function () {
|
|
68
|
+
return cancel;
|
|
69
|
+
}, [cancel]);
|
|
70
|
+
return {
|
|
71
|
+
run: run,
|
|
72
|
+
cancel: cancel
|
|
73
|
+
};
|
|
74
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A hook that runs a callback once after a delay. The
|
|
3
|
+
* latest `fn` is always invoked, so it never goes stale
|
|
4
|
+
* and needs no dependency array. Pass `undefined`, `null`
|
|
5
|
+
* or a negative `delay` to cancel the pending call. The
|
|
6
|
+
* timer is cleared automatically on unmount or when
|
|
7
|
+
* `delay` changes, and can be cancelled early via the
|
|
8
|
+
* returned `clear` function.
|
|
9
|
+
*
|
|
10
|
+
* @param fn The callback to run after the delay
|
|
11
|
+
* @param delay Delay in ms; nullish/negative cancels it
|
|
12
|
+
* @returns A `clear` function that cancels the timeout
|
|
13
|
+
*/
|
|
14
|
+
export default function useTimeout(fn: () => void, delay?: number | null): () => void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
import useLatest from "../useLatest";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A hook that runs a callback once after a delay. The
|
|
6
|
+
* latest `fn` is always invoked, so it never goes stale
|
|
7
|
+
* and needs no dependency array. Pass `undefined`, `null`
|
|
8
|
+
* or a negative `delay` to cancel the pending call. The
|
|
9
|
+
* timer is cleared automatically on unmount or when
|
|
10
|
+
* `delay` changes, and can be cancelled early via the
|
|
11
|
+
* returned `clear` function.
|
|
12
|
+
*
|
|
13
|
+
* @param fn The callback to run after the delay
|
|
14
|
+
* @param delay Delay in ms; nullish/negative cancels it
|
|
15
|
+
* @returns A `clear` function that cancels the timeout
|
|
16
|
+
*/
|
|
17
|
+
export default function useTimeout(fn, delay) {
|
|
18
|
+
var fnRef = useLatest(fn);
|
|
19
|
+
var timerRef = useRef(null);
|
|
20
|
+
var clear = useCallback(function () {
|
|
21
|
+
if (timerRef.current !== null) {
|
|
22
|
+
clearTimeout(timerRef.current);
|
|
23
|
+
timerRef.current = null;
|
|
24
|
+
}
|
|
25
|
+
}, []);
|
|
26
|
+
useEffect(function () {
|
|
27
|
+
if (delay === undefined || delay === null || delay < 0) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
timerRef.current = setTimeout(function () {
|
|
31
|
+
fnRef.current();
|
|
32
|
+
}, delay);
|
|
33
|
+
return clear;
|
|
34
|
+
}, [delay, clear, fnRef]);
|
|
35
|
+
return clear;
|
|
36
|
+
}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
export { default as useControlledState } from './useControlledState';
|
|
2
|
+
export { default as useDebouncedValue } from './useDebouncedValue';
|
|
3
|
+
export { default as useDebouncedCallback } from './useDebouncedCallback';
|
|
4
|
+
export { default as useThrottledCallback } from './useThrottledCallback';
|
|
2
5
|
export { default as useEventCallback } from './useEventCallback';
|
|
3
6
|
export { default as useLatest } from './useLatest';
|
|
4
7
|
export { default as useLayoutEffect } from './useLayoutEffect';
|
|
5
8
|
export { default as useMemoizedFn } from './useMemoizedFn';
|
|
9
|
+
export { default as useInterval } from './useInterval';
|
|
10
|
+
export type { UseIntervalOptions } from './useInterval';
|
|
11
|
+
export { default as useTimeout } from './useTimeout';
|
|
6
12
|
export { default as usePrevious } from './usePrevious';
|
|
7
13
|
export { default as useSafeState } from './useSafeState';
|
|
8
14
|
export { default as useSyncState } from './useSyncState';
|
package/lib/index.js
CHANGED
|
@@ -34,7 +34,10 @@ __export(index_exports, {
|
|
|
34
34
|
queryNumber: () => import_useQueryState.queryNumber,
|
|
35
35
|
queryString: () => import_useQueryState.queryString,
|
|
36
36
|
useControlledState: () => import_useControlledState.default,
|
|
37
|
+
useDebouncedCallback: () => import_useDebouncedCallback.default,
|
|
38
|
+
useDebouncedValue: () => import_useDebouncedValue.default,
|
|
37
39
|
useEventCallback: () => import_useEventCallback.default,
|
|
40
|
+
useInterval: () => import_useInterval.default,
|
|
38
41
|
useLatest: () => import_useLatest.default,
|
|
39
42
|
useLayoutEffect: () => import_useLayoutEffect.default,
|
|
40
43
|
useLayoutState: () => import_useLayoutState.default,
|
|
@@ -43,15 +46,22 @@ __export(index_exports, {
|
|
|
43
46
|
useQueryState: () => import_useQueryState.default,
|
|
44
47
|
useSafeState: () => import_useSafeState.default,
|
|
45
48
|
useSyncState: () => import_useSyncState.default,
|
|
49
|
+
useThrottledCallback: () => import_useThrottledCallback.default,
|
|
50
|
+
useTimeout: () => import_useTimeout.default,
|
|
46
51
|
useTimeoutLock: () => import_useLayoutState.useTimeoutLock,
|
|
47
52
|
useUpdateEffect: () => import_useUpdateEffect.default
|
|
48
53
|
});
|
|
49
54
|
module.exports = __toCommonJS(index_exports);
|
|
50
55
|
var import_useControlledState = __toESM(require("./useControlledState"));
|
|
56
|
+
var import_useDebouncedValue = __toESM(require("./useDebouncedValue"));
|
|
57
|
+
var import_useDebouncedCallback = __toESM(require("./useDebouncedCallback"));
|
|
58
|
+
var import_useThrottledCallback = __toESM(require("./useThrottledCallback"));
|
|
51
59
|
var import_useEventCallback = __toESM(require("./useEventCallback"));
|
|
52
60
|
var import_useLatest = __toESM(require("./useLatest"));
|
|
53
61
|
var import_useLayoutEffect = __toESM(require("./useLayoutEffect"));
|
|
54
62
|
var import_useMemoizedFn = __toESM(require("./useMemoizedFn"));
|
|
63
|
+
var import_useInterval = __toESM(require("./useInterval"));
|
|
64
|
+
var import_useTimeout = __toESM(require("./useTimeout"));
|
|
55
65
|
var import_usePrevious = __toESM(require("./usePrevious"));
|
|
56
66
|
var import_useSafeState = __toESM(require("./useSafeState"));
|
|
57
67
|
var import_useSyncState = __toESM(require("./useSyncState"));
|
|
@@ -65,7 +75,10 @@ var import_useQueryState = __toESM(require("./useQueryState"));
|
|
|
65
75
|
queryNumber,
|
|
66
76
|
queryString,
|
|
67
77
|
useControlledState,
|
|
78
|
+
useDebouncedCallback,
|
|
79
|
+
useDebouncedValue,
|
|
68
80
|
useEventCallback,
|
|
81
|
+
useInterval,
|
|
69
82
|
useLatest,
|
|
70
83
|
useLayoutEffect,
|
|
71
84
|
useLayoutState,
|
|
@@ -74,6 +87,8 @@ var import_useQueryState = __toESM(require("./useQueryState"));
|
|
|
74
87
|
useQueryState,
|
|
75
88
|
useSafeState,
|
|
76
89
|
useSyncState,
|
|
90
|
+
useThrottledCallback,
|
|
91
|
+
useTimeout,
|
|
77
92
|
useTimeoutLock,
|
|
78
93
|
useUpdateEffect
|
|
79
94
|
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Callback<T extends unknown[]> = (...args: T) => void;
|
|
2
|
+
/**
|
|
3
|
+
* A hook that returns a debounced wrapper around a
|
|
4
|
+
* callback. Calling `run` resets a `delay` ms timer;
|
|
5
|
+
* the callback only fires once calls stop for `delay`
|
|
6
|
+
* ms, always with the most recent arguments. The latest
|
|
7
|
+
* `callback` body is invoked, so it never goes stale and
|
|
8
|
+
* needs no dependency array. The pending call is
|
|
9
|
+
* cancelled automatically on unmount, or manually via
|
|
10
|
+
* `cancel`.
|
|
11
|
+
*
|
|
12
|
+
* @param callback The function to debounce
|
|
13
|
+
* @param delay The debounce delay in ms (default 300)
|
|
14
|
+
* @returns `{ run, cancel }` — debounced runner and a
|
|
15
|
+
* canceller for any pending call
|
|
16
|
+
*/
|
|
17
|
+
export default function useDebouncedCallback<T extends unknown[]>(callback: Callback<T>, delay?: number): {
|
|
18
|
+
run: (...args: T) => void;
|
|
19
|
+
cancel: () => void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/useDebouncedCallback/index.ts
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
default: () => useDebouncedCallback
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
var import_react = require("react");
|
|
36
|
+
var import_useLatest = __toESM(require("../useLatest"));
|
|
37
|
+
function useDebouncedCallback(callback, delay = 300) {
|
|
38
|
+
const callbackRef = (0, import_useLatest.default)(callback);
|
|
39
|
+
const timerRef = (0, import_react.useRef)(null);
|
|
40
|
+
const cancel = (0, import_react.useCallback)(() => {
|
|
41
|
+
if (timerRef.current !== null) {
|
|
42
|
+
clearTimeout(timerRef.current);
|
|
43
|
+
timerRef.current = null;
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
const run = (0, import_react.useCallback)(
|
|
47
|
+
(...args) => {
|
|
48
|
+
cancel();
|
|
49
|
+
timerRef.current = setTimeout(() => {
|
|
50
|
+
timerRef.current = null;
|
|
51
|
+
callbackRef.current(...args);
|
|
52
|
+
}, delay);
|
|
53
|
+
},
|
|
54
|
+
[delay, cancel, callbackRef]
|
|
55
|
+
);
|
|
56
|
+
(0, import_react.useEffect)(() => cancel, [cancel]);
|
|
57
|
+
return { run, cancel };
|
|
58
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A hook that returns a debounced copy of a value. The
|
|
3
|
+
* returned value only updates after `delay` ms have
|
|
4
|
+
* passed without `value` changing, which is handy for
|
|
5
|
+
* search inputs, resize handlers and other rapidly
|
|
6
|
+
* changing values you don't want to react to on every
|
|
7
|
+
* keystroke.
|
|
8
|
+
*
|
|
9
|
+
* @param value The value to debounce
|
|
10
|
+
* @param delay The debounce delay in ms (default 300)
|
|
11
|
+
* @returns The latest value, debounced by `delay`
|
|
12
|
+
*/
|
|
13
|
+
export default function useDebouncedValue<T>(value: T, delay?: number): T;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/useDebouncedValue/index.ts
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
default: () => useDebouncedValue
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
|
+
var import_react = require("react");
|
|
26
|
+
function useDebouncedValue(value, delay = 300) {
|
|
27
|
+
const [debounced, setDebounced] = (0, import_react.useState)(value);
|
|
28
|
+
(0, import_react.useEffect)(() => {
|
|
29
|
+
const timer = setTimeout(() => {
|
|
30
|
+
setDebounced(value);
|
|
31
|
+
}, delay);
|
|
32
|
+
return () => clearTimeout(timer);
|
|
33
|
+
}, [value, delay]);
|
|
34
|
+
return debounced;
|
|
35
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface UseIntervalOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Run the callback once immediately when the interval
|
|
4
|
+
* starts, in addition to every `delay` ms after.
|
|
5
|
+
*/
|
|
6
|
+
immediate?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* A hook that runs a callback on a fixed interval. The
|
|
10
|
+
* latest `fn` is always invoked, so it never goes stale
|
|
11
|
+
* and needs no dependency array. Pass `undefined`, `null`
|
|
12
|
+
* or a negative `delay` to pause the interval. The timer
|
|
13
|
+
* is cleared automatically on unmount or when `delay`
|
|
14
|
+
* changes, and can be stopped early via the returned
|
|
15
|
+
* `clear` function.
|
|
16
|
+
*
|
|
17
|
+
* @param fn The callback to run each interval
|
|
18
|
+
* @param delay Interval in ms; nullish/negative pauses it
|
|
19
|
+
* @param options `{ immediate }` to also fire on start
|
|
20
|
+
* @returns A `clear` function that stops the interval
|
|
21
|
+
*/
|
|
22
|
+
export default function useInterval(fn: () => void, delay?: number | null, options?: UseIntervalOptions): () => void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/useInterval/index.ts
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
default: () => useInterval
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
var import_react = require("react");
|
|
36
|
+
var import_useLatest = __toESM(require("../useLatest"));
|
|
37
|
+
function useInterval(fn, delay, options) {
|
|
38
|
+
const immediate = options == null ? void 0 : options.immediate;
|
|
39
|
+
const fnRef = (0, import_useLatest.default)(fn);
|
|
40
|
+
const timerRef = (0, import_react.useRef)(null);
|
|
41
|
+
const clear = (0, import_react.useCallback)(() => {
|
|
42
|
+
if (timerRef.current !== null) {
|
|
43
|
+
clearInterval(timerRef.current);
|
|
44
|
+
timerRef.current = null;
|
|
45
|
+
}
|
|
46
|
+
}, []);
|
|
47
|
+
(0, import_react.useEffect)(() => {
|
|
48
|
+
if (delay === void 0 || delay === null || delay < 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (immediate) {
|
|
52
|
+
fnRef.current();
|
|
53
|
+
}
|
|
54
|
+
timerRef.current = setInterval(() => {
|
|
55
|
+
fnRef.current();
|
|
56
|
+
}, delay);
|
|
57
|
+
return clear;
|
|
58
|
+
}, [delay, immediate, clear, fnRef]);
|
|
59
|
+
return clear;
|
|
60
|
+
}
|
package/lib/useLatest/index.d.ts
CHANGED
|
@@ -42,13 +42,24 @@ export declare const queryJson: Parser<unknown>;
|
|
|
42
42
|
* parameter, so it survives refreshes and is
|
|
43
43
|
* shareable via the link.
|
|
44
44
|
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
45
|
+
* Reading is reactive via Next's `useSearchParams`;
|
|
46
|
+
* writing goes through the native
|
|
47
|
+
* `history.pushState/replaceState`, which the Next.js
|
|
48
|
+
* App Router intercepts and syncs back into
|
|
49
|
+
* `useSearchParams` *without* a server round-trip (no
|
|
50
|
+
* route re-render, no scroll-to-top). Because the
|
|
51
|
+
* value is reactive, using it as a SWR/React Query key
|
|
50
52
|
* makes dependent requests refetch automatically.
|
|
51
53
|
*
|
|
54
|
+
* Constraints (inherited from `useSearchParams`):
|
|
55
|
+
* - Next.js App Router only; the calling component
|
|
56
|
+
* must be a Client Component (`'use client'`).
|
|
57
|
+
* - On statically rendered routes, wrap the consumer
|
|
58
|
+
* in `<Suspense>`; otherwise that subtree opts into
|
|
59
|
+
* client-side rendering. During prerender the param
|
|
60
|
+
* reads as absent, so `value` falls back to
|
|
61
|
+
* `defaultValue ?? null`.
|
|
62
|
+
*
|
|
52
63
|
* @param key The query parameter name
|
|
53
64
|
* @param options Parsing, serialization and history
|
|
54
65
|
* behaviour
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use client";
|
|
1
2
|
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -36,17 +37,13 @@ __export(index_exports, {
|
|
|
36
37
|
queryString: () => queryString
|
|
37
38
|
});
|
|
38
39
|
module.exports = __toCommonJS(index_exports);
|
|
39
|
-
var
|
|
40
|
+
var import_navigation = require("next/navigation");
|
|
40
41
|
var import_useMemoizedFn = __toESM(require("../useMemoizedFn"));
|
|
41
42
|
var queryString = (value) => value;
|
|
42
43
|
var queryNumber = (value) => Number(value);
|
|
43
44
|
var queryBoolean = (value) => value === "true";
|
|
44
45
|
var queryJson = (value) => JSON.parse(value);
|
|
45
46
|
var isBrowser = typeof window !== "undefined";
|
|
46
|
-
var listeners = /* @__PURE__ */ new Set();
|
|
47
|
-
var emit = () => {
|
|
48
|
-
listeners.forEach((fn) => fn());
|
|
49
|
-
};
|
|
50
47
|
function useQueryState(key, options = {}) {
|
|
51
48
|
const {
|
|
52
49
|
parser,
|
|
@@ -54,42 +51,24 @@ function useQueryState(key, options = {}) {
|
|
|
54
51
|
defaultValue,
|
|
55
52
|
history = "replace"
|
|
56
53
|
} = options;
|
|
57
|
-
const
|
|
58
|
-
if (!isBrowser) {
|
|
59
|
-
return defaultValue ?? null;
|
|
60
|
-
}
|
|
61
|
-
const params = new URLSearchParams(
|
|
62
|
-
window.location.search
|
|
63
|
-
);
|
|
64
|
-
const raw = params.get(key);
|
|
54
|
+
const parse = (raw) => {
|
|
65
55
|
if (raw === null) {
|
|
66
56
|
return defaultValue ?? null;
|
|
67
57
|
}
|
|
68
58
|
return parser ? parser(raw) : raw;
|
|
69
|
-
}
|
|
70
|
-
const
|
|
71
|
-
(
|
|
72
|
-
const handler = () => setValue(read());
|
|
73
|
-
listeners.add(handler);
|
|
74
|
-
window.addEventListener("popstate", handler);
|
|
75
|
-
handler();
|
|
76
|
-
return () => {
|
|
77
|
-
listeners.delete(handler);
|
|
78
|
-
window.removeEventListener(
|
|
79
|
-
"popstate",
|
|
80
|
-
handler
|
|
81
|
-
);
|
|
82
|
-
};
|
|
83
|
-
}, [key, read]);
|
|
59
|
+
};
|
|
60
|
+
const searchParams = (0, import_navigation.useSearchParams)();
|
|
61
|
+
const value = parse(searchParams.get(key));
|
|
84
62
|
const set = (0, import_useMemoizedFn.default)((next) => {
|
|
85
63
|
if (!isBrowser) {
|
|
86
64
|
return;
|
|
87
65
|
}
|
|
88
|
-
const prev = read();
|
|
89
|
-
const resolved = typeof next === "function" ? next(prev) : next;
|
|
90
66
|
const params = new URLSearchParams(
|
|
91
67
|
window.location.search
|
|
92
68
|
);
|
|
69
|
+
const resolved = typeof next === "function" ? next(
|
|
70
|
+
parse(params.get(key))
|
|
71
|
+
) : next;
|
|
93
72
|
if (resolved === null || resolved === void 0) {
|
|
94
73
|
params.delete(key);
|
|
95
74
|
} else {
|
|
@@ -102,7 +81,6 @@ function useQueryState(key, options = {}) {
|
|
|
102
81
|
} else {
|
|
103
82
|
window.history.replaceState(null, "", url);
|
|
104
83
|
}
|
|
105
|
-
emit();
|
|
106
84
|
});
|
|
107
85
|
return [value, set];
|
|
108
86
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
type Callback<T extends unknown[]> = (...args: T) => void;
|
|
2
|
+
/**
|
|
3
|
+
* A hook that returns a throttled wrapper around a
|
|
4
|
+
* callback. `run` fires immediately on the leading edge,
|
|
5
|
+
* then at most once per `delay` ms; the final call made
|
|
6
|
+
* during a throttled window is flushed on the trailing
|
|
7
|
+
* edge with its latest arguments. The most recent
|
|
8
|
+
* `callback` body is always used, so it never goes stale.
|
|
9
|
+
* Any pending trailing call is cancelled on unmount, or
|
|
10
|
+
* manually via `cancel`.
|
|
11
|
+
*
|
|
12
|
+
* @param callback The function to throttle
|
|
13
|
+
* @param delay The throttle window in ms (default 300)
|
|
14
|
+
* @returns `{ run, cancel }` — throttled runner and a
|
|
15
|
+
* canceller for any pending trailing call
|
|
16
|
+
*/
|
|
17
|
+
export default function useThrottledCallback<T extends unknown[]>(callback: Callback<T>, delay?: number): {
|
|
18
|
+
run: (...args: T) => void;
|
|
19
|
+
cancel: () => void;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/useThrottledCallback/index.ts
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
default: () => useThrottledCallback
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
var import_react = require("react");
|
|
36
|
+
var import_useLatest = __toESM(require("../useLatest"));
|
|
37
|
+
function useThrottledCallback(callback, delay = 300) {
|
|
38
|
+
const callbackRef = (0, import_useLatest.default)(callback);
|
|
39
|
+
const lastRunRef = (0, import_react.useRef)(0);
|
|
40
|
+
const timerRef = (0, import_react.useRef)(null);
|
|
41
|
+
const lastArgsRef = (0, import_react.useRef)(null);
|
|
42
|
+
const cancel = (0, import_react.useCallback)(() => {
|
|
43
|
+
if (timerRef.current !== null) {
|
|
44
|
+
clearTimeout(timerRef.current);
|
|
45
|
+
timerRef.current = null;
|
|
46
|
+
}
|
|
47
|
+
lastArgsRef.current = null;
|
|
48
|
+
lastRunRef.current = 0;
|
|
49
|
+
}, []);
|
|
50
|
+
const run = (0, import_react.useCallback)(
|
|
51
|
+
(...args) => {
|
|
52
|
+
const now = Date.now();
|
|
53
|
+
const remaining = delay - (now - lastRunRef.current);
|
|
54
|
+
lastArgsRef.current = args;
|
|
55
|
+
if (remaining <= 0) {
|
|
56
|
+
if (timerRef.current !== null) {
|
|
57
|
+
clearTimeout(timerRef.current);
|
|
58
|
+
timerRef.current = null;
|
|
59
|
+
}
|
|
60
|
+
lastRunRef.current = now;
|
|
61
|
+
lastArgsRef.current = null;
|
|
62
|
+
callbackRef.current(...args);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (timerRef.current === null) {
|
|
66
|
+
timerRef.current = setTimeout(() => {
|
|
67
|
+
lastRunRef.current = Date.now();
|
|
68
|
+
timerRef.current = null;
|
|
69
|
+
if (lastArgsRef.current) {
|
|
70
|
+
const pending = lastArgsRef.current;
|
|
71
|
+
lastArgsRef.current = null;
|
|
72
|
+
callbackRef.current(...pending);
|
|
73
|
+
}
|
|
74
|
+
}, remaining);
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
[delay, callbackRef]
|
|
78
|
+
);
|
|
79
|
+
(0, import_react.useEffect)(() => cancel, [cancel]);
|
|
80
|
+
return { run, cancel };
|
|
81
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A hook that runs a callback once after a delay. The
|
|
3
|
+
* latest `fn` is always invoked, so it never goes stale
|
|
4
|
+
* and needs no dependency array. Pass `undefined`, `null`
|
|
5
|
+
* or a negative `delay` to cancel the pending call. The
|
|
6
|
+
* timer is cleared automatically on unmount or when
|
|
7
|
+
* `delay` changes, and can be cancelled early via the
|
|
8
|
+
* returned `clear` function.
|
|
9
|
+
*
|
|
10
|
+
* @param fn The callback to run after the delay
|
|
11
|
+
* @param delay Delay in ms; nullish/negative cancels it
|
|
12
|
+
* @returns A `clear` function that cancels the timeout
|
|
13
|
+
*/
|
|
14
|
+
export default function useTimeout(fn: () => void, delay?: number | null): () => void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// src/useTimeout/index.ts
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
default: () => useTimeout
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
|
+
var import_react = require("react");
|
|
36
|
+
var import_useLatest = __toESM(require("../useLatest"));
|
|
37
|
+
function useTimeout(fn, delay) {
|
|
38
|
+
const fnRef = (0, import_useLatest.default)(fn);
|
|
39
|
+
const timerRef = (0, import_react.useRef)(null);
|
|
40
|
+
const clear = (0, import_react.useCallback)(() => {
|
|
41
|
+
if (timerRef.current !== null) {
|
|
42
|
+
clearTimeout(timerRef.current);
|
|
43
|
+
timerRef.current = null;
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
(0, import_react.useEffect)(() => {
|
|
47
|
+
if (delay === void 0 || delay === null || delay < 0) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
timerRef.current = setTimeout(() => {
|
|
51
|
+
fnRef.current();
|
|
52
|
+
}, delay);
|
|
53
|
+
return clear;
|
|
54
|
+
}, [delay, clear, fnRef]);
|
|
55
|
+
return clear;
|
|
56
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1money/hooks",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "React hooks for 1money front-end projects",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -21,6 +21,21 @@
|
|
|
21
21
|
"import": "./es/useControlledState/index.js",
|
|
22
22
|
"require": "./lib/useControlledState/index.js"
|
|
23
23
|
},
|
|
24
|
+
"./useDebouncedValue": {
|
|
25
|
+
"types": "./es/useDebouncedValue/index.d.ts",
|
|
26
|
+
"import": "./es/useDebouncedValue/index.js",
|
|
27
|
+
"require": "./lib/useDebouncedValue/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./useDebouncedCallback": {
|
|
30
|
+
"types": "./es/useDebouncedCallback/index.d.ts",
|
|
31
|
+
"import": "./es/useDebouncedCallback/index.js",
|
|
32
|
+
"require": "./lib/useDebouncedCallback/index.js"
|
|
33
|
+
},
|
|
34
|
+
"./useThrottledCallback": {
|
|
35
|
+
"types": "./es/useThrottledCallback/index.d.ts",
|
|
36
|
+
"import": "./es/useThrottledCallback/index.js",
|
|
37
|
+
"require": "./lib/useThrottledCallback/index.js"
|
|
38
|
+
},
|
|
24
39
|
"./useEventCallback": {
|
|
25
40
|
"types": "./es/useEventCallback/index.d.ts",
|
|
26
41
|
"import": "./es/useEventCallback/index.js",
|
|
@@ -51,6 +66,16 @@
|
|
|
51
66
|
"import": "./es/useMemoizedFn/index.js",
|
|
52
67
|
"require": "./lib/useMemoizedFn/index.js"
|
|
53
68
|
},
|
|
69
|
+
"./useInterval": {
|
|
70
|
+
"types": "./es/useInterval/index.d.ts",
|
|
71
|
+
"import": "./es/useInterval/index.js",
|
|
72
|
+
"require": "./lib/useInterval/index.js"
|
|
73
|
+
},
|
|
74
|
+
"./useTimeout": {
|
|
75
|
+
"types": "./es/useTimeout/index.d.ts",
|
|
76
|
+
"import": "./es/useTimeout/index.js",
|
|
77
|
+
"require": "./lib/useTimeout/index.js"
|
|
78
|
+
},
|
|
54
79
|
"./usePrevious": {
|
|
55
80
|
"types": "./es/usePrevious/index.d.ts",
|
|
56
81
|
"import": "./es/usePrevious/index.js",
|
|
@@ -90,8 +115,14 @@
|
|
|
90
115
|
"url": "https://github.com/1Money-Co/1money-hooks"
|
|
91
116
|
},
|
|
92
117
|
"peerDependencies": {
|
|
118
|
+
"next": ">=14.0.0",
|
|
93
119
|
"react": ">=16.8.0"
|
|
94
120
|
},
|
|
121
|
+
"peerDependenciesMeta": {
|
|
122
|
+
"next": {
|
|
123
|
+
"optional": true
|
|
124
|
+
}
|
|
125
|
+
},
|
|
95
126
|
"license": "MIT",
|
|
96
127
|
"devDependencies": {
|
|
97
128
|
"@eslint/js": "^9.39.4",
|
|
@@ -108,6 +139,7 @@
|
|
|
108
139
|
"father": "^4.6.17",
|
|
109
140
|
"globals": "^15.15.0",
|
|
110
141
|
"jsdom": "^29.0.2",
|
|
142
|
+
"next": "^14.2.0",
|
|
111
143
|
"prettier": "~3.5.3",
|
|
112
144
|
"react": "^19.1.0",
|
|
113
145
|
"react-dom": "^19.2.4",
|