先体验完整文档
打开 MD Editor 独立示例。同一份文档可以编辑、查看源码、只读浏览,
也可以通过 MdProse 查看静态阅读快照。示例包含嵌套提示块、折叠块、任务、列表、
引用、代码、表格、公式、流程图、思维导图、定义列表和脚注。模式切换保留编辑实例、选区与撤销历史。
@quirekit/md-editor 组合 MSFE 能力与 QuireKit 公共组件。源码、事务与解析仍属于
MSFE;正文外观由 Prose 定义。需要自己组合整个界面时,继续使用 Vue 接入。
先选保存模型,再选编辑器
| 需求 | 选择与边界 |
|---|---|
| README、技术文章、Git 审阅、跨工具 Markdown | MD Editor 以源码为权威;文档和源码视图共享文本与历史 |
| 富文档、可视块、更丰富的表格和格式 | Block Editor 使用 PM 结构文档与产品界面;按当前已交付能力接入,导出 Markdown 是有损风险的转换 |
| 自定义 schema、节点视图、已有 Tiptap 生态 | 原生 Tiptap 提供框架与扩展,宿主组合 UI 和服务;结构能力由 schema 与扩展决定 |
GFM 表格支持粗体、斜体、删除线、链接和行内代码;不支持嵌套表格、列表、代码块、多个段落、 合并单元格和任意列宽。多种行内样式可以嵌套,但标记前后的标点与文字决定实际解析。 行内代码内容按字面解释。不要把当前尚未实现的局部格式拆分,混同为 Markdown 禁止样式叠加。
可视格式命令共用 语法保真规划:保留既有样式并确认目标样式成立,
否则拒绝并保留原文;不会偷偷添加空格。单元格内允许行内格式,禁用标题、列表和块插入。
源码输入保持自由,不自动修复未完成或自定义语法。未知结构仍走源码回退。
扩展语法需要对应阅读器;仅保存 .md 不会自动包含评论、协作等外部状态。
完整对照与可编辑例子见 固定默认文档。规范依据: GFM 表格、 CommonMark 强调、 Tiptap schema。
四种视图
桌面的代码语言使用紧凑下拉列表,可通过方向键和标签前缀选择;文字样式使用按钮旁的 选择面板。窄屏代码语言保留可搜索的底部面板,文字样式整合到底部文字格式任务。 未知的现有语言仍会列出,选择“纯文本”会清除围栏的语言标记。 代码语言选择立即写回,可一次撤销;取消选择保留原文。文字格式按钮也立即应用, 关闭面板不会撤销已应用的设置。 示例页在窄屏使用同样的面板切换文档视图,回到编辑时保留选区与撤销历史。
窄于 768px 时,正文使用紧凑留白,底部工具栏提供撤销、重做、插入、文字样式、列表和 导入/导出。底栏使用公共 Toolbar 移动模式,不显示 Tooltip;当前表格动作只有放不下时才 收进“更多”,点击打开底部动作面板。插入目录先展示图片、链接、表格等常用内容,再展示 图表、结构和文字格式;搜索和参数表单提供输入提示。文字格式提供“全选、选中当前块”,后者选择光标所在的 最近完整 Markdown 块。空行与不完整围栏不提供块选择,选择动作不写源码或进入历史。 打开设置面板后,已聚焦过的正文保留静止光标或范围选区。 源文档替换、只读/locked 会清理或隐藏静止光标。移动 live 的键盘关闭或窗口失焦保留 被禁用的自绘端点;点击已有选区只切换操作菜单,不重新聚焦或唤起键盘。
选区菜单使用公共 Toolbar,提供复制、剪切、粘贴和全选,执行后自动收起。 粘贴读取系统剪贴板中的纯文本;浏览器不允许读取或使用局域网 HTTP 时,会打开粘贴面板, 可在“粘贴内容”输入框中调用系统粘贴,再点击“粘贴”替换原选区。取消或空内容不改动正文。 粘贴和剪切均可一次撤销;等待读取期间若选区或文档已改变,旧请求会取消。
窄屏触摸设备聚焦可编辑正文后显示公共 SelectionHandles 光标手柄:
拖动圆点移动光标;长按正文或圆点先保留插入点,实际拖动才扩大选区,不预选词语。松手后可拖动任一端点,
跨行或反向调整时保持端点身份。选区移动不增加文本撤销记录。移动 live 模式的正文
退出原生可编辑状态,由独立输入代理和共享 @quirekit/ime 接收键盘与中文组合输入,
光标和选区由产品绘制,避免系统菜单、光标和选区重叠。预编辑文字临时显示在正文中,
确认只提交一笔 CodeMirror 事务并可一次撤销;组合输入时光标继续显示,但手柄暂不可拖动。
源码、桌面、只读和独立嵌入编辑器保留各自的输入方式。文档、选区、命令和历史始终由 MSFE/CM 持有。
隐藏语法和零高度间隙只接受两侧的可见光标位置。点击或拖动到表格分隔线时,光标会
落到相邻单元格的文字插入点,空单元格仍可输入;边界处的中文预编辑保留在对应单元格内。
拖选靠近可用区域边缘时自动滚动,
松手立即停止。键盘缩小可用区域后,光标与圆点一起滚到工具栏上方;已可见的连续输入
不重复滚动,用户手动滚动也不会被拉回原位置。
工具栏消费当前可视视口,键盘遮挡时不重复加入底部安全区;示例编辑器 route 禁用 pinch,
原生输入至少使用 16px 字体以减少聚焦缩放。真实 iOS 的键盘附件条和候选窗仍需设备验证。
MD Editor 有四种视图,编辑和显示的都是同一份 Markdown 原文,中间不经过任何格式转换:
| 视图 | 设置 | 行为 |
|---|---|---|
| 文档视图(默认) | view="document" | 点击后仍隐藏已识别的标记,直接编辑正文;表格保持单元格,代码保留工具栏,容器保持连续结构 |
| 实时预览 | view="preview" | 段落或列表项的标记一起显露;活动表格显示结构源码、所选单元格显示行内标记,容器首尾围栏对齐 |
| 源码视图 | view="source" | 查看和编辑全部原文 |
| 阅读视图 | view="reading" | 用组件渲染当前文档,不可编辑;编辑器保持挂载,切回后选区和历史不变 |
只读不是单独的视图,而是叠加在前三种视图上的 readOnly:只停止输入,链接、折叠和复制照常可用,切换视图时保持不变。
四种视图共用一份 Markdown、选区、历史和 Prose 样式。示例页列出全部四种视图和只读开关,宿主也可以只提供其中几种。
<MdEditor :markdown="initialMarkdown" view="document" />
<!-- 改为 preview、source 或 reading 即切换视图,更新该属性无需重新挂载。 -->
无框架实例只包含三种可编辑视图(阅读视图是 Vue 组件里的渲染),通过公开方法切换:
import { createMdEditor, getMdView, setMdView } from '@quirekit/md-editor'
const editor = createMdEditor({ parent, markdown: '# 标题', view: 'document' })
const result = setMdView(editor, 'preview')
if (!result.ok) console.error(result.reason)
console.log(getMdView(editor)) // 当前视图
setMdView(editor, 'source', true) // 第三个参数设置只读
切换不修改源码、不进入撤销栈;拖选或组合输入期间延迟应用,避免改变正在输入的 DOM。 已隐藏的标记参与原生原子导航,列表回车继续列表,行首退格可以移除列表标记。 未知或不完整的语法仍保留可编辑源码;自定义投影应遵循 源码显露合同。 这不意味着任意 Markdown 插件自动拥有可编辑的文档 UI;复杂节点仍需声明投影、命令和回退。
实时预览按语义范围显露:跨行段落一起显示粗体、斜体、链接和行内代码的原始拼写;
任务项的列表前缀与 [x] / [ ] 同步显示,同级其他项保持阅读呈现。嵌套列表分别判断
各层列表项;容器里的段落独立判断,编辑一段不会显露其他段落的行内标记。
表格进入源码呈现时显示所有竖线和分隔行,但只显露所选单元格的行内标记。
输入法预编辑沿用这些范围,前后无关的标题、表格、代码、公式和图表继续保留呈现。
回车与块后输入
光标所在块会显示浅灰圆角背景,帮助识别当前段落、列表或引用的边界。容器内的正文按内部块 显示提示;这个提示不改源码、不增加间距,也不拦截鼠标。源码视图、只读和 阅读视图不显示它。
两种编辑体验都保留新建空段落的高度。被压缩的块间结构分隔行不接受正文光标,导航会落到
相邻真实内容;源码视图可以在这些行输入,切回后按新语法正常显示正文。
正文、ATX 标题及嵌套
容器里的段落按 Enter 会插入 Markdown 段落分隔,中间输入会拆分段落;空文档、连续回车和退出空列表后
都可以直接继续输入。块间纯排版分隔仍由 Prose 控制,编辑动作不重新序列化整篇文档。
| 位置或按键 | 行为 |
|---|---|
正文、ATX 标题里的 Enter | 从光标处分段;末尾开始新段落,标题后恢复正文 |
列表、引用里的 Enter | 续写当前标记;空列表项或空引用行直接退出一层,退出到正文时保留段落分隔 |
代码正文里的 Enter | 在当前代码块内换行 |
文档视图的表格单元格里 Enter | 在当前行后新增一行,保留列数与对齐;Tab / Shift+Tab 继续切换单元格 |
⌘+Enter / Ctrl+Enter | 在当前代码块、容器、表格、列表或引用后开始段落;嵌套块保留外层引用和列表缩进 |
正文里的 Shift+Enter | 插入两个尾随空格加换行的 Markdown 硬换行;保留外层列表缩进与引用前缀,不插入 <br> |
这些换段规则由 document 与 markdown 共用;纯源码视图保持原生源码输入。
引用末尾第一次回车立即显示引用内的可编辑空行,再按一次退出当前引用层级;嵌套引用逐层退出。
代码正文保留字面换行,实时预览中的表格保留源码操作;Setext 标题末尾在下划线之后换段。
换段可以单独撤销,只读与输入法组合状态继续由同一编辑实例管理。
光标与编辑边界
文档模式下,正文光标只能进入可编辑内容。功能插件声明完整结构范围和内部正文范围, 公共运行时据此处理方向键、Home/End、点击、拖选、删除和跨边界替换。所有范围使用 Markdown 源码偏移;隐藏标记和压缩空行不会产生第二套行号或文档。
默认行内代码保留样式外侧与内侧两个插入位置,加粗、斜体、高亮等直接进入内容。
代码围栏和语言信息受保护,代码正文可编辑;部分跨块删除保留外壳,完整选中块可以
整体删除。属性面板、图表等已投影的块组件按整体对象处理,边缘删除先选中整体。
正常回车、显式换行与退出块继续使用 addBlockInput(),见 块级回车 API。
覆盖产品默认规则
editingBoundaries 按解析树节点名称覆盖规则。下面把行内代码改为直接进入内容;
将 navigation 改为 split 可以恢复默认的内外两侧停留。宿主须先准备 #editor 容器。
import type { EditingBoundaryRule } from '@quirekit/msfe-core'
import { createMdEditor } from '@quirekit/md-editor'
const inlineCodeRule: EditingBoundaryRule = {
nodes: ['InlineCode'],
/** @param context - 当前已确认的语法。@returns 成对标记及可编辑正文,未闭合时返回 null。 */
resolve({ node }) {
const [opening, closing] = node.getChildren('CodeMark')
if (!opening || !closing) return null
return {
from: node.from, to: node.to,
contentFrom: opening.to, contentTo: closing.from,
kind: 'style', navigation: 'content', deletion: 'unwrap',
}
},
}
const editor = createMdEditor({
parent: document.getElementById('editor')!,
markdown: '正文 `code` 正文',
view: 'document',
editingBoundaries: [inlineCodeRule],
})
nodes 是解析树名称,from/to 覆盖反引号及文字,contentFrom/contentTo 只覆盖代码
内容;deletion: 'unwrap' 使边缘删除成对移除标记。规则查询不提交事务,也不改变
光标像素坐标。宿主离开时调用 editor.destroy() 释放实例。
Vue 沿用同一个 inlineCodeRule,通过组件属性传入:
<MdEditor :markdown="initialMarkdown" :editing-boundaries="[inlineCodeRule]" />
规则在创建/挂载时读取;改变规则集合需要重建实例,并由宿主保留需要的文档。
editingBoundaries: [] 表示没有宿主覆盖,内置规则继续生效。同一节点采用最高优先级
的第一条规则;该规则返回 null 表示退出该节点的语法边界处理,不再回退到默认规则。
已投影组件的整体对象保护独立保留。
在功能插件中声明
属于功能自身的规则放在 addEditingBoundaries()。以已有的行内代码语法为例,沿用
上面的规则声明一个扩展;宿主可以通过 extensions: [InlineCodeBoundaries] 安装它:
import { Extension } from '@quirekit/msfe-core'
const InlineCodeBoundaries = Extension.create({
name: 'inline-code-boundaries',
priority: 1000,
/** @returns 导航、选区和编辑共用的语法范围。 */
addEditingBoundaries() { return [inlineCodeRule] },
})
插件接入时使用此扩展承担规则,产品的 editingBoundaries 留给业务宿主覆盖。
已有插件可在自身 hook 中返回规则,或通过 .extend() 与父 hook 组合;同一节点的覆盖
规则应排在父规则前。该 hook 只描述边界,新增语法仍需由插件注册解析和投影。
when 默认是 hidden,只在整体隐藏语法的呈现中启用;prose 可在 实时预览
呈现中查询,规则应使用 isSourceRevealed(state, node) 判断具体结构是否已经显露。
源码视图关闭边界约束;在源码分隔行输入文字后,切回文档模式会按新语法把它作为正文。
当前 navigation: 'native' 会退出整条语法边界规则;若希望保留导航约束、将正文修改
交给原生处理,应使用 deletion: 'native'。旧 inlineBoundaries 通过同一个运行时兼容,
只替换原行内规则列表。六类边界、完整字段与高级 CM 接入见 编辑边界 API。
标题折叠
有正文的标题在左侧正文区域外提供折叠箭头,不挤占标题宽度。展开时悬停或键盘聚焦才显示, 收起后一直显示;触摸设备保留入口。点击后保留标题,收起到下一个同级或更高级标题之前的内容; 再次展开会保留子标题各自的折叠选择。支持 ATX 和 Setext 标题,容器、引用及列表项内的标题 以所在容器为边界。
文档视图、实时预览、只读与源码视图共用同一份折叠状态,折叠不改 Markdown,也不占用 文本撤销记录。查找定位到隐藏正文时会自动展开;改变标题层级导致旧范围失效时也会展开。 折叠选择不写入文件,刷新或替换文档后重置;Prose 静态阅读继续展示完整内容。
该能力归 @quirekit/msfe-heading,基础 MSFE 接入可通过 Heading.configure({ folding: false })
关闭标题控件及章节校验,原有 CodeMirror 源码折叠仍可使用。宿主可用 controls 和 toggleLabel
接入自己的组件与文案;MD Editor 默认使用公共 QuireIconButton 和统一图标。
块手柄与菜单
将鼠标移到块上,左侧会显示灰底描边的块类型与拖柄按钮,位于标题折叠箭头的外侧。点击打开菜单,或在正文中按
⌘+Alt+B / Ctrl+Alt+B。菜单使用公共 QuireKit 组件,可转换正文、标题和列表,
在上下插入内容,以及复制 Markdown、剪切、创建副本和删除。转换区只展示当前块可以执行的选项:
列表显示列表类型转换,代码、表格和公式等复杂块隐藏转换区,避免丢失结构。
窄屏触摸设备隐藏桌面悬停拖柄,插入入口保留在工具栏中;已经打开的块菜单继续保留锚点。
上下插入菜单按功能分组,在公共 QuireScrollArea 内滚动,包含当前安装的标题、Markdown 块、
公式、流程图、思维导图、白板、文本绘图,以及日期、表情和宿主提供的联系人。
图片、链接、公式和图表等先打开参数编辑器,确认后在原块前后一次插入;取消不会留下空块。
期间原块被改写、文档被替换或权限变为只读时,过时提交会被拒绝。
“流程图”“思维导图”和“白板”分别打开共享 Flow Editor、Mind Editor 和 Whiteboard Editor。
“文本绘图”打开共享源码绘图工作台,可选择 Mermaid、PlantUML 或 Graphviz / DOT。
Mermaid 的流程图、思维导图、时序图等在文本绘图里选择模板编写,保存为 Mermaid 代码块;
可拖拽编辑的流程图和思维导图保留各自的可编辑数据。
工具栏、空行加号和 / 菜单共用这些入口,图表分组放在段落列表之前。
默认示例文档直接包含项目交付流程、项目计划思维导图和灵感白板,保留完整可编辑数据及 从同一数据保存的 PNG 预览;双击即可继续编辑。单击会整体选中图形并浮出操作栏, 可编辑、预览、下载 PNG、复制、剪切或删除,白板还可重命名;选中后按 Delete 删除、Esc 取消。 预览会把文档里的图片和这几类图形按顺序放进同一图集,可左右切换。文本绘图部分还包含 PlantUML 时序图和 Graphviz / DOT 交付图,与公式一样单击整体选中、双击打开编辑;预览与下载 SVG 也在操作栏里。切换到 阅读视图可查看同一份内容。
光标进入或鼠标悬停可编辑空行时,左侧显示灰底描边的“+”,点击直接打开同一插入目录。 选择内容后替换该空行并保留必要的段落分隔,一次撤销恢复原文;取消菜单或参数编辑不改变源码。 代码、公式、列表内部的空白不作为独立插入位置;已声明子流的容器可在其空行内插入。
空段落中输入 / 也可打开同一目录,继续输入中文名称、英文别名或拼音首字母搜索,
例如 /表格、/table、/bg 或 /h2。上下方向键选择、Enter 插入,Esc 关闭并保留输入的文字。
图片、公式等复用同一个参数编辑器,取消保留 /查询,确认后一次撤销可恢复它。
菜单保留正文输入焦点,支持中文输入;普通正文、URL、代码、引用和列表内部不触发。
此入口独立于块拖柄,默认开启,可通过 :slash-menu="false" 动态关闭。
拖动手柄时显示原块摘要与插入线,松手才移动源码;一次撤销恢复整个操作。列表、引用、代码、
表格、公式与容器整体移动,容器内部的直接子块可在同一容器中排序。当前不做跨容器移动或
列表内部逐项拖动;会破坏外层围栏的插入不可用。Escape 或失焦取消拖动,源码更新会关闭旧菜单。
源码视图、只读和 阅读视图不显示操作手柄。行内公式直接点击公式编辑,不再附带铅笔按钮。
Vue 组件默认开启,可在挂载时用 :block-controls="false" 关闭。自建界面可使用
@quirekit/msfe-core 的 createSourceBlockControls,让核心提供当前块、视口几何、拖动状态及
版本化命令目标;宿主负责用自己的组件展示。自定义嵌套语法通过 sourceBlockScopes 声明子流。
空行通过可选的 insertionChange 和 openInsertionMenu 回调提供 SourceInsertionControls;
sourceBlankLineAt 查询当前位置,insertAtSourceBlankLine 负责受保护的空行插入,不构造虚假块节点。
rect 是整块边界,firstLine 是首个可见原生文本行的矩形,可用于让控件对齐换行标题的首行;
不含原生文本行的块组件返回 null,宿主可退回块顶部定位。
见 块控制协议 与 源码块命令。
每个 MdEditor 有独立的文档浮层,容纳块控件、块菜单、提及及工具栏插入面板。后代组件可从
@quirekit/md-editor/vue 调用 useMdOverlayTarget(),将返回的只读 ref 传给公共 Menu 的
portalTarget;子菜单自动继承同一目标。Menu 仍负责定位、视口避让与关闭,模态编辑器继续使用
公共 Dialog。该接口只提供挂载容器,不负责块命令或右键菜单的业务行为。
安装与宿主准备
当前包通过工作区或本地打包产物使用,尚未承诺公共 npm 稳定发布。
pnpm add '@quirekit/md-editor@workspace:*' '@quirekit/ui@workspace:*' '@quirekit/unocss-preset@workspace:*'
沿用应用的 QuireKit 主题、图标 Provider 和 UnoCSS / 独立样式入口。产品包没有第二套
颜色或正文 CSS。配置方法见 UI 与主题。SSR 应用应在客户端挂载
MdEditor,例如在 Nuxt 的 ClientOnly 中使用。
产品打包时另有 @quirekit/md-editor/styles.css,只负责工具栏和文档区域的布局,需显式
引入。正文的字体、间距和块外观仍来自公共 Prose 样式。
编辑底层使用源码维护的 @quirekit/cm-* 与 @quirekit/lezer-markdown。相邻块间距的
高度测量、旧视图清理与语法复用观察随包构建交付,无需额外安装 CodeMirror/Lezer 补丁。
每个包的 UPSTREAM.json 记录上游版本、commit 与本地差异,原始 MIT 许可随包保留。
原生 CodeMirror 扩展也必须从同一组 @quirekit/cm-* 导入;依赖官方 @codemirror/*
的第三方扩展需适配后使用,避免在同一编辑器混入两套 State、View 或 Facet。
Mermaid 使用 [email protected] 与 patches/[email protected],修复纯 SVG
模式下圆形等思维导图节点文字向右偏移的问题。编辑、阅读和 Word 图片导出共用此修复。
独立打包时仍需保留该 Mermaid 补丁;它针对默认 ESM 入口,不适用于独立浏览器脚本。
挂载、编辑与保存
<script setup lang="ts">
import { shallowRef, ref } from 'vue'
import { MdEditor, type MdEditorInstance } from '@quirekit/md-editor/vue'
import '@quirekit/md-editor/styles.css'
import { QuireButton } from '@quirekit/ui/vue'
const product = shallowRef<MdEditorInstance | null>(null)
const dirty = ref(false)
const initialMarkdown = '# 发布计划\n\n- [ ] 验证当前版本\n'
function save() {
const editor = product.value?.editor
if (!editor) return
const markdown = editor.getMarkdown()
// 将 markdown 交给应用自己的保存接口;成功后清除 dirty。
console.log(markdown)
}
</script>
<template>
<MdEditor ref="product" :markdown="initialMarkdown" locale="zh-CN" @change="dirty = true" />
<QuireButton :disabled="!dirty" @click="save">保存</QuireButton>
</template>
markdown 只作为挂载时的初始值,不是双向绑定。change 发出原始 MsfeChangeEvent
增量事件,不在每次输入后复制全文。换文档使用公开实例的 replaceDocument();
版本化外部更新使用 applyChanges()。完整规则见 读取与保存。
错误提示与原文保留
MdEditor 用公共 QuireAlert 显示创建或运行错误,提示文案跟随 locale。
创建失败时不会展示空白编辑器,而是通过 QuireProseSource 展示可复制的初始 Markdown。
已经创建的实例遇到扩展或监听器错误时保留当前文档、选区与撤销历史;关闭提示不会重建实例。
请先保存原文,再由应用决定是否在修正配置后重新挂载。
通过 @error="handleEditorError" 接收原始异常并接入应用自己的诊断服务。这个事件的参数
为 unknown,不把内部错误代码或堆栈当作用户提示。组件处理的是编辑器创建与 MSFE
onError 上报的错误,不会屏蔽应用其他位置的 Vue 错误或构建工具诊断。
配置产品能力
| 属性 | 用途 |
|---|---|
locale | 控件语言,zh-CN 或 en;不翻译文档正文 |
label | 编辑区的可访问名称 |
view | document(默认)、preview、source 或 reading;四种视图共用一份源码与历史,可响应式更新 |
readOnly | 叠加在前三种视图上的只读;只读时仍可展开折叠块和复制 |
mentions | 静态联系人数组或可取消的异步搜索函数;提供后启用提及菜单和输入 @ 的候选面板 |
documentLinks | 宿主文档链接配置:search 为静态文档数组或可取消的异步搜索(关键词为空时可返回最近文档),提供后输入 [[ 弹出文档搜索并插入标准链接 [标题](地址),“链接”对话框里也能搜索文档;recognize 识别指向宿主文档的地址,这类链接显示为带文档图标的引用;preview 返回文档的 Markdown 摘要,悬停引用时以缩略正文预览;exportUrl 决定导出 Markdown、Word 等文件时文档链接写成的地址,例如补全为完整网址 |
toolbar | 内置工具栏:true 或 'fixed'(默认)常驻正文上方;'floating' 在桌面端选中文字时于选区上方浮出样式、行内格式与链接;false 不显示。窄屏在非 false 时都使用底部工具坞 |
selectionToolbar | 固定工具栏时,桌面端选中文字也在选区上方浮出样式、行内格式、链接与“添加评论”,默认开启;只读时只保留“添加评论” |
blockControls | 挂载时启用块手柄、菜单与拖动排序,默认开启 |
slashMenu | 空段落中输入 / 搜索并插入内容,默认开启,可动态关闭 |
placeholder | 可编辑的空文档中显示的提示,默认「输入 / 插入内容,或直接开始写作」;传空字符串隐藏,挂载时读取 |
docx | Word 转换器与转换策略、图片回调,如 { converter: mdDocx() };未提供或 false 时隐藏 Word 导入、导出项 |
exporters | 宿主安装的导出格式(MdExporter 列表),如 PDF、OFD;每项在“导出”菜单中增加一个条目,复用所选模板和节点转换策略 |
layout | embedded 为嵌入式边框;document 为全宽工具栏与居中文档 |
outline | 在 document 布局中显示跟随阅读位置的标题大纲,默认关闭;宽度足够时固定在编辑区边缘,可收起成按钮再展开,宽度不足时点按钮弹出;正文独立居中,空间不足时避让大纲和评论 |
outlinePosition | 大纲位置:start(默认,正文左侧,右侧留给评论栏)或 end(正文右侧,在评论栏之后) |
features | 按 StarterKit 的同名选项替换或关闭功能 |
containers | 容器配置,false 关闭;types 替换完整名称列表 |
extras | 按 math、mermaid、textDiagram、footnotes、definitionList、subscript、superscript、insertedText、highlight、frontmatter 替换或关闭默认扩展;false 全部关闭 |
extensions | 额外 MSFE 扩展;不要重复安装已由产品提供的同名扩展 |
codeLanguages | 默认内置按需语言目录;传入后替换目录,[] 禁用,未注册语言保留纯文本 |
editingBoundaries | 挂载时按语法节点覆盖或新增边界规则;[] 保留功能默认策略,详见 光标与编辑边界 |
inlineBoundaries | 兼容的行内规则列表;默认代码内外分离,其他格式直接进入正文;[] 移除此列表,链接、块和组件规则仍生效 |
能力与语言目录在挂载时安装。切换功能集合时显式重新挂载,并由宿主保留需要的文档;
view、readOnly 可直接更新。更换整套界面语言建议按 locale 设置组件 key。
行内边界配置接受 InlineBoundaryRule[],每条声明语法 nodes、开闭标记 marker 和
behavior:split 保留内外插入位置,content 跳过重叠的边界停顿,native 使对应行内规则退出公共边界处理。
默认目录 mdInlineBoundaries 可从 @quirekit/md-editor 导入后复制修改;Vue 组件与
createMdEditor 使用同一选项。文档模式隐藏标记时生效,源码揭示、拖选与组合输入保持原有行为。
该选项和底层 inlineBoundaryNavigation(rules) 现在均适配到公共编辑边界运行时;新功能优先使用 addEditingBoundaries()。
空代码块的输入占位和默认语言列表见 代码块定制。
内置工具栏直接使用公共 QuireToolbar,与 Classic 共用分组、提示、选中态、方向键导航和
窄屏滚动。正文/标题使用与 Classic 相同的带边框选择器,文字格式平铺;插入菜单分组展示,
每项复用公共图标。菜单打开时捕获可映射的源码锚点,操作回到同一份 Markdown,参与原有撤销历史。
| 功能 | 实际写入与交互 |
|---|---|
| 正文与标题 | 正文、六级标题,保留原始 Markdown 文本 |
| 行内格式 | 粗体、斜体、删除线、行内代码,以及 ++下划线++、==高亮==、H~2~O、x^2^ 扩展 |
| 列表 | 对当前段落或选中行切换项目、编号、任务列表;嵌套缩进、回车继续列表、退格退出 |
| 链接与图片 | 对话框编辑地址、文字与标题;图片使用 QuireProseImage,不把资源内容写进文档 |
| 表格 | 在当前行上方/下方插入、删除当前行;在当前列左侧/右侧插入、删除当前列;按列设置左/中/右/默认对齐 |
| 代码与容器 | 代码语言、复制;提示、警告、折叠、高亮块和嵌套容器,内部正文直接编辑 |
| 公式 | 行内 $…$ 与块级 $$…$$;复用公共公式编辑器进行结构化输入 |
| 文本绘图 | Mermaid、PlantUML、Graphviz/DOT 共用源码工作区;基础模板、实时预览、SVG/PNG 下载 |
| 注释与术语 | 原子插入脚注引用和定义,引用/定义之间跳转;支持定义列表 |
| 分隔线、日期与表情 | --- 块、日历选择的 YYYY-MM-DD 普通日期、原始 Unicode 表情字符 |
| 提及 | 联系人由宿主提供;写入可移植的 [@姓名](<地址>) 链接 |
| 文件 | Markdown、Word 共用导入预览,可替换全文或追加末尾;导出 Markdown、Word 或宿主启用的 PDF/OFD |
下划线、高亮、公式、脚注和自定义容器属于扩展语法,接收 Markdown 的其他应用也需要 相应插件。GFM 表格没有合并单元格语法;本产品不会把合并、列宽、字体大小或文字颜色 伪装成标准 Markdown。云文档、评论、投票等服务也不属于这些源码命令。
document 布局用 --md-editor-toolbar-top 避开宿主固定页头,默认 0px;
工具栏吸附在宿主自己的滚动区内时,用 --md-editor-panel-top 单独指定右侧面板的顶部位置(默认同前者);
--md-editor-document-width 控制正文最大宽度,默认 960px。外部工具栏可设置
:toolbar="false",经 product.editor 调用公开命令;不要直接修改内容 DOM。
宿主自己的菜单可调用实例的 openFile(mode, exporter?),打开与内置“导入 / 导出”相同的窗口:
mode 为 markdownImport、wordImport、wordExport 或 formatExport(后者用 exporter 指定已安装的
导出插件,如 pdf、ofd);有其他任务打开或该项未启用时忽略。
header 插槽在正文上方、与正文同宽对齐的位置放置宿主内容,如文档标题输入框或作者信息;
footer 插槽对应地放在正文下方,如点赞或评论入口。两者都随正文一起滚动,不属于可编辑文档,也不写入 Markdown。
<MdEditor
:markdown="initialMarkdown"
:containers="{ types: ['note', 'warning', 'details', 'decision'] }"
:features="{ image: false }"
:extras="{ mermaid: false }"
:code-languages="[
{ name: 'typescript', load: () => import('@quirekit/cm-lang-javascript').then(m => m.javascript({ typescript: true })) },
]"
/>
自定义代码 UI 可通过 features.codeBlock 传入 ProseCodeBlock.extend({ addNodeView() { … } }),
保留产品的 Prose 框架和源语言命令,再替换控制组件。默认公式和文本绘图的替换应放在
extras.math / extras.mermaid / extras.textDiagram,不要在 extensions 重复安装同名功能。新的图表语言
如 ECharts 则经 extensions 加入,详见 代码块、图表 与
Markdown 插件。
高亮块
高亮块是左侧带表情图标、浅色背景的正文块,适合突出一条提醒或结论。可以在空段落输入 /高亮块
(或 /glk、/callout),也可以从工具栏“插入”或块菜单的“上方插入 / 下方插入”创建。块内是普通正文,
可以继续输入、换段、放列表或嵌套其他块。
- 点击图标打开表情面板,选中后只更换开头一行里的
emoji。 - 打开高亮块的块菜单,选择“颜色设置”:“高亮块颜色”提供浅橙、浅红、浅绿、浅蓝、浅紫、浅灰 6 种背景, “字体颜色”可选默认或同一组颜色。每次修改是一次可撤销的源码替换。
- 只读状态下图标仅展示,不能更换;实时预览下光标进入高亮块会显示完整源码。
::: highlight {emoji=📌 color=purple text=blue}
块内是普通 Markdown,可以有 **强调**、列表或多个段落。
:::
属性写在开头一行的 {} 里:emoji 缺省为 📌;color 为背景色名,缺省 orange;
text 为字体颜色名,缺省时不写。颜色只保存色名,编辑和阅读时映射到主题的语义颜色,深色主题自动适配;
未知的键或色名按缺省值显示,源码保持原样。不支持 ::: 容器的渲染器会把围栏行显示为普通文字,
正文按普通 Markdown 显示,内容不会丢失。
高亮块属于 containers 的默认名称 highlight。自定义 containers.types 时会替换整个名单,
需要高亮块就把 highlight 一起写上。MdProse 阅读视图、Word、PDF 与 OFD 导出使用同一份源码:
导出时图标作为首行、背景与字体颜色按固定的浅色近似值写入,重新导入 Word 时恢复原始源码。
日期、表情与联系人
“插入 → 日期”直接使用公共 QuireCalendar。浏览月份不会写入,选择一天或“今天”后才
插入 ISO 普通日期,不保存时区或时间戳。“插入 → 表情符号”使用公共 QuireEmojiPicker,
顶部提供常用快捷项,各分类在一个 QuireScrollArea 内连续滚动,使用组件库自定义滚动条。
搜索框和底部分类栏固定;点击分类定位对应区域,滚动同步高亮。支持中英文关键词搜索、
搜索结果去重和本次编辑器会话的最近选择。保存的是 Unicode 字符,组合表情
不会被拆开;所有这些插入都写到菜单打开时捕获的位置,可用一次撤销恢复。
提及必须由宿主提供候选联系人;独立示例中的小林、小陈、小许仅是本地示例数据。静态数组 按姓名、描述或 id 过滤;异步函数负责搜索,可以按业务权限限制候选结果:
<script setup lang="ts">
import { MdEditor } from '@quirekit/md-editor/vue'
import type { MdMention, MdMentionSource } from '@quirekit/md-editor'
const initialMarkdown = '# 项目计划\n\n'
const contacts: readonly MdMention[] = [
{ id: 'lin', label: '小林', url: '/people/lin', description: '设计' },
{ id: 'chen', label: '小陈', url: '/people/chen', description: '开发' },
]
// 可用此函数替代 contacts。接口由应用实现,返回同样的 MdMention[]。
const searchContacts: MdMentionSource = async ({ query, signal }) => {
const response = await fetch(`/api/people?q=${encodeURIComponent(query)}`, { signal })
if (!response.ok) throw new Error('联系人暂时不可用')
return await response.json() as MdMention[]
}
</script>
<template>
<MdEditor :markdown="initialMarkdown" :mentions="contacts" />
</template>
提供 mentions 后,可以选择“插入 → 提及”,也可以在正文的空白或开括号后输入 @。
候选面板内输入搜索词;方向键和 Enter 或点击选择联系人。输入 @ 触发时只将该字符替换为
链接;菜单入口替换原选区。取消保留已输入的 @,搜索草稿不写入文档。粘贴、邮箱地址、
代码、公式和链接内部不会触发提及。该能力在挂载时启用,运行中更换 provider 可更新候选来源;
从未配置状态改为启用时需重新挂载。
候选请求通过共享 SuggestionController 取消和关联;旧查询结果不能覆盖新查询,组合输入
期间不发送查询,失败有重试入口。目标被外部修改、换文档或变为只读时拒绝写入。每个联系人
的 id 必须稳定、label 非空、url 是通过安全校验的目的地。当前提及保存为普通 Markdown
链接,不维护隐藏的人员身份数据,不发送通知。通知、权限和人员详情页面由宿主负责。
通用 QuireEmojiPicker 可独立用于任何 QuireKit 界面,经 @quirekit/ui/vue 导入。
items / groups 替换目录,common 自定义常用快捷项顺序([] 隐藏),recent 由宿主
管理并单独显示。默认常用是精选快捷项,不按频次排序。select 发出包含精确 value 的条目。
它不依赖 MD Editor、不创建浮层、不自行存储使用记录。默认目录为常用精选集合,不代表
Unicode 表情全集,也不包含肤色选择器。
把正文文本显示为链接
工单号、需求号这类短标识可以显示为链接而不改动正文:@quirekit/msfe-link 的 textLinks() 按宿主给出的
规则识别可见区域中的文本,经 extensions 安装。保存的 Markdown 仍是原文,例如 CLOUD-15084。
import { textLinks } from '@quirekit/msfe-link'
const issueLinks = textLinks({
id: 'issues',
pattern: /[A-Z][A-Z0-9]+-\d+/u,
href: key => `https://issues.example.com/browse/${key}`,
// 可选:只链接真实存在的标识。同一批可见候选合并为一次调用,结果按文本缓存。
verify: async (keys, signal) => {
const response = await fetch(`/api/issues?keys=${keys.join(',')}`, { signal })
return response.ok ? await response.json() as string[] : []
},
// 可选:悬停卡片。MD Editor 用统一样式渲染,内容为纯文本。
card: async (key, signal) => {
const issue = await fetch(`/api/issues/${key}`, { signal }).then(response => response.ok ? response.json() : null)
return issue && { subtitle: `${key} · ${issue.type}`, title: issue.summary,
status: { label: issue.status, tone: 'info' }, fields: [{ label: '经办人', value: issue.assignee }] }
},
})
识别出的文本与普通链接外观一致,带 data-msfe-text-link 属性,编辑时 Cmd/Ctrl+点击、只读时单击跳转。
代码、已有链接、图片、HTML 与公式中的文本不识别,前后紧邻字母或数字的匹配也不识别;源码视图保持原样。
校验失败的候选不缓存,之后重新校验;光标仍停在末尾、尚未校验的候选等光标离开后再校验,避免逐字查询。
把同一个 options 对象传给多个编辑器即可共享校验结果。提供 card 后,悬停链接 300ms 显示卡片:
副标题、标题、最多三行说明、状态标签(tone 可选 neutral、info、success、warning、danger)、短字段和
「打开链接」入口;返回 null 不显示。再提供 fromHref(url) 把地址映射回文本,写成普通 Markdown 链接的
同一目标(如 [需求说明](https://issues.example.com/browse/CLOUD-9))也显示这张卡片。
设置 exportLinks: true 后,导出 Markdown、Word、PDF、OFD 时识别出的文本写成标准链接,其他软件中也可点击;
编辑器中的正文不变。宿主自己的导出可调用 linkifyTextLinks(editor.state) 得到同样的结果。卡片结果按文本缓存,失败的请求下次悬停重试。导出时转为真链接由宿主实现。
评论
评论由商业包 @quirekit/md-editor-comments 提供(开发与评估免费,生产使用需要授权码):把 mdComments() 传给 comments 即可打开,
并引入它的 styles.css。选中文字后用工具栏“添加评论”、浮动选区工具栏或 ⌘/Ctrl + Alt + M 留下评论,
可以回复、编辑、删除自己的消息、标记解决。选中的评论卡片上有上一条 / 下一条按钮和当前位置,工具栏“评论”菜单也能跳转或查看全部;解决一条后自动跳到下一条未解决的评论。
评论不写进 Markdown:原文保持干净,评论以标准数据交换格式由应用自己保存。
<script setup lang="ts">
import { shallowRef, watch } from 'vue'
import { MdEditor, type MdEditorInstance } from '@quirekit/md-editor/vue'
import { mdComments } from '@quirekit/md-editor-comments'
import '@quirekit/md-editor-comments/styles.css'
import { getComments } from '@quirekit/msfe-comments'
const props = defineProps<{ markdown: string; saved?: unknown }>()
const product = shallowRef<MdEditorInstance | null>(null)
const comments = mdComments({
user: { id: 'lin', name: '小林' }, // 新消息与解决的署名;null 时只读
canResolve: thread => thread.messages[0]!.author.id !== 'admin', // 可选:由应用决定谁能解决
onChange: change => saveComments(change.snapshot()), // 每次评论操作后保存
})
// 挂载后导入已保存的评论;原文改动过也会按原文引用重新定位,找不到的进入“找不到原文”分组。
watch(() => product.value?.editor, editor => { if (editor && props.saved) getComments(editor)?.importComments(props.saved) })
// 正文编辑只移动评论范围、不逐次通知;保存文档时一并导出,锚点保持最新。
function save() { return { markdown: product.value?.editor?.getMarkdown(), comments: product.value?.editor && getComments(product.value.editor)?.exportComments() } }
declare function saveComments(data: unknown): void
</script>
<template>
<MdEditor ref="product" layout="document" :markdown="markdown" :comments="comments" />
</template>
宽屏的文档布局在右侧页边显示评论,卡片对齐所评论的文字;窄屏、嵌入布局和手机通过“评论”
打开列表。提供 mentions 时,评论输入框中输入 @ 也会列出联系人,保存为与正文相同的
[@名称](<链接>),并在消息的 mentions 中列出,供应用发送通知。评论正文支持粗体、斜体、
行内代码、删除线、链接和提及,其他 Markdown 按原文显示。
canComment: false 只允许查看;canResolve 决定是否显示“解决 / 重开”,未提供时不限制;自己的消息总能删除,
canDelete 让管理员等角色也能删除别人的消息(不能编辑)。avatar 按作者返回头像地址,没有时显示姓名缩写。
这些设置只控制界面,权限必须由应用的服务端再次校验。只读文档也可以评论。评论不随 Word、PDF、
OFD 导出,导入 Word 时批注不会转成评论。交换格式、重新定位与协同计划见
@quirekit/msfe-comments 的类型说明。
除了划词评论,也可以对整篇文档发表全文评论:工具栏“评论”菜单或评论列表里的“添加全文评论”。
全文评论没有原文位置,回复、解决、@ 提及与划词评论相同,列在“全部评论”顶部的“全文评论”分组;
设置 documentComments: "end" 时,正文末尾还会显示全文评论区。含全文评论的数据以交换格式 v2 导出,
不含时仍是 v1。
需要和支持 CriticMarkup 的工具交换文件时,
设置 criticMarkup: true:“导出”中多出“导出 Markdown(含评论)”,把评论写成
{==原文==}{>>@作者: 评论<<};导入 Markdown 时识别这些标记并转成评论,正文中不保留标记。
编辑器里的原文和评论数据仍然分开,标记只出现在导出的文件里。也可以分别配置:
const comments = mdComments({
user: { id: 'lin', name: '小林' },
criticMarkup: { export: true, import: true, includeResolved: false, suggestions: 'keep' },
})
suggestions 决定 {++新增++}、{--删除--}、{~~旧~>新~~} 修订标记在导入时原样保留、全部接受
还是全部拒绝。评论落在代码里或跨行时改为写在旁边的单独批注,不会破坏原有语法。不用编辑器时,
也可以直接调用 @quirekit/msfe-comments/critic-markup 的 exportCriticMarkup 与 importCriticMarkup。
AI 助手
@quirekit/md-editor-ai 的 createMdEditorAi() 返回 panel、extensions 与 destroy():
将前两项交给 MdEditor,在宿主页卸载时调用 destroy()。助手使用内置模型设置、文档工具与改动审批;
ownerDocument 提供页面文档,storage 提供浏览器存储,images 可复用宿主图床。
团队统一管理模型时,传入 connection: () => Promise<QuireAiModelConnection>,首次打开面板才加载
授权模型目录。此时隐藏个人连接设置,也不会读取本地保存的 provider 配置;模型选择和审批偏好仍可保存。
管理员页面可复用 createQuireAiProviderSettings({ persistence }) 的表单,由 initialDraft、
异步 save(draft)、clear() 接入宿主服务端。保存失败保留草稿,不会写入浏览器凭据。
服务端使用 @quirekit/ai-assistant/settings 验证配置;模型密钥、成员权限和网关鉴权由宿主负责。
协作记录
协作记录回答“谁、何时、做了什么”。记录写在文档之外,格式遵循公共协议 @quirekit/edit-history,
存储由宿主实现 ActivityStore;编辑器只负责采集和展示。安装两部分并传入同一个存储与文档标识:
import { MdActivity } from '@quirekit/md-editor'
import { mdActivityPanel } from '@quirekit/md-editor/vue'
const activity = MdActivity.configure({
store, documentId: 'doc-42', epoch: '1',
actor: { id: user.id, name: user.name, trust: 'local' },
})
const panel = mdActivityPanel({ store, documentId: 'doc-42', local: true })
<MdEditor :markdown="markdown" :extensions="[activity]" :panels="[panel]" />
- 同一块里的连续输入在停顿约 3 秒、换块或失焦时合并为一条;粘贴、剪切、撤销、插入块、移动 / 删除块、 转换格式、修改高亮块颜色与图标各记一条。远端和宿主写入的变化不由本端记录。
- 面板按日期与相近时间分组,可展开明细、查看改动前后的 Markdown 片段、按成员或时间筛选、隐藏系统通知。 点击条目定位到当前原文:位置变了会定位到相同内容并标明“原位置已变化”,原内容已删除或无法确定 (例如同一段文字出现多处)时只提示,不会跳到别处;评论记录定位到评论当前标注的文字。
- 单人使用时
trust为local,local: true让面板标明“仅保存在本机”。多人可信记录需要服务端确认后写入, 通用协同采集适配器尚未提供。宿主也可在服务端确认正文更新后写入公共协议记录,前端只安装mdActivityPanel读取,避免与本地采集重复。@quirekit/edit-history/memory的内存实现只用于示例和测试,刷新即丢失;自建存储可用@quirekit/edit-history/conformance的规则逐条验证。
多人协同时
协同时由服务端确认后写入,客户端不再写存储。服务端安装 Hocuspocus 扩展,作者取自鉴权结果:
import { createMsfeActivityExtension } from '@quirekit/msfe-collaboration-hocuspocus/server'
const activity = createMsfeActivityExtension({
resolveActor: context => ({ id: context.user.id, name: context.user.name, trust: 'verified' }),
resolveDocument: room => ({ documentId: room, epoch: '1' }),
})
// 在自己的存档事务里写入:activity.takeActivity(room);失败时 activity.restoreActivity(room, events)
客户端只为插入块、粘贴、撤销等带标签的操作发送提示,连续输入由服务端从收到的改动中合并:
import { encodeActivityHint } from '@quirekit/edit-history/writer'
import { relativeActivityResolver } from '@quirekit/msfe-collaboration'
MdActivity.configure({ documentId, epoch, actor: null, store: null,
hints: hint => session.sendStateless(encodeActivityHint(hint)) })
mdActivityPanel({ store, documentId, resolveTarget: relativeActivityResolver(session.document) })
提示与实际改动对不上时,服务端把这次改动记为“编辑了正文”。断线后很快重连仍算同一次协作,不重复记“加入协作”。
评论房间传入 commentsRoom: room => room.endsWith(':comments') 后,添加、回复、解决、重新打开与删除评论也会记录,
作者同样取自连接身份;评论房间的记录在保存该房间时用 takeActivity(评论房间名) 取出。
服务端记录要有上限,否则会一直增长。协议的保留策略可以同时限制条数与时间:maxEvents 只保留每篇文档最近的若干条,
fullDays 之后删除改动片段只留摘要,summaryDays 之后整条删除。参考内存实现
createMemoryActivityStore({ retention }) 在每次写入后执行;数据库存储可在写入事务后或定时任务里执行同样的清理,
例如按序号删除超出条数的旧记录。历史版本另外按 versionThinning 稀疏化,命名版本不受影响。
历史版本
版本是整篇 Markdown 的快照,存储由宿主实现 VersionStore。把同一个版本存储同时交给 MdActivity 和面板,
面板会多出“版本”页:
const activity = MdActivity.configure({ store, versions, documentId: 'doc-42', epoch: '1', actor })
const panel = mdActivityPanel({ store, versions, documentId: 'doc-42', local: true })
- 可以输入名称保存命名版本,命名版本永久保留;宿主在自己的存档时机调用
getMdVersions(editor).save()生成自动版本,内容与上一个版本相同时复用它,不会重复存储。 - 点击版本打开只读预览,可切换到“与当前对比”查看逐行差异,也可以复制全文后手动粘回需要的部分。
- “恢复此版本”先把当前内容存为一个版本,再只改写不同的行,作为一次可撤销的编辑并记为“恢复了版本”; 没改动的行上的评论和协同锚点不受影响。只读时不能恢复。
- 协同时,服务端在存档时生成自动版本,命名版本由宿主的版本接口在服务端写入“保存了版本”记录, 作者取自鉴权身份;恢复的记录照常由提示配对确认,客户端不直接写记录。暂不提供撤回某一次编辑。
使用共享公式编辑器
从“插入”选择行内公式或块级公式;双击已有块级公式(或选中后点操作栏“编辑”)、点击行内公式都会打开同一个面板。
面板直接使用 @quirekit/math-ui 的 MathAuthoringPanel,沿用 @quirekit/math 的
公式文档、模板、结构化输入与可选 LaTeX 输入;产品不实现第二套公式 UI。
显示公式的 KaTeX 资源与编辑面板按需加载。
公式草稿独立于正文。取消不会写入;确认只替换该公式的 LaTeX 内容,保留美元围栏和
外围引用/列表前缀,作为一次撤销操作。行内公式要求单行且不含外层 $;多行内容使用
块级公式。原位置在编辑期间被改写、文档被替换或切为只读时,提交被拒绝并保留草稿。
在使用 UnoCSS 的工作区宿主中,除产品和 UI 源码外,也将公共 math-ui 源码纳入扫描。
它使用既有公共组件类名。使用预编译样式的宿主应确保这些公共组件样式已经包含。
需要自建公式宿主时,使用 MSFE 的 Math.configure({ edit }),再将它交给
extras.math。回调给出 editor、range 和 kind;返回 true 表示已接管编辑。
不要在异步面板中长期保存裸 range:先 captureAnchor(range),确认时取得
anchor.target() 并执行 editor.run(replaceMdPreview(latex), target),结束后释放锚点。
这也适用于 Mermaid.configure({ edit })。完整组件生命周期见 呈现 API。
图表、链接与图片的修改
“插入 → 文本绘图”打开 Classic、Block、MSFE 共用的源码工作区,支持 Mermaid、PlantUML、Graphviz/DOT。语言切换保留各自草稿,模板须显式应用;预览成功后可保存或下载 SVG/PNG,失败时保留草稿供修改,取消不改正文。标准 Markdown 围栏不保存独立图题,因此该宿主的工作区不显示标题输入。
保存生成普通的 mermaid、plantuml 或 dot 围栏,也能重开 puml / graphviz 别名。编辑保留原围栏风格及外围块前缀,必要时增长分隔符防止源码关闭外层围栏;切换语言才更新语言名。extras.mermaid: false 关闭 Mermaid;extras.textDiagram: false 同时关闭 PlantUML/DOT。未安装的语言保留为普通代码。引擎本地运行,外部 include、可选 PlantUML 图库与 D2 未启用,详见文本绘图接入。
把光标放在链接中再点工具栏“链接”可编辑该链接。点击图片会整体选中并浮出操作栏,可编辑、预览、复制、剪切或删除;双击图片直接预览。 若未改变显示文字,链接内部的粗体等原始写法会保留。修改引用式链接的单个使用位置 会将该位置改为行内链接,共享引用定义和其他使用位置不变。危险协议被拒绝。
图片地址保存在 Markdown;私有附件、上传接口或对象 URL 的获取应由宿主提供。
可以用 Image.configure({ resolve }) 保留图片来源合同,再覆盖 addNodeView 接入
自己的公共图片组件。解析器返回资源的释放仍由 MSFE 节点生命周期负责,详见
图片与资源生命周期。
提供 images(MdImageStorage)后,宿主的存储负责新图片,正文只写返回的地址:
const images: MdImageStorage = {
upload: async (file, { signal, source, name }) => (await uploadToHost(file, { signal, name })).url,
// 可选:导出 Word / PDF / OFD 时把地址取回为 PNG/JPEG data URI。
resolve: async (url, signal) => await fetchAsDataUrl(url, signal),
}
- 图片对话框出现「上传本地图片」,上传后填入地址与替代文字,仍由用户确认插入。
- 粘贴截图或拖入图片文件时直接上传,完成后插入到粘贴或落下的位置;上传期间的编辑不影响落点。
剪贴板同时带文字(如复制网页)时走普通粘贴。上传失败不写入任何内容,失败提示由宿主在
upload中给出。 - 流程图、思维导图、白板保存时,预览图以
source: 'diagram'上传,嵌入块只写地址(preview.url); 上传失败时预览图仍内联保存,不影响这次编辑。导出 Word / PDF / OFD 时经resolve取回预览图。 docx.storeImage/docx.resolveImage未设置时,Word 导入与导出使用同一个存储。- 只读编辑器不上传;未提供
images时保持原有行为(只能填写地址,图表预览图内联为 base64)。
调用产品源码命令
工具栏也是公开命令的消费者。需要自定义入口时,使用同一个编辑实例与事务:
import {
editMdDestination, insertMdFootnote, replaceMdPreview,
toggleMdInlineCode, toggleMdList, insertMdDate, insertMdMention, insertMdText,
} from '@quirekit/md-editor'
editor.run(toggleMdList('ordered')) // 转换当前段落/选区
editor.run(toggleMdInlineCode())
editor.run(insertMdDate('2026-10-16'))
editor.run(insertMdText('🎯'))
editor.run(insertMdMention({ id: 'lin', label: '小林', url: '/people/lin' }))
editor.run(insertMdFootnote('补充说明')) // 引用与定义在同一事务中
editor.run(editMdDestination(false, { url: '/docs' })) // false 为链接,true 为图片
editor.commands.insertTableRow('before')
editor.commands.insertTableColumn('after')
editor.commands.setTableColumnAlignment('center')
editor.commands.deleteTableRow()
replaceMdPreview(body, language?) 要求目标是已识别的公式或文本绘图节点;可选语言用于切换现有绘图围栏的语法,它不负责创建新块。
表格命令要求光标或选区属于同一个表格,列对齐只修改分隔行中对应的一个字段,保留
其他单元格原文。检查 result.ok;只读、过期目标、不适用的结构都会拒绝修改。
不要直接调用命令规划器后写 DOM,也不要绕过 editor.run() 的目标、权限、历史检查。
外部弹层应捕获目标并按生命周期释放,示例与 API 见 命令与事务。
导入与导出
工具栏的上下双箭头图标打开 导入 / 导出 菜单,悬停可查看名称。
菜单按方向分组:导入 Markdown、Word,导出 Markdown、Word。
宿主通过 exporters 安装的格式(如 PDF、OFD)各增加一项导出;未安装的格式不显示。
各导入、导出项使用带 MD、W、PDF、OFD 标记的文件类型图标,禁用项的图标同步弱化。
“导入 Markdown”接受文本或最大 2 MB 的本地 .md/.markdown/.txt 文件。文件通过
公共 FileUpload 选择、校验与移除,先读入草稿,去除 UTF-8 BOM、统一 CRLF/CR 为 LF。
草稿使用公共 CodeBlock 预览并复制,也可点击“编辑内容”修改或粘贴 Markdown。
点击“替换全文”使用草稿替换当前文档内容;点击“追加到末尾”保留原文并将草稿追加在末尾,
不依赖当前选区。两种操作均可一次撤销;窗口打开期间原文被修改、文档被替换或变为只读时,
保留草稿并禁止写回。若业务需要打开另一份文档并重置身份与历史,应由宿主处理保存后调用
replaceDocument()。
“导出 Markdown”读取当前权威原文,不从 Prose DOM 或 JSON 反向生成内容。保存到后端 仍属于宿主职责;在只读状态下也可导出。
Word 导入与导出
导入 / 导出 菜单中的 Word 操作由宿主安装的转换器提供。转换器 mdDocx() 位于商业包
@quirekit/md-editor-export,基础编辑器只定义 MdDocxConverter 合同;未安装时 Word 导入、导出项隐藏:
import { mdDocx } from '@quirekit/md-editor-export'
const docx = { converter: mdDocx() }
// <MdEditor :docx="docx" />
转换运行时仅在用户操作后加载。
导入接受最大 20 MB 的 .docx 文件,先转换为 Markdown 草稿,通过 CodeBlock 预览并显示报告。
它与 Markdown 导入共用“替换全文”“追加到末尾”两个按钮,均可一次撤销。
取消、转换失败、导入期间原文变更或文档变为只读时不会写回。
导出捕获打开窗口时的源码快照,转换完成后查看报告、下载 Word;只读状态仍可导出。
首版支持正文、1–6 级标题、粗体/斜体/删除线/行内代码、链接、代码块语言、基础嵌套列表、 带边框和表头底纹的简单表格、原生脚注、公式和 PNG/JPEG 图片。代码块保留语言和换行,并用底纹、边框内距增加留白。 任务状态变为可见勾选字符;默认容器和 Mermaid 使用下面的节点转换扩展。导入时复杂表格、 字体和版式会降级,批注、页眉页脚等省略并报告;导出可通过模板配置新的页眉页脚。 Word 格式和原始 Markdown 写法不保证无损。 可识别的修订删除文字被排除,插入文字保留;这不等同于完整的 Word“接受全部修订”。
行内和块级公式复用 @quirekit/math-omml,导出为可编辑的 Word 原生 OMML。重新导入时
只接受通过严格结构核对的 LaTeX;不支持的源公式保留源码,无法反推的 Word 公式保留可读数学文字,
均提供诊断。复杂公式属性、公式外围 Markdown 格式和脚注中的公式不保证保真。
脚注引用和正文写入真正的 Word 脚注,重新导入恢复为 Markdown 引用和定义,保留基础段落、 粗体、斜体等文字格式。重复引用同一定义时,导出为独立 Word 脚注并报告;未引用定义保留 为正文注释。注释内的链接保留文字和 URL,图片保留替代文字,复杂块保留源码并报告。 导入 Word 尾注会转为 Markdown 脚注并报告位置差异。普通脚注标签会规范化,不保证原标签拼写。
转换也可以独立使用 @quirekit/markdown-docx,无需挂载编辑器:
import { exportMarkdownDocx, importDocxMarkdown } from '@quirekit/markdown-docx'
const exported = await exportMarkdownDocx('# 文档\n\n**正文**')
// exported.data 是 Uint8Array;diagnostics 列出近似和丢弃。
const imported = await importDocxMarkdown(exported.data)
console.log(imported.markdown, imported.diagnostics)
markdownToLitAst() 与 litAstToMarkdown() 暴露同一中间转换阶段,方便宿主复用。
前者的 authoredParts 承载样式及文档设置;自行编译时必须随 ast 一起传入
createDocxPackagePlan(ast, { authoredParts }),确保样式与往返元数据采用同一份结果。
lossPolicy: 'strict' 会在发现损失时抛出带 diagnostics 的 MarkdownDocxLossError;
默认 best-effort 返回内容和报告。该适配包属于 QuireKit 商业组件,MSFE 的现有许可不变。
默认不请求外部图片:导出直接支持 PNG/JPEG data URI,其它来源需要显式
resolveImage(source): Promise<string | null> 返回这两种格式的 data URI。
默认模板使用 A4 页面和四边 1 英寸页边距;图片保持原始比例、只缩小不放大,按正文、列表
或嵌套单元格的实际可用范围限制尺寸。标题默认 1.1 倍行距、段后 4–6 磅,正文 1.15 倍行距、
段后 6 磅,列表项段后 2 磅;自定义转换已提供的间距或样式引用优先。
相邻表格和带框容器之间补充 8 磅的块间分隔,与已有段距共同决定可见留白;
嵌套容器内的同级块遵循相同规则,重新导入时不会因此增加空白内容。
这些外观现在可以通过导出模板配置;省略模板时保留上述默认值。
导入默认保留 data URI;可通过
storeImage({ dataUrl, alt }): Promise<string | null> 保存图片并返回持久 URL。
保存失败保留内嵌数据并报告,临时 blob: 地址不会进入结果。将这些选项与转换器一起传给 MdEditor
的 docx 属性,或传给独立转换函数。
在编辑器之外转换(例如宿主把 Word 文件导入为新文档)时,调用
mdDocx().importDocx(data, { policy, features, signal }),它使用与编辑器相同的默认转换(流程图、思维导图、
白板、容器与代码绘图),导入导出才能往返一致。宿主自定义节点转换通过 mdDocx({ extensions }) 安装。
Word 原生图表在 Markdown 中没有对应语法,导入时按图表缓存数据渲染为静态 PNG(随后同样经
storeImage 保存),每张图表报告一条 chart-rasterized;无法读取的图表族(散点、组合图、新式图表等)
替换为 [替代文字] 占位并报告 chart-omitted,不会让整个文件导入失败。宿主可通过
mdDocx({ renderChart }) 改用自己的渲染器(签名为 (chart) => Promise<string | null>),builtins: false 时不渲染图表。
PDF 与 OFD 导出
PDF 与 OFD 由可选商业包 @quirekit/md-editor-export 以导出插件的形式提供,基础编辑器不依赖它:
import { mdOfdExport, mdPdfExport } from '@quirekit/md-editor-export'
const exporters = [mdPdfExport(), mdOfdExport()]
// <MdEditor :exporters="exporters" />
每个插件在“导出”菜单中增加一项。导出时捕获当前源码与所选模板,生成后显示页数和转换报告,再由用户 下载;只读文档也可导出。导出窗口中的“更换”使用同一份源码重新生成,关闭或切换文档会废弃过期结果。 转换器与字体在第一次导出时才加载。
两种格式都通过临时 Classic 文档完成真正分页,再分别编码原生 PDF 与原生 OFD(不经 PDF 中转)。 正文是可选择的文字;表格、提示块、脚注、页眉页脚和动态页码使用现有排版能力,图表为图片。 公式当前使用默认数学字体输出高清图形并报告这一降级,其文字不能单独选择。自定义节点复用 已有转换器,不需要为每种格式再维护一套节点转换。
插件默认使用 @quirekit/font-pack 的便携字体:同一套字节先安装为浏览器字体用于度量,再嵌入文件。
OFD 没有标准 Courier,插件为常见代码字体嵌入 DejaVu Sans Mono 并报告替代,许可原文随 font-pack 发布。
PDF 中代码字体没有对应资源时,先解析为等宽后备字体再排版并报告。宿主可通过 fonts 选项替换整套字体,
通过 metadata 设置标题、作者等文档信息。缺字或资源失败均有诊断;lossPolicy: 'strict' 拒绝有损输出。
不需要编辑器界面时,可直接调用 @quirekit/md-editor-export/pdf 的 exportMarkdownPdf(markdown, options)
或 /ofd 的 exportMarkdownOfd,返回 data、pageCount 和 diagnostics。这时需显式提供可嵌入字体;
无浏览器环境必须提供 textMeasurer,包含公式时还需 rasterizeFormula。OFD 的 fontEmbedding
默认 subset,可设为 full。
两种格式都不承诺与 Word 在不同字体环境下逐像素一致,也不保留可往返编辑的 Markdown 元数据,不提供 Markdown 导入。PDF/A、Tagged PDF 与大文档后台线程属于后续能力。
导出模板
@quirekit/export-template 提供格式中立的配置、默认模板与严格校验,使用 MIT 许可。
模板只用于导出,不更改 Markdown 内容、选区或撤销历史,也不影响 Word 导入。
页面使用 mm;字号、段距、边框和内距使用 pt;行距明确区分倍数与固定值。下面是公开的合成配置示例:
import { resolveExportTemplate } from '@quirekit/export-template'
import { exportMarkdownDocx } from '@quirekit/markdown-docx'
const template = resolveExportTemplate({
fonts: { body: { latin: 'Arial', eastAsia: '微软雅黑' } },
body: { after: 5 },
headings: { h1: { border: { color: '287B69', width: 0.75 }, borderSpace: 4 } },
footer: { enabled: true, center: '{page} / {pages}' },
})
const file = await exportMarkdownDocx(markdown, { template, documentTitle: '项目记录' })
可以设置正文、H1–H6、列表、引用、代码、表格、容器、脚注、公式及图片的外观。
角色字体提供西文、东亚、复杂文字槽位;留空为主题字体。fonts.math.latin 对应 Word 的
默认数学字体,原生公式仍可编辑。模板不嵌入字体,不保证所有设备分页一致。
单节默认页眉页脚支持左中右内容及 {title}、{page}、{pages};后两者为 Word 原生动态域,
需阅读器更新后显示实际页码,过长单行文字会缩略并报告。快速样式示意不是 Word 分页预览。
MdEditor 可以直接接收 :docx="{ converter, template }",也可以由宿主接入模板库:
templates:实现ExportTemplateProvider的目录、精确版本读取与可选保存/删除服务。v-model:exportStyle:当前文档的{ id, revision },由宿主与文档设置一起持久化。#export-templates="{ provider, selected, choose, close }":安装宿主选择器;确认时调用choose,取消调用close。
同时提供 provider 与 slot 后,图标菜单显示“导出样式”;Word 和已安装的 PDF/OFD 导出自动沿用选择。
导出窗口中的“更换”保持本次源码快照并重新生成文件,关闭或切换文档废弃过期结果。
无持久化宿主时只记住当前实例;已有版本缺失或无权限会阻止导出,要求重新选择,不静默回退。
只读文档仍可选择样式和导出。扩展通过 markdownExportTemplateService 读取同一解析配置,
自定义转换明确提供的直接格式和样式引用仍然优先。
现有 MD Editor 示例 已接入模板库;中英文示例分别保存导出样式。文档站宿主 采用私有商业授权,基础编辑器和导出协议的授权保持不变。
第一方 @quirekit/export-template-library 组件和官方设计包独立采用商业授权,支持浏览、
新建、复制编辑、保存版本与显式本地存储,由商业宿主按上述接缝装配。组件授权与内容包授权分别解析,
支付、账号和生产授权校验由宿主提供;基础 Markdown/Word 导出不依赖商业包。上传 DOCX/DOTX
作为模板仍属于后续能力。
“模板管理”中,“新增模板”从默认配置开始;“基于当前模板新建”复制当前浏览的模板样式。 卡片通过主色边界、轻底色和勾选标记显示选择,点击右上角编辑按钮可修改该模板。 内置模板只读,编辑入口会创建副本并保留来源;个人模板编辑后保存为同一模板的新版本。 “当前使用”标记对应文档已经采用的版本;浏览、编辑和单独保存不会应用,点击“使用此模板”或“保存并使用”才更新文档的导出设置。
复制或编辑模板时,窗口尺寸保持稳定,切换分类后仅更新可滚动的字段区域;模板名称、 分类栏和底部保存按钮始终可见。窄屏使用紧凑预览,空间很低时优先显示编辑字段。 字段按外观、文字、段落等用途分组,数值旁直接显示单位。点击颜色块可选择预设色或打开 “更多颜色”精确调整;文字颜色可恢复“自动”,底色可设为“无填充”。加粗、斜体和对齐使用格式按钮。
自定义节点转换与往返
MD Editor 默认注册容器与三种文本绘图转换,开关跟随 containers / extras.mermaid / extras.textDiagram:
| 节点 | Word 中的内容 | 再导入 |
|---|---|---|
| 单段容器 | 段落底纹、四边框与边框内距 | 校验通过时恢复容器源码 |
| 含标题、列表或嵌套块的容器 | 单格表格底纹、边框和单元格内边距,正文仍可编辑 | 校验通过时恢复完整容器 |
| 高亮块 | 表情作为首行,无边框底纹,可选字体颜色 | 校验通过时恢复高亮块源码 |
| Mermaid、PlantUML、Graphviz/DOT | 从源码离屏渲染的 PNG 图片 | 校验通过时恢复原围栏与源码 |
圆角和折叠交互会降级并报告。默认容器解析支持根级及容器正文中的已关闭命名围栏; 列表、引用内部的容器需要宿主扩展解析。图形渲染失败保留代码,不依赖当前视口中是否挂载预览。
源码元数据存入标准 Custom XML part,通过内容控件关联。可见内容、图片字节、脚注/尾注或样式/编号 发生变化后,导入保留当前 Word 内容;不会用过期源码覆盖 Word 修改。元数据丢失、标识重复、 版本不兼容或扩展未安装时也保留原生内容或图片。这里已验证 QuireKit 往返,尚未承诺 Word/WPS 等软件再次保存后必定保留元数据。
<MdEditor :docx="{ converter, preserveMetadata: false }" /> 可导出纯原生内容和图片;
builtins: false 关闭默认节点转换,但保留宿主经 mdDocx({ extensions }) 安装的转换。基础 MSFE 包没有 DOCX 依赖。
独立适配器按需注册同一套功能。图片渲染由宿主明确提供,不隐式抓取资源:
import {
createMarkdownDocxContainerExtension,
createMarkdownDocxCodeImageExtension,
exportMarkdownDocx,
} from '@quirekit/markdown-docx'
// renderDiagram 是宿主提供的异步函数,返回 PNG/JPEG data URI 或 null。
const extensions = [
createMarkdownDocxContainerExtension({ names: ['note', 'warning', 'decision'] }),
createMarkdownDocxCodeImageExtension({ languages: ['mermaid'], render: renderDiagram }),
]
const result = await exportMarkdownDocx(markdown, { extensions })
// importDocxMarkdown 使用同一 extensions;仅导入时可以省略 render。
自定义功能实现 MarkdownDocxExtension.addDocx(),返回与 Classic 相同的节点转换贡献。
Word/PDF/OFD 共用 parse / prepare / 节点 codec 与模板 service;DOCX 的 package pass 和
Custom XML 恢复只适用于 Word。完整的原生业务卡片、图片渲染、组合注册、取消与失败处理见
自定义节点导出为 Word、PDF 与 OFD。
扩展必须校验 payload 版本与字段,并保留可见回退。每条恢复元数据上限为 64 KiB,
文档总计 1 MiB / 1000 条。preserveMetadata 控制内置扩展;宿主扩展自行管理其策略。
共享 Prose 类名
编辑区在实时和只读状态使用 qk-prose qk-prose--compact,MdProse 使用同一紧凑密度;
代码块使用 qk-code-block qk-prose-source。任务框复用公共 Checkbox 与 qk-prose-task-marker
组合类,保持正文行高,并与编辑时的 [x] / [ ] 共用占位宽度。
容器使用 qk-prose-container、qk-prose-container__header、qk-prose-container__body
和语义 data-tone。适配器将 CodeMirror 块映射为原生语义元素或 data-qk-prose 角色,
直接消费公共 Prose CSS。普通 DOM 阅读与编辑不各写一套皮肤。
先通过应用的 QuireKit 主题修改字体、色彩和间距。业务需要特殊容器时,在宿主作用域
下为 .qk-prose-container[data-container="你的类型"] 提供明确的变体;不要逐行画背景
或替换 CodeMirror 管理的 DOM。需要在静态阅读中复用该类型时,保留相同的容器标识。
独立的阅读视图快照
<script setup lang="ts">
import { shallowRef } from 'vue'
import type { EditorState } from '@quirekit/cm-state'
import { MdEditor, MdProse, type MdEditorInstance } from '@quirekit/md-editor/vue'
import { QuireButton } from '@quirekit/ui/vue'
const product = shallowRef<MdEditorInstance | null>(null)
const snapshot = shallowRef<EditorState>()
</script>
<template>
<MdEditor ref="product" markdown="# 同一份文档" />
<QuireButton @click="snapshot = product?.editor?.state">生成阅读快照</QuireButton>
<MdProse v-if="snapshot" :state="snapshot" locale="zh-CN" />
</template>
MdProse 消费不可变状态并生成可丢弃的语义 DOM,不生成另一份可编辑 JSON,也不会
反向序列化 Markdown。已注册容器名称保留为 data-container,可与编辑视图共用变体。
阅读适配覆盖核心块、行内扩展、链接、图片、公式、Mermaid、PlantUML、Graphviz/DOT、定义列表、脚注和 Frontmatter。
公式与图表复用同一安全渲染器,元数据保留为源码。未注册的绘图语言仍按普通代码块显示。
第三方扩展可通过 @quirekit/md-editor/vue 的 withMdReading() 贡献阅读内容,复用原
codec 的字段校验,并由公共层处理资源取消、释放和失败回退,见自定义节点。
未知节点保留源码文本,默认 HTML 也保留为文本。components 与显式 html 策略共用
公共 Incremark reader 的合同。阅读贡献不自动提供 Word/PDF/OFD 导出能力。
直接显示文本与 AI 流式回复
无需先创建编辑器,直接把当前收到的完整原文传给 content。每次追加更新同一个字符串,
改写、清空和切换消息也使用这个属性;不要同时传 state。
<MdProse
:content="message.content"
:identity="message.id"
:status="message.receiving ? 'receiving' : 'complete'"
locale="zh-CN"
@error="reportReadingError"
/>
status 接受 receiving、complete、stopped、error,只描述传输状态。停止/失败保留
原文,后置定义仍可修正前文;没有提前冻结的“完成块”。未闭合的代码块先展示代码,闭合后
才允许 Mermaid 等预览启动。重复脚注有独立的引用锚点,重复链接定义遵守首次定义优先。
options 接收 MdEditorExtensionOptions,包括 extras、containers 和 extensions;
阅读扩展仍通过 withMdReading 注册。更换 options 对象或 identity 会释放旧会话和资源。
配置必须是无需挂载编辑器的纯配置,不支持在初始化时使用 this.editor 或接入 source provider。
错误通过 MdReadingError 上报,文本解析/配置失败的 phase 为 parse,原文作为转义文本保留。
例子每 30ms 追加 20 个 UTF-16 字符,末尾才给出链接和脚注定义。停止后可以一次性加载,
也可以重新开始。这里的可运行示例使用 MdProse;为兼容原合同,SSR 和客户端首帧
都输出转义原文,挂载后再解析。需要服务端语义
DOM 时传入预先接受的 state 快照,或使用公共阅读组件。额外解析工作
协作让出主线程,但不是硬实时预算;大文档
和密集引用仍有全局工作。稳定顶层块在语法、位置与依赖均未变时复用投影;增长中的块仍需重新投影。
无框架宿主可使用 MdProseStream,调用 update(content) 接受全文、advance(budget)
推进解析,再消费 state。返回 false 时由宿主调度下一个切片;类本身不创建定时器。
不要把 Incremark 的 AST renderer、HTML 执行或图表配置直接传入这个入口。
无框架装配
createMdEditor(options) 返回原始 MsfeEditor,生命周期、命令和保存方法不变。
createMdEditorExtensions(options) 返回产品扩展组合,可以交给已有的 MSFE 实例工厂。
Vue 的任务、图片、代码语言选择与折叠按钮由 vueMdEditorExtensions(locale, options, edit?)
装配,需要同时使用 MSFE Vue 的组件宿主。第三个参数可接管公式/图表编辑;直接使用
MdEditor 时这些步骤及公共弹层已完成。无框架工厂本身不挂载 Vue 工具栏或公式面板;
宿主应提供 extras.math / extras.mermaid / extras.textDiagram 的编辑回调,或使用 view: 'preview'
直接编辑活动节点的源码。