mcpField
X
x-card

x-card

github.com/ant-designデザイン・UI4.8k68 回インストール2 日前に更新
リポジトリ

x-card について

x-cardは、`@ant-design/x-card`の利用方法を扱うスキルです。構造化コマンドからAIエージェント向けのインタラクティブなUIを描画するReactレンダラーについて、コンポーネント設定、データバインディング、アクション、ストリーミングを説明し、v0.9を推奨しつつv0.8にも対応します。

主な機能

  1. 01ReactでのA2UIコマンド描画
  2. 02コンポーネントカタログの管理
  3. 03JSON Pointerによるデータバインディング
  4. 04ユーザー操作の処理
  5. 05ストリーミング更新の段階的描画
  6. 06A2UI v0.8とv0.9への対応

活用シーン

  1. 01エージェント主導のフォームUI構築
  2. 02エージェント応答のインタラクティブ表示
  3. 03カードUIの段階的なストリーミング表示
  4. 04A2UIコマンドのv0.8からの移行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/ant-design/x --skill x-card

インストール後、Claude Code で/x-cardを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

reference/
ACTIONS.md
API.md
CATALOG.md
COMMANDS.md
DATA_BINDING.md
INTRODUCTION.md
USAGE.md

詳細

🎯 スキルの位置づけ

このスキルでは @ant-design/x-card を扱います — A2UI プロトコルの React 実装です。エージェントが構造化された JSON コマンドストリームを通じて、リッチでインタラクティブな UI を動的にレンダリングできます。

対象となる内容は次のとおりです。

  • XCard.Box と XCard.Card コンポーネントの使用方法
  • A2UI v0.9 のコマンドタイプ:createSurface、updateComponents、updateDataModel、deleteSurface
  • カスタムコンポーネントの登録とカタログ管理
  • JSON Pointer パス(RFC 6901)によるデータバインディング
  • アクション処理 — ユーザーイベントをエージェントに送信
  • ストリーミングによる段階的なレンダリングパターン
  • v0.8 と v0.9 のプロトコルの違い

対象範囲:推奨プロトコルは v0.9 です。v0.8 は後方互換性のためにのみサポートされています。新しい開発ではすべて v0.9 を使用してください。

目次

📦 パッケージの概要

パッケージ役割
@ant-design/x-cardA2UI プロトコル用の React レンダラー — XCard.Box、XCard.Card、カタログ API
@ant-design/xチャット UI コンポーネント(Bubble、Sender など)— ここでは扱いません
@ant-design/x-sdkデータプロバイダー、ストリーミング — ここでは扱いません
npm install @ant-design/x-card

エクスポート:

import {
  XCard,
  registerCatalog,
  loadCatalog,
  validateComponent,
  clearCatalogCache,
} from '@ant-design/x-card';
import type {
  XAgentCommand_v0_9,
  XAgentCommand_v0_8,
  ActionPayload,
  Catalog,
  CatalogComponent,
} from '@ant-design/x-card';

// Subcomponents
XCard.Box; // Container: receives commands, owns catalog maps
XCard.Card; // Renderer: renders a single surface by id

🗂️ コンポーネントのアーキテクチャ

XCard.Box
├── owns: catalogMap, surfaceCatalogMap
├── dispatches: commands → all XCard.Card children
├── aggregates: onAction events from all Cards
└── XCard.Card (id="surface-a")
│   ├── owns: component tree, data model, commandVersion
│   └── resolves: data bindings, triggers actions
└── XCard.Card (id="surface-b")
    └── ...

XCard.Box の Props

interface BoxProps {
  commands?: (XAgentCommand_v0_9 | XAgentCommand_v0_8)[];
  /** Component names must start with an uppercase letter (React component convention) */
  components?: Record<string, React.ComponentType<any>>;
  onAction?: (payload: ActionPayload) => void;
  children?: React.ReactNode; // Should contain XCard.Card elements
}

XCard.Card の Props

interface CardProps {
  id: string; // surfaceId to render
}

ActionPayload

interface ActionPayload {
  name: string; // from action.event.name
  surfaceId: string; // which surface triggered it
  /**
   * Context passed by component, with path references automatically resolved.
   *
   * For action.event.context fields using { path: "xxx" } format:
   * - X-Card automatically resolves them to { value: "actual_value" }
   * - Other properties (like label) are preserved
   *
   * Example input config:
   *   { username: { path: "/form/username", label: "用户名" } }
   *
   * Example resolved context:
   *   { username: { value: "张三", label: "用户名" } }
   */
  context: Record<string, any>;
}

🚀 クイックスタートの選択ガイド

次のことを行うには…まず読むもの
XCard.Box と XCard.Card をセットアップするUSAGE.md → 基本セットアップ
エージェントからカードにコマンドを送信するCOMMANDS.md
カスタムコンポーネントカタログを登録するCATALOG.md → ローカルカタログ
コンポーネントの Props をライブデータにバインドするDATA_BINDING.md
ユーザー操作やフォーム送信を処理するACTIONS.md
ストリーミングによる段階的な UI を構築するUSAGE.md → ストリーミング
v0.8 から v0.9 に移行するCOMMANDS.md → v0.8 と v0.9 の違い
すべての Props の型を確認するAPI.md

🛠 推奨ワークフロー

  1. カタログを定義する — ローカルカタログを登録するか、A2UI Basic Catalog URL を使用します。
  2. カスタムコンポーネントを登録する — XCard.Box の components prop 経由で渡します。
  3. React ツリーを作成する — サーフェスを XCard.Box でラップし、サーフェスごとに XCard.Card を追加します。
  4. コマンドを渡す — XAgentCommand_v0_9[] を commands prop に渡します(通常はストリーミング中のエージェント応答から渡します)。
  5. アクションを処理する — onAction で ActionPayload を受け取り、応答に応じてコマンドを更新します。

