# [recycle] Rust Block Editor Interaction Samples v1 > 更新时间:2026-04-18 > > 主要来源: > - `/mnt/Data1T/mnote-next/docs/architecture/p1-human-stable-interface.md` > - `/mnt/Data1T/mnote-next/apps/web/app/components/editor/BlockEditor.tsx` > - `/mnt/Data1T/mnote-next/apps/web/app/components/editor/*.test.mjs` > > 定位说明: > - 这些样例是内部回归样本 > - 用来冻结“人层已稳定语义” > - 明确 **不作为主 benchmark** ## 1. 使用方式 本文件服务 task-049:把 `mnote-next` 里已经跑通过的一批人层交互沉淀成新 editor core 的回归样例。 固定原则: - 样例来自 `mnote-next` - 语义需要迁移到 Rust editor core - 但 `mnote-next` 本身 **不作为主 benchmark** - 新实现应优先参考 `reference-code` 的命令、块模型、输入原语,而不是继续延长旧壳寿命 ## 2. 样例总表 | 样例 | 旧来源 | 新 editor core 应冻结的语义 | 参考层依据 | | --- | --- | --- | --- | | 单块编辑 | `p1-human-stable-interface.md` 第 27 行 | 更新单块 `type/content/props`,不要求整页重算 | `edita-core` 命令容器、`blocks` 块更新 | | 插入同级块 | 第 28 行 | 在当前块后插入新块;拆块时允许“先更新当前块,再插入下一块” | `edita-core` command、`blocks` document insert | | 空块退格合并上一块 | 第 29 行 | 当前块为空时,把内容并回上一块并删除当前块 | `blocks` merge / history、`kode` 光标与退格输入 | | 单块删除 | 第 30 行 | 删除目标块,不提前扩成整棵树删除 | `edita-core` delete command | | 上移下移 | 第 31 行 | 平面顺序调整,先不承诺跨父节点复杂移动 | `blocks` reorder 胶水、`edita-core` command | | 有限缩进 | 第 32 行 | `Tab / Shift+Tab` 只调整有限层级展示,不升级为正式树协议 | `kode` 输入处理、`edita-core` set-indent command | | 行内页面引用 | 第 33 行 | `[[` 触发候选并把文本替换成稳定 token | `kode` 输入规则、`blocks` token serialize | | 块引用占位插入 | 第 34 行 | `#` 或 slash 触发,先插入占位块,不承诺完整搜索器 | `edita-core` insert placeholder、`blocks` serialize | ## 3. 回归样例明细 ### 3.1 单块编辑 稳定语义: - 当前焦点块的文本可直接修改 - 块类型转换仍保持单块粒度 - 标题级别调整属于同一块 props 更新 新 editor core 的最小断言: - 输入文本只产生一次 `update_block` - 标题级别变化不应触发整页重排 - `advancedTodo` 状态切换仍属于单块更新 参考层采用依据: - `edita-core`:采用 `Command` 风格封装 `update_block` - `blocks`:采用块内容变更与序列化 - `kode`:部分采用块内光标、输入和选择处理 - `leptos-tiptap`:不作为主实现,仅保留 Leptos 事件桥接参考 ### 3.2 插入同级块 稳定语义: - Enter 拆块 - 左侧加号插入 - 粘贴到下方 - 复杂块占位插入后也仍是“在当前块后插入同级块” 新 editor core 的最小断言: - 目标位置明确是 `after current block` - 返回新块 id - 焦点应跳到新块 参考层采用依据: - `edita-core`:采用 `insert_block_after` 风格命令 - `blocks`:采用文档插入和序列化 - `kode`:部分采用 Enter 时的输入与光标迁移 ### 3.3 空块退格合并上一块 稳定语义: - 当前块为空 - 按 `Backspace` - 若上一块允许合并,则把当前块内容并入上一块并删除当前块 新 editor core 的最小断言: - 合并后焦点回到上一块末尾 - 不应残留空块 - 若块类型不兼容,则明确返回 no-op 参考层采用依据: - `blocks`:采用 merge / history 的思路 - `kode`:部分采用退格、选择、光标偏移处理 - `edita-core`:采用“命令执行后改写状态”的方式,不把逻辑写死在 DOM 事件里 ### 3.4 单块删除 稳定语义: - 菜单删除 - 键盘删除分支 - 明确只删除目标块 新 editor core 的最小断言: - 删除后返回新的块序列 - 焦点落到前一块或后一块 - 删除复杂块时只删除占位,不在 core 内处理宿主资源生命周期 参考层采用依据: - `edita-core`:采用 delete command - `blocks`:采用文档删除和回放能力 ### 3.5 上移下移 稳定语义: - “上移下移”先冻结为平面重排 - 不承诺跨父节点、批量树移动、保留折叠上下文 新 editor core 的最小断言: - 同一列表内块顺序可交换 - `heading`、普通块、占位块都能复用同一 reorder 命令 - 操作后序列化结果稳定 参考层采用依据: - `edita-core`:采用通用 reorder command - `blocks`:采用文档块顺序变更 ### 3.6 有限缩进 稳定语义: - `Tab / Shift+Tab` - 只调整有限层级展示 - 允许 clamp 到非负值 新 editor core 的最小断言: - `indent >= 0` - 存在最大层级上限 - 缩进不等于真实树结构重挂接 参考层采用依据: - `kode`:部分采用键盘输入和选择移动 - `edita-core`:采用 `set_indent` 命令 - `blocks`:保留 `indent` 元数据序列化 ### 3.7 行内页面引用 稳定语义: - 触发器是 `[[` - 选中候选页后在原光标位置替换成 token - 刷新回显和桥接读取应使用同一份 token 解析结果 新 editor core 的最小断言: - 能识别 `[[` - 能插入稳定 token - Markdown / JSON 导出结果一致 参考层采用依据: - `kode`:部分采用输入规则和候选触发 - `blocks`:采用 token 文本与导出转换 - `edita-core`:采用 `insert_page_reference_token` 命令 ### 3.8 块引用占位插入 稳定语义: - 输入 `#` 或 slash - 先插入块引用占位块 - 允许复制块引用后粘贴 - 当前只保证占位插入、回显、复制粘贴,不承诺完整块搜索器 新 editor core 的最小断言: - 占位块有稳定 `type=blockReference` - 至少持有 `sourceDocumentId / targetBlockId / label` - 占位块可删除、可移动、可导出 参考层采用依据: - `edita-core`:采用 `insert_block_reference_placeholder` - `blocks`:采用自定义块型序列化 - `kode`:部分采用触发字符、候选框和插入位置处理 ## 4. 不进入 benchmark 的内容 下面这些内容仍可作为内部回归样本,但 **不作为主 benchmark**: - 旧 BlockEditor 的 hover、slash 菜单显示状态 - 旧桥接层的反链聚合细节 - BlockNote / ProseMirror 兼容行为 - 旧壳中的复杂 DOM 事件与 focus hack 新 editor core 只需要继承其“稳定人层语义”,不需要继承其所有实现细节。 ## 5. 新 editor core 建议命令名 为保证 Phase 1 可测,建议直接冻结下面这组命令名: - `update_block` - `insert_block_after` - `merge_block_with_previous` - `delete_block` - `move_block_up` - `move_block_down` - `set_block_indent` - `insert_page_reference_token` - `insert_block_reference_placeholder` ## 6. 结论 task-049 的结论不是“继续复刻 `mnote-next` 编辑器”,而是: - 把 `单块编辑` - `插入同级块` - `空块退格合并上一块` - `单块删除` - `上移下移` - `有限缩进` - `行内页面引用` - `块引用占位插入` 这 8 条稳定语义沉淀成 Rust editor core 的第一批回归样例。