mermaid記法の図を描画する(続)

前回の実装では、ブログ記事を記述する mdx ファイル内に、mermaid クラスを持つ<div>要素を記述することで、mermaid 記法の記述・描画を可能としました。
ただ個人的にはあんまり mdx 内にタグを書きたくはありません。 できれば markdown の書き味のまま、mermaid 図を入れたいと感じるため、今回は markdown のコードブロックで図を書けるようにします。
mdx を html に変換するときに、独自のカスタムコンポーネントとマッピングさせることができるのでこれを使います。
mdx 内のコードブロックで mermaid が指定された場合に、上述のような<div>要素に置き換えられれば OK です。
実際に mdx で記述したコードブロック部分は html としては次のようになっています。
<figure> タグから始まり、その直下の<pre>タグで、data-language属性を持っています。
ここでは属性値がmdxとなっていますが、mermaidが入ってきた場合に変換すればよさそうです。
また、たくさんの<span>タグが連なっており、表示している文字列に装飾がされています。
mermaid指定のコードブロックとしては、すべての innerText を集めて、変換後の<div>要素内に入れてやればよさそうです。
mdx のカスタムコンポーネントを用意します
import { Child, FC, JSXNode } from "hono/jsx";
// 再帰的にchildrenを処理してテキストを抽出する関数
const extractInnerText = async (children: Child): Promise<string> => {
if (!children) {
return "";
}
if (typeof children === "string") {
return children; // テキストノードの場合、そのまま返す
}
if (children instanceof Promise) {
return await children; // テキストノードの場合、そのまま返す
}
if (Array.isArray(children)) {
// 子要素が配列の場合、それぞれを再帰的に処理
let text = "";
for (const child of children) {
text += await extractInnerText(child);
}
return text;
}
if (
typeof children === "object" &&
children.props &&
children.props.children
) {
// 子要素を持つJSX要素の場合、その子要素を再帰的に処理
return extractInnerText(children.props.children);
}
return ""; // その他の要素は無視
};
type Props = {
children: Child;
};
export const CustomCodeBlock: FC<Props> = async ({ children }) => {
// 直下のpreタグが、data-languageとしてmermaid指定されていれば要素置き換え
if (
children instanceof Object &&
"tag" in children &&
children.tag === "pre" &&
(children as JSXNode).props["data-language"] === "mermaid"
) {
// mermaidの要素として変換
const text = await extractInnerText(children);
return <div class="mermaid">{text}</div>;
} else {
// 通常のコードブロックの処理
return <figure data-rehype-pretty-code-figure>{children}</figure>;
}
};
export default CustomCodeBlock;カスタムコンポーネントとして登録
import CustomCodeBlock from "./CustomCodeBlock";
export function useMDXComponents(): MDXComponents {
return {
figure: CustomCodeBlock,
};
}上記 index.ts は vite の設定として参照します。
・・・略・・・
plugins: [
・・・略・・・
mdx({
jsxImportSource: "hono/jsx",
remarkPlugins: [remarkFrontmatter, remarkMdxFrontmatter],
/**
* カスタムmdxコンポーネントのインポート指定
* ※絶対パスとして指定が必要
**/
providerImportSource: path.resolve(__dirname, "./app/components/mdx"),
・・・略・・・
})
]
・・・略・・・本ブログ記事中で markdown の中で mermaid 記法の図を表示できるようにしました。
- カスタムコンポーネントとして、mdx のコードブロックで mermaid クラスが指定された場合に、
<div class="mermaid">・・・</div>要素に置き換えるようにしました。 - mdx から変換後の html の構成を解析し、関係ないコードブロックを変換しないようカスタムコンポーネントを実装しました。
以上です。
- コメント -
- 関連記事 -
- 記事検索 -
このサイトではcookieを利用して、サイト訪問者の識別に利用します。 cookieの利用に同意いただくことで、サイト訪問者は記事のいいね機能等をご利用いただけます。 なお、サイト運営者はアクセス統計としてcookieの情報を利用する場合があります。


