| "use client"; |
|
|
| import { useState, useCallback } from 'react'; |
| import { Node, Edge } from 'reactflow'; |
| import { NodeData } from './node-editor'; |
|
|
| interface HistoryState { |
| nodes: Node<NodeData>[]; |
| edges: Edge[]; |
| } |
|
|
| export function useUndoRedo( |
| initialNodes: Node<NodeData>[], |
| initialEdges: Edge[], |
| maxHistory: number = 50 |
| ) { |
| |
| const [past, setPast] = useState<HistoryState[]>([]); |
| |
| const [future, setFuture] = useState<HistoryState[]>([]); |
|
|
| |
| |
|
|
| |
| const takeSnapshot = useCallback((nodes: Node<NodeData>[], edges: Edge[]) => { |
| setPast((p) => { |
| |
| |
| |
| const newPast = [...p, { nodes, edges }]; |
| if (newPast.length > maxHistory) { |
| newPast.shift(); |
| } |
| return newPast; |
| }); |
| setFuture([]); |
| }, [maxHistory]); |
|
|
| const undo = useCallback((currentNodes: Node<NodeData>[], currentEdges: Edge[]) => { |
| setPast((p) => { |
| if (p.length === 0) return p; |
|
|
| |
| const newPast = p.slice(0, p.length - 1); |
|
|
| |
| setFuture((f) => [...f, { nodes: currentNodes, edges: currentEdges }]); |
|
|
| return newPast; |
| }); |
|
|
| |
| return past.length > 0 ? past[past.length - 1] : null; |
| }, [past]); |
|
|
| const redo = useCallback((currentNodes: Node<NodeData>[], currentEdges: Edge[]) => { |
| setFuture((f) => { |
| if (f.length === 0) return f; |
|
|
| |
| const newFuture = f.slice(0, f.length - 1); |
|
|
| |
| setPast((p) => [...p, { nodes: currentNodes, edges: currentEdges }]); |
|
|
| return newFuture; |
| }); |
|
|
| return future.length > 0 ? future[future.length - 1] : null; |
| }, [future]); |
|
|
| return { |
| undo, |
| redo, |
| takeSnapshot, |
| canUndo: past.length > 0, |
| canRedo: future.length > 0, |
| past, |
| future |
| }; |
| } |
|
|