# 機能設計書 55-数値ウィジェット

## 概要

本ドキュメントは、Decap CMSにおける数値ウィジェット（Number Widget）の設計を記述する。整数・小数の入力と最小値・最大値の範囲バリデーションを提供する数値入力ウィジェットである。

### 本機能の処理概要

**業務上の目的・背景**：CMSで管理するコンテンツには、価格・数量・スコア・ページ番号など数値型のフィールドが必要となる場面が多い。本ウィジェットはHTMLの`<input type="number">`を使用し、ブラウザネイティブの数値入力UIを提供する。整数（int）と小数（float）の型変換、最小値・最大値の範囲制限、ステップ値の制御をサポートする。

**機能の利用シーン**：エントリ編集画面・エントリ新規作成画面において、`widget: number`が指定されたフィールドに対して数値入力フィールドをレンダリングする。config.ymlで`value_type: int`（整数）または`value_type: float`（小数）を指定できる。

**主要な処理内容**：
1. 数値入力フィールド（`<input type="number">`）のレンダリング
2. value_type（int/float）に基づく入力値のパース（parseInt/parseFloat）
3. min/maxによる範囲バリデーション
4. step値の自動設定（intの場合は1）
5. NaN値の空文字への変換

**関連システム・外部連携**：なし

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | エントリ編集画面 | 主機能 | 数値フィールドの入力 |
| 7 | エントリ新規作成画面 | 主機能 | 数値フィールドの入力 |

## 機能種別

UI入力コンポーネント / バリデーション

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| field | ImmutableMap | Yes | フィールド設定（value_type, min, max, step, pattern等） | - |
| onChange | function | Yes | 値変更時のコールバック関数 | - |
| classNameWrapper | string | Yes | ラッパーのCSSクラス名 | - |
| setActiveStyle | function | Yes | フォーカス時のスタイル設定関数 | - |
| setInactiveStyle | function | Yes | ブラー時のスタイル設定関数 | - |
| value | node | No | 現在の入力値（デフォルト: ''） | - |
| forID | string | No | input要素のid属性 | - |
| t | function | Yes | ローカライズ関数 | - |

### フィールド設定（config.yml）

| 設定名 | 型 | 説明 |
|--------|-----|------|
| value_type | string | 'int'（整数）または'float'（小数） |
| min | number | 最小値 |
| max | number | 最大値 |
| step | number | ステップ値 |
| pattern | string/array | パターンバリデーション（設定時はmin/maxバリデーションを上書き） |

### 入力データソース

エディタのコントロールペインから提供されるprops。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| value | number / string | パース後の数値（NaNの場合は空文字列''） |

### 出力先

onChangeコールバック経由でReduxストアのエントリドラフトに反映される。

## 処理フロー

### 処理シーケンス

```
1. コンポーネントマウント
   └─ PropTypesの手動バリデーション実行（React 19対応）
2. ユーザーが数値入力
   └─ handleChangeメソッドが呼ばれる
3. value_typeに基づき値をパース
   └─ float: parseFloat(e.target.value)
   └─ int: parseInt(e.target.value, 10)
4. NaN判定
   └─ 数値: onChange(value)
   └─ NaN: onChange('')
5. バリデーション（isValid呼び出し時）
   └─ pattern設定あり: trueを返す（patternに委譲）
   └─ pattern設定なし: validateMinMax で min/max チェック
```

### フローチャート

