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

256 lines
11 KiB
Markdown
Raw Normal View 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`
- 文档页在阅读态和编辑态之间切换。
- `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 参考。