# [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 参考。