From 773f295fd9794616f9f479e2efde5d9291d2f84e Mon Sep 17 00:00:00 2001 From: unadlib Date: Mon, 25 Mar 2024 02:39:10 +0800 Subject: [PATCH] feat(archive): imlement canArchive() API --- README.md | 3 ++- package.json | 2 +- src/index.ts | 11 +++++++++-- test/index.test.ts | 47 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 55 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ae76016..bd95d16 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ yarn add use-travel mutative ### API -You can use `useTravel` to create a time travel state. And it returns a tuple with the current state, the state setter, and the controls. The controls include `back()`, `forward()`, `reset()`, `canBack()`, `canForward()`, `getHistory()`, `patches`, `position`, `archive()`, and `go()`. +You can use `useTravel` to create a time travel state. And it returns a tuple with the current state, the state setter, and the controls. The controls include `back()`, `forward()`, `reset()`, `canBack()`, `canForward()`, `canArchive()`, `getHistory()`, `patches`, `position`, `archive()`, and `go()`. ```jsx import { useTravel } from 'use-travel'; @@ -105,6 +105,7 @@ const App = () => { | `controls.reset` | () => void | Reset the state to the initial state | | `controls.canBack` | () => boolean | Check if can go back to the previous state | | `controls.canForward` | () => boolean | Check if can go forward to the next state | +| `controls.canArchive` | () => boolean | Check if can archive the current state | | `controls.getHistory` | () => T[] | Get the history of the state | | `controls.patches` | TravelPatches[] | Get the patches history of the state | | `controls.position` | number | Get the current position of the state | diff --git a/package.json b/package.json index d81f9e0..99c9649 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "use-travel", - "version": "1.0.2", + "version": "1.0.3", "description": "A React hook for state time travel with undo, redo, reset and archive functionalities.", "main": "dist/index.cjs.js", "unpkg": "dist/index.umd.js", diff --git a/src/index.ts b/src/index.ts index 01ba20b..4dd0639 100644 --- a/src/index.ts +++ b/src/index.ts @@ -88,6 +88,10 @@ type Result = [ * Archive the current state */ archive: () => void; + /** + * Check if it's possible to archive the current state + */ + canArchive: () => boolean; } : Controls ]; @@ -221,7 +225,7 @@ export const useTravel = ( }); }; const shouldArchive = useMemo( - () => !autoArchive && tempPatches.patches.length, + () => !autoArchive && !!tempPatches.patches.length, [tempPatches] ); const _allPatches = useMemo(() => { @@ -232,7 +236,9 @@ export const useTravel = ( inversePatches: allPatches.inversePatches.concat(), }; mergedPatches.patches.push(tempPatches.patches.flat()); - mergedPatches.inversePatches.push(tempPatches.inversePatches.flat().reverse()); + mergedPatches.inversePatches.push( + tempPatches.inversePatches.flat().reverse() + ); } return mergedPatches; }, [allPatches, tempPatches, shouldArchive]); @@ -322,6 +328,7 @@ export const useTravel = ( shouldArchive ? position < _allPatches.patches.length - 1 : position < allPatches.patches.length, + canArchive: () => shouldArchive, archive, }; }, [ diff --git a/test/index.test.ts b/test/index.test.ts index 9294f40..bdd1d8e 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1509,15 +1509,54 @@ describe('useTravel', () => { expect(nextState).toEqual(2); expect(controls.position).toEqual(1); expect(controls.getHistory()).toEqual([0, 2]); - - - // act(() => controls.archive()); - // [nextState, setState, controls] = result.current; + expect(controls.canBack()).toBe(true); + expect(controls.canForward()).toBe(false); + expect(controls.canArchive()).toBe(true); act(() => controls.back()); [nextState, setState, controls] = result.current; expect(nextState).toEqual(0); expect(controls.position).toEqual(0); expect(controls.getHistory()).toEqual([0, 2]); + expect(controls.canBack()).toBe(false); + expect(controls.canForward()).toBe(true); + expect(controls.canArchive()).toBe(false); + }); + + it('[useTravel] - back() with autoArchive: false', () => { + let { result } = renderHook(() => + useTravel(0, { + maxHistory: 3, + autoArchive: false, + }) + ); + let [nextState, setState, controls] = result.current; + expect(nextState).toEqual(0); + expect(controls.position).toEqual(0); + expect(controls.getHistory()).toEqual([0]); + + act(() => setState(() => 1)); + [nextState, setState, controls] = result.current; + expect(nextState).toEqual(1); + expect(controls.position).toEqual(1); + expect(controls.getHistory()).toEqual([0, 1]); + + act(() => setState(() => 2)); + [nextState, setState, controls] = result.current; + expect(nextState).toEqual(2); + expect(controls.position).toEqual(1); + expect(controls.getHistory()).toEqual([0, 2]); + expect(controls.canBack()).toBe(true); + expect(controls.canForward()).toBe(false); + expect(controls.canArchive()).toBe(true); + + act(() => controls.archive()); + [nextState, setState, controls] = result.current; + expect(nextState).toEqual(2); + expect(controls.position).toEqual(1); + expect(controls.getHistory()).toEqual([0, 2]); + expect(controls.canBack()).toBe(true); + expect(controls.canForward()).toBe(false); + expect(controls.canArchive()).toBe(false); }); });