state-in-url 2.2.3 → 2.2.5

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.CN.md CHANGED
@@ -1,9 +1,7 @@
1
1
  [English](./README.md) | [한국어](./README.KO.md) | 简体中文
2
2
 
3
- <h1 align="center">state-in-url</h1>
4
-
5
3
  <div align="center">
6
- <img src="/assets/logo.svg?raw=true" alt="库标志"/>
4
+ <img src="/assets/Logo_big.png?raw=true" alt="state-in-url logo"/>
7
5
 
8
6
  <div>轻松在不相关的React组件之间共享状态,具有IDE自动完成和TS验证功能。无需任何麻烦或样板代码。</div>
9
7
  </div>
package/README.KO.md CHANGED
@@ -1,10 +1,8 @@
1
1
  [English] | 한국어 | [简体中文](./README.CN.md)
2
2
 
3
- <h1 align="center">state-in-url</h1>
4
-
5
3
 
6
4
  <div align="center">
7
- <img src="/assets/logo.svg?raw=true" alt="라이브러리 로고"/>
5
+ <img src="/assets/Logo_big.png?raw=true" alt="state-in-url logo"/>
8
6
 
9
7
  <div>IDE 자동 완성 및 TS 검증과 함께 관련 없는 React 컴포넌트 간에 상태를 쉽게 공유할 수 있습니다. 번거로움이나 보일러플레이트 없이 사용 가능합니다.</div>
10
8
  </div>
package/README.md CHANGED
@@ -1,9 +1,7 @@
1
1
  English | [한국어](./README.KO.md) | [简体中文](./README.CN.md)
2
2
 
3
- <h1 align="center">state-in-url</h1>
4
-
5
3
  <div align="center">
6
- <img src="/assets/logo.svg?raw=true" alt="Library logo"/>
4
+ <img src="/assets/Logo_big.png?raw=true" alt="state-in-url logo"/>
7
5
 
8
6
  <div>Easily share state between unrelated React components, with IDE autocomplete and TS validation. Without any hasssle or boilerplate. </div>
9
7
  </div>
@@ -30,7 +28,7 @@ English | [한국어](./README.KO.md) | [简体中文](./README.CN.md)
30
28
 
31
29
  <hr />
32
30
 
33
- Add a ⭐️ to support the project!
31
+ Add a ⭐️ and <a href="https://github.com/asmyshlyaev177" target="_blank">follow me</a> to support the project!
34
32
 
35
33
  <hr />
36
34
 
@@ -38,7 +36,7 @@ Add a ⭐️ to support the project!
38
36
 
39
37
  ## Why use state-in-url?
40
38
 
41
- `state-in-url` Simple state management with optional URL sync. Share complex states between unrelated React components, TS-friendly, NextJS compatible.
39
+ `state-in-url` Simple state management with optional URL sync. Share complex states between unrelated React components, TS-friendly, NextJS compatible. Most of users don't care about URL, so, can use it to store your app state.
42
40
 
43
41
  # Use cases
44
42
 
