@tanstack/virtual-core 3.0.0-beta.2 → 3.0.0-beta.21

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: any\n debug?: () => any\n onChange?: (result: TResult) => void\n },\n): () => TResult {\n let deps: any[] = []\n let result: TResult | undefined\n\n return () => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n opts?.onChange?.(result)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n return result!\n }\n}\n"],"names":["memo","getDeps","fn","opts","deps","result","depTime","key","debug","Date","now","newDeps","depsChanged","length","some","dep","index","resultTime","onChange","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min"],"mappings":";;;;;;;;;;;;;;AAIO,SAASA,IAAT,CACLC,OADK,EAELC,EAFK,EAGLC,IAHK,EAQU;EACf,IAAIC,IAAW,GAAG,EAAlB,CAAA;AACA,EAAA,IAAIC,MAAJ,CAAA;AAEA,EAAA,OAAO,MAAM;AACX,IAAA,IAAIC,OAAJ,CAAA;AACA,IAAA,IAAIH,IAAI,CAACI,GAAL,IAAYJ,IAAI,CAACK,KAAjB,IAAYL,IAAAA,IAAAA,IAAI,CAACK,KAAL,EAAhB,EAAgCF,OAAO,GAAGG,IAAI,CAACC,GAAL,EAAV,CAAA;IAEhC,MAAMC,OAAO,GAAGV,OAAO,EAAvB,CAAA;IAEA,MAAMW,WAAW,GACfD,OAAO,CAACE,MAAR,KAAmBT,IAAI,CAACS,MAAxB,IACAF,OAAO,CAACG,IAAR,CAAa,CAACC,GAAD,EAAWC,KAAX,KAA6BZ,IAAI,CAACY,KAAD,CAAJ,KAAgBD,GAA1D,CAFF,CAAA;;IAIA,IAAI,CAACH,WAAL,EAAkB;AAChB,MAAA,OAAOP,MAAP,CAAA;AACD,KAAA;;AAEDD,IAAAA,IAAI,GAAGO,OAAP,CAAA;AAEA,IAAA,IAAIM,UAAJ,CAAA;AACA,IAAA,IAAId,IAAI,CAACI,GAAL,IAAYJ,IAAI,CAACK,KAAjB,IAAYL,IAAAA,IAAAA,IAAI,CAACK,KAAL,EAAhB,EAAgCS,UAAU,GAAGR,IAAI,CAACC,GAAL,EAAb,CAAA;AAEhCL,IAAAA,MAAM,GAAGH,EAAE,CAAC,GAAGS,OAAJ,CAAX,CAAA;IACAR,IAAI,IAAA,IAAJ,GAAAA,KAAAA,CAAAA,GAAAA,IAAI,CAAEe,QAAN,oBAAAf,IAAI,CAAEe,QAAN,CAAiBb,MAAjB,CAAA,CAAA;;AAEA,IAAA,IAAIF,IAAI,CAACI,GAAL,IAAYJ,IAAI,CAACK,KAAjB,IAAA,IAAA,IAAYL,IAAI,CAACK,KAAL,EAAhB,EAAgC;AAC9B,MAAA,MAAMW,UAAU,GAAGC,IAAI,CAACC,KAAL,CAAW,CAACZ,IAAI,CAACC,GAAL,EAAaJ,GAAAA,OAAd,IAA0B,GAArC,IAA4C,GAA/D,CAAA;AACA,MAAA,MAAMgB,aAAa,GAAGF,IAAI,CAACC,KAAL,CAAW,CAACZ,IAAI,CAACC,GAAL,EAAaO,GAAAA,UAAd,IAA6B,GAAxC,IAA+C,GAArE,CAAA;AACA,MAAA,MAAMM,mBAAmB,GAAGD,aAAa,GAAG,EAA5C,CAAA;;AAEA,MAAA,MAAME,GAAG,GAAG,CAACC,GAAD,EAAuBC,GAAvB,KAAuC;AACjDD,QAAAA,GAAG,GAAGE,MAAM,CAACF,GAAD,CAAZ,CAAA;;AACA,QAAA,OAAOA,GAAG,CAACZ,MAAJ,GAAaa,GAApB,EAAyB;UACvBD,GAAG,GAAG,MAAMA,GAAZ,CAAA;AACD,SAAA;;AACD,QAAA,OAAOA,GAAP,CAAA;OALF,CAAA;;AAQAG,MAAAA,OAAO,CAACC,IAAR,CAAA,WAAA,GACSL,GAAG,CAACF,aAAD,EAAgB,CAAhB,CADZ,GAAA,IAAA,GACmCE,GAAG,CAACL,UAAD,EAAa,CAAb,CADtC,uGAKmBC,IAAI,CAACU,GAAL,CACX,CADW,EAEXV,IAAI,CAACW,GAAL,CAAS,MAAM,GAAMR,GAAAA,mBAArB,EAA0C,GAA1C,CAFW,CALnB,GAAA,gBAAA,EASEpB,IATF,IASEA,IAAAA,GAAAA,KAAAA,CAAAA,GAAAA,IAAI,CAAEI,GATR,CAAA,CAAA;AAWD,KAAA;;AAED,IAAA,OAAOF,MAAP,CAAA;GAhDF,CAAA;AAkDD;;;;"}
@@ -8,76 +8,6 @@
8
8
  *
