Flatted and issues fixed with Claude Desktop.

This commit is contained in:
khalid@traclabs.com
2026-04-22 06:21:02 -05:00
parent 66bd69efe7
commit 4d19363d58
86 changed files with 1561 additions and 9232 deletions

View File

@@ -0,0 +1,72 @@
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 };
}