Files
mnote/design/old/05-editor-mainline/process/rust-block-editor-phase0-baseline-v1.md
T

11 KiB
Raw Blame History

[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 基线:

  1. 盘点当前 BlockNote 自定义块真实范围
  2. 盘点文档读写耦合点
  3. 冻结第一阶段 Rust Block Editor 的必须做 / 后补 / 延期边界
  4. 明确 reference-code 的采用、部分采用、不采用依据

Phase 0 的目标不是替换完全部现有能力,而是先把“什么必须进入第一阶段主链、什么只能先保留占位、什么明确延期”说清楚。

2. 当前 BlockNote 自定义块清单

当前 customBlockSchema 已注册的自定义块如下:

  • heading
  • advancedTodo
  • pageReference
  • blockReference
  • media
  • progressMeter
  • mindmap
  • onlineTable

对应实现位置:

  • 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.tsx
    • useCreateBlockNote(...) 直接以 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
    • 文档页在阅读态和编辑态之间切换。
    • initialPageSubtreeserverPageSubtreeSnapshot 已经进入页面读态,但编辑态仍直接消费 BlockNote 内容快照。
  • Phase 0 的关键判断:
    • 阅读态已经开始朝稳定 projection 收口。
    • 编辑态仍把 BlockNote 的块树和自定义 props 当成事实层。

3.3 工具与编辑器模型耦合

  • /mnt/Data1T/mnote/wolai-frontend/src/lib/blocks/block-ops-adapter.ts
    • 当前 AI / server tool 适配只支持 paragraphheading 两种插入规格。
    • 这说明自定义块虽然很多,但真正能被稳定工具链操作的只是一小部分。

3.4 复杂块与正文块混杂

当前一个 BlockNote 文档同时承载:

  • 轻量正文块:heading、段落、列表、待办
  • 语义引用块:pageReferenceblockReference
  • 重型宿主块:mediamindmaponlineTable
  • 派生统计块: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 的稳定块模型
  • pageReferenceblockReference 抽成稳定引用块,而不是继续仅作为 BlockNote 自定义 React block
  • media 抽成最小附件占位块,保留资源 id / 标题 / 打开动作
  • 规定 mindmaponlineTable 第一阶段只以宿主占位块进入文档
  • 把块命令统一成 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 的命令容器参考。

不直接采用的部分:

  • edita UI 壳和示例不是当前主链事实层。
  • 原因:mnote 需要的是 command / state 组织,不是直接套它的现成编辑器外壳。

6.2 blocks:采用

采用依据:

  • blocks/src/block.rsdocument.rsconverters.rshistory.rsdiff.rssanitizer.rs 已覆盖:
    • 块文档模型
    • Markdown / HTML / JSON 转换
    • history
    • diff / merge
  • 这正是第一阶段最缺、且不该再自研一套的基础层。

部分保留胶水的地方:

  • mnotepageReferenceblockReferencemindmaponlineTable 不是 blocks 原生块型,需要补最小扩展映射。

6.3 kode:部分采用

部分采用依据:

  • kode-core 的 buffer / selection / editing primitives 可作为块内输入器参考。
  • kode-leptosMarkdownEditorComponentTreeWysiwygEditor 可提供 Leptos 侧输入和光标处理样板。
  • kode-doc 的 tree node / token position 说明它适合借鉴“结构化编辑器内部表示”。

不直接全量采用的原因:

  • kode-doc 自带一套更接近富文本树编辑器的内部结构。
  • mnote 第一阶段不需要把全部文档事实改造成另一套通用 tree editor 语义。

6.4 leptos-tiptap:部分采用

部分采用依据:

  • src/api/component.rsuse_tiptap_editor.rsruntime/bridge.rs 对 Leptos 接第三方 runtime 的方式很清楚。
  • 若 Rust-native UI 壳卡住,它适合当 fallback 接缝参考。

不作为主线采用的原因:

  • 它本质仍是 Tiptap runtime bridge。
  • 第一阶段目标是 Rust-native 轻量块编辑器,而不是再回到 JS 富文本 runtime 作为主事实层。

7. Phase 0 结论

Phase 0 的冻结口径如下:

  • 第一阶段必须覆盖 headingadvancedTodopageReferenceblockReferencemedia 的最小稳定语义。
  • progressMetermindmaponlineTable 进入第一阶段时只保留占位或派生结果,不把完整嵌入式编辑能力一起搬过去。
  • 命令核优先采用 edita-core 思路,文档模型与转换优先采用 blocks,输入壳局部借鉴 kodeleptos-tiptap 仅作 fallback 参考。