From 10976c5849441077cc3022bb346b3a23ec9e0e07 Mon Sep 17 00:00:00 2001 From: Charles Kornoelje <33156025+charkour@users.noreply.github.com> Date: Sat, 9 Mar 2024 21:24:22 -0500 Subject: [PATCH 1/2] simplify handle set --- README.md | 38 +++++++++++++++++++++++++++++++-- examples/web/pages/chained.tsx | 4 ++-- examples/web/pages/index.tsx | 4 ++-- examples/web/pages/options.tsx | 4 ++-- src/index.ts | 27 +++++++++++------------ src/types.ts | 20 +++++++++++------ tests/__tests__/options.test.ts | 20 ++++++++--------- 7 files changed, 78 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index fe49eaf..2ace909 100644 --- a/README.md +++ b/README.md @@ -398,9 +398,9 @@ const useStoreWithUndo = create()( }), { handleSet: (handleSet) => - throttle((state) => { + throttle((...args) => { console.info('handleSet called'); - handleSet(state); + handleSet(...args); }, 1000), }, ), @@ -559,6 +559,40 @@ PRs are welcome! [pnpm](https://pnpm.io/) is used as a package manager. Run `pnp - [canUndo, canRedo, undoDepth, redoDepth](https://codesandbox.io/s/zundo-canundo-and-undodepth-l6jclx?file=/src/App.tsx:572-731) - [with deep equal](https://codesandbox.io/p/sandbox/zundo-deep-equal-qg69lj) +## Migrate from v2 to v3 + +
+Click to expand + +## v3.0.0 + +### Breaking Changes + +#### `wrapTemporal` behavior changes + +If you were previously modifying the store with returning a new `set` in the `config`, you'll need to overwrite the `store.setState` function. + +```tsx +// v2.0.0 + +// v3.0.0 + +``` + +#### `handleSet` argument + +The second parameter of `handleSet` has been removed. If you were previously using `replace` in `handleSet`, you'll need to modify your `handleSet` function. + +```tsx +// v2.0.0 + + +// v3.0.0 + +``` + +
+ ## Migrate from v1 to v2
diff --git a/examples/web/pages/chained.tsx b/examples/web/pages/chained.tsx index defbb45..ae13a06 100644 --- a/examples/web/pages/chained.tsx +++ b/examples/web/pages/chained.tsx @@ -17,9 +17,9 @@ interface MyState { // }), // { // handleSet: (handleSet) => -// throttle((state) => { +// throttle((...args) => { // console.error('handleSet called'); -// handleSet(state); +// handleSet(...args); // }, 1000), // }, // ); diff --git a/examples/web/pages/index.tsx b/examples/web/pages/index.tsx index 866bad8..e95fe27 100644 --- a/examples/web/pages/index.tsx +++ b/examples/web/pages/index.tsx @@ -17,9 +17,9 @@ const withZundo = temporal( }), { handleSet: (handleSet) => - throttle((state) => { + throttle((...args) => { console.info('handleSet called'); - handleSet(state); + handleSet(...args); }, 1000), }, ); diff --git a/examples/web/pages/options.tsx b/examples/web/pages/options.tsx index f22bf2e..f01c65f 100644 --- a/examples/web/pages/options.tsx +++ b/examples/web/pages/options.tsx @@ -28,8 +28,8 @@ const useMyStore = create()( { equality: deepEqual, handleSet: (handleSet) => - throttle((state) => { - handleSet(state); + throttle((...args) => { + handleSet(...args); }, 500), partialize: (state): HistoryTrackedState => { const { untrackedValue, ...trackedValues } = state; diff --git a/src/index.ts b/src/index.ts index 454b28b..d135a8e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ import type { _TemporalState, Write, ZundoOptions, + HandleSet, } from './types'; type Zundo = < @@ -50,23 +51,23 @@ export const temporal = (( temporalStateCreator(set, get, options), ); - const handleSet = ( - pastState: TState, - // `replace` will likely be deprecated and removed in the future - replace: boolean | undefined, - currentState: TState, - deltaState?: Partial, + const getTemporal = store.temporal.getState; + + const handleSet: HandleSet = ( + pastState, + currentState, + deltaState, ) => { - if (store.temporal.getState().isTracking) { + if (getTemporal().isTracking) { // This naively assumes that only one new state can be added at a time if ( options?.limit && - store.temporal.getState().pastStates.length >= options?.limit + getTemporal().pastStates.length >= options?.limit ) { - store.temporal.getState().pastStates.shift(); + getTemporal().pastStates.shift(); } - (store.temporal.getState() as _TemporalState)._onSave?.( + (getTemporal() as _TemporalState)._onSave?.( pastState, currentState, ); @@ -79,9 +80,7 @@ export const temporal = (( } }; - const curriedHandleSet = - options?.handleSet?.(handleSet as StoreApi['setState']) || - handleSet; + const curriedHandleSet = options?.handleSet?.(handleSet) || handleSet; const temporalHandleSet = (pastState: TState) => { if (!store.temporal.getState().isTracking) return; @@ -99,7 +98,7 @@ export const temporal = (( ) ) ) { - curriedHandleSet(pastState, undefined, currentState, deltaState); + curriedHandleSet(pastState, currentState, deltaState); } }; diff --git a/src/types.ts b/src/types.ts index 75b68c2..3bb980d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,6 +4,12 @@ type onSave = | ((pastState: TState, currentState: TState) => void) | undefined; +export type HandleSet = ( + pastState: Partial, + currentState: Partial, + deltaState?: Partial | null, +) => void; + export interface _TemporalState { pastStates: Partial[]; futureStates: Partial[]; @@ -16,8 +22,8 @@ export interface _TemporalState { pause: () => void; resume: () => void; - setOnSave: (onSave: onSave) => void; - _onSave: onSave; + setOnSave: (onSave: onSave>) => void; + _onSave: onSave>; } export interface ZundoOptions { @@ -28,11 +34,11 @@ export interface ZundoOptions { pastState: Partial, currentState: Partial, ) => Partial | null; - onSave?: onSave; - handleSet?: (handleSet: StoreApi['setState']) => ( - pastState: Parameters['setState']>[0], - // `replace` will likely be deprecated and removed in the future - replace: Parameters['setState']>[1], + onSave?: onSave>; + handleSet?: ( + handleSet: HandleSet>, + ) => ( + pastState: TState, currentState: PartialTState, deltaState?: Partial | null, ) => void; diff --git a/tests/__tests__/options.test.ts b/tests/__tests__/options.test.ts index 3e27dd9..aec65ea 100644 --- a/tests/__tests__/options.test.ts +++ b/tests/__tests__/options.test.ts @@ -565,9 +565,9 @@ describe('Middleware options', () => { global.console.info = vi.fn(); const storeWithHandleSet = createVanillaStore({ handleSet: (handleSet) => { - return (state) => { + return (...args) => { console.info('handleSet called'); - handleSet(state); + handleSet(...args); }; }, }); @@ -667,9 +667,9 @@ describe('Middleware options', () => { vi.useFakeTimers(); const storeWithHandleSet = createVanillaStore({ handleSet: (handleSet) => { - return throttle((state) => { + return throttle((...args) => { console.error('handleSet called'); - handleSet(state); + handleSet(...args); }, 1000); }, }); @@ -759,10 +759,10 @@ describe('Middleware options', () => { const storeWithHandleSetAndPartializeAndEquality = createVanillaStore({ handleSet: (handleSet) => { return throttle( - (state) => { + (...args) => { // used for determining how many times `handleSet` is called console.error('handleSet called'); - handleSet(state); + handleSet(...args); }, throttleIntervalInMs, // Call throttle only on leading edge of timeout @@ -811,10 +811,10 @@ describe('Middleware options', () => { const storeWithHandleSetAndPartializeAndDiff = createVanillaStore({ handleSet: (handleSet) => { return throttle( - (state) => { + (...args) => { // used for determining how many times `handleSet` is called console.error('handleSet called'); - handleSet(state); + handleSet(...args); }, throttleIntervalInMs, // Call throttle only on leading edge of timeout @@ -878,10 +878,10 @@ describe('Middleware options', () => { const storeWithHandleSetAndPartializeAndDiff = createVanillaStore({ handleSet: (handleSet) => { return throttle( - (state) => { + (...args) => { // used for determining how many times `handleSet` is called console.error('handleSet called'); - handleSet(state); + handleSet(...args); }, throttleIntervalInMs, // Call throttle only on leading edge of timeout From 204741610c58cccd8f1e253e2c77921cac6376ff Mon Sep 17 00:00:00 2001 From: Charles Kornoelje <33156025+charkour@users.noreply.github.com> Date: Sat, 9 Mar 2024 21:58:04 -0500 Subject: [PATCH 2/2] remove extra `isTracking` check --- src/index.ts | 47 ++++++++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/src/index.ts b/src/index.ts index d135a8e..1a7a28c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -51,38 +51,34 @@ export const temporal = (( temporalStateCreator(set, get, options), ); - const getTemporal = store.temporal.getState; - const handleSet: HandleSet = ( pastState, currentState, deltaState, ) => { - if (getTemporal().isTracking) { - // This naively assumes that only one new state can be added at a time - if ( - options?.limit && - getTemporal().pastStates.length >= options?.limit - ) { - getTemporal().pastStates.shift(); - } - - (getTemporal() as _TemporalState)._onSave?.( - pastState, - currentState, - ); - store.temporal.setState({ - pastStates: store.temporal - .getState() - .pastStates.concat(deltaState || pastState), - futureStates: [], - }); + // This naively assumes that only one new state can be added at a time + if ( + options?.limit && + store.temporal.getState().pastStates.length >= options?.limit + ) { + store.temporal.getState().pastStates.shift(); } + + (store.temporal.getState() as _TemporalState)._onSave?.( + pastState, + currentState, + ); + store.temporal.setState({ + pastStates: store.temporal + .getState() + .pastStates.concat(deltaState || pastState), + futureStates: [], + }); }; const curriedHandleSet = options?.handleSet?.(handleSet) || handleSet; - const temporalHandleSet = (pastState: TState) => { + const temporalHandleSet = (pastState: TState): void => { if (!store.temporal.getState().isTracking) return; const currentState = options?.partialize?.(get()) || get(); @@ -91,11 +87,8 @@ export const temporal = (( // Don't call handleSet if state hasn't changed, as determined by diff fn or equality fn !( // If the user has provided a diff function but nothing has been changed, deltaState will be null - ( - deltaState === null || - // If the user has provided an equality function, use it - options?.equality?.(pastState, currentState) - ) + // If the user has provided an equality function, use it + (deltaState === null || options?.equality?.(pastState, currentState)) ) ) { curriedHandleSet(pastState, currentState, deltaState);