@aiquants/virtualscroll 3.8.2 → 3.9.1
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 +82 -0
- package/README.md +112 -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 +2145 -2093
- package/package.json +1 -1
- package/src/ScrollBar.tsx +24 -8
- package/src/VirtualScroll.tsx +341 -200
- package/src/devicePixelGrid.ts +308 -0
- package/src/index.ts +2 -0
package/package.json
CHANGED
package/src/ScrollBar.tsx
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import type { CSSProperties, ReactNode } from "react"
|
|
7
7
|
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"
|
|
8
8
|
import { twMerge } from "tailwind-merge"
|
|
9
|
+
import { snapToDevicePixelGrid, usePaintingDevicePixelRatio } from "./devicePixelGrid.ts"
|
|
9
10
|
import { resolveVirtualScrollLabels, type VirtualScrollLabelOverrides, type VirtualScrollLocale } from "./labels.ts"
|
|
10
11
|
import { Logger } from "./logger.ts"
|
|
11
12
|
import { capturePointer, releaseCapturedPointer } from "./pointerCapture.ts"
|
|
@@ -20,7 +21,8 @@ import { getAxisScale, minmax } from "./utils.ts"
|
|
|
20
21
|
type OrientationConfig = {
|
|
21
22
|
mainSizeKey: "width" | "height"
|
|
22
23
|
crossSizeKey: "width" | "height"
|
|
23
|
-
|
|
24
|
+
/** The transform function that moves the thumb along the bar / つまみをバーに沿って動かす変換の関数 */
|
|
25
|
+
thumbTranslateFunction: "translateX" | "translateY"
|
|
24
26
|
selectDelta: (deltaX: number, deltaY: number) => number
|
|
25
27
|
getPointerCoordinate: (point: { clientX: number; clientY: number }) => number
|
|
26
28
|
arrowIcons: [string, string]
|
|
@@ -302,7 +304,7 @@ const createOrientationConfig = (horizontal: boolean): OrientationConfig => {
|
|
|
302
304
|
return {
|
|
303
305
|
mainSizeKey: "width",
|
|
304
306
|
crossSizeKey: "height",
|
|
305
|
-
|
|
307
|
+
thumbTranslateFunction: "translateX",
|
|
306
308
|
selectDelta: (deltaX: number, _deltaY: number) => deltaX,
|
|
307
309
|
getPointerCoordinate: ({ clientX }) => clientX,
|
|
308
310
|
arrowIcons: ["◀", "▶"],
|
|
@@ -314,7 +316,7 @@ const createOrientationConfig = (horizontal: boolean): OrientationConfig => {
|
|
|
314
316
|
return {
|
|
315
317
|
mainSizeKey: "height",
|
|
316
318
|
crossSizeKey: "width",
|
|
317
|
-
|
|
319
|
+
thumbTranslateFunction: "translateY",
|
|
318
320
|
selectDelta: (_deltaX: number, deltaY: number) => deltaY,
|
|
319
321
|
getPointerCoordinate: ({ clientY }) => clientY,
|
|
320
322
|
arrowIcons: ["▲", "▼"],
|
|
@@ -633,9 +635,15 @@ export const computeAutoTapScrollMaxSpeedMultiplier = (itemCount?: number) => {
|
|
|
633
635
|
}
|
|
634
636
|
|
|
635
637
|
/**
|
|
636
|
-
* A custom scrollbar component.
|
|
638
|
+
* A custom scrollbar component. The thumb wrapper stays at the start of the track (`top: 0; left: 0`) and moves along it
|
|
639
|
+
* by a 2D translate snapped to the device-pixel grid of the window that paints it, so a scroll step rewrites only that
|
|
640
|
+
* transform and runs no layout. `thumbPosition` in the overlay props stays the exact, unsnapped offset. Rendering into a
|
|
641
|
+
* document without a window throws when the thumb attaches (there is no device-pixel ratio to snap to).
|
|
637
642
|
*
|
|
638
|
-
*
|
|
643
|
+
* カスタムスクロールバーコンポーネント。つまみの器はトラックの始端 (`top: 0; left: 0`) に置いたまま、描くウィンドウの装置の
|
|
644
|
+
* 画素の格子へ揃えた 2D の平行移動でトラックに沿って動くので、スクロールの 1 段が書き換えるのはその transform だけで、
|
|
645
|
+
* レイアウトは走らない。オーバーレイの props の `thumbPosition` は揃える前の厳密なオフセットのまま。ウィンドウを持たない
|
|
646
|
+
* 文書へ描くと、つまみの取り付けで例外を投げる (揃える装置の画素比が無い)。
|
|
639
647
|
*/
|
|
640
648
|
export const ScrollBar = ({
|
|
641
649
|
contentSize,
|
|
@@ -714,7 +722,7 @@ export const ScrollBar = ({
|
|
|
714
722
|
onScroll,
|
|
715
723
|
scrollPosition,
|
|
716
724
|
})
|
|
717
|
-
const { mainSizeKey, crossSizeKey,
|
|
725
|
+
const { mainSizeKey, crossSizeKey, thumbTranslateFunction, selectDelta, getPointerCoordinate, arrowIcons, directionClass, orientation } = orientationConfig
|
|
718
726
|
const effectiveTapMaxDistance = Math.max(tapCircleMaxDistance, 1)
|
|
719
727
|
// 表示領域に対するコンテンツの比率
|
|
720
728
|
const scrollRatio = viewportSize / contentSize
|
|
@@ -730,6 +738,11 @@ export const ScrollBar = ({
|
|
|
730
738
|
// サムがトラック外へはみ出さないよう、レンダー時に [0, effectiveTrackLength] へクランプする。
|
|
731
739
|
const thumbPosition = maxScrollPosition <= 0 || effectiveTrackLength <= 0 ? 0 : minmax((scrollPosition / maxScrollPosition) * effectiveTrackLength, 0, effectiveTrackLength)
|
|
732
740
|
const thumbCenter = thumbPosition + thumbSize / 2
|
|
741
|
+
const { ratio: thumbPaintingRatio, attach: attachThumbWrapper } = usePaintingDevicePixelRatio("[ScrollBar] the thumb")
|
|
742
|
+
// ❗ つまみは top / left ではなく平行移動で動かす。top / left の書き換えは、描画の窓を変えないスクロールの 1 段にも文書の根からの
|
|
743
|
+
// レイアウトを 1 回足す (実測: 40px の段 60 回で Layout 60 → 30 回、13.9 → 9.1 ms)。平行移動は装置の画素の格子へ揃えて縁を
|
|
744
|
+
// 滲ませず、つまみの長さはどの位置でも同じ装置の画素の数になる
|
|
745
|
+
const thumbTranslate = thumbPaintingRatio === null ? thumbPosition : snapToDevicePixelGrid(thumbPosition, thumbPaintingRatio, "none")
|
|
733
746
|
|
|
734
747
|
// スクロールバーが表示されるかどうか
|
|
735
748
|
const scrollBarVisible = contentSize > viewportSize || isDragging
|
|
@@ -1581,11 +1594,14 @@ export const ScrollBar = ({
|
|
|
1581
1594
|
{/* DOMの再生成を防ぐため、常にレンダリングしてスタイルで表示制御を行う */}
|
|
1582
1595
|
<div
|
|
1583
1596
|
key="thumb-wrapper"
|
|
1597
|
+
ref={attachThumbWrapper}
|
|
1584
1598
|
className="aqvs-scrollbar-thumb-wrapper"
|
|
1585
1599
|
style={{
|
|
1586
1600
|
[mainSizeKey]: thumbSize,
|
|
1587
|
-
|
|
1588
|
-
|
|
1601
|
+
top: 0,
|
|
1602
|
+
left: 0,
|
|
1603
|
+
...(horizontal ? { bottom: 0 } : { right: 0 }),
|
|
1604
|
+
transform: `${thumbTranslateFunction}(${thumbTranslate}px)`,
|
|
1589
1605
|
}}
|
|
1590
1606
|
// ルート同様、非表示はパッケージ CSS の [data-visible="false"] が担う
|
|
1591
1607
|
data-visible={scrollBarVisible || isDragging ? "true" : "false"}
|