# 機能設計書 35-Transition

## 概要

本ドキュメントは、Vue 3の組み込みコンポーネント`<Transition>`の機能設計を記載する。`<Transition>`は単一要素の挿入・削除時にCSS/JavaScriptベースのアニメーション遷移を管理する高階コンポーネントである。

### 本機能の処理概要

`<Transition>`コンポーネントは、プラットフォーム非依存の`BaseTransition`コンポーネントをラップし、DOM固有のCSSトランジション/アニメーションクラスの管理を追加した高階コンポーネントである。要素のenter（挿入）、leave（削除）、appear（初回表示）の各フェーズでCSSクラスを自動的に付与・除去し、スムーズなUI遷移を実現する。

**業務上の目的・背景**：モダンなWebアプリケーションでは、要素の出入りに視覚的なフィードバックを提供することがUX向上に不可欠である。CSSトランジション/アニメーションの手動管理は複雑であり、Vueの宣言的なテンプレート構文と組み合わせることで、開発者は最小限のコードでリッチなアニメーションを実装できる。

**機能の利用シーン**：モーダルダイアログの表示/非表示、通知メッセージのフェードイン/フェードアウト、ルート遷移時のページ切替アニメーション、条件付き表示要素のスライドイン/スライドアウトなど。

**主要な処理内容**：
1. `BaseTransition`に渡すpropsの解決（`resolveTransitionProps`）
2. enter/leave/appearの各フェーズでのCSSクラスの付与・除去
3. CSSトランジション/アニメーションの終了イベント検出（`whenTransitionEnds`）
4. 明示的なduration指定のサポート
5. `requestAnimationFrame`のダブルフレームによるクラス切替タイミング制御
6. `mode`（in-out/out-in）によるトランジション順序制御
7. CSSトランジション情報の取得（`getTransitionInfo`）

**関連システム・外部連携**：`BaseTransition`（`@vue/runtime-core`）と連携。`v-show`ディレクティブとの連携によるpersisted transition。

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

## 関連画面

画面機能マッピングに該当する画面関連情報なし。

## 機能種別

アニメーション制御 / 組み込みコンポーネント

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | `string` | No | CSSクラスのプレフィックス（デフォルト: 'v'） | - |
| type | `'transition' \| 'animation'` | No | 使用するアニメーションタイプの明示指定 | - |
| css | `boolean` | No | CSSベースのトランジションを使用するか（デフォルト: true） | - |
| duration | `number \| { enter: number; leave: number }` | No | 明示的なトランジション時間（ms） | 数値であること |
| enterFromClass | `string` | No | enter開始時のCSSクラス | - |
| enterActiveClass | `string` | No | enterアクティブ時のCSSクラス | - |
| enterToClass | `string` | No | enter終了時のCSSクラス | - |
| appearFromClass | `string` | No | appear開始時のCSSクラス（デフォルト: enterFromClass） | - |
| appearActiveClass | `string` | No | appearアクティブ時のCSSクラス（デフォルト: enterActiveClass） | - |
| appearToClass | `string` | No | appear終了時のCSSクラス（デフォルト: enterToClass） | - |
| leaveFromClass | `string` | No | leave開始時のCSSクラス | - |
| leaveActiveClass | `string` | No | leaveアクティブ時のCSSクラス | - |
| leaveToClass | `string` | No | leave終了時のCSSクラス | - |
| mode | `'in-out' \| 'out-in' \| 'default'` | No | トランジションモード | BaseTransitionから継承 |
| appear | `boolean` | No | 初回表示時にトランジションを適用するか | BaseTransitionから継承 |

### 入力データソース

- テンプレート内の`<Transition>`コンポーネントのprops

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| CSS class操作 | - | DOM要素へのCSSクラスの追加・削除 |
| VNode | `VNode` | BaseTransitionをレンダリングしたVNode |

### 出力先

- DOM要素のclassList
- VNodeツリー

## 処理フロー

### 処理シーケンス

