@aiquants/virtualscroll 3.9.1 → 3.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +114 -0
- package/README.md +95 -29
- package/dist/ScrollBar.d.cts +41 -35
- package/dist/ScrollBar.d.ts +41 -35
- package/dist/ScrollBar.d.ts.map +1 -1
- package/dist/ScrollPane.d.cts +12 -14
- package/dist/ScrollPane.d.ts +12 -14
- package/dist/ScrollPane.d.ts.map +1 -1
- package/dist/VirtualGrid.d.cts +6 -6
- package/dist/VirtualGrid.d.ts +6 -6
- package/dist/VirtualGrid.d.ts.map +1 -1
- package/dist/VirtualScroll.d.cts +72 -23
- package/dist/VirtualScroll.d.ts +72 -23
- package/dist/VirtualScroll.d.ts.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +2048 -2025
- package/dist/labels.d.cts +38 -7
- package/dist/labels.d.ts +38 -7
- package/dist/labels.d.ts.map +1 -1
- package/dist/styles/virtualscroll.css +1 -1
- package/dist/styles/virtualscroll.standalone.css +1 -1
- package/dist/utils.d.cts +14 -0
- package/dist/utils.d.ts +14 -0
- package/dist/utils.d.ts.map +1 -1
- package/package.json +5 -2
- package/src/ScrollBar.tsx +91 -49
- package/src/ScrollPane.tsx +12 -14
- package/src/VirtualGrid.tsx +6 -6
- package/src/VirtualScroll.tsx +235 -116
- package/src/labels.ts +58 -7
- package/src/styles/virtualscroll.css +51 -3
- package/src/utils.ts +15 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,120 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@aiquants/virtualscroll` are documented here.
|
|
4
4
|
|
|
5
|
+
## 3.10.0 (2026-10-05)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **スクロールバーとつまみの名前 (WCAG 4.1.2)**: どのバーも名前付きの `role="scrollbar"` で、名前付きの `role="slider"` の
|
|
10
|
+
つまみを持つ (従来はどちらも名前が無く、支援技術は名前の無いスクロールバーとスライダーを示していた)。名前はラベルの
|
|
11
|
+
カタログの 4 キー: バーの `verticalScrollBar` / `horizontalScrollBar` (支援技術がロールを付け足すので、2 本のバーを
|
|
12
|
+
区別する向きだけ。en `Vertical` / `Horizontal`、ja `縦方向` / `横方向`) と、つまみの `verticalScrollThumb` /
|
|
13
|
+
`horizontalScrollThumb` (値が表すもの。en `Vertical scroll position` / `Horizontal scroll position`、ja `縦スクロール位置` /
|
|
14
|
+
`横スクロール位置`)。ほかのキーと同じく `labels` で 1 キーずつ上書きでき、空白の値は描画時に `RangeError`。
|
|
15
|
+
`VIRTUAL_SCROLL_LABEL_KEYS` はカタログ順の 11 キー (`scrollRight` の後に 4 つ) になり、型 `VirtualScrollLabels` は必須の
|
|
16
|
+
キーを 4 つ増やす。カタログに `labels` を重ねる代わりに `VirtualScrollLabels` を丸ごと手で組み立てるホストはこの 4 つを
|
|
17
|
+
足し、`VIRTUAL_SCROLL_LABEL_KEYS` を自分のキー表へ連結して件数を固定するホストは件数が 4 増える。
|
|
18
|
+
- **強制配色の描き方 (README「Forced colours」)**: `forced-colors: active` ではブラウザがシステム色でない地色をどれも `Canvas`
|
|
19
|
+
に置き換えるので、地色だけで描く部品にシステム色の描き方を与えた。バーとトラックは内側の辺の 1px の `GrayText` の輪郭、
|
|
20
|
+
つまみは `CanvasText` で塗り、ホバー中とドラッグ中は `Highlight`、つまみのドラッグを切ったとき (`enableThumbDrag: false`) は
|
|
21
|
+
`GrayText`。つまみは強制の置き換えから外す (`forced-color-adjust: none`) ので、地色が `Canvas` に戻ることはない。
|
|
22
|
+
`tapScrollCircleSampleVisual` の光と棒は `CanvasText`。
|
|
23
|
+
- **網羅率のつめ車**: `coverage-floors.json` (ファイルごとの分岐と関数の網羅率の下限) を Vitest がファイルごとの閾値として
|
|
24
|
+
読み (`thresholds: { perFile: true, ... }`。対象は `src` のソースすべてで、どの spec も読み込まないファイルは 0 %)、
|
|
25
|
+
`scripts/ratchet-coverage.mjs` が項目の無いファイルと古い項目を落とし、下限を上げるただ 1 つの手段になる。スクリプトは
|
|
26
|
+
`test:coverage` (全テストの網羅率つきの実行と検証)・`check:coverage`・`coverage:ratchet` (`--write`。新しいファイルは
|
|
27
|
+
100 % のときだけ入る)・`coverage:adopt` (`--adopt`。つめ車を取り入れるときに 1 度だけ、項目の無いファイルを測った
|
|
28
|
+
網羅率で記録する)。`src/devicePixelGrid.ts` は分岐も関数も 100 で入る。
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- **`enableArrowButtonTabStops: false` は、ホストがキーボードのスクロールを自分で持つことのただ 1 つの合図**: 従来の `false`
|
|
33
|
+
は矢印 2 個を `tabIndex={-1}` にするだけで、名前の無いバーとつまみは支援技術に残り、バーの押下はフォーカスを動かし
|
|
34
|
+
(Chromium は無効の矢印の押下でも、最も近いフォーカス可能な祖先 = `tabIndex={-1}` のバーへフォーカスを移す)、端へ戻る
|
|
35
|
+
ピルは Tab の止まり先のままだった。いまの `false` でバーはネイティブのスクロールバーと同じポインタ専用の部品になる。
|
|
36
|
+
バーは `aria-hidden="true"` を持ち、矢印は `tabIndex={-1}`、バーとつまみの器は `tabindex` を持たない。バーのどこを
|
|
37
|
+
どのボタンで押しても押下の既定動作を取り消すので、フォーカスは部品へも、ホストが置いた場所の外へも動かない (押下
|
|
38
|
+
そのもの、ポインタのイベントと click は部品へ届く)。ポインタのスクロール (矢印と長押しの連続・トラック・つまみ・
|
|
39
|
+
タップのサークル) は変わらない。`VirtualScroll` の端へ戻るピル (`enableScrollToTopBottomButtons`) も同じ合図に従い、
|
|
40
|
+
覆いは見えている間も `aria-hidden="true"`、ピルは Tab の止まり先にならず、押下はフォーカスを動かさず、click は端へ
|
|
41
|
+
スクロールする。既定 (`true`) は名前が付いたことのほかは変わらない。オプションの名前と意味は `ScrollBar` /
|
|
42
|
+
`ScrollPane` の props と `VirtualScroll` / `VirtualGrid` の `scrollBarOptions` で同じ (グリッドは両方のバーに適用)。
|
|
43
|
+
README の節は「Scrollbar accessibility and the Tab order」に改めた。
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- **窓をずらす 1 段のレイアウトが毎回文書の根から始まっていた**: 行ラッパーの包含ブロックはペインの中身で、これは flex の
|
|
48
|
+
子なので配置の境界 (relayout boundary) になれず、行を足し引きする 1 段のレイアウトは文書の根から始まっていた (日報の
|
|
49
|
+
アプリで 4 倍の CPU のとき、キー 1 回のレイアウトの CPU の中央値は一覧 3.99ms・詳細一覧 8.12ms で、すべてが文書の根から)。
|
|
50
|
+
ラッパーを `.aqvs-items-boundary` (ペインの中身のパディングの上・左・右の辺に付く高さ 0 の絶対配置の箱で、
|
|
51
|
+
`contain: size layout style`) の中に置き、その箱を包含ブロックで配置の境界にした。Chromium 148 で、2,231 個の
|
|
52
|
+
レイアウトのオブジェクトを持つページの 1 行ずつの窓のずれ 60 回は、文書の根からのレイアウト 60 回から、218 個の部分の
|
|
53
|
+
レイアウト 60 回になった。比 1・1.25・1.5・1.75・2・3、明暗、4 つのオフセットで画素は同一。箱は何も描かず、高さ 0 なので
|
|
54
|
+
自分の当たり判定を取らない (行の脇の押下は `background` の部品へ届く)。描画は封じ込めないので、切り取りはペインの中身の
|
|
55
|
+
ままで、窓をずらす 1 段の描き直しの振る舞いは変わらない。`.aqvs-items-boundary` は README の「Custom styling」の表に
|
|
56
|
+
加えた。配置の封じ込めで行のはみ出しはインクのはみ出しになり、ペインの中身のスクロールできる範囲に数えなくなる。
|
|
57
|
+
そのため、ブラウザが自分で行を見せるスクロール (オーバースキャンの行の中のフォーカス可能な要素への Tab・ページ内検索) は
|
|
58
|
+
ペインの中身を動かせず (従来もペインがすぐ 0 へ戻していた)、行の箱が外側のスクローラーの外にあればそちらを動かす。
|
|
59
|
+
スクロールするページで、ウィンドウの下端で終わる一覧のすぐ下の 100px のオーバースキャンの行へ Tab すると、ページが
|
|
60
|
+
300px 動いた。内蔵のキー操作は `focus({ preventScroll: true })` で動かすので影響しない (README「What a scroll step paints」)。
|
|
61
|
+
- **`scrollTo` が行の境界で、上に隠れた行を留めていた**: `scrollTo` は位置を切り捨ててから `findIndexAtOrAfter` で行を
|
|
62
|
+
引いていたので、行 i の下端にちょうど一致する位置では行 i をオフセット `-h_i` で留め、`getScrollAnchor` が知らせる行
|
|
63
|
+
(i + 1、オフセット 0) を留めなかった。`updateItemSize` は保留中の揃えの行を可視の先頭とみなすので、その後で行 i を
|
|
64
|
+
測り直すと、補正も `onScrollAdjust` も無いまま見えている中身が変化の分ずれた (300px の行と 500px の行 9 で
|
|
65
|
+
`scrollTo(3200)` の後に `updateItemSize(9, 300)` を呼ぶと、錨が `{ index: 10, offsetPx: 0 }` から
|
|
66
|
+
`{ index: 10, offsetPx: 200 }` へ動いた)。可視の先頭の境界の規則を 1 つの関数 `resolveVisibleStartRow` (モジュール
|
|
67
|
+
レベル。バレル非公開) にまとめ、`scrollTo`・`getScrollAnchor`・`updateItemSize`・`computeRenderingRanges` がどれもそれを
|
|
68
|
+
呼ぶ。位置を含む行、行の境界ではそこから始まる行をオフセット 0、末尾 (最後の行の下端とその先) では最後の行をその上端で
|
|
69
|
+
返す。同じ測り直しはいま錨 `{ 10, 0 }` を保ち、`"item-resize"` (差 -200) を 1 回知らせる。
|
|
70
|
+
- **強制配色でスクロールバーのつまみが消えていた**: 強制配色の規則はタップのサークルの輪郭だけで、つまみも溝も地色だけで
|
|
71
|
+
描くため、どちらも `Canvas` に置き換わった (Chromium の強制配色で、既定のテーマでも日報のテーマでも、つまみと溝が
|
|
72
|
+
どちらも rgb(255, 255, 255))。上の Added の描き方で、既定のつまみは rgb(255, 255, 255) の溝の上の rgb(0, 0, 0)
|
|
73
|
+
(`CanvasText`) になった。
|
|
74
|
+
|
|
75
|
+
### Tests
|
|
76
|
+
|
|
77
|
+
- `arrowButtonTabStops.spec.tsx` 24 → 38 (4 つの公開入口ごとに、既定のバーとつまみの名前、`false` のバーの `aria-hidden` と
|
|
78
|
+
支援技術から見えるスクロールバーとスライダーが 0 であること、バーの中の Tab の止まり先が 0 でルートとつまみの器が
|
|
79
|
+
`tabindex` を持たないこと、矢印が有効と無効のそれぞれで、バーのどの部品をどのボタン (左・右・中) で押してもフォーカスが
|
|
80
|
+
動かないこと、対照として既定のバーでは右ボタンで押したトラックからフォーカスがバーへ移ること、トラックの押下とつまみの
|
|
81
|
+
ドラッグのスクロール。端へ戻るピルの既定と `false` の 2 件)、`ScrollBar.spec.tsx` +3 (名前の既定値・`locale="ja"` と
|
|
82
|
+
キーごとの上書き・空白の上書きの `RangeError`)、`labels.spec.ts` (11 キーとその値)、`scrollStepRepaint.spec.tsx` +2 (ラッパーの
|
|
83
|
+
親が、位置指定され大きさと配置を封じ込め flex の子でも grid の子でもない高さ 0 の箱であること、グリッドの行も同じ箱の中で、
|
|
84
|
+
空の一覧は箱を描かないこと)、`renderedClassContract.spec.tsx` (表の `.aqvs-items-boundary` を描いた箱で確かめる)。
|
|
85
|
+
新しい spec: `scrollToBoundaryPin.spec.tsx` 8 (規則の関数の内側・境界・末尾・木の過渡状態と `computeRenderingRanges` の
|
|
86
|
+
一致、`scrollTo` の境界の錨・1px 下の対照・すべての行の上端)、`forcedColors.spec.tsx` 4 (地色だけで描く部品をスタイル
|
|
87
|
+
シートから導き、どれもシステム色の規則を持つこと・置き換えから外した部品の状態の言い直し・規則の順序・描いた要素の
|
|
88
|
+
一致)、`devicePixelGrid.server.spec.tsx` 4 (node の環境のサーバー描画: 比 `null`・行ラッパーとつまみの揃える前の
|
|
89
|
+
オフセット・名前付きのスクロールバー)、`devicePixelGrid.realm.spec.tsx` 1 (ウィンドウを持たないレルムのクライアントの描画:
|
|
90
|
+
最初の描画は比 `null` で購読せず、取り付けが要素のウィンドウへ切り替える)、`ratchetCoverage.spec.ts` 17 (つめ車の検証・
|
|
91
|
+
`--write`・`--adopt`・誤りの終了コード 2)。
|
|
92
|
+
- `tests/e2e/home-controls.spec.ts` の Top/Bottom のボタンの試験は、スクロール領域を `data-testid="aqvs-scroll-pane-content"` で探す。行の親の親をたどる
|
|
93
|
+
書き方は、行の外に置いた配置の境界 (`.aqvs-items-boundary`、大きさ 0) を指して「見えない」と判定していた。
|
|
94
|
+
|
|
95
|
+
## 3.9.2 (2026-10-04)
|
|
96
|
+
|
|
97
|
+
### Fixed
|
|
98
|
+
|
|
99
|
+
- **利用者が先頭へ戻した一覧への `scrollToIndex` が確定を足していた**: 行ラッパーが守る端を決める「覚えた揃え」は、
|
|
100
|
+
位置 0 では何を覚えていても上端で揃えるのに、「揃え無し」と「位置 0 の上端揃え」を別の状態として持っていた。そのため、
|
|
101
|
+
ホイールなどで先頭へ戻した一覧 (利用者のスクロールは揃えを忘れる) を先頭へ揃え直す最初の `scrollToIndex(0)` が揃えを書き、
|
|
102
|
+
確定を 1 回足していた (続く 2 回目も、その確定の直後の同じ値の書き込みで 1 回)。いまは位置 0 以下の揃えを揃え無しと
|
|
103
|
+
同じ 1 つの状態として持つ (正規形)。一覧がどう先頭へ着いたかによらず同じ状態なので、先頭へ揃え直しても何も書かない。
|
|
104
|
+
3.9.1 の「位置 0 から始まる一覧は上端揃えとして覚える」初期状態は、同じ正規形の揃え無しになる (見た目は変わらない)。
|
|
105
|
+
- **同じ位置への `scrollToIndex` が、確定の直後に中身の寸法と位置を同じ値で書き直していた**: React は確定の直後だと
|
|
106
|
+
同じ値の書き込みでも描画を 1 回予約するため、行の数の変化などで一覧が確定した直後に、一覧をその場に留める
|
|
107
|
+
`scrollToIndex` (ホストが打鍵ごとに揃え直すなど) が確定を 1 回足していた。いまは中身の寸法を最後に書いた値の同期の写しと、
|
|
108
|
+
位置を描画ループが止まっている間の位置の写しと比べ、同じなら書かない。
|
|
109
|
+
|
|
110
|
+
### Changed
|
|
111
|
+
|
|
112
|
+
- **一覧をその場に留める `scrollToIndex` は `onScroll` を呼ばない**: 位置が変わらない呼び出しは、現在位置への
|
|
113
|
+
`scrollTo` / `scrollBy` と同じく位置を知らせない (3.9.1 までは同じ位置を間引きの後でもう一度知らせていた)。
|
|
114
|
+
- **位置 0 から離れる補正は上端揃えを運ばない**: レイアウトシフトの補正が一覧を位置 0 から動かしたとき (先頭の高さ 0 の行が
|
|
115
|
+
高さを得た場合など)、3.9.1 は位置 0 で開いた一覧と `scrollToIndex` が位置 0 へ揃えた一覧では上端揃えを新しい位置へ運び、
|
|
116
|
+
利用者が位置 0 へ戻した一覧では運ばなかった。いまはどれも運ばず、新しい位置の行ラッパーは最も近い格子点へ揃う
|
|
117
|
+
(違いは装置の画素 1 つ未満)。
|
|
118
|
+
|
|
5
119
|
## 3.9.1 (2026-10-04)
|
|
6
120
|
|
|
7
121
|
### Fixed
|
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ High-performance virtual scrolling component for React with variable item height
|
|
|
13
13
|
- ↔️ **Horizontal Delegation**: Opt-in `onWheelHorizontal` hands horizontal wheel / trackpad (and shift+wheel) gestures to the parent — build frozen-column data grids
|
|
14
14
|
- 🎨 **Customizable**: Flexible styling and theming options
|
|
15
15
|
- 🌀 **Ultrafast Tap Scroll**: Adaptive tap scroll circle that scales speed up to 120× for massive datasets
|
|
16
|
-
- ♿ **Accessibility opt-ins
|
|
17
|
-
- 🌐 **Localization**: The built-in chrome strings (scrollbar arrow labels, scroll-to-edge pills, empty state) ship in English (default) and Japanese via `locale`, with per-key `labels` overrides. See [Localization](#localization)
|
|
16
|
+
- ♿ **Accessibility**: a named scrollbar and thumb, a forced-colours rendering, and opt-ins — Escape row-return (`enableEscapeRowReturn`), a screen-reader live region (`liveRegion`) announcing the visible range with your own wording, and a pointer-only scrollbar for apps with their own keyboard scrolling (`enableArrowButtonTabStops: false`)
|
|
17
|
+
- 🌐 **Localization**: The built-in chrome strings (scrollbar and thumb names, arrow labels, scroll-to-edge pills, empty state) ship in English (default) and Japanese via `locale`, with per-key `labels` overrides. See [Localization](#localization)
|
|
18
18
|
- 🔧 **TypeScript**: Full TypeScript support with comprehensive type definitions
|
|
19
19
|
|
|
20
20
|
## Installation
|
|
@@ -186,8 +186,29 @@ rounding:
|
|
|
186
186
|
|
|
187
187
|
## What a scroll step paints
|
|
188
188
|
|
|
189
|
-
The items wrapper
|
|
190
|
-
|
|
189
|
+
The items wrapper sits in `.aqvs-items-boundary`, its containing block and a relayout boundary: an absolutely
|
|
190
|
+
positioned box attached to the top, left and right padding edges of the row viewport, with a height of 0 and
|
|
191
|
+
`contain: size layout style`. Chromium lays out from a box instead of the document root (a relayout
|
|
192
|
+
boundary) only when the box is neither a flex nor a grid item and, for example, is positioned with size and
|
|
193
|
+
layout containment. The row viewport is a flex item, so without the box a step that mounts or unmounts rows
|
|
194
|
+
lays out from the document root. With it, that layout starts at the box. In Chromium 148, 60 one-row window shifts in a page of 2,231 layout objects (nested flex columns beside
|
|
195
|
+
a 400-item menu and a 600-paragraph side pane) ran 60 layouts from the document root without the box, and 60
|
|
196
|
+
partial layouts of 218 objects with it. With and without the box, a 1280×800 list paints identical pixels at
|
|
197
|
+
ratios 1, 1.25, 1.5, 1.75, 2 and 3, light and dark, at four offsets. The box paints nothing and takes no
|
|
198
|
+
pointer event of its own (its height is 0): the rows overflow it unclipped, the row viewport still clips them,
|
|
199
|
+
and a press beside the rows still reaches the `background` slot.
|
|
200
|
+
|
|
201
|
+
Layout containment turns that overflow into ink overflow, so the rows are no longer part of the row
|
|
202
|
+
viewport's scrollable area. A scroll the browser makes on its own to reveal a row outside the viewport — Tab
|
|
203
|
+
into a focusable element of an overscan row, a find-in-page match there — can no longer scroll the row
|
|
204
|
+
viewport (which the pane reset to 0 at once anyway). It scrolls the nearest outer scroller instead whenever
|
|
205
|
+
the row's box lies outside that scroller's view: in a page that scrolls, Tab into a 100 px overscan row just
|
|
206
|
+
below a list that ends at the bottom of a 500 px window centres that row's box and scrolls the page by
|
|
207
|
+
300 px. Focus rows with `focus({ preventScroll: true })`, as the built-in keyboard navigation does, or keep
|
|
208
|
+
one Tab stop per list (roving focus), so that Tab never lands in an overscan row.
|
|
209
|
+
|
|
210
|
+
The items wrapper itself is a plain compositor layer: `will-change: transform`, moved by a 2D translate that
|
|
211
|
+
is snapped to the device-pixel grid (see above), with nothing that takes its subtree out of 2D compositing.
|
|
191
212
|
Measured in Chromium 148 (1280×800, ratio 1, overscan 15, rows whose text ends in an ellipsis; 20 steps,
|
|
192
213
|
3 runs, median of the run medians):
|
|
193
214
|
|
|
@@ -279,6 +300,28 @@ render in them keep their own transitions. A host that does not load the package
|
|
|
279
300
|
transitions. In Chromium 148 the computed `transition-duration` of these parts drops from 0.08–0.5 s to
|
|
280
301
|
`0s`, while a row's own 0.2 s transition stays 0.2 s.
|
|
281
302
|
|
|
303
|
+
## Forced colours
|
|
304
|
+
|
|
305
|
+
Under `forced-colors: active` (for example a Windows contrast theme) the browser replaces every background
|
|
306
|
+
colour that is not a system colour with `Canvas`. A part painted by its background alone would then vanish
|
|
307
|
+
into its surroundings — the thumb would be `Canvas` on a `Canvas` track — so the shipped stylesheet gives
|
|
308
|
+
each such part a system-colour rendering:
|
|
309
|
+
|
|
310
|
+
- the bar and its track: a 1 px `GrayText` outline on their inner edge (the bar holds the arrows and the
|
|
311
|
+
track; the track is the range the thumb moves in);
|
|
312
|
+
- the thumb: filled with `CanvasText`, with `Highlight` while it is hovered or dragged and `GrayText` while
|
|
313
|
+
thumb dragging is off (`enableThumbDrag: false`). The thumb opts out of the browser's forcing
|
|
314
|
+
(`forced-color-adjust: none`), so its fill is never replaced by `Canvas`;
|
|
315
|
+
- the tap scroll circle: a 1 px `CanvasText` outline, since its gradient visual flattens;
|
|
316
|
+
- the bright spot and the rod of `tapScrollCircleSampleVisual`: `CanvasText`, since they show the direction
|
|
317
|
+
and the amount of the pull.
|
|
318
|
+
|
|
319
|
+
The other parts draw with text colour, borders or outlines, which the browser maps to system colours itself.
|
|
320
|
+
In Chromium 148 with forced colours emulated, the default thumb paints rgb(0, 0, 0) (`CanvasText`) on an
|
|
321
|
+
rgb(255, 255, 255) track instead of white on white. A host rule that restyles the thumb still wins here (see
|
|
322
|
+
[Custom styling](#custom-styling)); since the thumb opts out of forcing, the host's colour is then painted as
|
|
323
|
+
it is, so restate it inside `@media (forced-colors: active)` with system colours if you theme the thumb.
|
|
324
|
+
|
|
282
325
|
## Horizontal Scrolling
|
|
283
326
|
|
|
284
327
|
`VirtualScroll` virtualizes and scrolls the **vertical** axis only. To add a horizontal axis — e.g. a
|
|
@@ -471,16 +514,26 @@ itself has focus (an `Escape` on the row means whatever *you* decide — e.g. de
|
|
|
471
514
|
does act it calls `preventDefault()` only and does not stop propagation, the same contract as the
|
|
472
515
|
arrow keys.
|
|
473
516
|
|
|
474
|
-
## Scrollbar
|
|
517
|
+
## Scrollbar accessibility and the Tab order
|
|
475
518
|
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
and
|
|
519
|
+
Every bar is exposed to assistive technology as a named `role="scrollbar"` holding a named
|
|
520
|
+
`role="slider"` thumb, whose value is the scroll position (`aria-valuenow`, `aria-valuemin`,
|
|
521
|
+
`aria-valuemax`). The names come from the label catalog: `verticalScrollBar` / `horizontalScrollBar`
|
|
522
|
+
for the bar and `verticalScrollThumb` / `horizontalScrollThumb` for the thumb (see
|
|
523
|
+
[Localization](#localization)). Assistive technology appends the role itself, so the bar's name
|
|
524
|
+
carries only what tells the two bars of a grid apart.
|
|
525
|
+
|
|
526
|
+
The bar's two arrow buttons are Tab stops by default, because they are the only scrolling control a
|
|
527
|
+
keyboard user can reach with Tab: the pane moves its content by transform (there is no native
|
|
528
|
+
scroller for the browser to make focusable) and the rows are not Tab stops. Focus an arrow and
|
|
529
|
+
Enter / Space scrolls one step. The arrows are descendants of the `role="scrollbar"` element, whose
|
|
530
|
+
children ARIA 1.2 makes presentational, so whether assistive technology lists them as buttons of
|
|
531
|
+
their own is the browser's choice (Chromium does). While the arrows are disabled
|
|
532
|
+
(`enableArrowButtons: false`, or nothing to scroll) they are not focusable at all.
|
|
480
533
|
|
|
481
534
|
When your app already provides keyboard scrolling — roving focus with Arrow / Page / Home / End on
|
|
482
|
-
the rows, a grid keyboard model — the
|
|
483
|
-
|
|
535
|
+
the rows, a grid keyboard model — the bar only duplicates that path. Say so with the one signal,
|
|
536
|
+
`enableArrowButtonTabStops: false`:
|
|
484
537
|
|
|
485
538
|
```tsx
|
|
486
539
|
<VirtualScroll
|
|
@@ -489,16 +542,23 @@ the Tab order:
|
|
|
489
542
|
/>
|
|
490
543
|
```
|
|
491
544
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
545
|
+
The bar then becomes what a native scrollbar is, a pointer-only control:
|
|
546
|
+
|
|
547
|
+
- The bar carries `aria-hidden="true"`, so assistive technology meets no scrollbar and no slider for
|
|
548
|
+
this viewport; your keyboard model is the one it announces.
|
|
549
|
+
- Nothing in the bar is a Tab stop: the arrows get `tabIndex={-1}`, and the bar and the thumb wrapper
|
|
550
|
+
carry no `tabindex`.
|
|
551
|
+
- A press anywhere on the bar, with any button and on a disabled arrow too, cancels the press's
|
|
552
|
+
default action, so it never moves focus: neither onto a part of the bar nor away from where your
|
|
553
|
+
app put it. The press itself, its pointer events and its click still reach the part.
|
|
554
|
+
- Pointer scrolling is unchanged: the arrows (with press-and-hold repeat), the track, the thumb and
|
|
555
|
+
the tap circle work exactly as by default.
|
|
556
|
+
- The scroll-to-edge pills of `VirtualScroll` (`enableScrollToTopBottomButtons`) follow the same
|
|
557
|
+
signal: their overlay carries `aria-hidden="true"` while it shows, the pills are never Tab stops, a
|
|
558
|
+
press on one never moves focus, and its click still scrolls to the edge.
|
|
559
|
+
|
|
560
|
+
The option has one name and one meaning everywhere: `ScrollBar` and `ScrollPane` props, and
|
|
561
|
+
`scrollBarOptions` of `VirtualScroll` and `VirtualGrid` (the grid applies it to both of its bars).
|
|
502
562
|
|
|
503
563
|
## Screen-reader live region
|
|
504
564
|
|
|
@@ -518,7 +578,7 @@ settles:
|
|
|
518
578
|
```
|
|
519
579
|
|
|
520
580
|
The live region has **no built-in strings** — its wording and language are yours, and `locale` /
|
|
521
|
-
`labels` do not touch it (the built-in catalog covers only the
|
|
581
|
+
`labels` do not touch it (the built-in catalog covers only the eleven chrome strings, see
|
|
522
582
|
[Localization](#localization)). `format` returning the same string leaves the DOM untouched; `""`
|
|
523
583
|
clears the region. An invalid `debounceMs` (negative / non-finite) logs a warning and disables
|
|
524
584
|
announcements instead of silently substituting the default. ⚠️ If your app already maintains its
|
|
@@ -526,7 +586,7 @@ own live region for the list, keep using `onRangeChange` instead — two regions
|
|
|
526
586
|
|
|
527
587
|
## Localization
|
|
528
588
|
|
|
529
|
-
The components render exactly **
|
|
589
|
+
The components render exactly **eleven strings of their own** (UI chrome). They come from a built-in
|
|
530
590
|
catalog in English (`"en"`, the default) and Japanese (`"ja"`):
|
|
531
591
|
|
|
532
592
|
| Key | Where it appears | `en` | `ja` |
|
|
@@ -535,6 +595,10 @@ catalog in English (`"en"`, the default) and Japanese (`"ja"`):
|
|
|
535
595
|
| `scrollDown` | vertical ScrollBar end arrow (`aria-label`) | Scroll down | 下へスクロール |
|
|
536
596
|
| `scrollLeft` | horizontal ScrollBar start arrow (`aria-label`) | Scroll left | 左へスクロール |
|
|
537
597
|
| `scrollRight` | horizontal ScrollBar end arrow (`aria-label`) | Scroll right | 右へスクロール |
|
|
598
|
+
| `verticalScrollBar` | vertical ScrollBar (`role="scrollbar"`, `aria-label`) | Vertical | 縦方向 |
|
|
599
|
+
| `horizontalScrollBar` | horizontal ScrollBar (`role="scrollbar"`, `aria-label`) | Horizontal | 横方向 |
|
|
600
|
+
| `verticalScrollThumb` | vertical ScrollBar thumb (`role="slider"`, `aria-label`) | Vertical scroll position | 縦スクロール位置 |
|
|
601
|
+
| `horizontalScrollThumb` | horizontal ScrollBar thumb (`role="slider"`, `aria-label`) | Horizontal scroll position | 横スクロール位置 |
|
|
538
602
|
| `scrollToTop` | VirtualScroll scroll-to-top pill (`enableScrollToTopBottomButtons`) | Top | 先頭へ |
|
|
539
603
|
| `scrollToBottom` | VirtualScroll scroll-to-bottom pill (`enableScrollToTopBottomButtons`) | Bottom | 末尾へ |
|
|
540
604
|
| `noItems` | VirtualScroll empty state (`itemCount === 0`; also VirtualGrid with no scroll rows) | No items | 項目がありません |
|
|
@@ -583,7 +647,7 @@ catalog of `locale`:
|
|
|
583
647
|
a `lang` on an ancestor when the list's language differs from the page).
|
|
584
648
|
- Live-region wording stays yours (see [Screen-reader live region](#screen-reader-live-region)).
|
|
585
649
|
|
|
586
|
-
Exported API: `VIRTUAL_SCROLL_LOCALES` (`["en", "ja"]`), `VIRTUAL_SCROLL_LABEL_KEYS` (the
|
|
650
|
+
Exported API: `VIRTUAL_SCROLL_LOCALES` (`["en", "ja"]`), `VIRTUAL_SCROLL_LABEL_KEYS` (the eleven keys, in catalog order),
|
|
587
651
|
`VIRTUAL_SCROLL_LABEL_CATALOGS` (the frozen catalogs), `resolveVirtualScrollLocale(locale)` (`undefined`
|
|
588
652
|
→ `"en"`, otherwise the value or a `RangeError`), `resolveVirtualScrollLabels(locale, labels)` (the
|
|
589
653
|
effective frozen labels — the catalog object itself when `labels` is `undefined`), and the types
|
|
@@ -643,8 +707,9 @@ Contracts:
|
|
|
643
707
|
axis and consumes those deltas itself), and on the handle `scrollToIndex` (use `scrollToCell`)
|
|
644
708
|
and `getFenwickTreeTotalHeight` / `getFenwickSize` (use `getContentSize` and the counts you pass).
|
|
645
709
|
- `locale` / `labels` (see [Localization](#localization)) are forwarded to BOTH the embedded
|
|
646
|
-
`VirtualScroll` (vertical arrows and the "No items" empty state shown for 0 rows,
|
|
647
|
-
set or a degenerate band) and the horizontal `ScrollBar` (left / right
|
|
710
|
+
`VirtualScroll` (the vertical bar's names and arrows, and the "No items" empty state shown for 0 rows,
|
|
711
|
+
an all-frozen row set or a degenerate band) and the horizontal `ScrollBar` (its names and left / right
|
|
712
|
+
arrows).
|
|
648
713
|
- `scrollBarOptions`: the bar-local members — `width`, `enableThumbDrag`, `enableTrackClick`,
|
|
649
714
|
`enableArrowButtons` and `enableArrowButtonTabStops` — apply to BOTH bars alike, so no setting
|
|
650
715
|
covers only half of the grid. `tapScrollCircleOptions` configures the single two-axis circle;
|
|
@@ -805,7 +870,7 @@ exists in the DOM.
|
|
|
805
870
|
| `behaviorOptions` | `VirtualScrollBehaviorOptions` | ❌ | Options for scrolling behavior |
|
|
806
871
|
| `liveRegion` | `VirtualScrollLiveRegionOptions` | ❌ | Opt-in screen-reader live region announcing the visible range (nothing rendered when omitted). See [Screen-reader live region](#screen-reader-live-region) |
|
|
807
872
|
| `contentProps` | `React.AriaAttributes & { id?: string; role?: React.AriaRole }` | ❌ | ARIA / identity attributes for the scrollable **content** element — the correct host for a composite widget role. See [Composite widget roles](#composite-widget-roles-listbox--tree--grid). |
|
|
808
|
-
| `locale` | `VirtualScrollLocale` (`"en" \| "ja"`) | ❌ | UI chrome language of the built-in strings:
|
|
873
|
+
| `locale` | `VirtualScrollLocale` (`"en" \| "ja"`) | ❌ | UI chrome language of the built-in strings: the scrollbar's names (bar, thumb, arrows), scroll-to-edge pills, empty state (default: `"en"`). Unsupported values throw a `RangeError`. See [Localization](#localization) |
|
|
809
874
|
| `labels` | `VirtualScrollLabelOverrides` | ❌ | Per-key overrides laid over the catalog of `locale`: a plain object (prototype `Object.prototype` or `null`) whose own properties only are read. Unknown keys, blank or non-string values, and non-plain objects (arrays, class instances) throw a `RangeError`. See [Localization](#localization) |
|
|
810
875
|
|
|
811
876
|
### VirtualScrollScrollBarOptions
|
|
@@ -816,7 +881,7 @@ exists in the DOM.
|
|
|
816
881
|
| `enableThumbDrag` | `boolean` | Enable dragging the scrollbar thumb (default: true) |
|
|
817
882
|
| `enableTrackClick` | `boolean` | Enable clicking the scrollbar track (default: true) |
|
|
818
883
|
| `enableArrowButtons` | `boolean` | Enable arrow buttons on the scrollbar (default: true) |
|
|
819
|
-
| `enableArrowButtonTabStops` | `boolean` |
|
|
884
|
+
| `enableArrowButtonTabStops` | `boolean` | Whether the scrollbar is the keyboard user's scrolling control (default: true: a named scrollbar and thumb, the two arrows in the Tab order). Set `false` when your app already owns keyboard scrolling of the list: the bar and the scroll-to-edge pills become pointer-only (`aria-hidden`, no Tab stop, a press never moves focus) and pointer scrolling is unchanged. See [Scrollbar accessibility and the Tab order](#scrollbar-accessibility-and-the-tab-order) |
|
|
820
885
|
| `enableScrollToTopBottomButtons` | `boolean` | Enable the auto-hiding Top/Bottom pills (texts from `labels.scrollToTop` / `labels.scrollToBottom`; default: false) |
|
|
821
886
|
| `renderThumbOverlay` | `(props: ScrollBarThumbOverlayRenderProps) => ReactNode` | Render prop to anchor custom UI near the scrollbar thumb |
|
|
822
887
|
| `tapScrollCircleOptions` | `ScrollBarTapCircleOptions` | Customization for the auxiliary tap scroll circle |
|
|
@@ -839,7 +904,7 @@ exists in the DOM.
|
|
|
839
904
|
|
|
840
905
|
| Method | Type | Description |
|
|
841
906
|
| --- | --- | --- |
|
|
842
|
-
| `scrollTo` | `(position: number \| ((prev: number) => number)) => number` | **Jump** to a **logical** position (updater receives the current logical position). Returns the applied **logical** position (2.0.0). ⚠️ Not for bridging continuous input — see [Bridging input from outside the pane](#bridging-input-from-outside-the-pane) |
|
|
907
|
+
| `scrollTo` | `(position: number \| ((prev: number) => number)) => number` | **Jump** to a **logical** position (updater receives the current logical position). Returns the applied **logical** position (2.0.0). The position is held as the first visible row there plus the offset of its top — the row `getScrollAnchor()` reports: a position on a row boundary holds the row that starts there, at offset 0 — so a later size change above that row is compensated (`onScrollAdjust`, `"item-resize"`). ⚠️ Not for bridging continuous input — see [Bridging input from outside the pane](#bridging-input-from-outside-the-pane) |
|
|
843
908
|
| `scrollBy` | `(delta: number) => number` | Scroll **by a delta** with the pane's own wheel semantics (float accumulation, no anchor). Use this — not `scrollTo` — to bridge continuous input from outside the pane. Returns the applied **logical** position |
|
|
844
909
|
| `applyWheel` | `(event: WheelEvent) => boolean` | Apply one wheel event with the pane's own rules; returns whether it was consumed. The single entry point for wheel input originating outside the pane — normally reached through `useWheelBridge` |
|
|
845
910
|
| *(ScrollPaneHandle only)* `scrollTo` | `(pos, dimsOverride?)` | The pane-level jump. `dimsOverride` is an explicit clamp-space for callers that know **fresher-than-committed** dims (the layout-shift compensation passes `committed + delta`). Do not pass it casually — a wrong override clamps against dims that are not on screen |
|
|
@@ -1044,6 +1109,7 @@ removing one is a breaking change:
|
|
|
1044
1109
|
| --- | --- |
|
|
1045
1110
|
| `.aqvs-scroll-pane` | The scroll root, where `className` lands |
|
|
1046
1111
|
| `.aqvs-scroll-pane-content` | The row viewport |
|
|
1112
|
+
| `.aqvs-items-boundary` | The rows' containing block and relayout boundary inside the row viewport: absolutely positioned, height 0, `contain: size layout style` (see [What a scroll step paints](#what-a-scroll-step-paints)). It paints nothing; keep its `position`, `height` and `contain` |
|
|
1047
1113
|
| `.aqvs-item-container` | Each row's container |
|
|
1048
1114
|
| `.aqvs-no-items-container` | The empty state (`itemCount` 0): the box at the top of the viewport |
|
|
1049
1115
|
| `.aqvs-no-items-text` | The empty state's message (`labels.noItems`), centred, `color: #6b7280` |
|
package/dist/ScrollBar.d.cts
CHANGED
|
@@ -81,37 +81,41 @@ export type ScrollBarProps = {
|
|
|
81
81
|
/** Whether arrow buttons control the scroll position. / 矢印ボタンによるスクロール操作を許可するかどうか。 */
|
|
82
82
|
enableArrowButtons?: boolean;
|
|
83
83
|
/**
|
|
84
|
-
* Whether the
|
|
84
|
+
* Whether the bar is the keyboard user's scrolling control (default `true`), or a pointer-only control because the host
|
|
85
|
+
* scrolls this viewport by keyboard itself (`false`).
|
|
85
86
|
*
|
|
86
|
-
* `
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* scrolling of this viewport (roving row focus with Arrow / Page / Home / End, a grid keyboard
|
|
93
|
-
* model): the arrows then duplicate that path and cost every keyboard user two extra Tab presses
|
|
94
|
-
* per bar — native scrollbars are never Tab stops either. The default stays `true` because
|
|
95
|
-
* without such a host model the arrows are the only scrolling control a keyboard user can reach
|
|
96
|
-
* with Tab: `ScrollPane` / `VirtualScroll` move their content by transform, so there is no native
|
|
97
|
-
* scroller the browser could make focusable, and their rows are not Tab stops. No effect while
|
|
98
|
-
* the arrows are disabled (`enableArrowButtons: false`, or nothing to scroll) — a disabled button
|
|
99
|
-
* is never focusable.
|
|
87
|
+
* `true`: the bar is exposed to assistive technology as a named `role="scrollbar"` (`labels.verticalScrollBar` /
|
|
88
|
+
* `labels.horizontalScrollBar`) holding a named `role="slider"` thumb (`labels.verticalScrollThumb` /
|
|
89
|
+
* `labels.horizontalScrollThumb`), and its two arrow buttons are Tab stops: `ScrollPane` / `VirtualScroll` move their
|
|
90
|
+
* content by transform, so there is no native scroller the browser could make focusable, and their rows are not Tab
|
|
91
|
+
* stops — without a host keyboard model the arrows are the only scrolling control Tab reaches. Focus an arrow and
|
|
92
|
+
* Enter / Space scrolls one step.
|
|
100
93
|
*
|
|
101
|
-
*
|
|
94
|
+
* `false` declares that the host owns keyboard scrolling of this viewport (roving row focus with Arrow / Page / Home /
|
|
95
|
+
* End, a grid keyboard model), so the bar only duplicates that path. The bar then becomes what a native scrollbar is:
|
|
96
|
+
* a pointer-only control. The bar carries `aria-hidden="true"`; its arrows get `tabIndex={-1}`, and the bar root and
|
|
97
|
+
* the thumb wrapper are not focusable; a press anywhere on the bar cancels its default action, so it never moves
|
|
98
|
+
* focus — neither onto a part of the bar (an arrow, also a disabled one) nor away from where the host put it — while
|
|
99
|
+
* the press itself still reaches the part. Pointer scrolling is unchanged: the arrows (with press-and-hold repeat),
|
|
100
|
+
* the track, the thumb and the tap circle work exactly as with `true`. The same signal reaches the scroll-to-edge pills
|
|
101
|
+
* of `VirtualScroll` (`VirtualScrollScrollBarOptions["enableArrowButtonTabStops"]`).
|
|
102
102
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* (
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
103
|
+
* バーがキーボード利用者のスクロール操作部品か (既定 `true`)、ホストがこのビューポートのキーボードスクロールを自分で
|
|
104
|
+
* 持つためポインタ専用の部品か (`false`) の指定。
|
|
105
|
+
*
|
|
106
|
+
* `true`: バーは名前付きの `role="scrollbar"` (`labels.verticalScrollBar` / `labels.horizontalScrollBar`) として
|
|
107
|
+
* 支援技術へ見え、名前付きの `role="slider"` のつまみ (`labels.verticalScrollThumb` / `labels.horizontalScrollThumb`) を
|
|
108
|
+
* 持ち、矢印ボタン 2 個は Tab の止まり先。`ScrollPane` / `VirtualScroll` はコンテンツを transform で動かすため、
|
|
109
|
+
* ブラウザがフォーカス可能にできるネイティブのスクロール領域が無く、行も Tab の止まり先ではない — ホストのキーボード
|
|
110
|
+
* モデルが無ければ、矢印が Tab で届く唯一のスクロール操作部品。矢印にフォーカスして Enter / Space で 1 ステップ移動。
|
|
111
|
+
*
|
|
112
|
+
* `false` は、ホストがこのビューポートのキーボードスクロールを持つ (行のロービングフォーカスと矢印 / Page / Home / End、
|
|
113
|
+
* グリッドのキーボードモデル) ことの宣言で、バーはその経路の重複にすぎない。バーはネイティブのスクロールバーと同じく
|
|
114
|
+
* ポインタ専用の部品になる。バーは `aria-hidden="true"` を持ち、矢印は `tabIndex={-1}`、バーのルートとつまみの器は
|
|
115
|
+
* フォーカス不能。バーのどこを押しても押下の既定動作を取り消すので、押下はフォーカスを動かさない — バーの部品
|
|
116
|
+
* (矢印。無効の矢印も) へも、ホストが置いた場所の外へも — が、押下そのものは部品へ届く。ポインタのスクロールは
|
|
117
|
+
* 変わらない: 矢印 (長押しの連続を含む)・トラック・つまみ・タップのサークルは `true` と同じに動く。同じ合図は
|
|
118
|
+
* `VirtualScroll` の端へ戻るピルにも届く (`VirtualScrollScrollBarOptions["enableArrowButtonTabStops"]`)。
|
|
115
119
|
*/
|
|
116
120
|
enableArrowButtonTabStops?: boolean;
|
|
117
121
|
/** Whether the scrollbar is horizontal. / スクロールバーが水平かどうか。 */
|
|
@@ -149,18 +153,20 @@ export type ScrollBarProps = {
|
|
|
149
153
|
/** The index of the last visible item. / 最後の可視アイテムのインデックス。 */
|
|
150
154
|
visibleEndIndex?: number;
|
|
151
155
|
/**
|
|
152
|
-
* UI chrome locale of the built-in
|
|
153
|
-
* throws a RangeError at render; no language negotiation happens.
|
|
154
|
-
*
|
|
156
|
+
* UI chrome locale of the built-in accessible names of the bar, its thumb and its arrows (default `"en"`). An
|
|
157
|
+
* unsupported value throws a RangeError at render; no language negotiation happens.
|
|
158
|
+
* バー・つまみ・矢印の内蔵アクセシブルネームの UI クロームロケール (既定 `"en"`)。非対応値は描画時に RangeError、
|
|
155
159
|
* 言語ネゴシエーションなし。
|
|
156
160
|
*/
|
|
157
161
|
locale?: VirtualScrollLocale;
|
|
158
162
|
/**
|
|
159
|
-
* Per-key overrides laid over the catalog of `locale`.
|
|
160
|
-
*
|
|
163
|
+
* Per-key overrides laid over the catalog of `locale`. A vertical bar reads `verticalScrollBar`,
|
|
164
|
+
* `verticalScrollThumb`, `scrollUp` and `scrollDown`; a horizontal bar reads `horizontalScrollBar`,
|
|
165
|
+
* `horizontalScrollThumb`, `scrollLeft` and `scrollRight`. Unknown keys and blank values throw a
|
|
161
166
|
* RangeError at render.
|
|
162
|
-
* `locale`
|
|
163
|
-
*
|
|
167
|
+
* `locale` のカタログへ重ねるキー単位の上書き。縦のバーが読むのは `verticalScrollBar`・`verticalScrollThumb`・
|
|
168
|
+
* `scrollUp`・`scrollDown`、横のバーは `horizontalScrollBar`・`horizontalScrollThumb`・`scrollLeft`・`scrollRight`。
|
|
169
|
+
* 未知キーと空白値は描画時に RangeError。
|
|
164
170
|
*/
|
|
165
171
|
labels?: VirtualScrollLabelOverrides;
|
|
166
172
|
};
|
package/dist/ScrollBar.d.ts
CHANGED
|
@@ -81,37 +81,41 @@ export type ScrollBarProps = {
|
|
|
81
81
|
/** Whether arrow buttons control the scroll position. / 矢印ボタンによるスクロール操作を許可するかどうか。 */
|
|
82
82
|
enableArrowButtons?: boolean;
|
|
83
83
|
/**
|
|
84
|
-
* Whether the
|
|
84
|
+
* Whether the bar is the keyboard user's scrolling control (default `true`), or a pointer-only control because the host
|
|
85
|
+
* scrolls this viewport by keyboard itself (`false`).
|
|
85
86
|
*
|
|
86
|
-
* `
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* scrolling of this viewport (roving row focus with Arrow / Page / Home / End, a grid keyboard
|
|
93
|
-
* model): the arrows then duplicate that path and cost every keyboard user two extra Tab presses
|
|
94
|
-
* per bar — native scrollbars are never Tab stops either. The default stays `true` because
|
|
95
|
-
* without such a host model the arrows are the only scrolling control a keyboard user can reach
|
|
96
|
-
* with Tab: `ScrollPane` / `VirtualScroll` move their content by transform, so there is no native
|
|
97
|
-
* scroller the browser could make focusable, and their rows are not Tab stops. No effect while
|
|
98
|
-
* the arrows are disabled (`enableArrowButtons: false`, or nothing to scroll) — a disabled button
|
|
99
|
-
* is never focusable.
|
|
87
|
+
* `true`: the bar is exposed to assistive technology as a named `role="scrollbar"` (`labels.verticalScrollBar` /
|
|
88
|
+
* `labels.horizontalScrollBar`) holding a named `role="slider"` thumb (`labels.verticalScrollThumb` /
|
|
89
|
+
* `labels.horizontalScrollThumb`), and its two arrow buttons are Tab stops: `ScrollPane` / `VirtualScroll` move their
|
|
90
|
+
* content by transform, so there is no native scroller the browser could make focusable, and their rows are not Tab
|
|
91
|
+
* stops — without a host keyboard model the arrows are the only scrolling control Tab reaches. Focus an arrow and
|
|
92
|
+
* Enter / Space scrolls one step.
|
|
100
93
|
*
|
|
101
|
-
*
|
|
94
|
+
* `false` declares that the host owns keyboard scrolling of this viewport (roving row focus with Arrow / Page / Home /
|
|
95
|
+
* End, a grid keyboard model), so the bar only duplicates that path. The bar then becomes what a native scrollbar is:
|
|
96
|
+
* a pointer-only control. The bar carries `aria-hidden="true"`; its arrows get `tabIndex={-1}`, and the bar root and
|
|
97
|
+
* the thumb wrapper are not focusable; a press anywhere on the bar cancels its default action, so it never moves
|
|
98
|
+
* focus — neither onto a part of the bar (an arrow, also a disabled one) nor away from where the host put it — while
|
|
99
|
+
* the press itself still reaches the part. Pointer scrolling is unchanged: the arrows (with press-and-hold repeat),
|
|
100
|
+
* the track, the thumb and the tap circle work exactly as with `true`. The same signal reaches the scroll-to-edge pills
|
|
101
|
+
* of `VirtualScroll` (`VirtualScrollScrollBarOptions["enableArrowButtonTabStops"]`).
|
|
102
102
|
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* (
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
103
|
+
* バーがキーボード利用者のスクロール操作部品か (既定 `true`)、ホストがこのビューポートのキーボードスクロールを自分で
|
|
104
|
+
* 持つためポインタ専用の部品か (`false`) の指定。
|
|
105
|
+
*
|
|
106
|
+
* `true`: バーは名前付きの `role="scrollbar"` (`labels.verticalScrollBar` / `labels.horizontalScrollBar`) として
|
|
107
|
+
* 支援技術へ見え、名前付きの `role="slider"` のつまみ (`labels.verticalScrollThumb` / `labels.horizontalScrollThumb`) を
|
|
108
|
+
* 持ち、矢印ボタン 2 個は Tab の止まり先。`ScrollPane` / `VirtualScroll` はコンテンツを transform で動かすため、
|
|
109
|
+
* ブラウザがフォーカス可能にできるネイティブのスクロール領域が無く、行も Tab の止まり先ではない — ホストのキーボード
|
|
110
|
+
* モデルが無ければ、矢印が Tab で届く唯一のスクロール操作部品。矢印にフォーカスして Enter / Space で 1 ステップ移動。
|
|
111
|
+
*
|
|
112
|
+
* `false` は、ホストがこのビューポートのキーボードスクロールを持つ (行のロービングフォーカスと矢印 / Page / Home / End、
|
|
113
|
+
* グリッドのキーボードモデル) ことの宣言で、バーはその経路の重複にすぎない。バーはネイティブのスクロールバーと同じく
|
|
114
|
+
* ポインタ専用の部品になる。バーは `aria-hidden="true"` を持ち、矢印は `tabIndex={-1}`、バーのルートとつまみの器は
|
|
115
|
+
* フォーカス不能。バーのどこを押しても押下の既定動作を取り消すので、押下はフォーカスを動かさない — バーの部品
|
|
116
|
+
* (矢印。無効の矢印も) へも、ホストが置いた場所の外へも — が、押下そのものは部品へ届く。ポインタのスクロールは
|
|
117
|
+
* 変わらない: 矢印 (長押しの連続を含む)・トラック・つまみ・タップのサークルは `true` と同じに動く。同じ合図は
|
|
118
|
+
* `VirtualScroll` の端へ戻るピルにも届く (`VirtualScrollScrollBarOptions["enableArrowButtonTabStops"]`)。
|
|
115
119
|
*/
|
|
116
120
|
enableArrowButtonTabStops?: boolean;
|
|
117
121
|
/** Whether the scrollbar is horizontal. / スクロールバーが水平かどうか。 */
|
|
@@ -149,18 +153,20 @@ export type ScrollBarProps = {
|
|
|
149
153
|
/** The index of the last visible item. / 最後の可視アイテムのインデックス。 */
|
|
150
154
|
visibleEndIndex?: number;
|
|
151
155
|
/**
|
|
152
|
-
* UI chrome locale of the built-in
|
|
153
|
-
* throws a RangeError at render; no language negotiation happens.
|
|
154
|
-
*
|
|
156
|
+
* UI chrome locale of the built-in accessible names of the bar, its thumb and its arrows (default `"en"`). An
|
|
157
|
+
* unsupported value throws a RangeError at render; no language negotiation happens.
|
|
158
|
+
* バー・つまみ・矢印の内蔵アクセシブルネームの UI クロームロケール (既定 `"en"`)。非対応値は描画時に RangeError、
|
|
155
159
|
* 言語ネゴシエーションなし。
|
|
156
160
|
*/
|
|
157
161
|
locale?: VirtualScrollLocale;
|
|
158
162
|
/**
|
|
159
|
-
* Per-key overrides laid over the catalog of `locale`.
|
|
160
|
-
*
|
|
163
|
+
* Per-key overrides laid over the catalog of `locale`. A vertical bar reads `verticalScrollBar`,
|
|
164
|
+
* `verticalScrollThumb`, `scrollUp` and `scrollDown`; a horizontal bar reads `horizontalScrollBar`,
|
|
165
|
+
* `horizontalScrollThumb`, `scrollLeft` and `scrollRight`. Unknown keys and blank values throw a
|
|
161
166
|
* RangeError at render.
|
|
162
|
-
* `locale`
|
|
163
|
-
*
|
|
167
|
+
* `locale` のカタログへ重ねるキー単位の上書き。縦のバーが読むのは `verticalScrollBar`・`verticalScrollThumb`・
|
|
168
|
+
* `scrollUp`・`scrollDown`、横のバーは `horizontalScrollBar`・`horizontalScrollThumb`・`scrollLeft`・`scrollRight`。
|
|
169
|
+
* 未知キーと空白値は描画時に RangeError。
|
|
164
170
|
*/
|
|
165
171
|
labels?: VirtualScrollLabelOverrides;
|
|
166
172
|
};
|
package/dist/ScrollBar.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ScrollBar.d.ts","sourceRoot":"","sources":["../src/ScrollBar.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAIrD,OAAO,EAA8B,KAAK,2BAA2B,
|
|
1
|
+
{"version":3,"file":"ScrollBar.d.ts","sourceRoot":"","sources":["../src/ScrollBar.tsx"],"names":[],"mappings":"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"}
|