diff --git a/src/pages/editor/components/EditorCanvas.tsx b/src/pages/editor/components/EditorCanvas.tsx index 84e22c6..7dfbea8 100644 --- a/src/pages/editor/components/EditorCanvas.tsx +++ b/src/pages/editor/components/EditorCanvas.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from "react"; +import { useEffect, useRef } from "react"; import { Stage, Layer, Transformer, Rect, Group, Text } from "react-konva"; import Konva from "konva"; import { useEditorStore, type EditorObject } from "../store/editorStore"; @@ -20,7 +20,6 @@ const EditorCanvas = () => { selectedObjectId, selectedObjectIds, setSelectedObjectId, - setSelectedObjectIds, addToSelection, removeFromSelection, setSelectedTableId, @@ -50,7 +49,7 @@ const EditorCanvas = () => { } }, [setStageRef, setLayerRef]); - const handleSelect = (id: string, node: Konva.Node, e?: Konva.KonvaEventObject) => { + const handleSelect = (id: string, _node: Konva.Node, e?: Konva.KonvaEventObject) => { const obj = objects.find((o) => o.id === id); const isMultiSelect = e?.evt?.metaKey || e?.evt?.ctrlKey || e?.evt?.shiftKey; @@ -90,15 +89,15 @@ const EditorCanvas = () => { } else if (!isMultiSelect) { setSelectedTableId(null); } - + if (!isMultiSelect) { setSelectedCellId(null); } }; - const handleCellClick = (tableId: string, cellId: string, node?: Konva.Node, e?: Konva.KonvaEventObject) => { + const handleCellClick = (tableId: string, cellId: string, e?: Konva.KonvaEventObject) => { const isMultiSelect = e?.evt?.metaKey || e?.evt?.ctrlKey || e?.evt?.shiftKey; - + if (isMultiSelect) { // انتخاب چندتایی if (selectedObjectIds.includes(tableId)) { @@ -110,7 +109,7 @@ const EditorCanvas = () => { setSelectedTableId(tableId); setSelectedObjectId(tableId); } - + setSelectedCellId(cellId); }; @@ -181,7 +180,7 @@ const EditorCanvas = () => { if (!layerRef.current || !transformerRef.current) return; const nodesToTransform: Konva.Node[] = []; - + selectedObjectIds.forEach((objId) => { const selectedObject = objects.find((obj) => obj.id === objId); if (!selectedObject) return; @@ -243,8 +242,8 @@ const EditorCanvas = () => { const scaledY = relativeY * scaleY; // Find the Konva node for this member - const memberNode = layerRef.current?.findOne(`#${member.id}`) || - layerRef.current?.findOne(`#masked-${member.id}`); + const memberNode = layerRef.current?.findOne(`#${member.id}`) || + layerRef.current?.findOne(`#masked-${member.id}`); if (memberNode) { memberNode.x(newX + scaledX); memberNode.y(newY + scaledY); @@ -283,8 +282,6 @@ const EditorCanvas = () => { const groupMembers = objects.filter((o) => o.groupId === selectedObject.id); const oldGroupX = selectedObject.x || 0; const oldGroupY = selectedObject.y || 0; - const oldGroupWidth = selectedObject.width || 100; - const oldGroupHeight = selectedObject.height || 100; // محاسبه bounds جدید بر اساا member های update شده const updatedMembers = groupMembers.map((member) => { @@ -480,7 +477,7 @@ const EditorCanvas = () => { .map((obj) => { const groupObject = objects.find((o) => o.id === obj.groupId); if (!groupObject) return null; - + // Render with absolute position but wrapped in non-listening group return ( diff --git a/src/pages/editor/components/canvas/useDrawingHandlers.ts b/src/pages/editor/components/canvas/useDrawingHandlers.ts index bfacc5c..13e42a1 100644 --- a/src/pages/editor/components/canvas/useDrawingHandlers.ts +++ b/src/pages/editor/components/canvas/useDrawingHandlers.ts @@ -10,7 +10,7 @@ export const useDrawingHandlers = () => { const [tempObject, setTempObject] = useState(null); const transformerRef = useRef(null); - const { tool, addObject, updateObject, setSelectedObjectId, setSelectedObjectIds, selectedObjectId, selectedObjectIds, setTool, addTable, setSelectedTableId } = useEditorStore(); + const { tool, addObject, updateObject, setSelectedObjectId, setSelectedObjectIds, selectedObjectIds, setTool, addTable, setSelectedTableId } = useEditorStore(); const { defaults } = useTextDefaultsStore(); useEffect(() => { diff --git a/src/pages/editor/components/canvas/useKeyboardMovement.ts b/src/pages/editor/components/canvas/useKeyboardMovement.ts index 3424aee..aea763e 100644 --- a/src/pages/editor/components/canvas/useKeyboardMovement.ts +++ b/src/pages/editor/components/canvas/useKeyboardMovement.ts @@ -3,7 +3,6 @@ import { useEditorStore } from "../../store/editorStore"; export const useKeyboardMovement = () => { const { - selectedObjectId, selectedObjectIds, objects, updateObject, @@ -33,7 +32,7 @@ export const useKeyboardMovement = () => { if (e.key === "Delete" || e.key === "Backspace") { if (selectedObjectIds.length > 0) { e.preventDefault(); - selectedObjectIds.forEach(id => deleteObject(id)); + selectedObjectIds.forEach((id) => deleteObject(id)); return; } } @@ -42,7 +41,9 @@ export const useKeyboardMovement = () => { if ((e.metaKey || e.ctrlKey) && e.key === "g") { e.preventDefault(); if (selectedObjectIds.length === 1) { - const selectedObject = objects.find((obj) => obj.id === selectedObjectIds[0]); + const selectedObject = objects.find( + (obj) => obj.id === selectedObjectIds[0] + ); // اگر group انتخاب شده، ungroup کن if (selectedObject?.type === "group") { ungroupObjects(selectedObject.id); @@ -116,5 +117,14 @@ export const useKeyboardMovement = () => { return () => { window.removeEventListener("keydown", handleKeyDown); }; - }, [selectedObjectIds, objects, updateObject, deleteObject, tool, layerRef, groupObjects, ungroupObjects]); + }, [ + selectedObjectIds, + objects, + updateObject, + deleteObject, + tool, + layerRef, + groupObjects, + ungroupObjects, + ]); }; diff --git a/src/pages/editor/components/tools/AbstractShape.tsx b/src/pages/editor/components/tools/AbstractShape.tsx index 8a8c604..6cbcad3 100644 --- a/src/pages/editor/components/tools/AbstractShape.tsx +++ b/src/pages/editor/components/tools/AbstractShape.tsx @@ -1,9 +1,9 @@ -import { useEffect, useRef } from "react"; +import { useRef } from "react"; import { Star } from "react-konva"; import Konva from "konva"; import type { ShapeProps } from "./types"; -const AbstractShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, draggable }: ShapeProps) => { +const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => { const shapeRef = useRef(null); // Transformer is managed in EditorCanvas for multi-select support @@ -27,13 +27,13 @@ const AbstractShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, dr outerRadius={radius} fill={isMask ? "transparent" : obj.fill} stroke={ - isSelected - ? "#3b82f6" - : (isMask && showGuide) - ? "#ff6b6b" - : (isMask && !showGuide) - ? "transparent" - : obj.stroke + isSelected + ? "#3b82f6" + : (isMask && showGuide) + ? "#ff6b6b" + : (isMask && !showGuide) + ? "transparent" + : obj.stroke } strokeWidth={isSelected ? 3 : (isMask && showGuide ? 2 : (obj.strokeWidth ?? 0))} dash={isMask && showGuide ? [10, 5] : undefined} diff --git a/src/pages/editor/components/tools/ArrowShape.tsx b/src/pages/editor/components/tools/ArrowShape.tsx index 7add286..1858bfd 100644 --- a/src/pages/editor/components/tools/ArrowShape.tsx +++ b/src/pages/editor/components/tools/ArrowShape.tsx @@ -1,9 +1,9 @@ -import { useEffect, useRef } from "react"; +import { useRef } from "react"; import { Arrow } from "react-konva"; import Konva from "konva"; import type { ShapeProps } from "./types"; -const ArrowShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, draggable }: ShapeProps) => { +const ArrowShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => { const shapeRef = useRef(null); // Transformer is managed in EditorCanvas for multi-select support diff --git a/src/pages/editor/components/tools/CircleShape.tsx b/src/pages/editor/components/tools/CircleShape.tsx index b296e28..440be22 100644 --- a/src/pages/editor/components/tools/CircleShape.tsx +++ b/src/pages/editor/components/tools/CircleShape.tsx @@ -1,16 +1,16 @@ -import { useEffect, useRef } from "react"; +import { useRef } from "react"; import { Circle } from "react-konva"; import Konva from "konva"; import type { ShapeProps } from "./types"; -const CircleShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, draggable }: ShapeProps) => { +const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => { const shapeRef = useRef(null); // Transformer is managed in EditorCanvas for multi-select support const isMask = obj.isMask || false; const showGuide = obj.showMaskGuide !== false; - + return ( { +const LineShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => { const shapeRef = useRef(null); // Transformer is managed in EditorCanvas for multi-select support diff --git a/src/pages/editor/components/tools/LinkShape.tsx b/src/pages/editor/components/tools/LinkShape.tsx index 13ad1a4..33dff9c 100644 --- a/src/pages/editor/components/tools/LinkShape.tsx +++ b/src/pages/editor/components/tools/LinkShape.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useMemo } from "react"; +import { useRef, useMemo } from "react"; import { Text } from "react-konva"; import Konva from "konva"; import type { ShapeProps } from "./types"; @@ -14,8 +14,6 @@ const getFontWeight = (fontWeight?: string): string => { const LinkShape = ({ obj, - isSelected, - transformerRef, onSelect, onUpdate, draggable, diff --git a/src/pages/editor/components/tools/RectangleShape.tsx b/src/pages/editor/components/tools/RectangleShape.tsx index d074ea4..12c0dd6 100644 --- a/src/pages/editor/components/tools/RectangleShape.tsx +++ b/src/pages/editor/components/tools/RectangleShape.tsx @@ -1,9 +1,9 @@ -import { useEffect, useRef } from "react"; +import { useRef } from "react"; import { Rect } from "react-konva"; import Konva from "konva"; import type { ShapeProps } from "./types"; -const RectangleShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, draggable }: ShapeProps) => { +const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => { const shapeRef = useRef(null); // Transformer is managed in EditorCanvas for multi-select support @@ -22,10 +22,10 @@ const RectangleShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, d height={obj.height || 100} fill={isMask ? "transparent" : obj.fill} stroke={ - isSelected - ? "#3b82f6" - : (isMask && showGuide) - ? "#ff6b6b" + isSelected + ? "#3b82f6" + : (isMask && showGuide) + ? "#ff6b6b" : (isMask && !showGuide) ? "transparent" : obj.stroke diff --git a/src/pages/editor/components/tools/TriangleShape.tsx b/src/pages/editor/components/tools/TriangleShape.tsx index 327346a..1714ec2 100644 --- a/src/pages/editor/components/tools/TriangleShape.tsx +++ b/src/pages/editor/components/tools/TriangleShape.tsx @@ -1,9 +1,9 @@ -import { useEffect, useRef } from "react"; +import { useRef } from "react"; import { RegularPolygon } from "react-konva"; import Konva from "konva"; import type { ShapeProps } from "./types"; -const TriangleShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, draggable }: ShapeProps) => { +const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => { const shapeRef = useRef(null); // Transformer is managed in EditorCanvas for multi-select support @@ -23,13 +23,13 @@ const TriangleShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, dr radius={radius} fill={isMask ? "transparent" : obj.fill} stroke={ - isSelected - ? "#3b82f6" - : (isMask && showGuide) - ? "#ff6b6b" - : (isMask && !showGuide) - ? "transparent" - : obj.stroke + isSelected + ? "#3b82f6" + : (isMask && showGuide) + ? "#ff6b6b" + : (isMask && !showGuide) + ? "transparent" + : obj.stroke } strokeWidth={isSelected ? 3 : (isMask && showGuide ? 2 : (obj.strokeWidth ?? 0))} dash={isMask && showGuide ? [10, 5] : undefined} diff --git a/src/pages/editor/components/tools/VideoShape.tsx b/src/pages/editor/components/tools/VideoShape.tsx index 359efc2..bd9d434 100644 --- a/src/pages/editor/components/tools/VideoShape.tsx +++ b/src/pages/editor/components/tools/VideoShape.tsx @@ -8,7 +8,6 @@ import { createPortal } from "react-dom"; const VideoShape = ({ obj, isSelected, - transformerRef, onSelect, onUpdate, draggable, diff --git a/src/pages/editor/store/editorStore.ts b/src/pages/editor/store/editorStore.ts index 2757ec7..464aea5 100644 --- a/src/pages/editor/store/editorStore.ts +++ b/src/pages/editor/store/editorStore.ts @@ -307,34 +307,36 @@ export const useEditorStore = create((set, get) => { }, selectedObjectId: null, setSelectedObjectId: (id) => { - set({ + set({ selectedObjectId: id, - selectedObjectIds: id ? [id] : [] + selectedObjectIds: id ? [id] : [], }); }, selectedObjectIds: [], setSelectedObjectIds: (ids) => { - set({ + set({ selectedObjectIds: ids, - selectedObjectId: ids.length > 0 ? ids[0] : null + selectedObjectId: ids.length > 0 ? ids[0] : null, }); }, addToSelection: (id) => { const state = get(); if (!state.selectedObjectIds.includes(id)) { const newIds = [...state.selectedObjectIds, id]; - set({ + set({ selectedObjectIds: newIds, - selectedObjectId: newIds[0] + selectedObjectId: newIds[0], }); } }, removeFromSelection: (id) => { const state = get(); - const newIds = state.selectedObjectIds.filter(selectedId => selectedId !== id); - set({ + const newIds = state.selectedObjectIds.filter( + (selectedId) => selectedId !== id + ); + set({ selectedObjectIds: newIds, - selectedObjectId: newIds.length > 0 ? newIds[0] : null + selectedObjectId: newIds.length > 0 ? newIds[0] : null, }); }, selectedTableId: null, @@ -650,7 +652,9 @@ export const useEditorStore = create((set, get) => { if (!obj) return; const newVisible = !(obj.visible ?? true); - const shouldDeselect = !newVisible && (state.selectedObjectId === id || state.selectedTableId === id); + const shouldDeselect = + !newVisible && + (state.selectedObjectId === id || state.selectedTableId === id); if (state.currentPageId) { set((state) => ({ @@ -704,7 +708,9 @@ export const useEditorStore = create((set, get) => { oldGroupIdsToRemove.add(id); } else if (obj?.groupId) { // اگر این آبجکت در یک گروه است، همه آبجکت‌های آن گروه را اضافه کن - const oldGroupMembers = state.objects.filter((o) => o.groupId === obj.groupId); + const oldGroupMembers = state.objects.filter( + (o) => o.groupId === obj.groupId + ); oldGroupMembers.forEach((member) => { if (member.type !== "group") { allObjectIdsToGroup.add(member.id); @@ -721,10 +727,10 @@ export const useEditorStore = create((set, get) => { if (allObjectIdsToGroup.size < 2) return; const groupId = `group-${crypto.randomUUID()}`; - const objectsToGroup = state.objects.filter((obj) => - allObjectIdsToGroup.has(obj.id) && obj.type !== "group" + const objectsToGroup = state.objects.filter( + (obj) => allObjectIdsToGroup.has(obj.id) && obj.type !== "group" ); - + if (objectsToGroup.length === 0) return; // محاسبه bounds گروه با در نظر گرفتن rotation @@ -737,7 +743,7 @@ export const useEditorStore = create((set, get) => { // برای متن‌هایی که width و height ندارند، از مقادیر پیش‌فرض استفاده کن let w = obj.width || 0; let h = obj.height || 0; - + if (obj.type === "text") { // اگر متن width نداره، از fontSize و طول متن برای تخمین استفاده کن if (!w) { @@ -750,7 +756,7 @@ export const useEditorStore = create((set, get) => { h = obj.fontSize || 24; } } - + const cx = (obj.x || 0) + w / 2; const cy = (obj.y || 0) + h / 2; const rot = ((obj.rotation || 0) * Math.PI) / 180; @@ -853,7 +859,7 @@ export const useEditorStore = create((set, get) => { selectedObjectIds: [], })); }, - getGroupObjects: (groupId) => { + getGroupObjects: (groupId: string) => { const state = get(); return state.objects.filter((obj) => obj.groupId === groupId); },