@tanstack/virtual-core 3.0.0-beta.23 → 3.0.0-beta.26

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.
@@ -8,61 +8,23 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- function memo(getDeps, fn, opts) {
12
- let deps = [];
13
- let result;
14
- return () => {
15
- let depTime;
16
- if (opts.key && opts.debug != null && opts.debug()) depTime = Date.now();
17
- const newDeps = getDeps();
18
- const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
19
-
20
- if (!depsChanged) {
21
- return result;
22
- }
23
-
24
- deps = newDeps;
25
- let resultTime;
26
- if (opts.key && opts.debug != null && opts.debug()) resultTime = Date.now();
27
- result = fn(...newDeps);
28
- opts == null ? void 0 : opts.onChange == null ? void 0 : opts.onChange(result);
29
-
30
- if (opts.key && opts.debug != null && opts.debug()) {
31
- const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
32
- const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
33
- const resultFpsPercentage = resultEndTime / 16;
34
-
35
- const pad = (str, num) => {
36
- str = String(str);
37
-
38
- while (str.length < num) {
39
- str = ' ' + str;
40
- }
11
+ import { memo } from './utils.esm.js';
12
+ export { memo } from './utils.esm.js';
41
13
 
42
- return str;
43
- };
44
-
45
- console.info("%c\u23F1 " + pad(resultEndTime, 5) + " /" + pad(depEndTime, 5) + " ms", "\n font-size: .6rem;\n font-weight: bold;\n color: hsl(" + Math.max(0, Math.min(120 - 120 * resultFpsPercentage, 120)) + "deg 100% 31%);", opts == null ? void 0 : opts.key);
46
- }
47
-
48
- return result;
49
- };
50
- }
14
+ //
51
15
 
52
16
  //
17
+
53
18
  const defaultKeyExtractor = index => index;
54
19
  const defaultRangeExtractor = range => {
55
20
  const start = Math.max(range.startIndex - range.overscan, 0);
56
21
  const end = Math.min(range.endIndex + range.overscan, range.count - 1);
57
22
  const arr = [];
58
-
59
23
  for (let i = start; i <= end; i++) {
60
24
  arr.push(i);
61
25
  }
62
-
63
26
  return arr;
64
27
  };
