diff --git a/README.md b/README.md index af76bd1..8531b84 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🍜 Zundo -undo middleware for [zustand](https://github.com/pmndrs/zustand). built with zustand. +enable time-travel in your apps. undo/redo middleware for [zustand](https://github.com/pmndrs/zustand). built with zustand. [![Build Size](https://img.shields.io/bundlephobia/min/zundo?label=bundle%20size&style=flat&colorA=000000&colorB=000000)](https://bundlephobia.com/result?p=zundo) [![Version](https://img.shields.io/npm/v/zundo?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/zundo) @@ -38,7 +38,7 @@ Use your store anywhere and get undo from `zundo` and add it to a button to go b ```tsx const App = () => { - const { undo } = useUndo(); + const { undo, redo } = useUndo(); const { bears, increasePopulation, removeAllBears } = useStore(); return ( @@ -47,15 +47,43 @@ const App = () => { + ); }; ``` +## API + +### `undo()` + +Middleware for Zustand to add the ability to time travel through states. + +```tsx +import create from 'zustand'; +import { undo } from 'zundo'; + +const useStore = create( + undo(() => ({ ... })) +); +``` + +### `useUndo()` + +Hook that provides reference to a store containing actions that undo/redo states for your main store when called. + +```tsx +const { undo, redo } = useUndo(); +``` + +- `undo`: call function to apply previous state (if there are previous states) +- `redo`: call function to apply future state (if there are future states). Future states are "previous previous states." + +Dispatching a new state will clear all of the future states. + ## Road Map -- add redo. probably with index to traverse through prevStates -- possibly use better data structure for storing prevous states. Maybe just a diff between states? +- possibly use better data structure for storing previous states. Maybe just a diff between states? - clean up api? return `undo` with the store hook? ## Contributing diff --git a/package.json b/package.json index 2c3198b..49853bc 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "zundo", "version": "0.1.3", "private": false, - "description": "🍜 Undo middleware for zustand", + "description": "🍜 undo/redo middleware for zustand", "keywords": [ "undo", "middleware", diff --git a/src/index.ts b/src/index.ts index 952109c..3a05f2a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,17 +11,35 @@ import create from 'zustand'; interface UndoStoreState extends State { prevStates: any[]; + futureStates: any[]; undo: () => void; - handle: Function; + redo: () => void; + setStore: Function; + getStore: Function; } // Stores previous actions const undoStore = createVanilla((_, get) => ({ prevStates: [], undo: () => { - get().handle(get().prevStates.pop()); + const prevStates = get().prevStates; + if (prevStates.length > 0) { + const prevState = prevStates.pop(); + get().futureStates.push(get().getStore()); + get().setStore(prevState); + } + }, + setStore: () => {}, + getStore: () => {}, + futureStates: [], + redo: () => { + const futureStates = get().futureStates; + if (futureStates.length > 0) { + const futureState = futureStates.pop(); + get().prevStates.push(get().getStore()); + get().setStore(futureState); + } }, - handle: () => {}, })); const { getState, setState } = undoStore; export const useUndo = create(undoStore); @@ -36,7 +54,9 @@ export const undo = (config: StateCreator) => ( args => { setState({ prevStates: [...getState().prevStates, { ...get() }], - handle: set, + setStore: set, + futureStates: [], + getStore: get, }); set(args); }, diff --git a/stories/bears.stories.tsx b/stories/bears.stories.tsx index a781d67..f78ac0a 100644 --- a/stories/bears.stories.tsx +++ b/stories/bears.stories.tsx @@ -35,14 +35,19 @@ const useStore = create( ); const App = () => { - const { prevStates, undo } = useUndo(); - const { bears, increasePopulation, removeAllBears } = useStore(); + const { prevStates, undo, futureStates, redo } = useUndo(); + const store = useStore(); + const { bears, increasePopulation, removeAllBears } = store; return (

🐻 ♻️ Zundo!

previous states: {JSON.stringify(prevStates)}
+ future states: {JSON.stringify(futureStates)} +
+ current state: {JSON.stringify(store)} +

bears: {bears}
@@ -50,6 +55,7 @@ const App = () => {
+
); };