import { useState, useCallback, useRef, useEffect } from 'react'; const MAX_HISTORY = 50; const DEBOUNCE_DELAY_MS = 300; export function useDesignEditor() { const [elements, setElements] = useState([]); const [selectedId, setSelectedId] = useState(null); const historyRef = useRef([]); const historyIndexRef = useRef(-1); const historyTimerRef = useRef(null); const pendingChangesRef = useRef(null); const saveToHistory = useCallback((newElements) => { if (historyIndexRef.current < historyRef.current.length - 1) { historyRef.current = historyRef.current.slice(0, historyIndexRef.current + 1); } historyRef.current.push(JSON.stringify(newElements)); if (historyRef.current.length > MAX_HISTORY) { historyRef.current.shift(); } else { historyIndexRef.current++; } }, []); const flushPendingChanges = useCallback(() => { if (pendingChangesRef.current) { saveToHistory(pendingChangesRef.current); pendingChangesRef.current = null; } if (historyTimerRef.current) { clearTimeout(historyTimerRef.current); historyTimerRef.current = null; } }, [saveToHistory]); useEffect(() => { return () => { if (historyTimerRef.current) clearTimeout(historyTimerRef.current); }; }, []); const canUndo = historyIndexRef.current > 0; const canRedo = historyIndexRef.current < historyRef.current.length - 1; const addElement = useCallback((element) => { flushPendingChanges(); const newElement = { ...element, id: `element-${Date.now()}-${Math.random().toString(36).substr(2, 9)}` }; setElements((prev) => { const newElements = [...prev, newElement]; saveToHistory(newElements); return newElements; }); setSelectedId(newElement.id); return newElement.id; }, [flushPendingChanges, saveToHistory]); const updateElement = useCallback((id, attrs) => { setElements((prev) => { const newElements = prev.map((el) => (el.id === id ? { ...el, ...attrs } : el)); pendingChangesRef.current = newElements; if (historyTimerRef.current) clearTimeout(historyTimerRef.current); historyTimerRef.current = setTimeout(() => { flushPendingChanges(); }, DEBOUNCE_DELAY_MS); return newElements; }); }, [flushPendingChanges]); const deleteElement = useCallback((id) => { flushPendingChanges(); setElements((prev) => { const newElements = prev.filter((el) => el.id !== id); saveToHistory(newElements); return newElements; }); if (selectedId === id) setSelectedId(null); }, [selectedId, flushPendingChanges, saveToHistory]); const selectElement = useCallback((id) => setSelectedId(id), []); const deselectAll = useCallback(() => setSelectedId(null), []); const commitHistory = useCallback(() => flushPendingChanges(), [flushPendingChanges]); const undo = useCallback(() => { if (historyIndexRef.current > 0) { historyIndexRef.current--; setElements(JSON.parse(historyRef.current[historyIndexRef.current])); setSelectedId(null); } }, []); const redo = useCallback(() => { if (historyIndexRef.current < historyRef.current.length - 1) { historyIndexRef.current++; setElements(JSON.parse(historyRef.current[historyIndexRef.current])); setSelectedId(null); } }, []); const initializeHistory = useCallback(() => { historyRef.current = [JSON.stringify([])]; historyIndexRef.current = 0; }, []); return { elements, selectedId, addElement, updateElement, deleteElement, selectElement, deselectAll, commitHistory, undo, redo, canUndo, canRedo, initializeHistory }; }