mcpField
P
plan-ui-change

plan-ui-change

github.com/dotnet開発5.8k3.2k 回インストール1 日前に更新
リポジトリ

plan-ui-change について

複雑な Blazor UI の変更を計画・実装するスキルです。コーディングエージェントが UI を役割ごとのコンポーネントに分け、状態とデータフローを定めて、末端から構築できるよう支援します。

主な機能

  1. 01画面領域をコンポーネントに分割
  2. 02レンダーモードと状態所有者の分類
  3. 03パラメーターとイベントのデータフロー設計
  4. 04コンポーネント再利用機会の確認
  5. 05末端からのコンポーネント実装

活用シーン

  1. 01複数領域のダッシュボード計画
  2. 02大規模ページのコンポーネント分割
  3. 03親子間の状態とイベントの整理

インストール

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

$npx skills add https://github.com/dotnet/skills --skill plan-ui-change

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

詳細

Blazor UI 変更の計画

複雑な UI 機能の構築を依頼された場合は、まずコンポーネントの分割を計画し、その後すぐに実装してください。単一のモノリシックなページコンポーネントが適切な答えとなることはほとんどありません。UI を、焦点を絞った組み合わせ可能なコンポーネントに分割してください。

計画ワークフロー

ステップ 1 — 視覚的な領域を整理する

依頼内容を読み、個別の視覚的な領域をすべて特定します。それぞれに独自のデータ、動作、またはレイアウト上の責任がある領域は、コンポーネントの候補です。

コンポーネントツリーを作成します。

InventoryDashboard          (page — owns data, orchestrates layout)
├── StockSummaryBar         (read-only stats: total items, low-stock count, value)
├── InventoryFilters        (search box, category dropdown, stock-level toggle)
├── InventoryTable          (sortable table of products)
│   └── InventoryRow        (single product row with inline edit/delete)
└── AddProductForm          (slide-out form for new products)

コンポーネントを特定する際のルール:

  • 明確な責任 — 領域が独自の状態や動作を持つ場合 → 個別のコンポーネントにする
  • 繰り返し構造 — リスト内のアイテム、グリッド内のカード → アイテムのテンプレートを抽出する
  • 独立したインタラクティブ性 — 兄弟要素とは別にユーザー入力を処理するセクション → 個別のコンポーネントにする
  • サイズ — 単独でマークアップが約 150 行を超えるセクション → 分割する
ステップ 2 — 各コンポーネントを分類する

ツリー内の各コンポーネントについて、次の項目を決めます。

コンポーネントアクションレンダーモード所有する状態行数(概算)
InventoryDashboard作成InteractiveServer商品リスト、フィルター状態~80
StockSummaryBar作成(継承)なし — データを受け取る~30
InventoryFilters作成(継承)検索テキスト、選択中のカテゴリ~60
InventoryTable作成(継承)ソート列、ソート方向~50
InventoryRow作成(継承)インライン編集モードのフラグ~60
AddProductForm作成(継承)フォームモデル~80

マークアップとコードを合わせて約 200 行を超えるページコンポーネントは大きすぎます。 見積もりで単一のコンポーネントがそれを超える場合は、さらに分割してください。

ステップ 3 — データフローを設計する

各データの状態を所有するコンポーネントを特定し、データの流れを整理します。

InventoryDashboard (owns: products[], filters)
  │
  ├─ [Parameter] products ──→ StockSummaryBar (reads aggregate stats)
  │
  ├─ [Parameter] filters ──→ InventoryFilters
  │   └─ EventCallback<Filters> OnFiltersChanged ──→ InventoryDashboard
  │
  ├─ [Parameter] filteredProducts ──→ InventoryTable
  │   └─ [Parameter] product ──→ InventoryRow
  │       ├─ EventCallback<Product> OnSave ──→ InventoryTable ──→ InventoryDashboard
  │       └─ EventCallback<Product> OnDelete ──→ InventoryTable ──→ InventoryDashboard
  │
  └─ EventCallback<Product> OnProductAdded ←── AddProductForm

ルール:

  • データは常に [Parameter] を通じて下方向に流れる
  • イベントは常に EventCallback<T> を通じて上方向に流れる
  • ページ/親コンポーネントがデータを所有し、フィルターや変換を適用したビューを子に渡す
  • 子コンポーネントはパラメーターを変更しない。コールバックを介して親に通知する
  • 中間コンポーネントが必要としないデータを 2 階層を超えて渡す必要がある場合は、カスケード値またはスコープ付きサービスを使用する
