From 4f97d2bb006174a40cf483c62e7fd222fcd7c48e Mon Sep 17 00:00:00 2001 From: semantic-release-bot Date: Fri, 15 Nov 2024 19:56:34 +0000 Subject: [PATCH] chore(release): 4.1.0 [skip ci] # [4.1.0](https://github.com/asmyshlyaev177/state-in-url/compare/v4.0.9...v4.1.0) (2024-11-15) ### Features * **useurlstate:** return `reset` cb from `useUrlState`, it can reset state and URL to default ([68fc693](https://github.com/asmyshlyaev177/state-in-url/commit/68fc69347be80d511232e5805207734d2865b54a)) --- CHANGELOG.md | 7 +++++++ dist/next/useUrlState/useUrlState.d.ts | 18 +++++++++++++++--- dist/next/useUrlState/useUrlState.mjs | 2 +- dist/react-router/useUrlState/useUrlState.d.ts | 14 +++++++++++++- dist/react-router/useUrlState/useUrlState.mjs | 2 +- dist/useUrlStateBase/useUrlStateBase.d.ts | 17 +++++++++++++++-- dist/useUrlStateBase/useUrlStateBase.mjs | 2 +- package.json | 2 +- 8 files changed, 54 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 147b861..b32571b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [4.1.0](https://github.com/asmyshlyaev177/state-in-url/compare/v4.0.9...v4.1.0) (2024-11-15) + + +### Features + +* **useurlstate:** return `reset` cb from `useUrlState`, it can reset state and URL to default ([68fc693](https://github.com/asmyshlyaev177/state-in-url/commit/68fc69347be80d511232e5805207734d2865b54a)) + ## [4.0.9](https://github.com/asmyshlyaev177/state-in-url/compare/v4.0.8...v4.0.9) (2024-11-14) diff --git a/dist/next/useUrlState/useUrlState.d.ts b/dist/next/useUrlState/useUrlState.d.ts index 122d999..21f382a 100644 --- a/dist/next/useUrlState/useUrlState.d.ts +++ b/dist/next/useUrlState/useUrlState.d.ts @@ -19,10 +19,15 @@ export declare function useUrlState({ defaultState: T, * * @param {JSONCompatible} [defaultState] Fallback (default) values for state * @param {Object} params - Object with other parameters, including params from App router - * @param {boolean} params.replace replace URL of push, default `true` - * @param {boolean} params.useHistory use window.history for navigation, default true, no _rsc requests https://github.com/vercel/next.js/discussions/59167 + * @param {boolean} params.replace replace URL or push, default `true` + * @param {boolean} params.useHistory use window.history for navigation, default `true`, no _rsc requests https://github.com/vercel/next.js/discussions/59167 * @param {?SearchParams} params.searchParams searchParams from Next server component * @param {boolean} params.scroll reset scroll, default `false` + * @returns {Object} [result] State and callbacks + * @returns {Object} [result.state] - current state object + * @returns {Function} [result.setUrl] - function to update state and url + * @returns {Function} [result.setState] - function to update state only + * @returns {Function} [result.reset] - function to reset state and url to default * * * Example: @@ -30,11 +35,15 @@ export declare function useUrlState({ defaultState: T, * export const form = { name: '', age: 0 }; * const { urlState, setState, setUrl } = useUrlState(form); * // for nextjs server components - * const { urlState, setState, setUrl } = useUrlState(form, { searchParams }); + * const { urlState, setState, setUrl, reset } = useUrlState(form, { searchParams }); * * setState({ name: 'test' }); * setUrl({ name: 'test' }, { replace: true, scroll: true }); * setUrl(curr => ({ ...curr, name: 'test' }), { replace: true, scroll: true }); + * // reset state and url + * reset(); + * reset({ replace: true }); + * // same as setState(form) with setUrl(form) * ``` * * * Docs {@link https://github.com/asmyshlyaev177/state-in-url/tree/master/packages/urlstate/next/useUrlState#api} @@ -43,6 +52,9 @@ export declare function useUrlState(defaultState: T, p urlState: T; setState: (value: Partial | ((currState: T) => T)) => void; setUrl: (value?: Partial | ((currState: T) => T), options?: Options) => void; + reset: (options?: Options & { + [key: string]: unknown; + }) => void; }; type Router = ReturnType; type RouterOptions = NonNullable[1] | Parameters[1]>; diff --git a/dist/next/useUrlState/useUrlState.mjs b/dist/next/useUrlState/useUrlState.mjs index 7f59318..ca791af 100644 --- a/dist/next/useUrlState/useUrlState.mjs +++ b/dist/next/useUrlState/useUrlState.mjs @@ -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}; +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}; diff --git a/dist/react-router/useUrlState/useUrlState.d.ts b/dist/react-router/useUrlState/useUrlState.d.ts index b4e10fe..8adfba8 100644 --- a/dist/react-router/useUrlState/useUrlState.d.ts +++ b/dist/react-router/useUrlState/useUrlState.d.ts @@ -20,9 +20,14 @@ export declare function useUrlState({ defaultState: T, * @param {JSONCompatible} [defaultState] Fallback (default) values for state * @param {Object} params - Object with other parameters * @param {NavigateOptions} params.NavigateOptions See type from `react-router-dom` - * @param {boolean} params.replace replace URL of push, default `true` + * @param {boolean} params.replace replace URL or push, default `true` * @param {boolean} params.useHistory use window.history for navigation, default `false` * @param {boolean} params.preventScrollReset keep scroll position, default `true` + * @returns {Object} [result] State and callbacks + * @returns {Object} [result.state] - current state object + * @returns {Function} [result.setUrl] - function to update state and url + * @returns {Function} [result.setState] - function to update state only + * @returns {Function} [result.reset] - function to reset state and url to default * * Example: * ```ts * export const form = { name: '', age: 0 }; @@ -32,6 +37,10 @@ export declare function useUrlState({ defaultState: T, * setUrl({ name: 'test' }, { replace: true }); * // similar to React.useState * setUrl(curr => ({ ...curr, name: 'test' }), { replace: true }); + * // reset state and url + * reset(); + * reset({ replace: true }); + * // same as setState(form) with setUrl(form) * ``` * * * 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(defaultState: T, p urlState: T; setState: (value: Partial | ((currState: T) => T)) => void; setUrl: (value?: Partial | ((currState: T) => T), options?: Params) => void; + reset: (options?: NavigateOptions & { + [key: string]: unknown; + }) => void; }; type OldParams = { defaultState: T; diff --git a/dist/react-router/useUrlState/useUrlState.mjs b/dist/react-router/useUrlState/useUrlState.mjs index 7915dde..e94f80a 100644 --- a/dist/react-router/useUrlState/useUrlState.mjs +++ b/dist/react-router/useUrlState/useUrlState.mjs @@ -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}; +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}; diff --git a/dist/useUrlStateBase/useUrlStateBase.d.ts b/dist/useUrlStateBase/useUrlStateBase.d.ts index b10547b..7374130 100644 --- a/dist/useUrlStateBase/useUrlStateBase.d.ts +++ b/dist/useUrlStateBase/useUrlStateBase.d.ts @@ -7,16 +7,28 @@ import { type JSONCompatible, type Router } from "../utils"; * @param {T} defaultState - An object representing the default state values. * @param {Router} router - Router object with [push] and [replace] methods. * @param {Function} [getInitialState] - Optional function to get the initial state, passes `parse`, and `filterUnknownParams` helpers - * @returns {Object} An object containing `state`, `getState`, `updateState`, and `updateUrl` properties. + * @returns {Object} [result] State and callbacks + * @returns {Object} [result.state] - current state object + * @returns {Function} [result.updateUrl] - function to update state and url + * @returns {Function} [result.updateState] - function to update state only + * @returns {Function} [result.reset] - function to reset state and url to default * * * * Example: * ```ts * export const form = { name: '' }; * const router = { push: () => {}, replace: () => {} }; - * const { state, updateState, updateUrl } = useUrlStateBase(form, router, ({ parse, filterClientSP }) => + * const { state, updateState, updateUrl, reset } = useUrlStateBase(form, router, ({ parse, filterClientSP }) => * isSSR() ? getServerState() : getClientState() * ); + * + * updateState({ name: 'John' }); + * updateState(curr => ({ ...curr, name: 'John' })); + * updateUrl({ name: 'John' }, { replace: true }); + * updateUrl(curr => ({ ...curr, name: 'John' }), { replace: true }); + * reset() + * reset({ replace: true }) + * * ``` * * * Docs {@link https://github.com/asmyshlyaev177/state-in-url/tree/integrations/packages/urlstate/useUrlStateBase#api} @@ -27,6 +39,7 @@ export declare function useUrlStateBase(defaultState: updateState: (value: Partial | ((currState: T) => T)) => void; updateUrl: (value?: Parameters<(value: Partial | ((currState: T) => T)) => void>[0], options?: Options) => void; state: T; + reset: (options?: Options) => void; getState: () => T; }; interface OptionsObject { diff --git a/dist/useUrlStateBase/useUrlStateBase.mjs b/dist/useUrlStateBase/useUrlStateBase.mjs index 8138975..5962771 100644 --- a/dist/useUrlStateBase/useUrlStateBase.mjs +++ b/dist/useUrlStateBase/useUrlStateBase.mjs @@ -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}; +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}; diff --git a/package.json b/package.json index f76081d..989060d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "state-in-url", - "version": "4.0.9", + "version": "4.1.0", "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.", "homepage": "https://state-in-url.dev", "repository": {