API 总览
CallioText 的所有导出都来自同一个入口 @project-callio/calliotext,数量在一百个以上。
这一页先按模块把它们分成五组,说明每组的职责和边界;逐项的细节可以配合
TypeDoc 完整参考查阅。
模块分层
库的源码分为下面几层,越靠下越基础:
从下往上看。最底层的 core 是纯数据:一级和二级概念的类、七种节点的类型定义、
树的校验函数。它不依赖 React,也不关心界面,任何环境都能引用,比如在服务端校验一篇文档。
往上一层是 implbase 和 uibase,一批 React 基础设施:
读取当前节点和参数的 hooks、样式配置系统、支持键盘导航的按钮组件,以及贯穿全库的异常类。
它们自己不构成编辑器,但上面两层都搭在它们之上。
再往上,editor 和 printer 并排而立,分别是编辑一侧和输出一侧的核心。
并排意味着互不依赖:editor 不知道文档将来会被怎样排版,printer 也不知道文档是怎么被编辑出来的,
两者只共享 core 定义的文档树。教程第 1 章用编译器前端和后端做的比喻,说的就是这个结构。
editor 负责对 Slate 的封装、树操作和插件系统;printer 负责两阶段渲染和渲染器协议。
最顶层的 default_implementation 把下面所有东西组装成开箱即用的成品:
完整的编辑器和印刷器组件、各类渲染器工厂函数、contexter 系列。教程通篇使用的都是这一层。
日常使用的路径通常也是自顶向下的:从 default_implementation 的组件和工厂开始; 需要定制某个概念的外观时,用工厂的定制点,配合 implbase 的 hooks; 需要程序化修改文档或编写插件时,下到 editor; 需要自动编号和交叉引用时,和 printer 的预处理机制打交道; 而 core 随时都在场,因为概念和节点类型贯穿一切。下表是各层职责的速查:
| 分层 | 职责 | 典型使用场景 |
|---|---|---|
| core | 纯数据层:概念类、节点类型定义、树的校验。不依赖 React。 | 定义概念、持久化、类型标注 |
| editor | 编辑一侧:对 Slate 的封装、渲染器的注册与分派、树操作方法、插件系统、编辑器状态 hooks。 | 写自定义插件、自定义按钮、程序化修改文档 |
| printer | 输出一侧:两阶段渲染(预处理加渲染)、渲染器协议、预处理产物的类型定义。 | 写自定义印刷渲染器、实现引用类功能 |
| default_implementation | 默认实现:完整的编辑器和印刷器组件、各类渲染器工厂函数、contexter 系列。 | 绝大多数应用从这一层开始用 |
| implbase / uibase | 基础设施:useNode、useParameters 等 hooks、样式配置系统、UI 小组件、异常类。 |
在自定义渲染器内部使用 |
典型的组装方式
教程第 3 到第 5 章搭建的结构,浓缩起来就是这样:
import {
// core:定义概念
FirstClassConcept, SecondClassConcept,
// printer:印刷核心
Printer,
// editor:编辑核心
EditorCore,
// default_implementation:默认组件与工厂
DefaultEditorComponent, DefaultPrinterComponent,
get_default_editors, get_default_group_renderer,
} from "@project-callio/calliotext"
const printer = new Printer(first_concepts, second_concepts,
printer_renderers, printer_defaults)
const core = new EditorCore({renderers, default_renderers: get_default_editors(), printer})
<DefaultEditorComponent editorcore={core} />
<DefaultPrinterComponent printer={printer} root={tree} />
这几行浓缩了各层之间的接线:core 定义的概念交给 Printer 保管;Printer 交给 EditorCore, 供编辑侧随时查询;最后两个默认组件各自拿着自己一侧的核心开始工作。 任何 CallioText 应用的骨架都是这个形状,区别只在概念清单和渲染器的具体内容。
贯穿全库的几条约定
下面这些约定在各个模块里反复出现,先记住它们,读后面几页会顺畅很多:
- 渲染器字典按一级概念名索引。形如
{group: {"primary": renderer}, inline: {...}, ...}, 第一层是节点种类,第二层是一级概念名。查不到的节点使用按节点种类提供的默认渲染器。 - 文档节点引用的是二级概念。节点的
concept字段存二级概念名, 由Printer解析出它继承的一级概念,进而找到渲染器和参数原型。 - 参数有两种形态。树上存储的是带类型标注的
ParameterList(形如{type, val}); 渲染代码收到的是处理后的ProcessedParameterList:二级概念的重写已经套用、 函数型参数已经求值、类型包装已经剥掉,拿到的直接是普通值。 - 命名风格。函数和方法是 snake_case(
get_root),类和组件是 PascalCase(EditorCore)。 个别导出保留了历史拼写,例如get_deafult_group_editor_with_appbar和模块名intermidiate,使用时照抄即可。