# Bone Flow #048 - Table 操作ガイド

## 1. 最初に

#048 Table は、列定義と行データを表形式で表示する Display UI です。通常利用HTML Functional Classは `bf-table` です。

- UI ID: `UI-048`
- DOC ID: `DOC-0048`
- DOC Version: `1.0.32`
- Runtime: `BoneTable 1.0.16`
- HTML Functional Class: `bf-table`

Tableは「表として表示すること」を担当します。セル編集やスプレッドシート操作をTableへ持ち込みません。

## 2. Tableとは

責務の境界は次の通りです。

- `#048 Table`: 行・列・セルの表示、セル内UI Rendererの配置
- `#049 Grid`: セル編集、グリッド操作
- `#073 Pagination`: ページ移動
- `#121 Timeline`: 時間制御
- `#002 Bone Joint`: 接続判定、Joint描画、異常marker、WAIT / FIFO / BLOCKED

## 3. 最小HTML

```html
<div class="bf-table"
     data-table-columns='[{"key":"name","label":"氏名"},{"key":"age","label":"年齢","align":"right"}]'
     data-table-rows='[{"name":"佐藤","age":31},{"name":"田中","age":28}]'></div>
```

`data-table-columns` と `data-table-rows` はJSONです。通常の文字列セルは `textContent` で描画され、HTMLとして実行されません。

## 4. Table Property

#048 Table自身の正式Property定義はRuntime-ownedです。`BoneTable.getPropertySchema()` / `getPropertyDefaults()` / `getPropertyDefinition(key)` を使用します。`inheritParent` は表示名 **「親に吸着」**、型 `boolean`、既定値 `true` です。ONでは親要素の利用可能幅へ吸着し、OFFではTable自身の内容幅を基準にします。

| Property | 型 | 既定値 | 意味 |
|---|---|---|---|
| `caption` | string | empty | 表の見出し |
| `columns` | array | `[]` | 列定義 |
| `rows` | array | `[]` | 行データ |
| `showHeader` | boolean | `true` | Header行を表示 |
| `displayRowCount` | integer | `0` | 最低表示行数。0はデータ行数に従う |
| `showEmptyRows` | boolean | `true` | 値なし行・補完行を表示 |
| `striped` | boolean | `true` | 行の背景を交互表示 |
| `hover` | boolean | `true` | Hover行を強調 |
| `bordered` | boolean | `true` | 枠線を表示 |
| `compact` | boolean | `false` | Cell paddingを縮める |
| `emptyText` | string | `データがありません` | 0件時の表示 |
| `theme` | select | `dark` | `light / dark / neon` |
| `inheritParent` | boolean | `true` | Table自身を親要素の利用可能幅へ吸着 |
| `ariaLabel` | string | `Table` | アクセシビリティ名 |


### 親要素に吸着（inheritParent）

`inheritParent` は **#048 Table自身と、そのTableを配置している親要素とのレイアウト契約**です。Cell Rendererの子要素をセルへ吸着する `snapToCell` とは別Propertyです。

- 正式Property名: `inheritParent`
- Property表示名: **親に吸着（デフォルト）**
- 型: `boolean`
- 既定値: `true`
- Runtime Schema: `BoneTable.getPropertyDefinition("inheritParent")`
- HTML Functional Class: `data-table-inherit-parent="true|false"`

**ON (`true`)**

- Table rootへ `bone-table--inherit-parent` を付与します。
- `data-inherit-parent="true"` を設定します。
- Tableは `width:100%; max-width:100%` で親要素の利用可能幅へ吸着します。
- #048をPanel、Card、Grid cellなどの親領域へ配置した場合、その親の横幅を基準にTableを表示します。

**OFF (`false`)**

- Table rootへ `bone-table--free` を付与します。
- `data-inherit-parent="false"` を設定します。
- Table rootは `display:inline-block; width:auto; max-width:100%`、内部Tableは `width:auto` となり、Table自身の内容幅を基準に表示します。
- 親領域を無制限にはみ出す指定ではなく、`max-width:100%` は維持します。

**`snapToCell` との違い**

- `inheritParent`: **Table自身 → 親要素** の吸着。#048 Tableの正式Runtime Propertyです。
- `snapToCell`: **Cell Renderer → Tableセル** の吸着。`columns[].cellElement` / `row.$cells[columnKey]` 側の設定です。
- 両者は独立しており、`inheritParent=true` だからCell Rendererが自動的にセル全面へ吸着するわけではありません。
- 逆に `snapToCell=true` でも、Table自身を親幅へ吸着するかどうかは `inheritParent` で決まります。