```
enterフェーズ:
1. onBeforeEnter: {name}-enter-from + {name}-enter-active を追加
2. onEnter: nextFrame後に {name}-enter-from を削除、{name}-enter-to を追加
3. トランジション終了イベント検出 → finishEnter
4. finishEnter: {name}-enter-to + {name}-enter-active を削除

leaveフェーズ:
1. onLeave: {name}-leave-from を追加、forceReflow、{name}-leave-active を追加
2. nextFrame: {name}-leave-from を削除、{name}-leave-to を追加
3. トランジション終了イベント検出 → finishLeave
4. finishLeave: {name}-leave-from + {name}-leave-to + {name}-leave-active を削除
```

### フローチャート

```mermaid
flowchart TD
    A[要素の挿入/削除] --> B{css=true?}
    B -->|No| C[BaseTransitionのフックのみ実行]
    B -->|Yes| D{enterフェーズ?}
    D -->|Yes| E[enter-from + enter-active 追加]
    E --> F[nextFrame: enter-from削除 + enter-to追加]
    F --> G[transitionend/animationend検出]
    G --> H[enter-to + enter-active 削除]
    D -->|No| I[leave-from追加 + forceReflow]
    I --> J[leave-active追加]
    J --> K[nextFrame: leave-from削除 + leave-to追加]
    K --> L[transitionend/animationend検出]
    L --> M[leave-from + leave-to + leave-active 削除]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-35-01 | デフォルトクラス名 | nameが指定されない場合はプレフィックス'v'を使用 | name未指定時 |
| BR-35-02 | nextFrameタイミング | `requestAnimationFrame`を2回ネストして次フレームでクラスを切替 | CSSトランジション適用時 |
| BR-35-03 | forceReflow | leave開始時に`document.body.offsetHeight`で強制リフローを発生させ、クラス変更を即座に反映 | leaveフェーズ開始時 |
| BR-35-04 | 明示的duration | `duration`propが指定された場合、CSSイベントの代わりにsetTimeoutで終了を検出 | duration指定時 |
| BR-35-05 | トランジション情報自動検出 | `window.getComputedStyle`でtransition/animationのdelay+durationを計算し、タイムアウトを設定 | duration未指定かつCSS有効時 |
| BR-35-06 | vtcキー | トランジション中に一時的に追加されたクラスを`Set<string>`で管理し、class patchingとの競合を防止 | 常時 |
| BR-35-07 | cancelledEnter | leaveキャンセル処理（#10677対応） - enter中にキャンセルされた場合はreflowの順序を変更 | enter中のleave開始時 |

### 計算ロジック

`getTransitionInfo`: `window.getComputedStyle`からtransition/animationのDelay/Durationを取得し、各プロパティの最大値をタイムアウトとして計算。

`toMs`: CSS時間文字列を数値（ms）に変換。`'auto'`の場合は0を返す。

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

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 開発時警告 | duration値が数値でない | `assertNumber`による検証 |
| - | 開発時警告 | 無効なmodeが指定された | BaseTransitionで警告 |
| - | 開発時警告 | 複数のルート要素が渡された | BaseTransitionで警告 |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

- `@__PURE__`アノテーションによりtree-shaking対応
- CSSクラスの操作はbatchされ、強制リフローは必要最小限に抑制
- `whenTransitionEnds`で安全マージン（timeout + 1ms）を設定し、イベント未発火時のフォールバックを提供

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

特記事項なし。

## 備考

- `endId`カウンターにより、複数のトランジションが同時進行した場合の古いコールバックの無効化を実現
- 旧Chromiumブラウザ（61.0.3163.100以前）のロケール依存の小数点フォーマットに対応（コンマをドットに置換）
- CSS時間値の`'auto'`は0msとして扱われる（#8409対応）

---

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

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

### 推奨読解順序

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

`TransitionProps`インターフェースと`BaseTransitionProps`を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Transition.ts | `packages/runtime-dom/src/components/Transition.ts` | `TransitionProps`インターフェース（18-33行目） |
| 1-2 | BaseTransition.ts | `packages/runtime-core/src/components/BaseTransition.ts` | `BaseTransitionProps`インターフェース（30-58行目）、`TransitionHooks`インターフェース（60-75行目） |

**読解のコツ**: `TransitionProps`は`BaseTransitionProps`を拡張し、DOM固有のCSS関連プロパティを追加している。`BaseTransitionProps`にはmode, appear, persistedおよびenter/leave/appearの各フェーズのフック関数が定義される。

#### Step 2: Transitionコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Transition.ts | `packages/runtime-dom/src/components/Transition.ts` | `Transition`関数コンポーネント（87-90行目）、`resolveTransitionProps`関数（121-298行目） |

**主要処理フロー**:
1. **87-90行目**: `h(BaseTransition, resolveTransitionProps(props), slots)`で委譲
2. **135-148行目**: CSSクラス名の解決
3. **184-194行目**: `finishEnter`関数 - enterクラスの除去
4. **196-205行目**: `finishLeave`関数 - leaveクラスの除去
5. **207-228行目**: `makeEnterHook` - enterフック生成
6. **249-283行目**: `onLeave`フック - leaveフェーズの制御

#### Step 3: CSSトランジション情報の取得を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Transition.ts | `packages/runtime-dom/src/components/Transition.ts` | `getTransitionInfo`関数（401-459行目）、`whenTransitionEnds`関数（348-387行目） |

#### Step 4: BaseTransitionの内部ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | BaseTransition.ts | `packages/runtime-core/src/components/BaseTransition.ts` | `BaseTransitionImpl`（145-267行目）、`resolveTransitionHooks`関数（323-482行目） |

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

```
<Transition> (FunctionalComponent)
    │
    └─ h(BaseTransition, resolveTransitionProps(props), slots)
           │
           ├─ resolveTransitionProps()
           │      ├─ CSSクラス名解決
           │      ├─ normalizeDuration()
           │      ├─ onBeforeEnter → addTransitionClass()
           │      ├─ makeEnterHook() → onEnter/onAppear
           │      │      ├─ nextFrame() → removeTransitionClass + addTransitionClass
           │      │      └─ whenTransitionEnds() → finishEnter
           │      └─ onLeave
           │             ├─ addTransitionClass() + forceReflow()
           │             ├─ nextFrame() → removeTransitionClass + addTransitionClass
           │             └─ whenTransitionEnds() → finishLeave
           │
           └─ BaseTransition.setup()
                  ├─ useTransitionState()
                  ├─ resolveTransitionHooks()
                  ├─ setTransitionHooks()
                  └─ mode処理 (in-out / out-in)
