"use client"; import { useState, useCallback, useEffect } from "react"; import { Handle, Position, useReactFlow, type NodeProps, type Node, } from "@xyflow/react"; import type { Id } from "@/convex/_generated/dataModel"; import { useDebouncedCallback } from "@/hooks/use-debounced-callback"; import BaseNodeWrapper from "./base-node-wrapper"; import { useCanvasSync } from "@/components/canvas/canvas-sync-context"; type TextNodeData = { content?: string; _status?: string; _statusMessage?: string; }; export type TextNode = Node; export default function TextNode({ id, data, selected }: NodeProps) { const { setNodes } = useReactFlow(); const { queueNodeDataUpdate } = useCanvasSync(); const [content, setContent] = useState(data.content ?? ""); const [isEditing, setIsEditing] = useState(false); // Sync von außen (Convex-Update) wenn nicht gerade editiert wird useEffect(() => { if (!isEditing) { // eslint-disable-next-line react-hooks/set-state-in-effect setContent(data.content ?? ""); } }, [data.content, isEditing]); // Debounced Save — 500ms nach letztem Tastendruck const saveContent = useDebouncedCallback( (newContent: string) => { void queueNodeDataUpdate({ nodeId: id as Id<"nodes">, data: { ...data, content: newContent, _status: undefined, _statusMessage: undefined, }, }); }, 500, ); const handleChange = useCallback( (e: React.ChangeEvent) => { const newContent = e.target.value; setContent(newContent); setNodes((nodes) => nodes.map((node) => node.id === id ? { ...node, data: { ...node.data, content: newContent, }, } : node, ), ); saveContent(newContent); }, [id, saveContent, setNodes], ); return (
📝 Text
{isEditing ? (