最小限の動作例

import React, { useState } from 'react';
import { XCard, registerCatalog } from '@ant-design/x-card';
import type { XAgentCommand_v0_9, ActionPayload, Catalog } from '@ant-design/x-card';

// 1. Define and register local catalog
const myCatalog: Catalog = {
  catalogId: 'local://my_catalog.json',
  components: {
    Text: {
      type: 'object',
      properties: { text: { type: 'string' }, variant: { type: 'string' } },
      required: ['text'],
    },
    Button: {
      type: 'object',
      properties: { text: { type: 'string' }, action: {} },
      required: ['text'],
    },
  },
};
registerCatalog(myCatalog);

// 2. Custom component implementations
const Text: React.FC<{ text: string; variant?: string }> = ({ text, variant }) => (
  <p className={`text-${variant ?? 'body'}`}>{text}</p>
);

const Button: React.FC<{ text: string; onAction?: (ctx: any) => void; action?: any }> = ({
  text,
  onAction,
  action,
}) => <button onClick={() => onAction?.(action?.event?.context ?? {})}>{text}</button>;

// 3. Build commands (from agent stream)
const commands: XAgentCommand_v0_9[] = [
  {
    version: 'v0.9',
    createSurface: {
      surfaceId: 'welcome',
      catalogId: 'local://my_catalog.json',
    },
  },
  {
    version: 'v0.9',
    updateComponents: {
      surfaceId: 'welcome',
      components: [
        { id: 'root', component: 'Column', children: ['title', 'btn'] },
        { id: 'title', component: 'Text', text: { path: '/user/name' }, variant: 'h1' },
        {
          id: 'btn',
          component: 'Button',
          text: 'Start',
          action: { event: { name: 'start', context: {} } },
        },
      ],
    },
  },
  {
    version: 'v0.9',
    updateDataModel: {
      surfaceId: 'welcome',
      path: '/user/name',
      value: 'Alice',
    },
  },
];

// 4. Render
export default function App() {
  const [cmdQueue, setCmdQueue] = useState<XAgentCommand_v0_9[]>(commands);

  const handleAction = (payload: ActionPayload) => {
    console.log('Action:', payload.name, payload.context);
    // Append new commands based on agent response
    setCmdQueue((prev) => [...prev /* new commands */]);
  };

  return (
    <XCard.Box commands={cmdQueue} components={{ Text, Button }} onAction={handleAction}>
      <XCard.Card id="welcome" />
    </XCard.Box>
  );
}

🚨 開発ルール

  • すべてのコマンドに "version": "v0.9" を必ず含めてください — 省略するとプロトコルによって拒否されます。
  • 各サーフェスのコンポーネントツリーに id: "root" コンポーネントを1つだけ配置してください — これがツリーのルートです。
  • フラットな隣接リストのみを使用してください — コンポーネントオブジェクトを別のコンポーネントオブジェクトの中にネストせず、必ず id 文字列で子を参照してください。
  • 構造とデータを分けてください — レイアウトには updateComponents、コンテンツや状態には updateDataModel を使用します。
  • マウント前にカタログを登録してください — コンポーネントツリーがレンダリングされる前に registerCatalog() を呼び出してください。
  • components マップは XCard.Card ではなく XCard.Box に渡してください — Box がすべての Card に配布します。
  • components オブジェクトをインラインで再作成しないでください — 再レンダリングを避けるため、useMemo またはモジュールレベルの定数で安定させてください。
  • 入力コンポーネントには双方向バインディング用の value: { path: "..." } が必要です — リテラル値ではデータモデルが更新されません。
  • ストリーミングの場合:コマンドを置き換えるのではなく、配列に新しいコマンドを追加してください — Card が差分を段階的に処理します。
  • action.event.context のパスは書き込み先です — データモデル内でユーザー入力データが格納される場所を指します。読み取り元として解決しないでください。
  • アクションコンテキスト内のパス参照は自動的に解決されます — アクションがトリガーされると、X-Card はアクション設定内の { path: "xxx" } を onAction ペイロード内の { value: "actual_value" } に変換します。これは v0.9(action.event.context = { key: { path } })形式と v0.8(action.context = [{ key, value: { path } }])形式の両方で機能します。

🤝 スキル連携

シナリオスキルの組み合わせ
構造化されたカード応答を使う AI チャットuse-x-chat + x-components + x-card
単独エージェント向けフォーム UIx-card のみ
ストリーミング Markdown + カードのサイドパネルx-markdown + x-card
エージェントからカードへの HTTP ストリーミングx-request → 応答をコマンドとして渡す

🔗 参考資料

  • USAGE.md — セットアップガイド、ストリーミングのパターン、複数サーフェスの例
  • COMMANDS.md — 4種類すべての A2UI v0.9 コマンドタイプ、v0.8 と v0.9 の差分
  • DATA_BINDING.md — JSON Pointer パス、動的型、双方向バインディング、テンプレート反復
  • ACTIONS.md — アクション定義、ActionPayload、フォーム送信パターン
  • CATALOG.md — ローカルカタログの登録、リモート URL の読み込み、カスタムコンポーネントのスキーマ
  • API.md — Box、Card、コマンド、カタログ、アクションの TypeScript 型の詳細

公式ドキュメント

コメント