Skip to content
fandhe-frontendcore v0.4.3
GitHub

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)ResizeTriggerSplitterAction::Increment/Decrement(ステップ 1%)として状態遷移し、aria-valuenow が追随します。DOM keydown 配線はイシュー #1074 で fandhe-frontend-wasm-full の splitter モジュールが実装済みです。
Home / EndResizeTriggerSplitterAction::SetToMin/SetToMax(先行パネルを min/max へ設定)として状態遷移します。実装済みです。
Shift+ArrowResizeTriggerSplitterAction::IncrementLarge/DecrementLarge(ステップ 10%、zag.js keyboardResizeBy 既定値相当)として状態機械のみ提供します。fandhe-frontend-wasm-full の Shift 修飾キー配線は現状存在せず未実装です(イシュー #1664 時点で確認済み、別 Issue の起票対象)。
EnterResizeTriggercollapse/expand トグル相当の対応はありません(意図的非採用)。
F6Rootトリガー間フォーカス循環の対応はありません(意図的非採用、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 経由)を渡してください。

CSS
[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 自体はスタイルを持ちません。

Panel A
Panel B

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-indicator

API Reference

Arguments

NameTypeDefaultDescription
root: orientation, disabledOrientation, 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

PartAttributeObserved Values
paneldata-idsplitter-panel-a, splitter-panel-b
paneldata-index0, 1
paneldata-orientationhorizontal
resize-triggerdata-idsplitter-panel-a:splitter-panel-b
resize-triggerdata-orientationhorizontal
rootdata-orientationhorizontal

Examples

Vertical 3-panel splitter

縦方向レイアウトで 3 パネル・2 セパレータを組んだ例です(Demo は水平 2 パネル)。

Top
Middle
Bottom

Accessibility

Keyboard Interactions

KeyDescription
Tabresize_trigger は disabled=false のとき tabindex="0" で通常の Tab 順序に入り、disabled=true のとき tabindex="-1" で除外される。
Arrow(軸別)SplitterAction::Increment/Decrement(ステップ 1%)として状態遷移する。イシュー #1074 で fandhe-frontend-wasm-full の splitter モジュールが DOM keydown 配線済み。
Home / EndSplitterAction::SetToMin/SetToMax として状態遷移する。DOM 配線済み(イシュー #1074)。
Shift+ArrowSplitterAction::IncrementLarge/DecrementLarge(ステップ 10%)として状態機械のみ提供する。fandhe-frontend-wasm-full の DOM 配線は未実装(イシュー #1664 時点、別 Issue 起票対象)。

WAI-ARIA

AttributeDescription
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 のときのみ出力する。