テストページの「正式Property定義（Runtime Schema）」はHTMLへ手書きした一覧ではなく、`BoneTable.getPropertySchema()` / `getPropertyDefaults()` / `getPropertyDefinition(key)` の実値を描画します。したがって `inheritParent` の型・既定値・説明もRuntime定義が正本です。


### 表示行数 / 値なし行を表示

Table Property の **「表示行数」** は `displayRowCount` に対応します。`0` は自動（データ行数に従う）です。実データより大きい値を指定すると、不足分を値なし行として補完します。実データより小さい値を指定してもデータ行を切り捨てません。勘定元帳など、先に一定数の帳票枠を表示したい場合に使用します。


Table Property のチェック **「値なし行を表示」** は `showEmptyRows` に対応し、既定値は `true` です。

- ON: `{}`、空文字、`null`、`[]` など、列値がすべて空の行でもTableの行枠・縦線・横線を残します。
- OFF: 列値がすべて空の行を `tbody` から非表示にします。
- `0` と `false` は有効な値なので空扱いしません。
- `$cells` にRenderer設定があっても、値が空なら「値なし行」のままです。

通常の Text / Label / Shape は空値では生成せず、Tableのセル罫線だけを残します。
一方、Rendererが `renderEmpty:true` を宣言した場合は、値なしでもUI構造を描画できます。

#054 Display Timeline は `renderEmpty:true` で登録されるため、`items=[]` でも時間軸・縦グリッド線を表示し、Bar / Shape Commentは表示しません。
#029 NumberBox は標準Cell Rendererとして `renderEmpty:true` で登録され、伝票表示では値を `null` のまま保持します。`voucherMode:true` / `voucherGridLines:true` のため、数値がなくても伝票の桁枠・罫線だけを表示し、ダミー数値は生成しません。

## 5. Columns

各Columnは次のPropertyを持ちます。

| Property | 必須 | 意味 |
|---|---:|---|
| `key` | YES | Row Objectから値を取り出すキー |
| `label` | NO | Header表示名。省略時は`key` |
| `align` | NO | `left / center / right` |
| `width` | NO | `auto` または `px / % / rem / em / ch` |
| `cellElement` | NO | その列のセル内UI Renderer設定 |

`key` は重複できません。Cell Element設定は列の既定値として全行へ適用されます。

## 6. Rows / $cells 上書き

`rows` はplain objectの配列です。Column `key` と同じキーの値がセル値になります。

```json
{
  "name": "営業A",
  "status": "勤務中"
}
```

特定のセルだけRendererやPropertyを変える場合は `$cells` を使います。

```json
{
  "name": "営業A",
  "status": "重要",
  "$cells": {
    "status": {
      "renderer": "017",
      "props": { "tag": "strong" },
      "snapToCell": true
    }
  }
}
```

`$cells.<columnKey>` は、そのセルだけ列側 `cellElement` を上書きします。

## 7. Cell Element設定

Cell Element設定は「セル値をどのUI Rendererで表示するか」を指定します。

```json
{
  "renderer": "021",
  "props": {
    "type": "PROCESS",
    "theme": "dark"
  },
  "snapToCell": true
}
```

- `renderer`: Renderer ID / Component ID / className / alias
- `props`: 選択UIへ渡すProperty
- `snapToCell`: セル領域へ吸着するか。既定値`true`

## 8. 対象列 ＋ / −

Cell Element設定の「対象列」には `＋ / −` があります。

- `＋`: 選択列の直後へ新しい列を追加し、全Rowsへ同名の空フィールドを追加
- `−`: 選択列を削除し、Rowsの同名フィールドと `$cells` 上書きも同時に削除

列だけ削除してRows側に古いデータを残す動作にはしません。

## 9. UI Renderer / Cell Renderer Registry

標準登録Rendererは次の7種です。

| Renderer | Component | 主用途 |
|---|---|---|
| `plain` | Plain Text | 安全な文字列表示 |
| `017` | #017 Text | Text表示 |
| `018` | #018 Icon | Icon表示 |
| `020` | #020 Label | Label表示 |
| `021` | #021 Shape | Shape表示 |
| `029` | #029 NumberBox | 数値 / 伝票表示 |
| `054` | #054 Display Timeline | Timeline表示 |
> #029 NumberBox は描画時に **#022 Hover Border Effect** を必須使用します。#048テストページは#029より先に#022 Runtime/CSSを読み込みます。

