Message Scroller
fandhe-frontend-pre-styled-ui の message_scroller mod が提供するスタイル済み Message Scroller 部品です。AI チャット UI の会話ログを収めるスクロールコンテナで、Root / Viewport / Content / Anchor / Jump To Latest / Load More の 6 パーツ構成です。
viewport は overflow-y: auto によるネイティブスクロール(JS 不要)で、既定で高さ 24rem(--fandhe-message-scroller-height で上書き可能)を確保します。両端は mask-image による既定フェードを持ち、root が最下部に張り付いている(data-stuck="bottom")ときは末尾フェードを自動的に解除して最新メッセージを霞ませません。
root の data-stuck(bottom / free)・data-has-new(存在属性)、jump_to_latest の data-visible / hidden(2 択)、load_more の data-loading / data-disabled(存在属性)は headless 層が出力する data-* を CSS セレクタとして参照するだけで、class ベースの軸は持ちません。data-has-new が付いた root の jump-to-latest はアクセント色へ強調されます。load_more は loading が true のとき装飾的な spinner を children 先頭へ埋め込みます。
最下部追従・新着検知・履歴読み込み時の位置維持といったスクロール位置の計測・実行時更新はこの部品では実装しません(fandhe-frontend-wasm-full 側の配線が別イシューで担当します)。
関連 API: fandhe-frontend-pre-styled-ui API / fandhe-frontend-headless-ui API
Demo
会話ログを収めるスクロールコンテナ。data-stuck(bottom/free)・data-has-new・jump-to-latest の data-visible・load-more の data-loading/data-disabled は headless の data-* を参照するのみで class 軸は持ちません。1 例目は最下部に張り付いている既定状態(末尾フェード解除)、2 例目は手動スクロールで離脱し新着がある状態(jump-to-latest 強調・load-more 読み込み中)です。
Features
- root/viewport/content/anchor/jump-to-latest/load-more の 6 パーツで会話ログのスクロールコンテナを構造化する
- MessageScrollerStuck(Bottom/Free)で data-stuck を切り替え、最下部に張り付いているときは viewport の末尾フェードを解除する(root[data-stuck="bottom"] > viewport の raw CSS 追記、message_scroller.rs モジュール doc「端フェードの採否」節参照)
- has_new: bool で data-has-new 存在属性を切り替え、root[data-has-new] > jump-to-latest をアクセント色で強調する
- jump_to_latest の visible: bool で data-visible / hidden の 2 択を切り替える(自動連動しない。hidden 時は UA 既定を display: none の明示規則で上書きする)
- load_more の loading: bool で spinner_decorative を children 先頭へ埋め込み、disabled: bool でネイティブ disabled + data-disabled を切り替える(自動連動しない)
- viewport は既定で mask-image による両端フェードを持つ(--fandhe-message-scroller-fade-start/-end を 0px へ上書きすれば片端無効化できる)
- 最下部追従・新着検知・履歴読み込み時の位置維持等のスクロール計測はこの部品では実装しない(docs/policy/intentional-non-adoption.md §3.25 規則 1、message_scroller.rs モジュール doc「責務境界」節。実行時配線は fandhe-frontend-wasm-full、イシュー #2122)
Anatomy
root
viewport
load-more
content
anchor
jump-to-latestAPI Reference
Arguments
| Name | Type | Default | Description |
|---|---|---|---|
stuck | MessageScrollerStuck | Bottom | 最下部追従の状態(Bottom/Free)。data-stuck として出力され、Bottom のとき viewport の末尾フェードを解除する。 |
has_new | bool | false | true の場合 data-has-new 存在属性を付与し、jump-to-latest をアクセント色で強調する(新着メッセージの表示のみ)。 |
viewport.label | &str | "" | 非空のとき viewport へ role="region" + aria-label を出力する(空文字なら付与しない)。 |
jump_to_latest.visible | bool | false | true で data-visible 存在属性、false で hidden 存在属性を出力する(2 択、自動連動しない)。 |
load_more.loading | bool | false | true の場合 data-loading 存在属性を付与し、spinner_decorative を children 先頭へ埋め込む。 |
load_more.disabled | bool | false | true の場合ネイティブ disabled + data-disabled 存在属性を付与する(loading とは自動連動しない)。 |
Data Attributes
| Part | Attribute | Observed Values |
|---|---|---|
jump-to-latest | data-visible | (値なし) |
load-more | data-disabled | (値なし) |
load-more | data-loading | (値なし) |
root | data-has-new | (値なし) |
root | data-stuck | bottom, free |
CSS Variables
| Variable | Default |
|---|---|
--fandhe-message-scroller-fade-end | 1.5rem |
--fandhe-message-scroller-fade-start | 1.5rem |
--fandhe-message-scroller-height | 24rem |
--fandhe-message-scroller-thumb-bg | var(--fandhe-color-fg-subtle, var(--fandhe-color-border-emphasized, var(--fandhe-color-border))) |
Examples
Default (stuck at bottom)
最下部に張り付いている既定状態です。jump-to-latest は hidden、末尾フェードは解除されています。
Scrolled up with new messages
手動スクロールで離脱し新着がある状態です。jump-to-latest が強調表示され、load-more は読み込み中です。
Accessibility
Keyboard Interactions
| Key | Description |
|---|---|
| Arrow keys / Page Up / Page Down | viewport は tabindex="0" を固定付与したネイティブスクロール領域であり、フォーカス時にブラウザ標準のスクロールキー操作を受け付ける(JS 不要)。 |
WAI-ARIA
| Attribute | Description |
|---|---|
| tabindex="0" / role="region" + aria-label (viewport) | viewport は tabindex="0" を固定付与し、label が非空のときのみ role="region" + aria-label を出力する(名前のない region を作らない)。 |
| aria-hidden="true" (anchor) | anchor は最下部センチネルであり aria-hidden="true" を固定付与する(fandhe-frontend-wasm-full がスクロール計測の観測対象にする、イシュー #2122)。 |
| type="button" (jump-to-latest / load-more) | 両ボタンとも type="button" を固定付与する(フォーム内でも誤送信しない)。 |
| (付与しない) aria-live / aria-busy / aria-posinset / aria-setsize | 通知・応答待ちの読み上げ、総数の伝達はいずれもアプリ固有の判断のため付与しない(headless message_scroller.rs モジュール doc「aria-live/aria-busy を付けない理由」「aria-posinset/aria-setsize を持たない理由」節参照)。 |