UNPKG

@lobehub/ui

Version:

Lobe UI is an open-source UI component library for building AIGC web apps

97 lines (96 loc) 3.14 kB
"use client"; import { prepareInlineMermaidSvg } from "../Mermaid/SyntaxMermaid/prepareInlineSvg.mjs"; import { createCdnMermaidConfig, renderWithCdnMermaid } from "./useMermaidCdn.mjs"; import { useEffect, useId, useMemo, useState } from "react"; import { useThemeMode } from "antd-style"; import { THEMES, renderMermaidSVG } from "beautiful-mermaid"; //#region src/hooks/useMermaid.ts /** * beautiful-mermaid emits these as CSS custom properties on the SVG root and * derives the rest with color-mix(), so pointing them at antd's variables lets * the diagram follow the theme through CSS alone — no token subscription, and * no re-render (or re-layout) when the appearance changes. */ const LOBE_THEME_OPTIONS = { accent: "var(--ant-color-primary)", bg: "var(--ant-color-bg-container)", border: "var(--ant-color-border)", fg: "var(--ant-color-text)", line: "var(--ant-color-text-secondary)", muted: "var(--ant-color-text-description)", surface: "var(--ant-color-fill-tertiary)", transparent: true }; const isNamedTheme = (theme) => !!theme && theme !== "lobe-theme" && theme in THEMES; const createMermaidOptions = (customTheme) => isNamedTheme(customTheme) ? THEMES[customTheme] : LOBE_THEME_OPTIONS; /** * beautiful-mermaid covers six diagram types; anything else throws here and is * handed to the CDN-loaded upstream mermaid instead. */ const renderMermaid = (content, scopeId, customTheme) => { if (!content) return { svg: "" }; try { return { svg: prepareInlineMermaidSvg(renderMermaidSVG(content, createMermaidOptions(customTheme)), scopeId) }; } catch { return { error: "unsupported", svg: "" }; } }; const useCdnMermaidFallback = (content, { enabled, theme: customTheme }) => { const { isDarkMode } = useThemeMode(); const reactId = useId(); const [result, setResult] = useState({ svg: "" }); useEffect(() => { if (!enabled || !content) { setResult({ svg: "" }); return; } let active = true; setResult({ loading: true, svg: "" }); const config = createCdnMermaidConfig(isDarkMode, isNamedTheme(customTheme) ? customTheme : void 0); renderWithCdnMermaid(content, `mermaid-cdn-${reactId.replaceAll(":", "")}`, config).then((svg) => { if (!active) return; setResult(svg ? { svg } : { error: "Failed to render diagram", svg: "" }); }).catch(() => { if (active) setResult({ error: "Failed to render diagram", svg: "" }); }); return () => { active = false; }; }, [ enabled, content, isDarkMode, customTheme, reactId ]); return result; }; const useMermaid = (content, { theme: customTheme } = {}) => { const reactId = useId(); const scopeId = useMemo(() => `mermaid-${reactId.replaceAll(":", "")}`, [reactId]); const primary = useMemo(() => renderMermaid(content, scopeId, customTheme), [ content, scopeId, customTheme ]); const fallback = useCdnMermaidFallback(content, { enabled: Boolean(primary.error), theme: customTheme }); return primary.error ? fallback : primary; }; //#endregion export { createMermaidOptions, renderMermaid, useCdnMermaidFallback, useMermaid }; //# sourceMappingURL=useMermaid.mjs.map