docs(canvas): clarify editing guards and projection lifetimes

This commit is contained in:
2026-11-12 16:18:24 +08:00
parent 65c54e7b9e
commit f28d3810d4
7 changed files with 16 additions and 3 deletions
+2
View File
@@ -17,11 +17,13 @@ export function NodeTitle({ id, title, selected,renderedTarget }: { id: string;
useEffect(() => { if (!selected) setEditing(false); }, [selected]);
useEffect(() => { if (editing) { input.current?.focus(); input.current?.select(); } }, [editing]);
/** blur是统一提交入口:忽略取消、空名称与无变化名称,随后复位取消标记并退出输入态。 */
// rename 是同步动作入口,不等待远端 ACK;若实现抛错,下方标记复位与退出也不会自动执行。
function save() {
if (!cancelled.current) { const name = value.trim(); if (name && name !== title) actions.rename(id, name); }
cancelled.current = false; setEditing(false);
}
// Enter在非输入法组合态触发blur保存,Escape先置取消标记再blur;按键不继续冒泡到画布。
// maxLength 是浏览器 UTF-16 长度限制;此 save 只 trim/去空/比旧值,不另做 UTF-8 字节校验。
// 标题长度限制300字符,nodrag/nopan/nowheel避免文本操作被当成画布手势。
if (editing) return <input ref={input} className={`${styles.nodeTitleInput} nodrag nopan nowheel`} value={value} maxLength={300} aria-label="节点名称" onChange={(event) => setValue(event.target.value)} onBlur={save}
onKeyDown={(event) => { event.stopPropagation(); if (event.key === "Enter" && !event.nativeEvent.isComposing) event.currentTarget.blur(); if (event.key === "Escape") { cancelled.current = true; event.currentTarget.blur(); } }} />;