`text / bf-text`、`icon / bf-icon`、`label / bf-label`、`shape / bf-shape`、`numberbox / voucher / bf-numberbox`、`display-timeline / bf-display-timeline` などの登録aliasでも指定できます。

未登録Renderer、または必要Runtimeが未読込の場合はraw HTMLを実行せず、セル値を安全なテキストへフォールバックします。

## 10. 選択UI Property

「UI Renderer」を選択すると、**そのRendererのPropertyだけ**をCell Element設定内に表示します。

- 選択Component本体のPreviewは表示しない
- Smoke / Validation / Completionは表示しない
- 入力結果は `cellElement.props` に保存
- `text / number / boolean / select / textarea / json` 型に対応
- `options.theme` のようなネストProperty pathにも対応

TableはProperty入力UIを生成する汎用Editorを持ちますが、各Component固有のProperty意味をTable側で勝手に再設計しません。

## 11. Runtime-owned Property Schema

Cell Rendererは `propertySchema` を配列またはProvider関数として登録できます。Provider関数はProperty Editor表示時に再評価されます。

#054 Display Timelineは #048側にProperty一覧を複製せず、正式Runtimeの

```js
BoneDisplayTimeline.getPropertySchema()
```

を直接参照します。このため #054 のProperty名称・許容値・既定値は #054 Runtimeが正本です。

## 12. セルごとの要素に吸着（デフォルト）

`cellElement.snapToCell` は既定値 `true` です。

- `true`: セル側の余白を外し、Renderer hostと子UIをセル幅へ吸着
- `false`: 通常のTable Cell paddingを維持

列共通の `columns[].cellElement` と、セル単位の `row.$cells[columnKey]` の両方で指定できます。

#054 Display Timelineでは `snapToCell:true` かつ #054側 `snapToParent` が未指定の場合、#048から `snapToParent:true` を渡します。ただし高さ計算は#054 Runtimeへ委譲し、#048が固定高さで上書きしません。

## 13. #017 Text をセルへ設定

例:

```json
{
  "renderer": "017",
  "props": {
    "tag": "strong",
    "position": "center",
    "whitespace": "normal",
    "overflow": "wrap",
    "selectable": true
  }
}
```

#048で現在提供するText用Property Schemaは、`tag / position / whitespace / overflow / maxLines / selectable / prefix / suffix` です。Text側の`id`が未指定または空の場合、#048はTableインスタンス・行・列から一意なDOM idを自動付与し、複数行/複数Tableで空IDや重複IDを発生させません。

## 14. #020 Label をセルへ設定

例:

```json
{
  "renderer": "020",
  "props": {
    "position": "center",
    "hidden": false,
    "disabled": false,
    "title": "勤務状態"
  }
}
```

セル値はLabelの表示文字として渡されます。

## 15. #021 Shape をセルへ設定

例:

```json
{
  "renderer": "021",
  "props": {
    "type": "PROCESS",
    "theme": "dark",
    "displayRate": 72,
    "disabled": false
  }
}
```

Shape TYPEは#021の正式TYPEを指定します。#048はShape自体を再実装しません。

Table内に複数の#021 Shapeを配置すると、#021 Runtimeが持つ標準Port ID（`port-left-in` / `port-right-out` / `port-top-in` / `port-bottom-out`）がDOM上で重複するため、#048は**Tableインスタンス＋行＋列**を付けてセル内Port IDだけを一意化します。元IDは `data-bone-table-original-id` に保持し、#021 Runtime本体は変更しません。

## 16. #054 Display Timeline をセルへ設定

#054のPropertyは #054 Runtime-owned Property Schemaから取得します。

特に「時間ラベル表示」は `timeAxisMode` です。

| 値 | 意味 |
|---|---|
| `all` | 各Timelineに時間ラベルを表示 |
| `group-first` | 同一グループの先頭Timelineだけ表示 |
| `none` | 時間ラベルを表示しない |

`showLabels` は#054側の互換ゲートPropertyとして扱い、`timeAxisMode` と混同しません。

## 17. #054 group-first / groupIndex

