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