11 KiB
11 KiB
[recycle] Rust Block Editor Phase 0 Baseline v1
更新时间:2026-04-18
关联文档:
/mnt/Data1T/mnote/design/old/05-editor-mainline/process/ai-first-rust-block-editor-baseline-v1.md/mnt/Data1T/mnote/design/05-editor-mainline/reference-code//mnt/Data1T/mnote/wolai-frontend/src/components/editor/schema.ts/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsx/mnt/Data1T/mnote/wolai-frontend/src/lib/blocks/block-ops-adapter.ts
1. 目的
本文用于冻结 task-048 所需的 Phase 0 基线:
- 盘点当前 BlockNote 自定义块真实范围
- 盘点文档读写耦合点
- 冻结第一阶段 Rust Block Editor 的必须做 / 后补 / 延期边界
- 明确
reference-code的采用、部分采用、不采用依据
Phase 0 的目标不是替换完全部现有能力,而是先把“什么必须进入第一阶段主链、什么只能先保留占位、什么明确延期”说清楚。
2. 当前 BlockNote 自定义块清单
当前 customBlockSchema 已注册的自定义块如下:
headingadvancedTodopageReferenceblockReferencemediaprogressMetermindmaponlineTable
对应实现位置:
heading/mnt/Data1T/mnote/wolai-frontend/src/components/editor/schema.ts- 现状:覆盖 BlockNote 默认标题块,允许 1-5 级并支持折叠。
advancedTodo/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/AdvancedTodoBlock.tsx- 现状:状态为
todo/doing/done/cancelled,点击轮转,Alt+Click可直接置为cancelled。
pageReference/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/PageReferenceBlock.tsx- 现状:块级页面引用,依赖
pageId/title/asChildPage,点击直接跳转文档页。
blockReference/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/BlockReferenceBlock.tsx- 现状:块级引用占位,运行时拉
/api/blocks/get,仅对段落/标题提供纯文本回写。
media/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MediaBlock.tsx- 现状:附件卡片,带选择资源、对齐、边框、OCR、下载、OnlyOffice 打开等强 UI 行为。
progressMeter/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/ProgressBlock.tsx- 现状:支持自动/手动模式;自动模式由编辑器扫描后续
advancedTodo并计算百分比。
mindmap/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/MindmapBlock.tsx- 现状:内嵌思维导图壳,包含预览、内联编辑、全屏、独立页、自动保存、资源联动。
onlineTable/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocks/OnlineTableBlock.tsx- 现状:内嵌表格预览卡片,支持拖拽改尺寸、删除、全屏编辑。
3. 当前读写耦合点
3.1 写链耦合
当前编辑主链仍深度绑定 BlockNote:
/mnt/Data1T/mnote/wolai-frontend/src/components/editor/blocknote-editor.tsxuseCreateBlockNote(...)直接以customBlockSchema启动编辑器。- 保存经
saveContent(...) -> /api/documents/save整体回写块树快照。 - 自定义块的大量副作用都挂在 BlockNote 壳上:
progressMeter自动统计media删除与恢复mindmap删除、自动保存、资源广播onlineTable删除、全屏切换
- 协作仍挂着
HocuspocusProvider + Y.Doc,这与“当前不需要协作”的新主线并不一致。
3.2 读链耦合
/mnt/Data1T/mnote/wolai-frontend/src/components/editor/document-content.tsx- 文档页在阅读态和编辑态之间切换。
initialPageSubtree与serverPageSubtreeSnapshot已经进入页面读态,但编辑态仍直接消费 BlockNote 内容快照。
- Phase 0 的关键判断:
- 阅读态已经开始朝稳定 projection 收口。
- 编辑态仍把 BlockNote 的块树和自定义 props 当成事实层。
3.3 工具与编辑器模型耦合
/mnt/Data1T/mnote/wolai-frontend/src/lib/blocks/block-ops-adapter.ts- 当前 AI / server tool 适配只支持
paragraph与heading两种插入规格。 - 这说明自定义块虽然很多,但真正能被稳定工具链操作的只是一小部分。
- 当前 AI / server tool 适配只支持
3.4 复杂块与正文块混杂
当前一个 BlockNote 文档同时承载:
- 轻量正文块:
heading、段落、列表、待办 - 语义引用块:
pageReference、blockReference - 重型宿主块:
media、mindmap、onlineTable - 派生统计块:
progressMeter
这会导致第一阶段编辑器如果不先切分边界,就会被复杂块宿主逻辑拖着走。
4. 第一阶段迁移范围冻结
4.1 必须做
下面这些能力必须进入第一阶段 Rust Block Editor 主链:
heading- 必须保留 1-5 级标题与折叠语义。
- 原因:这是阅读态结构、目录、AI 引用定位的基础。
advancedTodo- 必须保留最小四态语义:
todo/doing/done/cancelled。 - 原因:当前
progressMeter依赖它,且任务型记录是高频场景。
- 必须保留最小四态语义:
pageReference- 必须保留块级引用能力,并与后续行内页面引用 token 对齐。
- 原因:页面导航和引用挂接是高频主链。
blockReference- 必须保留“占位插入 + 回显 + 最小跳转”能力。
- 原因:当前产品已存在块引用占位语义,但不要求第一阶段保留远程原位编辑。
media- 必须保留“附件块占位 + 标题/描述 + 打开原资源”最小能力。
- 原因:附件是文档主链,不应在替换编辑器时丢失。
- 最小块命令集
- 单块编辑
- 插入同级块
- 删除块
- 合并块
- 上移下移
- 有限缩进
- 最小格式收口
- JSON 块快照
- Markdown 导入导出
- Rust command 层稳定执行
4.2 后补
下面这些能力保留,但不要求在第一阶段做成完整壳:
progressMeter- 后补为“派生块”或“只读统计块”。
- 原因:其核心不是富交互编辑,而是基于
advancedTodo的派生结果。
mindmap- 后补为“占位卡片 + 打开独立编辑器/独立页”。
- 原因:当前实现太重,不应绑进第一阶段核心编辑循环。
onlineTable- 后补为“占位卡片 + 打开全屏表格编辑器”。
- 原因:表格预览和尺寸拖拽属于宿主 UI,不是轻量块编辑核心。
media- 第一阶段只保留最小资源卡片。
- OCR、OnlyOffice、复杂菜单、拖拽尺寸属于后补。
blockReference- 第一阶段只保留占位和跳转。
- 远程拉块、原位编辑、富回显属于后补。
4.3 延期
下面这些能力明确延期,不进入第一阶段主链:
- Yjs / Hocuspocus 协作
- BlockNote / ProseMirror 专属菜单状态兼容
mindmap内联复杂快捷键与嵌入式编辑器行为onlineTable内嵌尺寸拖拽与高保真表格交互media的完整 OCR / 上传 / replace-storage 流程- 任何依赖 BlockNote runtime 才能成立的行为
5. Phase 0 冻结清单
5.1 必须做清单
- 把
heading、段落、列表、基础待办、advancedTodo抽成 Rust editor core 的稳定块模型 - 把
pageReference与blockReference抽成稳定引用块,而不是继续仅作为 BlockNote 自定义 React block - 把
media抽成最小附件占位块,保留资源 id / 标题 / 打开动作 - 规定
mindmap、onlineTable第一阶段只以宿主占位块进入文档 - 把块命令统一成 Rust 侧可测试命令,不再把 Enter / Backspace / Tab 语义写死在 BlockNote 事件壳
- 把保存边界从“直接保存 BlockNote 快照”改为“保存 Rust block document + 最小宿主块 props”
5.2 后补清单
progressMeter自动统计改成独立派生器mindmap预览投影和独立编辑器接缝onlineTable预览投影和独立编辑器接缝blockReference远程块拉取和最小编辑同步media高级工具栏、OCR、OnlyOffice 入口
5.3 延期清单
- 协作协议
- BlockNote 级 UI 状态兼容层
- 重型块的嵌入式内核迁移
6. reference-code 采用依据
6.1 edita-core:采用
采用依据:
edita-core/src/lib.rs已经给出最小Editor / Block / Command无头边界。- 这与第一阶段“先把块命令从 UI 壳里抽出来”的目标完全一致。
- 它不绑定 DOM、ProseMirror、Tiptap,因此适合作为 Rust editor core 的命令容器参考。
不直接采用的部分:
editaUI 壳和示例不是当前主链事实层。- 原因:
mnote需要的是 command / state 组织,不是直接套它的现成编辑器外壳。
6.2 blocks:采用
采用依据:
blocks/src/block.rs、document.rs、converters.rs、history.rs、diff.rs、sanitizer.rs已覆盖:- 块文档模型
- Markdown / HTML / JSON 转换
- history
- diff / merge
- 这正是第一阶段最缺、且不该再自研一套的基础层。
部分保留胶水的地方:
mnote的pageReference、blockReference、mindmap、onlineTable不是blocks原生块型,需要补最小扩展映射。
6.3 kode:部分采用
部分采用依据:
kode-core的 buffer / selection / editing primitives 可作为块内输入器参考。kode-leptos的MarkdownEditorComponent与TreeWysiwygEditor可提供 Leptos 侧输入和光标处理样板。kode-doc的 tree node / token position 说明它适合借鉴“结构化编辑器内部表示”。
不直接全量采用的原因:
kode-doc自带一套更接近富文本树编辑器的内部结构。mnote第一阶段不需要把全部文档事实改造成另一套通用 tree editor 语义。
6.4 leptos-tiptap:部分采用
部分采用依据:
src/api/component.rs、use_tiptap_editor.rs、runtime/bridge.rs对 Leptos 接第三方 runtime 的方式很清楚。- 若 Rust-native UI 壳卡住,它适合当 fallback 接缝参考。
不作为主线采用的原因:
- 它本质仍是 Tiptap runtime bridge。
- 第一阶段目标是 Rust-native 轻量块编辑器,而不是再回到 JS 富文本 runtime 作为主事实层。
7. Phase 0 结论
Phase 0 的冻结口径如下:
- 第一阶段必须覆盖
heading、advancedTodo、pageReference、blockReference、media的最小稳定语义。 progressMeter、mindmap、onlineTable进入第一阶段时只保留占位或派生结果,不把完整嵌入式编辑能力一起搬过去。- 命令核优先采用
edita-core思路,文档模型与转换优先采用blocks,输入壳局部借鉴kode,leptos-tiptap仅作 fallback 参考。