Table内では各セルの#054は別インスタンスです。そのため `timeAxisMode="group-first"` を正しく成立させるため、#048は**同じ列の#054セル順**に `groupIndex=0,1,2...` を自動付与します。

- 先頭の#054セル: `groupIndex=0`
- 2つ目: `groupIndex=1`
- 3つ目: `groupIndex=2`

`row.$cells.<columnKey>.props.groupIndex` を明示した場合だけ、そのセルの明示値を優先します。

## 18. DOM配置後レイアウト / afterLayout

セル内UIによってはDOMへ配置される前の `clientWidth / clientHeight` が0で、初期座標を正しく計算できません。

Cell Rendererは `mount(ctx)` の戻り値に `afterLayout()` を持てます。#048は

1. Rendererをmount
2. Table全体をDOMへ配置
3. `afterLayout()` を実行

の順で処理します。

#054 Display Timelineはこの契約を使って正式 `render()` を再実行し、Shape Commentの初期座標を確定します。クリック操作をレイアウト確定の代用にはしません。

## 19. Resize / 再描画

#054セルは幅変更を監視します。列幅やTable幅が変化した場合にだけ再描画し、Shape Commentや時間軸を新しい実幅へ合わせます。

#048は#054の高さや内部レイアウトを固定値で上書きしません。

## 20. HTML Functional Class

通常利用Classは `bf-table` 1つです。

主なHTML属性:

| 属性 | Runtime Property |
|---|---|
| `data-table-caption` | `caption` |
| `data-table-columns` | `columns` |
| `data-table-rows` | `rows` |
| `data-table-header` | `showHeader` |
| `data-table-striped` | `striped` |
| `data-table-hover` | `hover` |
| `data-table-bordered` | `bordered` |
| `data-table-compact` | `compact` |
| `data-table-empty-text` | `emptyText` |
| `data-table-theme` | `theme` |
| `aria-label` | `ariaLabel` |

## 21. JavaScript / Public API

基本例:

```js
const host = document.getElementById('table');
BoneTable.create(host, {
  columns: [{ key: 'name', label: '氏名' }],
  rows: [{ name: '佐藤' }]
});
BoneTable.setRows(host, [{ name: '田中' }]);
```

主なPublic API:

`defaults / normalizeOptions / normalizeCellElement / create / render / update / setOptions / setRows / setColumns / refreshCells / getRows / getColumns / getOptions / getState / registerCellRenderer / unregisterCellRenderer / getCellRenderer / getCellRendererPropertySchema / getCellRendererPropertyDefaults / listCellRenderers / hasCellRenderer / destroy / isInstance / getCompletionState / complete / reopen`

## 22. 将来UIを追加する

UIが増えても#048本体へComponent別 `if` 分岐を追加しない方針です。新UIはCell Renderer Registryへ登録します。

```js
BoneTable.registerCellRenderer({
  id: "130",
  componentId: "130",
  className: "bf-new-ui",
  aliases: ["new-ui"],
  available: () => Boolean(window.BoneNewUI),
  propertySchema: () => BoneNewUI.getPropertySchema(),
  mount(ctx) {
    const element = BoneNewUI.create(ctx.value, ctx.props);
    ctx.host.appendChild(element);
    return {
      element,
      destroy: () => BoneNewUI.destroy(element)
    };
  }
});
```

新UIがRuntime-owned Property Schemaを公開する場合は、そのSchema Providerを直接登録できます。


### 空値でも構造を描くUI

新UIが値なしでも枠・目盛・罫線等を表示する場合は、Renderer定義に `renderEmpty:true` を追加します。

```js
BoneTable.registerCellRenderer({
  id: "029",
  componentId: "029",
  renderEmpty: ctx => ctx.props && ctx.props.voucherMode === true,
  mount(ctx) {
    // voucherMode時は空値でも数値を出さず構造だけ描画する
  }
});
```

`renderEmpty` は #048 が特定UI名をハードコードしないための共通契約です。

## 23. Security / Error

- Plain cell値は `textContent` で描画し、HTMLを実行しない
- 未登録Rendererは安全なTextへフォールバック
- Renderer alias衝突は拒否
- 不正Columns / Rows / Property SchemaはRuntime Errorとして拒否

代表Error:

