@versini/ui-datagrid 4.0.0 → 4.0.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/dist/197.js +1 -1
- package/dist/430.js +1 -1
- package/dist/799.js +1 -1
- package/dist/91.js +1 -1
- package/dist/DataGrid/index.js +1 -1
- package/dist/DataGridAnimated/index.js +1 -1
- package/dist/DataGridBody/index.js +1 -1
- package/dist/DataGridCell/index.js +1 -1
- package/dist/DataGridCellSort/index.js +1 -1
- package/dist/DataGridConstants/index.js +1 -1
- package/dist/DataGridFooter/index.js +1 -1
- package/dist/DataGridHeader/index.js +1 -1
- package/dist/DataGridInfinite/index.js +83 -14
- package/dist/DataGridRow/index.js +1 -1
- package/dist/DataGridSorting/index.js +1 -1
- package/package.json +2 -2
package/dist/197.js
CHANGED
package/dist/430.js
CHANGED
package/dist/799.js
CHANGED
package/dist/91.js
CHANGED
package/dist/DataGrid/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
@versini/ui-datagrid v4.0.
|
|
2
|
+
@versini/ui-datagrid v4.0.1
|
|
3
3
|
© 2026 gizmette.com
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -23,6 +23,9 @@ import { getBodyClass, useColumnMeasurement } from "../197.js";
|
|
|
23
23
|
const DEFAULT_OVERSCAN = 8;
|
|
24
24
|
const DEFAULT_ESTIMATED_ROW_HEIGHT = 44;
|
|
25
25
|
const DEFAULT_COMPACT_ESTIMATED_ROW_HEIGHT = 29;
|
|
26
|
+
// Fallback used to restore the normal window after a jump when the browser does
|
|
27
|
+
// not fire `scrollend` (e.g. Safari < 17.4) or the target was already centered.
|
|
28
|
+
const JUMP_SETTLE_FALLBACK_MS = 1000;
|
|
26
29
|
/**
|
|
27
30
|
* A virtualized DataGrid body for large datasets.
|
|
28
31
|
*
|
|
@@ -73,6 +76,22 @@ const DEFAULT_COMPACT_ESTIMATED_ROW_HEIGHT = 29;
|
|
|
73
76
|
* estimate far from the real height hurts scrollbar accuracy and scrollToIndex.
|
|
74
77
|
*/ const resolvedEstimatedRowHeight = estimatedRowHeight ?? (ctx.compact ? DEFAULT_COMPACT_ESTIMATED_ROW_HEIGHT : DEFAULT_ESTIMATED_ROW_HEIGHT);
|
|
75
78
|
const [scrollMargin, setScrollMargin] = useState(0);
|
|
79
|
+
/**
|
|
80
|
+
* Jump-to-row state. A programmatic `scrollToIndex` first widens the
|
|
81
|
+
* virtualized window (`jump.overscan`) so every row between the current view
|
|
82
|
+
* and the target is mounted, then lets the browser natively smooth-scroll to
|
|
83
|
+
* the real target element. Scrolling over real, laid-out rows lands exactly and
|
|
84
|
+
* glides smoothly — the virtualizer never re-estimates the target offset
|
|
85
|
+
* mid-flight (which is what made the jump stutter near the target). The window
|
|
86
|
+
* is restored once the scroll settles, so the path rows recycle back out.
|
|
87
|
+
*
|
|
88
|
+
* `seq` makes every request a fresh object: two jumps that happen to compute
|
|
89
|
+
* the same `overscan` still re-run the jump effect (a plain number would be a
|
|
90
|
+
* no-op setState and the second jump would be dropped). `handledSeqRef` records
|
|
91
|
+
* the last seq the effect acted on, so it scrolls once per request.
|
|
92
|
+
*/ const [jump, setJump] = useState(null);
|
|
93
|
+
const jumpSeqRef = useRef(0);
|
|
94
|
+
const handledSeqRef = useRef(-1);
|
|
76
95
|
/**
|
|
77
96
|
* The scroll target is provided by the parent DataGrid: its internal bounded
|
|
78
97
|
* scroller (sticky / maxHeight), or the page (window scroll) when it owns
|
|
@@ -117,7 +136,9 @@ const DEFAULT_COMPACT_ESTIMATED_ROW_HEIGHT = 29;
|
|
|
117
136
|
// useVirtualizer's element constraint excludes Window.
|
|
118
137
|
getScrollElement: ()=>useWindow ? typeof window !== "undefined" ? window : null : scrollEl,
|
|
119
138
|
estimateSize: ()=>resolvedEstimatedRowHeight,
|
|
120
|
-
overscan
|
|
139
|
+
// While a jump is in flight, `jump.overscan` widens the window to mount the
|
|
140
|
+
// rows along the path; otherwise the consumer's (or default) overscan.
|
|
141
|
+
overscan: jump?.overscan ?? overscan,
|
|
121
142
|
scrollMargin,
|
|
122
143
|
// React 19: let React batch the scroll-driven updates natively.
|
|
123
144
|
useFlushSync: false,
|
|
@@ -168,28 +189,76 @@ const DEFAULT_COMPACT_ESTIMATED_ROW_HEIGHT = 29;
|
|
|
168
189
|
totalItems
|
|
169
190
|
]);
|
|
170
191
|
/**
|
|
171
|
-
* Expose scrollToIndex via ref
|
|
172
|
-
*
|
|
192
|
+
* Expose scrollToIndex via ref. Rather than letting the virtualizer scroll to
|
|
193
|
+
* an estimated offset (which re-corrects as rows measure, stuttering near the
|
|
194
|
+
* target), we widen the window to mount every row from the current view to the
|
|
195
|
+
* target, then a layout effect natively smooth-scrolls to the real element.
|
|
196
|
+
* Works for any index, mounted or not.
|
|
173
197
|
*/ useImperativeHandle(ref, ()=>({
|
|
174
198
|
scrollToIndex: (index)=>{
|
|
175
199
|
if (index < 0 || index >= totalItems) {
|
|
176
200
|
console.warn(`scrollToIndex: index ${index} is out of bounds${totalItems === 0 ? " (the grid is empty)" : ` (0-${totalItems - 1})`}`);
|
|
177
201
|
return;
|
|
178
202
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
203
|
+
const items = virtualizer.getVirtualItems();
|
|
204
|
+
const first = items.length > 0 ? items[0].index : 0;
|
|
205
|
+
const last = items.length > 0 ? items[items.length - 1].index : 0;
|
|
206
|
+
// Overscan is symmetric, so widen by the larger gap to either edge of
|
|
207
|
+
// the current window; that guarantees the target (and the rows between)
|
|
208
|
+
// mount. The jump effect scrolls once they render, then restores the
|
|
209
|
+
// normal window.
|
|
210
|
+
const reach = Math.max(index - first, last - index, 0);
|
|
211
|
+
jumpSeqRef.current += 1;
|
|
212
|
+
setJump({
|
|
213
|
+
index,
|
|
214
|
+
overscan: reach + overscan,
|
|
215
|
+
seq: jumpSeqRef.current
|
|
188
216
|
});
|
|
189
217
|
}
|
|
190
218
|
}), [
|
|
191
219
|
totalItems,
|
|
192
|
-
virtualizer
|
|
220
|
+
virtualizer,
|
|
221
|
+
overscan
|
|
222
|
+
]);
|
|
223
|
+
/**
|
|
224
|
+
* Perform a pending jump once the widened window has mounted the target row
|
|
225
|
+
* (react-virtual recomputes the window synchronously, so it is mounted in the
|
|
226
|
+
* commit that follows the `jump` change), then restore the normal window after
|
|
227
|
+
* the scroll settles. `scrollend` fires when the native smooth scroll finishes;
|
|
228
|
+
* the timeout is a fallback for browsers without it and for the no-op case
|
|
229
|
+
* (target already centered, so no scroll — and thus no `scrollend` — fires).
|
|
230
|
+
*/ useLayoutEffect(()=>{
|
|
231
|
+
if (jump === null || handledSeqRef.current === jump.seq) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
handledSeqRef.current = jump.seq;
|
|
235
|
+
const rowEl = bodyRef.current?.querySelector(`[data-index="${jump.index}"]`);
|
|
236
|
+
if (!rowEl) {
|
|
237
|
+
// The widened window should always mount the target; if it somehow did
|
|
238
|
+
// not, don't stay stuck in widened mode — restore the normal window so
|
|
239
|
+
// later jumps aren't dropped.
|
|
240
|
+
setJump(null);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const reduceMotion = typeof window !== "undefined" && !!window.matchMedia?.("(prefers-reduced-motion: reduce)").matches;
|
|
244
|
+
rowEl.scrollIntoView({
|
|
245
|
+
behavior: reduceMotion ? "auto" : "smooth",
|
|
246
|
+
block: "center"
|
|
247
|
+
});
|
|
248
|
+
const scroller = useWindow ? typeof window !== "undefined" ? window : null : scrollEl;
|
|
249
|
+
const settle = ()=>setJump(null);
|
|
250
|
+
scroller?.addEventListener("scrollend", settle, {
|
|
251
|
+
once: true
|
|
252
|
+
});
|
|
253
|
+
const timer = setTimeout(settle, JUMP_SETTLE_FALLBACK_MS);
|
|
254
|
+
return ()=>{
|
|
255
|
+
clearTimeout(timer);
|
|
256
|
+
scroller?.removeEventListener("scrollend", settle);
|
|
257
|
+
};
|
|
258
|
+
}, [
|
|
259
|
+
jump,
|
|
260
|
+
useWindow,
|
|
261
|
+
scrollEl
|
|
193
262
|
]);
|
|
194
263
|
/**
|
|
195
264
|
* Report a monotonic high-water mark via onVisibleCountChange: the furthest
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@versini/ui-datagrid",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Arno Versini",
|
|
6
6
|
"publishConfig": {
|
|
@@ -99,5 +99,5 @@
|
|
|
99
99
|
"sideEffects": [
|
|
100
100
|
"**/*.css"
|
|
101
101
|
],
|
|
102
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "15ac9e9cbe112e9ed49be5c857a6d4ac4444472e"
|
|
103
103
|
}
|