# [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<State>` 风格封装 `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 的第一批回归样例。