```

### データフロー図

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

TransitionProps      ┌──────────────────────────┐
  name/duration ─────▶│ resolveTransitionProps    │
                    │  └ CSSクラス名解決          │
                    └──────────┬───────────────┘
                               │
VNode挿入/削除       ┌───────▼──────────────────┐
  (条件変化) ────────▶│ BaseTransition            │
                    │  ├ enter → addClass        │──────▶ el.classList
                    │  │   └ nextFrame → swapCls │──────▶ CSSトランジション発動
                    │  ├ leave → addClass        │──────▶ el.classList
                    │  │   └ nextFrame → swapCls │──────▶ CSSトランジション発動
                    │  └ whenTransitionEnds      │──────▶ クラス除去・要素削除
                    └──────────────────────────┘
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Transition.ts | `packages/runtime-dom/src/components/Transition.ts` | ソース | DOM固有のTransitionコンポーネント実装 |
| BaseTransition.ts | `packages/runtime-core/src/components/BaseTransition.ts` | ソース | プラットフォーム非依存のTransition基盤 |
| index.ts | `packages/runtime-dom/src/index.ts` | ソース | Transitionのエクスポート |
| vShow.ts | `packages/runtime-dom/src/directives/vShow.ts` | ソース | v-showとの連携（persistedモード） |
