@tanstack/virtual-core 3.0.0-beta.30 → 3.0.0-beta.33
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/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js +27 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js.map +1 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.js +31 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs +27 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs.map +1 -0
- package/build/lib/index.d.ts +12 -8
- package/build/lib/index.esm.js +421 -399
- package/build/lib/index.esm.js.map +1 -1
- package/build/lib/index.js +421 -399
- package/build/lib/index.js.map +1 -1
- package/build/lib/index.mjs +421 -399
- package/build/lib/index.mjs.map +1 -1
- package/build/lib/utils.esm.js +15 -16
- package/build/lib/utils.esm.js.map +1 -1
- package/build/lib/utils.js +15 -16
- package/build/lib/utils.js.map +1 -1
- package/build/lib/utils.mjs +15 -16
- package/build/lib/utils.mjs.map +1 -1
- package/build/umd/index.development.js +450 -415
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +97 -66
package/src/index.ts
CHANGED
|
@@ -4,6 +4,8 @@ export * from './utils'
|
|
|
4
4
|
|
|
5
5
|
//
|
|
6
6
|
|
|
7
|
+
type ScrollDirection = 'forward' | 'backward'
|
|
8
|
+
|
|
7
9
|
type ScrollAlignment = 'start' | 'center' | 'end' | 'auto'
|
|
8
10
|
|
|
9
11
|
type ScrollBehavior = 'auto' | 'smooth'
|
|
@@ -149,7 +151,7 @@ const createOffsetObserver = (mode: ObserverMode) => {
|
|
|
149
151
|
const offset =
|
|
150
152
|
instance.scrollElement[instance.options.horizontal ? propX : propY]
|
|
151
153
|
|
|
152
|
-
cb(
|
|
154
|
+
cb(offset)
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
scroll()
|
|
@@ -195,15 +197,12 @@ export const measureElement = <TItemElement extends Element>(
|
|
|
195
197
|
export const windowScroll = <T extends Window>(
|
|
196
198
|
offset: number,
|
|
197
199
|
{
|
|
198
|
-
adjustments,
|
|
200
|
+
adjustments = 0,
|
|
199
201
|
behavior,
|
|
200
|
-
|
|
201
|
-
}: { adjustments?: number; behavior?: ScrollBehavior; sync: boolean },
|
|
202
|
+
}: { adjustments?: number; behavior?: ScrollBehavior },
|
|
202
203
|
instance: Virtualizer<T, any>,
|
|
203
204
|
) => {
|
|
204
|
-
const toOffset =
|
|
205
|
-
(sync ? offset : offset + instance.options.scrollMargin) +
|
|
206
|
-
(adjustments ?? 0)
|
|
205
|
+
const toOffset = offset + adjustments
|
|
207
206
|
|
|
208
207
|
instance.scrollElement?.scrollTo?.({
|
|
209
208
|
[instance.options.horizontal ? 'left' : 'top']: toOffset,
|
|
@@ -214,15 +213,12 @@ export const windowScroll = <T extends Window>(
|
|
|
214
213
|
export const elementScroll = <T extends Element>(
|
|
215
214
|
offset: number,
|
|
216
215
|
{
|
|
217
|
-
adjustments,
|
|
216
|
+
adjustments = 0,
|
|
218
217
|
behavior,
|
|
219
|
-
|
|
220
|
-
}: { adjustments?: number; behavior?: ScrollBehavior; sync: boolean },
|
|
218
|
+
}: { adjustments?: number; behavior?: ScrollBehavior },
|
|
221
219
|
instance: Virtualizer<T, any>,
|
|
222
220
|
) => {
|
|
223
|
-
const toOffset =
|
|
224
|
-
(sync ? offset : offset + instance.options.scrollMargin) +
|
|
225
|
-
(adjustments ?? 0)
|
|
221
|
+
const toOffset = offset + adjustments
|
|
226
222
|
|
|
227
223
|
instance.scrollElement?.scrollTo?.({
|
|
228
224
|
[instance.options.horizontal ? 'left' : 'top']: toOffset,
|
|
@@ -242,7 +238,7 @@ export interface VirtualizerOptions<
|
|
|
242
238
|
// Required from the framework adapter (but can be overridden)
|
|
243
239
|
scrollToFn: (
|
|
244
240
|
offset: number,
|
|
245
|
-
options: { adjustments?: number; behavior?: ScrollBehavior
|
|
241
|
+
options: { adjustments?: number; behavior?: ScrollBehavior },
|
|
246
242
|
instance: Virtualizer<TScrollElement, TItemElement>,
|
|
247
243
|
) => void
|
|
248
244
|
observeElementRect: (
|
|
@@ -274,6 +270,7 @@ export interface VirtualizerOptions<
|
|
|
274
270
|
scrollMargin?: number
|
|
275
271
|
scrollingDelay?: number
|
|
276
272
|
indexAttribute?: string
|
|
273
|
+
initialMeasurementsCache?: VirtualItem[]
|
|
277
274
|
}
|
|
278
275
|
|
|
279
276
|
export class Virtualizer<
|
|
@@ -286,10 +283,11 @@ export class Virtualizer<
|
|
|
286
283
|
isScrolling: boolean = false
|
|
287
284
|
private isScrollingTimeoutId: ReturnType<typeof setTimeout> | null = null
|
|
288
285
|
measurementsCache: VirtualItem[] = []
|
|
289
|
-
private
|
|
286
|
+
private itemSizeCache: Record<Key, number> = {}
|
|
290
287
|
private pendingMeasuredCacheIndexes: number[] = []
|
|
291
288
|
private scrollRect: Rect
|
|
292
|
-
|
|
289
|
+
scrollOffset: number
|
|
290
|
+
scrollDirection: ScrollDirection | null = null
|
|
293
291
|
private scrollAdjustments: number = 0
|
|
294
292
|
private measureElementCache: Record<Key, TItemElement> = {}
|
|
295
293
|
private pendingScrollToIndexCallback: (() => void) | null = null
|
|
@@ -319,6 +317,10 @@ export class Virtualizer<
|
|
|
319
317
|
this.setOptions(opts)
|
|
320
318
|
this.scrollRect = this.options.initialRect
|
|
321
319
|
this.scrollOffset = this.options.initialOffset
|
|
320
|
+
this.measurementsCache = this.options.initialMeasurementsCache
|
|
321
|
+
this.measurementsCache.forEach((item) => {
|
|
322
|
+
this.itemSizeCache[item.key] = item.size
|
|
323
|
+
})
|
|
322
324
|
|
|
323
325
|
this.calculateRange()
|
|
324
326
|
}
|
|
@@ -345,6 +347,7 @@ export class Virtualizer<
|
|
|
345
347
|
scrollMargin: 0,
|
|
346
348
|
scrollingDelay: 150,
|
|
347
349
|
indexAttribute: 'data-index',
|
|
350
|
+
initialMeasurementsCache: [],
|
|
348
351
|
...opts,
|
|
349
352
|
}
|
|
350
353
|
}
|
|
@@ -383,7 +386,6 @@ export class Virtualizer<
|
|
|
383
386
|
this._scrollToOffset(this.scrollOffset, {
|
|
384
387
|
adjustments: undefined,
|
|
385
388
|
behavior: undefined,
|
|
386
|
-
sync: true,
|
|
387
389
|
})
|
|
388
390
|
|
|
389
391
|
this.unsubs.push(
|
|
@@ -395,6 +397,12 @@ export class Virtualizer<
|
|
|
395
397
|
|
|
396
398
|
this.unsubs.push(
|
|
397
399
|
this.options.observeElementOffset(this, (offset) => {
|
|
400
|
+
this.scrollAdjustments = 0
|
|
401
|
+
|
|
402
|
+
if (this.scrollOffset === offset) {
|
|
403
|
+
return
|
|
404
|
+
}
|
|
405
|
+
|
|
398
406
|
if (this.isScrollingTimeoutId !== null) {
|
|
399
407
|
clearTimeout(this.isScrollingTimeoutId)
|
|
400
408
|
this.isScrollingTimeoutId = null
|
|
@@ -407,17 +415,18 @@ export class Virtualizer<
|
|
|
407
415
|
}
|
|
408
416
|
}
|
|
409
417
|
|
|
410
|
-
this.
|
|
418
|
+
this.scrollDirection =
|
|
419
|
+
this.scrollOffset < offset ? 'forward' : 'backward'
|
|
411
420
|
|
|
412
|
-
|
|
413
|
-
this.scrollOffset = offset
|
|
414
|
-
onIsScrollingChange(true)
|
|
415
|
-
}
|
|
421
|
+
this.scrollOffset = offset
|
|
416
422
|
|
|
417
423
|
this.calculateRange()
|
|
418
424
|
|
|
425
|
+
onIsScrollingChange(true)
|
|
426
|
+
|
|
419
427
|
this.isScrollingTimeoutId = setTimeout(() => {
|
|
420
428
|
this.isScrollingTimeoutId = null
|
|
429
|
+
this.scrollDirection = null
|
|
421
430
|
onIsScrollingChange(false)
|
|
422
431
|
}, this.options.scrollingDelay)
|
|
423
432
|
}),
|
|
@@ -435,10 +444,11 @@ export class Virtualizer<
|
|
|
435
444
|
() => [
|
|
436
445
|
this.options.count,
|
|
437
446
|
this.options.paddingStart,
|
|
447
|
+
this.options.scrollMargin,
|
|
438
448
|
this.options.getItemKey,
|
|
439
|
-
this.
|
|
449
|
+
this.itemSizeCache,
|
|
440
450
|
],
|
|
441
|
-
(count, paddingStart, getItemKey,
|
|
451
|
+
(count, paddingStart, scrollMargin, getItemKey, itemSizeCache) => {
|
|
442
452
|
const min =
|
|
443
453
|
this.pendingMeasuredCacheIndexes.length > 0
|
|
444
454
|
? Math.min(...this.pendingMeasuredCacheIndexes)
|
|
@@ -449,10 +459,10 @@ export class Virtualizer<
|
|
|
449
459
|
|
|
450
460
|
for (let i = min; i < count; i++) {
|
|
451
461
|
const key = getItemKey(i)
|
|
452
|
-
const measuredSize =
|
|
462
|
+
const measuredSize = itemSizeCache[key]
|
|
453
463
|
const start = measurements[i - 1]
|
|
454
464
|
? measurements[i - 1]!.end
|
|
455
|
-
: paddingStart
|
|
465
|
+
: paddingStart + scrollMargin
|
|
456
466
|
const size =
|
|
457
467
|
typeof measuredSize === 'number'
|
|
458
468
|
? measuredSize
|
|
@@ -462,6 +472,7 @@ export class Virtualizer<
|
|
|
462
472
|
}
|
|
463
473
|
|
|
464
474
|
this.measurementsCache = measurements
|
|
475
|
+
|
|
465
476
|
return measurements
|
|
466
477
|
},
|
|
467
478
|
{
|
|
@@ -557,12 +568,16 @@ export class Virtualizer<
|
|
|
557
568
|
|
|
558
569
|
const measuredItemSize = this.options.measureElement(node, this)
|
|
559
570
|
|
|
560
|
-
const itemSize = this.
|
|
571
|
+
const itemSize = this.itemSizeCache[item.key] ?? item.size
|
|
561
572
|
|
|
562
573
|
const delta = measuredItemSize - itemSize
|
|
563
574
|
|
|
564
575
|
if (delta !== 0) {
|
|
565
|
-
if (
|
|
576
|
+
if (
|
|
577
|
+
item.start < this.scrollOffset &&
|
|
578
|
+
this.isScrolling &&
|
|
579
|
+
this.scrollDirection === 'backward'
|
|
580
|
+
) {
|
|
566
581
|
if (process.env.NODE_ENV !== 'production' && this.options.debug) {
|
|
567
582
|
console.info('correction', delta)
|
|
568
583
|
}
|
|
@@ -570,13 +585,12 @@ export class Virtualizer<
|
|
|
570
585
|
this._scrollToOffset(this.scrollOffset, {
|
|
571
586
|
adjustments: (this.scrollAdjustments += delta),
|
|
572
587
|
behavior: undefined,
|
|
573
|
-
sync: false,
|
|
574
588
|
})
|
|
575
589
|
}
|
|
576
590
|
|
|
577
591
|
this.pendingMeasuredCacheIndexes.push(index)
|
|
578
|
-
this.
|
|
579
|
-
...this.
|
|
592
|
+
this.itemSizeCache = {
|
|
593
|
+
...this.itemSizeCache,
|
|
580
594
|
[item.key]: measuredItemSize,
|
|
581
595
|
}
|
|
582
596
|
this.notify()
|
|
@@ -611,10 +625,7 @@ export class Virtualizer<
|
|
|
611
625
|
},
|
|
612
626
|
)
|
|
613
627
|
|
|
614
|
-
|
|
615
|
-
toOffset: number,
|
|
616
|
-
{ align = 'start', behavior }: ScrollToOffsetOptions = {},
|
|
617
|
-
) => {
|
|
628
|
+
getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {
|
|
618
629
|
const offset = this.scrollOffset
|
|
619
630
|
const size = this.getSize()
|
|
620
631
|
|
|
@@ -628,35 +639,43 @@ export class Virtualizer<
|
|
|
628
639
|
}
|
|
629
640
|
}
|
|
630
641
|
|
|
642
|
+
if (align === 'start') {
|
|
643
|
+
return toOffset
|
|
644
|
+
} else if (align === 'end') {
|
|
645
|
+
return toOffset - size
|
|
646
|
+
} else if (align === 'center') {
|
|
647
|
+
return toOffset - size / 2
|
|
648
|
+
}
|
|
649
|
+
return toOffset
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
scrollToOffset = (
|
|
653
|
+
toOffset: number,
|
|
654
|
+
{ align = 'start', behavior }: ScrollToOffsetOptions = {},
|
|
655
|
+
) => {
|
|
631
656
|
const options = {
|
|
632
657
|
adjustments: undefined,
|
|
633
658
|
behavior,
|
|
634
659
|
sync: false,
|
|
635
660
|
}
|
|
636
|
-
|
|
637
|
-
this._scrollToOffset(toOffset, options)
|
|
638
|
-
} else if (align === 'end') {
|
|
639
|
-
this._scrollToOffset(toOffset - size, options)
|
|
640
|
-
} else if (align === 'center') {
|
|
641
|
-
this._scrollToOffset(toOffset - size / 2, options)
|
|
642
|
-
}
|
|
661
|
+
this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), options)
|
|
643
662
|
}
|
|
644
663
|
|
|
645
664
|
scrollToIndex = (
|
|
646
665
|
index: number,
|
|
647
|
-
{ align = 'auto',
|
|
666
|
+
{ align = 'auto', behavior }: ScrollToIndexOptions = {},
|
|
648
667
|
) => {
|
|
649
668
|
this.pendingScrollToIndexCallback = null
|
|
650
669
|
|
|
651
|
-
const measurements = this.getMeasurements()
|
|
652
670
|
const offset = this.scrollOffset
|
|
653
671
|
const size = this.getSize()
|
|
654
672
|
const { count } = this.options
|
|
655
673
|
|
|
674
|
+
const measurements = this.getMeasurements()
|
|
656
675
|
const measurement = measurements[Math.max(0, Math.min(index, count - 1))]
|
|
657
676
|
|
|
658
677
|
if (!measurement) {
|
|
659
|
-
|
|
678
|
+
throw new Error(`VirtualItem not found for index = ${index}`)
|
|
660
679
|
}
|
|
661
680
|
|
|
662
681
|
if (align === 'auto') {
|
|
@@ -672,52 +691,64 @@ export class Virtualizer<
|
|
|
672
691
|
}
|
|
673
692
|
}
|
|
674
693
|
|
|
675
|
-
const
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
694
|
+
const getOffsetForIndexAndAlignment = (measurement: VirtualItem) => {
|
|
695
|
+
const toOffset =
|
|
696
|
+
align === 'end'
|
|
697
|
+
? measurement.end + this.options.scrollPaddingEnd
|
|
698
|
+
: measurement.start - this.options.scrollPaddingStart
|
|
699
|
+
|
|
700
|
+
return this.getOffsetForAlignment(toOffset, align)
|
|
701
|
+
}
|
|
679
702
|
|
|
680
|
-
|
|
703
|
+
const toOffset = getOffsetForIndexAndAlignment(measurement)
|
|
704
|
+
|
|
705
|
+
if (toOffset === offset) {
|
|
706
|
+
return
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
const options = {
|
|
710
|
+
adjustments: undefined,
|
|
711
|
+
behavior,
|
|
712
|
+
}
|
|
713
|
+
this._scrollToOffset(toOffset, options)
|
|
681
714
|
|
|
682
715
|
const isDynamic = Object.keys(this.measureElementCache).length > 0
|
|
683
716
|
|
|
684
717
|
if (isDynamic) {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
'number'
|
|
688
|
-
|
|
689
|
-
if (!didSeen()) {
|
|
690
|
-
this.pendingScrollToIndexCallback = () => {
|
|
691
|
-
if (didSeen()) {
|
|
692
|
-
this.pendingScrollToIndexCallback = null
|
|
693
|
-
this.scrollToIndex(index, { align, ...rest })
|
|
694
|
-
}
|
|
695
|
-
}
|
|
718
|
+
this.pendingScrollToIndexCallback = () => {
|
|
719
|
+
this.scrollToIndex(index, { align, behavior })
|
|
696
720
|
}
|
|
697
721
|
}
|
|
698
722
|
}
|
|
699
723
|
|
|
724
|
+
scrollBy = (adjustments: number, options?: { behavior: ScrollBehavior }) => {
|
|
725
|
+
this._scrollToOffset(this.scrollOffset, {
|
|
726
|
+
adjustments,
|
|
727
|
+
behavior: options?.behavior,
|
|
728
|
+
})
|
|
729
|
+
}
|
|
730
|
+
|
|
700
731
|
getTotalSize = () =>
|
|
701
732
|
(this.getMeasurements()[this.options.count - 1]?.end ||
|
|
702
|
-
this.options.paddingStart)
|
|
733
|
+
this.options.paddingStart) -
|
|
734
|
+
this.options.scrollMargin +
|
|
735
|
+
this.options.paddingEnd
|
|
703
736
|
|
|
704
737
|
private _scrollToOffset = (
|
|
705
738
|
offset: number,
|
|
706
739
|
{
|
|
707
740
|
adjustments,
|
|
708
741
|
behavior,
|
|
709
|
-
sync,
|
|
710
742
|
}: {
|
|
711
743
|
adjustments: number | undefined
|
|
712
744
|
behavior: ScrollBehavior | undefined
|
|
713
|
-
sync: boolean
|
|
714
745
|
},
|
|
715
746
|
) => {
|
|
716
|
-
this.options.scrollToFn(offset, { behavior,
|
|
747
|
+
this.options.scrollToFn(offset, { behavior, adjustments }, this)
|
|
717
748
|
}
|
|
718
749
|
|
|
719
750
|
measure = () => {
|
|
720
|
-
this.
|
|
751
|
+
this.itemSizeCache = {}
|
|
721
752
|
this.notify()
|
|
722
753
|
}
|
|
723
754
|
}
|