state-in-url 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,12 +1,16 @@
1
1
 
2
2
  <h1 align="center">state-in-url</h1>
3
3
 
4
+
4
5
  <p align="center">
5
6
  <img src="/assets/logo.svg?raw=true" alt="Library logo"/>
6
7
  </p>
7
8
 
8
9
  <div align="center">
9
- Seamlessly sync React state with URL query parameters in Next.js/React.js applications. Simplify state management, enhance shareability, and maintain type safety—all through your browser's URL.
10
+ Seamlessly store complex React state object in URL query parameters without losing types. Works with Next.js/React.js applications.
11
+
12
+ <h4 align="center">Don't hesitate to open issue if you found a bug</h4>
13
+
10
14
 
11
15
  <a href="https://state-in-url-wine.vercel.app" target="_blank">DEMO</a>
12
16
 
@@ -39,9 +43,10 @@ Add a ⭐️ to support the project!
39
43
 
40
44
  ## Table of content
41
45
  - [Installation](#installation)
42
- - [Usage with Next.js](#useurlstate-hook-for-nextjs)
43
- - [Usage with React.js](#useurlencode-hook-for-reactjs)
44
- - [Low-level encode/decode functions](#encode-and-decode-helpers)
46
+ - [`useUrlState` for Next.js](#useurlstate-hook-for-nextjs)
47
+ - [`useUrlEncode` for React.js](#useurlencode-hook-for-reactjs)
48
+ - [`encodeState` and `decodeState` for pure JS usage](#encodestate-and-decodestate-helpers)
49
+ - [Low-level `encode` and `decode` functions](#encode-and-decode-helpers)
45
50
  - [Gothas](#gothas)
46
51
  - [Contact & Support](#contact--support)
47
52
  - [Changelog](#changelog)
@@ -59,7 +64,7 @@ pnpm add state-in-url
59
64
  ```
60
65
 
61
66
  ## Run locally
62
- Clone this repo, run `npm install` and
67
+ Clone this repo, run `npm install` and
63
68
  ```sh
64
69
  npm run dev
65
70
  ```
@@ -67,7 +72,7 @@ Go to [localhost:3000](http://localhost:3000)
67
72
 
68
73
  ## useUrlState hook for Next.js
69
74
 
70
- `useUrlState` is a custom React hook for Next.js applications that manages state in the URL query string. It allows you to store and retrieve state from the URL search parameters, providing a way to persist state across page reloads and share application state via URLs.
75
+ `useUrlState` is a custom React hook for Next.js applications that make communication between client components easy. It allows you to store and retrieve state from the URL search parameters, providing a way to persist state across page reloads and share application state via URLs.
71
76
 
72
77
 
73
78
  ### Usage examples
@@ -91,7 +96,7 @@ function MyComponent() {
91
96
  <div>
92
97
  <p>Count: {state.count}</p>
93
98
 
94
- <button onClick={() => updateUrl({ count: state.count + 1 })}>
99
+ <button onClick={() => updateUrl({ count: state.count + 1 }), { replace: true }}>
95
100
  Increment (Update URL)
96
101
  </button>
97
102
 
@@ -174,7 +179,7 @@ function SettingsComponent() {
174
179
 
175
180
  ## useUrlEncode hook for React.js
176
181
 
177
- `useUrlEncode` is a custom React hook that provides utility functions for encoding and decoding state to and from URL search parameters. This hook doesn't depend on Nextjs, and will works with any React application.
182
+ `useUrlEncode` is a custom React hook that provides utility functions for encoding and decoding state object to and from URL search parameters. This hook doesn't depend on Nextjs, and will works with any React application.
178
183
 
179
184
  Accepts optional `defaultState` argument.
180
185
 
@@ -201,6 +206,22 @@ const Component = () => {
201
206
  }
202
207
  ```
203
208
 
209
+ ## `encodeState` and `decodeState` helpers
210
+
211
+ `encodeState` let you encode some object with optional `defaults`, and optional existing queryString
212
+ ```ts
213
+ export const form = { name: '' };
214
+ ...
215
+ encodeState({ name: 'test' }, form, 'someExistingParam=123');
216
+ ```
217
+
218
+ `decodeState` let you decode queryString with optional defaults
219
+ ```ts
220
+ export const form = { name: '' };
221
+ ...
222
+ decodeState('name=Alex', form);
223
+ ```
224
+
204
225
  ## `encode` and `decode` helpers
205
226
 
206
227
  There low level helpers to stringify and parse query string params. Useful for other frameworks or pure JS.
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import t from"react";import{useRouter as e,usePathname as n,useSearchParams as r}from"next/navigation";const a=t=>{const e=null===t,n=Array.isArray(t),r=t instanceof Date;return(e?"null":r&&"date")||n&&"array"||!e&&!r&&!n&&"object"==typeof t&&"object"||typeof t},c={boolean:"🗵",null:"∙null",undefined:"∙undefined",number:"∓",date:"⏲"};function o(t){switch(a(t)){case"function":case"symbol":return"";case"date":return c.date+t.toISOString();case"string":return encodeURIComponent(t);case"number":return c.number+String(t);case"boolean":return c.boolean+String(t);case"object":case"array":return s(t);case"null":return c.null;case"undefined":return c.undefined;default:return String(t)}}const s=t=>JSON.stringify(t,u).replaceAll('"',"'"),u=(t,e)=>{const n=a(e);return t&&"object"!==n&&"array"!==n?o(e):e},i=t=>t.match(/^∓/)?Number.parseFloat(t.replaceAll("∓","")):t.match(/^🗵/)?!!t.includes("true"):t.match(/^⏲/)?new Date(t.slice(1)):t===c.null?null:t!==c.undefined?decodeURIComponent(t):void 0,l=(t,e)=>t&&"string"==typeof e?i(e):e,f=t=>{let e;try{e=JSON.parse(t,l)}catch{}return e};function d(t){const e=t.replaceAll("'",'"');return f(e)??i(t)}function p(e){const n=t.useCallback((function(t,n){const r=y(n);return"object"===a(t)&&Object.entries(t).forEach((([t,n])=>{const a=e?.[t];JSON.stringify(n)!==JSON.stringify(a)?r.set(t,o(n)):r.delete(t)})),r.toString()}),[e]);return{parse:t.useCallback((function(t){const n=y(t);return{...e,...Object.fromEntries([...n.entries()].map((([t,n])=>[t,d(n)??e?.[t]])))}}),[e]),stringify:n}}const y=t=>new URLSearchParams("string"==typeof t?t:t?.toString?.()||"");function b(a){const c=e(),o=n(),{parse:s,stringify:u}=p(a),i=r(),[l,f]=t.useState((()=>s(i)));t.useEffect((()=>{f((t=>{const e=s(i);return JSON.stringify(t)===JSON.stringify(e)?t:e}))}),[s,i]);const d=t.useCallback((t=>{f("function"==typeof t?e=>t(e):t)}),[]);return{updateUrl:t.useCallback(((t,e)=>{const n=`${o}?${i.toString()}`,r="function"==typeof t?`${o}?${u(t(l))}`:`${o}?${u(t)}`;n!==r&&c.push(r,e)}),[o,c,u,i,l]),updateState:d,state:l}}export{d as decode,o as encode,p as useUrlEncode,b as useUrlState};
1
+ import e from"react";import{useRouter as t,usePathname as n,useSearchParams as r}from"next/navigation";const c=e=>{const t=null===e,n=Array.isArray(e),r=e instanceof Date;return(t?"null":r&&"date")||n&&"array"||!t&&!r&&!n&&"object"==typeof e&&"object"||typeof e},a=e=>new URLSearchParams("string"==typeof e?e:e?.toString?.()||""),o={boolean:"🗵",null:"∙null",undefined:"∙undefined",number:"∓",date:"⏲"};function u(e){switch(c(e)){case"function":case"symbol":return"";case"date":return o.date+e.toISOString();case"string":return encodeURIComponent(e);case"number":return o.number+String(e);case"boolean":return o.boolean+String(e);case"object":case"array":return s(e);case"null":return o.null;case"undefined":return o.undefined;default:return String(e)}}const s=e=>JSON.stringify(e,i).replaceAll('"',"'"),i=(e,t)=>{const n=c(t);return e&&"object"!==n&&"array"!==n?u(t):t},l=e=>e.match(/^∓/)?Number.parseFloat(e.replaceAll("∓","")):e.match(/^🗵/)?!!e.includes("true"):e.match(/^⏲/)?new Date(e.slice(1)):e===o.null?null:e!==o.undefined?decodeURIComponent(e):void 0,f=(e,t)=>e&&"string"==typeof t?l(t):t,p=e=>{let t;try{t=JSON.parse(e,f)}catch{}return t};function d(e){const t=e.replaceAll("'",'"');return p(t)??l(e)}function g(e,t,n){const r=a(n);return Object.entries(e||{}).forEach((([e,n])=>{const c=t?.[e];JSON.stringify(n)!==JSON.stringify(c)&&r.set(e,u(n))})),r.toString()}function y(e,t){return{...t||{},...Object.fromEntries([...a(e).entries()].map((([e,n])=>[e,d(n)??t?.[e]])))}}function b(t){const n=e.useCallback((function(e,n){return"object"===c(e)?g(e,t,n):""}),[t]);return{parse:e.useCallback((function(e){return y(e,t)}),[t]),stringify:n}}function m(c){const a=t(),o=n(),{parse:u,stringify:s}=b(c),i=r(),[l,f]=e.useState((()=>u(i)));e.useEffect((()=>{f((e=>{const t=u(i);return JSON.stringify(e)===JSON.stringify(t)?e:t}))}),[u,i]);const p=e.useCallback((e=>{f("function"==typeof e?t=>e(t):e)}),[]);return{updateUrl:e.useCallback(((e,t)=>{const n=i.toString(),r=`${o}${n.length?"?":""}${n}`,c=s("function"==typeof e?e(l):e),u=`${o}${c.length?"?":""}${c}`;if(r!==u){const{replace:e,...n}=t||{};a[e?"replace":"push"](u,{scroll:!1,...n})}}),[o,a,s,i,l]),updateState:p,state:l}}export{d as decode,y as decodeState,u as encode,g as encodeState,b as useUrlEncode,m as useUrlState};
@@ -0,0 +1 @@
1
+ export { encodeState, decodeState, encode, decode, type Type, useUrlEncode, useUrlState, } from './urlstate';
@@ -0,0 +1,28 @@
1
+ import { type JSONCompatible } from './utils';
2
+ /**
3
+ * Encodes the state object into a URL query string.
4
+ *
5
+ * @param {JSONCompatible<T>} state - The state object to encode.
6
+ * @param {JSONCompatible<T>} [defaults] - Optional default values for the state object.
7
+ * @return {string} The encoded URL query string representing the state object.
8
+ *
9
+ * * Example:
10
+ * ```ts
11
+ * export const form = { name: '' };
12
+ * encodeState({ name: 'test' }, form, 'someExistingParam=123');
13
+ * ```
14
+ */
15
+ export declare function encodeState<T>(state: never extends T ? object : JSONCompatible<T>, defaults?: JSONCompatible<T>, paramsToKeep?: string | URLSearchParams): string;
16
+ /**
17
+ * Decodes a URI string into an object of type T.
18
+ *
19
+ * @param {string} uriString - The URI string to decode.
20
+ * @return {T} The decoded object of type T.
21
+ *
22
+ * * Example:
23
+ * ```ts
24
+ * export const form = { name: '' };
25
+ * decodeState('key=value&name=Alex', form);
26
+ * ```
27
+ */
28
+ export declare function decodeState<T>(uriString: string | URLSearchParams, defaults?: never extends T ? object : JSONCompatible<T>): never extends T ? object : T;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -2,5 +2,6 @@ import { encode, decode } from './encoder';
2
2
  import { type Type, type JSONCompatible, typeOf } from './utils';
3
3
  import { useUrlEncode } from './useUrlEncode';
4
4
  import { useUrlState } from './useUrlState';
5
- export { encode, decode, typeOf, useUrlEncode, useUrlState };
5
+ import { encodeState, decodeState } from './encodeState';
6
+ export { encode, decode, typeOf, useUrlEncode, useUrlState, encodeState, decodeState, };
6
7
  export type { Type, JSONCompatible };
@@ -0,0 +1,23 @@
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
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -1,11 +1,42 @@
1
+ import { useRouter } from 'next/navigation';
1
2
  import { type JSONCompatible } from './utils';
2
3
  /**
3
4
  * NextJS hook. Returns `state`, `updateState`, and `updateUrl` functions
4
5
  *
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
+ * ```
6
31
  */
7
32
  export declare function useUrlState<T>(defaultState?: JSONCompatible<T>): {
8
- 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?: import("next/dist/shared/lib/app-router-context.shared-runtime").NavigateOptions | undefined) => void;
9
- 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_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>) => Readonly<JSONCompatible<T> & {} extends infer T_33 ? { readonly [P in keyof T_33]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_34 ? { readonly [P_1 in keyof T_34]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_35 ? { readonly [P_2 in keyof T_35]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_36 ? { readonly [P_3 in keyof T_36]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_37 ? { readonly [P_4 in keyof T_37]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_38 ? { readonly [P_5 in keyof T_38]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_39 ? { readonly [P_6 in keyof T_39]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_40 ? { readonly [P_7 in keyof T_40]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_41 ? { readonly [P_8 in keyof T_41]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_42 ? { readonly [P_9 in keyof T_42]: 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_43 ? { readonly [P_10 in keyof T_43]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>)) => void;
10
- state: Readonly<JSONCompatible<T> & {} extends infer T_44 ? { readonly [P in keyof T_44]: Readonly<(JSONCompatible<T> & {})[P] extends infer T_45 ? { readonly [P_1 in keyof T_45]: Readonly<(JSONCompatible<T> & {})[P][P_1] extends infer T_46 ? { readonly [P_2 in keyof T_46]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2] extends infer T_47 ? { readonly [P_3 in keyof T_47]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3] extends infer T_48 ? { readonly [P_4 in keyof T_48]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4] extends infer T_49 ? { readonly [P_5 in keyof T_49]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5] extends infer T_50 ? { readonly [P_6 in keyof T_50]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6] extends infer T_51 ? { readonly [P_7 in keyof T_51]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7] extends infer T_52 ? { readonly [P_8 in keyof T_52]: Readonly<(JSONCompatible<T> & {})[P][P_1][P_2][P_3][P_4][P_5][P_6][P_7][P_8] extends infer T_53 ? { readonly [P_9 in keyof T_53]: 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_54 ? { readonly [P_10 in keyof T_54]: Readonly<any>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>; } : never>;
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>;
11
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 {};
@@ -19,4 +19,5 @@ export type JSONCompatible<T> = unknown extends T ? never : {
19
19
  export type DeepReadonly<T> = Readonly<{
20
20
  readonly [P in keyof T]: DeepReadonly<T[P]>;
21
21
  }>;
22
+ export declare const getParams: (strOrSearchParams?: string | URLSearchParams) => URLSearchParams;
22
23
  export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "state-in-url",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
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": [
@@ -72,9 +72,11 @@
72
72
  "dev": "wireit",
73
73
  "dev:lib": "wireit",
74
74
  "dev:nextjs": "wireit",
75
- "bump": "standard-version",
75
+ "bump": "npx standard-version --no-verify",
76
+ "bump:ex": "npm i state-in-url@latest --workspace=packages/example-nextjs",
76
77
  "build": "wireit",
77
78
  "build:demo": "cd packages/example-nextjs && npx cross-env DEMO=true npm run build",
79
+ "start:demo": "cd packages/example-nextjs && npm run build && npx serve -s ./out",
78
80
  "cleanup": "rm -rf dist",
79
81
  "setup": "playwright install --with-deps",
80
82
  "prepare": "npx husky"
package/dist/index.d.ts DELETED
@@ -1 +0,0 @@
1
- export { encode, decode, type Type, useUrlEncode, useUrlState, } from './urlstate';
@@ -1,10 +0,0 @@
1
- import { type JSONCompatible, type DeepReadonly } from './utils';
2
- /**
3
- * Returns stringify and parse functions
4
- *
5
- * @param {?JSONCompatible<T>} [stateShape] Optional fallback values for state
6
- */
7
- export declare function useUrlEncode<T>(stateShape?: JSONCompatible<T>): {
8
- 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>;
9
- stringify: (state: DeepReadonly<NonNullable<typeof stateShape>> | NonNullable<typeof stateShape>, strOrSearchParams?: string | URLSearchParams) => string;
10
- };