figmatic-print-builder/elements/TextElement.jsx

125 lines
4.6 KiB
React
Raw Permalink Normal View History

2026-06-16 12:58:18 +05:30
import { Text, Transformer } from "react-konva";
import { useRef, useEffect, useState } from "react";
import useEditorStore from "../useEditorStore";
import { Html } from "react-konva-utils";
export default function TextElement({ element }) {
const updateElement = useEditorStore((state) => state.updateElement);
const setSelectedId = useEditorStore((state) => state.setSelectedId);
const selectedId = useEditorStore((state) => state.selectedId);
const shapeRef = useRef();
const trRef = useRef();
const [isEditing, setIsEditing] = useState(false);
const [editValue, setEditValue] = useState(element.text);
const isSelected = selectedId === element.id;
useEffect(() => {
if (isSelected && trRef.current && shapeRef.current) {
trRef.current.nodes([shapeRef.current]);
trRef.current.getLayer().batchDraw();
}
}, [isSelected]);
useEffect(() => {
setEditValue(element.text);
}, [element.text]);
const handleDoubleClick = () => {
setIsEditing(true);
setEditValue(element.text);
};
const handleBlur = () => {
setIsEditing(false);
updateElement(element.id, { text: editValue });
};
const handleKeyDown = (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
handleBlur();
}
if (e.key === "Escape") {
setIsEditing(false);
setEditValue(element.text);
}
};
return (
<>
{isEditing ? (
<Html
divProps={{
style: {
position: "absolute",
top: `${element.y}px`,
left: `${element.x}px`,
transform: `rotate(${element.rotation}deg)`,
transformOrigin: "top left",
},
}}
>
<textarea
value={editValue}
onChange={(e) => setEditValue(e.target.value)}
onBlur={handleBlur}
onKeyDown={handleKeyDown}
autoFocus
style={{
fontSize: `${element.fontSize}px`,
fontFamily: element.fontFamily,
color: element.color,
textAlign: element.align,
fontWeight: element.fontWeight || "normal",
fontStyle: element.italic ? "italic" : "normal",
textDecoration: element.underline ? "underline" : "none",
border: "2px solid #2196f3",
outline: "none",
padding: "2px 4px",
background: "rgba(255, 255, 255, 0.95)",
resize: "none",
minWidth: "100px",
minHeight: `${element.fontSize + 10}px`,
}}
/>
</Html>
) : (
<Text
ref={shapeRef}
text={element.text}
fontSize={element.fontSize}
fontFamily={element.fontFamily}
fill={element.color}
align={element.align}
fontStyle={`${element.bold ? "bold" : ""} ${element.italic ? "italic" : ""} ${element.fontWeight || "normal"}`}
textDecoration={element.underline ? "underline" : ""}
x={element.x}
y={element.y}
rotation={element.rotation}
draggable
onClick={() => setSelectedId(element.id)}
onDblClick={handleDoubleClick}
onDblTap={handleDoubleClick}
onDragEnd={(e) => {
const snap = (v) => Math.round(v / 10) * 10;
updateElement(element.id, {
x: snap(e.target.x()),
y: snap(e.target.y()),
});
}}
onTransformEnd={() => {
const node = shapeRef.current;
updateElement(element.id, {
rotation: node.rotation(),
});
}}
/>
)}
{isSelected && !isEditing && <Transformer ref={trRef} enabledAnchors={[]} rotateEnabled={true} />}
</>
);
}