show live change values object
This commit is contained in:
@@ -74,7 +74,7 @@ const ObjectRenderer = ({
|
|||||||
if (rafId1) cancelAnimationFrame(rafId1);
|
if (rafId1) cancelAnimationFrame(rafId1);
|
||||||
groupNode?.clearCache();
|
groupNode?.clearCache();
|
||||||
};
|
};
|
||||||
}, [shouldApplyMask, isSelected, maskShape?.x, maskShape?.y, maskShape?.width, maskShape?.height, maskShape?.rotation, obj.x, obj.y, obj.width, obj.height, obj.rotation, obj.maskInvert]);
|
}, [shouldApplyMask, isSelected, maskShape?.x, maskShape?.y, maskShape?.width, maskShape?.height, maskShape?.rotation, obj.x, obj.y, obj.width, obj.height, obj.rotation, obj.maskInvert, obj.strokeWidth, obj.stroke, obj.fill]);
|
||||||
|
|
||||||
// Refresh cache after transformer is attached (when isSelected changes)
|
// Refresh cache after transformer is attached (when isSelected changes)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { useEffect, useState } from "react";
|
|
||||||
import Button from "@/components/Button";
|
|
||||||
import Input from "@/components/Input";
|
import Input from "@/components/Input";
|
||||||
import ColorPicker from "@/components/ColorPicker";
|
import ColorPicker from "@/components/ColorPicker";
|
||||||
import type { EditorObject } from "@/pages/editor/store/editorStore";
|
import type { EditorObject } from "@/pages/editor/store/editorStore";
|
||||||
@@ -9,14 +7,6 @@ type ShapeSettingsProps = {
|
|||||||
onUpdate: (id: string, updates: Partial<EditorObject>) => void;
|
onUpdate: (id: string, updates: Partial<EditorObject>) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ShapeFormState = {
|
|
||||||
width: string;
|
|
||||||
height: string;
|
|
||||||
fill: string;
|
|
||||||
stroke: string;
|
|
||||||
strokeWidth: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
const ShapeSettings = ({ selectedObject, onUpdate }: ShapeSettingsProps) => {
|
const ShapeSettings = ({ selectedObject, onUpdate }: ShapeSettingsProps) => {
|
||||||
const baseWidth = selectedObject.width ?? 100;
|
const baseWidth = selectedObject.width ?? 100;
|
||||||
const baseHeight = selectedObject.height ?? 100;
|
const baseHeight = selectedObject.height ?? 100;
|
||||||
@@ -24,105 +14,57 @@ const ShapeSettings = ({ selectedObject, onUpdate }: ShapeSettingsProps) => {
|
|||||||
const baseStroke = selectedObject.stroke ?? "#1e40af";
|
const baseStroke = selectedObject.stroke ?? "#1e40af";
|
||||||
const baseStrokeWidth = selectedObject.strokeWidth ?? 0;
|
const baseStrokeWidth = selectedObject.strokeWidth ?? 0;
|
||||||
|
|
||||||
const [formState, setFormState] = useState<ShapeFormState>({
|
|
||||||
width: String(baseWidth),
|
|
||||||
height: String(baseHeight),
|
|
||||||
fill: baseFill,
|
|
||||||
stroke: baseStroke,
|
|
||||||
strokeWidth: String(baseStrokeWidth),
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setFormState({
|
|
||||||
width: String(baseWidth),
|
|
||||||
height: String(baseHeight),
|
|
||||||
fill: baseFill,
|
|
||||||
stroke: baseStroke,
|
|
||||||
strokeWidth: String(baseStrokeWidth),
|
|
||||||
});
|
|
||||||
}, [baseWidth, baseHeight, baseFill, baseStroke, baseStrokeWidth]);
|
|
||||||
|
|
||||||
const parseNumber = (value: string, fallback: number) => {
|
|
||||||
const parsed = parseInt(value, 10);
|
|
||||||
return Number.isNaN(parsed) ? fallback : parsed;
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleSave = () => {
|
|
||||||
onUpdate(selectedObject.id, {
|
|
||||||
width: parseNumber(formState.width, baseWidth),
|
|
||||||
height: parseNumber(formState.height, baseHeight),
|
|
||||||
fill: formState.fill || baseFill,
|
|
||||||
stroke: formState.stroke || baseStroke,
|
|
||||||
strokeWidth: parseNumber(formState.strokeWidth, baseStrokeWidth),
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const isDirty =
|
|
||||||
formState.width !== String(baseWidth) ||
|
|
||||||
formState.height !== String(baseHeight) ||
|
|
||||||
formState.fill !== baseFill ||
|
|
||||||
formState.stroke !== baseStroke ||
|
|
||||||
formState.strokeWidth !== String(baseStrokeWidth);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<Input
|
<Input
|
||||||
label="عرض"
|
label="عرض"
|
||||||
type="number"
|
type="number"
|
||||||
value={formState.width}
|
value={baseWidth}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setFormState((prev) => ({
|
onUpdate(selectedObject.id, {
|
||||||
...prev,
|
width: parseInt(e.target.value) || baseWidth,
|
||||||
width: e.target.value,
|
})
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="ارتفاع"
|
label="ارتفاع"
|
||||||
type="number"
|
type="number"
|
||||||
value={formState.height}
|
value={baseHeight}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setFormState((prev) => ({
|
onUpdate(selectedObject.id, {
|
||||||
...prev,
|
height: parseInt(e.target.value) || baseHeight,
|
||||||
height: e.target.value,
|
})
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
label="رنگ پسزمینه"
|
label="رنگ پسزمینه"
|
||||||
value={formState.fill}
|
value={baseFill}
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
setFormState((prev) => ({
|
onUpdate(selectedObject.id, {
|
||||||
...prev,
|
|
||||||
fill: value,
|
fill: value,
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ColorPicker
|
<ColorPicker
|
||||||
label="رنگ خط"
|
label="رنگ خط"
|
||||||
value={formState.stroke}
|
value={baseStroke}
|
||||||
onChange={(value) =>
|
onChange={(value) =>
|
||||||
setFormState((prev) => ({
|
onUpdate(selectedObject.id, {
|
||||||
...prev,
|
|
||||||
stroke: value,
|
stroke: value,
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Input
|
<Input
|
||||||
label="ضخامت خط"
|
label="ضخامت خط"
|
||||||
type="number"
|
type="number"
|
||||||
value={formState.strokeWidth}
|
value={baseStrokeWidth}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setFormState((prev) => ({
|
onUpdate(selectedObject.id, {
|
||||||
...prev,
|
strokeWidth: parseInt(e.target.value) || 0,
|
||||||
strokeWidth: e.target.value,
|
})
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
min={0}
|
min={0}
|
||||||
/>
|
/>
|
||||||
<Button type="button" onClick={handleSave} disabled={!isDirty} className="w-full">
|
|
||||||
ذخیره تغییرات
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,6 +15,22 @@ const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
|||||||
const radius = baseRadius * abstractScale;
|
const radius = baseRadius * abstractScale;
|
||||||
const innerRadius = radius * 0.5;
|
const innerRadius = radius * 0.5;
|
||||||
|
|
||||||
|
const actualStrokeWidth = obj.strokeWidth ?? 0;
|
||||||
|
const hasStroke = actualStrokeWidth > 0;
|
||||||
|
|
||||||
|
// برای نمایش انتخاب: اگر strokeWidth واقعی > 0 است، از آن استفاده کن، وگرنه stroke را برای انتخاب نمایش بده
|
||||||
|
const displayStroke = isSelected
|
||||||
|
? (hasStroke ? obj.stroke : "#3b82f6")
|
||||||
|
: (isMask && showGuide)
|
||||||
|
? "#ff6b6b"
|
||||||
|
: (isMask && !showGuide)
|
||||||
|
? "transparent"
|
||||||
|
: (hasStroke ? obj.stroke : undefined);
|
||||||
|
|
||||||
|
const displayStrokeWidth = isSelected
|
||||||
|
? (hasStroke ? actualStrokeWidth : 3)
|
||||||
|
: (isMask && showGuide ? 2 : actualStrokeWidth);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Star
|
<Star
|
||||||
ref={shapeRef}
|
ref={shapeRef}
|
||||||
@@ -26,16 +42,8 @@ const AbstractShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
|||||||
innerRadius={innerRadius}
|
innerRadius={innerRadius}
|
||||||
outerRadius={radius}
|
outerRadius={radius}
|
||||||
fill={isMask ? "transparent" : obj.fill}
|
fill={isMask ? "transparent" : obj.fill}
|
||||||
stroke={
|
stroke={displayStroke}
|
||||||
isSelected
|
strokeWidth={displayStrokeWidth}
|
||||||
? "#3b82f6"
|
|
||||||
: (isMask && showGuide)
|
|
||||||
? "#ff6b6b"
|
|
||||||
: (isMask && !showGuide)
|
|
||||||
? "transparent"
|
|
||||||
: obj.stroke
|
|
||||||
}
|
|
||||||
strokeWidth={isSelected ? 3 : (isMask && showGuide ? 2 : (obj.strokeWidth ?? 0))}
|
|
||||||
dash={isMask && showGuide ? [10, 5] : undefined}
|
dash={isMask && showGuide ? [10, 5] : undefined}
|
||||||
rotation={obj.rotation || 0}
|
rotation={obj.rotation || 0}
|
||||||
draggable={draggable}
|
draggable={draggable}
|
||||||
|
|||||||
@@ -11,6 +11,22 @@ const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapePr
|
|||||||
const isMask = obj.isMask || false;
|
const isMask = obj.isMask || false;
|
||||||
const showGuide = obj.showMaskGuide !== false;
|
const showGuide = obj.showMaskGuide !== false;
|
||||||
|
|
||||||
|
const actualStrokeWidth = obj.strokeWidth ?? 0;
|
||||||
|
const hasStroke = actualStrokeWidth > 0;
|
||||||
|
|
||||||
|
// برای نمایش انتخاب: اگر strokeWidth واقعی > 0 است، از آن استفاده کن، وگرنه stroke را برای انتخاب نمایش بده
|
||||||
|
const displayStroke = isSelected
|
||||||
|
? (hasStroke ? obj.stroke : "#3b82f6")
|
||||||
|
: (isMask && showGuide)
|
||||||
|
? "#ff6b6b"
|
||||||
|
: (isMask && !showGuide)
|
||||||
|
? "transparent"
|
||||||
|
: (hasStroke ? obj.stroke : undefined);
|
||||||
|
|
||||||
|
const displayStrokeWidth = isSelected
|
||||||
|
? (hasStroke ? actualStrokeWidth : 3)
|
||||||
|
: (isMask && showGuide ? 2 : actualStrokeWidth);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Circle
|
<Circle
|
||||||
ref={shapeRef}
|
ref={shapeRef}
|
||||||
@@ -20,16 +36,8 @@ const CircleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: ShapePr
|
|||||||
y={obj.y}
|
y={obj.y}
|
||||||
radius={(obj.width || 50) / 2}
|
radius={(obj.width || 50) / 2}
|
||||||
fill={isMask ? "transparent" : obj.fill}
|
fill={isMask ? "transparent" : obj.fill}
|
||||||
stroke={
|
stroke={displayStroke}
|
||||||
isSelected
|
strokeWidth={displayStrokeWidth}
|
||||||
? "#3b82f6"
|
|
||||||
: (isMask && showGuide)
|
|
||||||
? "#ff6b6b"
|
|
||||||
: (isMask && !showGuide)
|
|
||||||
? "transparent"
|
|
||||||
: obj.stroke
|
|
||||||
}
|
|
||||||
strokeWidth={isSelected ? 3 : (isMask && showGuide ? 2 : (obj.strokeWidth ?? 0))}
|
|
||||||
dash={isMask && showGuide ? [10, 5] : undefined}
|
dash={isMask && showGuide ? [10, 5] : undefined}
|
||||||
rotation={obj.rotation || 0}
|
rotation={obj.rotation || 0}
|
||||||
draggable={draggable}
|
draggable={draggable}
|
||||||
|
|||||||
@@ -11,6 +11,22 @@ const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shap
|
|||||||
const isMask = obj.isMask || false;
|
const isMask = obj.isMask || false;
|
||||||
const showGuide = obj.showMaskGuide !== false;
|
const showGuide = obj.showMaskGuide !== false;
|
||||||
|
|
||||||
|
const actualStrokeWidth = obj.strokeWidth ?? 0;
|
||||||
|
const hasStroke = actualStrokeWidth > 0;
|
||||||
|
|
||||||
|
// برای نمایش انتخاب: اگر strokeWidth واقعی > 0 است، از آن استفاده کن، وگرنه stroke را برای انتخاب نمایش بده
|
||||||
|
const displayStroke = isSelected
|
||||||
|
? (hasStroke ? obj.stroke : "#3b82f6")
|
||||||
|
: (isMask && showGuide)
|
||||||
|
? "#ff6b6b"
|
||||||
|
: (isMask && !showGuide)
|
||||||
|
? "transparent"
|
||||||
|
: (hasStroke ? obj.stroke : undefined);
|
||||||
|
|
||||||
|
const displayStrokeWidth = isSelected
|
||||||
|
? (hasStroke ? actualStrokeWidth : 3)
|
||||||
|
: (isMask && showGuide ? 2 : actualStrokeWidth);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Rect
|
<Rect
|
||||||
ref={shapeRef}
|
ref={shapeRef}
|
||||||
@@ -21,16 +37,8 @@ const RectangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shap
|
|||||||
width={obj.width || 100}
|
width={obj.width || 100}
|
||||||
height={obj.height || 100}
|
height={obj.height || 100}
|
||||||
fill={isMask ? "transparent" : obj.fill}
|
fill={isMask ? "transparent" : obj.fill}
|
||||||
stroke={
|
stroke={displayStroke}
|
||||||
isSelected
|
strokeWidth={displayStrokeWidth}
|
||||||
? "#3b82f6"
|
|
||||||
: (isMask && showGuide)
|
|
||||||
? "#ff6b6b"
|
|
||||||
: (isMask && !showGuide)
|
|
||||||
? "transparent"
|
|
||||||
: obj.stroke
|
|
||||||
}
|
|
||||||
strokeWidth={isSelected ? 3 : (isMask && showGuide ? 2 : (obj.strokeWidth ?? 0))}
|
|
||||||
dash={isMask && showGuide ? [10, 5] : undefined}
|
dash={isMask && showGuide ? [10, 5] : undefined}
|
||||||
rotation={obj.rotation || 0}
|
rotation={obj.rotation || 0}
|
||||||
draggable={draggable}
|
draggable={draggable}
|
||||||
|
|||||||
@@ -12,6 +12,22 @@ const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
|||||||
const showGuide = obj.showMaskGuide !== false;
|
const showGuide = obj.showMaskGuide !== false;
|
||||||
const radius = Math.min((obj.width || 100) / 2, (obj.height || 100) / 2);
|
const radius = Math.min((obj.width || 100) / 2, (obj.height || 100) / 2);
|
||||||
|
|
||||||
|
const actualStrokeWidth = obj.strokeWidth ?? 0;
|
||||||
|
const hasStroke = actualStrokeWidth > 0;
|
||||||
|
|
||||||
|
// برای نمایش انتخاب: اگر strokeWidth واقعی > 0 است، از آن استفاده کن، وگرنه stroke را برای انتخاب نمایش بده
|
||||||
|
const displayStroke = isSelected
|
||||||
|
? (hasStroke ? obj.stroke : "#3b82f6")
|
||||||
|
: (isMask && showGuide)
|
||||||
|
? "#ff6b6b"
|
||||||
|
: (isMask && !showGuide)
|
||||||
|
? "transparent"
|
||||||
|
: (hasStroke ? obj.stroke : undefined);
|
||||||
|
|
||||||
|
const displayStrokeWidth = isSelected
|
||||||
|
? (hasStroke ? actualStrokeWidth : 3)
|
||||||
|
: (isMask && showGuide ? 2 : actualStrokeWidth);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RegularPolygon
|
<RegularPolygon
|
||||||
ref={shapeRef}
|
ref={shapeRef}
|
||||||
@@ -22,16 +38,8 @@ const TriangleShape = ({ obj, isSelected, onSelect, onUpdate, draggable }: Shape
|
|||||||
sides={3}
|
sides={3}
|
||||||
radius={radius}
|
radius={radius}
|
||||||
fill={isMask ? "transparent" : obj.fill}
|
fill={isMask ? "transparent" : obj.fill}
|
||||||
stroke={
|
stroke={displayStroke}
|
||||||
isSelected
|
strokeWidth={displayStrokeWidth}
|
||||||
? "#3b82f6"
|
|
||||||
: (isMask && showGuide)
|
|
||||||
? "#ff6b6b"
|
|
||||||
: (isMask && !showGuide)
|
|
||||||
? "transparent"
|
|
||||||
: obj.stroke
|
|
||||||
}
|
|
||||||
strokeWidth={isSelected ? 3 : (isMask && showGuide ? 2 : (obj.strokeWidth ?? 0))}
|
|
||||||
dash={isMask && showGuide ? [10, 5] : undefined}
|
dash={isMask && showGuide ? [10, 5] : undefined}
|
||||||
rotation={obj.rotation || 0}
|
rotation={obj.rotation || 0}
|
||||||
draggable={draggable}
|
draggable={draggable}
|
||||||
|
|||||||
Reference in New Issue
Block a user