9
9
  * @license MIT
10
10
  */
11
- var props = ["bottom", "height", "left", "right", "top", "width"];
12
-
13
- var rectChanged = function rectChanged(a, b) {
14
- if (a === void 0) {
15
- a = {};
16
- }
17
-
18
- if (b === void 0) {
19
- b = {};
20
- }
21
-
22
- return props.some(function (prop) {
23
- return a[prop] !== b[prop];
24
- });
25
- };
26
-
27
- var observedNodes = /*#__PURE__*/new Map();
28
- var rafId;
29
-
30
- var run = function run() {
31
- var changedStates = [];
32
- observedNodes.forEach(function (state, node) {
33
- var newRect = node.getBoundingClientRect();
34
-
35
- if (rectChanged(newRect, state.rect)) {
36
- state.rect = newRect;
37
- changedStates.push(state);
38
- }
39
- });
40
- changedStates.forEach(function (state) {
41
- state.callbacks.forEach(function (cb) {
42
- return cb(state.rect);
43
- });
44
- });
45
- rafId = window.requestAnimationFrame(run);
46
- };
47
-
48
- function observeRect(node, cb) {
49
- return {
50
- observe: function observe() {
51
- var wasEmpty = observedNodes.size === 0;
52
-
53
- if (observedNodes.has(node)) {
54
- observedNodes.get(node).callbacks.push(cb);
55
- } else {
56
- observedNodes.set(node, {
57
- rect: undefined,
58
- hasRectChanged: false,
59
- callbacks: [cb]
60
- });
61
- }
62
-
63
- if (wasEmpty) run();
64
- },
65
- unobserve: function unobserve() {
66
- var state = observedNodes.get(node);
67
-
68
- if (state) {
69
- // Remove the callback
70
- var index = state.callbacks.indexOf(cb);
71
- if (index >= 0) state.callbacks.splice(index, 1); // Remove the node reference
72
-
73
- if (!state.callbacks.length) observedNodes["delete"](node); // Stop the loop
74
-
75
- if (!observedNodes.size) cancelAnimationFrame(rafId);
76
- }
77
- }
78
- };
79
- }
80
-
81
11
  function memo(getDeps, fn, opts) {
82
12
  let deps = [];
83
13
  let result;
@@ -132,9 +62,29 @@ const defaultRangeExtractor = range => {
132
62
 
133
63
  return arr;
134
64
  };
65
+
66
+ const memoRectCallback = (instance, cb) => {
67
+ let prev = {
68
+ height: -1,
69
+ width: -1
70
+ };
71
+ return rect => {
72
+ if (instance.options.horizontal ? rect.width !== prev.width : rect.height !== prev.height) {
73
+ cb(rect);
74
+ }
75
+
76
+ prev = rect;
77
+ };
78
+ };
79
+
135
80
  const observeElementRect = (instance, cb) => {
136
- const observer = observeRect(instance.scrollElement, rect => {
137
- cb(rect);
81
+ const observer = new ResizeObserver(entries => {
82
+ var _entries$, _entries$2;
83
+
84
+ cb({
85
+ width: (_entries$ = entries[0]) == null ? void 0 : _entries$.contentRect.width,
86
+ height: (_entries$2 = entries[0]) == null ? void 0 : _entries$2.contentRect.height
87
+ });
138
88
  });
139
89
 
140
90
  if (!instance.scrollElement) {
@@ -142,18 +92,18 @@ const observeElementRect = (instance, cb) => {
142
92
  }
143
93
 
144
94
  cb(instance.scrollElement.getBoundingClientRect());
145
- observer.observe();
95
+ observer.observe(instance.scrollElement);
146
96
  return () => {
147
- observer.unobserve();
97
+ observer.unobserve(instance.scrollElement);
148
98
  };
149
99
  };
150
100
  const observeWindowRect = (instance, cb) => {
151
- const onResize = () => {
152
- cb({
153
- width: instance.scrollElement.innerWidth,
154
- height: instance.scrollElement.innerHeight
155
- });
156
- };
101
+ const memoizedCallback = memoRectCallback(instance, cb);
102
+
103
+ const onResize = () => memoizedCallback({
104
+ width: instance.scrollElement.innerWidth,
105
+ height: instance.scrollElement.innerHeight
106
+ });
157
107
 
158
108
  if (!instance.scrollElement) {
159
109
  return;
@@ -168,52 +118,80 @@ const observeWindowRect = (instance, cb) => {
168
118
  instance.scrollElement.removeEventListener('resize', onResize);
169
119
  };
170
120
  };
171
- const observeElementOffset = (instance, cb) => {
172
- const onScroll = () => cb(instance.scrollElement[instance.options.horizontal ? 'scrollLeft' : 'scrollTop']);
121
+ const scrollProps = {
122
+ element: ['scrollLeft', 'scrollTop'],
123
+ window: ['scrollX', 'scrollY']
124
+ };
173
125
 
174
- if (!instance.scrollElement) {
175
- return;
176
- }
126
+ const createOffsetObserver = mode => {
127
+ return (instance, cb) => {
128
+ if (!instance.scrollElement) {
129
+ return;
130
+ }
177
131
 
178
- onScroll();
179
- instance.scrollElement.addEventListener('scroll', onScroll, {
180
- capture: false,
181
- passive: true
182
- });
183
- return () => {
184
- instance.scrollElement.removeEventListener('scroll', onScroll);
185
- };
186
- };
187
- const observeWindowOffset = (instance, cb) => {
188
- const onScroll = () => cb(instance.scrollElement[instance.options.horizontal ? 'scrollX' : 'scrollY']);
132
+ const propX = scrollProps[mode][0];
133
+ const propY = scrollProps[mode][1];
134
+ let prevX = instance.scrollElement[propX];
135
+ let prevY = instance.scrollElement[propY];
189
136
 
190
- if (!instance.scrollElement) {
191
- return;
192
- }
137
+ const scroll = () => {
138
+ const offset = instance.scrollElement[instance.options.horizontal ? propX : propY];
139
+ cb(Math.max(0, offset - instance.options.scrollMargin));
140
+ };
193
141
 
194
- onScroll();
195
- instance.scrollElement.addEventListener('scroll', onScroll, {
196
- capture: false,
197
- passive: true
198
- });
199
- return () => {
200
- instance.scrollElement.removeEventListener('scroll', onScroll);
142
+ scroll();
143
+
144
+ const onScroll = e => {
145
+ const target = e.currentTarget;
146
+ const scrollX = target[propX];
147
+ const scrollY = target[propY];
148
+
149
+ if (instance.options.horizontal ? prevX - scrollX : prevY - scrollY) {
150
+ scroll();
151
+ }
152
+
153
+ prevX = scrollX;
154
+ prevY = scrollY;
155
+ };
156
+
157
+ instance.scrollElement.addEventListener('scroll', onScroll, {
158
+ capture: false,
159
+ passive: true
160
+ });
161
+ return () => {
162
+ instance.scrollElement.removeEventListener('scroll', onScroll);
163
+ };
201
164
  };
202
165
  };
166
+
167
+ const observeElementOffset = createOffsetObserver('element');
168
+ const observeWindowOffset = createOffsetObserver('window');
203
169
  const measureElement = (element, instance) => {
204
- return element.getBoundingClientRect()[instance.options.horizontal ? 'width' : 'height'];
170
+ return Math.round(element.getBoundingClientRect()[instance.options.horizontal ? 'width' : 'height']);
205
171
  };
206
- const windowScroll = (offset, canSmooth, instance) => {
172
+ const windowScroll = (offset, _ref, instance) => {
207
173
  var _instance$scrollEleme;
208
- (_instance$scrollEleme = instance.scrollElement) == null ? void 0 : _instance$scrollEleme.scrollTo({
209
- [instance.options.horizontal ? 'left' : 'top']: offset,
174
+
175
+ let {
176
+ canSmooth,
177
+ sync
178
+ } = _ref;
179
+ const toOffset = sync ? offset : offset + instance.options.scrollMargin;
180
+ (_instance$scrollEleme = instance.scrollElement) == null ? void 0 : _instance$scrollEleme.scrollTo == null ? void 0 : _instance$scrollEleme.scrollTo({
181
+ [instance.options.horizontal ? 'left' : 'top']: toOffset,
210
182
  behavior: canSmooth ? 'smooth' : undefined
211
183
  });
212
184
  };
213
- const elementScroll = (offset, canSmooth, instance) => {
185
+ const elementScroll = (offset, _ref2, instance) => {
214
186
  var _instance$scrollEleme2;
215
- (_instance$scrollEleme2 = instance.scrollElement) == null ? void 0 : _instance$scrollEleme2.scrollTo({
216
- [instance.options.horizontal ? 'left' : 'top']: offset,
187
+
188
+ let {
189
+ canSmooth,
190
+ sync
191
+ } = _ref2;
192
+ const toOffset = sync ? offset : offset + instance.options.scrollMargin;
193
+ (_instance$scrollEleme2 = instance.scrollElement) == null ? void 0 : _instance$scrollEleme2.scrollTo == null ? void 0 : _instance$scrollEleme2.scrollTo({
194
+ [instance.options.horizontal ? 'left' : 'top']: toOffset,
217
195
  behavior: canSmooth ? 'smooth' : undefined
218
196
  });
219
197
  };
@@ -223,13 +201,26 @@ class Virtualizer {
223
201
 
224
202
  this.unsubs = [];
225
203
  this.scrollElement = null;
204
+ this.isScrolling = false;
205
+ this.isScrollingTimeoutId = null;
226
206
  this.measurementsCache = [];
227
207
  this.itemMeasurementsCache = {};
228
208
  this.pendingMeasuredCacheIndexes = [];
209
+ this.scrollDelta = 0;
210
+ this.measureElementCache = {};
211
+ this.ro = new ResizeObserver(entries => {
212
+ entries.forEach(entry => {
213
+ this._measureElement(entry.target, false);
214
+ });
215
+ });
216
+ this.range = {
217
+ startIndex: 0,
218
+ endIndex: 0
219
+ };
229
220
 
230
221
  this.setOptions = opts => {
231
- Object.entries(opts).forEach(_ref => {
232
- let [key, value] = _ref;
222
+ Object.entries(opts).forEach(_ref3 => {
223
+ let [key, value] = _ref3;
233
224
  if (typeof value === 'undefined') delete opts[key];
234
225
  });
235
226
  this.options = {
@@ -250,6 +241,9 @@ class Virtualizer {
250
241
  width: 0,
251
242
  height: 0
252
243
  },
244
+ scrollMargin: 0,
245
+ scrollingDelay: 150,
246
+ indexAttribute: 'data-index',
253
247
  ...opts
254
248
  };
255
249
  };
@@ -263,10 +257,13 @@ class Virtualizer {
263
257
  this.cleanup = () => {
264
258
  this.unsubs.filter(Boolean).forEach(d => d());
265
259
  this.unsubs = [];
260
+ this.scrollElement = null;
266
261
  };
267
262
 
268
263
  this._didMount = () => {
269
264
  return () => {
265
+ this.ro.disconnect();
266
+ this.measureElementCache = {};
270
267
  this.cleanup();
271
268
  };
272
269
  };
@@ -277,14 +274,41 @@ class Virtualizer {
277
274
  if (this.scrollElement !== scrollElement) {
278
275
  this.cleanup();
279
276
  this.scrollElement = scrollElement;
277
+
278
+ this._scrollToOffset(this.scrollOffset, {
279
+ canSmooth: false,
280
+ sync: true,
281
+ requested: false
282
+ });
283
+
280
284
  this.unsubs.push(this.options.observeElementRect(this, rect => {
281
285
  this.scrollRect = rect;
282
- this.notify();
286
+ this.calculateRange();
283
287
  }));
284
288
  this.unsubs.push(this.options.observeElementOffset(this, offset => {
285
- this.scrollOffset = offset;
286
- this.notify();
289
+ if (this.isScrollingTimeoutId !== null) {
290
+ clearTimeout(this.isScrollingTimeoutId);
291
+ this.isScrollingTimeoutId = null;
292
+ }
293
+
294
+ if (this.scrollOffset !== offset) {
295
+ this.scrollOffset = offset;
296
+ this.isScrolling = true;
297
+ this.scrollDelta = 0;
298
+ this.isScrollingTimeoutId = setTimeout(() => {
299
+ this.isScrollingTimeoutId = null;
300
+ this.isScrolling = false;
301
+ this.notify();
302
+ }, this.options.scrollingDelay);
303
+ } else {
304
+ this.isScrolling = false;
305
+ this.scrollDelta = 0;
306
+ }
307
+
308
+ this.calculateRange();
287
309
  }));
310
+ } else if (!this.isScrolling) {
311
+ this.calculateRange();
288
312
  }
289
313
  };
290
314
 
@@ -315,108 +339,170 @@ class Virtualizer {
315
339
  this.measurementsCache = measurements;
316
340
  return measurements;
317
341
  }, {
318
- key: process.env.NODE_ENV === 'development' && 'getMeasurements',
342
+ key: process.env.NODE_ENV !== 'production' && 'getMeasurements',
319
343
  debug: () => this.options.debug
320
344
  });
321
345
  this.calculateRange = memo(() => [this.getMeasurements(), this.getSize(), this.scrollOffset], (measurements, outerSize, scrollOffset) => {
322
- return calculateRange({
346
+ const range = calculateRange({
323
347
  measurements,
324
348
  outerSize,
325
349
  scrollOffset
326
350
  });
351
+
352
+ if (range.startIndex !== this.range.startIndex || range.endIndex !== this.range.endIndex) {
353
+ this.range = range;
354
+ this.notify();
355
+ }
356
+
357
+ return this.range;
327
358
  }, {
328
- key: process.env.NODE_ENV === 'development' && 'calculateRange',
359
+ key: process.env.NODE_ENV !== 'production' && 'calculateRange',
329
360
  debug: () => this.options.debug
330
361
  });
331
- this.getIndexes = memo(() => [this.options.rangeExtractor, this.calculateRange(), this.options.overscan, this.options.count], (rangeExtractor, range, overscan, count) => {
362
+ this.getIndexes = memo(() => [this.options.rangeExtractor, this.range, this.options.overscan, this.options.count], (rangeExtractor, range, overscan, count) => {
332
363
  return rangeExtractor({ ...range,
333
364
  overscan,
334
365
  count: count
335
366
  });
336
367
  }, {
337
- key: process.env.NODE_ENV === 'development' && 'getIndexes'
368
+ key: process.env.NODE_ENV !== 'production' && 'getIndexes',
369
+ debug: () => this.options.debug
338
370
  });
339
- this.getVirtualItems = memo(() => [this.getIndexes(), this.getMeasurements(), this.options.measureElement], (indexes, measurements, measureElement) => {
371
+
372
+ this.indexFromElement = node => {
373
+ const attributeName = this.options.indexAttribute;
374
+ const indexStr = node.getAttribute(attributeName);
375
+
376
+ if (!indexStr) {
377
+ console.warn("Missing attribute name '" + attributeName + "={index}' on measured element.");
378
+ return -1;
379
+ }
380
+
381
+ return parseInt(indexStr, 10);
382
+ };
383
+
384
+ this._measureElement = (node, _sync) => {
385
+ var _this$itemMeasurement;
386
+
387
+ const index = this.indexFromElement(node);
388
+ const item = this.measurementsCache[index];
389
+
390
+ if (!item) {
391
+ return;
392
+ }
393
+
394
+ const key = String(item.key);
395
+ const prevNode = this.measureElementCache[key];
396
+
397
+ if (!node.isConnected) {
398
+ if (prevNode) {
399
+ this.ro.unobserve(prevNode);
400
+ delete this.measureElementCache[key];
401
+ }
402
+
403
+ return;
404
+ }
405
+
406
+ if (!prevNode || prevNode !== node) {
407
+ if (prevNode) {
408
+ this.ro.unobserve(prevNode);
409
+ }
410
+
411
+ this.measureElementCache[key] = node;
412
+ this.ro.observe(node);
413
+ }
414
+
415
+ const measuredItemSize = this.options.measureElement(node, this);
416
+ const itemSize = (_this$itemMeasurement = this.itemMeasurementsCache[item.key]) != null ? _this$itemMeasurement : item.size;
417
+
418
+ if (measuredItemSize !== itemSize) {
419
+ if (item.start < this.scrollOffset) {
420
+ if (process.env.NODE_ENV !== 'production' && this.options.debug) {
421
+ console.info('correction', measuredItemSize - itemSize);
422
+ }
423
+
424
+ if (this.destinationOffset === undefined) {
425
+ this.scrollDelta += measuredItemSize - itemSize;
426
+
427
+ this._scrollToOffset(this.scrollOffset + this.scrollDelta, {
428
+ canSmooth: false,
429
+ sync: false,
430
+ requested: false
431
+ });
432
+ }
433
+ }
434
+
435
+ this.pendingMeasuredCacheIndexes.push(index);
436
+ this.itemMeasurementsCache = { ...this.itemMeasurementsCache,
437
+ [item.key]: measuredItemSize
438
+ };
439
+ this.notify();
440
+ }
441
+ };
442
+
443
+ this.measureElement = node => {
444
+ if (!node) {
445
+ return;
446
+ }
447
+
448
+ this._measureElement(node, true);
449
+ };
450
+
451
+ this.getVirtualItems = memo(() => [this.getIndexes(), this.getMeasurements()], (indexes, measurements) => {
340
452
  const virtualItems = [];
341
453
 
342
454
  for (let k = 0, len = indexes.length; k < len; k++) {
343
455
  const i = indexes[k];
344
456
  const measurement = measurements[i];
345
- const item = { ...measurement,
346
- measureElement: measurableItem => {
347
- if (measurableItem) {
348
- const measuredItemSize = measureElement(measurableItem, this);
349
-
350
- if (measuredItemSize !== item.size) {
351
- if (item.start < this.scrollOffset) {
352
- if (process.env.NODE_ENV === 'development' && this.options.debug) console.info('correction', measuredItemSize - item.size);
353
-
354
- if (!this.destinationOffset) {
355
- this._scrollToOffset(this.scrollOffset + (measuredItemSize - item.size), false);
356
- }
357
- }
358
-
359
- this.pendingMeasuredCacheIndexes.push(i);
360
- this.itemMeasurementsCache = { ...this.itemMeasurementsCache,
361
- [item.key]: measuredItemSize
362
- };
363
- this.notify();
364
- }
365
- }
366
- }
367
- };
368
- virtualItems.push(item);
457
+ virtualItems.push(measurement);
369
458
  }
370
459
 
371
460
  return virtualItems;
372
461
  }, {
373
- key: process.env.NODE_ENV === 'development' && 'getIndexes'
462
+ key: process.env.NODE_ENV !== 'production' && 'getIndexes',
463
+ debug: () => this.options.debug
374
464
  });
375
465
 
376
466
  this.scrollToOffset = function (toOffset, _temp) {
377
467
  let {
378
- align
379
- } = _temp === void 0 ? {
380
- align: 'start'
381
- } : _temp;
382
-
383
- const attempt = () => {
384
- const offset = _this.scrollOffset;
468
+ align = 'start',
469
+ smoothScroll = _this.options.enableSmoothScroll
470
+ } = _temp === void 0 ? {} : _temp;
471
+ const offset = _this.scrollOffset;
385
472
 
386
- const size = _this.getSize();
473
+ const size = _this.getSize();
387
474
 
388
- if (align === 'auto') {
389
- if (toOffset <= offset) {
390
- align = 'start';
391
- } else if (toOffset >= offset + size) {
392
- align = 'end';
393
- } else {
394
- align = 'start';
395
- }
475
+ if (align === 'auto') {
476
+ if (toOffset <= offset) {
477
+ align = 'start';
478
+ } else if (toOffset >= offset + size) {
479
+ align = 'end';
480
+ } else {
481
+ align = 'start';
396
482
  }
483
+ }
397
484
 
398
- if (align === 'start') {
399
- _this._scrollToOffset(toOffset, true);
400
- } else if (align === 'end') {
401
- _this._scrollToOffset(toOffset - size, true);
402
- } else if (align === 'center') {
403
- _this._scrollToOffset(toOffset - size / 2, true);
404
- }
485
+ const options = {
486
+ canSmooth: smoothScroll,
487
+ sync: false,
488
+ requested: true
405
489
  };
406
490
 
407
- attempt();
408
- requestAnimationFrame(() => {
409
- attempt();
410
- });
491
+ if (align === 'start') {
492
+ _this._scrollToOffset(toOffset, options);
493
+ } else if (align === 'end') {
494
+ _this._scrollToOffset(toOffset - size, options);
495
+ } else if (align === 'center') {
496
+ _this._scrollToOffset(toOffset - size / 2, options);
497
+ }
411
498
  };
412
499
 
413
500
  this.scrollToIndex = function (index, _temp2) {
414
501
  let {
415
- align,
502
+ align = 'auto',
503
+ smoothScroll = _this.options.enableSmoothScroll,
416
504
  ...rest
417
- } = _temp2 === void 0 ? {
418
- align: 'auto'
419
- } : _temp2;
505
+ } = _temp2 === void 0 ? {} : _temp2;
420
506
 
421
507
  const measurements = _this.getMeasurements();
422
508
 
@@ -447,6 +533,7 @@ class Virtualizer {
447
533
 
448
534
  _this.scrollToOffset(toOffset, {
449
535
  align,
536
+ smoothScroll,
450
537
  ...rest
451
538
  });
452
539
  };
@@ -457,10 +544,22 @@ class Virtualizer {
457
544
  return (((_this$getMeasurements = this.getMeasurements()[this.options.count - 1]) == null ? void 0 : _this$getMeasurements.end) || this.options.paddingStart) + this.options.paddingEnd;
458
545
  };
459
546
 
460
- this._scrollToOffset = (offset, canSmooth) => {
547
+ this._scrollToOffset = (offset, _ref4) => {
548
+ let {
549
+ requested,
550
+ canSmooth,
551
+ sync
552
+ } = _ref4;
461
553
  clearTimeout(this.scrollCheckFrame);
462
- this.destinationOffset = offset;
463
- this.options.scrollToFn(offset, this.options.enableSmoothScroll && canSmooth, this);
554
+
555
+ if (requested) {
556
+ this.destinationOffset = offset;
557
+ }
558
+
559
+ this.options.scrollToFn(offset, {
560
+ canSmooth,
561
+ sync
562
+ }, this);
464
563
  let scrollCheckFrame;
465
564
 
466
565
  const check = () => {
@@ -491,6 +590,7 @@ class Virtualizer {
491
590
  this.setOptions(_opts);
492
591
  this.scrollRect = this.options.initialRect;
493
592
  this.scrollOffset = this.options.initialOffset;
593
+ this.calculateRange();
494
594
  }
495
595
 
496
596
  }
@@ -516,12 +616,12 @@ const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
516
616
  }
517
617
  };
518
618
 
519
- function calculateRange(_ref2) {
619
+ function calculateRange(_ref5) {
520
620
  let {
521
621
  measurements,
522
622
  outerSize,
523
623
  scrollOffset
524
- } = _ref2;
624
+ } = _ref5;
525
625
  const count = measurements.length - 1;
526
626
 
527
627
  const getOffset = index => measurements[index].start;