- `BONE_TABLE_COLUMN_KEY_DUPLICATE`
- `BONE_TABLE_THEME_INVALID`
- `BONE_TABLE_CELL_RENDERER_REQUIRED`
- `BONE_TABLE_CELL_PROPS_INVALID`
- `BONE_TABLE_CELL_PROPERTY_SCHEMA_INVALID`
- `BONE_TABLE_CELL_PROPERTY_KEY_DUPLICATE`

## 24. Joint / Smoke / Validation / Completion

接続判定・線・異常marker・WAIT / FIFO / BLOCKEDは #002 Bone Jointへ委譲します。

Smoke / ValidationではRuntime identity、Functional Class、Cell Renderer、Property Schema、安全なfallback、#054 Runtime Schema、group-first、初期post-layout reflow等を確認します。

CompletionはSmoke / Validation ALL PASSとWAIT / BLOCKED目視確認が揃うまで実行できません。ユーザーlocalhost確認前にCompleted / Specification Frozenとは扱いません。


### #029 値なし伝票の配置確定
#029 NumberBoxを伝票表示で使用する場合、#048はTableがDOMへ配置された後のafterLayoutで親サイズを同期し、Voucher表示を確定します。値なしでは数値を生成せず、伝票の桁枠・罫線だけを表示します。

### OUT WAIT / BLOCKED 実操作

#017 Text基準の正式構成を使用します。見出しは `OUT WAIT / BLOCKED - #002 Joint v1.1.36 Integration`、操作は `▶ WAIT / FIFO 実行` / `⛔ BLOCKED 実行` / `↻ Reset` の3つだけです。独立したREADY/FIFOボタン、Target READY/BUSY selector、Payload selectorは追加しません。WAIT / FIFO実行ではTarget BUSY / WAITINGでA・BをQueueへ保持し、目視可能な待機後にTarget READYへ復帰して #002 Delivery Channel がA → BをFIFO順に自動配送します。目視確認checkboxはWAIT/BLOCKED実行やSmoke / Validationで勝手に解除せず、`↻ Reset`だけが明示的に解除します。Smoke / ValidationのOverallと目視確認は分離し、目視確認はCompletion gateで要求します。


## 25. Theme継承

Table Property の `theme` は `light / dark / neon` の3値です。Table本体だけでなく、Cell Rendererへ `context.theme` として継承されます。#021 Shape / #029 NumberBox / #054 Display Timelineは親Table Themeを正式Themeとして使用します。#017 Text / #020 Label / #018 IconもTable Themeの表示色へ追従します。#018 IconはCell Renderer Registryの標準Renderer `018` / `bf-icon` として利用できます。


**Runtime Schema 可視化:** テストページの「正式Property定義（Runtime Schema）」は `BoneTable.getPropertySchema()` の実値を直接描画し、HTML側へ定義を複製しません。

## テーブル表示パターン（tableStyle）
`standard` / `striped` / `bordered` / `borderless` / `hover` / `compact` / `striped-hover` / `striped-bordered` / `compact-bordered` を正式Presetとして使用します。個別の Stripe / Hover / Border / Compact 指定はPreset結果を上書きします。


## Cell Renderer自動登録 / 依存Version追従

#048はCell UIのRuntime Versionを完全一致で固定しません。登録済みRendererの`componentId`と必要APIを確認し、現在読み込まれているRuntime Versionを表示します。#017など互換更新時に#048の期待Versionを書き換える運用は行いません。

将来UIは、Runtimeで`getTableCellRendererDefinition()`（または`tableCellRendererDefinition`）を公開するか、`BoneTable.registerCellRendererProvider()`へProviderを登録します。#048は`discoverCellRenderers()`でProviderを自動検出し、Cell Renderer一覧と「使用コンポーネント」へ反映します。登録/解除時は`bone-table-cell-renderer-registry-change`で画面も自動更新します。

Providerがこの契約を持たない任意UIを、#048が推測でCell Renderer化することはありません。描画方法はUI自身がProviderとして公開します。これにより、新UI追加時に#048本体へUI番号やRuntime Versionを追記する必要をなくします。

## #029 伝票セルの縦罫線（v1.0.31）

`cellElement: {renderer:"029", snapToCell:true}` は、#048側がセルの高さを確保し、伝票の縦線を表の行端まで伸ばします。#029のRuntimeは変更しません。`snapToCell:false`には適用されません。


<!-- #048 package 1.0.32; Runtime 1.0.16; #017 Text base preserved. -->