@@ -68,6 +66,7 @@ Add a ⭐️ to support the project!
68
66
  - [Low-level `encode` and `decode` functions](#encode-and-decode-helpers)
69
67
  - [Best practices](#best-practices)
70
68
  - [Gothas](#gothas)
69
+ - [Roadmap](#roadmap)
71
70
  - [Contact & Support](#contact--support)
72
71
  - [Changelog](#changelog)
73
72
  - [License](#license)
@@ -387,6 +386,11 @@ npm run dev
387
386
 
388
387
  Go to [localhost:3000](http://localhost:3000)
389
388
 
389
+ ## Roadmap
390
+ - [x] hook for `Next.js`
391
+ - [ ] hook for 'react-router`
392
+ - [ ] hook for store state in hash ?
393
+
390
394
  ## Contact & Support
391
395
 
392
396
  - Create a [GitHub issue](https://github.com/asmyshlyaev177/state-in-url/issues) for bug reports, feature requests, or questions
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import { decode, encode } from './encoder';
2
2
  import { decodeState, encodeState } from './encodeState';
3
- import { parseSsrQs, useUrlState } from './next';
3
+ import { parseSPObj, useUrlState } from './next';
4
4
  import { useSharedState } from './useSharedState';
5
5
  import { useUrlEncode } from './useUrlEncode';
6
6
  import { useUrlStateBase } from './useUrlStateBase';
7
7
  import { isSSR, type JSONCompatible, type Type, typeOf } from './utils';
8
- export { decode, decodeState, encode, encodeState, isSSR, parseSsrQs, typeOf, useSharedState, useUrlEncode, useUrlState, useUrlStateBase, };
8
+ export { decode, decodeState, encode, encodeState, isSSR, parseSPObj, typeOf, useSharedState, useUrlEncode, useUrlState, useUrlStateBase, };
9
9
  export type { JSONCompatible, Type };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export{decode,encode}from"./encoder/encoder.mjs";export{decodeState,encodeState}from"./encodeState/encodeState.mjs";export{parseSsrQs}from"./next/parseSsrQs.mjs";export{useUrlState}from"./next/useUrlState/useUrlState.mjs";export{useSharedState}from"./useSharedState/useSharedState.mjs";export{useUrlEncode}from"./useUrlEncode/useUrlEncode.mjs";export{useUrlStateBase}from"./useUrlStateBase/useUrlStateBase.mjs";export{isSSR,typeOf}from"./utils.mjs";
1
+ export{decode,encode}from"./encoder/encoder.mjs";export{decodeState,encodeState}from"./encodeState/encodeState.mjs";export{parseSPObj}from"./next/parseSPObj.mjs";export{useUrlState}from"./next/useUrlState/useUrlState.mjs";export{useSharedState}from"./useSharedState/useSharedState.mjs";export{useUrlEncode}from"./useUrlEncode/useUrlEncode.mjs";export{useUrlStateBase}from"./useUrlStateBase/useUrlStateBase.mjs";export{isSSR,typeOf}from"./utils.mjs";
@@ -1,2 +1,2 @@
1
- export { parseSsrQs } from './parseSsrQs';
1
+ export { parseSPObj } from './parseSPObj';
2
2
  export { useUrlState } from './useUrlState';
@@ -1 +1 @@
1
- export{parseSsrQs}from"./parseSsrQs.mjs";export{useUrlState}from"./useUrlState/useUrlState.mjs";
1
+ export{parseSPObj}from"./parseSPObj.mjs";export{useUrlState}from"./useUrlState/useUrlState.mjs";
@@ -6,4 +6,4 @@ import { type JSONCompatible } from '../utils';
6
6
  * @param {T} defaults - The default values to use if parsing fails.
7
7
  * @return {T} - The parsed object or the default values.
8
8
  */
9
- export declare function parseSsrQs<T extends JSONCompatible>(sp: object | undefined, defaults: T): T;
9
+ export declare function parseSPObj<T extends JSONCompatible>(sp: object | undefined, defaults: T): T;
@@ -1 +1 @@
1
- import{decodePrimitive as r,errorSym as t,decode as n}from"../encoder/encoder.mjs";function e(r,t){return{...t,...o(JSON.stringify(r),t)}}function o(n,e){try{return JSON.parse(n,c)}catch{const o=r(n);return o!==t?o:e}}const c=(r,t)=>{const e="string"==typeof t,o=e&&n(t?.replaceAll?.("'",'"'));return r&&e?o:t};export{e as parseSsrQs};
1
+ import{decodePrimitive as r,errorSym as t,decode as n}from"../encoder/encoder.mjs";function e(r,t){return{...t,...o(JSON.stringify(r),t)}}function o(n,e){try{return JSON.parse(n,c)}catch{const o=r(n);return o!==t?o:e}}const c=(r,t)=>{const e="string"==typeof t,o=e&&n(t?.replaceAll?.("'",'"'));return r&&e?o:t};export{e as parseSPObj};
@@ -1 +1 @@
1
- import{useRouter as t,useSearchParams as e}from"next/navigation";import a from"react";import{parseSsrQs as r}from"../parseSsrQs.mjs";import{useUrlStateBase as s}from"../../useUrlStateBase/useUrlStateBase.mjs";function c(c,l){const{_defaultState:n,_searchParams:u,_replace:o}=function(t,e){const a="defaultState"in t?t.defaultState:t,r="defaultState"in t?t.searchParams:e,s="defaultState"in t&&(t.replace??!0);return{_defaultState:a,_searchParams:r,_replace:s}}(c,l),f=t(),{state:i,updateState:m,updateUrl:p,getState:S}=s(n,f,u),d=a.useCallback(((t,e)=>{const a={scroll:!1,replace:o,...e};p(t,a)}),[p,o]),_=e();return a.useEffect((()=>{const t=Object.keys(n),e=Object.fromEntries([..._.entries()].filter((([e])=>t.includes(e))));m(r(e,n))}),[_]),{updateState:m,updateUrl:d,state:i,getState:S}}export{c as useUrlState};
1
+ import{useRouter as t,useSearchParams as e}from"next/navigation";import a from"react";import{parseSPObj as r}from"../parseSPObj.mjs";import{useUrlStateBase as s}from"../../useUrlStateBase/useUrlStateBase.mjs";import{isSSR as c,filterUnknownParamsClient as l}from"../../utils.mjs";function n(n,o){const{_defaultState:u,_searchParams:i,_replace:f}=function(t,e){const a="defaultState"in t?t.defaultState:t,r="defaultState"in t?t.searchParams:e,s="defaultState"in t&&(t.replace??!0);return{_defaultState:a,_searchParams:r,_replace:s}}(n,o),m=t(),{state:p,updateState:S,updateUrl:d,getState:j}=s(u,m,(({parse:t})=>c()?r(function(t,e){const a=Object.keys(t),r=Object.fromEntries(Object.entries(e||{}).map((([t,e])=>[t.replaceAll("+"," "),e])).filter((([t])=>a.includes(t))));return r}(u,i),u):t(l(u)))),b=a.useCallback(((t,e)=>{const a={scroll:!1,replace:f,...e};d(t,a)}),[d,f]),O=e();return a.useEffect((()=>{const t=Object.keys(u),e=Object.fromEntries([...O.entries()].filter((([e])=>t.includes(e))));S(r(e,u))}),[O]),{updateState:S,updateUrl:b,state:p,getState:j}}export{n as useUrlState};
@@ -1 +1 @@
1
- import t from"react";import{stateMap as r,subscribers as e}from"../subscribers.mjs";import{useInsertionEffect as n}from"../useInsertionEffect.mjs";import{isSSR as c,isEqual as u}from"../utils.mjs";function s(s,o){const f=t.useRef(s),[i,a]=t.useState((()=>{if(c())return o?o?.():f.current;const t=r.get(f.current);if(t)return t;{const t=o?.()||f.current;return r.set(f.current,t),t}})),m=t.useCallback((t=>{const n=r.get(f.current);if("function"==typeof t){const c=t(n);if(u(n,c))return;r.set(f.current,c),e.get(f.current).forEach((t=>{t()}))}else{const c={...n,...t};if(u(n,c))return;r.set(f.current,c),e.get(f.current).forEach((t=>{t()}))}}),[]);n((()=>{const t=e.add(f.current,(()=>{a(r.get(f.current)||f.current)}));return()=>{t()}}),[]);return{state:i,getState:t.useCallback((()=>r.get(f.current)||f.current),[]),setState:m}}export{s as useSharedState};
1
+ import t from"react";import{stateMap as r,subscribers as e}from"../subscribers.mjs";import{useInsertionEffect as n}from"../useInsertionEffect.mjs";import{isSSR as u,isEqual as c}from"../utils.mjs";function s(s,o){const f=t.useRef(s),[a,i]=t.useState((()=>{if(u())return o?o?.():f.current;const t=r.get(f.current);if(t)return t;{const t=o?.()||f.current;return r.set(f.current,t),t}})),m=t.useCallback((t=>{const n=r.get(f.current),u="function"==typeof t?t(n):{...n,...t};c(n,u)||(r.set(f.current,u),e.get(f.current).forEach((t=>{t()})))}),[]);n((()=>{const t=e.add(f.current,(()=>{i(r.get(f.current)||f.current)}));return()=>{t()}}),[]);return{state:a,getState:t.useCallback((()=>r.get(f.current)||f.current),[]),setState:m}}export{s as useSharedState};
@@ -1,21 +1,29 @@
1
+ import { useUrlEncode } from '../useUrlEncode';
1
2
  import { type DeepReadonly, type JSONCompatible } from '../utils';
2
3
  /**
3
- * Base hook to integrate it with different routers
4
+ * A custom React hook to create custom hooks.
5
+ *
6
+ * @template T extends JSONCompatible
7
+ * @param {T} defaultState - An object representing the default state values.
8
+ * @param {Router} router - Router object with [push] and [replace] methods.
9
+ * @param {Function} [getInitialState] - Optional function to get the initial state, passes `parse`, and `filterUnknownParams` helpers
10
+ * @returns {Object} An object containing `state`, `getState`, `updateState`, and `updateUrl` properties.
4
11
  *
5
- * @param {JSONCompatible<T>} [defaultState] Fallback (default) values for state
6
- * @param {Router} [router] Router object with `push` and `replace` methods
7
- * @param {?SearchParams<T>} [searchParams] searchParams from Next server component
8
12
  *
9
13
  * * Example:
10
14
  * ```ts
11
15
  * export const form = { name: '' };
12
16
  * const router = { push: () => {}, replace: () => {} };
13
- * const { state, updateState, updateUrl } = useUrlStateBase(form, router, sp);
17
+ * const { state, updateState, updateUrl } = useUrlStateBase(form, router, ({ parse, filterClientSP }) =>
18
+ * isSSR() ? getServerState() : getClientState()
19
+ * );
14
20
  * ```
15
21
  *
16
- * * Docs {@link https://github.com/asmyshlyaev177/state-in-url/tree/integrations/packages/urlstate/useUrlStateBase#api}
22
+ * * Docs {@link https://github.com/asmyshlyaev177/state-in-url/tree/integrations/packages/urlstate/useUrlStateBase#api}
17
23
  */
18
- export declare function useUrlStateBase<T extends JSONCompatible>(defaultState: T, router: Router, searchParams?: object): {
24
+ export declare function useUrlStateBase<T extends JSONCompatible>(defaultState: T, router: Router, getInitialState?: ({ parse, }: {
25
+ parse: ReturnType<typeof useUrlEncode<T>>['parse'];
26
+ }) => T): {
19
27
  updateState: (value: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T)) => void;
20
28
  updateUrl: (value?: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T) | undefined, options?: Options) => void;
21
29
  state: DeepReadonly<T>;
@@ -1 +1 @@
1
- import t from"react";import{parseSsrQs as e}from"../next/parseSsrQs.mjs";import{useInsertionEffect as n}from"../useInsertionEffect.mjs";import{useSharedState as o}from"../useSharedState/useSharedState.mjs";import{useUrlEncode as r}from"../useUrlEncode/useUrlEncode.mjs";import{isSSR as s}from"../utils.mjs";function a(a,m,l){const{parse:u,stringify:w}=r(a),{state:f,getState:p,setState:d}=o(a,(()=>s()?e(function(t,e){const n=Object.keys(t),o=Object.fromEntries(Object.entries(e||{}).map((([t,e])=>[t.replaceAll("+"," "),e])).filter((([t])=>n.includes(t))));return o}(a,l),a):u(c(a))));n((()=>{const t=()=>{const t=u(c(a));d(t)};return window.addEventListener(i,t),()=>{window.removeEventListener(i,t)}}),[d]);const h=t.useCallback(((t,e)=>{const n=`${window.location.pathname}${window.location.search}${window.location.hash}`,o="function"==typeof t,r=function(t){const e=Object.keys(t),n=window.location.search,o=new URLSearchParams(n),r=new URLSearchParams;return o.forEach(((t,n)=>!e.includes(n)&&r.set(n,t))),r}(a),s=o?t(p()):t?{...p(),...t}:p(),c=w(s,r);d(s);const i=`${window.location.pathname}${c.length?"?":""}${c}${window.location.hash}`;if(n!==i){const{replace:t,...n}=e||{};m[t?"replace":"push"](i,{...n})}}),[m,w,p]);return{updateState:d,updateUrl:h,state:f,getState:p}}function c(t){const e=new URLSearchParams(window.location.search),n=Object.keys(t),o=new URLSearchParams;return[...e.entries()].filter((([t])=>n.includes(t))).forEach((([t,e])=>o.set(t,e))),o.toString()}const i="popstate";export{a as useUrlStateBase};
1
+ import t from"react";import{useInsertionEffect as e}from"../useInsertionEffect.mjs";import{useSharedState as o}from"../useSharedState/useSharedState.mjs";import{useUrlEncode as n}from"../useUrlEncode/useUrlEncode.mjs";import{filterUnknownParamsClient as a}from"../utils.mjs";function s(s,c,i){const{parse:m,stringify:p}=n(s),{state:w,getState:d,setState:u}=o(s,(()=>i?.({parse:m})||s));e((()=>{const t=()=>{const t=m(a(s));u(t)};return window.addEventListener(r,t),()=>{window.removeEventListener(r,t)}}),[u]);const l=t.useCallback(((t,e)=>{const o=`${window.location.pathname}${window.location.search}${window.location.hash}`,n="function"==typeof t,a=function(t){const e=Object.keys(t),o=window.location.search,n=new URLSearchParams(o),a=new URLSearchParams;return n.forEach(((t,o)=>!e.includes(o)&&a.set(o,t))),a}(s),r=n?t(d()):t?{...d(),...t}:d(),i=p(r,a);u(r);const m=`${window.location.pathname}${i.length?"?":""}${i}${window.location.hash}`;if(o!==m){const{replace:t,...o}=e||{};c[t?"replace":"push"](m,{...o})}}),[c,p,d]);return{updateState:u,updateUrl:l,state:w,getState:d}}const r="popstate";export{s as useUrlStateBase};
package/dist/utils.d.ts CHANGED
@@ -23,3 +23,4 @@ export type UnknownObj = {
23
23
  [key: string]: unknown;
24
24
  };
25
25
  export declare const isEqual: (val1: unknown, val2: unknown) => boolean;
26
+ export declare function filterUnknownParamsClient<T extends object>(shape: T): string;
package/dist/utils.mjs CHANGED
@@ -1 +1 @@
1
- const t=t=>{const n=typeof t,r=null===t,e=Array.isArray(t),i=t instanceof Date;return(r?"null":i&&"date")||e&&"array"||!r&&!i&&!e&&"object"===n&&"object"||n},n=()=>"undefined"==typeof window,r=t=>new URLSearchParams("string"==typeof t?e(t):t?.toString?.()||""),e=t=>t.split("?")?.[1]||t||"",i=(t,n)=>JSON.stringify(t)===JSON.stringify(n);export{r as getParams,i as isEqual,n as isSSR,t as typeOf};
1
+ const t=t=>{const e=typeof t,n=null===t,r=Array.isArray(t),a=t instanceof Date;return(n?"null":a&&"date")||r&&"array"||!n&&!a&&!r&&"object"===e&&"object"||e},e=()=>"undefined"==typeof window,n=t=>new URLSearchParams("string"==typeof t?r(t):t?.toString?.()||""),r=t=>t.split("?")?.[1]||t||"",a=(t,e)=>JSON.stringify(t)===JSON.stringify(e);function i(t){const e=new URLSearchParams(window.location.search),n=Object.keys(t),r=new URLSearchParams;return[...e.entries()].filter((([t])=>n.includes(t))).forEach((([t,e])=>r.set(t,e))),r.toString()}export{i as filterUnknownParamsClient,n as getParams,a as isEqual,e as isSSR,t as typeOf};
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "state-in-url",
3
- "version": "2.2.3",
3
+ "version": "2.2.5",
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": [
7
7
  "state-management",
8
8
  "state management",
9
9
  "Next.js",
10
+ "useUrlState",
10
11
  "client components communication",
11
12
  "signals alternative",
12
13
  "query string",