state-in-url 2.0.2 → 2.1.1
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 +1 -1
- package/README.KO.md +1 -1
- package/README.md +6 -4
- package/dist/next/useUrlState/useUrlState.d.ts +5 -3
- package/dist/useSharedState/useSharedState.d.ts +2 -2
- package/dist/useSharedState/useSharedState.mjs +1 -1
- package/dist/useUrlStateBase/useUrlStateBase.d.ts +6 -6
- package/dist/useUrlStateBase/useUrlStateBase.mjs +1 -1
- package/package.json +10 -4
package/README.CN.md
CHANGED
|
@@ -91,7 +91,7 @@ pnpm add state-in-url
|
|
|
91
91
|
|
|
92
92
|
## Next.js的useUrlState钩子
|
|
93
93
|
|
|
94
|
-
[文档](
|
|
94
|
+
[文档](packages/urlstate/next/useUrlState#api)
|
|
95
95
|
|
|
96
96
|
`useUrlState`是一个为Next.js应用程序设计的自定义React钩子,使客户端组件之间的通信变得简单。它允许你共享任何复杂的状态并将其与URL搜索参数同步,提供了一种在页面重新加载之间持久化状态并通过URL共享应用程序状态的方法。
|
|
97
97
|
|
package/README.KO.md
CHANGED
|
@@ -98,7 +98,7 @@ pnpm add state-in-url
|
|
|
98
98
|
|
|
99
99
|
## Next.js용 useUrlState 훅
|
|
100
100
|
|
|
101
|
-
[문서](
|
|
101
|
+
[문서](packages/urlstate/next/useUrlState#api)
|
|
102
102
|
|
|
103
103
|
`useUrlState`는 Next.js 애플리케이션을 위한 사용자 정의 React 훅으로, 클라이언트 컴포넌트 간의 통신을 쉽게 만듭니다. 복잡한 상태를 공유하고 URL 검색 매개변수와 동기화할 수 있게 해주어, 페이지 새로고침 시 상태를 유지하고 URL을 통해 애플리케이션 상태를 공유할 수 있습니다.
|
|
104
104
|
|
package/README.md
CHANGED
|
@@ -42,16 +42,18 @@ Add a ⭐️ to support the project!
|
|
|
42
42
|
|
|
43
43
|
## Why use state-in-url?
|
|
44
44
|
|
|
45
|
-
`state-in-url` Simple state management with URL sync. Share complex states between unrelated React components,
|
|
45
|
+
`state-in-url` Simple state management with optional URL sync. Share complex states between unrelated React components, TS-friendly, NextJS compatible.
|
|
46
46
|
|
|
47
47
|
|
|
48
48
|
# Use cases
|
|
49
49
|
|
|
50
|
+
- 🧮 Store unsaved user forms in URL
|
|
50
51
|
- 🙃 Share the state between different components without changing url, good as alternative to signals and other state management tools
|
|
52
|
+
- 🧠 Sync data between unrelated client components
|
|
51
53
|
- 🔗 Shareable URLs with full application state
|
|
52
54
|
- 🔄 Easy state persistence across page reloads
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
|
|
56
|
+
|
|
55
57
|
|
|
56
58
|
# Features
|
|
57
59
|
|
|
@@ -98,7 +100,7 @@ In `tsconfig.json` in `compilerOptions` set `"moduleResolution": "Node16"` or `"
|
|
|
98
100
|
|
|
99
101
|
## useUrlState hook for Next.js
|
|
100
102
|
|
|
101
|
-
[Docs](
|
|
103
|
+
[Docs](packages/urlstate/next/useUrlState#api)
|
|
102
104
|
|
|
103
105
|
`useUrlState` is a custom React hook for Next.js applications that make communication between client components easy. It allows you to share any complex state and sync it with the URL search parameters, providing a way to persist state across page reloads and share application state via URLs.
|
|
104
106
|
|
|
@@ -8,7 +8,7 @@ import { type DeepReadonly, type JSONCompatible } from '../../utils';
|
|
|
8
8
|
*
|
|
9
9
|
* * Example:
|
|
10
10
|
* ```ts
|
|
11
|
-
* export const form = { name: '' };
|
|
11
|
+
* export const form = { name: '', age: 0 };
|
|
12
12
|
* const { state, updateState, updateUrl } = useUrlState(form);
|
|
13
13
|
* // for nextjs seerver components
|
|
14
14
|
* // const { state, updateState, updateUrl } = useUrlState(form, searchParams);
|
|
@@ -16,6 +16,8 @@ import { type DeepReadonly, type JSONCompatible } from '../../utils';
|
|
|
16
16
|
* updateState({ name: 'test' });
|
|
17
17
|
* // by default it's uses router.push with scroll: false
|
|
18
18
|
* updateUrl({ name: 'test' }, { replace: true, scroll: true });
|
|
19
|
+
* // similar to React.useState
|
|
20
|
+
* updateUrl(curr => ({ ...curr, name: 'test' }), { replace: true, scroll: true });
|
|
19
21
|
* ```
|
|
20
22
|
*
|
|
21
23
|
* * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#api}
|
|
@@ -31,7 +33,7 @@ export declare function useUrlState<T extends JSONCompatible>(defaultState: T, s
|
|
|
31
33
|
*
|
|
32
34
|
* * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#updatestate}
|
|
33
35
|
*/
|
|
34
|
-
updateState: (value: T | DeepReadonly<T
|
|
36
|
+
updateState: (value: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T)) => void;
|
|
35
37
|
/**
|
|
36
38
|
* * Example:
|
|
37
39
|
* ```ts
|
|
@@ -42,7 +44,7 @@ export declare function useUrlState<T extends JSONCompatible>(defaultState: T, s
|
|
|
42
44
|
*
|
|
43
45
|
* * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/main/packages/urlstate/next/useUrlState#updateurl}
|
|
44
46
|
*/
|
|
45
|
-
updateUrl: (value?: T | DeepReadonly<T
|
|
47
|
+
updateUrl: (value?: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T) | undefined, options?: Options) => void;
|
|
46
48
|
state: DeepReadonly<DeepReadonly<T>>;
|
|
47
49
|
getState: () => T;
|
|
48
50
|
};
|
|
@@ -8,7 +8,7 @@ import { type DeepReadonly, type JSONCompatible } from '../utils';
|
|
|
8
8
|
*
|
|
9
9
|
* * Example:
|
|
10
10
|
* ```ts
|
|
11
|
-
* export const form = { name: '' };
|
|
11
|
+
* export const form = { name: '', age: 0 };
|
|
12
12
|
* const { state, setState } = useSharedState(form);
|
|
13
13
|
*
|
|
14
14
|
* setState({ name: 'test' });
|
|
@@ -20,5 +20,5 @@ import { type DeepReadonly, type JSONCompatible } from '../utils';
|
|
|
20
20
|
export declare function useSharedState<T extends JSONCompatible>(defaultState: T, _getInitial?: () => T): {
|
|
21
21
|
state: T;
|
|
22
22
|
getState: () => T;
|
|
23
|
-
setState: (value: T | DeepReadonly<T
|
|
23
|
+
setState: (value: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T)) => void;
|
|
24
24
|
};
|
|
@@ -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
|
|
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,8 +1,4 @@
|
|
|
1
1
|
import { type DeepReadonly, type JSONCompatible } from '../utils';
|
|
2
|
-
type Router = {
|
|
3
|
-
push: (href: string, opts: object) => void;
|
|
4
|
-
replace: (href: string, opts: object) => void;
|
|
5
|
-
};
|
|
6
2
|
/**
|
|
7
3
|
* Base hook to integrate it with different routers
|
|
8
4
|
*
|
|
@@ -20,12 +16,16 @@ type Router = {
|
|
|
20
16
|
* * Github {@link https://github.com/asmyshlyaev177/state-in-url/tree/integrations/packages/urlstate/useUrlStateBase#api}
|
|
21
17
|
*/
|
|
22
18
|
export declare function useUrlStateBase<T extends JSONCompatible>(defaultState: T, router: Router, searchParams?: object): {
|
|
23
|
-
updateState: (value: T | DeepReadonly<T
|
|
24
|
-
updateUrl: (value?: T | DeepReadonly<T
|
|
19
|
+
updateState: (value: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T)) => void;
|
|
20
|
+
updateUrl: (value?: Partial<T> | Partial<DeepReadonly<T>> | ((currState: T) => T) | undefined, options?: Options) => void;
|
|
25
21
|
state: DeepReadonly<T>;
|
|
26
22
|
getState: () => T;
|
|
27
23
|
};
|
|
28
24
|
interface Options extends Object {
|
|
29
25
|
replace?: boolean;
|
|
30
26
|
}
|
|
27
|
+
type Router = {
|
|
28
|
+
push: (href: string, opts: object) => void;
|
|
29
|
+
replace: (href: string, opts: object) => void;
|
|
30
|
+
};
|
|
31
31
|
export {};
|
|
@@ -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,i,m){const{parse:w,stringify:
|
|
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,i,m){const{parse:w,stringify:u}=r(a),{state:l,getState:d,setState:f}=o(a,(()=>s()?e(function(t,e){const n=Object.keys(t),o=Object.fromEntries(Object.entries(e||{}).filter((([t])=>n.includes(t))));return o}(a,m),a):w(function(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()}(a))));n((()=>{const t=()=>{const t=w(window.location.search);f(t)};return window.addEventListener(c,t),()=>{window.removeEventListener(c,t)}}),[f]);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(d()):t?{...d(),...t}:d(),c=u(s,r);f(s);const m=`${window.location.pathname}${c.length?"?":""}${c}${window.location.hash}`;if(n!==m){const{replace:t,...n}=e||{};i[t?"replace":"push"](m,{...n})}}),[i,u,d]);return{updateState:f,updateUrl:h,state:l,getState:d}}const c="popstate";export{a as useUrlStateBase};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "state-in-url",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
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": [
|
|
@@ -85,6 +85,7 @@
|
|
|
85
85
|
"test:unit": "wireit",
|
|
86
86
|
"test:int": "wireit",
|
|
87
87
|
"test:int:ci": "wireit",
|
|
88
|
+
"test:exports": "npx babel-node --extensions .js,.mjs,.ts,.mts --config-file ./babel.config.json -- ./packages/urlstate/exportsTest.ts",
|
|
88
89
|
"test": "wireit",
|
|
89
90
|
"tsc": "wireit",
|
|
90
91
|
"dev": "wireit",
|
|
@@ -184,7 +185,7 @@
|
|
|
184
185
|
]
|
|
185
186
|
},
|
|
186
187
|
"build": {
|
|
187
|
-
"command": "rollup -c rollup.config.js",
|
|
188
|
+
"command": "rollup -c rollup.config.js && npm run test:exports",
|
|
188
189
|
"dependencies": [
|
|
189
190
|
"cleanup"
|
|
190
191
|
]
|
|
@@ -218,9 +219,13 @@
|
|
|
218
219
|
]
|
|
219
220
|
},
|
|
220
221
|
"devDependencies": {
|
|
222
|
+
"@babel/core": "^7.25.2",
|
|
223
|
+
"@babel/node": "^7.25.0",
|
|
224
|
+
"@babel/preset-env": "^7.25.3",
|
|
225
|
+
"@babel/preset-typescript": "^7.24.7",
|
|
221
226
|
"@commitlint/cli": "^19.0.3",
|
|
222
227
|
"@commitlint/config-conventional": "^19.0.3",
|
|
223
|
-
"@playwright/test": "^1.45.
|
|
228
|
+
"@playwright/test": "^1.45.3",
|
|
224
229
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
225
230
|
"@rollup/plugin-terser": "^0.4.4",
|
|
226
231
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
@@ -233,6 +238,7 @@
|
|
|
233
238
|
"@types/node": "^20.11.24",
|
|
234
239
|
"@types/react": "^18.3.3",
|
|
235
240
|
"@types/react-dom": "^18.3.0",
|
|
241
|
+
"babel-plugin-module-resolver": "^5.0.2",
|
|
236
242
|
"commitizen": "^4.3.0",
|
|
237
243
|
"cross-env": "^7.0.3",
|
|
238
244
|
"cz": "^1.8.2",
|
|
@@ -243,7 +249,7 @@
|
|
|
243
249
|
"jest": "^29.7.0",
|
|
244
250
|
"jest-environment-jsdom": "^29.7.0",
|
|
245
251
|
"lint-staged": "^15.2.2",
|
|
246
|
-
"playwright": "^1.45.
|
|
252
|
+
"playwright": "^1.45.3",
|
|
247
253
|
"prettier": "^3.2.5",
|
|
248
254
|
"rollup": "^2.79.1",
|
|
249
255
|
"rollup-plugin-filesize": "^10.0.0",
|