fix build

This commit is contained in:
hamid zarghami
2026-01-05 14:24:45 +03:30
parent 34e0b882fa
commit 3a01267b55
13 changed files with 88 additions and 79 deletions
+10 -13
View File
@@ -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<MouseEvent>) => {
const handleSelect = (id: string, _node: Konva.Node, e?: Konva.KonvaEventObject<MouseEvent>) => {
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<MouseEvent>) => {
const handleCellClick = (tableId: string, cellId: string, e?: Konva.KonvaEventObject<MouseEvent>) => {
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 (
<Group key={`group-member-${obj.id}`} listening={false}>
@@ -10,7 +10,7 @@ export const useDrawingHandlers = () => {
const [tempObject, setTempObject] = useState<EditorObject | null>(null);
const transformerRef = useRef<Konva.Transformer>(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(() => {
@@ -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,
]);
};
@@ -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<Konva.Star>(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}
@@ -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<Konva.Arrow>(null);
// Transformer is managed in EditorCanvas for multi-select support
@@ -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<Konva.Circle>(null);
// Transformer is managed in EditorCanvas for multi-select support
const isMask = obj.isMask || false;
const showGuide = obj.showMaskGuide !== false;
return (
<Circle
ref={shapeRef}
@@ -21,13 +21,13 @@ const CircleShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, drag
radius={(obj.width || 50) / 2}
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}
@@ -1,4 +1,4 @@
import { useEffect, useRef } from "react";
import { useRef } from "react";
import { Image as KonvaImage } from "react-konva";
import Konva from "konva";
import useImage from "use-image";
@@ -7,7 +7,6 @@ import type { ShapeProps } from "./types";
const ImageObject = ({
obj,
isSelected,
transformerRef,
onSelect,
onUpdate,
draggable,
@@ -1,9 +1,9 @@
import { useEffect, useRef } from "react";
import { useRef } from "react";
import { Line } from "react-konva";
import Konva from "konva";
import type { ShapeProps } from "./types";
const LineShape = ({ obj, isSelected, transformerRef, onSelect, onUpdate, draggable }: ShapeProps) => {
const LineShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapeProps) => {
const shapeRef = useRef<Konva.Line>(null);
// Transformer is managed in EditorCanvas for multi-select support
@@ -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,
@@ -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<Konva.Rect>(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
@@ -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<Konva.RegularPolygon>(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}
@@ -8,7 +8,6 @@ import { createPortal } from "react-dom";
const VideoShape = ({
obj,
isSelected,
transformerRef,
onSelect,
onUpdate,
draggable,
+23 -17
View File
@@ -307,34 +307,36 @@ export const useEditorStore = create<EditorStoreType>((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<EditorStoreType>((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<EditorStoreType>((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<EditorStoreType>((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<EditorStoreType>((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<EditorStoreType>((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<EditorStoreType>((set, get) => {
selectedObjectIds: [],
}));
},
getGroupObjects: (groupId) => {
getGroupObjects: (groupId: string) => {
const state = get();
return state.objects.filter((obj) => obj.groupId === groupId);
},