默认实现总览

教程里,DefaultEditorComponent 一直是个黑盒:把编辑器核心交给它,一个能用的编辑界面就出现了。 这一部分把这个盒子拆开。本页先讲清楚默认实现在整个库里的位置、它为什么被设计成一个可以整体替换的层, 以及那个组件到底替你装配了哪些东西;后面几页分别讲界面、键盘、渲染器工厂、定制手段和印刷侧。

库分成哪两半

库的代码分成两大部分。一部分是核心:概念与节点的定义、编辑器核心、印刷器核心。 它们只关心「文档树是什么样、怎么被修改、怎么被渲染」,不做任何界面上的决定。 核心里没有一个按钮、没有一种配色、没有一条快捷键。

另一部分就是默认实现。它是对「界面应该长什么样」这个问题给出的一整套答案: 一块纸张、一条侧边栏、每个节点上的一排按钮、两个可以拖动的浮动面板、一整套快捷键, 以及印刷侧的一套排版部件。这套答案是有立场的,它假设你在做的是一个偏长文、偏严肃、 需要频繁操作结构的编辑器;如果你的场景不是这样,这一层可以整个不要。

这条分界线的位置解释了一个乍看奇怪的设计:编辑器和印刷器都各自分成了「核心」和「组件」两个对象。 EditorCoreEditorComponent 是一对,PrinterPrinterComponent 是另一对。核心保存信息但不负责绘制,组件负责绘制但不保存信息。

拆开的好处是同一个核心可以同时被多个组件使用。默认实现里编辑抽象节点的那个浮动窗口就是现成的例子: 它是又一个编辑器组件,和主编辑器共用同一个编辑器核心,因此两边看到的概念定义、渲染器完全一致, 在脚注里插入的定理和在正文里插入的定理走的是同一套代码。

三档深度

对使用者来说,上面这条分界线意味着有三档不同深度的做法,代价和自由度依次增加。

做法你要写的适合
直接用默认实现概念定义、渲染器,以及 DefaultEditorComponent 的几个参数绝大多数情况
在默认实现上改造加上自定义按钮、替换个别渲染器、改配置和主题需要自己的操作或外观时
不用默认实现基于 EditorComponent 自己搭整套界面界面形态和默认实现差得很远时

第三档很少有人需要,但它是可行的:默认实现没有使用任何私有接口,它调用的东西你都能调用。

DefaultEditorComponent 装配了什么

这个组件本身几乎没有业务逻辑,它的价值在于把七八个必须同时存在、且顺序不能错的东西套在了一起。 把它渲染出来的结构从外往里剥,依次是:

作用
EditorConfigContext.Provider把样式配置(字体、边距、宽度)交给下游所有组件,渲染器里用 useEditorConfig() 读取
SnackbarProvider提示气泡的容器,来自 notistack
IdxConflictSolver监视文档里是否出现重复的节点编号,出现时自动重新编号
KeyEventManager全局按键分发器,来自 @ftyyy/mouseless
EditorComponent真正的编辑器组件,也就是那块可以打字的纸
EditorGlobalInfo.Provider把编辑器实例交给下游,侧边栏、浮动面板、你自己写的按钮都靠它拿到编辑器
DefaultSidebar / Areas / AbstractEditorArea侧边栏、两个浮动面板、抽象节点的浮动编辑器

其中三层值得单独说明。

第一层是 SnackbarProvider。它在这里出现的原因是,默认实现的按钮在操作成功或失败时会弹出提示, 而弹提示需要一个容器。它被放在编辑器内部,意味着你在自定义按钮里可以直接调用 useSnackbar(), 不需要自己再套一层。反过来,如果你想在编辑器之外的地方(比如页面顶栏)弹提示, 那就需要在更外层自己再放一个 SnackbarProvider

第二层是 IdxConflictSolver。教程第 1 章说过,每个概念节点都有一个全文唯一的编号 idx,交叉引用就是靠它定位的。复制粘贴会天然地破坏这个唯一性:复制一个定理再粘贴, 文档里就出现了两个 idx 相同的节点,引用会指向错误的目标。这个组件在每次文档变化后检查冲突, 发现之后给其中一个重新编号。这是一件必须做、但没有人愿意自己写的事情,所以默认实现替你做了。

第三层是 KeyEventManager,它是整套键盘操作的中枢。所有按键先到它这里, 再按当前状态分发给对应的界面部件;默认编辑器在这里注册了四组界面元素,并登记了一批需要 阻止浏览器默认行为的组合键。这套机制单独一页讲,见键盘操作

这一部分怎么读

剩下五页各自独立,可以按需要挑着读,顺序大致是从「看得见的」到「改得动的」:

内容
编辑界面纸张、节点上的八个按钮、参数抽屉、抽象节点、侧边栏、两个浮动面板,以及必须由你摆放的 AreaContainer
键盘操作空间导航的模型、全部组合键、按键提示
编辑渲染器工厂各类节点的渲染器工厂及其选项、UniversalExtra、渲染器里可用的 hook
定制默认编辑器样式配置、追加按钮、主题,以及替换单个渲染器
印刷侧的默认实现DefaultPrinterComponent、印刷配置、排版部件

在线演示的源码(仓库的 demo/ 目录)是这一部分内容的一个完整用例, 读到某处觉得抽象时可以去那里对照。