virtua 0.45.2 → 0.46.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/README.md +1 -1
- package/lib/core/index.cjs +1 -1
- package/lib/core/index.cjs.map +1 -1
- package/lib/core/index.js +1 -1
- package/lib/core/index.js.map +1 -1
- package/lib/index.cjs +1 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/react/VGrid.d.ts +3 -3
- package/lib/react/VList.d.ts +1 -1
- package/lib/react/Virtualizer.d.ts +6 -6
- package/lib/react/WindowVirtualizer.d.ts +5 -5
- package/lib/solid/VList.d.ts +1 -1
- package/lib/solid/Virtualizer.d.ts +5 -5
- package/lib/solid/WindowVirtualizer.d.ts +4 -4
- package/lib/solid/index.cjs +1 -1
- package/lib/solid/index.cjs.map +1 -1
- package/lib/solid/index.js +1 -1
- package/lib/solid/index.js.map +1 -1
- package/lib/solid/index.jsx +61 -44
- package/lib/solid/index.jsx.map +1 -1
- package/lib/svelte/VList.svelte +2 -2
- package/lib/svelte/VList.type.d.ts +1 -1
- package/lib/svelte/Virtualizer.svelte +2 -3
- package/lib/svelte/Virtualizer.type.d.ts +5 -5
- package/lib/svelte/WindowVirtualizer.svelte +2 -3
- package/lib/svelte/WindowVirtualizer.type.d.ts +4 -4
- package/lib/vue/VList.d.ts +10 -10
- package/lib/vue/Virtualizer.d.ts +12 -12
- package/lib/vue/WindowVirtualizer.d.ts +8 -8
- package/lib/vue/index.cjs +1 -1
- package/lib/vue/index.cjs.map +1 -1
- package/lib/vue/index.js +1 -1
- package/lib/vue/index.js.map +1 -1
- package/package.json +1 -1
package/lib/solid/index.jsx
CHANGED
|
@@ -132,20 +132,20 @@ const findIndex = (cache, offset, low = 0, high = cache._length - 1) => {
|
|
|
132
132
|
/**
|
|
133
133
|
* @internal
|
|
134
134
|
*/
|
|
135
|
-
const computeRange = (cache,
|
|
135
|
+
const computeRange = (cache, startOffset, endOffset, prevStartIndex) => {
|
|
136
136
|
// Clamp because prevStartIndex may exceed the limit when children decreased a lot after scrolling
|
|
137
137
|
prevStartIndex = min(prevStartIndex, cache._length - 1);
|
|
138
|
-
if (computeOffset(cache, prevStartIndex) <=
|
|
138
|
+
if (computeOffset(cache, prevStartIndex) <= startOffset) {
|
|
139
139
|
// search forward
|
|
140
140
|
// start <= end, prevStartIndex <= start
|
|
141
|
-
const end = findIndex(cache,
|
|
142
|
-
return [findIndex(cache,
|
|
141
|
+
const end = findIndex(cache, endOffset, prevStartIndex);
|
|
142
|
+
return [findIndex(cache, startOffset, prevStartIndex, end), end];
|
|
143
143
|
}
|
|
144
144
|
else {
|
|
145
145
|
// search backward
|
|
146
146
|
// start <= end, start <= prevStartIndex
|
|
147
|
-
const start = findIndex(cache,
|
|
148
|
-
return [start, findIndex(cache,
|
|
147
|
+
const start = findIndex(cache, startOffset, undefined, prevStartIndex);
|
|
148
|
+
return [start, findIndex(cache, endOffset, start)];
|
|
149
149
|
}
|
|
150
150
|
};
|
|
151
151
|
/**
|
|
@@ -302,7 +302,7 @@ const getScrollSize = (store) => {
|
|
|
302
302
|
/**
|
|
303
303
|
* @internal
|
|
304
304
|
*/
|
|
305
|
-
const createVirtualStore = (elementsCount, itemSize = 40,
|
|
305
|
+
const createVirtualStore = (elementsCount, itemSize = 40, ssrCount = 0, cacheSnapshot, shouldAutoEstimateItemSize = false) => {
|
|
306
306
|
let isSSR = !!ssrCount;
|
|
307
307
|
let stateVersion = 1;
|
|
308
308
|
let viewportSize = 0;
|
|
@@ -313,17 +313,15 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
|
|
|
313
313
|
let _flushedJump = 0;
|
|
314
314
|
let _scrollDirection = SCROLL_IDLE;
|
|
315
315
|
let _scrollMode = SCROLL_BY_NATIVE;
|
|
316
|
-
let _frozenRange =
|
|
317
|
-
|
|
318
|
-
: NULL;
|
|
319
|
-
let _prevRange = [0, 0];
|
|
316
|
+
let _frozenRange = NULL;
|
|
317
|
+
let _prevRange = [0, isSSR ? max(ssrCount - 1, 0) : -1];
|
|
320
318
|
let _totalMeasuredSize = 0;
|
|
321
319
|
const cache = initCache(elementsCount, itemSize, cacheSnapshot);
|
|
322
320
|
const subscribers = new Set();
|
|
323
321
|
const getRelativeScrollOffset = () => scrollOffset - startSpacerSize;
|
|
324
322
|
const getVisibleOffset = () => getRelativeScrollOffset() + pendingJump + jump;
|
|
325
|
-
const getRange = (
|
|
326
|
-
return computeRange(cache,
|
|
323
|
+
const getRange = (startOffset, endOffset) => {
|
|
324
|
+
return computeRange(cache, startOffset, endOffset, _prevRange[0]);
|
|
327
325
|
};
|
|
328
326
|
const getTotalSize = () => computeTotalSize(cache);
|
|
329
327
|
const getItemOffset = (index) => {
|
|
@@ -332,6 +330,9 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
|
|
|
332
330
|
const getItemSize$1 = (index) => {
|
|
333
331
|
return getItemSize(cache, index);
|
|
334
332
|
};
|
|
333
|
+
const isSizeEqual = (index, value = UNCACHED) => {
|
|
334
|
+
return cache._sizes[index] === value;
|
|
335
|
+
};
|
|
335
336
|
const applyJump = (j) => {
|
|
336
337
|
if (j) {
|
|
337
338
|
if (
|
|
@@ -352,7 +353,13 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
|
|
|
352
353
|
$getCacheSnapshot: () => {
|
|
353
354
|
return takeCacheSnapshot(cache);
|
|
354
355
|
},
|
|
355
|
-
$getRange: () => {
|
|
356
|
+
$getRange: (bufferSize = 200) => {
|
|
357
|
+
if (!viewportSize || isSSR) {
|
|
358
|
+
// Empty viewportSize means the first render.
|
|
359
|
+
// We return range for SSR here, or return [0, -1] to render nothing, until the scroll offset and viewport size are determined.
|
|
360
|
+
// https://github.com/inokawa/virtua/issues/415
|
|
361
|
+
return _prevRange;
|
|
362
|
+
}
|
|
356
363
|
let startIndex;
|
|
357
364
|
let endIndex;
|
|
358
365
|
if (_flushedJump) {
|
|
@@ -361,23 +368,29 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
|
|
|
361
368
|
[startIndex, endIndex] = _prevRange;
|
|
362
369
|
}
|
|
363
370
|
else {
|
|
364
|
-
|
|
371
|
+
bufferSize = max(0, bufferSize);
|
|
372
|
+
let startOffset = max(0, getVisibleOffset());
|
|
373
|
+
let endOffset = startOffset + viewportSize;
|
|
374
|
+
// For faster initial render pass, returns without buffer if measurement seems to be in progress.
|
|
375
|
+
if (!shouldAutoEstimateItemSize) {
|
|
376
|
+
if (_scrollDirection !== SCROLL_DOWN) {
|
|
377
|
+
startOffset -= bufferSize;
|
|
378
|
+
}
|
|
379
|
+
if (_scrollDirection !== SCROLL_UP) {
|
|
380
|
+
endOffset += bufferSize;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
[startIndex, endIndex] = _prevRange = getRange(max(0, startOffset), max(0, endOffset));
|
|
365
384
|
if (_frozenRange) {
|
|
366
385
|
startIndex = min(startIndex, _frozenRange[0]);
|
|
367
386
|
endIndex = max(endIndex, _frozenRange[1]);
|
|
368
387
|
}
|
|
369
388
|
}
|
|
370
|
-
if (_scrollDirection !== SCROLL_DOWN) {
|
|
371
|
-
startIndex -= max(0, overscan);
|
|
372
|
-
}
|
|
373
|
-
if (_scrollDirection !== SCROLL_UP) {
|
|
374
|
-
endIndex += max(0, overscan);
|
|
375
|
-
}
|
|
376
389
|
return [max(startIndex, 0), min(endIndex, cache._length - 1)];
|
|
377
390
|
},
|
|
378
391
|
$findStartIndex: () => findIndex(cache, getVisibleOffset()),
|
|
379
392
|
$findEndIndex: () => findIndex(cache, getVisibleOffset() + viewportSize),
|
|
380
|
-
$isUnmeasuredItem:
|
|
393
|
+
$isUnmeasuredItem: isSizeEqual,
|
|
381
394
|
$getItemOffset: getItemOffset,
|
|
382
395
|
$getItemSize: getItemSize$1,
|
|
383
396
|
$getItemsLength: () => cache._length,
|
|
@@ -430,7 +443,6 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
|
|
|
430
443
|
// shouldFlushPendingJump = true;
|
|
431
444
|
// }
|
|
432
445
|
if (isSSR) {
|
|
433
|
-
_frozenRange = NULL;
|
|
434
446
|
isSSR = false;
|
|
435
447
|
}
|
|
436
448
|
scrollOffset = payload;
|
|
@@ -458,7 +470,7 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
|
|
|
458
470
|
break;
|
|
459
471
|
}
|
|
460
472
|
case ACTION_ITEM_RESIZE: {
|
|
461
|
-
const updated = payload.filter(([index, size]) =>
|
|
473
|
+
const updated = payload.filter(([index, size]) => !isSizeEqual(index, size));
|
|
462
474
|
// Skip if all items are cached and not updated
|
|
463
475
|
if (!updated.length) {
|
|
464
476
|
break;
|
|
@@ -542,7 +554,7 @@ const createVirtualStore = (elementsCount, itemSize = 40, overscan = 4, ssrCount
|
|
|
542
554
|
break;
|
|
543
555
|
}
|
|
544
556
|
case ACTION_BEFORE_MANUAL_SMOOTH_SCROLL: {
|
|
545
|
-
_frozenRange = getRange(payload);
|
|
557
|
+
_frozenRange = getRange(payload, payload + viewportSize);
|
|
546
558
|
mutated = UPDATE_VIRTUAL_STATE;
|
|
547
559
|
break;
|
|
548
560
|
}
|
|
@@ -911,13 +923,20 @@ const createWindowScroller = (store, isHorizontal) => {
|
|
|
911
923
|
const scrollOffsetKey = isHorizontal ? "scrollX" : "scrollY";
|
|
912
924
|
const document = getCurrentDocument(container);
|
|
913
925
|
const window = getCurrentWindow(document);
|
|
914
|
-
scrollObserver = createScrollObserver(store, window, isHorizontal, () => normalizeOffset(window[scrollOffsetKey], isHorizontal), (jump) => {
|
|
915
|
-
// Use absolute position not to exceed scrollable bounds
|
|
916
|
-
// https://github.com/inokawa/virtua/discussions/475
|
|
926
|
+
scrollObserver = createScrollObserver(store, window, isHorizontal, () => normalizeOffset(window[scrollOffsetKey], isHorizontal), (jump, shift) => {
|
|
917
927
|
// TODO support case two window scrollers exist in the same view
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
928
|
+
if (shift) {
|
|
929
|
+
// Use absolute position not to exceed scrollable bounds
|
|
930
|
+
window.scroll({
|
|
931
|
+
[scrollToKey]: store.$getScrollOffset() + jump,
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
else {
|
|
935
|
+
// Use window.scrollBy here, which causes less layout shift for some reason.
|
|
936
|
+
window.scrollBy({
|
|
937
|
+
[scrollToKey]: jump,
|
|
938
|
+
});
|
|
939
|
+
}
|
|
921
940
|
}, () => calcOffsetToViewport(container, document.body, window, isHorizontal));
|
|
922
941
|
initialized[1](true);
|
|
923
942
|
},
|
|
@@ -1284,9 +1303,9 @@ const isSameRange = (prev, next) => {
|
|
|
1284
1303
|
*/
|
|
1285
1304
|
const Virtualizer = (props) => {
|
|
1286
1305
|
let containerRef;
|
|
1287
|
-
const { itemSize, horizontal = false,
|
|
1306
|
+
const { itemSize, horizontal = false, cache } = props;
|
|
1288
1307
|
props = mergeProps({ as: "div" }, props);
|
|
1289
|
-
const store = createVirtualStore(props.data.length, itemSize,
|
|
1308
|
+
const store = createVirtualStore(props.data.length, itemSize, undefined, cache, !itemSize);
|
|
1290
1309
|
const resizer = createResizer(store, horizontal);
|
|
1291
1310
|
const scroller = createScroller(store, horizontal);
|
|
1292
1311
|
const [stateVersion, setRerender] = createSignal(store.$getStateVersion());
|
|
@@ -1303,7 +1322,7 @@ const Virtualizer = (props) => {
|
|
|
1303
1322
|
});
|
|
1304
1323
|
const range = createMemo((prev) => {
|
|
1305
1324
|
stateVersion();
|
|
1306
|
-
const next = store.$getRange();
|
|
1325
|
+
const next = store.$getRange(props.bufferSize);
|
|
1307
1326
|
if (prev && isSameRange(prev, next)) {
|
|
1308
1327
|
return prev;
|
|
1309
1328
|
}
|
|
@@ -1364,12 +1383,11 @@ const Virtualizer = (props) => {
|
|
|
1364
1383
|
store.$update(ACTION_ITEMS_LENGTH_CHANGE, [count, props.shift]);
|
|
1365
1384
|
}
|
|
1366
1385
|
});
|
|
1367
|
-
const [startIndex, endIndex] = range();
|
|
1368
1386
|
const items = [];
|
|
1369
1387
|
const indexes = [];
|
|
1370
1388
|
if (props.keepMounted) {
|
|
1371
1389
|
const mounted = new Set(props.keepMounted);
|
|
1372
|
-
for (let i
|
|
1390
|
+
for (let [i, j] = range(); i <= j; i++) {
|
|
1373
1391
|
mounted.add(i);
|
|
1374
1392
|
}
|
|
1375
1393
|
sort([...mounted]).forEach((index) => {
|
|
@@ -1378,7 +1396,7 @@ const Virtualizer = (props) => {
|
|
|
1378
1396
|
});
|
|
1379
1397
|
}
|
|
1380
1398
|
else {
|
|
1381
|
-
for (let i
|
|
1399
|
+
for (let [i, j] = range(); i <= j; i++) {
|
|
1382
1400
|
items.push(props.data[i]);
|
|
1383
1401
|
indexes.push(i);
|
|
1384
1402
|
}
|
|
@@ -1430,7 +1448,7 @@ const VList = (props) => {
|
|
|
1430
1448
|
"ref",
|
|
1431
1449
|
"data",
|
|
1432
1450
|
"children",
|
|
1433
|
-
"
|
|
1451
|
+
"bufferSize",
|
|
1434
1452
|
"itemSize",
|
|
1435
1453
|
"shift",
|
|
1436
1454
|
"horizontal",
|
|
@@ -1449,7 +1467,7 @@ const VList = (props) => {
|
|
|
1449
1467
|
height: "100%",
|
|
1450
1468
|
...local.style,
|
|
1451
1469
|
}}>
|
|
1452
|
-
<Virtualizer ref={local.ref} data={local.data}
|
|
1470
|
+
<Virtualizer ref={local.ref} data={local.data} bufferSize={local.bufferSize} itemSize={local.itemSize} shift={local.shift} horizontal={local.horizontal} keepMounted={local.keepMounted} cache={local.cache} item={local.item} onScroll={local.onScroll} onScrollEnd={local.onScrollEnd}>
|
|
1453
1471
|
{local.children}
|
|
1454
1472
|
</Virtualizer>
|
|
1455
1473
|
</div>);
|
|
@@ -1463,8 +1481,8 @@ const VList = (props) => {
|
|
|
1463
1481
|
*/
|
|
1464
1482
|
const WindowVirtualizer = (props) => {
|
|
1465
1483
|
let containerRef;
|
|
1466
|
-
const { ref: _ref, data: _data, children: _children,
|
|
1467
|
-
const store = createVirtualStore(props.data.length, itemSize,
|
|
1484
|
+
const { ref: _ref, data: _data, children: _children, itemSize, shift: _shift, horizontal = false, cache, onScrollEnd: _onScrollEnd, } = props;
|
|
1485
|
+
const store = createVirtualStore(props.data.length, itemSize, undefined, cache, !itemSize);
|
|
1468
1486
|
const resizer = createWindowResizer(store, horizontal);
|
|
1469
1487
|
const scroller = createWindowScroller(store, horizontal);
|
|
1470
1488
|
const [stateVersion, setRerender] = createSignal(store.$getStateVersion());
|
|
@@ -1482,7 +1500,7 @@ const WindowVirtualizer = (props) => {
|
|
|
1482
1500
|
});
|
|
1483
1501
|
const range = createMemo((prev) => {
|
|
1484
1502
|
stateVersion();
|
|
1485
|
-
const next = store.$getRange();
|
|
1503
|
+
const next = store.$getRange(props.bufferSize);
|
|
1486
1504
|
if (prev && isSameRange(prev, next)) {
|
|
1487
1505
|
return prev;
|
|
1488
1506
|
}
|
|
@@ -1524,9 +1542,8 @@ const WindowVirtualizer = (props) => {
|
|
|
1524
1542
|
store.$update(ACTION_ITEMS_LENGTH_CHANGE, [count, props.shift]);
|
|
1525
1543
|
}
|
|
1526
1544
|
});
|
|
1527
|
-
const [startIndex, endIndex] = range();
|
|
1528
1545
|
const items = [];
|
|
1529
|
-
for (let i
|
|
1546
|
+
for (let [i, j] = range(); i <= j; i++) {
|
|
1530
1547
|
items.push(props.data[i]);
|
|
1531
1548
|
}
|
|
1532
1549
|
return items;
|