Files
llm-in-text/src/plugins/mermaidPlugin.ts
T

68 lines
2.6 KiB
TypeScript
Raw Normal View History

import { codeBlockConfig } from '@milkdown/kit/component/code-block'
import mermaid from 'mermaid'
// ── Mermaid init ────────────────────────────────────────────────────────────
let mermaidReady = false
let diagramCounter = 0
function ensureMermaid() {
if (mermaidReady) return
const dark = window.matchMedia?.('(prefers-color-scheme: dark)').matches
mermaid.initialize({
startOnLoad: false,
theme: dark ? 'dark' : 'default',
securityLevel: 'loose',
fontFamily: 'inherit',
})
mermaidReady = true
}
// ── renderPreview ───────────────────────────────────────────────────────────
// Pass this function to codeBlockConfig.renderPreview via crepe.editor.config().
// For non-mermaid languages, return null to use the default preview renderer.
export async function mermaidRenderPreview(
language: string,
content: string,
applyPreview: (value: null | string | HTMLElement) => void,
): Promise<void> {
if (language !== 'mermaid') {
applyPreview(null)
return
}
ensureMermaid()
// Show a placeholder immediately
const wrapper = document.createElement('div')
wrapper.className = 'mermaid-block'
const inner = document.createElement('div')
inner.className = 'mermaid-inner'
inner.innerHTML = '<div class="mermaid-loading">···</div>'
wrapper.appendChild(inner)
applyPreview(wrapper)
const id = `mermaid-render-${++diagramCounter}`
const code = content.trim() || 'graph TD\nA-->B'
try {
const { svg } = await mermaid.render(id, code)
inner.innerHTML = svg
applyPreview(wrapper)
} catch (err) {
const pre = document.createElement('pre')
pre.className = 'mermaid-error'
pre.textContent = `Mermaid error:\n${err instanceof Error ? err.message : String(err)}`
inner.innerHTML = ''
inner.appendChild(pre)
applyPreview(wrapper)
}
}
// ── Milkdown plugin helper ─────────────────────────────────────────────────
// Call this inside a crepe.editor.config() callback:
// ctx.update(codeBlockConfig.key, (prev) => ({ ...prev, renderPreview: mermaidRenderPreview }))
//
// Re-export the config key so callers don't need to import @milkdown/components directly.
export { codeBlockConfig }