```mermaid
flowchart TD
    A[input type=number レンダリング] --> B[ユーザー入力]
    B --> C{value_type?}
    C -->|float| D[parseFloat]
    C -->|int| E[parseInt]
    D --> F{NaN?}
    E --> F
    F -->|No| G["onChange(数値)"]
    F -->|Yes| H["onChange('')"]
    G --> I[バリデーション]
    H --> I
    I --> J{pattern設定あり?}
    J -->|Yes| K[true返却]
    J -->|No| L[validateMinMax]
    L --> M{範囲内?}
    M -->|Yes| N[true返却]
    M -->|No| O[エラーメッセージ返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-55-01 | 型変換 | value_type === 'float'ならparseFloat、それ以外はparseIntで値をパースする | 入力変更時 |
| BR-55-02 | NaN処理 | パース結果がNaNの場合は空文字列''をonChangeに渡す | パース結果がNaN時 |
| BR-55-03 | pattern優先 | pattern設定がある場合、min/maxバリデーションはスキップされる | pattern設定あり時 |
| BR-55-04 | 範囲バリデーション | min/max設定時、値が範囲外ならローカライズされたエラーメッセージを返す | isValid呼び出し時 |
| BR-55-05 | ステップ自動設定 | value_type === 'int'の場合、step未設定時に自動的に1が設定される | レンダリング時 |
| BR-55-06 | ゼロ値表示 | value === 0の場合もinputに0として表示する（value || のfalsy判定を回避） | レンダリング時 |

### 計算ロジック

`validateMinMax`関数:
- `value < min && value > max` → 「{fieldLabel}は{min}から{max}の範囲で入力してください」
- `value < min` → 「{fieldLabel}は{min}以上で入力してください」
- `value > max` → 「{fieldLabel}は{max}以下で入力してください」

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

### 操作別データベース影響一覧

該当なし。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| RANGE | 範囲エラー | 値がmin/maxの範囲外 | ローカライズされたエラーメッセージを返却 |
| - | NaN | 数値以外の文字が入力された場合 | 空文字列に変換してonChange |

### リトライ仕様

該当なし。

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

該当なし。

## パフォーマンス要件

特になし。

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

HTML input type="number"要素を使用しているため、ブラウザのデフォルトの入力制御が適用される。

## 備考

- スキーマ定義（schema.js）でstep, value_type, min, maxのプロパティ型が定義されている
- バリデーションメッセージは`editor.editorControlPane.widget.range`, `.min`, `.max`のローカライズキーを使用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | schema.js | `packages/decap-cms-widget-number/src/schema.js` | フィールドスキーマ定義（step, value_type, min, max） |
| 1-2 | index.js | `packages/decap-cms-widget-number/src/index.js` | Widget関数がname: 'number'とschemaを含む構造（4-13行目） |

#### Step 2: バリデーションロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | NumberControl.js | `packages/decap-cms-widget-number/src/NumberControl.js` | validateMinMax関数（11-49行目）: 範囲バリデーションの3パターン分岐 |

**主要処理フロー**:
1. **4-9行目**: ValidationErrorTypes定義
2. **11-49行目**: validateMinMax関数 - min/maxの組合せによる3種類のエラーパターン
3. **88-101行目**: isValid - pattern優先判定とvalidateMinMax呼び出し

#### Step 3: コントロールコンポーネントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | NumberControl.js | `packages/decap-cms-widget-number/src/NumberControl.js` | handleChange（76-86行目）: value_typeによるパース分岐とNaN処理。render（103-122行目）: ステップ自動設定とゼロ値表示処理 |

**主要処理フロー**:
- **76-86行目**: handleChange - value_type判定、parseFloat/parseInt、NaN判定
- **103-122行目**: render - min, max, step属性の設定。step自動設定（107行目）
- **115行目**: `value || (value === 0 ? value : '')` - ゼロ値を正しく表示

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

```
DecapCmsWidgetNumber (index.js)
    |
    +-- Widget()
    |       └── { name: 'number', controlComponent, previewComponent, schema }
    |
    +-- NumberControl (NumberControl.js)
    |       +-- handleChange() - 値パース（parseInt/parseFloat）
    |       +-- isValid() - バリデーション
    |       |       └── validateMinMax() - 範囲チェック
    |       └── render() - <input type="number"> レンダリング
    |
    └── NumberPreview (NumberPreview.js)
            └── WidgetPreviewContainer で値表示
```

### データフロー図

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

ユーザー数値入力  ──> handleChange()          onChange(number | '')
                        |
                        v
                   parseInt / parseFloat
                        |
                        v
                   NaN判定
                        |
                        v
                   isValid() バリデーション
                        |
                        v
                   validateMinMax()
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `packages/decap-cms-widget-number/src/index.js` | ソース | ウィジェットエクスポート定義 |
| NumberControl.js | `packages/decap-cms-widget-number/src/NumberControl.js` | ソース | 入力コントロール・バリデーション |
| NumberPreview.js | `packages/decap-cms-widget-number/src/NumberPreview.js` | ソース | プレビューコンポーネント |
| schema.js | `packages/decap-cms-widget-number/src/schema.js` | ソース | フィールドスキーマ定義 |
