state-machine について
state-machine は、1 つの UI コンポーネントが取り得る状態を確認するビジュアル作業環境です。モックデータで各状態を表示し、切り替えながら見られます。コード上で到達できる状態だけを扱い、見た目の調整と再確認に使えます。
主な機能
- 01既存コードの分岐から状態を特定
- 02モックデータで各状態を表示
- 03切り替え機能で状態を確認
- 04データ境界からフィクスチャを注入
- 05見た目の変更後に全状態を再確認
活用シーン
- 01ローディング、空、エラー状態の確認
- 02アカウント権限別の表示確認
- 03見た目を調整して他の状態も再確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jakubkrehel/ skills --skill state-machineインストール後、Claude Code で/state-machineを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlswitcher.md
詳細
状態マシン
このスキルでは、1つのコンポーネントを取り上げ、使い捨てのページ上に、そのコンポーネントが取り得るすべての状態を表示します。各状態にはモックデータを用意し、切り替えスイッチで状態を切り替えられます。作業が終わったら、ページを一度の操作で削除できます。
これは作業台であり、レビュー用の場ではありません。ユーザーがビジュアルに取り組んでいる間、ページは表示されたままになり、1つの状態を画面に表示しながら、ほかの状態へキー操作ですぐに切り替えられます。1回の確認のために厳しいシナリオを1ページに積み重ねるのは break、別のデザインを試すのは variant、完成した成果物をレビューするのは interface-review です。
1. 対象コンポーネントを1つに絞る
1回の実行につき、コンポーネントは1つです。監査ログのテーブル、ネットワークパネル、請求カードなどです。「設定ページ」には複数のコンポーネントが含まれるため、候補を列挙してどれかを確認してください。
そのコンポーネントが何を表示し、本番環境のどこに描画され、データがどこから来るのかを、1文で言い直してください。
2. コードから状態を見つける
状態とは、コンポーネントにすでに存在する分岐です。コードとデータフックを読み、該当する状態をすべて確認します。
| 種類 | 状態 |
|---|---|
| データ | 読み込み中、空、エラー、1件、標準的な件数、スクロールまたはページネーションが必要な件数、一部のリクエストが解決済みでほかが保留中、古いデータの再取得中 |
| アカウント | プランの階層、ロールと権限のチェック、オーナーとメンバー |
| 機能 | フラグ、トライアル、上限到達、無効化またはロックされた機能 |
コードで到達できない状態は、状態ではありません。その状態を表示するための分岐を追加しないでください。デザイン上は存在するものの、コードにない状態は、不足として列挙し、対象から外してください。
ページを構築する前に、状態を1行ずつ書き出してください。名前は empty、enterprise、member-no-access のように、プロダクトで使われている表現にします。変化する内容に応じて、プロダクトの言葉で見出しを付けてグループ化してください。Data や Account、あるいは Connection や Access のような、より具体的な見出しを使います。切り替えスイッチにはこれらのグループを表示します。対象から外した種類と、その理由を1行で記してください。種類を組み合わせるのは、member-empty のようにコードがその組み合わせで分岐する場合に限り、すべての組み合わせを掛け合わせないでください。
3. 使い捨てページを構築する
アプリ内のスクラッチ用ルートに、プロジェクトからインポートした実際のコンポーネントを、変更せずに配置します。ルートはアプリのレイアウト、フォント、グローバルスタイル、プロバイダーをそのまま継承します。
フレームワークがサーバーコンポーネントとクライアントコンポーネントを分けている場合、ページはクライアントコードにしてください。Next では "use client" を指定します。そうしないと、その境界を越える際にフィクスチャデータが気づかないうちに消え、ページが空で描画されることがあります。
本番環境でのコンポーネントと同じ幅のコンテナに、インスタンスを1つだけ描画します。ページに追加するのは、コンテナ、フィクスチャ、切り替えスイッチだけです。独自のフォント、スタイル、テーマは追加しません。ページ、フィクスチャ、切り替えスイッチは、たとえば /states/audit-log のように1つのフォルダーにまとめ、削除を一度で済ませられるようにします。
4. データの境界で各状態のデータを渡す
コンポーネントを編集せずに、ページからコンポーネントがデータを受け取る場所でデータを渡します。優先順位は次のとおりです。
- コンポーネントがデータを props として受け取る場合は、props。
- アプリ独自のデータ境界:シード済みのクエリキャッシュ、モックプロバイダー、またはプロジェクトのリクエストモック。
フィクスチャを props として5階層下まで渡す方法では、本番環境では通らない経路をテストすることになります。コンポーネントを編集する以外にデータを渡す方法がない場合は、その旨を伝え、データ境界を追加する前に確認してください。
データは実際のプロダクトに即したものにします。実在しそうな名前、タイムスタンプ、金額、そしてユーザーが実際に扱う件数を使ってください。「テスト項目」の3行だけでは、どの状態も問題なく見えてしまいます。
読み込み中や保留中の状態は、そのまま維持します。タイムアウト後に解決させるのではなく、切り替えスイッチで移動するまで保留状態を保ってください。
5. 切り替えスイッチを追加する
コンポーネントの横にグループ化した一覧を置き、__state 検索パラメーターを切り替えられるようにします。これにより、各状態がリンクになります。コンポーネントの横に置く余地がない場合は、同じグループを使う選択メニューにして、コンポーネントの上に配置します。アンダースコアを2つ付けることで、アプリのレイアウトが読み取るパラメーターと明確に区別できます。仕様は switcher.md に記載されています。
6. すべての状態が表示されることを確認してから、引き渡します
ブラウザーをすぐに使える状態でページを一度読み込み、すべての状態を順に切り替えます。コンポーネントには実データでも空白領域でもなく、モックデータが表示されます。モックデータが一度も表示されないことが、よくある失敗です。ライブ同期、シードデータを上書きして再取得するキャッシュ、またはフィクスチャを破棄するサーバー境界が原因です。引き渡す前に、データの受け渡しを修正してください。
ブラウザーをすぐに使えない場合は、その旨を伝え、ユーザーが確認できるよう URL を渡します。
その後、URL、状態の一覧、切り替えキーを引き渡します。そこで終了します。状態の見た目を変えるのは、ユーザーの次の依頼であり、今回の作業には含まれません。
変更のたびに、すべての状態を再確認します
見た目を変更した後は、毎回すべての状態を順に切り替えて再確認します。ある状態への修正が、別の状態を壊すことがよくあるためです。
ユーザーの指示があれば、一度で削除します
ページフォルダーと、ユーザーが承認したシームを削除します。その後、コードベースでルート名とフィクスチャ名を検索し、差分がセットアップの他の部分に触れていないことを確認します。
完了する前に
| 間違い | 修正方法 |
|---|---|
| フィクスチャを受け取れるようにコンポーネントを編集した | ページからプロップスまたはアプリのデータシームを通じてデータを渡します。シームの追加前に確認してください |
| ページ上に、見た目だけ似せたコンポーネントを再構築した | プロジェクトから実際のコンポーネントをインポートします |
| ページでコンポーネントのスタイルやテーマを変更した | アプリのレイアウト、フォント、トークンをそのまま使います |
| ツリーの深い位置で、プロップスとしてフィクスチャを渡した | コンポーネントがデータを受け取る箇所でデータを渡します |
| 状態を表示するために、コンポーネントに分岐を追加した | コードから到達できない状態は追加せず、不足している状態を一覧にします |
| 「アイテム 1」、「テストユーザー」、3 行 | 実際の数量に合わせた、製品らしいデータを使います |
| タイムアウト後に読み込みが完了する | スイッチャーを切り替えるまで読み込み中の状態を保ちます |
| すべての状態を読み込まずに引き渡した | すべての状態を読み込みます。空白または実データが表示された場合は、データの受け渡しに問題があります |
| プロジェクトのトークンでスイッチャーをスタイリングした | デザインシステムの外にあることが見た目で分かるようにします |
| 状態ごとのタブを横一列に並べた | コンポーネントの横にグループ化した一覧を置き、それ自体をスクロールできるようにします。一覧が収まらない場合は、その上にセレクトを置きます |
| 頼まれていないのに見た目を変更した | 引き渡して、次の指示を待ちます |
| 作成したのと同じターンでページを削除した | ユーザーの指示があった場合にのみ削除します |
| ルート名やフィクスチャ名を残した | 削除後に両方を検索します |