编辑器与图表
MarkdownEditor 与交互式 Mermaid
编辑器与图表
主入口只管渲染。编辑器和交互图表各自住在独立入口里,不引入就不会进产物——这是入口隔离的实际意义。
MarkdownEditor
编辑器以 Markdown 文本为唯一真源:左边 CodeMirror,右边实时预览,工具栏插入的容器骨架保证「插进去即合法」。
"use client";
import { useState } from "react";
import { MarkdownEditor } from "@heikeson/md-engine/editor";
import "@heikeson/md-engine/styles.css";
export default function EditorPage() {
const [value, setValue] = useState("");
return (
<MarkdownEditor
value={value}
onChange={setValue}
view="split"
config={{ placeholder: "开始写作…" }}
/>
);
}编辑器是客户端组件
它依赖 CodeMirror 与 DOM,只能在客户端组件里使用。view 只决定初始视图,挂载后的切换由编辑器自己的工具栏接管。
| 属性 | 类型 | 默认值 | 说明 |
|---|
配置项
| 属性 | 类型 | 默认值 | 说明 |
|---|
uploadImage 由宿主注入,引擎不假设你的存储在哪。rendererConfig 整体透传给预览渲染器,sourcePositions 由编辑器强制开启,不用你操心。
滚动同步
旧做法是「贴到最近锚点顶部」,源码滚到两块之间时预览会跳到前一个块——通常是标题,观感很跳。现在改成区间插值:
- 只保留最内层锚点,避免父子块互相抢。
- 用
posAtCoords取精确字符位置,而不是按块取整。 - 相邻锚点之间线性插值;预览反向驱动源码时用
lineBlockAt直接设scrollTop。
Mermaid
<Mermaid> 在主入口里只渲染源码骨架,不加载 mermaid。要图表真正可缩放、可导出,在客户端组件里合并覆写表:
"use client";
import { MarkdownRenderer, mdxComponents } from "@heikeson/md-engine";
import { mermaidComponents } from "@heikeson/md-engine/mermaid";
import "@heikeson/md-engine/styles.css";
const components = { ...mdxComponents, ...mermaidComponents };
<MarkdownRenderer content={md} config={{ components }} />;键名必须大写开头
渲染层按 hast 的 tagName 查表,写成 mermaid 不会报错,只会静默停留在源码骨架。这个坑很安静,所以写在这里。
mermaid 是可选 peer,未安装时不打包、运行时降级为源码;dompurify 是直接依赖,随包安装。
图表配色
图表不读宿主的任何 CSS 变量,亮暗两套内置在 styles/mermaid.css 的组件作用域里,祖先带 .dark 就自动切换。要整体换色用 JS 配置:
import { configureChartTheme } from "@heikeson/md-engine/mermaid";
configureChartTheme({
light: { series1: "#0f766e" },
dark: { series1: "#19d3c5" },
});取色优先级是「JS 配置 → CSS 变量 → 内置」,三层都不满足才回落默认值。
导出
图表右上角能下载 SVG 与 PNG,也可以自己做按钮直接调用:
import { downloadSvg, downloadPng } from "@heikeson/md-engine/mermaid";PNG 走的是先把 SVG 转成 blob 再画到 canvas,因此外部图片必须同源,否则会被 canvas 污染而导出失败。