@aiquants/virtualscroll 3.8.1 → 3.9.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 +113 -0
- package/README.md +164 -24
- package/dist/ScrollBar.d.cts +8 -2
- package/dist/ScrollBar.d.ts +8 -2
- package/dist/ScrollBar.d.ts.map +1 -1
- package/dist/VirtualScroll.d.cts +122 -19
- package/dist/VirtualScroll.d.ts +122 -19
- package/dist/VirtualScroll.d.ts.map +1 -1
- package/dist/devicePixelGrid.d.cts +78 -0
- package/dist/devicePixelGrid.d.ts +79 -0
- package/dist/devicePixelGrid.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2143 -2092
- package/dist/styles/virtualscroll.css +1 -1
- package/dist/styles/virtualscroll.standalone.css +1 -1
- package/package.json +1 -1
- package/src/ScrollBar.tsx +24 -8
- package/src/VirtualScroll.tsx +335 -200
- package/src/devicePixelGrid.ts +308 -0
- package/src/index.ts +2 -0
- package/src/styles/virtualscroll.css +22 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,119 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to `@aiquants/virtualscroll` are documented here.
|
|
4
4
|
|
|
5
|
+
## 3.9.0 (2026-10-04)
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **自分で動かした位置を同期で知らせる `onScrollAdjust`**: `VirtualScroll` が入力なしにスクロール位置を自分で動かすたびに、
|
|
10
|
+
間引かず同期で、動かし終えてから呼ぶ。理由 (`cause`) は 4 つ: `"item-resize"` (`updateItemSize` が先頭の可視行より上の
|
|
11
|
+
行の高さを変え、位置を同じ差だけ動かした。`updateItemSize` から戻る前)、`"reconciliation"` (描画が、描いた行のうち先頭の
|
|
12
|
+
可視行より上の行に `getItemHeight` の新しい高さを見つけ、その描画の後のマイクロタスクが位置を同じ差だけ動かした)、
|
|
13
|
+
`"drift"` (寸法の変化の後、最後の `scrollToIndex` または `initialScrollAnchor` の保留中の揃えを、確定の後の effect で
|
|
14
|
+
留め直した)、`"re-issue"` (前の中身の寸法でクランプされた補正を、新しい寸法の確定の後の effect でもう一度発行した)。
|
|
15
|
+
引数は `{ position, delta, cause }` (`VirtualScrollAdjustment`。論理 px) で、`position` は動かした後の `getScrollPosition()`
|
|
16
|
+
の値、`delta` は適用した変化 (0 にはならない)。中で読む `getScrollPosition()` と `getScrollAnchor()` は動かした後の位置と
|
|
17
|
+
行の高さを返す。利用者やホストが始めたスクロール (ホイール・ドラッグと慣性・スクロールバー・行のキー移動・`scrollTo` /
|
|
18
|
+
`scrollBy` / `scrollToIndex` / `applyWheel`) と、`getScrollPosition()` を変えない変化では呼ばない。`onScroll` /
|
|
19
|
+
`onRangeChange` は間引いたうえで 1 フレーム遅れるため、項目の同一性で自前の錨を持つホストがそこでだけ錨を記録すると、
|
|
20
|
+
次の範囲の知らせより前に確定した一覧の変化が、既に動いた位置を巻き戻していた (補正の分ずれる、または隣の項目に着地する)。
|
|
21
|
+
そうしたホストはここでも錨を記録する (README「Position changes the list makes on its own」)。型
|
|
22
|
+
`VirtualScrollAdjustment` / `VirtualScrollAdjustmentCause` をバレルから公開する。`VirtualGrid` は公開しない (位置が 2 軸で、
|
|
23
|
+
自分で動かすのは縦だけのため)。
|
|
24
|
+
- **スタイルの口の表と空状態のクラス**: README の節を「Custom styling」へ改め、スタイルの口 (描かれる部品と組の
|
|
25
|
+
`aqvs-*` クラス) を表にした。空状態の `.aqvs-no-items-container` (表示域の上端の箱) と `.aqvs-no-items-text`
|
|
26
|
+
(`labels.noItems` の文言。既定の文字色 `#6b7280` は明るい背景でしか 4.5:1 に届かない) を加えた。表のクラスの改名・削除は
|
|
27
|
+
破壊的変更として扱う。
|
|
28
|
+
- **テスト**: `VirtualScroll.spec.ts` +15 (下記 Fixed の揃える関数の 2 件と守る端の選び方の 3 件、端数のビューポートで
|
|
29
|
+
揃えた端を越えないことのコンポーネントの 4 件、`onScrollAdjust` の 6 件 — 4 つの理由をそれぞれ実物で起こし 1 回ずつ適用した
|
|
30
|
+
差で知らせ、中で読むハンドルが動かした後の位置と錨を返すこと、利用者とホストのスクロール (`scrollBy`・`scrollTo`・
|
|
31
|
+
`scrollToIndex`・ホイール・スクロールバーの矢印・行の PageDown・ポインタのドラッグとその慣性・つまみのドラッグ・トラックの
|
|
32
|
+
押下) では知らせないこと)、`renderedClassContract.spec.tsx` +3 (README の表のクラスがこの契約が部品を引く表とちょうど一致し
|
|
33
|
+
空状態の 2 つを含むこと、どのクラスも名指す部品 (ARIA のロール・`data-*`・文言で引いた要素) のすべてに付いて描かれること、
|
|
34
|
+
空の一覧の文言と箱)、`scrollStepRepaint.spec.tsx` +2 (下記 Fixed のつまみ)。
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **端に揃えた行の余白を装置の画素への揃えが削っていた**: 行ラッパーの平行移動は最も近い格子点へ揃えていた (`Math.round`。
|
|
39
|
+
ちょうど半分は +∞ 側)。そのためビューポートの高さが端数のとき、最大位置の最後の行や `align: "bottom"` で見せた行が、
|
|
40
|
+
表示域の終端を最大で半装置画素越えた (比 1 の 705.5px のビューポートで、終端の 8px の余白が 7.5px。ホストの視覚の検査では
|
|
41
|
+
比 1.5 で 0.3335px が切れた)。揃えは守る端を選ぶ。位置 0 と、最後の `scrollToIndex` の `align: "top"` (既定。offset の
|
|
42
|
+
有無を問わない) の着地位置では、格子点を正確な値以上に取り (`Math.ceil`)、中身を始端側へ動かさない。最大位置と、最後の
|
|
43
|
+
`align: "bottom"` の着地位置では、正確な値以下に取り (`Math.floor`)、中身を終端側へ動かさない。それ以外 (中央揃え・
|
|
44
|
+
利用者やホストのスクロール) は従来どおり最も近い格子点。覚えた揃えは、揃えた行をその場に留めるレイアウトシフトの補正と
|
|
45
|
+
ドリフト補正で一緒に動き、ほかのスクロールで忘れる。位置 0 は最大位置に勝ち、どちらも覚えた揃えに勝つ。端から 2^-10 px
|
|
46
|
+
以内は端とみなす。揃えた端を保つため、`scrollToIndex` は揃えた位置へ厳密に着地し (従来は 0.5px 以下の差ではペインを
|
|
47
|
+
動かさなかった)、ドリフト補正は 2^-10 px を超えるずれで留め直す (従来は 1px 超)。平行移動は 2D で装置の画素の整数の
|
|
48
|
+
ままなので、`perspective: none` との画素の同一性は変わらない。揃える関数は `snapToDevicePixelGrid(cssPx, ratio, edge)`
|
|
49
|
+
(`edge` は `"none"` / `"start"` / `"end"`) として新しいモジュール `devicePixelGrid.ts` へ移した (モジュールレベル。
|
|
50
|
+
バレル非公開)。
|
|
51
|
+
- **層の中の行も整数の画素に描かれるという説明を正した**: 行ラッパーの docstring と README は「層の中の端数のレイアウト
|
|
52
|
+
位置は描画が画素へ揃える」としていたが、Chromium は角の丸い枠線・輪・輪郭を層の中の正確な位置で滲ませて描く (比 1.25 で、
|
|
53
|
+
描画のアンカーから 7814px の行の 1px の枠線が 75% と 50% の被覆で描かれた)。揃えるのは層の平行移動だけで、行が装置の画素
|
|
54
|
+
の整数から始まるのは、その上の行の高さの和が装置 px の整数のときだけ。README に、そのためのホストの契約 (行の高さを、
|
|
55
|
+
L × 比 が整数になる格子 L の倍数にする。比が 4 分の 1 刻みなら L = 4px) を書いた。
|
|
56
|
+
- **スクロールバーのつまみを `top` で動かしていた**: つまみの器を `top` (横のバーは `left`) で動かしていたため、描画の窓を
|
|
57
|
+
変えないスクロールの 1 段ごとに、文書の根からのレイアウトが 1 回足されていた (Chromium で、描画の窓を変えない 40px の
|
|
58
|
+
60 段が、`top` で動かすと Layout 60 回・13.9ms、つまみを止めると 30 回・9.1ms)。器は `top: 0; left: 0` に置いたまま、
|
|
59
|
+
行ラッパーと同じく描くウィンドウの装置の画素の格子へ最も近い点で揃えた `translateY` (横は `translateX`) で動かし、遷移は
|
|
60
|
+
付けない。描画の窓を変えない 1 段がつまみの器へ書くのは `transform` と `aria-valuenow` だけになった。オーバーレイの props の
|
|
61
|
+
`thumbPosition` / `thumbCenter` は揃える前の厳密な値のまま。ドラッグとホバーの当たり判定は器の `top` を読まない (位置は
|
|
62
|
+
状態から、当たりは `getBoundingClientRect` から求め、平行移動を含む)。ウィンドウを持たない文書へ描くと、行ラッパーと同じく
|
|
63
|
+
つまみの取り付けで `Error` を投げる (同じ確定で両方が投げると React はまとめた `AggregateError` を投げる)。装置の画素比の
|
|
64
|
+
監視 (`(resolution: <比>dppx)` のメディアクエリ) はウィンドウごとに 1 つで、行ラッパーとつまみが共有する。
|
|
65
|
+
- **テスト**: `ScrollBar.spec.tsx` (つまみの位置を平行移動から読み、`top` / `left` が 0 であることを確かめる 2 件の改修)、
|
|
66
|
+
`externalScrollBridge.spec.tsx` (`scrollTo` が 1px 未満の差を積み上げないことの対比を整数の位置から始める 1 件の改修。
|
|
67
|
+
`scrollTo` は floor した位置へ厳密に着地するので、端数の位置 0.75 から 1.0 を求めると 1 へ 1 度だけ跳ぶ)、
|
|
68
|
+
`reducedMotion.spec.tsx` (部品をパッケージ自身のクラスで引く箇所に、規則のセレクタが名指すクラスそのものが検査の対象で
|
|
69
|
+
あるという例外の注記を付け、サークルの中かどうかの判定・グリッドのサークルとその器・セルは `data-*` で引く)、E2E
|
|
70
|
+
`scrollbar-handle-speed.spec.ts` (つまみの厳密な位置はデモのつまみのオーバーレイの印から読んで等速の CV を変えずに検査し、
|
|
71
|
+
描かれたつまみがそれから半装置画素 + レイアウトの単位 1 つ以内であることを全サンプルで確かめる。つまみの `top` が常に 0 に
|
|
72
|
+
なったため、従来の `top` の読み取りでは CV が 0 になり検査が空になるところだった)。
|
|
73
|
+
|
|
74
|
+
## 3.8.2 (2026-10-03)
|
|
75
|
+
|
|
76
|
+
### Fixed
|
|
77
|
+
|
|
78
|
+
- **動きを減らす設定で、パッケージが動かす部品をすべて止める**: `prefers-reduced-motion: reduce` では、配布 CSS の
|
|
79
|
+
ただ 1 つの規則が、パッケージが動かすすべての部品へ `transition: none !important; animation: none !important` を
|
|
80
|
+
宣言する。対象はタップスクロールサークル (バーとグリッド) とその中の全要素 (既定のビジュアル・
|
|
81
|
+
`tapScrollCircleSampleVisual`・消費側の `renderVisual`)、バーのサークルの器 (出入り)、矢印ボタン (色)、
|
|
82
|
+
スクロールバーのつまみ (ホバーとドラッグの太り。80ms と 60ms)、端へ戻るボタン (押下の縮みと地色。150ms) と
|
|
83
|
+
その覆い (出入り。500ms)。ビジュアルがインラインで書く 40〜260ms の遷移にも勝つ (カスケードは重要度をインライン
|
|
84
|
+
かどうかより先に比べる)。状態そのものは即座に切り替わる (つまみは太り、ボタンは押下で縮み、サークルは緩急なしで
|
|
85
|
+
ドラッグに追従する)。行と消費側の部品の遷移には触れない。Chromium 148 では、動きを減らす設定でこれらの部品と
|
|
86
|
+
サークルの中のインラインの遷移の `transition-duration` が 0.08〜0.5s から `0s` になり、行の中身が自分で持つ
|
|
87
|
+
0.2s の遷移はそのまま。パッケージの CSS を読み込まないホストでは遷移が残る。
|
|
88
|
+
- **テスト**: `scrollStepRepaint.spec.tsx` 4 件 (新規。行ラッパーのインラインの様式が top・平行移動・
|
|
89
|
+
`will-change: transform` の 3 つだけで `perspective` を持たないこと、配布 CSS が行ラッパーと行の器に
|
|
90
|
+
perspective・3D の文脈・filter を与えず行の器が transform を持たないこと、描画の窓を変えない 1 段の DOM の
|
|
91
|
+
書き込みがラッパーの `transform` だけであること、窓を 1 行ずらす 1 段は行の器の追加と削除だけで残る行へ
|
|
92
|
+
書き込まないこと) と `reducedMotion.spec.tsx` 5 件 (新規。動きを減らす設定の規則がただ 1 つで、そのセレクタが
|
|
93
|
+
同じファイルで遷移を宣言する部品のすべてとサークルの子孫にちょうど一致すること、既定のビジュアルと
|
|
94
|
+
`tapScrollCircleSampleVisual` の全要素が規則に一致しインラインの遷移が通常の重要度であること、一覧とグリッドの
|
|
95
|
+
全要素で規則に一致することと動く部品かサークルの中にあることが同値で、行・セル・バーの器・トラック・行ラッパーは
|
|
96
|
+
一致しないこと)。
|
|
97
|
+
|
|
98
|
+
### Notes
|
|
99
|
+
|
|
100
|
+
- **行ラッパーは 2D の平行移動だけの合成層のまま**: 行ラッパーは 3.8.1 と同じく `will-change: transform` だけを持つ。
|
|
101
|
+
`perspective` や 3D の変換は Chromium に描画の切り取り (表示領域を 4000px 広げた範囲) を外させるが、行を非 2D の
|
|
102
|
+
変換の下で合成させ、画素比によっては層ごと再標本化させる。ラッパーに `perspective: 16777216px` を置くと、
|
|
103
|
+
Chromium 148 で比 1.25 の明色では 420×708 の一覧の 111,871〜142,452 装置画素が 8 位置すべてで変わり、2px の
|
|
104
|
+
選択の輪と 2px のフォーカスの輪の間の帯が上下の辺で混ざった (一覧の終端では 4 辺とも)。比 1 の暗色でも 8 位置の
|
|
105
|
+
うち 4 位置で最大 107 画素が変わり、比 1.5・1.75・2・3 は同一だった。`will-change: transform` だけの層では、
|
|
106
|
+
1px の枠線・2px の輪・2px の隙間・2px のフォーカスの輪を持つ選択中の面が、比 1・1.25・1.5・1.75・2・3、明色と
|
|
107
|
+
暗色、8 位置 (0〜1,572,864.5px と 2 万行の終端) のすべての辺で、枠線の色の画素、floor(2 × 比) 個の輪の画素、
|
|
108
|
+
1 個までの混ざり、floor(2 × 比) 個の隙間の画素、floor(2 × 比) 個のフォーカスの輪の画素で描かれる。
|
|
109
|
+
- **窓をずらす 1 段の描き直しの費用**: 行をマウントしない 1 段 (8px) はラッパーの `transform` だけを書き、どの行も
|
|
110
|
+
描き直さない (描く層 0、PrePaint と Layerize で 0.4ms)。窓をずらす 1 段は行の器を足し引きするだけで残る行へ
|
|
111
|
+
書き込まないが、マウントで層が描き直しを要するので Chromium は描画の範囲をヒステリシス無しで今の位置へ置き直し
|
|
112
|
+
(`CullRectUpdater::ShouldProactivelyUpdate`)、中身が自分のはみ出しを切る残る行 (`kMayBeClippedByCullRect`) を
|
|
113
|
+
描き直す。Chromium 148 (1280×800・比 1・overscan 15・省略記号で終わる文の行。20 段 × 3 回の中央値) で、次の行を
|
|
114
|
+
選んで 1 行スクロールする 1 段は、高さ 160px の行で 36 層 (Paint 0.99ms、Paint・PrePaint・Layerize の和 2.6ms、
|
|
115
|
+
ラスター 3.7ms)、448px の行で 26 層 (0.66ms・1.9ms・2.6ms)。`perspective` を置いた場合は 160px の行で 6 層
|
|
116
|
+
(Paint 0.40ms) だった。
|
|
117
|
+
|
|
5
118
|
## 3.8.1 (2026-10-03)
|
|
6
119
|
|
|
7
120
|
### Fixed
|
package/README.md
CHANGED
|
@@ -139,29 +139,145 @@ leaves the viewport, or a list that ignores the wheel entirely).
|
|
|
139
139
|
|
|
140
140
|
The rows move inside one wrapper that is translated with `transform: translateY(…)` on its own compositor
|
|
141
141
|
layer (`will-change: transform`). That translate is snapped to the device-pixel grid of the window the list
|
|
142
|
-
is painted in
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
is painted in: whole CSS pixels at a ratio of 1, steps of 0.8 px at 1.25, 2/3 px at 1.5 and 0.5 px at 2.
|
|
143
|
+
Fractional scroll positions (trackpad and inertia deltas, centred alignment, fractional row heights or
|
|
144
|
+
insets) therefore never move the layer by a fraction of a device pixel. A layer moved by a fraction is
|
|
145
|
+
resampled as a whole: 2 px borders, outlines, focus rings and the gaps between them smear across
|
|
146
|
+
neighbouring pixel rows, and text blurs.
|
|
147
147
|
|
|
148
|
+
The snap keeps the edge the list is aligned to, so aligned content never loses part of its gutter to the
|
|
149
|
+
rounding:
|
|
150
|
+
|
|
151
|
+
| Where the list rests | Grid point | Result |
|
|
152
|
+
| --- | --- | --- |
|
|
153
|
+
| At position 0, or where the last `scrollToIndex` with `align: "top"` (the default, with or without `offset`) landed | At or after the exact translate: `Math.ceil(offset × ratio) / ratio` | The content never moves toward the viewport start, so the first row (or the aligned row, less its `offset`) never crosses it |
|
|
154
|
+
| At the maximum position, or where the last `scrollToIndex` with `align: "bottom"` landed | At or before the exact translate: `Math.floor(offset × ratio) / ratio` | The content never moves toward the viewport end, so the last row and the bottom inset (or the aligned row) never cross it |
|
|
155
|
+
| Anywhere else (a centred row, a scroll the user or the host started) | The nearest one: `Math.round(offset × ratio) / ratio` | At most half a device pixel either way |
|
|
156
|
+
|
|
157
|
+
- `scrollToIndex` lands exactly on the aligned position (clamped to the content), and a size change that
|
|
158
|
+
moves a pending alignment by more than 2^-10 px pins it again, so an aligned edge holds through fractional
|
|
159
|
+
row heights. A remembered alignment moves with the layout-shift compensation and the drift
|
|
160
|
+
correction that keep the aligned row in place, and any other scroll forgets it. Position 0 wins over the
|
|
161
|
+
maximum position (a list that does not scroll stays top-aligned), and both win over a remembered
|
|
162
|
+
alignment. A position within 2^-10 px of one of these counts as that position.
|
|
163
|
+
- Only the wrapper translate is snapped. The rows inside it paint at their exact layout positions, where
|
|
164
|
+
rounded borders, rings and outlines are anti-aliased, so a row starts on a whole device pixel only when the
|
|
165
|
+
sum of the row heights above it is a whole number of device pixels. A host that needs crisp row edges keeps
|
|
166
|
+
every row height on a lattice L with L × ratio a whole number: L = 4 px gives whole device pixels at every
|
|
167
|
+
ratio in quarter steps (1, 1.25, 1.5, 1.75, 2, …). Other zoom levels need other lattices (10 px at 1.1);
|
|
168
|
+
at a ratio the host's lattice does not fit, the rows keep their fractional positions.
|
|
169
|
+
- Every position the component reports (`onScroll`, `onRangeChange`, `onScrollAdjust`, `getScrollPosition()`,
|
|
170
|
+
`getScrollAnchor()`) stays exact. The rows are drawn less than one device pixel away from the exact scroll
|
|
171
|
+
position (at most half a device pixel where no edge is kept). `VirtualGrid` rows are drawn by the same
|
|
172
|
+
wrapper, so they are snapped vertically as well.
|
|
148
173
|
- The ratio comes from the window of the list's own document, and it is read while the wrapper renders.
|
|
149
174
|
Before the wrapper is attached, the component expects the window of the page that runs React, and the
|
|
150
175
|
attach confirms it. A list rendered into its own window's document is therefore snapped in its first
|
|
151
176
|
commit, with no extra render. A list rendered into an iframe or a second window switches to that
|
|
152
177
|
window's ratio when the wrapper attaches, with one extra synchronous render before the browser paints.
|
|
153
178
|
The ratio is read again whenever it changes (browser zoom, or moving the window to a screen of another
|
|
154
|
-
density), through
|
|
155
|
-
|
|
156
|
-
fractional positions inside a layer on whole pixels already), and every position the component reports
|
|
157
|
-
(`onScroll`, `onRangeChange`, `getScrollPosition()`, `getScrollAnchor()`) stays exact. The rows are drawn
|
|
158
|
-
at most half a device pixel away from the exact scroll position. `VirtualGrid` rows are drawn by the same
|
|
159
|
-
wrapper, so they are snapped vertically as well.
|
|
179
|
+
density), through one `(resolution: <ratio>dppx)` media query per window, shared by the wrappers and the
|
|
180
|
+
scrollbar thumbs painted there.
|
|
160
181
|
- Server-rendered HTML carries the exact offset, since there is no screen on the server. Hydration renders
|
|
161
182
|
the same exact offset, so it reports no mismatch, and the snapped offset replaces it right after hydration.
|
|
162
183
|
- Rendering into a document without a window (for example one made with
|
|
163
|
-
`document.implementation.createHTMLDocument()`) throws when the wrapper
|
|
164
|
-
so there is no ratio to snap to.
|
|
184
|
+
`document.implementation.createHTMLDocument()`) throws when the wrapper or a scrollbar thumb attaches:
|
|
185
|
+
nothing is painted there, so there is no ratio to snap to.
|
|
186
|
+
|
|
187
|
+
## What a scroll step paints
|
|
188
|
+
|
|
189
|
+
The items wrapper is a plain compositor layer: `will-change: transform`, moved by a 2D translate that is
|
|
190
|
+
snapped to the device-pixel grid (see above), with nothing that takes its subtree out of 2D compositing.
|
|
191
|
+
Measured in Chromium 148 (1280×800, ratio 1, overscan 15, rows whose text ends in an ellipsis; 20 steps,
|
|
192
|
+
3 runs, median of the run medians):
|
|
193
|
+
|
|
194
|
+
- A step that mounts no row writes only the wrapper's `transform` and repaints no row. An 8 px step paints
|
|
195
|
+
0 layers; PrePaint and Layerize take 0.4 ms.
|
|
196
|
+
- A step that shifts the rendering window adds and removes row containers and writes nothing to the rows it
|
|
197
|
+
keeps, yet Chromium repaints the kept rows whose content clips its own overflow (an ellipsis, a card with
|
|
198
|
+
`overflow: hidden`). A mount makes the layer need a repaint, so Chromium re-centres the area it paints the
|
|
199
|
+
layer in (the visible area grown by 4000 px) without its usual hysteresis
|
|
200
|
+
(`CullRectUpdater::ShouldProactivelyUpdate`), and every row painted with `kMayBeClippedByCullRect` is
|
|
201
|
+
repainted. Selecting the next row and scrolling one row paints 36 layers with 160 px rows (Paint 0.99 ms;
|
|
202
|
+
Paint, PrePaint and Layerize 2.6 ms; raster 3.7 ms) and 26 layers with 448 px rows (0.66 ms, 1.9 ms,
|
|
203
|
+
2.6 ms).
|
|
204
|
+
- The wrapper declares no `perspective` and no 3D transform, although either would make Chromium paint the
|
|
205
|
+
subtree without that area: the rows would then be composited under a non-2D transform, which Chromium
|
|
206
|
+
resamples at some ratios. With `perspective: 16777216px` on the wrapper, at ratio 1.25 in a light theme
|
|
207
|
+
111,871 to 142,452 device pixels of a 420×708 list changed at each of 8 offsets, and the band between a
|
|
208
|
+
2 px selection ring and a 2 px focus outline blended on the top and bottom edges (on all four edges at the
|
|
209
|
+
end of the list); at ratio 1 in a dark theme up to 107 pixels changed at 4 of the 8 offsets. Ratios 1.5,
|
|
210
|
+
1.75, 2 and 3 were identical. The same step would have painted 6 layers (Paint 0.40 ms).
|
|
211
|
+
- With the plain layer, a selected row whose surface has a 1 px border, a 2 px ring, a 2 px gap and a 2 px
|
|
212
|
+
outline renders on every side, at ratios 1, 1.25, 1.5, 1.75, 2 and 3, light and dark, and at 8 offsets
|
|
213
|
+
(0 to 1,572,864.5 px and the end of a 20,000-row list), as a full border pixel, floor(2 × ratio) ring
|
|
214
|
+
pixels, at most one blended pixel, floor(2 × ratio) gap pixels and floor(2 × ratio) outline pixels.
|
|
215
|
+
- The scrollbar thumb moves the same way. Its wrapper stays at `top: 0` (`left: 0` on a horizontal bar) and is
|
|
216
|
+
moved by a 2D translate (`translateY`, `translateX` on a horizontal bar) snapped to the same device-pixel
|
|
217
|
+
grid, with no transition, so a step writes only that `transform` and the slider's `aria-valuenow`, and the
|
|
218
|
+
thumb adds no layout. A thumb positioned by `top` adds a layout from the document root to every step: in
|
|
219
|
+
Chromium, 60 steps of 40 px that kept the rendering window (200,000 rows of 160 px inside nested flex
|
|
220
|
+
columns beside a 600-row sidebar) ran 60 layouts in 13.9 ms with the thumb moved by `top`, and 30 layouts in
|
|
221
|
+
9.1 ms with the thumb held still. `thumbPosition` in the `renderThumbOverlay` props stays the exact,
|
|
222
|
+
unsnapped offset.
|
|
223
|
+
|
|
224
|
+
## Position changes the list makes on its own
|
|
225
|
+
|
|
226
|
+
`onScroll` and `onRangeChange` report every position, throttled (`callbackThrottleMs`) and one animation frame
|
|
227
|
+
late. Four moves are made by the list itself, without a scroll from the user or the host, and `onScrollAdjust`
|
|
228
|
+
reports each of them synchronously and unthrottled once it is complete: `getScrollPosition()` and
|
|
229
|
+
`getScrollAnchor()` read inside the callback already return the moved position and the new row heights.
|
|
230
|
+
|
|
231
|
+
| `cause` | The move | When it runs |
|
|
232
|
+
| --- | --- | --- |
|
|
233
|
+
| `"item-resize"` | `updateItemSize` changed a row above the first visible row, and the position moved by the same delta, so the visible rows stay where they were | Inside `updateItemSize`, before it returns |
|
|
234
|
+
| `"reconciliation"` | A render found a new `getItemHeight` value for a rendered row above the first visible row, and the position moved by the same delta | In the microtask after that render |
|
|
235
|
+
| `"drift"` | After a size change (content, viewport, item count or insets), the pending alignment of the last `scrollToIndex` (or of `initialScrollAnchor`) was pinned again | In an effect after the commit |
|
|
236
|
+
| `"re-issue"` | A compensation that the pane clamped against the previous content size (several compensations in one batch near the end of the list) was issued again once the new size had committed | In an effect after the commit |
|
|
237
|
+
|
|
238
|
+
The argument is `{ position, delta, cause }` (`VirtualScrollAdjustment`): `position` is the **logical**
|
|
239
|
+
position after the move, what `getScrollPosition()` returns, and `delta` is the change the move applied to it
|
|
240
|
+
(never 0). Scrolls the user or the host start (wheel, drags and their inertia, the scrollbar, keyboard row
|
|
241
|
+
navigation, `scrollTo` / `scrollBy` / `scrollToIndex` / `applyWheel`) are not reported here, and neither is a
|
|
242
|
+
change that leaves `getScrollPosition()` where it was (a top-inset change keeps the logical position).
|
|
243
|
+
|
|
244
|
+
A host that keeps its own scroll anchor by item identity, re-finding the first visible item by key after a
|
|
245
|
+
list change (rows inserted or removed above it), records that anchor from `onRangeChange` and after its own
|
|
246
|
+
scrolls. It must also re-record it from `onScrollAdjust`. Otherwise a list change committed before the next
|
|
247
|
+
range report restores a position the list has already moved, and the view shifts by the compensation or
|
|
248
|
+
lands on a neighbouring item.
|
|
249
|
+
|
|
250
|
+
```tsx
|
|
251
|
+
const recordAnchor = () => {
|
|
252
|
+
const anchor = listRef.current?.getScrollAnchor()
|
|
253
|
+
if (anchor) anchorRef.current = { key: keyOf(anchor.index), offsetPx: anchor.offsetPx }
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
<VirtualScroll ref={listRef} onRangeChange={recordAnchor} onScrollAdjust={recordAnchor} {...props}>
|
|
257
|
+
{renderRow}
|
|
258
|
+
</VirtualScroll>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Reduced motion
|
|
262
|
+
|
|
263
|
+
Under `prefers-reduced-motion: reduce`, every part that the package animates changes state without a
|
|
264
|
+
transition or an animation. One rule in the shipped stylesheet sets
|
|
265
|
+
`transition: none !important; animation: none !important` on:
|
|
266
|
+
|
|
267
|
+
- the tap scroll circle (the bar's and the grid's) and every element inside it: the default visual,
|
|
268
|
+
`tapScrollCircleSampleVisual` or your own `renderVisual`. Their inline transitions lose to `!important`,
|
|
269
|
+
because the cascade compares importance before it considers the `style` attribute;
|
|
270
|
+
- the bar's circle wrapper (its fade);
|
|
271
|
+
- the arrow buttons (their colour fade);
|
|
272
|
+
- the scrollbar thumb (its thickening on hover and while dragged, 80 ms and 60 ms);
|
|
273
|
+
- the scroll-to-edge buttons (their shrink while pressed and their background fade, 150 ms) and their
|
|
274
|
+
overlay (its fade, 500 ms).
|
|
275
|
+
|
|
276
|
+
The states themselves still change, at once: the thumb still thickens on hover and while dragged, an edge
|
|
277
|
+
button still shrinks while pressed, and the circle follows the drag without easing. Rows and everything you
|
|
278
|
+
render in them keep their own transitions. A host that does not load the package stylesheet keeps the
|
|
279
|
+
transitions. In Chromium 148 the computed `transition-duration` of these parts drops from 0.08–0.5 s to
|
|
280
|
+
`0s`, while a row's own 0.2 s transition stays 0.2 s.
|
|
165
281
|
|
|
166
282
|
## Horizontal Scrolling
|
|
167
283
|
|
|
@@ -668,11 +784,12 @@ exists in the DOM.
|
|
|
668
784
|
| `getItemHeight` | `(index: number) => number` | ✅ | Function to get item height |
|
|
669
785
|
| `viewportSize` | `number` | ❌ | Height of the visible band. **Omit it** — the component then measures its host with a `ResizeObserver`. Pass it only when you know the band by calculation rather than measurement (e.g. a dropdown sized from row count × row height). See [Sizing](#sizing) |
|
|
670
786
|
| `overscanCount` | `number` | ❌ | Number of items to render outside viewport (default: 15) |
|
|
671
|
-
| `className` | `string` | ❌ | CSS class name. Lands on the scroll root (`.aqvs-scroll-pane`) — see [Custom
|
|
787
|
+
| `className` | `string` | ❌ | CSS class name. Lands on the scroll root (`.aqvs-scroll-pane`) — see [Custom styling](#custom-styling) |
|
|
672
788
|
| `getItemKey` | `(index: number) => React.Key` | ❌ | Stable React key per index (defaults to the index) |
|
|
673
789
|
| `testId` | `string` | ❌ | Emitted as `data-testid` on the scroll root. DOM hooks should use `data-*`, never class selectors |
|
|
674
790
|
| `onScroll` | `(position: number, totalHeight: number) => void` | ❌ | Scroll event handler |
|
|
675
791
|
| `onRangeChange` | `(range: VirtualScrollRange) => void` | ❌ | Range change handler |
|
|
792
|
+
| `onScrollAdjust` | `(adjustment: VirtualScrollAdjustment) => void` | ❌ | Called synchronously, without throttling, each time the list moves its own scroll position (layout-shift compensation, the re-pinning of a pending alignment, the second stage of a clamped compensation). `adjustment` is `{ position, delta, cause }` in **logical** px, and handle reads inside the callback already see the adjusted state. Never called for scrolls the user or the host start. See [Position changes the list makes on its own](#position-changes-the-list-makes-on-its-own) |
|
|
676
793
|
| `onWheelHorizontal` | `(deltaX: number) => void` | ❌ | Opt-in horizontal delegation. Horizontal-dominant wheel / trackpad gestures (and shift+wheel) are delegated to this handler so the parent can implement horizontal scrolling. ⚠️ **Keyboard deltas arrive here too** when `horizontalKeyInputs` is set. When omitted, horizontal gestures bypass vertical scrolling so parent native scrolling works. See [Horizontal Scrolling](#horizontal-scrolling). |
|
|
677
794
|
| `onPanHorizontal` | `(deltaX: number) => void` | ❌ | Opt-in delegation of the horizontal component of pointer pans (touch / pen drags) — the pan twin of `onWheelHorizontal` with the same sign convention, per-move increments divided by the press-time x-axis ancestor scale (3.2.0). When set, purely horizontal pans also activate the drag. Same seal family as `onWheelHorizontal` — wrappers sealing the horizontal axis must `Omit` this name too. |
|
|
678
795
|
| `horizontalKeyInputs` | `readonly "arrow"[]` | ❌ | Keyboard gestures that emit a horizontal delta through `onWheelHorizontal` (default: `[]`, so row-level arrow handling is never stolen). `Shift + ←/→` is never consumed. Fires only when the row itself is the event target. ⚠️ Requires `behaviorOptions.enableKeyboardNavigation` (default `true`) — with it off the rows have no key handler at all and this prop does nothing (the package warns) |
|
|
@@ -726,7 +843,7 @@ exists in the DOM.
|
|
|
726
843
|
| `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 |
|
|
727
844
|
| `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` |
|
|
728
845
|
| *(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 |
|
|
729
|
-
| `scrollToIndex` | `(index: number, options?: { align?: "top" \| "bottom" \| "center"; offset?: number }) => void` | Scroll to specific item index with optional alignment and offset |
|
|
846
|
+
| `scrollToIndex` | `(index: number, options?: { align?: "top" \| "bottom" \| "center"; offset?: number }) => void` | Scroll to specific item index with optional alignment and offset. Lands exactly on the aligned position (clamped to the content); a `"top"` (default) or `"bottom"` alignment is remembered there, so the device-pixel snap keeps that edge — see [Device-pixel snapping](#device-pixel-snapping) |
|
|
730
847
|
| `getScrollPosition` | `() => number` | Get current **logical** scroll position (2.0.0; `-1` when the pane is not connected) |
|
|
731
848
|
| `getContentSize` | `() => number` | Get total content size (insets included). Returns the `-1` sentinel while the pane is unconnected |
|
|
732
849
|
| `getViewportSize` | `() => number` | Get viewport size. Returns the `-1` sentinel while the pane is unconnected |
|
|
@@ -735,7 +852,7 @@ exists in the DOM.
|
|
|
735
852
|
| `getScrollAnchor` | `() => { index: number; offsetPx: number } \| null` | Capture the current top visible row anchor for exact restore via `initialScrollAnchor` (`null` when `itemCount` is 0) |
|
|
736
853
|
| `getFenwickTreeTotalHeight` | `() => number` | Total content height managed by the Fenwick tree (insets excluded) |
|
|
737
854
|
| `getFenwickSize` | `() => number` | Item count managed by the Fenwick tree |
|
|
738
|
-
| `updateItemSize` | `(index: number, size: number) => void` | Manually update one item's size (with layout-shift compensation). `getItemHeight(index)` must return the same value afterwards |
|
|
855
|
+
| `updateItemSize` | `(index: number, size: number) => void` | Manually update one item's size (with layout-shift compensation: a row above the first visible row moves the position by the same delta before this returns, reported through `onScrollAdjust` as `"item-resize"`). `getItemHeight(index)` must return the same value afterwards |
|
|
739
856
|
|
|
740
857
|
**Coordinate system (2.0.0)**: every position the handle and callbacks accept or return is
|
|
741
858
|
**logical** (content px, insets excluded) — `onScroll` / `onRangeChange` / `initialScroll*` /
|
|
@@ -852,10 +969,11 @@ function AdvancedExample() {
|
|
|
852
969
|
}
|
|
853
970
|
```
|
|
854
971
|
|
|
855
|
-
### Custom
|
|
972
|
+
### Custom styling
|
|
856
973
|
|
|
857
|
-
`className` lands on the **scroll root** (`.aqvs-scroll-pane`). The
|
|
858
|
-
|
|
974
|
+
`className` lands on the **scroll root** (`.aqvs-scroll-pane`). The rows, the bar with its track, thumb and
|
|
975
|
+
arrow buttons, the scroll-to-edge pills and the empty-state message are all descendants of that element, so
|
|
976
|
+
one wrapper class reaches every part:
|
|
859
977
|
|
|
860
978
|
```tsx
|
|
861
979
|
<VirtualScroll
|
|
@@ -885,6 +1003,9 @@ and the scroll-to-edge pills are all descendants of that element, so one wrapper
|
|
|
885
1003
|
.custom-virtual-scroll .aqvs-scrollbar-arrow-button:enabled:hover { background-color: #cfe8f7; }
|
|
886
1004
|
.custom-virtual-scroll .aqvs-scroll-to-edge-button { background-color: rgba(0, 122, 204, 0.85); }
|
|
887
1005
|
.custom-virtual-scroll .aqvs-scroll-to-edge-button:hover { background-color: rgba(0, 92, 153, 0.9); }
|
|
1006
|
+
|
|
1007
|
+
/* The empty state (itemCount 0). Restate the colour on a dark background: the default #6b7280 reaches 4.5:1 only on a light one. */
|
|
1008
|
+
.custom-virtual-scroll .aqvs-no-items-text { color: #94a3b8; padding-block: 1rem; }
|
|
888
1009
|
```
|
|
889
1010
|
|
|
890
1011
|
The packaged rules live in `@layer components` in **both** artifacts, so an ordinary (unlayered) rule in
|
|
@@ -916,11 +1037,28 @@ Three consequences are worth knowing:
|
|
|
916
1037
|
users. Forcing `opacity: 1` on the hidden overlay therefore paints a pill that cannot be clicked or focused.
|
|
917
1038
|
Scope such rules to `[data-visible="true"]` as well.
|
|
918
1039
|
|
|
919
|
-
The
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1040
|
+
The styling hooks are the classes below. Each one is rendered on the part it names, and renaming or
|
|
1041
|
+
removing one is a breaking change:
|
|
1042
|
+
|
|
1043
|
+
| Class | Part |
|
|
1044
|
+
| --- | --- |
|
|
1045
|
+
| `.aqvs-scroll-pane` | The scroll root, where `className` lands |
|
|
1046
|
+
| `.aqvs-scroll-pane-content` | The row viewport |
|
|
1047
|
+
| `.aqvs-item-container` | Each row's container |
|
|
1048
|
+
| `.aqvs-no-items-container` | The empty state (`itemCount` 0): the box at the top of the viewport |
|
|
1049
|
+
| `.aqvs-no-items-text` | The empty state's message (`labels.noItems`), centred, `color: #6b7280` |
|
|
1050
|
+
| `.aqvs-scrollbar` | The bar (`role="scrollbar"`) |
|
|
1051
|
+
| `.aqvs-scrollbar-vertical` | A vertical bar |
|
|
1052
|
+
| `.aqvs-scrollbar-horizontal` | A horizontal bar |
|
|
1053
|
+
| `.aqvs-scrollbar-track` | The track behind the thumb |
|
|
1054
|
+
| `.aqvs-scrollbar-thumb-wrapper` | The thumb's wrapper (`role="slider"`); the package positions it with an inline translate |
|
|
1055
|
+
| `.aqvs-scrollbar-thumb` | The thumb, with `data-thumb-state` |
|
|
1056
|
+
| `.aqvs-scrollbar-thumb-vertical` | The thumb of a vertical bar |
|
|
1057
|
+
| `.aqvs-scrollbar-thumb-horizontal` | The thumb of a horizontal bar |
|
|
1058
|
+
| `.aqvs-scrollbar-arrow-button` | The arrow buttons |
|
|
1059
|
+
| `.aqvs-scroll-to-edge-overlay` | The scroll-to-edge pills' overlay (`enableScrollToTopBottomButtons`) |
|
|
1060
|
+
| `.aqvs-scroll-to-edge-button` | A scroll-to-edge pill |
|
|
1061
|
+
| `.aqvs-tap-scroll-circle` | The tap scroll circle |
|
|
924
1062
|
|
|
925
1063
|
### Tap Scroll Circle Configuration
|
|
926
1064
|
|
|
@@ -940,6 +1078,8 @@ The auxiliary tap scroll circle can replace the native scrollbar for large datas
|
|
|
940
1078
|
- **Per-pointer drag control**: `behaviorOptions.pointerDragInputs` restricts content drag-scrolling to specific pointer types, e.g. `["pen", "touch"]` to keep touch scrolling while freeing the mouse for text selection. Do **not** use `enablePointerDrag: false` for that — the pane has no native scroller, so disabling drag removes the only way to scroll on touch devices.
|
|
941
1079
|
- **Full layout control** (`size`, `offsetX`, `offsetY`) keeps the circle accessible on both desktop and touch devices.
|
|
942
1080
|
- **Visibility tuning** exposes an `opacity` knob so you can match subdued or high-contrast UI themes.
|
|
1081
|
+
- **Reduced motion**: the circle and every element inside it follow the package-wide rule in
|
|
1082
|
+
[Reduced motion](#reduced-motion).
|
|
943
1083
|
|
|
944
1084
|
```tsx
|
|
945
1085
|
import { VirtualScroll } from "@aiquants/virtualscroll"
|
package/dist/ScrollBar.d.cts
CHANGED
|
@@ -296,9 +296,15 @@ export declare const computeTapScrollSpeed: ({ distance, maxDistance, viewportSi
|
|
|
296
296
|
*/
|
|
297
297
|
export declare const computeAutoTapScrollMaxSpeedMultiplier: (itemCount?: number) => number;
|
|
298
298
|
/**
|
|
299
|
-
* A custom scrollbar component.
|
|
299
|
+
* A custom scrollbar component. The thumb wrapper stays at the start of the track (`top: 0; left: 0`) and moves along it
|
|
300
|
+
* by a 2D translate snapped to the device-pixel grid of the window that paints it, so a scroll step rewrites only that
|
|
301
|
+
* transform and runs no layout. `thumbPosition` in the overlay props stays the exact, unsnapped offset. Rendering into a
|
|
302
|
+
* document without a window throws when the thumb attaches (there is no device-pixel ratio to snap to).
|
|
300
303
|
*
|
|
301
|
-
*
|
|
304
|
+
* カスタムスクロールバーコンポーネント。つまみの器はトラックの始端 (`top: 0; left: 0`) に置いたまま、描くウィンドウの装置の
|
|
305
|
+
* 画素の格子へ揃えた 2D の平行移動でトラックに沿って動くので、スクロールの 1 段が書き換えるのはその transform だけで、
|
|
306
|
+
* レイアウトは走らない。オーバーレイの props の `thumbPosition` は揃える前の厳密なオフセットのまま。ウィンドウを持たない
|
|
307
|
+
* 文書へ描くと、つまみの取り付けで例外を投げる (揃える装置の画素比が無い)。
|
|
302
308
|
*/
|
|
303
309
|
export declare const ScrollBar: ({ contentSize, viewportSize, scrollPosition, onScroll, enableThumbDrag, enableTrackClick, enableArrowButtons, enableArrowButtonTabStops, horizontal, enableHorizontalTapCircle, stretchMainSize, scrollBarWidth, className, ariaControls, tapScrollCircleOptions, itemCount, renderThumbOverlay, visibleStartIndex, visibleEndIndex, locale, labels, }: ScrollBarProps) => import("react").JSX.Element;
|
|
304
310
|
export {};
|
package/dist/ScrollBar.d.ts
CHANGED
|
@@ -296,9 +296,15 @@ export declare const computeTapScrollSpeed: ({ distance, maxDistance, viewportSi
|
|
|
296
296
|
*/
|
|
297
297
|
export declare const computeAutoTapScrollMaxSpeedMultiplier: (itemCount?: number) => number;
|
|
298
298
|
/**
|
|
299
|
-
* A custom scrollbar component.
|
|
299
|
+
* A custom scrollbar component. The thumb wrapper stays at the start of the track (`top: 0; left: 0`) and moves along it
|
|
300
|
+
* by a 2D translate snapped to the device-pixel grid of the window that paints it, so a scroll step rewrites only that
|
|
301
|
+
* transform and runs no layout. `thumbPosition` in the overlay props stays the exact, unsnapped offset. Rendering into a
|
|
302
|
+
* document without a window throws when the thumb attaches (there is no device-pixel ratio to snap to).
|
|
300
303
|
*
|
|
301
|
-
*
|
|
304
|
+
* カスタムスクロールバーコンポーネント。つまみの器はトラックの始端 (`top: 0; left: 0`) に置いたまま、描くウィンドウの装置の
|
|
305
|
+
* 画素の格子へ揃えた 2D の平行移動でトラックに沿って動くので、スクロールの 1 段が書き換えるのはその transform だけで、
|
|
306
|
+
* レイアウトは走らない。オーバーレイの props の `thumbPosition` は揃える前の厳密なオフセットのまま。ウィンドウを持たない
|
|
307
|
+
* 文書へ描くと、つまみの取り付けで例外を投げる (揃える装置の画素比が無い)。
|
|
302
308
|
*/
|
|
303
309
|
export declare const ScrollBar: ({ contentSize, viewportSize, scrollPosition, onScroll, enableThumbDrag, enableTrackClick, enableArrowButtons, enableArrowButtonTabStops, horizontal, enableHorizontalTapCircle, stretchMainSize, scrollBarWidth, className, ariaControls, tapScrollCircleOptions, itemCount, renderThumbOverlay, visibleStartIndex, visibleEndIndex, locale, labels, }: ScrollBarProps) => import("react").JSX.Element;
|
|
304
310
|
export {};
|
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;
|
|
1
|
+
{"version":3,"file":"ScrollBar.d.ts","sourceRoot":"","sources":["../src/ScrollBar.tsx"],"names":[],"mappings":"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"}
|