ステップ 4 — 再利用の機会を特定する

新しいコンポーネントを作成する前に、プロジェクト内の既存コンポーネントを目的に利用できるか確認します。次の項目を探してください。

  • 構造が一致する既存のリストアイテムコンポーネント
  • プロジェクト内にすでにある共有フィルター/検索コンポーネント
  • テンプレートを受け取る汎用コンポーネント(例:DataTable<T>、Pagination)

複数のページで使用するコンポーネントは、Shared/ または Components/ フォルダーに配置します。

ステップ 5 — 実装の順序を決める

下から上へ構築します。まずリーフコンポーネントを作成し、次にそれらを組み合わせる親コンポーネントを作成します。

  1. モデル/DTO — データの形を定義する
  2. サービス — データアクセス、ビジネスロジック(インターフェイス+実装)
  3. リーフコンポーネント — 子を持たないコンポーネント(InventoryRow、StockSummaryBar)
  4. コンテナーコンポーネント — リーフを組み合わせるコンポーネント(InventoryTable、InventoryFilters)
  5. ページコンポーネント — すべてをつなぎ合わせ、ルートを登録する
  6. 設定 — DI 登録、レンダーモードのセットアップ

各コンポーネントは単独でコンパイルできる必要があります。まだ存在しないコンポーネントを参照してはいけません。

出力形式

計画を簡潔に提示してから、すぐに実装に進んでください。計画だけで終わったり、コードを書く前に確認を求めたりしてはいけません。計画は思考のためのツールであり、成果物ではありません。

## Component Plan: [Feature Name]

### Component Tree
[ASCII tree showing parent-child relationships]

### Component Table
| Component | Action | Render Mode | Purpose | Est. Lines |
|-----------|--------|-------------|---------|------------|
| ... | ... | ... | ... | ... |

### Data Flow
[State owner] → [Parameters down] → [EventCallbacks up]

### Implementation Order
1. [First file to create — why]
2. [Second file — why]
...

計画を出力した後、記載した順序でコンポーネントの実装をすぐに開始してください。承認を待ったり、「続けてもよいですか?」と尋ねたりしてはいけません。計画はユーザーに承認してもらうための提案ではなく、あなたが従うためのガイドです。

避けるべきアンチパターン

アンチパターン望ましくない理由正しいアプローチ
500行を超える単一のページコンポーネントテスト、再利用、保守ができません役割を絞ったコンポーネントに分割します
中間コンポーネントを介して10個以上のパラメーターを渡すパラメーターの受け渡しが意図を分かりにくくしますカスケード値またはスコープ付き状態サービスを使用します
子コンポーネントが独自にAPIからデータを取得する複数のコンポーネントが重複した呼び出しを行います親がデータを所有し、パラメーターで渡します
複雑なマークアップを使ってリスト項目をインラインでレンダリングするロジックが重複し、再利用できず、テストも困難です項目テンプレートを独立したコンポーネントに切り出します
すべてを1つのファイルで構築してから「後でリファクタリングする」リファクタリングはほとんど行われず、モノリスのままリリースされますあらかじめ分割を計画します
一度限りの用途に汎用コンポーネントを使う過剰な設計によって複雑さが増します再利用の実績が確認できた場合にのみ、ジェネリックとして切り出します

ガイドライン

  • 簡潔に計画してから、実装します。 コンポーネントの表とデータフロー図を簡潔に作成し、すぐに .razor ファイルを作成します。計画だけで終わらせないでください。
  • 大きなコンポーネントを1つ作るより、小さなコンポーネントを複数作ることを優先します。 目的が明確なコンポーネントは理解、テスト、再利用が容易です。
  • 最初に決めるべきことは、状態をどのコンポーネントが所有するかです。 データ取得のロジックを書く前に、どのコンポーネントがデータを所有するかを決めます。
  • 下から上へ構築します。 まず末端のコンポーネントを作成し、親コンポーネントからすぐに参照できるようにします。
  • コンポーネント名には、内部で何をするかではなく、何をレンダリングするかを使います。 ProductRenderer ではなく ProductCard、FilterHandler ではなく OrderFilters とします。

コメント