import { useState, useCallback, useRef } from 'react' export interface UndoRedoState { past: T[] present: T future: T[] } interface UseUndoRedoReturn { state: T setState: (newState: T | ((prev: T) => T)) => void undo: () => void redo: () => void canUndo: boolean canRedo: boolean clear: () => void } const MAX_HISTORY_SIZE = 50 export function useUndoRedo(initialState: T): UseUndoRedoReturn { const [history, setHistory] = useState>({ past: [], present: initialState, future: [], }) // Track if we're in an undo/redo operation to prevent adding to history const isUndoRedoAction = useRef(false) const setState = useCallback((newState: T | ((prev: T) => T)) => { // Skip if this is an undo/redo action if (isUndoRedoAction.current) { isUndoRedoAction.current = false return } setHistory((currentHistory) => { const resolvedNewState = typeof newState === 'function' ? (newState as (prev: T) => T)(currentHistory.present) : newState // Don't add to history if state hasn't changed if (JSON.stringify(resolvedNewState) === JSON.stringify(currentHistory.present)) { return currentHistory } const newPast = [...currentHistory.past, currentHistory.present] // Limit history size if (newPast.length > MAX_HISTORY_SIZE) { newPast.shift() } return { past: newPast, present: resolvedNewState, future: [], // Clear future on new action } }) }, []) const undo = useCallback(() => { setHistory((currentHistory) => { if (currentHistory.past.length === 0) return currentHistory const previous = currentHistory.past[currentHistory.past.length - 1] const newPast = currentHistory.past.slice(0, currentHistory.past.length - 1) isUndoRedoAction.current = true return { past: newPast, present: previous, future: [currentHistory.present, ...currentHistory.future], } }) }, []) const redo = useCallback(() => { setHistory((currentHistory) => { if (currentHistory.future.length === 0) return currentHistory const next = currentHistory.future[0] const newFuture = currentHistory.future.slice(1) isUndoRedoAction.current = true return { past: [...currentHistory.past, currentHistory.present], present: next, future: newFuture, } }) }, []) const clear = useCallback(() => { setHistory({ past: [], present: initialState, future: [], }) }, [initialState]) return { state: history.present, setState, undo, redo, canUndo: history.past.length > 0, canRedo: history.future.length > 0, clear, } }