state-in-url 0.1.4 → 0.1.6
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/README.md +1 -0
- package/dist/index.js +1 -1
- package/dist/{packages/urlstate → urlstate}/constants.d.ts +1 -0
- package/dist/{packages/urlstate → urlstate}/encodeState.d.ts +2 -2
- package/dist/urlstate/encoder.d.ts +27 -0
- package/dist/urlstate/useUrlEncode.d.ts +25 -0
- package/dist/urlstate/useUrlState.d.ts +56 -0
- package/dist/{packages/urlstate → urlstate}/utils.d.ts +3 -0
- package/package.json +2 -1
- package/dist/packages/urlstate/encodeState.test.d.ts +0 -1
- package/dist/packages/urlstate/encoder.d.ts +0 -14
- package/dist/packages/urlstate/encoder.test.d.ts +0 -1
- package/dist/packages/urlstate/useUrlEncode.d.ts +0 -23
- package/dist/packages/urlstate/useUrlEncode.test.d.ts +0 -1
- package/dist/packages/urlstate/useUrlState.d.ts +0 -42
- package/dist/packages/urlstate/utils.test.d.ts +0 -1
- package/dist/tests/smoke-test.spec.d.ts +0 -1
- /package/dist/{packages/index.d.ts → index.d.ts} +0 -0
- /package/dist/{packages/urlstate → urlstate}/index.d.ts +0 -0
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import t from"react";import{useRouter as n,usePathname as e,useSearchParams as r}from"next/navigation";const o=t=>{const n=null===t,e=Array.isArray(t),r=t instanceof Date;return(n?"null":r&&"date")||e&&"array"||!n&&!r&&!e&&"object"==typeof t&&"object"||typeof t},s=t=>new URLSearchParams("string"==typeof t?t:t?.toString?.()||""),a={string:"◖",boolean:"🗵",null:"∙null",undefined:"∙undefined",number:"∓",date:"⏲"};function c(t){switch(o(t)){case"function":case"symbol":return"";case"date":return a.date+t.toISOString();case"string":return t.match(/^◖/)?encodeURIComponent(t):`${a.string}${encodeURIComponent(t)}`;case"number":return a.number+String(t);case"boolean":return a.boolean+String(t);case"object":case"array":return u(t);case"null":return a.null;case"undefined":return a.undefined;default:return String(t)}}const u=t=>JSON.stringify(t,i).replaceAll('"',"'"),i=(t,n)=>{const e=o(n);return t&&"object"!==e&&"array"!==e?c(n):n},l=t=>t===a.null?null:t!==a.undefined?t.startsWith(a.number)?Number.parseFloat(t.replace(a.number,"")):t.startsWith(a.boolean)?!!t.includes("true"):t.startsWith(a.date)?new Date(t.slice(1)):t.startsWith(a.string)?decodeURIComponent(t).replace(/^◖/,""):f:void 0,f=Symbol("isError"),p=(t,n)=>{const e="string"==typeof n,r=e&&l(n);return r===f?n:t&&e?r:n};function d(t,n){return function(t,n){try{return JSON.parse(t,p)}catch{const e=l(t);return e!==f?e:n}}(t.replaceAll("'",'"'),n)}function b(t,n,e){const r=s(e);return Object.entries(t||{}).forEach((([t,e])=>{const o=n?.[t];JSON.stringify(e)!==JSON.stringify(o)&&r.set(t,c(e))})),r.toString()}function g(t,n){return{...n||{},...Object.fromEntries([...s(t).entries()].map((([t,e])=>{const r=n?.[t];return[t,d(e,r)??r]})))}}function y(n){const e=t.useCallback((function(t,e){return"object"===o(t)?b(t,n,e):""}),[n]);return{parse:t.useCallback((function(t){return g(t,n)}),[n]),stringify:e}}function m(o){const s=n(),a=e(),{parse:c,stringify:u}=y(o),i=r(),[l,f]=t.useState((()=>c(i)));t.useEffect((()=>{f((t=>{const n=c(i);return JSON.stringify(t)===JSON.stringify(n)?t:n}))}),[c,i]);const p=t.useCallback((t=>{f("function"==typeof t?n=>t(n):t)}),[]);return{updateUrl:t.useCallback(((t,n)=>{const e=i.toString(),r=`${a}${e.length?"?":""}${e}`,o=u("function"==typeof t?t(l):t),c=`${a}${o.length?"?":""}${o}`;if(r!==c){const{replace:t,...e}=n||{};s[t?"replace":"push"](c,{scroll:!1,...e})}}),[a,s,u,i,l]),updateState:p,state:l}}export{d as decode,g as decodeState,c as encode,b as encodeState,y as useUrlEncode,m as useUrlState};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type JSONCompatible } from './utils';
|
|
1
|
+
import { type JSONCompatible, type UnknownObj } from './utils';
|
|
2
2
|
/**
|
|
3
3
|
* Encodes the state object into a URL query string.
|
|
4
4
|
*
|
|
@@ -25,4 +25,4 @@ export declare function encodeState<T>(state: never extends T ? object : JSONCom
|
|
|
25
25
|
* decodeState('key=value&name=Alex', form);
|
|
26
26
|
* ```
|
|
27
27
|
*/
|
|
28
|
-
export declare function decodeState<T>(uriString: string | URLSearchParams, defaults?:
|
|
28
|
+
export declare function decodeState<T>(uriString: string | URLSearchParams, defaults?: JSONCompatible<T>): undefined extends T ? UnknownObj : T;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Encode any JSON serializable value to URL friendly string
|
|
3
|
+
*
|
|
4
|
+
* @param {unknown} payload any value to serialize
|
|
5
|
+
* @returns {string} URLSearchParams compatible value string
|
|
6
|
+
*/
|
|
7
|
+
export declare function encode(payload: unknown): string;
|
|
8
|
+
type Primitive = Exclude<ReturnType<typeof decodePrimitive>, typeof errorSym>;
|
|
9
|
+
export declare const decodePrimitive: (str: string) => string | number | boolean | Date | typeof errorSym | null | undefined;
|
|
10
|
+
export declare const errorSym: unique symbol;
|
|
11
|
+
/**
|
|
12
|
+
* Parses a JSON string into a TypeScript object.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} jsonString - The JSON string to parse.
|
|
15
|
+
* @param {T} [fallbackValue] - The fallback value to use if parsing fails.
|
|
16
|
+
* @return {T | Primitive | undefined} - The parsed object or a primitive value, or undefined if parsing fails.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parseJSON<T>(jsonString: string, fallbackValue?: T): T | Primitive | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Decode value part of URLSearchParams back to JS value
|
|
21
|
+
*
|
|
22
|
+
* @param {string} payload URLSearchParams compatible value string
|
|
23
|
+
* @param {any} fallback optional fallback value
|
|
24
|
+
* @returns {unknown} decoded object
|
|
25
|
+
*/
|
|
26
|
+
export declare function decode<T>(payload: string, fallback?: T): Primitive | T;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type JSONCompatible, type DeepReadonly } from './utils';
|
|
2
|
+
/**
|
|
3
|
+
* A hook that returns stringify and parse functions for encoding and decoding state
|
|
4
|
+
* to and from URL search parameters.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The type of the state shape
|
|
7
|
+
* @param {JSONCompatible<T>} [stateShape] Optional fallback values for state
|
|
8
|
+
* @returns {} `stringify` and `parse` functions
|
|
9
|
+
*
|
|
10
|
+
* * Example:
|
|
11
|
+
* ```ts
|
|
12
|
+
* export const form = { name: '' };
|
|
13
|
+
* const { parse, stringify } = useUrlEncode(form);
|
|
14
|
+
*
|
|
15
|
+
* stringify({ name: 'John' }, 'someExistingParamToKeep=123');
|
|
16
|
+
* // by default it's uses router.push with scroll: false
|
|
17
|
+
* parse('name=Tom');
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function useUrlEncode<T>(stateShape?: JSONCompatible<T>): {
|
|
21
|
+
parse: (strOrSearchParams: string | URLSearchParams) => undefined extends T ? Readonly<{
|
|
22
|
+
readonly [x: string]: Readonly<{}>;
|
|
23
|
+
}> : Readonly<JSONCompatible<T> & {} extends infer T ? { readonly [P in keyof T]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_1 ? { readonly [P_1 in keyof T_1]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_2 ? { readonly [P_2 in keyof T_2]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_3 ? { readonly [P_3 in keyof T_3]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_4 ? { readonly [P_4 in keyof T_4]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { readonly [P_5 in keyof T_5]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { readonly [P_6 in keyof T_6]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { readonly [P_7 in keyof T_7]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { readonly [P_8 in keyof T_8]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { readonly [P_9 in keyof T_9]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { readonly [P_10 in keyof T_10]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>;
|
|
24
|
+
stringify: (state: typeof stateShape | NonNullable<typeof stateShape> | DeepReadonly<NonNullable<typeof stateShape>>, paramsToKeep?: string | URLSearchParams) => string;
|
|
25
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useRouter } from 'next/navigation';
|
|
2
|
+
import { type JSONCompatible } from './utils';
|
|
3
|
+
/**
|
|
4
|
+
* NextJS hook. Returns `state`, `updateState`, and `updateUrl` functions
|
|
5
|
+
*
|
|
6
|
+
* @param {?JSONCompatible<T>} [defaultState] Optional fallback values for state
|
|
7
|
+
*
|
|
8
|
+
* * Example:
|
|
9
|
+
* ```ts
|
|
10
|
+
* export const form = { name: '' };
|
|
11
|
+
* const { state, updateState, updateUrl } = useUrlState(form);
|
|
12
|
+
*
|
|
13
|
+
* updateState({ name: 'test' });
|
|
14
|
+
* // by default it's uses router.push with scroll: false
|
|
15
|
+
* updateUrl({ name: 'test' }, { replace: true, scroll: true });
|
|
16
|
+
* ```
|
|
17
|
+
* * Auto update URL
|
|
18
|
+
* ```ts
|
|
19
|
+
* const timer = React.useRef(0 as unknown as NodeJS.Timeout);
|
|
20
|
+
* React.useEffect(() => {
|
|
21
|
+
* clearTimeout(timer.current);
|
|
22
|
+
* timer.current = setTimeout(() => {
|
|
23
|
+
* updateUrl(state);
|
|
24
|
+
* }, 500);
|
|
25
|
+
*
|
|
26
|
+
* return () => {
|
|
27
|
+
* clearTimeout(timer.current);
|
|
28
|
+
* };
|
|
29
|
+
* }, [state, updateUrl]);
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export declare function useUrlState<T>(defaultState?: JSONCompatible<T>): {
|
|
33
|
+
updateUrl: (value: (undefined extends T ? Readonly<{
|
|
34
|
+
readonly [x: string]: Readonly<{}>;
|
|
35
|
+
}> : Readonly<JSONCompatible<T> & {} extends infer T ? { readonly [P in keyof T]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_1 ? { readonly [P_1 in keyof T_1]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_2 ? { readonly [P_2 in keyof T_2]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_3 ? { readonly [P_3 in keyof T_3]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_4 ? { readonly [P_4 in keyof T_4]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { readonly [P_5 in keyof T_5]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { readonly [P_6 in keyof T_6]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { readonly [P_7 in keyof T_7]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { readonly [P_8 in keyof T_8]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { readonly [P_9 in keyof T_9]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { readonly [P_10 in keyof T_10]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>) | ((currState: undefined extends T ? Readonly<{
|
|
36
|
+
readonly [x: string]: Readonly<{}>;
|
|
37
|
+
}> : Readonly<JSONCompatible<T> & {} extends infer T ? { readonly [P in keyof T]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_1 ? { readonly [P_1 in keyof T_1]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_2 ? { readonly [P_2 in keyof T_2]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_3 ? { readonly [P_3 in keyof T_3]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_4 ? { readonly [P_4 in keyof T_4]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { readonly [P_5 in keyof T_5]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { readonly [P_6 in keyof T_6]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { readonly [P_7 in keyof T_7]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { readonly [P_8 in keyof T_8]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { readonly [P_9 in keyof T_9]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { readonly [P_10 in keyof T_10]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>) => undefined extends T ? Readonly<{
|
|
38
|
+
readonly [x: string]: Readonly<{}>;
|
|
39
|
+
}> : Readonly<JSONCompatible<T> & {} extends infer T ? { readonly [P in keyof T]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_1 ? { readonly [P_1 in keyof T_1]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_2 ? { readonly [P_2 in keyof T_2]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_3 ? { readonly [P_3 in keyof T_3]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_4 ? { readonly [P_4 in keyof T_4]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { readonly [P_5 in keyof T_5]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { readonly [P_6 in keyof T_6]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { readonly [P_7 in keyof T_7]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { readonly [P_8 in keyof T_8]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { readonly [P_9 in keyof T_9]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { readonly [P_10 in keyof T_10]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>), options?: Options) => void;
|
|
40
|
+
updateState: (value: (undefined extends T ? Readonly<{
|
|
41
|
+
readonly [x: string]: Readonly<{}>;
|
|
42
|
+
}> : Readonly<JSONCompatible<T> & {} extends infer T_11 ? { readonly [P in keyof T_11]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_12 ? { readonly [P_1 in keyof T_12]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_13 ? { readonly [P_2 in keyof T_13]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_14 ? { readonly [P_3 in keyof T_14]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_15 ? { readonly [P_4 in keyof T_15]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_16 ? { readonly [P_5 in keyof T_16]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_17 ? { readonly [P_6 in keyof T_17]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_18 ? { readonly [P_7 in keyof T_18]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_19 ? { readonly [P_8 in keyof T_19]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_20 ? { readonly [P_9 in keyof T_20]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_21 ? { readonly [P_10 in keyof T_21]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>) | ((currState: undefined extends T ? Readonly<{
|
|
43
|
+
readonly [x: string]: Readonly<{}>;
|
|
44
|
+
}> : Readonly<JSONCompatible<T> & {} extends infer T_11 ? { readonly [P in keyof T_11]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_12 ? { readonly [P_1 in keyof T_12]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_13 ? { readonly [P_2 in keyof T_13]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_14 ? { readonly [P_3 in keyof T_14]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_15 ? { readonly [P_4 in keyof T_15]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_16 ? { readonly [P_5 in keyof T_16]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_17 ? { readonly [P_6 in keyof T_17]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_18 ? { readonly [P_7 in keyof T_18]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_19 ? { readonly [P_8 in keyof T_19]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_20 ? { readonly [P_9 in keyof T_20]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_21 ? { readonly [P_10 in keyof T_21]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>) => undefined extends T ? Readonly<{
|
|
45
|
+
readonly [x: string]: Readonly<{}>;
|
|
46
|
+
}> : Readonly<JSONCompatible<T> & {} extends infer T_11 ? { readonly [P in keyof T_11]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_12 ? { readonly [P_1 in keyof T_12]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_13 ? { readonly [P_2 in keyof T_13]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_14 ? { readonly [P_3 in keyof T_14]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_15 ? { readonly [P_4 in keyof T_15]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_16 ? { readonly [P_5 in keyof T_16]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_17 ? { readonly [P_6 in keyof T_17]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_18 ? { readonly [P_7 in keyof T_18]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_19 ? { readonly [P_8 in keyof T_19]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_20 ? { readonly [P_9 in keyof T_20]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_21 ? { readonly [P_10 in keyof T_21]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>)) => void;
|
|
47
|
+
state: undefined extends T ? Readonly<{
|
|
48
|
+
readonly [x: string]: Readonly<{}>;
|
|
49
|
+
}> : Readonly<JSONCompatible<T> & {} extends infer T_22 ? { readonly [P in keyof T_22]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_23 ? { readonly [P_1 in keyof T_23]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_24 ? { readonly [P_2 in keyof T_24]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_25 ? { readonly [P_3 in keyof T_25]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_26 ? { readonly [P_4 in keyof T_26]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_27 ? { readonly [P_5 in keyof T_27]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_28 ? { readonly [P_6 in keyof T_28]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_29 ? { readonly [P_7 in keyof T_29]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_30 ? { readonly [P_8 in keyof T_30]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_31 ? { readonly [P_9 in keyof T_31]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_32 ? { readonly [P_10 in keyof T_32]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>;
|
|
50
|
+
};
|
|
51
|
+
type Router = ReturnType<typeof useRouter>;
|
|
52
|
+
type RouterOptions = NonNullable<Parameters<Router['push']>[1]>;
|
|
53
|
+
interface Options extends RouterOptions {
|
|
54
|
+
replace?: boolean;
|
|
55
|
+
}
|
|
56
|
+
export {};
|
|
@@ -20,4 +20,7 @@ export type DeepReadonly<T> = Readonly<{
|
|
|
20
20
|
readonly [P in keyof T]: DeepReadonly<T[P]>;
|
|
21
21
|
}>;
|
|
22
22
|
export declare const getParams: (strOrSearchParams?: string | URLSearchParams) => URLSearchParams;
|
|
23
|
+
export type UnknownObj = {
|
|
24
|
+
[key: string]: unknown;
|
|
25
|
+
};
|
|
23
26
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "state-in-url",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Library to store state in browser URL, includes hook for NextJS, hook for pure React, and low level helpers.",
|
|
5
5
|
"homepage": "https://github.com/asmyshlyaev177/state-in-url#readme",
|
|
6
6
|
"keywords": [
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"start:demo": "cd packages/example-nextjs && npm run build && npx serve -s ./out",
|
|
80
80
|
"cleanup": "rm -rf dist",
|
|
81
81
|
"setup": "playwright install --with-deps",
|
|
82
|
+
"cleanupDist": "wireit",
|
|
82
83
|
"prepare": "npx husky"
|
|
83
84
|
},
|
|
84
85
|
"wireit": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Encode any JSON serializable value to URL friendly string
|
|
3
|
-
*
|
|
4
|
-
* @param {unknown} payload any value to serialize
|
|
5
|
-
* @returns {string} URLSearchParams compatible value string
|
|
6
|
-
*/
|
|
7
|
-
export declare function encode(payload: unknown): string;
|
|
8
|
-
/**
|
|
9
|
-
* Decode value part of URLSearchParams back to JS value
|
|
10
|
-
*
|
|
11
|
-
* @param {string} payload URLSearchParams compatible value string
|
|
12
|
-
* @returns {unknown} decoded object
|
|
13
|
-
*/
|
|
14
|
-
export declare function decode<T>(payload: string): T;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { type JSONCompatible, type DeepReadonly } from './utils';
|
|
2
|
-
/**
|
|
3
|
-
* A hook that returns stringify and parse functions for encoding and decoding state
|
|
4
|
-
* to and from URL search parameters.
|
|
5
|
-
*
|
|
6
|
-
* @template T - The type of the state shape
|
|
7
|
-
* @param {JSONCompatible<T>} [stateShape] Optional fallback values for state
|
|
8
|
-
* @returns {} `stringify` and `parse` functions
|
|
9
|
-
*
|
|
10
|
-
* * Example:
|
|
11
|
-
* ```ts
|
|
12
|
-
* export const form = { name: '' };
|
|
13
|
-
* const { parse, stringify } = useUrlEncode(form);
|
|
14
|
-
*
|
|
15
|
-
* stringify({ name: 'John' }, 'someExistingParamToKeep=123');
|
|
16
|
-
* // by default it's uses router.push with scroll: false
|
|
17
|
-
* parse('name=Tom');
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
export declare function useUrlEncode<T>(stateShape?: JSONCompatible<T>): {
|
|
21
|
-
parse: (strOrSearchParams: string | URLSearchParams) => Readonly<JSONCompatible<T> & {} extends infer T ? { readonly [P in keyof T]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_1 ? { readonly [P_1 in keyof T_1]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_2 ? { readonly [P_2 in keyof T_2]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_3 ? { readonly [P_3 in keyof T_3]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_4 ? { readonly [P_4 in keyof T_4]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { readonly [P_5 in keyof T_5]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { readonly [P_6 in keyof T_6]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { readonly [P_7 in keyof T_7]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { readonly [P_8 in keyof T_8]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { readonly [P_9 in keyof T_9]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { readonly [P_10 in keyof T_10]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>;
|
|
22
|
-
stringify: (state: DeepReadonly<NonNullable<typeof stateShape>> | NonNullable<typeof stateShape>, paramsToKeep?: string | URLSearchParams) => string;
|
|
23
|
-
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { useRouter } from 'next/navigation';
|
|
2
|
-
import { type JSONCompatible } from './utils';
|
|
3
|
-
/**
|
|
4
|
-
* NextJS hook. Returns `state`, `updateState`, and `updateUrl` functions
|
|
5
|
-
*
|
|
6
|
-
* @param {?JSONCompatible<T>} [defaultState] Optional fallback values for state
|
|
7
|
-
*
|
|
8
|
-
* * Example:
|
|
9
|
-
* ```ts
|
|
10
|
-
* export const form = { name: '' };
|
|
11
|
-
* const { state, updateState, updateUrl } = useUrlState(form);
|
|
12
|
-
*
|
|
13
|
-
* updateState({ name: 'test' });
|
|
14
|
-
* // by default it's uses router.push with scroll: false
|
|
15
|
-
* updateUrl({ name: 'test' }, { replace: true, scroll: true });
|
|
16
|
-
* ```
|
|
17
|
-
* * Auto update URL
|
|
18
|
-
* ```ts
|
|
19
|
-
* const timer = React.useRef(0 as unknown as NodeJS.Timeout);
|
|
20
|
-
* React.useEffect(() => {
|
|
21
|
-
* clearTimeout(timer.current);
|
|
22
|
-
* timer.current = setTimeout(() => {
|
|
23
|
-
* updateUrl(state);
|
|
24
|
-
* }, 500);
|
|
25
|
-
*
|
|
26
|
-
* return () => {
|
|
27
|
-
* clearTimeout(timer.current);
|
|
28
|
-
* };
|
|
29
|
-
* }, [state, updateUrl]);
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export declare function useUrlState<T>(defaultState?: JSONCompatible<T>): {
|
|
33
|
-
updateUrl: (value: Readonly<JSONCompatible<T> & {} extends infer T ? { readonly [P in keyof T]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_1 ? { readonly [P_1 in keyof T_1]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_2 ? { readonly [P_2 in keyof T_2]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_3 ? { readonly [P_3 in keyof T_3]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_4 ? { readonly [P_4 in keyof T_4]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { readonly [P_5 in keyof T_5]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { readonly [P_6 in keyof T_6]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { readonly [P_7 in keyof T_7]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { readonly [P_8 in keyof T_8]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { readonly [P_9 in keyof T_9]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { readonly [P_10 in keyof T_10]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never> | ((currState: Readonly<JSONCompatible<T> & {} extends infer T ? { readonly [P in keyof T]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_1 ? { readonly [P_1 in keyof T_1]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_2 ? { readonly [P_2 in keyof T_2]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_3 ? { readonly [P_3 in keyof T_3]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_4 ? { readonly [P_4 in keyof T_4]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { readonly [P_5 in keyof T_5]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { readonly [P_6 in keyof T_6]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { readonly [P_7 in keyof T_7]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { readonly [P_8 in keyof T_8]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { readonly [P_9 in keyof T_9]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { readonly [P_10 in keyof T_10]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>) => Readonly<JSONCompatible<T> & {} extends infer T ? { readonly [P in keyof T]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_1 ? { readonly [P_1 in keyof T_1]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_2 ? { readonly [P_2 in keyof T_2]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_3 ? { readonly [P_3 in keyof T_3]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_4 ? { readonly [P_4 in keyof T_4]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_5 ? { readonly [P_5 in keyof T_5]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_6 ? { readonly [P_6 in keyof T_6]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_7 ? { readonly [P_7 in keyof T_7]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_8 ? { readonly [P_8 in keyof T_8]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_9 ? { readonly [P_9 in keyof T_9]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_10 ? { readonly [P_10 in keyof T_10]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>), options?: Options) => void;
|
|
34
|
-
updateState: (value: Readonly<JSONCompatible<T> & {} extends infer T_11 ? { readonly [P in keyof T_11]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_12 ? { readonly [P_1 in keyof T_12]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_13 ? { readonly [P_2 in keyof T_13]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_14 ? { readonly [P_3 in keyof T_14]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_15 ? { readonly [P_4 in keyof T_15]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_16 ? { readonly [P_5 in keyof T_16]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_17 ? { readonly [P_6 in keyof T_17]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_18 ? { readonly [P_7 in keyof T_18]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_19 ? { readonly [P_8 in keyof T_19]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_20 ? { readonly [P_9 in keyof T_20]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_21 ? { readonly [P_10 in keyof T_21]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never> | ((currState: Readonly<JSONCompatible<T> & {} extends infer T_11 ? { readonly [P in keyof T_11]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_12 ? { readonly [P_1 in keyof T_12]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_13 ? { readonly [P_2 in keyof T_13]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_14 ? { readonly [P_3 in keyof T_14]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_15 ? { readonly [P_4 in keyof T_15]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_16 ? { readonly [P_5 in keyof T_16]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_17 ? { readonly [P_6 in keyof T_17]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_18 ? { readonly [P_7 in keyof T_18]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_19 ? { readonly [P_8 in keyof T_19]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_20 ? { readonly [P_9 in keyof T_20]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_21 ? { readonly [P_10 in keyof T_21]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>) => Readonly<JSONCompatible<T> & {} extends infer T_11 ? { readonly [P in keyof T_11]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_12 ? { readonly [P_1 in keyof T_12]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_13 ? { readonly [P_2 in keyof T_13]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_14 ? { readonly [P_3 in keyof T_14]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_15 ? { readonly [P_4 in keyof T_15]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_16 ? { readonly [P_5 in keyof T_16]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_17 ? { readonly [P_6 in keyof T_17]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_18 ? { readonly [P_7 in keyof T_18]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_19 ? { readonly [P_8 in keyof T_19]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_20 ? { readonly [P_9 in keyof T_20]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_21 ? { readonly [P_10 in keyof T_21]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>)) => void;
|
|
35
|
-
state: Readonly<JSONCompatible<T> & {} extends infer T_22 ? { readonly [P in keyof T_22]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_23 ? { readonly [P_1 in keyof T_23]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_24 ? { readonly [P_2 in keyof T_24]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_25 ? { readonly [P_3 in keyof T_25]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_26 ? { readonly [P_4 in keyof T_26]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_27 ? { readonly [P_5 in keyof T_27]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_28 ? { readonly [P_6 in keyof T_28]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_29 ? { readonly [P_7 in keyof T_29]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_30 ? { readonly [P_8 in keyof T_30]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_31 ? { readonly [P_9 in keyof T_31]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8][P_9] extends infer T_32 ? { readonly [P_10 in keyof T_32]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>;
|
|
36
|
-
};
|
|
37
|
-
type Router = ReturnType<typeof useRouter>;
|
|
38
|
-
type RouterOptions = NonNullable<Parameters<Router['push']>[1]>;
|
|
39
|
-
interface Options extends RouterOptions {
|
|
40
|
-
replace?: boolean;
|
|
41
|
-
}
|
|
42
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
File without changes
|
|
File without changes
|