94 lines
2.6 KiB
TypeScript
94 lines
2.6 KiB
TypeScript
import React, { useRef, useCallback } from 'react';
|
|
import { Box, Center } from '@chakra-ui/react';
|
|
import { Stage, Layer, Rect } from 'react-konva';
|
|
import { useDispatch, useSelector } from 'react-redux';
|
|
import { RootState } from '@/store';
|
|
import { selectComponent, clearSelection } from '@/store/slices/selectionSlice';
|
|
import ComponentRenderer from './ComponentRenderer';
|
|
import useCanvasSize from '@/hooks/useCanvasSize';
|
|
import useCanvasZoom from '@/hooks/useCanvasZoom';
|
|
|
|
const Canvas: React.FC = () => {
|
|
const dispatch = useDispatch();
|
|
const stageRef = useRef<any>(null);
|
|
const { mockup } = useSelector((state: RootState) => state);
|
|
const { components, canvas } = mockup;
|
|
|
|
// Custom hooks for canvas operations
|
|
const { containerSize, canvasContainerRef } = useCanvasSize();
|
|
const { scale, position, handleWheel, handleDragMove } = useCanvasZoom();
|
|
|
|
// Handle background click (deselect all)
|
|
const handleStageClick = useCallback((e: any) => {
|
|
// If clicked on the stage background
|
|
if (e.target === e.currentTarget) {
|
|
dispatch(clearSelection());
|
|
}
|
|
}, [dispatch]);
|
|
|
|
// Handle component selection
|
|
const handleComponentClick = useCallback((id: string, e: any) => {
|
|
e.cancelBubble = true; // Stop propagation to parent
|
|
dispatch(selectComponent(id));
|
|
}, [dispatch]);
|
|
|
|
return (
|
|
<Center
|
|
flex="1"
|
|
bg="gray.100"
|
|
overflow="hidden"
|
|
ref={canvasContainerRef}
|
|
position="relative"
|
|
>
|
|
<Box
|
|
position="absolute"
|
|
top="0"
|
|
left="0"
|
|
bottom="0"
|
|
right="0"
|
|
className="canvas-grid"
|
|
/>
|
|
<Stage
|
|
ref={stageRef}
|
|
width={containerSize.width}
|
|
height={containerSize.height}
|
|
onClick={handleStageClick}
|
|
onWheel={handleWheel}
|
|
draggable
|
|
onDragMove={handleDragMove}
|
|
x={position.x}
|
|
y={position.y}
|
|
scaleX={scale}
|
|
scaleY={scale}
|
|
>
|
|
<Layer>
|
|
{/* Canvas background */}
|
|
<Rect
|
|
x={0}
|
|
y={0}
|
|
width={canvas.width}
|
|
height={canvas.height}
|
|
fill={canvas.background}
|
|
shadowColor="rgba(0,0,0,0.2)"
|
|
shadowBlur={10}
|
|
shadowOffsetX={0}
|
|
shadowOffsetY={0}
|
|
cornerRadius={4}
|
|
/>
|
|
|
|
{/* Render components */}
|
|
{components.map((component) => (
|
|
<ComponentRenderer
|
|
key={component.id}
|
|
component={component}
|
|
onClick={(e) => handleComponentClick(component.id, e)}
|
|
/>
|
|
))}
|
|
</Layer>
|
|
</Stage>
|
|
</Center>
|
|
);
|
|
};
|
|
|
|
export default Canvas;
|