Files
Endoleap/src/components/canvas/canvas-text-editor.tsx
T

38 lines
2.6 KiB
TypeScript

"use client";
import { useEffect, useRef, useState } from "react";
import type { CanvasNodeData } from "@/lib/canvas-elements";
import {useScopedNodeEditing} from "./node-editing";
import { textAppearance } from "./text-appearance";
import styles from "./canvas.module.css";
/** Single clicks select; native double-click timing controls entry into editing. */
export function CanvasTextEditor({ id, data, selected, plain = false }: { id: string; data: CanvasNodeData; selected: boolean; plain?: boolean }) {
const actions = useScopedNodeEditing(id,data.__headlessTarget);
const [editing, setEditing] = useState(false);
const textarea = useRef<HTMLTextAreaElement>(null);
const press = useRef({ x: 0, y: 0, moved: false });
useEffect(() => { if (!selected) setEditing(false); }, [selected]);
useEffect(() => {
if (!editing) return;
const element = textarea.current;
element?.focus({ preventScroll: true });
element?.setSelectionRange(element.value.length, element.value.length);
}, [editing]);
function begin() { actions.begin(id); setEditing(true); }
const active = editing && selected;
const label = plain ? "纯文本" : data.title;
return <div className={`${styles.textEditor} ${active ? "nodrag" : ""}`}>
<textarea ref={textarea} style={textAppearance(data)} className={`${plain ? styles.plainText : styles.cardText} nodrag nowheel`}
aria-label={label} readOnly={!active} tabIndex={active ? 0 : -1}
placeholder={plain ? "写下文字…" : data.kind === "script" ? "写下你的脚本…" : "留住一个想法…"}
value={data.text} maxLength={100000} onChange={(event) => actions.edit(id, event.target.value)}
onBlur={() => { setEditing(false); actions.endEditing?.(id); }} onKeyDown={(event) => { if (event.key === "Escape") { event.preventDefault(); event.stopPropagation(); setEditing(false); event.currentTarget.blur(); } }} />
{!active && <div className={styles.textSelectLayer} role="button" tabIndex={selected ? 0 : -1} aria-label={`单击选中,双击编辑${label}`}
onPointerDown={(event) => { press.current = { x: event.clientX, y: event.clientY, moved: false }; }}
onPointerMove={(event) => { if (Math.hypot(event.clientX - press.current.x, event.clientY - press.current.y) > 4) press.current.moved = true; }}
onDoubleClick={(event) => { if (!press.current.moved) { event.preventDefault(); event.stopPropagation(); if (!selected) actions.select(id); begin(); } }}
onKeyDown={(event) => { if (selected && (event.key === "Enter" || event.key === "F2")) { event.preventDefault(); event.stopPropagation(); begin(); } }} />}
</div>;
}