diff --git a/README.md b/README.md index 0a861e7..35c2b5c 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 b929662..72bebb3 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..1a7a28c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,6 +11,7 @@ import type { _TemporalState, Write, ZundoOptions, + HandleSet, } from './types'; type Zundo = < @@ -50,40 +51,34 @@ 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 handleSet: HandleSet = ( + pastState, + currentState, + deltaState, ) => { - if (store.temporal.getState().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 - ) { - 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: [], - }); + // 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 as StoreApi['setState']) || - handleSet; + 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(); @@ -92,14 +87,11 @@ 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, 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 562405e..1c17d0d 100644 --- a/tests/__tests__/options.test.ts +++ b/tests/__tests__/options.test.ts @@ -587,9 +587,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); }; }, }); @@ -689,9 +689,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); }, }); @@ -781,10 +781,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 @@ -833,10 +833,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 @@ -900,10 +900,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