7.2 KiB
7.2 KiB
[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_blockblocks:采用块内容变更与序列化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 commandblocks:采用文档删除和回放能力
3.5 上移下移
稳定语义:
- “上移下移”先冻结为平面重排
- 不承诺跨父节点、批量树移动、保留折叠上下文
新 editor core 的最小断言:
- 同一列表内块顺序可交换
heading、普通块、占位块都能复用同一 reorder 命令- 操作后序列化结果稳定
参考层采用依据:
edita-core:采用通用 reorder commandblocks:采用文档块顺序变更
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_placeholderblocks:采用自定义块型序列化kode:部分采用触发字符、候选框和插入位置处理
4. 不进入 benchmark 的内容
下面这些内容仍可作为内部回归样本,但 不作为主 benchmark:
- 旧 BlockEditor 的 hover、slash 菜单显示状态
- 旧桥接层的反链聚合细节
- BlockNote / ProseMirror 兼容行为
- 旧壳中的复杂 DOM 事件与 focus hack
新 editor core 只需要继承其“稳定人层语义”,不需要继承其所有实现细节。
5. 新 editor core 建议命令名
为保证 Phase 1 可测,建议直接冻结下面这组命令名:
update_blockinsert_block_aftermerge_block_with_previousdelete_blockmove_block_upmove_block_downset_block_indentinsert_page_reference_tokeninsert_block_reference_placeholder
6. 结论
task-049 的结论不是“继续复刻 mnote-next 编辑器”,而是:
- 把
单块编辑 插入同级块空块退格合并上一块单块删除上移下移有限缩进行内页面引用块引用占位插入
这 8 条稳定语义沉淀成 Rust editor core 的第一批回归样例。