// SVG 节点:编辑与渲染 SVG,透明背景直接融入画布;无自身内容时可取上游文本节点里的 SVG 源码。 import { definePlugin, useEffect, useRef, useState } from "@infinite-canvas/plugin-sdk"; import type { CanvasNodeContentProps } from "@infinite-canvas/plugin-sdk"; function SvgContent({ ctx }: CanvasNodeContentProps) { const [editing, setEditing] = useState(false); const rootRef = useRef(null); const stored = ctx.node.metadata?.content as string | undefined; const upstream = ctx .getUpstream() .map((node) => node.metadata?.content) .find((text): text is string => typeof text === "string" && text.trim().startsWith(" { if (stored === undefined && upstream) ctx.updateMetadata({ content: upstream }); }, [ctx, stored, upstream]); // 点击节点外部时退出编辑。用 pointerdown 的 capture 阶段:宿主画布在 pointerdown 上 // preventDefault 会抑制 mousedown,capture 又能先于宿主 stopPropagation 触发。 useEffect(() => { if (!editing) return; const onDocDown = (e: PointerEvent) => { if (rootRef.current && !rootRef.current.contains(e.target as Node)) setEditing(false); }; document.addEventListener("pointerdown", onDocDown, true); return () => document.removeEventListener("pointerdown", onDocDown, true); }, [editing]); // 交互控件上按下时阻止冒泡,避免误触发节点拖动/双击编辑 const stop = (e: { stopPropagation: () => void }) => e.stopPropagation(); const toggle = { position: "absolute", right: 8, top: 8, zIndex: 20, width: 32, height: 32, display: "grid", placeItems: "center", borderRadius: 8, border: `1px solid ${ctx.theme.node.stroke}`, background: `${ctx.theme.toolbar.panel}dd`, color: ctx.theme.node.text, cursor: "pointer" } as const; return (
{ e.stopPropagation(); setEditing(true); }} > {editing ? (