65
-
66
28
  const memoRectCallback = (instance, cb) => {
67
29
  let prev = {
68
30
  height: -1,
@@ -72,25 +34,20 @@ const memoRectCallback = (instance, cb) => {
72
34
  if (instance.options.horizontal ? rect.width !== prev.width : rect.height !== prev.height) {
73
35
  cb(rect);
74
36
  }
75
-
76
37
  prev = rect;
77
38
  };
78
39
  };
79
-
80
40
  const observeElementRect = (instance, cb) => {
81
41
  const observer = new ResizeObserver(entries => {
82
42
  var _entries$, _entries$2;
83
-
84
43
  cb({
85
44
  width: (_entries$ = entries[0]) == null ? void 0 : _entries$.contentRect.width,
86
45
  height: (_entries$2 = entries[0]) == null ? void 0 : _entries$2.contentRect.height
87
46
  });
88
47
  });
89
-
90
48
  if (!instance.scrollElement) {
91
49
  return;
92
50
  }
93
-
94
51
  cb(instance.scrollElement.getBoundingClientRect());
95
52
  observer.observe(instance.scrollElement);
96
53
  return () => {
@@ -99,16 +56,13 @@ const observeElementRect = (instance, cb) => {
99
56
  };
100
57
  const observeWindowRect = (instance, cb) => {
101
58
  const memoizedCallback = memoRectCallback(instance, cb);
102
-
103
59
  const onResize = () => memoizedCallback({
104
60
  width: instance.scrollElement.innerWidth,
105
61
  height: instance.scrollElement.innerHeight
106
62
  });
107
-
108
63
  if (!instance.scrollElement) {
109
64
  return;
110
65
  }
111
-
112
66
  onResize();
113
67
  instance.scrollElement.addEventListener('resize', onResize, {
114
68
  capture: false,
@@ -122,38 +76,30 @@ const scrollProps = {
122
76
  element: ['scrollLeft', 'scrollTop'],
123
77
  window: ['scrollX', 'scrollY']
124
78
  };
125
-
126
79
  const createOffsetObserver = mode => {
127
80
  return (instance, cb) => {
128
81
  if (!instance.scrollElement) {
129
82
  return;
130
83
  }
131
-
132
84
  const propX = scrollProps[mode][0];
133
85
  const propY = scrollProps[mode][1];
134
86
  let prevX = instance.scrollElement[propX];
135
87
  let prevY = instance.scrollElement[propY];
136
-
137
88
  const scroll = () => {
138
89
  const offset = instance.scrollElement[instance.options.horizontal ? propX : propY];
139
90
  cb(Math.max(0, offset - instance.options.scrollMargin));
140
91
  };
141
-
142
92
  scroll();
143
-
144
93
  const onScroll = e => {
145
94
  const target = e.currentTarget;
146
95
  const scrollX = target[propX];
147
96
  const scrollY = target[propY];
148
-
149
97
  if (instance.options.horizontal ? prevX - scrollX : prevY - scrollY) {
150
98
  scroll();
151
99
  }
152
-
153
100
  prevX = scrollX;
154
101
  prevY = scrollY;
155
102
  };
156
-
157
103
  instance.scrollElement.addEventListener('scroll', onScroll, {
158
104
  capture: false,
159
105
  passive: true
@@ -163,7 +109,6 @@ const createOffsetObserver = mode => {
163
109
  };
164
110
  };
165
111
  };
166
-
167
112
  const observeElementOffset = createOffsetObserver('element');
168
113
  const observeWindowOffset = createOffsetObserver('window');
169
114
  const measureElement = (element, instance) => {
@@ -171,34 +116,33 @@ const measureElement = (element, instance) => {
171
116
  };
172
117
  const windowScroll = (offset, _ref, instance) => {
173
118
  var _instance$scrollEleme;
174
-
175
119
  let {
176
- canSmooth,
120
+ adjustments,
121
+ behavior,
177
122
  sync
178
123
  } = _ref;
179
- const toOffset = sync ? offset : offset + instance.options.scrollMargin;
124
+ const toOffset = (sync ? offset : offset + instance.options.scrollMargin) + (adjustments ?? 0);
180
125
  (_instance$scrollEleme = instance.scrollElement) == null ? void 0 : _instance$scrollEleme.scrollTo == null ? void 0 : _instance$scrollEleme.scrollTo({
181
126
  [instance.options.horizontal ? 'left' : 'top']: toOffset,
182
- behavior: canSmooth ? 'smooth' : undefined
127
+ behavior
183
128
  });
184
129
  };
185
130
  const elementScroll = (offset, _ref2, instance) => {
186
131
  var _instance$scrollEleme2;
187
-
188
132
  let {
189
- canSmooth,
133
+ adjustments,
134
+ behavior,
190
135
  sync
191
136
  } = _ref2;
192
- const toOffset = sync ? offset : offset + instance.options.scrollMargin;
137
+ const toOffset = (sync ? offset : offset + instance.options.scrollMargin) + (adjustments ?? 0);
193
138
  (_instance$scrollEleme2 = instance.scrollElement) == null ? void 0 : _instance$scrollEleme2.scrollTo == null ? void 0 : _instance$scrollEleme2.scrollTo({
194
139
  [instance.options.horizontal ? 'left' : 'top']: toOffset,
195
- behavior: canSmooth ? 'smooth' : undefined
140
+ behavior
196
141
  });
197
142
  };
198
143
  class Virtualizer {
199
144
  constructor(_opts) {
200
145
  var _this = this;
201
-
202
146
  this.unsubs = [];
203
147
  this.scrollElement = null;
204
148
  this.isScrolling = false;
@@ -206,9 +150,8 @@ class Virtualizer {
206
150
  this.measurementsCache = [];
207
151
  this.itemMeasurementsCache = {};
208
152
  this.pendingMeasuredCacheIndexes = [];
209
- this.scrollDelta = 0;
153
+ this.scrollAdjustments = 0;
210
154
  this.measureElementCache = {};
211
-
212
155
  this.getResizeObserver = (() => {
213
156
  let _ro = null;
214
157
  return () => {
@@ -225,12 +168,10 @@ class Virtualizer {
225
168
  }
226
169
  };
227
170
  })();
228
-
229
171
  this.range = {
230
172
  startIndex: 0,
231
173
  endIndex: 0
232
174
  };
233
-
234
175
  this.setOptions = opts => {
235
176
  Object.entries(opts).forEach(_ref3 => {
236
177
  let [key, value] = _ref3;
@@ -247,7 +188,6 @@ class Virtualizer {
247
188
  horizontal: false,
248
189
  getItemKey: defaultKeyExtractor,
249
190
  rangeExtractor: defaultRangeExtractor,
250
- enableSmoothScroll: true,
251
191
  onChange: () => {},
252
192
  measureElement,
253
193
  initialRect: {
@@ -260,42 +200,33 @@ class Virtualizer {
260
200
  ...opts
261
201
  };
262
202
  };
263
-
264
203
  this.notify = () => {
265
204
  var _this$options$onChang, _this$options;
266
-
267
205
  (_this$options$onChang = (_this$options = this.options).onChange) == null ? void 0 : _this$options$onChang.call(_this$options, this);
268
206
  };
269
-
270
207
  this.cleanup = () => {
271
208
  this.unsubs.filter(Boolean).forEach(d => d());
272
209
  this.unsubs = [];
273
210
  this.scrollElement = null;
274
211
  };
275
-
276
212
  this._didMount = () => {
277
213
  return () => {
278
214
  var _this$getResizeObserv;
279
-
280
215
  (_this$getResizeObserv = this.getResizeObserver()) == null ? void 0 : _this$getResizeObserv.disconnect();
281
216
  this.measureElementCache = {};
282
217
  this.cleanup();
283
218
  };
284
219
  };
285
-
286
220
  this._willUpdate = () => {
287
221
  const scrollElement = this.options.getScrollElement();
288
-
289
222
  if (this.scrollElement !== scrollElement) {
290
223
  this.cleanup();
291
224
  this.scrollElement = scrollElement;
292
-
293
225
  this._scrollToOffset(this.scrollOffset, {
294
- canSmooth: false,
295
- sync: true,
296
- requested: false
226
+ adjustments: undefined,
227
+ behavior: undefined,
228
+ sync: true
297
229
  });
298
-
299
230
  this.unsubs.push(this.options.observeElementRect(this, rect => {
300
231
  this.scrollRect = rect;
301
232
  this.calculateRange();
@@ -305,11 +236,10 @@ class Virtualizer {
305
236
  clearTimeout(this.isScrollingTimeoutId);
306
237
  this.isScrollingTimeoutId = null;
307
238
  }
308
-
309
239
  if (this.scrollOffset !== offset) {
310
240
  this.scrollOffset = offset;
311
241
  this.isScrolling = true;
312
- this.scrollDelta = 0;
242
+ this.scrollAdjustments = 0;
313
243
  this.isScrollingTimeoutId = setTimeout(() => {
314
244
  this.isScrollingTimeoutId = null;
315
245
  this.isScrolling = false;
@@ -317,25 +247,21 @@ class Virtualizer {
317
247
  }, this.options.scrollingDelay);
318
248
  } else {
319
249
  this.isScrolling = false;
320
- this.scrollDelta = 0;
250
+ this.scrollAdjustments = 0;
321
251
  }
322
-
323
252
  this.calculateRange();
324
253
  }));
325
254
  } else if (!this.isScrolling) {
326
255
  this.calculateRange();
327
256
  }
328
257
  };
329
-
330
258
  this.getSize = () => {
331
259
  return this.scrollRect[this.options.horizontal ? 'width' : 'height'];
332
260
  };
333
-
334
261
  this.getMeasurements = memo(() => [this.options.count, this.options.paddingStart, this.options.getItemKey, this.itemMeasurementsCache], (count, paddingStart, getItemKey, measurementsCache) => {
335
262
  const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
336
263
  this.pendingMeasuredCacheIndexes = [];
337
264
  const measurements = this.measurementsCache.slice(0, min);
338
-
339
265
  for (let i = min; i < count; i++) {
340
266
  const key = getItemKey(i);
341
267
  const measuredSize = measurementsCache[key];
@@ -350,7 +276,6 @@ class Virtualizer {
350
276
  key
351
277
  };
352
278
  }
353
-
354
279
  this.measurementsCache = measurements;
355
280
  return measurements;
356
281
  }, {
@@ -363,19 +288,18 @@ class Virtualizer {
363
288
  outerSize,
364
289
  scrollOffset
365
290
  });
366
-
367
291
  if (range.startIndex !== this.range.startIndex || range.endIndex !== this.range.endIndex) {
368
292
  this.range = range;
369
293
  this.notify();
370
294
  }
371
-
372
295
  return this.range;
373
296
  }, {
374
297
  key: process.env.NODE_ENV !== 'production' && 'calculateRange',
375
298
  debug: () => this.options.debug
376
299
  });
377
300
  this.getIndexes = memo(() => [this.options.rangeExtractor, this.range, this.options.overscan, this.options.count], (rangeExtractor, range, overscan, count) => {
378
- return rangeExtractor({ ...range,
301
+ return rangeExtractor({
302
+ ...range,
379
303
  overscan,
380
304
  count: count
381
305
  });
@@ -383,109 +307,84 @@ class Virtualizer {
383
307
  key: process.env.NODE_ENV !== 'production' && 'getIndexes',
384
308
  debug: () => this.options.debug
385
309
  });
386
-
387
310
  this.indexFromElement = node => {
388
311
  const attributeName = this.options.indexAttribute;
389
312
  const indexStr = node.getAttribute(attributeName);
390
-
391
313
  if (!indexStr) {
392
- console.warn("Missing attribute name '" + attributeName + "={index}' on measured element.");
314
+ console.warn(`Missing attribute name '${attributeName}={index}' on measured element.`);
393
315
  return -1;
394
316
  }
395
-
396
317
  return parseInt(indexStr, 10);
397
318
  };
398
-
399
319
  this._measureElement = (node, _sync) => {
400
- var _this$itemMeasurement;
401
-
402
320
  const index = this.indexFromElement(node);
403
321
  const item = this.measurementsCache[index];
404
-
405
322
  if (!item) {
406
323
  return;
407
324
  }
408
-
409
325
  const prevNode = this.measureElementCache[item.key];
410
326
  const ro = this.getResizeObserver();
411
-
412
327
  if (!node.isConnected) {
413
328
  if (prevNode) {
414
329
  ro == null ? void 0 : ro.unobserve(prevNode);
415
330
  delete this.measureElementCache[item.key];
416
331
  }
417
-
418
332
  return;
419
333
  }
420
-
421
334
  if (!prevNode || prevNode !== node) {
422
335
  if (prevNode) {
423
336
  ro == null ? void 0 : ro.unobserve(prevNode);
424
337
  }
425
-
426
338
  this.measureElementCache[item.key] = node;
427
339
  ro == null ? void 0 : ro.observe(node);
428
340
  }
429
-
430
341
  const measuredItemSize = this.options.measureElement(node, this);
431
- const itemSize = (_this$itemMeasurement = this.itemMeasurementsCache[item.key]) != null ? _this$itemMeasurement : item.size;
342
+ const itemSize = this.itemMeasurementsCache[item.key] ?? item.size;
432
343
  const delta = measuredItemSize - itemSize;
433
-
434
344
  if (delta !== 0) {
435
- if (item.start < this.scrollOffset && this.isScrolling && this.destinationOffset === undefined) {
345
+ if (item.start < this.scrollOffset && this.isScrolling) {
436
346
  if (process.env.NODE_ENV !== 'production' && this.options.debug) {
437
347
  console.info('correction', delta);
438
348
  }
439
-
440
- this.scrollDelta += delta;
441
-
442
- this._scrollToOffset(this.scrollOffset + this.scrollDelta, {
443
- canSmooth: false,
444
- sync: false,
445
- requested: false
349
+ this._scrollToOffset(this.scrollOffset, {
350
+ adjustments: this.scrollAdjustments += delta,
351
+ behavior: undefined,
352
+ sync: false
446
353
  });
447
354
  }
448
-
449
355
  this.pendingMeasuredCacheIndexes.push(index);
450
- this.itemMeasurementsCache = { ...this.itemMeasurementsCache,
356
+ this.itemMeasurementsCache = {
357
+ ...this.itemMeasurementsCache,
451
358
  [item.key]: measuredItemSize
452
359
  };
453
360
  this.notify();
454
361
  }
455
362
  };
456
-
457
363
  this.measureElement = node => {
458
364
  if (!node) {
459
365
  return;
460
366
  }
461
-
462
367
  this._measureElement(node, true);
463
368
  };
464
-
465
369
  this.getVirtualItems = memo(() => [this.getIndexes(), this.getMeasurements()], (indexes, measurements) => {
466
370
  const virtualItems = [];
467
-
468
371
  for (let k = 0, len = indexes.length; k < len; k++) {
469
372
  const i = indexes[k];
470
373
  const measurement = measurements[i];
471
374
  virtualItems.push(measurement);
472
375
  }
473
-
474
376
  return virtualItems;
475
377
  }, {
476
378
  key: process.env.NODE_ENV !== 'production' && 'getIndexes',
477
379
  debug: () => this.options.debug
478
380
  });
479
-
480
381
  this.scrollToOffset = function (toOffset, _temp) {
481
382
  let {
482
383
  align = 'start',
483
- smoothScroll = _this.options.enableSmoothScroll
384
+ behavior
484
385
  } = _temp === void 0 ? {} : _temp;
485
386
  const offset = _this.scrollOffset;
486
-
487
387
  const size = _this.getSize();
488
-
489
388
  if (align === 'auto') {
490
389
  if (toOffset <= offset) {
491
390
  align = 'start';
@@ -495,13 +394,11 @@ class Virtualizer {
495
394
  align = 'start';
496
395
  }
497
396
  }
498
-
499
397
  const options = {
500
- canSmooth: smoothScroll,
501
- sync: false,
502
- requested: true
398
+ adjustments: undefined,
399
+ behavior,
400
+ sync: false
503
401
  };
504
-
505
402
  if (align === 'start') {
506
403
  _this._scrollToOffset(toOffset, options);
507
404
  } else if (align === 'end') {
@@ -510,29 +407,21 @@ class Virtualizer {
510
407
  _this._scrollToOffset(toOffset - size / 2, options);
511
408
  }
512
409
  };
513
-
514
410
  this.scrollToIndex = function (index, _temp2) {
515
411
  let {
516
412
  align = 'auto',
517
- smoothScroll = _this.options.enableSmoothScroll,
518
413
  ...rest
519
414
  } = _temp2 === void 0 ? {} : _temp2;
520
-
521
415
  const measurements = _this.getMeasurements();
522
-
523
416
  const offset = _this.scrollOffset;
524
-
525
417
  const size = _this.getSize();
526
-
527
418
  const {
528
419
  count
529
420
  } = _this.options;
530
421
  const measurement = measurements[Math.max(0, Math.min(index, count - 1))];
531
-
532
422
  if (!measurement) {
533
423
  return;
534
424
  }
535
-
536
425
  if (align === 'auto') {
537
426
  if (measurement.end >= offset + size - _this.options.scrollPaddingEnd) {
538
427
  align = 'end';
@@ -542,78 +431,42 @@ class Virtualizer {
542
431
  return;
543
432
  }
544
433
  }
545
-
546
434
  const toOffset = align === 'end' ? measurement.end + _this.options.scrollPaddingEnd : measurement.start - _this.options.scrollPaddingStart;
547
-
548
435
  _this.scrollToOffset(toOffset, {
549
436
  align,
550
- smoothScroll,
551
437
  ...rest
552
438
  });
553
439
  };
554
-
555
440
  this.getTotalSize = () => {
556
441
  var _this$getMeasurements;
557
-
558
442
  return (((_this$getMeasurements = this.getMeasurements()[this.options.count - 1]) == null ? void 0 : _this$getMeasurements.end) || this.options.paddingStart) + this.options.paddingEnd;
559
443
  };
560
-
561
444
  this._scrollToOffset = (offset, _ref4) => {
562
445
  let {
563
- requested,
564
- canSmooth,
446
+ adjustments,
447
+ behavior,
565
448
  sync
566
449
  } = _ref4;
567
- clearTimeout(this.scrollCheckFrame);
568
-
569
- if (requested) {
570
- this.destinationOffset = offset;
571
- }
572
-
573
450
  this.options.scrollToFn(offset, {
574
- canSmooth,
575
- sync
451
+ behavior,
452
+ sync,
453
+ adjustments
576
454
  }, this);
577
- let scrollCheckFrame;
578
-
579
- const check = () => {
580
- let lastOffset = this.scrollOffset;
581
- this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {
582
- if (this.scrollCheckFrame !== scrollCheckFrame) {
583
- return;
584
- }
585
-
586
- if (this.scrollOffset === lastOffset) {
587
- this.destinationOffset = undefined;
588
- return;
589
- }
590
-
591
- lastOffset = this.scrollOffset;
592
- check();
593
- }, 100);
594
- };
595
-
596
- check();
597
455
  };
598
-
599
456
  this.measure = () => {
600
457
  this.itemMeasurementsCache = {};
601
458
  this.notify();
602
459
  };
603
-
604
460
  this.setOptions(_opts);
605
461
  this.scrollRect = this.options.initialRect;
606
462
  this.scrollOffset = this.options.initialOffset;
607
463
  this.calculateRange();
608
464
  }
609
-
610
465
  }
611
-
612
466
  const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
613
467
  while (low <= high) {
614
468
  const middle = (low + high) / 2 | 0;
615
469
  const currentValue = getCurrentValue(middle);
616
-
617
470
  if (currentValue < value) {
618
471
  low = middle + 1;
619
472
  } else if (currentValue > value) {
@@ -622,14 +475,12 @@ const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
622
475
  return middle;
623
476
  }
624
477
  }
625
-
626
478
  if (low > 0) {
627
479
  return low - 1;
628
480
  } else {
629
481
  return 0;
630
482
  }
631
483
  };
632
-
633
484
  function calculateRange(_ref5) {
634
485
  let {
635
486
  measurements,
@@ -637,21 +488,17 @@ function calculateRange(_ref5) {
637
488
  scrollOffset
638
489
  } = _ref5;
639
490
  const count = measurements.length - 1;
640
-
641
491
  const getOffset = index => measurements[index].start;
642
-
643
492
  const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
644
493
  let endIndex = startIndex;
645
-
646
494
  while (endIndex < count && measurements[endIndex].end < scrollOffset + outerSize) {
647
495
  endIndex++;
648
496
  }
649
-
650
497
  return {
651
498
  startIndex,
652
499
  endIndex
653
500
  };
654
501
  }
655
502
 
656
- export { Virtualizer, defaultKeyExtractor, defaultRangeExtractor, elementScroll, measureElement, memo, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, windowScroll };
657
- //# sourceMappingURL=index.js.map
503
+ export { Virtualizer, defaultKeyExtractor, defaultRangeExtractor, elementScroll, measureElement, observeElementOffset, observeElementRect, observeWindowOffset, observeWindowRect, windowScroll };
504
+ //# sourceMappingURL=index.esm.js.map