import { useCallback, useState } from "react" /** * Base interface for a command that can be managed * by the `useCommandHistory` hook. */ export interface Command { execute: () => void undo: () => void redo: () => void } /** * Hook to manage a history of commands that can be undone, redone, and executed. */ export const useCommandHistory = (maxHistory = 20) => { const [past, setPast] = useState([]) const [future, setFuture] = useState([]) const canUndo = past.length > 0 const canRedo = future.length > 0 const undo = useCallback(() => { if (!canUndo) { return } const previous = past[past.length - 1] const newPast = past.slice(0, past.length - 1) previous.undo() setPast(newPast) setFuture([previous, ...future.slice(0, maxHistory - 1)]) }, [canUndo, future, past, maxHistory]) const redo = useCallback(() => { if (!canRedo) { return } const next = future[0] const newFuture = future.slice(1) next.redo() setPast([...past, next].slice(0, maxHistory - 1)) setFuture(newFuture) }, [canRedo, future, past, maxHistory]) const execute = useCallback( (command: Command) => { command.execute() setPast((past) => [...past, command].slice(0, maxHistory - 1)) setFuture([]) }, [maxHistory] ) return { undo, redo, execute, canUndo, canRedo, } }