Floating Panel
ドラッグ移動・リサイズ可能な浮遊パネルです。fandhe-frontend-headless-ui の floating_panel mod は Root / Trigger / Positioner / Content / Header / Title / Control / StageTrigger / CloseTrigger / Body の 10 anatomy パーツと、開閉・Stage(Default/Minimized/Maximized)・座標を持つ状態機械を提供します。content は role="dialog" を固定付与しますが、非モーダル overlay のため aria-modal は出力しません(ユーザーは他の要素を操作し続けられます)。header/control は現在の Stage を data-stage へ反映し、body は Stage::Minimized のとき hidden 存在属性を付与します。
キーボード操作(現時点の配線状況)
fandhe-frontend-wasm-full の headless 部品 → dispatch 対応表(headless.rs)に floating-panel scope の行が無く、trigger / close-trigger / stage-trigger の click・Escape キーでの閉鎖・矢印キーでの移動はいずれも実際には配線されていません(本文書時点の事実)。headless 層は型付きアクション("open"/"close"/"toggle"/"minimize"/ "maximize"/"restore"/"set_position")を提供済みであり、配線自体は fandhe-frontend-wasm-full 側の将来スコープです。
参考サイトとの差分
ark-ui(zag floating-panel.connect.ts/floating-panel.anatomy.ts。chakra-ui は ark-ui のラッパのため実質同一)と突合し、header/control への data-stage 付与、body への Stage::Minimized 時 hidden 付与を追加しました。一方、以下は意図的に合わせていません。
dragTrigger/resizeTrigger(data-axis付き)anatomy パーツ: ポインタイベント配線がfandhe-frontend-wasm-fullに無い状態で anatomy だけ追加すると、利用者へ「操作できる」という誤った安心を与えるため不採用です(docs/policy/intentional-non-adoption.md§3.25 規則 2)。trigger/contentのdata-dragging、contentのdata-topmost/data-behind、CSS 変数--width/--height/--z-index: いずれもドラッグ・重なり順という実行時計測の関心のため headless 層へ持ち込みません。contentのtabIndex: 0: zag は矢印キー移動の配線とセットでフォーカス可能にしていますが、本実装は矢印移動が未配線のため、tabindex="0"だけを先に付けると機能しないタブストップになるため不採用です。stage-triggerの現在 stage に応じたhidden: 現在 stage を引数に要する破壊的変更がさらに増えるため見送りました。代わりにcontrolがdata-stageを持つため、control[data-stage="minimized"] [data-part="stage-trigger"][data-stage="minimized"]のような子孫セレクタで同等の表示切替を実装できます。header/control/bodyの真偽 3 属性(data-minimized/data-maximized/data-staged): 本実装は最初からdata-stage列挙 1 属性で同じ情報を表しており、二重化しません。
スタイル済みの表示例は Floating Panel を参照してください。
関連 API: fandhe-frontend-headless-ui API
自前 CSS の最小例
Themes 版を使わず本部品を直接使う場合、[data-scope="floating-panel"][data-part="..."] セレクタでスタイルを当てます。以下は positioner(座標反映)・content(枠・余白)・body(minimized 時の折り畳み)・control 経由の stage-trigger 表示切替の最小例です。author スタイルの display が UA の [hidden] { display: none } を上書きして隠れるべき状態が見えてしまわないよう、[hidden] ガードを必ず含めます。
[data-scope="floating-panel"][data-part="positioner"] {
position: fixed;
top: var(--fandhe-y);
left: var(--fandhe-x);
}
[data-scope="floating-panel"][data-part="positioner"][hidden] {
display: none;
}
[data-scope="floating-panel"][data-part="content"] {
border: 1px solid #d0d0d0;
background: #fff;
border-radius: 8px;
}
[data-scope="floating-panel"][data-part="body"] {
padding: 1rem;
}
[data-scope="floating-panel"][data-part="body"][hidden] {
display: none;
}
/* control の data-stage に応じて、現在の stage と同じ遷移先を示す
stage-trigger を隠す(例: minimized 中は「最小化」ボタン自体を隠す)。*/
[data-scope="floating-panel"][data-part="control"][data-stage="minimized"]
[data-part="stage-trigger"][data-stage="minimized"] {
display: none;
}Demo
枠線・余白は docs サイト側のデモ枠であり、fandhe-frontend-headless-ui 自体はスタイルを持ちません。
Notes
Features
- Root / Trigger / Positioner / Content / Header / Title / Control / StageTrigger / CloseTrigger / Body の 10 anatomy パーツと、開閉・stage(Default/Minimized/Maximized)・座標を持つ状態機械 FloatingPanel を提供する。
- stage(Default/Minimized/Maximized)は crate::state::Disclosure/SingleSelect に写像できないため、Steps/Progress と同じ判断で独自 enum として実装する。
- content は role="dialog" を固定付与するが、非モーダル overlay のため aria-modal は出力しない(ユーザーは他の要素を操作し続けられる)。
- 座標(--fandhe-x/--fandhe-y)は crate::positioning の CSS 変数語彙を再利用するが、実際のドラッグ・リサイズ操作・trigger/close-trigger/stage-trigger の click・Escape キー閉鎖・矢印キー移動はいずれも fandhe-frontend-wasm-full に未配線(イシュー #1640 時点の事実)。headless 層は型付きアクション(open/close/toggle/minimize/maximize/restore/set_position)のみを提供する。
Anatomy
trigger
root
positioner
content
header
title
control
stage-trigger
close-trigger
bodyAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
root: state | OpenState | Closed | パネル全体の開閉状態(data-state へ反映)。 |
root: stage | Stage | Default | パネルの表示段階(Default/Minimized/Maximized、data-stage へ反映)。 |
trigger: state | OpenState | Closed | aria-expanded/data-state へ反映される開閉状態。 |
trigger: disabled | bool | — | ネイティブ disabled 存在属性のみで表現する disabled 状態。 |
trigger: controls | Option<&str> | — | Some のとき aria-controls で content と関連付ける。 |
positioner: state | OpenState | Closed | closed のとき hidden 存在属性を付与する配置ラッパーの開閉状態。 |
positioner: stage | Stage | Default | data-stage へ反映される表示段階。 |
content: state | OpenState | Closed | 開閉状態(closed のとき hidden 存在属性を付与)。 |
content: stage | Stage | Default | data-stage へ反映される表示段階。 |
content: id | Option<&str> | — | trigger の controls と対で aria-controls 関連付けを成立させる。 |
content: labelledby | Option<&str> | — | Some のとき title の id と対で aria-labelledby 関連付けを成立させる。 |
title: id | Option<&str> | — | content の labelledby と対にする。 |
header: stage | Stage | Default | data-stage へ反映される表示段階(イシュー #1640。zag getHeaderProps との突合是正)。 |
control: stage | Stage | Default | data-stage へ反映される表示段階(イシュー #1640。zag getControlProps との突合是正。styled 層は data-stage 経由で stage-trigger の表示切替を実装できる)。 |
stage_trigger: target | Stage | — | 遷移先の表示段階(data-stage へ反映。実際の dispatch 配線は呼び出し側/wasm 層の責務)。 |
body: stage | Stage | Default | data-stage へ反映される表示段階。Stage::Minimized のとき hidden 存在属性も付与する(イシュー #1640。zag getBodyProps の hidden: isMinimized との突合是正)。styled 層の data-stage="minimized" 折り畳みは headless 層の hidden と二重化するが無害(多層防御)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
body | data-stage | default |
content | data-stage | default |
content | data-state | open |
control | data-stage | default |
header | data-stage | default |
positioner | data-stage | default |
positioner | data-state | open |
root | data-stage | default |
root | data-state | open |
stage-trigger | data-stage | minimized |
trigger | data-state | open |
Examples
Maximized stage
Stage::Maximized(既定 Default とは異なる表示段階)で開いた FloatingPanel の例です。
Editor
Minimized stage
Stage::Minimized で開いた FloatingPanel の例です。body へ hidden 存在属性が付与され本文が隠れます(header・control は表示されたままです)。
Notes
Accessibility
WAI-ARIA
| Attribute | Description |
|---|---|
| aria-haspopup="dialog" | trigger に固定付与。 |
| aria-expanded | trigger に付与。開閉状態を反映する。 |
| aria-controls | trigger に付与。controls が Some のとき content と関連付ける。 |
| role="dialog" | content に固定付与。 |
| aria-labelledby | content に付与。labelledby が Some のときのみ出力される。 |
| aria-modal(非付与) | content は role="dialog" を固定付与するが aria-modal は出力しない(非モーダル overlay。ユーザーは他の要素を操作し続けられ、支援技術へ誤ったモーダル通知を送らない)。 |
| hidden | positioner/content は closed のとき、body は Stage::Minimized のとき hidden 存在属性を付与する(イシュー #1640。body は zag getBodyProps との突合是正)。 |