Skip to content

架构设计

本文档是 ARCHITECTURE.md阅读导读。完整 normative 规范(伪代码、验收清单、历史迁移)见仓库根目录原文。

分层总览

mermaid
flowchart TB
  subgraph shell [Shell — Vue 组件]
    YanivEditor
    EditorShell
  end
  subgraph runtime [Runtime — 纯推导]
    Profile[resolveEditorProfile]
    Chrome[resolveChromePolicy]
    SessionKey[computeSessionKey]
  end
  subgraph session [Session — Tiptap 生命周期]
    useEditorSession
    ContentAdapter
  end
  subgraph registry [Capability Registry]
    CAPABILITIES
    buildExtensions
  end
  YanivEditor --> EditorShell
  EditorShell --> Profile
  Profile --> useEditorSession
  CAPABILITIES --> buildExtensions
  buildExtensions --> useEditorSession
职责禁止
Shell布局、slot、expose、BlockMenuHost直接 initEditor、散落 watch
Runtimeprops → profile / chromePolicy / gates操作 Tiptap 实例
SessionsessionKey 重建、phase、受控内容UI 显隐逻辑
Registry能力 → 扩展 + toolbar 映射import NodeView 自 components

配置模型

四条轴合并为 EditorRuntimeProfile

  • Phasemode: edit | preview
  • Presetbasic | full | notion → 默认 features + layout
  • Appearanceappearance + colorMode
  • Overridesfeatures(显式 true/false;undefined 继承 preset)

mergeFeatures 是唯一合并入口。

ChromePolicy

resolveChromePolicy(profile, layout, gates) 决定 chrome 显隐。Shell 只读 policy,禁止模板内写 mode === 'preview'

preview 时:showEditChrome=false,顶栏/底栏/块菜单/上下文条隐藏;扩展集合不变。

大纲展开状态由 provideOutlinePanel 持有,不在 chromePolicy 中。初始状态由 defaultOutlineExpanded prop 控制(v0.1.1 起默认 false)。

Session 与 sessionKey

触发 rebuild:extension gates、locale、inline toolbar 签名、Inline 的 placeholder / extraExtensions、schema 相关选项。

不触发 rebuild:phase、appearance、colorMode、upload/gallery/aiConfig、defaultOutlineExpandedzIndexBase 等集成 props。

rebuild 流程:快照 content → destroy → loading skeleton → async buildExtensions → prepareEditorContent 按新 schema 清洗 → create Editor。

schema 收窄(如关闭 table)时,JSON 快照可能含未知节点;统一由 ContentAdapter.adaptJsonToSchema 提升未知节点子内容并剥离未知 mark,再交给 new Editor / setContent,避免 TipTap Unknown node type

Phase 切换

统一入口 requestPhaseTransition

  • edit → preview:先 emit 清理,再 setEditable(false)
  • preview → edit: setEditable(true)再 emit

ContentAdapter 用 raw transaction + BYPASS_GUARD_META,禁止 commands.setContent。写入前经 schema-aware 解析(HTML 走 DOMParser;JSON 走 adaptJsonToSchema)。

Capability Registry

src/capabilities/registry.ts 是唯一能力真相源。buildExtensions(host, ctx) 同时服务 Full / Inline。

Extension tier:

Tier示例Phase 行为
coreStarterKit, Link始终
contentImage, Table, AIpreview 仍展示
interactionDragHandle, Slasheditable 守卫
auxiliarySearchReplacephase 切换清状态
chromeCoupledOutlineDOM late-binding

Provide 树

核心 context 挂在 EditorShell 根(preview 不会卸载):

  • provideEditorRuntime
  • provideYanivEditor
  • provideEditorRoot / provideOverlayPortal(z-index token 与浮层挂载)
  • provideEditorLocale
  • provideBlockMenuHost
  • provideOutlinePanel

Z-Index 与浮层

  • z-index token 定义在 .yaniv-editorvariables.css),基准 --ye-z-base 默认 1000,由 zIndexBase prop 写入根节点。
  • EditorShell 在根内渲染 .yaniv-editor__overlay-portal;bubble menu、BlockPicker、mention、AI popover、Ant Design 浮层、自建 Toast/Notice 等均挂载于此,使用 document.body(drag preview / 隐藏 file input 除外);禁止 Ant Design 静态 message / notification
  • 详见 Z-Index 与浮层

架构不变量(摘要)

  1. DOM 属性仅声明式绑定(data-phasedata-color-mode
  2. 仅 sessionKey 触发 rebuild
  3. Chrome 显隐只读 chromePolicy
  4. 每实例独立 locale / appearance
  5. 扩展禁止全局 t(),走 ctx.locale
  6. AI config 用 getter,configure 阶段不 capture 静态值
  7. 浮层挂载 overlay portal,z-index 从编辑器根读取,禁止挂 body 或使用全局 z-index fallback

完整不变量见根目录 ARCHITECTURE.md

目录结构

src/core/runtime/     profile, chrome, sessionKey
src/core/session/     useEditorSession, ContentAdapter
src/core/shell/       EditorShell, chrome 子组件
src/capabilities/     registry, buildExtensions
src/extensions/       Tiptap 扩展实现
src/components/       工具栏与 UI 控件

详见 项目结构

测试

运行时纯函数与 Session 行为有 vitest 覆盖:runtime.test.tscontentAdapter.test.tsuseEditorSession.test.ts

运行:pnpm test