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

256 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# [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`
- 文档页在阅读态和编辑态之间切换。
- `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` 两种插入规格。
- 这说明自定义块虽然很多,但真正能被稳定工具链操作的只是一小部分。
### 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 的命令容器参考。
不直接采用的部分:
- `edita` UI 壳和示例不是当前主链事实层。
- 原因:`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 参考。