Splitter
リサイズ可能なパネル分割レイアウトです。fandhe-frontend-headless-ui の splitter mod は Root / Panel / ResizeTrigger / ResizeTriggerIndicator の 4 anatomy パーツと、role="separator" + aria-valuemin/aria-valuemax/aria-valuenow/aria-orientation/aria-controls を提供する決定的なパネルサイズ状態機械です。Themes 版と異なりドラッグ操作の視覚表現を持たず、構造・ARIA 属性・数値正規化ロジックのみを担います。
スタイル済みの表示例は Splitter を参照してください。
キーボード操作
| キー | 対象 | 効果 |
|---|---|---|
| Arrow(軸別、Horizontal: Left/Right、Vertical: Up/Down) | ResizeTrigger | SplitterAction::Increment/Decrement(ステップ 1%)として状態遷移し、aria-valuenow が追随します。DOM keydown 配線はイシュー #1074 で fandhe-frontend-wasm-full の splitter モジュールが実装済みです。 |
| Home / End | ResizeTrigger | SplitterAction::SetToMin/SetToMax(先行パネルを min/max へ設定)として状態遷移します。実装済みです。 |
| Shift+Arrow | ResizeTrigger | SplitterAction::IncrementLarge/DecrementLarge(ステップ 10%、zag.js keyboardResizeBy 既定値相当)として状態機械のみ提供します。fandhe-frontend-wasm-full の Shift 修飾キー配線は現状存在せず未実装です(イシュー #1664 時点で確認済み、別 Issue の起票対象)。 |
| Enter | ResizeTrigger | collapse/expand トグル相当の対応はありません(意図的非採用)。 |
| F6 | Root | トリガー間フォーカス循環の対応はありません(意図的非採用、DOM フォーカス管理は fandhe-frontend-wasm-full の責務)。 |
参考サイトとの差分
イシュー #1664 で ark-ui docs・zag.js(packages/machines/splitter/src/splitter.connect.ts)・WAI-ARIA APG Window Splitter パターンと突合しました(Radix Primitives に Splitter 相当は存在しません)。
- panel の
data-index/data-id欠落を是正: ark-ui docs のdata-*表に従い、panelへパネル序数index: usize(data-index)とidの写し(data-id)を追加しました(破壊的変更、panelの引数順変更)。 - resize-trigger の
data-id欠落・aria-controlsが先行パネルのみだったのを是正:aria-controlsを zag.js の実出力(隣接 2 パネルの id を空白区切りで列挙)に合わせて拡張し、data-idを"<leading>:<trailing>"形式で追加しました。resize_triggerのcontrols: &str引数をleading_id: &str, trailing_id: &strへ置換しています(破壊的変更)。 - Shift+Arrow(
keyboardResizeBy既定 ×10)の状態機械を追加:SplitterAction::IncrementLarge/DecrementLarge(dispatch 名"increment_large"/"decrement_large")を追加しました。DOM 配線は上記キーボード操作表のとおり未実装です。 - 予約キーなりすまし除去を追加: 呼び出し側
attrsがrole/aria-*/tabindex/data-*/idを偽装・重複出力できないようdrop_reservedを導入しました(slider/toolbar等と同型のパターン)。aria-label/aria-labelledbyは zag.js が固定付与しない拡張点のため予約対象に含めません。
一方で以下は意図的に参考サイトと合わせていません。
data-focus/data-dragging(root/panel/resize-trigger): focus・pointer ドラッグの DOM ローカル状態です。headless 層は pointer 配線を持たないため実データがなく、docs/policy/intentional-non-adoption.md§3.25 規則 2(装飾・ポインタ計測は headless 層へ持ち込まない)に従い非採用です。- resize-trigger-indicator への
data-orientation追加: ark-ui docs の Anatomy にこの行が無いため追加しません。 aria-orientationの向き: WAI-ARIA APG Window Splitter パターンの記述(左右分割のセパレータは vertical)に従いパネルレイアウトと逆向きを維持します。zag.js の実出力(非反転)とは非同値のままです。- disabled 時の
tabindex="-1"+aria-disabled: zag.js は disabled 時にこれらを出力しませんが、本実装はリポジトリ横断規約(disabled でも属性で明示する)の superset として維持します。 - Enter(collapse/expand)・F6(フォーカス循環): 上記キーボード操作表のとおり非採用です。
dir: 本リポジトリ横断で未採用です。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
Themes 版を使わず本部品を直接使う場合、[data-scope="splitter"][data-part="..."] セレクタと data-orientation/data-disabled で見た目を組み立てます。resize-trigger にはアクセシブルネームが自動付与されないため、呼び出し側から aria-label(attrs 経由)を渡してください。
[data-scope="splitter"][data-part="root"] {
display: flex;
}
[data-scope="splitter"][data-part="root"][data-orientation="vertical"] {
flex-direction: column;
}
[data-scope="splitter"][data-part="panel"] {
flex: 1 1 0;
overflow: hidden;
}
[data-scope="splitter"][data-part="resize-trigger"] {
flex: 0 0 4px;
cursor: col-resize;
}
[data-scope="splitter"][data-part="root"][data-orientation="vertical"] [data-part="resize-trigger"] {
cursor: row-resize;
}
[data-scope="splitter"] [data-disabled] {
opacity: 0.5;
}
[data-scope="splitter"] :focus-visible {
outline: 2px solid #2563eb;
outline-offset: 2px;
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Features
- Root / Panel / ResizeTrigger / ResizeTriggerIndicator の 4 anatomy パーツと、パネルサイズ状態機械 Splitter を提供する(splitter.rs:1-11)。
- resize_trigger は role="separator" + aria-valuemin/aria-valuemax/aria-valuenow + aria-orientation(パネルレイアウトと逆向き)+ aria-controls(隣接 2 パネルの id)+ data-id("<leading>:<trailing>")を常に出力する。
- panel は data-index(パネル序数)・data-id(id の写し)を出力する(イシュー #1664 で ark-ui docs の data-* 表と突合し追加)。
- disabled=true のとき tabindex="-1" + aria-disabled、false のとき tabindex="0" を出力する。
- SplitterAction::IncrementLarge/DecrementLarge(zag.js keyboardResizeBy 既定値 ×10 相当)を状態機械として提供する(イシュー #1664、DOM 配線は未実装)。
- 呼び出し側 attrs からの role/aria-*/tabindex/data-*/id のなりすまし・重複出力を drop_reserved で除去する(イシュー #1664)。
- Splitter::new はパネル数 2 未満・非有限値・制約矛盾等の実現不能構成を既定(2 パネル 50/50)へ fail-closed にフォールバックする(splitter.rs:33-45,194-208)。
Anatomy
root
panel
resize-trigger
resize-trigger-indicatorAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
root: orientation, disabled | Orientation, bool | — | パネルレイアウトの向きと無効状態。 |
panel: id, index | &str, usize | — | resize_trigger の aria-controls 先となる id(必須)と data-index として出力するパネル序数(イシュー #1664 で index を追加、破壊的変更)。 |
resize_trigger: min, max, now, leading_id, trailing_id, disabled | &str, &str, &str, &str, &str, bool | — | aria-valuemin/aria-valuemax/aria-valuenow と、隣接 2 パネルの id(aria-controls/data-id へ出力)・tabindex 切替の元(イシュー #1664 で controls 単一引数を leading_id/trailing_id へ置換、破壊的変更)。 |
Splitter::new: panels, orientation | &[PanelSpec], Orientation | — | パネル構成(size/min/max)と向き。fail-closed に正規化する(splitter.rs:352)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
panel | data-id | splitter-panel-a, splitter-panel-b |
panel | data-index | 0, 1 |
panel | data-orientation | horizontal |
resize-trigger | data-id | splitter-panel-a:splitter-panel-b |
resize-trigger | data-orientation | horizontal |
root | data-orientation | horizontal |
Examples
Vertical 3-panel splitter
縦方向レイアウトで 3 パネル・2 セパレータを組んだ例です(Demo は水平 2 パネル)。
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Tab | resize_trigger は disabled=false のとき tabindex="0" で通常の Tab 順序に入り、disabled=true のとき tabindex="-1" で除外される。 |
| Arrow(軸別) | SplitterAction::Increment/Decrement(ステップ 1%)として状態遷移する。イシュー #1074 で fandhe-frontend-wasm-full の splitter モジュールが DOM keydown 配線済み。 |
| Home / End | SplitterAction::SetToMin/SetToMax として状態遷移する。DOM 配線済み(イシュー #1074)。 |
| Shift+Arrow | SplitterAction::IncrementLarge/DecrementLarge(ステップ 10%)として状態機械のみ提供する。fandhe-frontend-wasm-full の DOM 配線は未実装(イシュー #1664 時点、別 Issue 起票対象)。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| role="separator" | resize_trigger に固定出力する。 |
| aria-valuemin / aria-valuemax / aria-valuenow | 先行パネルのサイズ%(有限性検証・クランプ済み)を出力する。 |
| aria-orientation | セパレータ自体の向き(パネルレイアウトと逆向き、WAI-ARIA APG 準拠。zag.js の非反転出力とは非同値、イシュー #1664 参照突合)。 |
| aria-controls | 隣接 2 パネルの id("<leading> <trailing>"、イシュー #1664 で先行パネルのみから拡張)。 |
| aria-disabled="true" | disabled=true のときのみ出力する。 |