# 機能設計書 47-ダークモードプラグイン

## 概要

本ドキュメントは、v3互換のダークモード設定（media/class/selector/variant）をv4のバリアントシステムに変換する `darkModePlugin` 関数の設計を記述する。

### 本機能の処理概要

darkModePluginは、v3のdarkMode設定に基づいて `dark` バリアントをDesignSystemのVariantsに登録するプラグインである。

**業務上の目的・背景**：Tailwind CSS v3では `tailwind.config.js` の `darkMode` オプションでダークモードの実装方式を設定する（media/class/selector/variant）。v4ではバリアントシステムが刷新されたが、v3設定との互換性を維持するため、darkMode設定をv4の `addVariant` APIに変換する必要がある。

**機能の利用シーン**：`upgradeToFullPluginSupport` の `resolveConfig` 呼び出し時に、常にresolvedConfigの最後のプラグインとして追加される。設定ファイルの `darkMode` オプションに応じて適切なバリアントを生成する。

**主要な処理内容**：
1. `config('darkMode')` から設定値を取得
2. 設定値の形式に基づいて適切なバリアントセレクタを決定
3. `addVariant('dark', selector)` でバリアントを登録
4. 各モードに応じたセレクタ生成：
   - `null`: 何もしない（デフォルト）
   - `'selector'`: `&:where({selector}, {selector} *)`
   - `'media'`: `@media (prefers-color-scheme: dark)`
   - `'variant'`: カスタムセレクタをそのまま使用
   - `'class'`: `&:is({selector} *)`（v3旧動作）

**関連システム・外部連携**：PluginAPI（addVariant/config）を使用する。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面には直接関連しない |

## 機能種別

計算処理（バリアント生成）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| addVariant | Function | Yes | PluginAPIのaddVariantメソッド | 有効な関数 |
| config | Function | Yes | PluginAPIのconfigメソッド | 有効な関数 |

### 入力データソース

- ResolvedConfigの `darkMode` プロパティ（config関数経由で取得）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| - | void | 副作用としてdarkバリアントを登録 |

### 出力先

- DesignSystemのVariantsオブジェクト（addVariant経由）

## 処理フロー

### 処理シーケンス

```
1. darkMode設定の取得
   └─ config('darkMode', null) でdarkMode値を取得

2. 設定値の正規化
   └─ 配列の場合は [mode, selector] に分割、文字列の場合は [mode]

3. variantモードの特別処理
   ├─ セレクタが配列/関数/文字列かを判定
   ├─ '.dark'のみの場合は警告を出してスキップ
   └─ '&'を含まない場合は警告を出してスキップ

4. モードに基づくバリアント登録
   ├─ null: 何もしない
   ├─ 'selector': addVariant('dark', '&:where({selector}, {selector} *)')
   ├─ 'media': addVariant('dark', '@media (prefers-color-scheme: dark)')
   ├─ 'variant': addVariant('dark', selector)
   └─ 'class': addVariant('dark', '&:is({selector} *)')
```

### フローチャート

```mermaid
flowchart TD
    A[darkModePlugin開始] --> B[config取得: darkMode]
    B --> C[設定値の正規化]
    C --> D{mode値?}
    D -->|null| E[何もしない]
    D -->|selector| F["addVariant('dark', '&:where(sel, sel *)')"]
    D -->|media| G["addVariant('dark', '@media prefers-color-scheme')"]
    D -->|variant| H{セレクタ検証}
    H -->|有効| I["addVariant('dark', selector)"]
    H -->|無効| J[警告出力・スキップ]
    D -->|class| K["addVariant('dark', '&:is(sel *)')"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-47-01 | デフォルトセレクタ | selector/classモードのデフォルトセレクタは`.dark` | セレクタ未指定時 |
| BR-47-02 | selectorモード | `:where()` を使用して詳細度を低く保つ新しい推奨動作 | mode === 'selector' |
| BR-47-03 | classモード | `:is()` を使用するv3旧動作 | mode === 'class' |
| BR-47-04 | variantモード検証 | `&` を含まないセレクタは無効として警告 | mode === 'variant' |
| BR-47-05 | variant '.dark'警告 | variantモードで'.dark'のみは不正として警告 | selector === '.dark' |

### 計算ロジック

各モードで生成されるセレクタ:
- **selector**: `&:where(.dark, .dark *)` - `:where()` で詳細度0
- **media**: `@media (prefers-color-scheme: dark)` - OSの設定に従う
- **class**: `&:is(.dark *)` - `:is()` で詳細度が上がる（v3旧動作）
- **variant**: ユーザー指定のセレクタをそのまま使用

## データベース操作仕様

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | console.warn | variantモードで'.dark'のみ | 警告を出力しスキップ |
| - | console.warn | variantモードで'&'を含まないセレクタ | 警告を出力しスキップ |

### リトライ仕様

該当なし

## トランザクション仕様

該当なし

## パフォーマンス要件

- 単純な条件分岐処理のためパフォーマンス影響は無視できる

## セキュリティ考慮事項

該当なし

## 備考

- darkModePluginは `upgradeToFullPluginSupport` で `resolveConfig` に渡される設定の最後に追加されるため、他のプラグインが登録したdarkバリアントを上書きする可能性がある
- v4のデフォルトでは `darkMode: null` であり、v4コアが独自にdarkバリアントを提供する。この互換プラグインはv3設定が存在する場合のみ影響する

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | types.ts | `packages/tailwindcss/src/compat/config/types.ts` | DarkModeStrategy型（42-64行目）。false/media/class/selector/variant + カスタムセレクタ |

**読解のコツ**: DarkModeStrategyはunion型で、文字列リテラル型とタプル型の組み合わせ。配列の場合、第2要素がセレクタのカスタマイズ。

#### Step 2: メイン関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dark-mode.ts | `packages/tailwindcss/src/compat/dark-mode.ts` | darkModePlugin関数（4-51行目） |

**主要処理フロー**:
1. **5行目**: config('darkMode', null)で設定取得
2. **6行目**: 配列/文字列の正規化
3. **8-36行目**: variantモードの特別処理と検証
4. **38-50行目**: 各モードに対応するaddVariant呼び出し

### プログラム呼び出し階層図

```
darkModePlugin({ addVariant, config })
    │
    ├─ config('darkMode', null)
    │
    └─ addVariant('dark', selector)
           └─ designSystem.variants.static('dark', ...)
```

### データフロー図

```
[入力]                   [処理]                           [出力]

darkMode設定 ────▶ darkModePlugin() ──────▶ 'dark'バリアント登録
(null/media/       (モード判定 +
class/selector/     セレクタ生成)
variant)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dark-mode.ts | `packages/tailwindcss/src/compat/dark-mode.ts` | ソース | ダークモードプラグイン本体 |
| types.ts | `packages/tailwindcss/src/compat/config/types.ts` | ソース | DarkModeStrategy型定義 |
| plugin-api.ts | `packages/tailwindcss/src/compat/plugin-api.ts` | ソース | PluginAPI（addVariant/config） |
| apply-compat-hooks.ts | `packages/tailwindcss/src/compat/apply-compat-hooks.ts` | ソース | 呼び出し元（273行目でresolveConfigに渡される） |
