Your Name dcb82c73b5
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: add detail generation mode pipeline and solid select popovers
2026-02-24 18:06:33 +08:00

107 lines
3.0 KiB
TypeScript

"use client";
import React, { useState, useRef, useEffect } from "react";
import { useCanvasStore } from "@/store/canvas";
import type { CanvasNode, TextNodeData } from "@/types/canvas";
import { cn } from "@/lib/utils";
interface TextNodeProps {
node: CanvasNode;
isSelected: boolean;
}
export function TextNode({ node, isSelected }: TextNodeProps) {
const data = node.data as TextNodeData;
const [isEditing, setIsEditing] = useState(false);
const [editContent, setEditContent] = useState(data.content);
const textareaRef = useRef<HTMLTextAreaElement>(null);
const updateNode = useCanvasStore((state) => state.updateNode);
// 进入编辑模式时聚焦
useEffect(() => {
if (isEditing && textareaRef.current) {
textareaRef.current.focus();
textareaRef.current.select();
}
}, [isEditing]);
// 保存编辑
const handleSave = () => {
updateNode(node.id, {
data: { ...data, content: editContent },
});
setIsEditing(false);
};
// 取消编辑
const handleCancel = () => {
setEditContent(data.content);
setIsEditing(false);
};
// 双击进入编辑
const handleDoubleClick = (e: React.MouseEvent) => {
e.stopPropagation();
setIsEditing(true);
};
return (
<div
className={cn(
"relative w-full h-full overflow-hidden p-3",
data.transparent
? "rounded-none border-0 bg-transparent p-0 shadow-none"
: "rounded-lg border bg-card shadow-sm",
isSelected && (data.transparent ? "ring-1 ring-primary/50" : "border-primary")
)}
onDoubleClick={handleDoubleClick}
>
{isEditing ? (
<textarea
ref={textareaRef}
value={editContent}
onChange={(e) => setEditContent(e.target.value)}
onBlur={handleSave}
onKeyDown={(e) => {
if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
handleSave();
}
if (e.key === 'Escape') {
handleCancel();
}
}}
className="w-full h-full resize-none bg-transparent outline-none text-sm"
style={{
fontSize: data.fontSize || 14,
color: data.color || 'inherit',
fontWeight: data.fontWeight || 'normal',
lineHeight: data.lineHeight || 1.35,
textAlign: data.textAlign || "left",
}}
/>
) : (
<div
className="w-full h-full overflow-auto text-sm whitespace-pre-wrap"
style={{
fontSize: data.fontSize || 14,
color: data.color || 'inherit',
fontWeight: data.fontWeight || 'normal',
lineHeight: data.lineHeight || 1.35,
textAlign: data.textAlign || "left",
}}
>
{data.content || '双击编辑文本'}
</div>
)}
{/* 编辑提示 */}
{!isEditing && isSelected && (
<div className="absolute bottom-1 right-1 text-[10px] text-muted-foreground">
双击编辑
</div>
)}
</div>
);
}