跳到正文
QuireKit MSFE
开发者文档
v0.0.0 · 实验版本

自定义节点

从一个可点击的状态标记,理解语法、字段、命令和组件的完整接入。

体验字段修改

点击「待处理」将它切换为「已完成」,下方阅读预览同步改变。再读取 Markdown,确认按钮只改写 [[todo]] 中的状态,其他正文保持原样。撤销与重做同时更新编辑和阅读视图;切换只读后不能修改字段。

正在准备编辑器…

定义语法和字段

status.ts 使用 Node.create() 声明语义;addAttributes() 允许 value 字段并校验取值。defineSource() 的字面分隔符语法适合单行、不嵌套的 token。

read(document, node) 只读取已确认范围;不符合约定的值返回 null,继续显示源码。复杂或嵌套语法应通过 addMarkdownExtensions() 提供解析规则。

精确写回

patch(document, node, patch) 返回源码修改。这个例子保留两侧括号,只替换内部值。字段验证、只读、过期目标和撤销由编辑器统一处理。

@quirekit/msfe-core

不依赖特定解析器的语义编解码器;渲染是可选能力,不负责持久化。

SourceDefinitionts

添加命令

addCommands() 定义 insertStatus();types.ts 的模块增强让 editor.commands、editor.can() 和 editor.chain() 获得类型提示。命令使用提供的 tr,避免自己提交另一笔事务。

ts

替换组件

应用用 .extend({ addNodeView() { ... } }) 接入 VueNodeViewRenderer()。status-view.vue 接收 nodeView.attrs 和 updateAttributes(),无需自行计算源码偏移。

组件树必须包含 VueNodeViewHost。更换为 React 时保留同一语法扩展,使用对应的 renderer 与 host。

接入静态阅读

MdProse 使用 withMdReading(extension, definition) 接收第三方阅读贡献。先完成扩展的 configure() / extend(),再包装并安装到同一个编辑器。示例使用的公开入口是 @quirekit/md-editor/vue,不需要修改产品内部的语法分支。

ts

render(context, resource) 的 attrs 来自原扩展安装后的 codec,字段默认值与校验只定义 一次。context 同时提供 name、node、document 和 locale,不提供编辑动作。 renderInline(from?, to?) 与 renderBlocks(omitted?) 将子内容交回公共阅读器;行内范围 必须在当前节点内且不能截断一个子语法节点,非法范围会触发局部源码回退。

MdProse 的 state 接收原编辑器的不可变快照。示例用 const state = useMsfeState(editor) 接入 Vue,公共 hook 自动管理订阅与清理,见 Vue 状态订阅。 每次输入不序列化 Markdown,纯选区与焦点变化不重复解码或加载。 阅读只依赖源码、解析树、已安装贡献、呈现配置与 locale;codec 不应读取选区或可变外部状态 来决定静态内容。文档变化可以保守重建阅读快照,这个接口不承诺逐节点增量更新。

阅读资源与失败回退

有 IO 的贡献可声明 load(context, signal),返回 ResourceLease<Resource>,即 { value, release? },或相应 Promise。render 只在资源就绪后运行。取消信号在快照替换 或卸载时触发;即使加载方忽略取消,迟到资源仍会调用 release()。阅读资源与编辑 NodeView 的资源分别拥有生命周期,不自动重用 addSource().load。

待加载、失败和服务端渲染时保留原节点的精确源码;SSR 不启动加载。同步 renderer 可以 服务端渲染。Vue 子组件继承应用 provider,客户端子组件异常也隔离在本节点。 渲染器是宿主提供的可信代码,原始 Markdown 不会被当作 HTML 执行。

用 <MdProse @error="reportReadingError" /> 接收 MdReadingError,其中包含 owner、 read / load / render / dispose 阶段、原始异常与捕获快照的 UTF-16 范围。 这个范围是诊断信息,不能用于异步写回当前编辑器。无错误监听器时,Vue 阅读入口只保留 可见源码;宿主可按需接入日志。资源释放失败会被报告,不替换已经成功显示的新内容。

场景编辑 / 源码静态阅读
合法的自定义字段由原扩展 patch 精确修改,可撤销/重做使用同一个 codec 的默认值与校验结果
字段非法、未知或未闭合语法保留原文未命中贡献时保留内置展示或源码
代码块 / 行内代码中的 token仍是代码文本不额外解析成自定义节点
同语法有多个语义候选沿用安装顺序首个 codec 返回非 null 的候选拥有该节点
render 返回 undefined / null原文不变undefined 保留精确源码;null 明确不输出内容
加载等待、拒绝或渲染异常原文不变,其他块正常仅失败节点回退并可报告错误
只读模式字段动作与历史写入被拒绝继续展示同一份内容
没有 source codec / 重复阅读 owner明确拒绝安装不创建无效阅读贡献
React 或 Word/PDF/OFD 导出保留中立语义扩展此适配器只负责 Vue 阅读;导出需独立转换贡献

生命周期约束

离开视口、显露源码、换文档或销毁时,节点组件可能卸载。持久字段写回源码,临时 UI 状态按合适的生命周期管理;不要依赖组件永远挂载。

read、patch 与字段校验的契约

addAttributes() 是允许写入的字段清单,默认值与 validate 不能替代源码编码。read() 返回 null 表示这个已识别语法不属于该语义形式,原文保留;它不应修复或标准化用户文本。

patch() 接收局部字段,不保证包含所有字段。返回 { from, to, insert }、多个不重叠修改或 null。只替换需要的字段区域,保留空白、引号、其他属性和分隔符风格。如果新值包含分隔符,必须编码或拒绝,不能直接拼入语法。

只传入未知字段或不合法值时,运行时会拒绝。对多种源码拼写(例如单引号、双引号、参考定义)先定义可逆写回策略;不能写回的形式继续可读,不假装支持编辑。

source 指纹何时需要

默认源码身份由相关范围确定。提供 source(document, node) 可给出更小的精确指纹,但必须覆盖所有会被 patch 修改的字段。若控件只修改代码围栏语言,指纹可以只覆盖 header;若控件同时修改正文,就不能仍只比较 header。

指纹用于防止过期组件修改不同内容,不能用作持久业务 ID,也不能用节点在视口内的 id 保存到数据库。需要业务 ID 时把它定义为可校验的源码字段。

从字段到异步组件

defineSource<Attrs, Resource>() 可增加 load(attrs, signal)。组件收到 status: 'loading' | 'ready' | 'error' 和可选 resource;字段变化和卸载由资源协议管理。组件仍通过 updateAttributes()、deleteNode()、revealSource() 等受控动作操作源码。先看 异步资源,再增加上传或服务器查询。

块节点应该如何选择

本页的字面语法是单行、不嵌套 token,NodeView 只拥有这个 token 的显示。syntax helper 不适合冒号嵌套容器或任意跨行语法。容器正文沿用原生 Markdown,见 容器;跨行静态预览见 图表;自定义解析见 Markdown 插件。

检查新增节点是否完整

先验证合法、非法、未闭合和转义形式;再验证字段更新只改变对应源码、撤销恢复原样、只读动作拒绝、快速改字段时旧资源释放、组件卸载后动作失效。最后在窄屏和深浅主题下检视按钮与周围文本的基线、选区和焦点。

MSFE · QuireKitMarkdown 源码始终属于你。