Implements the core canvas editor with react-konva: - Added dependencies: react-konva, konva, use-image - DesignCanvas component: 300×300px Stage with T-shirt SVG overlay - TShirtSVG component: Visual t-shirt outline with print zone indicator - ImageElement: Draggable/resizable image with Transformer handles - TextElement: Draggable/resizable text with Transformer handles - useDesignEditor hook: Element CRUD, selection, reordering - Keyboard shortcut: Delete/Backspace removes selected element - Test image added on mount for Phase 2 verification Canvas info bar shows: "Design Area: 15" × 15" • Export: 4500 × 4500px @ 300 DPI" Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
60 lines
1.5 KiB
JavaScript
60 lines
1.5 KiB
JavaScript
import { useState, useCallback } from 'react';
|
|
|
|
export function useDesignEditor() {
|
|
const [elements, setElements] = useState([]);
|
|
const [selectedId, setSelectedId] = useState(null);
|
|
|
|
const addElement = useCallback((element) => {
|
|
const newElement = {
|
|
...element,
|
|
id: `element-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
|
|
};
|
|
setElements((prev) => [...prev, newElement]);
|
|
setSelectedId(newElement.id);
|
|
return newElement.id;
|
|
}, []);
|
|
|
|
const updateElement = useCallback((id, attrs) => {
|
|
setElements((prev) =>
|
|
prev.map((el) => (el.id === id ? { ...el, ...attrs } : el))
|
|
);
|
|
}, []);
|
|
|
|
const deleteElement = useCallback((id) => {
|
|
setElements((prev) => prev.filter((el) => el.id !== id));
|
|
if (selectedId === id) {
|
|
setSelectedId(null);
|
|
}
|
|
}, [selectedId]);
|
|
|
|
const selectElement = useCallback((id) => {
|
|
setSelectedId(id);
|
|
}, []);
|
|
|
|
const deselectAll = useCallback(() => {
|
|
setSelectedId(null);
|
|
}, []);
|
|
|
|
const reorderElement = useCallback((id, newOrder) => {
|
|
setElements((prev) => {
|
|
const index = prev.findIndex((el) => el.id === id);
|
|
if (index === -1 || index === newOrder) return prev;
|
|
const newElements = [...prev];
|
|
const [removed] = newElements.splice(index, 1);
|
|
newElements.splice(newOrder, 0, removed);
|
|
return newElements;
|
|
});
|
|
}, []);
|
|
|
|
return {
|
|
elements,
|
|
selectedId,
|
|
addElement,
|
|
updateElement,
|
|
deleteElement,
|
|
selectElement,
|
|
deselectAll,
|
|
reorderElement,
|
|
};
|
|
}
|