@trackunit/react-components 3.8.2-alpha-0ef4e15e7c1.0 → 3.8.2-alpha-775ca1816d6.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/index.cjs.js +321 -801
- package/index.esm.js +322 -800
- package/package.json +6 -6
- package/src/hooks/persistence/usePersistedState.d.ts +31 -44
- package/src/hooks/persistence/useSearchParamSync.d.ts +7 -26
- package/src/hooks/persistence/useUrlParamSync.d.ts +71 -0
- package/src/index.d.ts +0 -1
- package/src/hooks/persistence/useHashParamSync.d.ts +0 -55
- package/src/hooks/persistence/useMigrateLegacySearchParam.d.ts +0 -62
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trackunit/react-components",
|
|
3
|
-
"version": "3.8.2-alpha-
|
|
3
|
+
"version": "3.8.2-alpha-775ca1816d6.0",
|
|
4
4
|
"repository": "https://github.com/Trackunit/manager",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"migrations": "./migrations.json",
|
|
@@ -14,16 +14,16 @@
|
|
|
14
14
|
"@floating-ui/react": "^0.26.25",
|
|
15
15
|
"string-ts": "^2.0.0",
|
|
16
16
|
"tailwind-merge": "^2.0.0",
|
|
17
|
-
"@trackunit/ui-design-tokens": "1.18.5-alpha-
|
|
18
|
-
"@trackunit/css-class-variance-utilities": "2.3.5-alpha-
|
|
19
|
-
"@trackunit/shared-utils": "1.19.5-alpha-
|
|
20
|
-
"@trackunit/ui-icons": "1.17.5-alpha-
|
|
17
|
+
"@trackunit/ui-design-tokens": "1.18.5-alpha-775ca1816d6.0",
|
|
18
|
+
"@trackunit/css-class-variance-utilities": "2.3.5-alpha-775ca1816d6.0",
|
|
19
|
+
"@trackunit/shared-utils": "1.19.5-alpha-775ca1816d6.0",
|
|
20
|
+
"@trackunit/ui-icons": "1.17.5-alpha-775ca1816d6.0",
|
|
21
21
|
"es-toolkit": "^1.52.0",
|
|
22
22
|
"@tanstack/react-virtual": "^3.14.13",
|
|
23
23
|
"dequal": "^2.0.3",
|
|
24
24
|
"fflate": "^0.8.3",
|
|
25
25
|
"zod": "^3.25.76",
|
|
26
|
-
"@trackunit/i18n-library-translation": "2.8.5-alpha-
|
|
26
|
+
"@trackunit/i18n-library-translation": "2.8.5-alpha-775ca1816d6.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"react": "^19.0.0",
|
|
@@ -1,24 +1,19 @@
|
|
|
1
|
+
import { type UrlParamLocation } from "./useUrlParamSync";
|
|
1
2
|
/**
|
|
2
3
|
* Selects which part of the URL backs the persisted state.
|
|
3
4
|
*
|
|
4
5
|
* - `"search"` (default): `?<key>=<encoded>`. Subject to the AWS WAF
|
|
5
|
-
* managed-rule cap (~5000 bytes) — large states
|
|
6
|
-
* truncated before they hit the browser bar.
|
|
6
|
+
* managed-rule cap (~5000 bytes) — large states are dropped from the URL.
|
|
7
7
|
* - `"hash"`: `#<key>=<encoded>`. Stays on the client, so the cap is
|
|
8
|
-
* driven only by browser URL limits.
|
|
9
|
-
* `usePersistedState` also performs a one-shot migration from any
|
|
10
|
-
* legacy `?<key>=...` value so previously shared links don't lose state.
|
|
8
|
+
* driven only by browser URL limits.
|
|
11
9
|
*/
|
|
12
|
-
export type UrlPersistenceLocation =
|
|
10
|
+
export type UrlPersistenceLocation = UrlParamLocation;
|
|
13
11
|
type UsePersistedStateOptions<TState> = {
|
|
14
12
|
readonly key: string;
|
|
15
13
|
readonly validate: (raw: unknown) => TState | undefined;
|
|
16
|
-
readonly serialize?: (state: TState) => string;
|
|
17
14
|
readonly toUrlValue?: (state: TState) => string | object | Array<object>;
|
|
18
15
|
readonly fromUrlValue?: (decoded: unknown) => unknown;
|
|
19
|
-
readonly enabled?: boolean;
|
|
20
16
|
readonly localStorageEnabled?: boolean;
|
|
21
|
-
readonly onExternalChange?: () => void;
|
|
22
17
|
readonly replace?: boolean;
|
|
23
18
|
readonly clientSideUserId?: string;
|
|
24
19
|
/**
|
|
@@ -30,8 +25,7 @@ type UsePersistedStateOptions<TState> = {
|
|
|
30
25
|
* (e.g. per-user layout details that shouldn't be shareable) so the
|
|
31
26
|
* omitted fields still survive reloads via localStorage.
|
|
32
27
|
*
|
|
33
|
-
* Default is `false
|
|
34
|
-
* fully replaces localStorage state on read.
|
|
28
|
+
* Default is `false`: URL state fully replaces localStorage state on read.
|
|
35
29
|
*/
|
|
36
30
|
readonly mergeWithStorageOnRead?: boolean;
|
|
37
31
|
/**
|
|
@@ -56,15 +50,16 @@ type UsePersistedStateOptions<TState> = {
|
|
|
56
50
|
};
|
|
57
51
|
type UsePersistedStateReturn<TState> = {
|
|
58
52
|
readonly initialState: TState | undefined;
|
|
53
|
+
/** Writes `state` to localStorage and the URL; each slot skips a value equal to its last write. */
|
|
59
54
|
readonly persistState: (state: TState) => void;
|
|
60
|
-
readonly clearState: () => void;
|
|
61
55
|
/**
|
|
62
|
-
* Writes
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
* the caller can retry. A no-op success returns `true`.
|
|
56
|
+
* Writes `state` to localStorage only; `undefined` removes the entry.
|
|
57
|
+
* Use together with `persistToUrl` when the two writes should not share a
|
|
58
|
+
* schedule — e.g. storage immediately, URL debounced.
|
|
66
59
|
*/
|
|
67
|
-
readonly
|
|
60
|
+
readonly persistToStorage: (state: TState | undefined) => void;
|
|
61
|
+
/** Writes `state` to the URL only; `undefined` removes the entry. */
|
|
62
|
+
readonly persistToUrl: (state: TState | undefined) => void;
|
|
68
63
|
};
|
|
69
64
|
/**
|
|
70
65
|
* Generic persistence hook that loads state from a URL slot (search param
|
|
@@ -72,47 +67,39 @@ type UsePersistedStateReturn<TState> = {
|
|
|
72
67
|
* and writes changes to both.
|
|
73
68
|
*
|
|
74
69
|
* On mount the hook resolves the initial state as follows:
|
|
75
|
-
* - If the
|
|
76
|
-
* value, decode it and pass through `validate`.
|
|
77
|
-
* - In `urlLocation: "hash"` mode, if the canonical hash slot has no valid
|
|
78
|
-
* value but a **legacy** `?<key>=...` search param is present, decode and
|
|
79
|
-
* validate that as a one-shot fallback. The value is copied into the hash
|
|
80
|
-
* and the search param is stripped via a `replace` navigation.
|
|
81
|
-
* - A value that comes only from localStorage is not written to the URL.
|
|
82
|
-
* Copying it on load left a layout in history, bookmarks, and login
|
|
83
|
-
* redirects, which then replayed an older layout over the saved one
|
|
84
|
-
* (GLU-2396). The URL is written when the user changes the state.
|
|
70
|
+
* - If the URL slot holds a value, decode it and pass through `validate`.
|
|
85
71
|
* - If localStorage is enabled, read and validate its value.
|
|
86
72
|
* - When `mergeWithStorageOnRead` is `false` (default): URL state wins
|
|
87
73
|
* entirely when present, otherwise fall back to localStorage.
|
|
88
74
|
* - When `mergeWithStorageOnRead` is `true`: shallow-merge URL fields over
|
|
89
75
|
* localStorage so fields stripped by `toUrlValue` survive via storage.
|
|
90
76
|
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
94
|
-
*
|
|
77
|
+
* A value that comes only from localStorage is never written to the URL on
|
|
78
|
+
* load. Copying it left a layout in history, bookmarks, and login redirects,
|
|
79
|
+
* which then replayed an older layout over the saved one (GLU-2396). The URL
|
|
80
|
+
* is written when the consumer persists a change.
|
|
95
81
|
*
|
|
96
|
-
* `
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
100
|
-
*
|
|
82
|
+
* `persistState` writes to localStorage (`storageSerializer`) and to the URL
|
|
83
|
+
* (via `toUrlValue` + encoding).
|
|
84
|
+
* Each slot skips a value deep-equal to its last write. The URL side starts
|
|
85
|
+
* from the hydrated state, so echoing `initialState` writes no URL entry. The
|
|
86
|
+
* storage side starts from what localStorage held, so a consumer that persists
|
|
87
|
+
* `initialState` after opening a link saves that link's state for the account
|
|
88
|
+
* that opened it, and a reload of the account's own link writes nothing.
|
|
89
|
+
* `persistToStorage` and `persistToUrl` are the same two halves exposed
|
|
90
|
+
* separately for consumers that schedule them differently; passing `undefined`
|
|
91
|
+
* removes the entry rather than writing an empty value.
|
|
101
92
|
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
* user has reset. It is idempotent — clearing an absent entry is a no-op.
|
|
93
|
+
* The snapshot is re-read when the storage key or the storage/merge options
|
|
94
|
+
* change, in the same render, so a write in that commit already sees the
|
|
95
|
+
* state for the new key.
|
|
106
96
|
*
|
|
107
97
|
* @param options - Configuration for the persisted state.
|
|
108
98
|
* @param options.key - Unique identifier used for both the URL slot and the localStorage key.
|
|
109
99
|
* @param options.validate - Called with the decoded/parsed value; must return `TState` or `undefined`.
|
|
110
|
-
* @param options.serialize - Custom localStorage serialiser (default `storageSerializer.serialize`).
|
|
111
100
|
* @param options.toUrlValue - Transform applied before URL encoding (default: encode state as-is).
|
|
112
101
|
* @param options.fromUrlValue - Transform applied after URL decoding, before validation (default: identity).
|
|
113
|
-
* @param options.enabled - When `false` the URL is neither read nor written (default `true`).
|
|
114
102
|
* @param options.localStorageEnabled - When `false` localStorage is neither read nor written (default `true`).
|
|
115
|
-
* @param options.onExternalChange - Fired when the URL value changes externally (e.g. browser back).
|
|
116
103
|
* @param options.replace - Forwarded to the underlying URL sync hook.
|
|
117
104
|
* @param options.clientSideUserId - The user ID to use for the localStorage key.
|
|
118
105
|
* @param options.mergeWithStorageOnRead - Merge URL state on top of localStorage
|
|
@@ -122,5 +109,5 @@ type UsePersistedStateReturn<TState> = {
|
|
|
122
109
|
* @param options.stampUrlWithIdentity - Stamp URL writes with the current identity so the login
|
|
123
110
|
* redirect can drop entries left by another account on this browser. Default `false`.
|
|
124
111
|
*/
|
|
125
|
-
export declare const usePersistedState: <TState extends object>({ key, validate,
|
|
112
|
+
export declare const usePersistedState: <TState extends object>({ key, validate, toUrlValue, fromUrlValue, localStorageEnabled, replace, clientSideUserId, mergeWithStorageOnRead, urlLocation, stampUrlWithIdentity, }: UsePersistedStateOptions<TState>) => UsePersistedStateReturn<TState>;
|
|
126
113
|
export {};
|
|
@@ -1,30 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* Sized to stay safely below the AWS WAF managed-rule default
|
|
6
|
-
* `SizeRestrictions_QUERYSTRING` cap of 5000 bytes for the entire url host + path + query + hash string
|
|
7
|
-
*/
|
|
8
|
-
export declare const MAX_URL_LENGTH = 5000;
|
|
9
|
-
type UseSearchParamSyncOptions = {
|
|
10
|
-
readonly key: string;
|
|
11
|
-
readonly enabled?: boolean;
|
|
12
|
-
readonly onExternalChange?: () => void;
|
|
13
|
-
readonly replace?: boolean;
|
|
14
|
-
};
|
|
15
|
-
type UseSearchParamSyncReturn = {
|
|
16
|
-
readonly searchValue: string | undefined;
|
|
17
|
-
readonly updateSearchParam: (encodedValue: string | undefined, options?: {
|
|
18
|
-
readonly replace?: boolean;
|
|
19
|
-
}) => void;
|
|
20
|
-
};
|
|
1
|
+
import { type UseUrlParamSyncOptions, type UseUrlParamSyncReturn } from "./useUrlParamSync";
|
|
2
|
+
export { MAX_URL_LENGTH } from "./useUrlParamSync";
|
|
3
|
+
type UseSearchParamSyncOptions = Omit<UseUrlParamSyncOptions, "location">;
|
|
21
4
|
/**
|
|
22
5
|
* Syncs an encoded string value with a URL search parameter via Tanstack Router.
|
|
23
6
|
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* back/forward, shared links) via an optional callback.
|
|
7
|
+
* Thin wrapper over {@link useUrlParamSync} with `location: "search"`; see it
|
|
8
|
+
* for the write queue, the size guard (`MAX_URL_LENGTH`), and external-change
|
|
9
|
+
* detection.
|
|
28
10
|
*
|
|
29
11
|
* @param options - Configuration for the search param sync.
|
|
30
12
|
* @param options.key - The URL search parameter name.
|
|
@@ -32,5 +14,4 @@ type UseSearchParamSyncReturn = {
|
|
|
32
14
|
* @param options.onExternalChange - Called when the param changes externally.
|
|
33
15
|
* @param options.replace - `true` to always use `replaceState`.
|
|
34
16
|
*/
|
|
35
|
-
export declare const useSearchParamSync: (
|
|
36
|
-
export {};
|
|
17
|
+
export declare const useSearchParamSync: (options: UseSearchParamSyncOptions) => UseUrlParamSyncReturn;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maximum full URL length after adding one persisted search param before the
|
|
3
|
+
* URL write is skipped (localStorage still persists the full state).
|
|
4
|
+
*
|
|
5
|
+
* Sized to stay safely below the AWS WAF managed-rule default
|
|
6
|
+
* `SizeRestrictions_QUERYSTRING` cap of 5000 bytes for the entire
|
|
7
|
+
* host + path + query + hash string.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MAX_URL_LENGTH = 5000;
|
|
10
|
+
/**
|
|
11
|
+
* Maximum length of the URL fragment after adding one persisted entry.
|
|
12
|
+
* Oversized new entries are skipped; oversized replacements remove the stale
|
|
13
|
+
* entry so localStorage remains authoritative.
|
|
14
|
+
*
|
|
15
|
+
* The fragment is never sent to the server, so the WAF cap above does not
|
|
16
|
+
* apply. 64 KB stays well below typical browser URL limits (Chromium ≳ 100 KB,
|
|
17
|
+
* Firefox ≳ 64 KB on the address bar) while leaving generous headroom for any
|
|
18
|
+
* realistic table state.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MAX_HASH_LENGTH: number;
|
|
21
|
+
/**
|
|
22
|
+
* Which part of the URL a persisted value lives in.
|
|
23
|
+
*
|
|
24
|
+
* - `"search"`: `?<key>=<encoded>`. Subject to the AWS WAF cap
|
|
25
|
+
* ({@link MAX_URL_LENGTH}); large states are dropped from the URL.
|
|
26
|
+
* - `"hash"`: `#<key>=<encoded>`. Client-only, capped by
|
|
27
|
+
* {@link MAX_HASH_LENGTH}.
|
|
28
|
+
*/
|
|
29
|
+
export type UrlParamLocation = "search" | "hash";
|
|
30
|
+
export type UseUrlParamSyncOptions = {
|
|
31
|
+
readonly key: string;
|
|
32
|
+
readonly location: UrlParamLocation;
|
|
33
|
+
readonly enabled?: boolean;
|
|
34
|
+
readonly onExternalChange?: () => void;
|
|
35
|
+
readonly replace?: boolean;
|
|
36
|
+
};
|
|
37
|
+
export type UseUrlParamSyncReturn = {
|
|
38
|
+
/** The raw encoded value currently in the URL slot, or `undefined` when absent or disabled. */
|
|
39
|
+
readonly searchValue: string | undefined;
|
|
40
|
+
/** Writes `encodedValue` into the URL slot; `undefined` removes the entry. */
|
|
41
|
+
readonly updateSearchParam: (encodedValue: string | undefined) => void;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Syncs an encoded string value with a single named entry in the URL — either
|
|
45
|
+
* a search param or an entry inside the hash fragment — via Tanstack Router.
|
|
46
|
+
*
|
|
47
|
+
* Writes go through the application router so other search params and
|
|
48
|
+
* foreign fragment content are preserved. Each slot has a size guard
|
|
49
|
+
* ({@link MAX_URL_LENGTH} for search, {@link MAX_HASH_LENGTH} for hash); an
|
|
50
|
+
* oversized value is dropped from the URL and localStorage stays
|
|
51
|
+
* authoritative. External changes to the entry (browser back/forward, a
|
|
52
|
+
* pasted link, a foreign router push) fire `onExternalChange`.
|
|
53
|
+
*
|
|
54
|
+
* Writes are dispatched via a pending-write queue rather than calling
|
|
55
|
+
* `navigate` directly. Tanstack Router's `router.state.status === "pending"`
|
|
56
|
+
* is common during the first paint of a route (loaders, suspense), and an
|
|
57
|
+
* implementation that simply returned in that case lost the write outright.
|
|
58
|
+
* `updateSearchParam` stores the latest attempted write and schedules an rAF
|
|
59
|
+
* flush; the flush only navigates when the router is idle, and an effect
|
|
60
|
+
* retries whenever the router settles. A queued write is dropped on unmount so
|
|
61
|
+
* it cannot drain onto the next route.
|
|
62
|
+
*
|
|
63
|
+
* @param options - Configuration for the URL entry sync.
|
|
64
|
+
* @param options.key - The search param name or fragment entry name.
|
|
65
|
+
* @param options.location - `"search"` or `"hash"`.
|
|
66
|
+
* @param options.enabled - Set to `false` to disable all URL interaction (default `true`).
|
|
67
|
+
* @param options.onExternalChange - Called when the entry changes externally.
|
|
68
|
+
* @param options.replace - `true` to always use `replaceState`; `false` to always push.
|
|
69
|
+
* Default: replace when the entry is being added, push when it already has a value.
|
|
70
|
+
*/
|
|
71
|
+
export declare const useUrlParamSync: ({ key, location: urlLocation, enabled, onExternalChange, replace: replaceOption, }: UseUrlParamSyncOptions) => UseUrlParamSyncReturn;
|
package/src/index.d.ts
CHANGED
|
@@ -126,7 +126,6 @@ export * from "./hooks/localStorage/useLocalStorageReducer";
|
|
|
126
126
|
export * from "./hooks/localStorage/useSessionStorage";
|
|
127
127
|
export * from "./hooks/localStorage/useSessionStorageReducer";
|
|
128
128
|
export * from "./hooks/noPagination";
|
|
129
|
-
export * from "./hooks/persistence/useHashParamSync";
|
|
130
129
|
export * from "./hooks/persistence/usePersistedState";
|
|
131
130
|
export * from "./hooks/persistence/useSearchParamSync";
|
|
132
131
|
export * from "./hooks/persistence/useStorageKey";
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Default maximum length of the resulting URL fragment after adding one
|
|
3
|
-
* persisted entry. Oversized new entries are skipped; oversized replacements
|
|
4
|
-
* remove the stale entry so localStorage remains authoritative.
|
|
5
|
-
*
|
|
6
|
-
* The fragment is never sent to the server, so it is not subject to the
|
|
7
|
-
* AWS WAF managed-rule `SizeRestrictions_QUERYSTRING` cap that applies to
|
|
8
|
-
* search params (5000 bytes). 64 KB stays well below typical browser URL
|
|
9
|
-
* limits (Chromium ≳ 100 KB, Firefox ≳ 64 KB on the address bar) while
|
|
10
|
-
* still leaving generous headroom for any realistic table state.
|
|
11
|
-
*/
|
|
12
|
-
export declare const MAX_HASH_LENGTH: number;
|
|
13
|
-
type UseHashParamSyncOptions = {
|
|
14
|
-
readonly key: string;
|
|
15
|
-
readonly enabled?: boolean;
|
|
16
|
-
readonly onExternalChange?: () => void;
|
|
17
|
-
readonly replace?: boolean;
|
|
18
|
-
};
|
|
19
|
-
type UseHashParamSyncReturn = {
|
|
20
|
-
/**
|
|
21
|
-
* Mirrors the field name on `useSearchParamSync` so this hook is a
|
|
22
|
-
* drop-in replacement when only the URL location changes (search ↔ hash).
|
|
23
|
-
* Despite the name, this value is read from `location.hash`.
|
|
24
|
-
*/
|
|
25
|
-
readonly searchValue: string | undefined;
|
|
26
|
-
/**
|
|
27
|
-
* Mirrors the function name on `useSearchParamSync`. Writes to
|
|
28
|
-
* `location.hash`, preserving any foreign fragment content untouched.
|
|
29
|
-
*/
|
|
30
|
-
readonly updateSearchParam: (encodedValue: string | undefined, options?: {
|
|
31
|
-
readonly replace?: boolean;
|
|
32
|
-
}) => void;
|
|
33
|
-
};
|
|
34
|
-
/**
|
|
35
|
-
* Syncs an encoded string value with a single named entry inside the URL
|
|
36
|
-
* fragment (`location.hash`) via Tanstack Router.
|
|
37
|
-
*
|
|
38
|
-
* Behaviour mirrors `useSearchParamSync`, with two differences:
|
|
39
|
-
* - Reads from and writes to `location.hash` instead of `location.search`.
|
|
40
|
-
* - Oversized replacements remove stale values using
|
|
41
|
-
* {@link MAX_HASH_LENGTH}, rather than the AWS-WAF-driven search-param cap.
|
|
42
|
-
*
|
|
43
|
-
* The fragment is treated as a sequence of `&`-separated tokens via the
|
|
44
|
-
* pure utilities in `./hashFragment`. Foreign tokens (bare anchors, other
|
|
45
|
-
* named entries) are preserved byte-for-byte on every write.
|
|
46
|
-
*
|
|
47
|
-
* @param options - Configuration for the hash entry sync.
|
|
48
|
-
* @param options.key - The named entry inside the fragment.
|
|
49
|
-
* @param options.enabled - Set to `false` to disable all URL interaction (default `true`).
|
|
50
|
-
* @param options.onExternalChange - Called when the entry changes externally
|
|
51
|
-
* (e.g. browser back/forward, pasted link, foreign router push).
|
|
52
|
-
* @param options.replace - `true` to always use `replaceState` instead of pushState.
|
|
53
|
-
*/
|
|
54
|
-
export declare const useHashParamSync: ({ key, enabled, onExternalChange, replace: replaceOption, }: UseHashParamSyncOptions) => UseHashParamSyncReturn;
|
|
55
|
-
export {};
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
type UseMigrateLegacySearchParamOptions<TState> = {
|
|
2
|
-
readonly key: string;
|
|
3
|
-
readonly enabled: boolean;
|
|
4
|
-
/**
|
|
5
|
-
* Pure decoder for the raw search-param string. Should not throw — return
|
|
6
|
-
* `undefined` when the input can't be decoded.
|
|
7
|
-
*/
|
|
8
|
-
readonly decode: (rawSearchValue: string) => unknown;
|
|
9
|
-
/**
|
|
10
|
-
* Optional transform applied to the decoded payload before validation
|
|
11
|
-
* (mirrors `usePersistedState`'s `fromUrlValue`).
|
|
12
|
-
*/
|
|
13
|
-
readonly fromUrlValue?: (decoded: unknown) => unknown;
|
|
14
|
-
/**
|
|
15
|
-
* Schema validator. Return the parsed state on success, `undefined`
|
|
16
|
-
* otherwise.
|
|
17
|
-
*/
|
|
18
|
-
readonly validate: (raw: unknown) => TState | undefined;
|
|
19
|
-
/**
|
|
20
|
-
* When `true`, the hash already carries a valid value for this key. The
|
|
21
|
-
* hook still strips the legacy search param (so the URL is clean) but
|
|
22
|
-
* does NOT fire `onMigrated` — the hash is canonical and we must not
|
|
23
|
-
* stomp on it.
|
|
24
|
-
*/
|
|
25
|
-
readonly hashAlreadyHasValue: boolean;
|
|
26
|
-
/**
|
|
27
|
-
* Called at most once when a valid legacy search-param value is found
|
|
28
|
-
* and the hash is currently empty. Pipe through your normal
|
|
29
|
-
* `persistState` so the value ends up in both the hash and localStorage.
|
|
30
|
-
*/
|
|
31
|
-
readonly onMigrated: (state: TState) => void;
|
|
32
|
-
};
|
|
33
|
-
/**
|
|
34
|
-
* One-shot migration: if the URL still carries a legacy `?<key>=...`
|
|
35
|
-
* search param from before this hook moved table-style state to the
|
|
36
|
-
* fragment, decode it, hand it to the caller via `onMigrated`, then strip
|
|
37
|
-
* the search param via a `replace` navigation so back/forward history
|
|
38
|
-
* isn't polluted.
|
|
39
|
-
*
|
|
40
|
-
* Invariants:
|
|
41
|
-
* - The strip navigation fires at most once per mount (guarded by
|
|
42
|
-
* `hasStrippedRef`) so we don't loop on the navigation we ourselves
|
|
43
|
-
* triggered.
|
|
44
|
-
* - `onMigrated` is also fired at most once per mount (guarded by
|
|
45
|
-
* `hasMigratedRef`), but its gating is independent of the strip:
|
|
46
|
-
* if `hashAlreadyHasValue` flips `true → false` after the strip
|
|
47
|
-
* (e.g. an external actor clears the canonical hash mid-mount), the
|
|
48
|
-
* next render still gets a chance to migrate the legacy value into
|
|
49
|
-
* the hash. Conflating the two flags would have permanently lost
|
|
50
|
-
* the legacy state in that race.
|
|
51
|
-
* - Never throws — a decode/validate failure silently drops the value
|
|
52
|
-
* and still strips the search param. The legacy key is owned by this
|
|
53
|
-
* codebase's persistence convention (camelCase + `Tp` suffix), so
|
|
54
|
-
* stripping unparseable values cannot destroy third-party data.
|
|
55
|
-
* - When `hashAlreadyHasValue` is `true` the hash wins: the search
|
|
56
|
-
* param is stripped but `onMigrated` is not fired.
|
|
57
|
-
* - The `location.hash` is preserved verbatim across the strip
|
|
58
|
-
* navigation so any concurrent hash content (including a freshly
|
|
59
|
-
* written value) survives the cleanup.
|
|
60
|
-
*/
|
|
61
|
-
export declare const useMigrateLegacySearchParam: <TState>({ key, enabled, decode, fromUrlValue, validate, hashAlreadyHasValue, onMigrated, }: UseMigrateLegacySearchParamOptions<TState>) => void;
|
|
62
|
-
export {};
|