# コーディングルール詳細 このプロジェクト固有の Incorrect/Correct ペアを収録する。shadcn スキルの `rules/` にある汎用例とは異なり、workspace-ui-kit の実コードに基づく固有パターンを扱う。 ## 目次 - base(Base UI)固有のパターン - スペーシング - タイポグラフィ - セマンティックカラー - アイコン - コンポジション - フォーム - components/ui/ 編集の具体例 --- ## base(Base UI)固有のパターン このプロジェクトは base(Base UI)を使用している(`components.json` の `style` フィールドで確認できる)。AI は radix の API をデフォルトで生成しやすいので、特に注意する。 **Incorrect:** ```tsx ``` **Correct:** ```tsx }>設定を開く ``` ポイント: base では `asChild` ではなく `render` を使う。`render` は JSX 要素を受け取り、そのまま描画する。 **Incorrect:** ```tsx ``` **Correct:** ```tsx ``` ポイント: base の Select は `items` prop でオプションを渡す方式もある。`components.json` の `base` フィールドを確認して API を選ぶ。 --- ## スペーシング **Incorrect — Pane4 のセクション内で子要素に余白を持たせている:** ```tsx

プロフィール

... ... {showSource && ...}
``` **Correct — 入れ物が子同士の隙間を管理:** ```tsx

プロフィール

... ... {showSource && ...}
``` `showSource` が `false` になったとき、`space-y-3` だと最後の `Row` に余計な `margin-top` が残ることがある。`gap-3` なら親が管理するので子が何個でも崩れない。 --- ## タイポグラフィ **Incorrect — 呼び出し側で見た目を毎回打ち消す(コピペ蔓延の原因):** ```tsx 評価サマリ ``` **Correct — 部品側にサイズ展開を用意して、呼び出し側はシンプルに:** ```tsx 評価サマリ ``` `components/ui/card.tsx` に `data-size="sm"` の variant を追加する(components/ui/ 編集の具体例を参照)。 **Incorrect — Pane4 セクション見出しを h2 + className で毎回書く:** ```tsx

基本情報

``` この h2 + className の組み合わせが 11 セクション分コピペされているのが前回の監査で発見された。 **Correct — 見出し用のプリミティブを抽出:** ```tsx 基本情報 ``` 共通の見出しプリミティブ `` を `components/primitives/` に作り、内部で h2 + スタイルを持たせる。 --- ## セマンティックカラー **Incorrect — 生の色クラスで状態を表す:** ```tsx 通過 不合格 ``` **Correct — semantic token または Badge variant:** ```tsx 通過 不合格 ``` このプロジェクトのサーフェス階層は `openspec/decision/` の配色 ADR で定義されている。`app/globals.css` の `@theme` セクションと ADR を読み、既存トークンで表現できるか確認する。 --- ## アイコン **Incorrect — Button 内のアイコンにサイジングクラスを付ける:** ```tsx ``` **Correct — 部品が CSS でアイコンサイズを制御:** ```tsx ``` shadcn の Button は内部でアイコンのサイズを制御している。サイジングクラスを付けると二重制御になり、サイズ変更時に壊れる。 正方形のアイコンコンテナには `size-*` を使う: ```tsx ``` --- ## コンポジション **Card は Header / Title / Content のフル構成で使う。** 中身を全部 CardContent に詰めない: ```tsx 評価サマリ 最新の面接評価 {/* 本文 */} ``` **Dialog / Sheet / Drawer には Title が必須。** 視覚的に不要でも `sr-only` で付ける: ```tsx 候補者を追加 {/* 本文 */} ``` **Avatar には AvatarFallback が必須。** 画像が読み込めなかった場合の代替表示: ```tsx {candidate.name.charAt(0)} ``` --- ## フォーム shadcn の Forms ルールに従い、`FieldGroup` + `Field` + `FieldLabel` で構成する。生の `div` + `Label` で組まない。 ```tsx 氏名 メールアドレス ``` 2〜7 択の選択肢には `ToggleGroup` を使う。`Button` をループして独自の active state を管理しない。 --- ## components/ui/ 編集の具体例 ### variant を追加する手順 例: `CardTitle` に `data-size="sm"` variant を追加する。 `components/ui/card.tsx` を開き、`CardTitle` の定義に data 属性によるスタイル切替を追加: ```tsx function CardTitle({ className, ...props }: React.ComponentProps<"div">) { return (
); } ``` 呼び出し側: ```tsx 評価サマリ ``` ### upstream の更新を取り込む手順 1. `npx shadcn@latest add card --dry-run` で影響範囲を確認 2. `npx shadcn@latest add card --diff card.tsx` で自分の変更と公式の変更を比較 3. 差分を見て、自分の variant 追加を保持しつつ公式の修正を取り込む 4. `--overwrite` はユーザーの明示的な承認なしに使わない