Skip to content

Commit

Permalink
chore(release): 4.1.0 [skip ci]
Browse files Browse the repository at this point in the history
# [4.1.0](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](68fc693))
  • Loading branch information
semantic-release-bot committed Nov 15, 2024
1 parent 3f00560 commit 4f97d2b
Show file tree
Hide file tree
Showing 8 changed files with 54 additions and 10 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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)


Expand Down
18 changes: 15 additions & 3 deletions dist/next/useUrlState/useUrlState.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,31 @@ export declare function useUrlState<T extends JSONCompatible>({ defaultState: T,
*
* @param {JSONCompatible<T>} [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<T>} 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:
* ```ts
* 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}
Expand All @@ -43,6 +52,9 @@ export declare function useUrlState<T extends JSONCompatible>(defaultState: T, p
urlState: T;
setState: (value: Partial<T> | ((currState: T) => T)) => void;
setUrl: (value?: Partial<T> | ((currState: T) => T), options?: Options) => void;
reset: (options?: Options & {
[key: string]: unknown;
}) => void;
};
type Router = ReturnType<typeof useRouter>;
type RouterOptions = NonNullable<Parameters<Router["push"]>[1] | Parameters<Router["replace"]>[1]>;
Expand Down
2 changes: 1 addition & 1 deletion dist/next/useUrlState/useUrlState.mjs
Original file line number Diff line number Diff line change
@@ -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};
14 changes: 13 additions & 1 deletion dist/react-router/useUrlState/useUrlState.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,14 @@ export declare function useUrlState<T extends JSONCompatible>({ defaultState: T,
* @param {JSONCompatible<T>} [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 };
Expand All @@ -32,6 +37,10 @@ export declare function useUrlState<T extends JSONCompatible>({ 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}
Expand All @@ -40,6 +49,9 @@ export declare function useUrlState<T extends JSONCompatible>(defaultState: T, p
urlState: T;
setState: (value: Partial<T> | ((currState: T) => T)) => void;
setUrl: (value?: Partial<T> | ((currState: T) => T), options?: Params) => void;
reset: (options?: NavigateOptions & {
[key: string]: unknown;
}) => void;
};
type OldParams<T> = {
defaultState: T;
Expand Down
2 changes: 1 addition & 1 deletion dist/react-router/useUrlState/useUrlState.mjs
Original file line number Diff line number Diff line change
@@ -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};
17 changes: 15 additions & 2 deletions dist/useUrlStateBase/useUrlStateBase.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -27,6 +39,7 @@ export declare function useUrlStateBase<T extends JSONCompatible>(defaultState:
updateState: (value: Partial<T> | ((currState: T) => T)) => void;
updateUrl: (value?: Parameters<(value: Partial<T> | ((currState: T) => T)) => void>[0], options?: Options) => void;
state: T;
reset: (options?: Options) => void;
getState: () => T;
};
interface OptionsObject {
Expand Down
2 changes: 1 addition & 1 deletion dist/useUrlStateBase/useUrlStateBase.mjs
Original file line number Diff line number Diff line change
@@ -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};
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down

0 comments on commit 4f97d2b

Please sign in to comment.