state-in-url 4.0.9 → 4.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -168,10 +168,11 @@ import { userState } from './userState';
168
168
  function MyComponent() {
169
169
  // can pass `replace` arg, it's control will `setUrl` will use `rounter.push` or `router.replace`, default replace=true
170
170
  // can pass `searchParams` from server components
171
- const { urlState, setUrl, setState } = useUrlState(userState);
171
+ const { urlState, setUrl, setState, reset } = useUrlState(userState);
172
172
 
173
173
  return (
174
174
  <div>
175
+ // urlState.name will return default value from `userState` if url empty
175
176
  <input value={urlState.name}
176
177
  // same api as React.useState, e.g. setUrl(currVal => currVal + 1)
177
178
  onChange={(ev) => setUrl({ name: ev.target.value }) }
@@ -186,7 +187,7 @@ function MyComponent() {
186
187
  onBlur={() => setUrl()}
187
188
  />
188
189
 
189
- <button onClick={() => setUrl(userState)}>
190
+ <button onClick={reset}>
190
191
  Reset
191
192
  </button>
192
193
 
@@ -19,10 +19,15 @@ export declare function useUrlState<T extends JSONCompatible>({ defaultState: T,
19
19
  *
20
20
  * @param {JSONCompatible<T>} [defaultState] Fallback (default) values for state
21
21
  * @param {Object} params - Object with other parameters, including params from App router
22
- * @param {boolean} params.replace replace URL of push, default `true`
23
- * @param {boolean} params.useHistory use window.history for navigation, default true, no _rsc requests https://github.com/vercel/next.js/discussions/59167
22
+ * @param {boolean} params.replace replace URL or push, default `true`
23
+ * @param {boolean} params.useHistory use window.history for navigation, default `true`, no _rsc requests https://github.com/vercel/next.js/discussions/59167
24
24
  * @param {?SearchParams<T>} params.searchParams searchParams from Next server component
25
25
  * @param {boolean} params.scroll reset scroll, default `false`
26
+ * @returns {Object} [result] State and callbacks
27
+ * @returns {Object} [result.state] - current state object
28
+ * @returns {Function} [result.setUrl] - function to update state and url
29
+ * @returns {Function} [result.setState] - function to update state only
30
+ * @returns {Function} [result.reset] - function to reset state and url to default
26
31
 
27
32
  *
28
33
  * * Example:
@@ -30,11 +35,15 @@ export declare function useUrlState<T extends JSONCompatible>({ defaultState: T,
30
35
  * export const form = { name: '', age: 0 };
31
36
  * const { urlState, setState, setUrl } = useUrlState(form);
32
37
  * // for nextjs server components
33
- * const { urlState, setState, setUrl } = useUrlState(form, { searchParams });
38
+ * const { urlState, setState, setUrl, reset } = useUrlState(form, { searchParams });
34
39
  *
35
40
  * setState({ name: 'test' });
36
41
  * setUrl({ name: 'test' }, { replace: true, scroll: true });
37
42
  * setUrl(curr => ({ ...curr, name: 'test' }), { replace: true, scroll: true });
43
+ * // reset state and url
44
+ * reset();
45
+ * reset({ replace: true });
46
+ * // same as setState(form) with setUrl(form)
38
47
  * ```
39
48
  *
40
49
  * * Docs {@link https://github.com/asmyshlyaev177/state-in-url/tree/master/packages/urlstate/next/useUrlState#api}
@@ -43,6 +52,9 @@ export declare function useUrlState<T extends JSONCompatible>(defaultState: T, p
43
52
  urlState: T;
44
53
  setState: (value: Partial<T> | ((currState: T) => T)) => void;
45
54
  setUrl: (value?: Partial<T> | ((currState: T) => T), options?: Options) => void;
55
+ reset: (options?: Options & {
56
+ [key: string]: unknown;
57
+ }) => void;
46
58
  };
47
59
  type Router = ReturnType<typeof useRouter>;
48
60
  type RouterOptions = NonNullable<Parameters<Router["push"]>[1] | Parameters<Router["replace"]>[1]>;
@@ -1 +1 @@
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{routerHistory as l,isSSR as o,filterUnknownParams as c,filterUnknownParamsClient as u}from"../../utils.mjs";function i(i,m){const f="defaultState"in i?i.defaultState:i,n="defaultState"in i?i.searchParams:m?.searchParams,S="defaultState"in i?i.useHistory:m?.useHistory,d="defaultState"in i?{scroll:i.scroll,replace:i.replace}:{scroll:m?.scroll,replace:m?.replace},j=void 0===S||S?l:t(),{state:U,updateState:b,updateUrl:g,getState:P}=s(f,j,(({parse:t})=>o()?r(c(f,n),f):t(u(f)))),h=a.useCallback(((t,e)=>g(t,{...p,...d,...e})),[g,d]),v=e();return a.useEffect((()=>{b(c(f,r(Object.fromEntries([...v.entries()]),f)))}),[v]),{setState:b,updateState:b,setUrl:h,updateUrl:h,urlState:U,state:U,getState:P}}const p={replace:!0,scroll:!1};export{i as useUrlState};
1
+ import{useRouter as e,useSearchParams as t}from"next/navigation";import a from"react";import{parseSPObj as r}from"../../parseSPObj.mjs";import{useUrlStateBase as s}from"../../useUrlStateBase/useUrlStateBase.mjs";import{routerHistory as l,isSSR as o,filterUnknownParams as c,filterUnknownParamsClient as u}from"../../utils.mjs";function i(i,p){const n="defaultState"in i?i.defaultState:i,f="defaultState"in i?i.searchParams:p?.searchParams,S="defaultState"in i?i.useHistory:p?.useHistory,d="defaultState"in i?{scroll:i.scroll,replace:i.replace}:{scroll:p?.scroll,replace:p?.replace},j=void 0===S||S?l:e(),{state:U,updateState:b,updateUrl:g,reset:P,getState:h}=s(n,j,(({parse:e})=>o()?r(c(n,f),n):e(u(n)))),k=a.useMemo((()=>({...m,...d})),[]),v=a.useCallback(((e,t)=>g(e,{...k,...t})),[g]),x=t();a.useEffect((()=>{b(c(n,r(Object.fromEntries([...x.entries()]),n)))}),[x]);const y=a.useCallback((e=>{P({...k,...e})}),[P]);return{setState:b,updateState:b,setUrl:v,updateUrl:v,urlState:U,state:U,reset:y,getState:h}}const m={replace:!0,scroll:!1};export{i as useUrlState};
@@ -20,9 +20,14 @@ export declare function useUrlState<T extends JSONCompatible>({ defaultState: T,
20
20
  * @param {JSONCompatible<T>} [defaultState] Fallback (default) values for state
21
21
  * @param {Object} params - Object with other parameters
22
22
  * @param {NavigateOptions} params.NavigateOptions See type from `react-router-dom`
23
- * @param {boolean} params.replace replace URL of push, default `true`
23
+ * @param {boolean} params.replace replace URL or push, default `true`
24
24
  * @param {boolean} params.useHistory use window.history for navigation, default `false`
25
25
  * @param {boolean} params.preventScrollReset keep scroll position, default `true`
26
+ * @returns {Object} [result] State and callbacks
27
+ * @returns {Object} [result.state] - current state object
28
+ * @returns {Function} [result.setUrl] - function to update state and url
29
+ * @returns {Function} [result.setState] - function to update state only
30
+ * @returns {Function} [result.reset] - function to reset state and url to default
26
31
  * * Example:
27
32
  * ```ts
28
33
  * export const form = { name: '', age: 0 };
@@ -32,6 +37,10 @@ export declare function useUrlState<T extends JSONCompatible>({ defaultState: T,
32
37
  * setUrl({ name: 'test' }, { replace: true });
33
38
  * // similar to React.useState
34
39
  * setUrl(curr => ({ ...curr, name: 'test' }), { replace: true });
40
+ * // reset state and url
41
+ * reset();
42
+ * reset({ replace: true });
43
+ * // same as setState(form) with setUrl(form)
35
44
  * ```
36
45
  *
37
46
  * * Docs {@link https://github.com/asmyshlyaev177/state-in-url/tree/master/packages/urlstate/react-router/useUrlState#api}
@@ -40,6 +49,9 @@ export declare function useUrlState<T extends JSONCompatible>(defaultState: T, p
40
49
  urlState: T;
41
50
  setState: (value: Partial<T> | ((currState: T) => T)) => void;
42
51
  setUrl: (value?: Partial<T> | ((currState: T) => T), options?: Params) => void;
52
+ reset: (options?: NavigateOptions & {
53
+ [key: string]: unknown;
54
+ }) => void;
43
55
  };
44
56
  type OldParams<T> = {
45
57
  defaultState: T;
@@ -1 +1 @@
1
- import e from"react";import{useNavigate as t,useSearchParams as r}from"react-router-dom";import{parseSPObj as a}from"../../parseSPObj.mjs";import{useUrlStateBase as s}from"../../useUrlStateBase/useUrlStateBase.mjs";import{routerHistory as l,filterUnknownParamsClient as o,assignValue as p,filterUnknownParams as u}from"../../utils.mjs";function c(c,m){const n="defaultState"in c?c.defaultState:c,i="defaultState"in c?c.useHistory:m?.useHistory,f="defaultState"in c?{replace:c.replace,preventScrollReset:c.preventScrollReset}:{replace:m?.replace,preventScrollReset:m?.preventScrollReset},d=t(),j=e.useMemo((()=>i?l:{replace:(e,t)=>d(e,{...S,...f,...t}),push:(e,t)=>d(e,{...S,...f,...t})}),[d,f]),{state:v,updateState:R,updateUrl:U,getState:b}=s(n,j,(({parse:e})=>e(o(n)))),g=e.useCallback(((e,t)=>U(e,{...S,...f,...t})),[f]),[y]=r();return e.useEffect((()=>{R(p(n,u(n,a(Object.fromEntries([...y.entries()]),n))))}),[y]),{setState:R,updateState:R,setUrl:g,updateUrl:g,urlState:v,state:v,getState:b}}const S={replace:!0,preventScrollReset:!0};export{c as useUrlState};
1
+ import e from"react";import{useNavigate as t,useSearchParams as r}from"react-router-dom";import{parseSPObj as a}from"../../parseSPObj.mjs";import{useUrlStateBase as s}from"../../useUrlStateBase/useUrlStateBase.mjs";import{routerHistory as l,filterUnknownParamsClient as o,assignValue as p,filterUnknownParams as u}from"../../utils.mjs";function c(c,m){const n="defaultState"in c?c.defaultState:c,i="defaultState"in c?c.useHistory:m?.useHistory,f="defaultState"in c?{replace:c.replace,preventScrollReset:c.preventScrollReset}:{replace:m?.replace,preventScrollReset:m?.preventScrollReset},d=e.useMemo((()=>({...S,...f})),[]),j=t(),v=e.useMemo((()=>i?l:{replace:(e,t)=>j(e,{...d,...t}),push:(e,t)=>j(e,{...d,...t})}),[j]),{state:R,updateState:U,updateUrl:b,getState:g,reset:k}=s(n,v,(({parse:e})=>e(o(n)))),y=e.useCallback(((e,t)=>b(e,{...d,...t})),[b]),[B]=r();e.useEffect((()=>{U(p(n,u(n,a(Object.fromEntries([...B.entries()]),n))))}),[B]);const C=e.useCallback((e=>{k({...d,...e})}),[k]);return{setState:U,updateState:U,setUrl:y,updateUrl:y,urlState:R,state:R,reset:C,getState:g}}const S={replace:!0,preventScrollReset:!0};export{c as useUrlState};
@@ -7,16 +7,28 @@ import { type JSONCompatible, type Router } from "../utils";
7
7
  * @param {T} defaultState - An object representing the default state values.
8
8
  * @param {Router} router - Router object with [push] and [replace] methods.
9
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.
10
+ * @returns {Object} [result] State and callbacks
11
+ * @returns {Object} [result.state] - current state object
12
+ * @returns {Function} [result.updateUrl] - function to update state and url
13
+ * @returns {Function} [result.updateState] - function to update state only
14
+ * @returns {Function} [result.reset] - function to reset state and url to default
11
15
  *
12
16
  *
13
17
  * * Example:
14
18
  * ```ts
15
19
  * export const form = { name: '' };
16
20
  * const router = { push: () => {}, replace: () => {} };
17
- * const { state, updateState, updateUrl } = useUrlStateBase(form, router, ({ parse, filterClientSP }) =>
21
+ * const { state, updateState, updateUrl, reset } = useUrlStateBase(form, router, ({ parse, filterClientSP }) =>
18
22
  * isSSR() ? getServerState() : getClientState()
19
23
  * );
24
+ *
25
+ * updateState({ name: 'John' });
26
+ * updateState(curr => ({ ...curr, name: 'John' }));
27
+ * updateUrl({ name: 'John' }, { replace: true });
28
+ * updateUrl(curr => ({ ...curr, name: 'John' }), { replace: true });
29
+ * reset()
30
+ * reset({ replace: true })
31
+ *
20
32
  * ```
21
33
  *
22
34
  * * Docs {@link https://github.com/asmyshlyaev177/state-in-url/tree/integrations/packages/urlstate/useUrlStateBase#api}
@@ -27,6 +39,7 @@ export declare function useUrlStateBase<T extends JSONCompatible>(defaultState:
27
39
  updateState: (value: Partial<T> | ((currState: T) => T)) => void;
28
40
  updateUrl: (value?: Parameters<(value: Partial<T> | ((currState: T) => T)) => void>[0], options?: Options) => void;
29
41
  state: T;
42
+ reset: (options?: Options) => void;
30
43
  getState: () => T;
31
44
  };
32
45
  interface OptionsObject {
@@ -1 +1 @@
1
- import t from"react";import{useInsertionEffect as e}from"../useInsertionEffect.mjs";import{useSharedState as n}from"../useSharedState/useSharedState.mjs";import{useUrlEncode as o}from"../useUrlEncode/useUrlEncode.mjs";import{filterUnknownParamsClient as r}from"../utils.mjs";function s(s,c,i){const{parse:u,stringify:l}=o(s),{state:p,getState:d,setState:h}=n(s,(()=>i?.({parse:u})||s));e((()=>{const t=()=>{const t=u(r(s));h(t)};return window.addEventListener(a,t),()=>{window.removeEventListener(a,t)}}),[h]);const m=t.useRef([]),w=t.useCallback(((t,e)=>{const n="function"==typeof t?t(d()):t?{...d(),...t}:d(),o=l(n,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}(s)),r=`${window.location.pathname}${o.length?"?":""}${o}${window.location.hash}`;if(r===`${window.location.pathname}${window.location.search}${window.location.hash}`)return;let a;h(n);const i=e?.replace;delete e?.replace,m.current.push([i?"replace":"push",r,e]),1===m.current.length&&queueMicrotask((()=>{for(;m.current.length;){const t=m.current.shift();t&&t?.[1]!==a?.[1]&&(a=t)}const[t,e,n]=a||{};a=void 0,t&&c[t](e,n)}))}),[c,l,d]);return{updateState:h,updateUrl:w,state:p,getState:d}}const a="popstate";export{s as useUrlStateBase};
1
+ import e from"react";import{useInsertionEffect as t}from"../useInsertionEffect.mjs";import{useSharedState as n}from"../useSharedState/useSharedState.mjs";import{useUrlEncode as o}from"../useUrlEncode/useUrlEncode.mjs";import{filterUnknownParamsClient as r}from"../utils.mjs";function s(s,c,i){const{parse:u,stringify:l}=o(s),{state:p,getState:d,setState:h}=n(s,(()=>i?.({parse:u})||s));t((()=>{const e=()=>{const e=u(r(s));h(e)};return window.addEventListener(a,e),()=>{window.removeEventListener(a,e)}}),[h]);const m=e.useRef([]),w=e.useCallback(((e,t)=>{const n="function"==typeof e?e(d()):e?{...d(),...e}:d(),o=l(n,function(e){const t=Object.keys(e),n=window.location.search,o=new URLSearchParams(n),r=new URLSearchParams;return o.forEach(((e,n)=>!t.includes(n)&&r.set(n,e))),r}(s)),r=`${window.location.pathname}${o.length?"?":""}${o}${window.location.hash}`;if(r===`${window.location.pathname}${window.location.search}${window.location.hash}`)return;let a;h(n);const i=t?.replace;delete t?.replace,m.current.push([i?"replace":"push",r,t]),1===m.current.length&&queueMicrotask((()=>{for(;m.current.length;){const e=m.current.shift();e&&e?.[1]!==a?.[1]&&(a=e)}const[e,t,n]=a||{};a=void 0,e&&c[e](t,n)}))}),[c,l,d]),f=e.useCallback((e=>{w(s,e)}),[w]);return{updateState:h,updateUrl:w,state:p,reset:f,getState:d}}const a="popstate";export{s as useUrlStateBase};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "state-in-url",
3
- "version": "4.0.9",
3
+ "version": "4.1.0",
4
4
  "description": "Easily share complex state objects between unrelated React components, preserve types and structure, with TS validation. Deep links and url state synchronization wthout any hasssle or boilerplate.",
5
5
  "homepage": "https://state-in-url.dev",
6
6
  "repository": {