@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.
Files changed (2) hide show
  1. package/README.md +55 -0
  2. 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 |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiquants/virtualscroll",
3
- "version": "1.18.0",
3
+ "version": "1.18.2",
4
4
  "description": "High-performance virtual scrolling component for React with variable item heights",
5
5
  "sideEffects": [
6
6
  "**/*.css"