UNPKG

mdx-mermaid

Version:

Display mermaid diagrams in mdx files.

95 lines (90 loc) 3.21 kB
'use strict'; var React = require('react'); var mermaid = require('mermaid'); const DEFAULT_DARK_THEME = 'dark'; const DEFAULT_LIGHT_THEME = 'default'; const DARK_THEME_KEY = 'dark'; const LIGHT_THEME_KEY = 'light'; const HTML_THEME_ATTRIBUTE = 'data-theme'; /** * Gets the theme based on config and current data-theme of the HTML. * * @param html The HTML element of the page. * @param config The configuration for this chart. */ function getTheme(html, config) { let htmlTheme = html.getAttribute(HTML_THEME_ATTRIBUTE) ?? LIGHT_THEME_KEY; if (!(htmlTheme === LIGHT_THEME_KEY || htmlTheme === DARK_THEME_KEY)) { htmlTheme = LIGHT_THEME_KEY; } const defaultTheme = htmlTheme === LIGHT_THEME_KEY ? DEFAULT_LIGHT_THEME : DEFAULT_DARK_THEME; return config?.theme?.[htmlTheme] ?? config?.mermaid?.theme ?? defaultTheme; } /** * Copyright (c) Samuel Wall. * * This source code is licensed under the MIT license found in the * license file in the root directory of this source tree. */ /** * Component to display Mermaid diagrams. * * @param param0 Diagram to display. * @param param1 Config. * @returns The component. */ const Mermaid = ({ chart, config: configSrc }) => { // Mermaid doesn't support server-side rendering /* istanbul ignore next */ if (typeof window === 'undefined') { return React.createElement("div", { className: "mermaid", "data-mermaid-src": chart }, chart); } const config = React.useMemo(() => typeof configSrc === 'string' ? JSON.parse(configSrc) : configSrc, [configSrc]); const html = document.querySelector('html'); const [rerender, setRerender] = React.useState(false); const theme = React.useMemo(() => getTheme(html, config), [config, rerender]); React.useEffect(() => { const observer = new MutationObserver((mutations) => { for (const mutation of mutations) { if (mutation.type !== 'attributes' || mutation.attributeName !== 'data-theme') { continue; } setRerender((cur) => !cur); break; } }); observer.observe(html, { attributes: true }); return () => { try { observer.disconnect(); } catch { // Do nothing } }; }, []); React.useEffect(() => { if (config) { if (config.mermaid) { mermaid.initialize({ startOnLoad: true, ...config.mermaid, theme }); } else { mermaid.initialize({ startOnLoad: true, theme }); } document.querySelectorAll('div.mermaid[data-processed="true"]').forEach((v) => { v.removeAttribute('data-processed'); v.innerHTML = v.getAttribute('data-mermaid-src'); }); mermaid.contentLoaded(); } }, [config, theme]); React.useEffect(() => { setTimeout(mermaid.contentLoaded, 0); }, [chart]); return React.createElement("div", { className: "mermaid", "data-mermaid-src": chart }, chart); }; exports.Mermaid = Mermaid;