zfb
GitHub リポジトリ

検索したい単語を入力

いつでも検索バーを開ける

ディレクティブ

:::name / ::name / :name のディレクティブ構文を独自の JSX コンポーネントにマッピングして登録する。デフォルトでは何も登録されていない — 語彙はあなたが用意する。

directives 機能は、zfb.config.ts からコアの ディレクティブレジストリ に登録を行います。CommonMark Directives 構文 — コンテナ(:::name)、リーフ(::name)、テキスト(:name) — を、コンパイル済み MDX の JSX コンポーネント呼び出しにマッピングします。

デフォルトでは、ディレクティブ名は一つも登録されていません。 語彙はあなたが選び、zfb が JSX を出力します。

有効化

zfb.config.ts
import { defineConfig } from "zfb/config";

export default defineConfig({
  markdown: {
    features: {
      directives: {
        note: "Note",
        tip: "Tip",
        warning: "Warning",
      },
    },
  },
});

値は「ディレクティブ名 → コンポーネント」のマップです。各エントリは短縮形の文字列でも、完全形の DirectiveSpec オブジェクト(後述)でも構いません。

短縮形 — コンポーネント名のみ

最も単純なエントリは、ディレクティブ名をコンポーネント識別子の文字列にマッピングするものです。このディレクティブは titleFromLabel: trueコンテナ として登録され、角括弧で囲んだ [label] が、出力される JSX 要素の title="…" 属性になります。

zfb.config.ts
export default defineConfig({
  markdown: {
    features: {
      directives: {
        callout: "Callout",
      },
    },
  },
});

著者が次のように書くと:

:::callout[Heads up]

Body text.

:::

パイプラインは次を出力します:

<Callout title="Heads up">
  <p>Body text.</p>
</Callout>

完全形 — DirectiveSpec オブジェクト

完全形を使うと、ディレクティブの形状(containerleaftext)と、角括弧のラベルを title 属性にするかどうかを制御できます。

zfb.config.ts
export default defineConfig({
  markdown: {
    features: {
      directives: {
        // container (default kind), titleFromLabel on
        note: "Note",

        // leaf directive — self-closing, no body
        youtube: {
          component: "Youtube",
          kind: "leaf",
          titleFromLabel: true,
        },

        // text (inline) directive
        kbd: {
          component: "Kbd",
          kind: "text",
          titleFromLabel: false,
        },
      },
    },
  },
});

DirectiveSpec のフィールド:

フィールド必須デフォルト
componentstringYes
kind"container" | "leaf" | "text"No"container"
titleFromLabelbooleanNotrue

ディレクティブの形状

  • コンテナ:::name[label]::: は、複数段落の本文を JSX コンポーネントで包みます。コールアウト形式のブロックで最もよく使われます。

  • リーフ::name[label]{attrs} は、子要素を持たない自己終結型のコンポーネントを生成します。埋め込み(動画、コードプレイグラウンドなど)に使われます。

  • テキスト:name[label]{attrs} は、本文中に混在させるインラインコンポーネントです。

フェンスの間隔

コンテナフェンスの前後に空行を書けますが、必須ではありません。zfb は、opener、body、closer が 1 つの段落に入ったときに markdown-rs が生成する collapsed form も扱います。

:::note
Body text.
:::
:::tip
Another block.
:::

兄弟のディレクティブと、ネストしたディレクティブの両方が、名前が登録されている場合に書き換えられます。collapsed form でも、空行で区切った形でも同様です。未知のディレクティブ名は引き続き警告診断を出し、元のソーステキストを変更せずに残します。

コンテナディレクティブを別のコンテナディレクティブの中にネストする場合は、CommonMark-Directives の慣習に従い、外側のフェンスに内側より多いコロンを使います。

:::::note
Prose above.
:::tip
Inner body.
:::
:::::

フェンスを空行で区切った場合も、同じ慣習が適用されます。

:::::note

Prose above.

:::tip
Inner body.
:::

:::::

これは hardBreakscjkFriendly を有効にしている場合でも、:::include 経由で取り込んだ collapsed directive でも成り立ちます。これらのオプションはディレクティブレジストリが見る前に段落を再トークン化しますが、認識側がその形に寛容になっています(#2413)。ネストを正しく解決するのにコロン数のルールが必要な ::::: の外側フェンスも同様です。これは空行で区切った形でも成り立ちます。

ディレクティブの登録はコンポーネントを提供しない

directives はフレームワーク非依存で、JSX コンポーネントは一切同梱しません。ディレクティブを登録しても、コンパイル済み MDX に <ComponentName> を出力するようパイプラインに指示するだけです。次の作業が必要です:

  1. コンポーネント自体を自分で作成する。

  2. それをプロジェクトの MDX コンポーネントマップ に追加する。

  3. 自前の CSS でスタイリングする。

大文字小文字とそのままの出力

あなたが指定するコンポーネント識別子("Note""Kbd""Youtube")はそのまま出力されます。自動の PascalCase 化も検証も行われません。note: "Note"<Note> を出力し、note: "my-note"<my-note>(DOM 要素であり、おそらく意図したものではない)を出力します。

ディレクティブ名のキーは、ディレクティブ文法 [A-Za-z_][A-Za-z0-9_-]* に従います。このパターンに一致しないキーは、ソース中のどの :::name にも決してマッチしません。

関連項目

Revision History

作成更新