@1money/hooks 0.1.0 → 0.1.2
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 +2 -0
- package/es/index.js +2 -1
- package/es/useQueryState/index.d.ts +64 -0
- package/es/useQueryState/index.js +133 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +14 -3
- package/lib/useControlledState/index.js +3 -3
- package/lib/useEventCallback/index.js +3 -3
- package/lib/useLatest/index.js +3 -3
- package/lib/useLayoutEffect/index.js +3 -3
- package/lib/useLayoutState/index.js +3 -3
- package/lib/useMemoizedFn/index.js +3 -3
- package/lib/usePrevious/index.js +3 -3
- package/lib/useQueryState/index.d.ts +64 -0
- package/lib/useQueryState/index.js +116 -0
- package/lib/useSafeState/index.js +5 -5
- package/lib/useSyncState/index.js +3 -3
- package/lib/useUpdateEffect/index.js +3 -3
- package/package.json +36 -17
package/es/index.d.ts
CHANGED
|
@@ -9,3 +9,5 @@ export { default as useSyncState } from './useSyncState';
|
|
|
9
9
|
export { default as useUpdateEffect } from './useUpdateEffect';
|
|
10
10
|
export { default as useLayoutState, useTimeoutLock } from './useLayoutState';
|
|
11
11
|
export type { Updater } from './useLayoutState';
|
|
12
|
+
export { default as useQueryState, queryString, queryNumber, queryBoolean, queryJson, } from './useQueryState';
|
|
13
|
+
export type { Parser, Serializer, QueryStateOptions, } from './useQueryState';
|
package/es/index.js
CHANGED
|
@@ -8,4 +8,5 @@ export { default as usePrevious } from "./usePrevious";
|
|
|
8
8
|
export { default as useSafeState } from "./useSafeState";
|
|
9
9
|
export { default as useSyncState } from "./useSyncState";
|
|
10
10
|
export { default as useUpdateEffect } from "./useUpdateEffect";
|
|
11
|
-
export { default as useLayoutState, useTimeoutLock } from "./useLayoutState";
|
|
11
|
+
export { default as useLayoutState, useTimeoutLock } from "./useLayoutState";
|
|
12
|
+
export { default as useQueryState, queryString, queryNumber, queryBoolean, queryJson } from "./useQueryState";
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Turn a raw query string into a typed value. */
|
|
2
|
+
export type Parser<T> = (value: string) => T;
|
|
3
|
+
/** Turn a typed value back into a query string. */
|
|
4
|
+
export type Serializer<T> = (value: T) => string;
|
|
5
|
+
export interface QueryStateOptions<T> {
|
|
6
|
+
/**
|
|
7
|
+
* Parse the raw `string` read from the URL into `T`.
|
|
8
|
+
* Defaults to identity (the raw string).
|
|
9
|
+
*/
|
|
10
|
+
parser?: Parser<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Serialize `T` back into a `string` for the URL.
|
|
13
|
+
* Defaults to `String(value)`.
|
|
14
|
+
*/
|
|
15
|
+
serializer?: Serializer<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Value returned when the param is absent from
|
|
18
|
+
* the URL. When set, the hook never returns
|
|
19
|
+
* `null`.
|
|
20
|
+
*/
|
|
21
|
+
defaultValue?: T;
|
|
22
|
+
/**
|
|
23
|
+
* How the URL is mutated:
|
|
24
|
+
* - `'replace'` (default) — `history.replaceState`,
|
|
25
|
+
* does not add a history entry.
|
|
26
|
+
* - `'push'` — `history.pushState`, back/forward
|
|
27
|
+
* navigates between values.
|
|
28
|
+
*/
|
|
29
|
+
history?: 'push' | 'replace';
|
|
30
|
+
}
|
|
31
|
+
type SetQueryState<T> = (value: T | null | ((prev: T | null) => T | null)) => void;
|
|
32
|
+
/** Identity parser used when none is supplied. */
|
|
33
|
+
export declare const queryString: Parser<string>;
|
|
34
|
+
/** Parse a numeric query param. `NaN` for non-numbers. */
|
|
35
|
+
export declare const queryNumber: Parser<number>;
|
|
36
|
+
/** Parse a boolean query param. Only `'true'` is true. */
|
|
37
|
+
export declare const queryBoolean: Parser<boolean>;
|
|
38
|
+
/** Parse a JSON-encoded query param. */
|
|
39
|
+
export declare const queryJson: Parser<unknown>;
|
|
40
|
+
/**
|
|
41
|
+
* Sync a piece of React state with a URL query
|
|
42
|
+
* parameter, so it survives refreshes and is
|
|
43
|
+
* shareable via the link.
|
|
44
|
+
*
|
|
45
|
+
* Reads/writes go through native
|
|
46
|
+
* `history.pushState/replaceState`, which keeps it
|
|
47
|
+
* compatible with the Next.js App Router (it does
|
|
48
|
+
* not trigger a route re-mount). Because the value
|
|
49
|
+
* is reactive, using it as a SWR/React Query key
|
|
50
|
+
* makes dependent requests refetch automatically.
|
|
51
|
+
*
|
|
52
|
+
* @param key The query parameter name
|
|
53
|
+
* @param options Parsing, serialization and history
|
|
54
|
+
* behaviour
|
|
55
|
+
* @returns A `[value, setValue]` tuple. `setValue`
|
|
56
|
+
* accepts a value, an updater function, or `null`
|
|
57
|
+
* to remove the param.
|
|
58
|
+
*/
|
|
59
|
+
declare function useQueryState(key: string): [string | null, SetQueryState<string>];
|
|
60
|
+
declare function useQueryState<T>(key: string, options: QueryStateOptions<T> & {
|
|
61
|
+
defaultValue: T;
|
|
62
|
+
}): [T, SetQueryState<T>];
|
|
63
|
+
declare function useQueryState<T>(key: string, options: QueryStateOptions<T>): [T | null, SetQueryState<T>];
|
|
64
|
+
export default useQueryState;
|
|
@@ -0,0 +1,133 @@
|
|
|
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 { useState, useEffect } from 'react';
|
|
8
|
+
import useMemoizedFn from "../useMemoizedFn";
|
|
9
|
+
|
|
10
|
+
/** Turn a raw query string into a typed value. */
|
|
11
|
+
|
|
12
|
+
/** Turn a typed value back into a query string. */
|
|
13
|
+
|
|
14
|
+
/** Identity parser used when none is supplied. */
|
|
15
|
+
export var queryString = function queryString(value) {
|
|
16
|
+
return value;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** Parse a numeric query param. `NaN` for non-numbers. */
|
|
20
|
+
export var queryNumber = function queryNumber(value) {
|
|
21
|
+
return Number(value);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Parse a boolean query param. Only `'true'` is true. */
|
|
25
|
+
export var queryBoolean = function queryBoolean(value) {
|
|
26
|
+
return value === 'true';
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** Parse a JSON-encoded query param. */
|
|
30
|
+
export var queryJson = function queryJson(value) {
|
|
31
|
+
return JSON.parse(value);
|
|
32
|
+
};
|
|
33
|
+
var isBrowser = typeof window !== 'undefined';
|
|
34
|
+
|
|
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
|
+
/**
|
|
48
|
+
* Sync a piece of React state with a URL query
|
|
49
|
+
* parameter, so it survives refreshes and is
|
|
50
|
+
* shareable via the link.
|
|
51
|
+
*
|
|
52
|
+
* Reads/writes go through native
|
|
53
|
+
* `history.pushState/replaceState`, which keeps it
|
|
54
|
+
* compatible with the Next.js App Router (it does
|
|
55
|
+
* not trigger a route re-mount). Because the value
|
|
56
|
+
* is reactive, using it as a SWR/React Query key
|
|
57
|
+
* makes dependent requests refetch automatically.
|
|
58
|
+
*
|
|
59
|
+
* @param key The query parameter name
|
|
60
|
+
* @param options Parsing, serialization and history
|
|
61
|
+
* behaviour
|
|
62
|
+
* @returns A `[value, setValue]` tuple. `setValue`
|
|
63
|
+
* accepts a value, an updater function, or `null`
|
|
64
|
+
* to remove the param.
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
// eslint-disable-next-line no-redeclare
|
|
68
|
+
|
|
69
|
+
// eslint-disable-next-line no-redeclare
|
|
70
|
+
|
|
71
|
+
// eslint-disable-next-line no-redeclare
|
|
72
|
+
function useQueryState(key) {
|
|
73
|
+
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
74
|
+
var parser = options.parser,
|
|
75
|
+
_options$serializer = options.serializer,
|
|
76
|
+
serializer = _options$serializer === void 0 ? String : _options$serializer,
|
|
77
|
+
defaultValue = options.defaultValue,
|
|
78
|
+
_options$history = options.history,
|
|
79
|
+
history = _options$history === void 0 ? 'replace' : _options$history;
|
|
80
|
+
var read = useMemoizedFn(function () {
|
|
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);
|
|
86
|
+
if (raw === null) {
|
|
87
|
+
return defaultValue !== null && defaultValue !== void 0 ? defaultValue : null;
|
|
88
|
+
}
|
|
89
|
+
return parser ? parser(raw) : raw;
|
|
90
|
+
});
|
|
91
|
+
var _useState = useState(read),
|
|
92
|
+
_useState2 = _slicedToArray(_useState, 2),
|
|
93
|
+
value = _useState2[0],
|
|
94
|
+
setValue = _useState2[1];
|
|
95
|
+
useEffect(function () {
|
|
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]);
|
|
110
|
+
var set = useMemoizedFn(function (next) {
|
|
111
|
+
if (!isBrowser) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
var prev = read();
|
|
115
|
+
var resolved = typeof next === 'function' ? next(prev) : next;
|
|
116
|
+
var params = new URLSearchParams(window.location.search);
|
|
117
|
+
if (resolved === null || resolved === undefined) {
|
|
118
|
+
params.delete(key);
|
|
119
|
+
} else {
|
|
120
|
+
params.set(key, serializer(resolved));
|
|
121
|
+
}
|
|
122
|
+
var search = params.toString();
|
|
123
|
+
var url = window.location.pathname + (search ? "?".concat(search) : '') + window.location.hash;
|
|
124
|
+
if (history === 'push') {
|
|
125
|
+
window.history.pushState(null, '', url);
|
|
126
|
+
} else {
|
|
127
|
+
window.history.replaceState(null, '', url);
|
|
128
|
+
}
|
|
129
|
+
emit();
|
|
130
|
+
});
|
|
131
|
+
return [value, set];
|
|
132
|
+
}
|
|
133
|
+
export default useQueryState;
|
package/lib/index.d.ts
CHANGED
|
@@ -9,3 +9,5 @@ export { default as useSyncState } from './useSyncState';
|
|
|
9
9
|
export { default as useUpdateEffect } from './useUpdateEffect';
|
|
10
10
|
export { default as useLayoutState, useTimeoutLock } from './useLayoutState';
|
|
11
11
|
export type { Updater } from './useLayoutState';
|
|
12
|
+
export { default as useQueryState, queryString, queryNumber, queryBoolean, queryJson, } from './useQueryState';
|
|
13
|
+
export type { Parser, Serializer, QueryStateOptions, } from './useQueryState';
|
package/lib/index.js
CHANGED
|
@@ -27,8 +27,12 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
29
|
// src/index.ts
|
|
30
|
-
var
|
|
31
|
-
__export(
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
queryBoolean: () => import_useQueryState.queryBoolean,
|
|
33
|
+
queryJson: () => import_useQueryState.queryJson,
|
|
34
|
+
queryNumber: () => import_useQueryState.queryNumber,
|
|
35
|
+
queryString: () => import_useQueryState.queryString,
|
|
32
36
|
useControlledState: () => import_useControlledState.default,
|
|
33
37
|
useEventCallback: () => import_useEventCallback.default,
|
|
34
38
|
useLatest: () => import_useLatest.default,
|
|
@@ -36,12 +40,13 @@ __export(src_exports, {
|
|
|
36
40
|
useLayoutState: () => import_useLayoutState.default,
|
|
37
41
|
useMemoizedFn: () => import_useMemoizedFn.default,
|
|
38
42
|
usePrevious: () => import_usePrevious.default,
|
|
43
|
+
useQueryState: () => import_useQueryState.default,
|
|
39
44
|
useSafeState: () => import_useSafeState.default,
|
|
40
45
|
useSyncState: () => import_useSyncState.default,
|
|
41
46
|
useTimeoutLock: () => import_useLayoutState.useTimeoutLock,
|
|
42
47
|
useUpdateEffect: () => import_useUpdateEffect.default
|
|
43
48
|
});
|
|
44
|
-
module.exports = __toCommonJS(
|
|
49
|
+
module.exports = __toCommonJS(index_exports);
|
|
45
50
|
var import_useControlledState = __toESM(require("./useControlledState"));
|
|
46
51
|
var import_useEventCallback = __toESM(require("./useEventCallback"));
|
|
47
52
|
var import_useLatest = __toESM(require("./useLatest"));
|
|
@@ -52,8 +57,13 @@ var import_useSafeState = __toESM(require("./useSafeState"));
|
|
|
52
57
|
var import_useSyncState = __toESM(require("./useSyncState"));
|
|
53
58
|
var import_useUpdateEffect = __toESM(require("./useUpdateEffect"));
|
|
54
59
|
var import_useLayoutState = __toESM(require("./useLayoutState"));
|
|
60
|
+
var import_useQueryState = __toESM(require("./useQueryState"));
|
|
55
61
|
// Annotate the CommonJS export names for ESM import in node:
|
|
56
62
|
0 && (module.exports = {
|
|
63
|
+
queryBoolean,
|
|
64
|
+
queryJson,
|
|
65
|
+
queryNumber,
|
|
66
|
+
queryString,
|
|
57
67
|
useControlledState,
|
|
58
68
|
useEventCallback,
|
|
59
69
|
useLatest,
|
|
@@ -61,6 +71,7 @@ var import_useLayoutState = __toESM(require("./useLayoutState"));
|
|
|
61
71
|
useLayoutState,
|
|
62
72
|
useMemoizedFn,
|
|
63
73
|
usePrevious,
|
|
74
|
+
useQueryState,
|
|
64
75
|
useSafeState,
|
|
65
76
|
useSyncState,
|
|
66
77
|
useTimeoutLock,
|
|
@@ -27,11 +27,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
29
|
// src/useControlledState/index.ts
|
|
30
|
-
var
|
|
31
|
-
__export(
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
32
|
default: () => useControlledState
|
|
33
33
|
});
|
|
34
|
-
module.exports = __toCommonJS(
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
35
|
var import_react = require("react");
|
|
36
36
|
var import_useLayoutEffect = __toESM(require("../useLayoutEffect"));
|
|
37
37
|
function useControlledState(defaultStateValue, value) {
|
|
@@ -27,11 +27,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
29
|
// src/useEventCallback/index.ts
|
|
30
|
-
var
|
|
31
|
-
__export(
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
32
|
default: () => useEventCallback
|
|
33
33
|
});
|
|
34
|
-
module.exports = __toCommonJS(
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
35
|
var import_react = require("react");
|
|
36
36
|
var import_useLatest = __toESM(require("../useLatest"));
|
|
37
37
|
function useEventCallback(fn) {
|
package/lib/useLatest/index.js
CHANGED
|
@@ -17,11 +17,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
19
|
// src/useLatest/index.ts
|
|
20
|
-
var
|
|
21
|
-
__export(
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
22
|
default: () => useLatest
|
|
23
23
|
});
|
|
24
|
-
module.exports = __toCommonJS(
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
25
|
var import_react = require("react");
|
|
26
26
|
function useLatest(value) {
|
|
27
27
|
const ref = (0, import_react.useRef)(value);
|
|
@@ -17,11 +17,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
19
|
// src/useLayoutEffect/index.ts
|
|
20
|
-
var
|
|
21
|
-
__export(
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
22
|
default: () => useLayoutEffect
|
|
23
23
|
});
|
|
24
|
-
module.exports = __toCommonJS(
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
25
|
var import_react = require("react");
|
|
26
26
|
function useLayoutEffect(effect, deps) {
|
|
27
27
|
const isMounted = (0, import_react.useRef)(false);
|
|
@@ -17,12 +17,12 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
19
|
// src/useLayoutState/index.ts
|
|
20
|
-
var
|
|
21
|
-
__export(
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
22
|
default: () => useLayoutState,
|
|
23
23
|
useTimeoutLock: () => useTimeoutLock
|
|
24
24
|
});
|
|
25
|
-
module.exports = __toCommonJS(
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
26
|
var import_react = require("react");
|
|
27
27
|
function useLayoutState(defaultState) {
|
|
28
28
|
const stateRef = (0, import_react.useRef)(defaultState);
|
|
@@ -17,11 +17,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
19
|
// src/useMemoizedFn/index.ts
|
|
20
|
-
var
|
|
21
|
-
__export(
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
22
|
default: () => useMemoizedFn
|
|
23
23
|
});
|
|
24
|
-
module.exports = __toCommonJS(
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
25
|
var import_react = require("react");
|
|
26
26
|
function useMemoizedFn(fn) {
|
|
27
27
|
const fnRef = (0, import_react.useRef)(fn);
|
package/lib/usePrevious/index.js
CHANGED
|
@@ -17,11 +17,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
19
|
// src/usePrevious/index.ts
|
|
20
|
-
var
|
|
21
|
-
__export(
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
22
|
default: () => usePrevious
|
|
23
23
|
});
|
|
24
|
-
module.exports = __toCommonJS(
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
25
|
var import_react = require("react");
|
|
26
26
|
function usePrevious(value) {
|
|
27
27
|
const ref = (0, import_react.useRef)(void 0);
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/** Turn a raw query string into a typed value. */
|
|
2
|
+
export type Parser<T> = (value: string) => T;
|
|
3
|
+
/** Turn a typed value back into a query string. */
|
|
4
|
+
export type Serializer<T> = (value: T) => string;
|
|
5
|
+
export interface QueryStateOptions<T> {
|
|
6
|
+
/**
|
|
7
|
+
* Parse the raw `string` read from the URL into `T`.
|
|
8
|
+
* Defaults to identity (the raw string).
|
|
9
|
+
*/
|
|
10
|
+
parser?: Parser<T>;
|
|
11
|
+
/**
|
|
12
|
+
* Serialize `T` back into a `string` for the URL.
|
|
13
|
+
* Defaults to `String(value)`.
|
|
14
|
+
*/
|
|
15
|
+
serializer?: Serializer<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Value returned when the param is absent from
|
|
18
|
+
* the URL. When set, the hook never returns
|
|
19
|
+
* `null`.
|
|
20
|
+
*/
|
|
21
|
+
defaultValue?: T;
|
|
22
|
+
/**
|
|
23
|
+
* How the URL is mutated:
|
|
24
|
+
* - `'replace'` (default) — `history.replaceState`,
|
|
25
|
+
* does not add a history entry.
|
|
26
|
+
* - `'push'` — `history.pushState`, back/forward
|
|
27
|
+
* navigates between values.
|
|
28
|
+
*/
|
|
29
|
+
history?: 'push' | 'replace';
|
|
30
|
+
}
|
|
31
|
+
type SetQueryState<T> = (value: T | null | ((prev: T | null) => T | null)) => void;
|
|
32
|
+
/** Identity parser used when none is supplied. */
|
|
33
|
+
export declare const queryString: Parser<string>;
|
|
34
|
+
/** Parse a numeric query param. `NaN` for non-numbers. */
|
|
35
|
+
export declare const queryNumber: Parser<number>;
|
|
36
|
+
/** Parse a boolean query param. Only `'true'` is true. */
|
|
37
|
+
export declare const queryBoolean: Parser<boolean>;
|
|
38
|
+
/** Parse a JSON-encoded query param. */
|
|
39
|
+
export declare const queryJson: Parser<unknown>;
|
|
40
|
+
/**
|
|
41
|
+
* Sync a piece of React state with a URL query
|
|
42
|
+
* parameter, so it survives refreshes and is
|
|
43
|
+
* shareable via the link.
|
|
44
|
+
*
|
|
45
|
+
* Reads/writes go through native
|
|
46
|
+
* `history.pushState/replaceState`, which keeps it
|
|
47
|
+
* compatible with the Next.js App Router (it does
|
|
48
|
+
* not trigger a route re-mount). Because the value
|
|
49
|
+
* is reactive, using it as a SWR/React Query key
|
|
50
|
+
* makes dependent requests refetch automatically.
|
|
51
|
+
*
|
|
52
|
+
* @param key The query parameter name
|
|
53
|
+
* @param options Parsing, serialization and history
|
|
54
|
+
* behaviour
|
|
55
|
+
* @returns A `[value, setValue]` tuple. `setValue`
|
|
56
|
+
* accepts a value, an updater function, or `null`
|
|
57
|
+
* to remove the param.
|
|
58
|
+
*/
|
|
59
|
+
declare function useQueryState(key: string): [string | null, SetQueryState<string>];
|
|
60
|
+
declare function useQueryState<T>(key: string, options: QueryStateOptions<T> & {
|
|
61
|
+
defaultValue: T;
|
|
62
|
+
}): [T, SetQueryState<T>];
|
|
63
|
+
declare function useQueryState<T>(key: string, options: QueryStateOptions<T>): [T | null, SetQueryState<T>];
|
|
64
|
+
export default useQueryState;
|
|
@@ -0,0 +1,116 @@
|
|
|
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/useQueryState/index.ts
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
default: () => index_default,
|
|
33
|
+
queryBoolean: () => queryBoolean,
|
|
34
|
+
queryJson: () => queryJson,
|
|
35
|
+
queryNumber: () => queryNumber,
|
|
36
|
+
queryString: () => queryString
|
|
37
|
+
});
|
|
38
|
+
module.exports = __toCommonJS(index_exports);
|
|
39
|
+
var import_react = require("react");
|
|
40
|
+
var import_useMemoizedFn = __toESM(require("../useMemoizedFn"));
|
|
41
|
+
var queryString = (value) => value;
|
|
42
|
+
var queryNumber = (value) => Number(value);
|
|
43
|
+
var queryBoolean = (value) => value === "true";
|
|
44
|
+
var queryJson = (value) => JSON.parse(value);
|
|
45
|
+
var isBrowser = typeof window !== "undefined";
|
|
46
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
47
|
+
var emit = () => {
|
|
48
|
+
listeners.forEach((fn) => fn());
|
|
49
|
+
};
|
|
50
|
+
function useQueryState(key, options = {}) {
|
|
51
|
+
const {
|
|
52
|
+
parser,
|
|
53
|
+
serializer = String,
|
|
54
|
+
defaultValue,
|
|
55
|
+
history = "replace"
|
|
56
|
+
} = options;
|
|
57
|
+
const read = (0, import_useMemoizedFn.default)(() => {
|
|
58
|
+
if (!isBrowser) {
|
|
59
|
+
return defaultValue ?? null;
|
|
60
|
+
}
|
|
61
|
+
const params = new URLSearchParams(
|
|
62
|
+
window.location.search
|
|
63
|
+
);
|
|
64
|
+
const raw = params.get(key);
|
|
65
|
+
if (raw === null) {
|
|
66
|
+
return defaultValue ?? null;
|
|
67
|
+
}
|
|
68
|
+
return parser ? parser(raw) : raw;
|
|
69
|
+
});
|
|
70
|
+
const [value, setValue] = (0, import_react.useState)(read);
|
|
71
|
+
(0, import_react.useEffect)(() => {
|
|
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]);
|
|
84
|
+
const set = (0, import_useMemoizedFn.default)((next) => {
|
|
85
|
+
if (!isBrowser) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const prev = read();
|
|
89
|
+
const resolved = typeof next === "function" ? next(prev) : next;
|
|
90
|
+
const params = new URLSearchParams(
|
|
91
|
+
window.location.search
|
|
92
|
+
);
|
|
93
|
+
if (resolved === null || resolved === void 0) {
|
|
94
|
+
params.delete(key);
|
|
95
|
+
} else {
|
|
96
|
+
params.set(key, serializer(resolved));
|
|
97
|
+
}
|
|
98
|
+
const search = params.toString();
|
|
99
|
+
const url = window.location.pathname + (search ? `?${search}` : "") + window.location.hash;
|
|
100
|
+
if (history === "push") {
|
|
101
|
+
window.history.pushState(null, "", url);
|
|
102
|
+
} else {
|
|
103
|
+
window.history.replaceState(null, "", url);
|
|
104
|
+
}
|
|
105
|
+
emit();
|
|
106
|
+
});
|
|
107
|
+
return [value, set];
|
|
108
|
+
}
|
|
109
|
+
var index_default = useQueryState;
|
|
110
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
111
|
+
0 && (module.exports = {
|
|
112
|
+
queryBoolean,
|
|
113
|
+
queryJson,
|
|
114
|
+
queryNumber,
|
|
115
|
+
queryString
|
|
116
|
+
});
|
|
@@ -17,11 +17,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
19
|
// src/useSafeState/index.ts
|
|
20
|
-
var
|
|
21
|
-
__export(
|
|
22
|
-
default: () =>
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
default: () => index_default
|
|
23
23
|
});
|
|
24
|
-
module.exports = __toCommonJS(
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
25
|
var import_react = require("react");
|
|
26
26
|
function useSafeState(initialState) {
|
|
27
27
|
const isMountedRef = (0, import_react.useRef)(true);
|
|
@@ -39,4 +39,4 @@ function useSafeState(initialState) {
|
|
|
39
39
|
}, []);
|
|
40
40
|
return [state, setSafeState];
|
|
41
41
|
}
|
|
42
|
-
var
|
|
42
|
+
var index_default = useSafeState;
|
|
@@ -27,11 +27,11 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
27
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
28
|
|
|
29
29
|
// src/useSyncState/index.ts
|
|
30
|
-
var
|
|
31
|
-
__export(
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
32
|
default: () => useSyncState
|
|
33
33
|
});
|
|
34
|
-
module.exports = __toCommonJS(
|
|
34
|
+
module.exports = __toCommonJS(index_exports);
|
|
35
35
|
var import_react = require("react");
|
|
36
36
|
var import_useEventCallback = __toESM(require("../useEventCallback"));
|
|
37
37
|
var UNINITIALIZED = Symbol("useSyncState.uninitialized");
|
|
@@ -17,11 +17,11 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
19
|
// src/useUpdateEffect/index.ts
|
|
20
|
-
var
|
|
21
|
-
__export(
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
22
|
default: () => useUpdateEffect
|
|
23
23
|
});
|
|
24
|
-
module.exports = __toCommonJS(
|
|
24
|
+
module.exports = __toCommonJS(index_exports);
|
|
25
25
|
var import_react = require("react");
|
|
26
26
|
function useUpdateEffect(effect, deps) {
|
|
27
27
|
const isMounted = (0, import_react.useRef)(false);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1money/hooks",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React hooks for 1money front-end projects",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"module": "es/index.js",
|
|
@@ -41,6 +41,11 @@
|
|
|
41
41
|
"import": "./es/useLayoutState/index.js",
|
|
42
42
|
"require": "./lib/useLayoutState/index.js"
|
|
43
43
|
},
|
|
44
|
+
"./useQueryState": {
|
|
45
|
+
"types": "./es/useQueryState/index.d.ts",
|
|
46
|
+
"import": "./es/useQueryState/index.js",
|
|
47
|
+
"require": "./lib/useQueryState/index.js"
|
|
48
|
+
},
|
|
44
49
|
"./useMemoizedFn": {
|
|
45
50
|
"types": "./es/useMemoizedFn/index.d.ts",
|
|
46
51
|
"import": "./es/useMemoizedFn/index.js",
|
|
@@ -89,29 +94,43 @@
|
|
|
89
94
|
},
|
|
90
95
|
"license": "MIT",
|
|
91
96
|
"devDependencies": {
|
|
92
|
-
"@eslint/js": "^9.
|
|
97
|
+
"@eslint/js": "^9.39.4",
|
|
93
98
|
"@testing-library/react": "^16.3.2",
|
|
94
|
-
"@
|
|
95
|
-
"@types/
|
|
96
|
-
"@types/node": "~18.19.86",
|
|
97
|
-
"@types/react": "~19.1.2",
|
|
99
|
+
"@types/node": "^20.19.0",
|
|
100
|
+
"@types/react": "^19.2.14",
|
|
98
101
|
"@types/react-dom": "^19.2.3",
|
|
99
|
-
"@typescript-eslint/eslint-plugin": "
|
|
100
|
-
"@typescript-eslint/parser": "
|
|
101
|
-
"eslint": "
|
|
102
|
-
"eslint-config-prettier": "
|
|
103
|
-
"eslint-plugin-prettier": "
|
|
102
|
+
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
|
103
|
+
"@typescript-eslint/parser": "^8.58.1",
|
|
104
|
+
"eslint": "^9.39.4",
|
|
105
|
+
"eslint-config-prettier": "^10.1.8",
|
|
106
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
104
107
|
"eslint-plugin-react": "~7.37.5",
|
|
105
|
-
"father": "^4.
|
|
108
|
+
"father": "^4.6.17",
|
|
106
109
|
"globals": "^15.15.0",
|
|
107
|
-
"
|
|
108
|
-
"jest-environment-jsdom": "^29.7.0",
|
|
109
|
-
"jsdom": "^29.0.0",
|
|
110
|
+
"jsdom": "^29.0.2",
|
|
110
111
|
"prettier": "~3.5.3",
|
|
111
112
|
"react": "^19.1.0",
|
|
112
113
|
"react-dom": "^19.2.4",
|
|
113
|
-
"ts-jest": "~29.2.6",
|
|
114
114
|
"typescript": "~5.5.4",
|
|
115
|
-
"
|
|
115
|
+
"vite": "^8.0.5",
|
|
116
|
+
"vitest": "^4.1.4"
|
|
117
|
+
},
|
|
118
|
+
"pnpm": {
|
|
119
|
+
"overrides": {
|
|
120
|
+
"@babel/runtime": "7.26.10",
|
|
121
|
+
"@eslint/plugin-kit": "0.3.4",
|
|
122
|
+
"@tootallnate/once": "3.0.1",
|
|
123
|
+
"ajv@6.12.6": "6.14.0",
|
|
124
|
+
"brace-expansion@2.0.2": "2.0.3",
|
|
125
|
+
"esbuild": "0.25.0",
|
|
126
|
+
"flatted": "3.4.2",
|
|
127
|
+
"lodash": "4.18.0",
|
|
128
|
+
"minimatch@3.0.8": "3.1.5",
|
|
129
|
+
"minimatch@3.1.2": "3.1.5",
|
|
130
|
+
"picomatch@2.3.1": "2.3.2",
|
|
131
|
+
"picomatch@4.0.3": "4.0.4",
|
|
132
|
+
"send": "0.19.0",
|
|
133
|
+
"yaml": "1.10.3"
|
|
134
|
+
}
|
|
116
135
|
}
|
|
117
136
|
}
|