react-markdownでmermaidを使えるようにする

published
2025-01-25

初めに

ブログ内でmermaidを使いたい欲が自分の中で高まったので、対応しました。のメモです。

ブログでは、react-markdownのライブラリを用いて、markdownをHTMLに変換しています。

やること

react-markdownをmermaidに対応させる拡張プラグインがあればサクッと...と思っていましたが、よさげなものが見当たらなかったので、mermaidのライブラリから自作で対応します。

と言っても、mermaidのドキュメントを見る限り、行うことはシンプルで、展開するDOM要素をmermaid.runのnodesに指定すればよさそうなので、その通りやります。

インストール

まずはインストール

$ npm install mermaid

Marmaidコンポーネント

mermaidの表示を行うコンポーネントです。childrenでmermaidで表示する内容を受け取ります。
mermaid.runで指定するnodesにはuseRefで対応させます。

'use client';

import mermaid from 'mermaid';
import { memo, useEffect, useRef, type ReactNode } from 'react';

mermaid.initialize({
  startOnLoad: false,
  theme: 'dark',
});

// eslint-disable-next-line react/display-name
const Mermaid = memo(({ children }: { children: ReactNode }) => {
  const ref = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (ref.current) {
      mermaid.run({ nodes: [ref.current] });
    }
  }, []);

  return (
    <div className="mermaid" ref={ref}>
      {children}
    </div>
  );
});

export default Mermaid;

また、react-markdownのコンポーネントでは、SyntaxHighlighterの拡張プラグインの前段で先ほどのMermaidコンポーネントに渡します。

        code(props) {
          // eslint-disable-next-line
          const { children, className, node, ref, ...rest } = props;
          if (className === 'language-mermaid') {
            return <Mermaid>{children}</Mermaid>;
          }
          const match = /language-(\w+)/.exec(className || '');
          return match ? (
            <SyntaxHighlighter {...rest} PreTag="div" language={match[1]} style={coldarkDark}>
              {String(children).replace(/\n$/, '')}
            </SyntaxHighlighter>
          ) : (
            <code {...rest} className={className}>
              {children}
            </code>
          );
        },

確認

Sequence diagramsのサンプルを表示してみます。

888。新しい機能も問題なく表示されるか確認します。

ちゃんと表示されました。