@aiquants/virtualscroll 1.18.0 → 1.18.2
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/README.md +55 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ High-performance virtual scrolling component for React with variable item height
|
|
|
10
10
|
- 🎯 **Precise Scrolling**: Accurate scroll positioning and smooth navigation
|
|
11
11
|
<!-- - 🔄 **LRU Caching**: Built-in cache for optimal memory usage -->
|
|
12
12
|
- 📱 **Touch Support**: Full support for touch devices
|
|
13
|
+
- ↔️ **Horizontal Delegation**: Opt-in `onWheelHorizontal` hands horizontal wheel / trackpad (and shift+wheel) gestures to the parent — build frozen-column data grids
|
|
13
14
|
- 🎨 **Customizable**: Flexible styling and theming options
|
|
14
15
|
- 🌀 **Ultrafast Tap Scroll**: Adaptive tap scroll circle that scales speed up to 120× for massive datasets
|
|
15
16
|
- 🔧 **TypeScript**: Full TypeScript support with comprehensive type definitions
|
|
@@ -76,6 +77,59 @@ function App() {
|
|
|
76
77
|
}
|
|
77
78
|
```
|
|
78
79
|
|
|
80
|
+
## Horizontal Scrolling
|
|
81
|
+
|
|
82
|
+
`VirtualScroll` virtualizes and scrolls the **vertical** axis only. To add a horizontal axis — e.g. a
|
|
83
|
+
data grid whose columns extend past the viewport — pass `onWheelHorizontal`. Horizontal-dominant
|
|
84
|
+
wheel / trackpad gestures (and shift+wheel) are then delegated to your handler, which drives a
|
|
85
|
+
horizontal offset you own. Vertical scrolling is untouched, and omitting the prop keeps the exact
|
|
86
|
+
previous behavior (backward compatible).
|
|
87
|
+
|
|
88
|
+
A common pattern freezes a left column and translates the remaining columns via a shared CSS
|
|
89
|
+
variable (so rows don't re-render on horizontal scroll), reusing the package's `ScrollBar` with the
|
|
90
|
+
`horizontal` prop for the bottom bar:
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { ScrollBar, VirtualScroll } from '@aiquants/virtualscroll'
|
|
94
|
+
import { useCallback, useState } from 'react'
|
|
95
|
+
|
|
96
|
+
const clamp = (v: number, max: number) => Math.max(0, Math.min(v, max))
|
|
97
|
+
|
|
98
|
+
function Grid() {
|
|
99
|
+
const [hscroll, setHscroll] = useState(0)
|
|
100
|
+
const maxHScroll = /* contentWidth - visibleWidth */ 632
|
|
101
|
+
const onWheelHorizontal = useCallback((dx: number) => setHscroll((h) => clamp(h + dx, maxHScroll)), [maxHScroll])
|
|
102
|
+
|
|
103
|
+
// `--hx` on the container is inherited by every row; numeric tracks translate via CSS only.
|
|
104
|
+
return (
|
|
105
|
+
<div style={{ ['--hx' as string]: `${hscroll}px`, display: 'flex', flexDirection: 'column' }}>
|
|
106
|
+
<div style={{ height: 440 }}>
|
|
107
|
+
<VirtualScroll itemCount={rows.length} getItem={getItem} getItemHeight={getItemHeight} viewportSize={440} onWheelHorizontal={onWheelHorizontal}>
|
|
108
|
+
{(row) => (
|
|
109
|
+
<div style={{ display: 'flex' }}>
|
|
110
|
+
<div style={{ width: 180, flexShrink: 0 }}>{row.label}{/* frozen column */}</div>
|
|
111
|
+
<div style={{ flex: 1, overflow: 'hidden' }}>
|
|
112
|
+
<div style={{ transform: 'translateX(calc(-1 * var(--hx)))' }}>{/* numeric columns */}</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
)}
|
|
116
|
+
</VirtualScroll>
|
|
117
|
+
</div>
|
|
118
|
+
<ScrollBar
|
|
119
|
+
horizontal
|
|
120
|
+
contentSize={1200}
|
|
121
|
+
viewportSize={568}
|
|
122
|
+
scrollPosition={hscroll}
|
|
123
|
+
onScroll={(next) => { const c = clamp(typeof next === 'function' ? next(hscroll) : next, maxHScroll); setHscroll(c); return c }}
|
|
124
|
+
/>
|
|
125
|
+
</div>
|
|
126
|
+
)
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
A runnable version lives in the demo at **`/horizontal`** (`pnpm demo:dev`), and
|
|
131
|
+
[`@aiquants/directory-tree`](../directory-tree)'s TreeGrid mode uses this exact pattern in production.
|
|
132
|
+
|
|
79
133
|
## API Reference
|
|
80
134
|
|
|
81
135
|
### VirtualScroll Props
|
|
@@ -91,6 +145,7 @@ function App() {
|
|
|
91
145
|
| `className` | `string` | ❌ | CSS class name |
|
|
92
146
|
| `onScroll` | `(position: number, totalHeight: number) => void` | ❌ | Scroll event handler |
|
|
93
147
|
| `onRangeChange` | `(range: VirtualScrollRange) => void` | ❌ | Range change handler |
|
|
148
|
+
| `onWheelHorizontal` | `(deltaX: number) => void` | ❌ | Opt-in horizontal wheel delegation. When set, horizontal-dominant wheel / trackpad gestures (and shift+wheel) are delegated to this handler so the parent can implement horizontal scrolling; vertical behavior is unchanged, and it is a no-op when omitted (fully backward compatible). See [Horizontal Scrolling](#horizontal-scrolling). |
|
|
94
149
|
| `background` | `ReactNode` | ❌ | Background element |
|
|
95
150
|
| `initialScrollIndex` | `number` | ❌ | Initial scroll index |
|
|
96
151
|
| `initialScrollOffset` | `number` | ❌ | Initial scroll offset |
|