@tanstack/virtual-core 3.0.0-beta.8 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/LICENSE +21 -0
  2. package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js +27 -0
  3. package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js.map +1 -0
  4. package/build/lib/_virtual/_rollupPluginBabelHelpers.js +31 -0
  5. package/build/lib/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  6. package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs +27 -0
  7. package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs.map +1 -0
  8. package/build/lib/index.d.ts +126 -0
  9. package/build/lib/index.esm.js +639 -0
  10. package/build/lib/index.esm.js.map +1 -0
  11. package/build/lib/index.js +654 -0
  12. package/build/lib/index.js.map +1 -0
  13. package/build/lib/index.mjs +639 -0
  14. package/build/lib/index.mjs.map +1 -0
  15. package/build/lib/utils.d.ts +10 -0
  16. package/build/lib/utils.esm.js +58 -0
  17. package/build/lib/utils.esm.js.map +1 -0
  18. package/build/{cjs/packages/virtual-core/src → lib}/utils.js +28 -21
  19. package/build/lib/utils.js.map +1 -0
  20. package/build/lib/utils.mjs +58 -0
  21. package/build/lib/utils.mjs.map +1 -0
  22. package/build/umd/index.development.js +592 -454
  23. package/build/umd/index.development.js.map +1 -1
  24. package/build/umd/index.production.js +1 -1
  25. package/build/umd/index.production.js.map +1 -1
  26. package/package.json +16 -14
  27. package/src/index.ts +551 -244
  28. package/src/utils.ts +17 -5
  29. package/build/cjs/packages/virtual-core/src/index.js +0 -466
  30. package/build/cjs/packages/virtual-core/src/index.js.map +0 -1
  31. package/build/cjs/packages/virtual-core/src/utils.js.map +0 -1
  32. package/build/esm/index.js +0 -560
  33. package/build/esm/index.js.map +0 -1
  34. package/build/stats-html.html +0 -2689
  35. package/build/stats.json +0 -101
  36. package/build/types/index.d.ts +0 -88
  37. package/build/types/utils.d.ts +0 -7
@@ -14,515 +14,657 @@
14
14
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.VirtualCore = {}));
15
15
  })(this, (function (exports) { 'use strict';
16
16
 
17
- var props = ["bottom", "height", "left", "right", "top", "width"];
18
-
19
- var rectChanged = function rectChanged(a, b) {
20
- if (a === void 0) {
21
- a = {};
22
- }
23
-
24
- if (b === void 0) {
25
- b = {};
26
- }
27
-
28
- return props.some(function (prop) {
29
- return a[prop] !== b[prop];
30
- });
31
- };
32
-
33
- var observedNodes = /*#__PURE__*/new Map();
34
- var rafId;
35
-
36
- var run = function run() {
37
- var changedStates = [];
38
- observedNodes.forEach(function (state, node) {
39
- var newRect = node.getBoundingClientRect();
40
-
41
- if (rectChanged(newRect, state.rect)) {
42
- state.rect = newRect;
43
- changedStates.push(state);
44
- }
45
- });
46
- changedStates.forEach(function (state) {
47
- state.callbacks.forEach(function (cb) {
48
- return cb(state.rect);
49
- });
50
- });
51
- rafId = window.requestAnimationFrame(run);
52
- };
53
-
54
- function observeRect(node, cb) {
55
- return {
56
- observe: function observe() {
57
- var wasEmpty = observedNodes.size === 0;
58
-
59
- if (observedNodes.has(node)) {
60
- observedNodes.get(node).callbacks.push(cb);
61
- } else {
62
- observedNodes.set(node, {
63
- rect: undefined,
64
- hasRectChanged: false,
65
- callbacks: [cb]
66
- });
67
- }
68
-
69
- if (wasEmpty) run();
70
- },
71
- unobserve: function unobserve() {
72
- var state = observedNodes.get(node);
73
-
74
- if (state) {
75
- // Remove the callback
76
- var index = state.callbacks.indexOf(cb);
77
- if (index >= 0) state.callbacks.splice(index, 1); // Remove the node reference
78
-
79
- if (!state.callbacks.length) observedNodes["delete"](node); // Stop the loop
80
-
81
- if (!observedNodes.size) cancelAnimationFrame(rafId);
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
+ }
82
25
  }
83
26
  }
27
+ return target;
84
28
  };
29
+ return _extends.apply(this, arguments);
85
30
  }
86
31
 
87
32
  function memo(getDeps, fn, opts) {
88
- let deps = [];
89
- let result;
90
- return () => {
91
- let depTime;
33
+ var _opts$initialDeps;
34
+ var deps = (_opts$initialDeps = opts.initialDeps) != null ? _opts$initialDeps : [];
35
+ var result;
36
+ return function () {
37
+ var depTime;
92
38
  if (opts.key && opts.debug != null && opts.debug()) depTime = Date.now();
93
- const newDeps = getDeps();
94
- const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
95
-
39
+ var newDeps = getDeps();
40
+ var depsChanged = newDeps.length !== deps.length || newDeps.some(function (dep, index) {
41
+ return deps[index] !== dep;
42
+ });
96
43
  if (!depsChanged) {
97
44
  return result;
98
45
  }
99
-
100
46
  deps = newDeps;
101
- let resultTime;
47
+ var resultTime;
102
48
  if (opts.key && opts.debug != null && opts.debug()) resultTime = Date.now();
103
- result = fn(...newDeps);
104
- opts == null ? void 0 : opts.onChange == null ? void 0 : opts.onChange(result);
105
-
49
+ result = fn.apply(void 0, newDeps);
106
50
  if (opts.key && opts.debug != null && opts.debug()) {
107
- const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
108
- const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
109
- const resultFpsPercentage = resultEndTime / 16;
110
-
111
- 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) {
112
55
  str = String(str);
113
-
114
56
  while (str.length < num) {
115
57
  str = ' ' + str;
116
58
  }
117
-
118
59
  return str;
119
60
  };
120
-
121
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);
122
62
  }
123
-
63
+ opts == null || opts.onChange == null || opts.onChange(result);
124
64
  return result;
125
65
  };
126
66
  }
67
+ function notUndefined(value, msg) {
68
+ if (value === undefined) {
69
+ throw new Error("Unexpected undefined" + (msg ? ": " + msg : ''));
70
+ } else {
71
+ return value;
72
+ }
73
+ }
74
+ var approxEqual = function approxEqual(a, b) {
75
+ return Math.abs(a - b) < 1;
76
+ };
127
77
 
128
78
  //
129
- const defaultKeyExtractor = index => index;
130
- const defaultRangeExtractor = range => {
131
- const start = Math.max(range.startIndex - range.overscan, 0);
132
- const end = Math.min(range.endIndex + range.overscan, range.count - 1);
133
- const arr = [];
134
79
 
135
- for (let i = start; i <= end; i++) {
136
- arr.push(i);
137
- }
80
+ //
138
81
 
82
+ var defaultKeyExtractor = function defaultKeyExtractor(index) {
83
+ return index;
84
+ };
85
+ var defaultRangeExtractor = function defaultRangeExtractor(range) {
86
+ var start = Math.max(range.startIndex - range.overscan, 0);
87
+ var end = Math.min(range.endIndex + range.overscan, range.count - 1);
88
+ var arr = [];
89
+ for (var _i = start; _i <= end; _i++) {
90
+ arr.push(_i);
91
+ }
139
92
  return arr;
140
93
  };
141
- const observeElementRect = (instance, cb) => {
142
- const observer = observeRect(instance.scrollElement, rect => {
143
- cb(rect);
144
- });
145
-
146
- if (!instance.scrollElement) {
94
+ var observeElementRect = function observeElementRect(instance, cb) {
95
+ var element = instance.scrollElement;
96
+ if (!element) {
147
97
  return;
148
98
  }
149
-
150
- cb(instance.scrollElement.getBoundingClientRect());
151
- observer.observe();
152
- return () => {
153
- observer.unobserve();
154
- };
155
- };
156
- const observeWindowRect = (instance, cb) => {
157
- const onResize = () => {
99
+ var handler = function handler(rect) {
100
+ var width = rect.width,
101
+ height = rect.height;
158
102
  cb({
159
- width: instance.scrollElement.innerWidth,
160
- height: instance.scrollElement.innerHeight
103
+ width: Math.round(width),
104
+ height: Math.round(height)
161
105
  });
162
106
  };
163
-
164
- if (!instance.scrollElement) {
107
+ handler(element.getBoundingClientRect());
108
+ var observer = new ResizeObserver(function (entries) {
109
+ var entry = entries[0];
110
+ if (entry != null && entry.borderBoxSize) {
111
+ var box = entry.borderBoxSize[0];
112
+ if (box) {
113
+ handler({
114
+ width: box.inlineSize,
115
+ height: box.blockSize
116
+ });
117
+ return;
118
+ }
119
+ }
120
+ handler(element.getBoundingClientRect());
121
+ });
122
+ observer.observe(element, {
123
+ box: 'border-box'
124
+ });
125
+ return function () {
126
+ observer.unobserve(element);
127
+ };
128
+ };
129
+ var observeWindowRect = function observeWindowRect(instance, cb) {
130
+ var element = instance.scrollElement;
131
+ if (!element) {
165
132
  return;
166
133
  }
167
-
168
- onResize();
169
- instance.scrollElement.addEventListener('resize', onResize, {
170
- capture: false,
134
+ var handler = function handler() {
135
+ cb({
136
+ width: element.innerWidth,
137
+ height: element.innerHeight
138
+ });
139
+ };
140
+ handler();
141
+ element.addEventListener('resize', handler, {
171
142
  passive: true
172
143
  });
173
- return () => {
174
- instance.scrollElement.removeEventListener('resize', onResize);
144
+ return function () {
145
+ element.removeEventListener('resize', handler);
175
146
  };
176
147
  };
177
- const observeElementOffset = (instance, cb) => {
178
- const onScroll = () => cb(instance.scrollElement[instance.options.horizontal ? 'scrollLeft' : 'scrollTop']);
179
-
180
- if (!instance.scrollElement) {
148
+ var observeElementOffset = function observeElementOffset(instance, cb) {
149
+ var element = instance.scrollElement;
150
+ if (!element) {
181
151
  return;
182
152
  }
183
-
184
- onScroll();
185
- instance.scrollElement.addEventListener('scroll', onScroll, {
186
- capture: false,
153
+ var handler = function handler() {
154
+ cb(element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop']);
155
+ };
156
+ handler();
157
+ element.addEventListener('scroll', handler, {
187
158
  passive: true
188
159
  });
189
- return () => {
190
- instance.scrollElement.removeEventListener('scroll', onScroll);
160
+ return function () {
161
+ element.removeEventListener('scroll', handler);
191
162
  };
192
163
  };
193
- const observeWindowOffset = (instance, cb) => {
194
- const onScroll = () => cb(instance.scrollElement[instance.options.horizontal ? 'scrollX' : 'scrollY']);
195
-
196
- if (!instance.scrollElement) {
164
+ var observeWindowOffset = function observeWindowOffset(instance, cb) {
165
+ var element = instance.scrollElement;
166
+ if (!element) {
197
167
  return;
198
168
  }
199
-
200
- onScroll();
201
- instance.scrollElement.addEventListener('scroll', onScroll, {
202
- capture: false,
169
+ var handler = function handler() {
170
+ cb(element[instance.options.horizontal ? 'scrollX' : 'scrollY']);
171
+ };
172
+ handler();
173
+ element.addEventListener('scroll', handler, {
203
174
  passive: true
204
175
  });
205
- return () => {
206
- instance.scrollElement.removeEventListener('scroll', onScroll);
176
+ return function () {
177
+ element.removeEventListener('scroll', handler);
207
178
  };
208
179
  };
209
- const measureElement = (element, instance) => {
210
- return element.getBoundingClientRect()[instance.options.horizontal ? 'width' : 'height'];
180
+ var measureElement = function measureElement(element, entry, instance) {
181
+ if (entry != null && entry.borderBoxSize) {
182
+ var box = entry.borderBoxSize[0];
183
+ if (box) {
184
+ var size = Math.round(box[instance.options.horizontal ? 'inlineSize' : 'blockSize']);
185
+ return size;
186
+ }
187
+ }
188
+ return Math.round(element.getBoundingClientRect()[instance.options.horizontal ? 'width' : 'height']);
211
189
  };
212
- const windowScroll = (offset, canSmooth, instance) => {
213
- var _instance$scrollEleme;
214
- (_instance$scrollEleme = instance.scrollElement) == null ? void 0 : _instance$scrollEleme.scrollTo({
215
- [instance.options.horizontal ? 'left' : 'top']: offset,
216
- behavior: canSmooth ? 'smooth' : undefined
217
- });
190
+ var windowScroll = function windowScroll(offset, _ref, instance) {
191
+ var _instance$scrollEleme, _instance$scrollEleme2;
192
+ var _ref$adjustments = _ref.adjustments,
193
+ adjustments = _ref$adjustments === void 0 ? 0 : _ref$adjustments,
194
+ behavior = _ref.behavior;
195
+ var toOffset = offset + adjustments;
196
+ (_instance$scrollEleme = instance.scrollElement) == null || _instance$scrollEleme.scrollTo == null || _instance$scrollEleme.scrollTo((_instance$scrollEleme2 = {}, _instance$scrollEleme2[instance.options.horizontal ? 'left' : 'top'] = toOffset, _instance$scrollEleme2.behavior = behavior, _instance$scrollEleme2));
218
197
  };
219
- const elementScroll = (offset, canSmooth, instance) => {
220
- var _instance$scrollEleme2;
221
- (_instance$scrollEleme2 = instance.scrollElement) == null ? void 0 : _instance$scrollEleme2.scrollTo({
222
- [instance.options.horizontal ? 'left' : 'top']: offset,
223
- behavior: canSmooth ? 'smooth' : undefined
224
- });
198
+ var elementScroll = function elementScroll(offset, _ref2, instance) {
199
+ var _instance$scrollEleme3, _instance$scrollEleme4;
200
+ var _ref2$adjustments = _ref2.adjustments,
201
+ adjustments = _ref2$adjustments === void 0 ? 0 : _ref2$adjustments,
202
+ behavior = _ref2.behavior;
203
+ var toOffset = offset + adjustments;
204
+ (_instance$scrollEleme3 = instance.scrollElement) == null || _instance$scrollEleme3.scrollTo == null || _instance$scrollEleme3.scrollTo((_instance$scrollEleme4 = {}, _instance$scrollEleme4[instance.options.horizontal ? 'left' : 'top'] = toOffset, _instance$scrollEleme4.behavior = behavior, _instance$scrollEleme4));
225
205
  };
226
- class Virtualizer {
227
- constructor(_opts) {
228
- var _this = this;
229
-
230
- this.unsubs = [];
231
- this.scrollElement = null;
232
- this.measurementsCache = [];
233
- this.itemMeasurementsCache = {};
234
- this.pendingMeasuredCacheIndexes = [];
235
- this.measureElementCache = {};
236
-
237
- this.setOptions = opts => {
238
- Object.entries(opts).forEach(_ref => {
239
- let [key, value] = _ref;
240
- if (typeof value === 'undefined') delete opts[key];
241
- });
242
- this.options = {
243
- debug: false,
244
- initialOffset: 0,
245
- overscan: 1,
246
- paddingStart: 0,
247
- paddingEnd: 0,
248
- scrollPaddingStart: 0,
249
- scrollPaddingEnd: 0,
250
- horizontal: false,
251
- getItemKey: defaultKeyExtractor,
252
- rangeExtractor: defaultRangeExtractor,
253
- enableSmoothScroll: true,
254
- onChange: () => {},
255
- measureElement,
256
- initialRect: {
257
- width: 0,
258
- height: 0
259
- },
260
- ...opts
261
- };
262
- };
263
-
264
- this.notify = () => {
265
- var _this$options$onChang, _this$options;
266
-
267
- (_this$options$onChang = (_this$options = this.options).onChange) == null ? void 0 : _this$options$onChang.call(_this$options, this);
268
- };
269
-
270
- this.cleanup = () => {
271
- this.unsubs.filter(Boolean).forEach(d => d());
272
- this.unsubs = [];
273
- this.scrollElement = null;
274
- };
275
-
276
- this._didMount = () => {
277
- return () => {
278
- this.cleanup();
279
- };
280
- };
281
-
282
- this._willUpdate = () => {
283
- const scrollElement = this.options.getScrollElement();
284
-
285
- if (this.scrollElement !== scrollElement) {
286
- this.cleanup();
287
- this.scrollElement = scrollElement;
288
- this.unsubs.push(this.options.observeElementRect(this, rect => {
289
- this.scrollRect = rect;
290
- this.notify();
291
- }));
292
- this.unsubs.push(this.options.observeElementOffset(this, offset => {
293
- this.scrollOffset = offset;
294
- this.notify();
295
- }));
206
+ var Virtualizer = function Virtualizer(_opts) {
207
+ var _this = this;
208
+ this.unsubs = [];
209
+ this.scrollElement = null;
210
+ this.isScrolling = false;
211
+ this.isScrollingTimeoutId = null;
212
+ this.scrollToIndexTimeoutId = null;
213
+ this.measurementsCache = [];
214
+ this.itemSizeCache = new Map();
215
+ this.pendingMeasuredCacheIndexes = [];
216
+ this.scrollDirection = null;
217
+ this.scrollAdjustments = 0;
218
+ this.measureElementCache = new Map();
219
+ this.observer = function () {
220
+ var _ro = null;
221
+ var get = function get() {
222
+ if (_ro) {
223
+ return _ro;
224
+ } else if (typeof ResizeObserver !== 'undefined') {
225
+ return _ro = new ResizeObserver(function (entries) {
226
+ entries.forEach(function (entry) {
227
+ _this._measureElement(entry.target, entry);
228
+ });
229
+ });
230
+ } else {
231
+ return null;
296
232
  }
297
233
  };
298
-
299
- this.getSize = () => {
300
- return this.scrollRect[this.options.horizontal ? 'width' : 'height'];
301
- };
302
-
303
- this.getMeasurements = memo(() => [this.options.count, this.options.paddingStart, this.options.getItemKey, this.itemMeasurementsCache], (count, paddingStart, getItemKey, measurementsCache) => {
304
- const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
305
- this.pendingMeasuredCacheIndexes = [];
306
- const measurements = this.measurementsCache.slice(0, min);
307
-
308
- for (let i = min; i < count; i++) {
309
- const key = getItemKey(i);
310
- const measuredSize = measurementsCache[key];
311
- const start = measurements[i - 1] ? measurements[i - 1].end : paddingStart;
312
- const size = typeof measuredSize === 'number' ? measuredSize : this.options.estimateSize(i);
313
- const end = start + size;
314
- measurements[i] = {
315
- index: i,
316
- start,
317
- size,
318
- end,
319
- key
320
- };
234
+ return {
235
+ disconnect: function disconnect() {
236
+ var _get;
237
+ return (_get = get()) == null ? void 0 : _get.disconnect();
238
+ },
239
+ observe: function observe(target) {
240
+ var _get2;
241
+ return (_get2 = get()) == null ? void 0 : _get2.observe(target, {
242
+ box: 'border-box'
243
+ });
244
+ },
245
+ unobserve: function unobserve(target) {
246
+ var _get3;
247
+ return (_get3 = get()) == null ? void 0 : _get3.unobserve(target);
321
248
  }
322
-
323
- this.measurementsCache = measurements;
324
- return measurements;
325
- }, {
326
- key: 'getMeasurements',
327
- debug: () => this.options.debug
249
+ };
250
+ }();
251
+ this.range = null;
252
+ this.setOptions = function (opts) {
253
+ Object.entries(opts).forEach(function (_ref3) {
254
+ var key = _ref3[0],
255
+ value = _ref3[1];
256
+ if (typeof value === 'undefined') delete opts[key];
328
257
  });
329
- this.calculateRange = memo(() => [this.getMeasurements(), this.getSize(), this.scrollOffset], (measurements, outerSize, scrollOffset) => {
330
- return calculateRange({
331
- measurements,
332
- outerSize,
333
- scrollOffset
334
- });
335
- }, {
336
- key: 'calculateRange',
337
- debug: () => this.options.debug
258
+ _this.options = _extends({
259
+ debug: false,
260
+ initialOffset: 0,
261
+ overscan: 1,
262
+ paddingStart: 0,
263
+ paddingEnd: 0,
264
+ scrollPaddingStart: 0,
265
+ scrollPaddingEnd: 0,
266
+ horizontal: false,
267
+ getItemKey: defaultKeyExtractor,
268
+ rangeExtractor: defaultRangeExtractor,
269
+ onChange: function onChange() {},
270
+ measureElement: measureElement,
271
+ initialRect: {
272
+ width: 0,
273
+ height: 0
274
+ },
275
+ scrollMargin: 0,
276
+ scrollingDelay: 150,
277
+ indexAttribute: 'data-index',
278
+ initialMeasurementsCache: [],
279
+ lanes: 1
280
+ }, opts);
281
+ };
282
+ this.notify = function (sync) {
283
+ _this.options.onChange == null || _this.options.onChange(_this, sync);
284
+ };
285
+ this.maybeNotify = memo(function () {
286
+ _this.calculateRange();
287
+ return [_this.isScrolling, _this.range ? _this.range.startIndex : null, _this.range ? _this.range.endIndex : null];
288
+ }, function (isScrolling) {
289
+ _this.notify(isScrolling);
290
+ }, {
291
+ key: 'maybeNotify',
292
+ debug: function debug() {
293
+ return _this.options.debug;
294
+ },
295
+ initialDeps: [this.isScrolling, this.range ? this.range.startIndex : null, this.range ? this.range.endIndex : null]
296
+ });
297
+ this.cleanup = function () {
298
+ _this.unsubs.filter(Boolean).forEach(function (d) {
299
+ return d();
338
300
  });
339
- this.getIndexes = memo(() => [this.options.rangeExtractor, this.calculateRange(), this.options.overscan, this.options.count], (rangeExtractor, range, overscan, count) => {
340
- return rangeExtractor({ ...range,
341
- overscan,
342
- count: count
301
+ _this.unsubs = [];
302
+ _this.scrollElement = null;
303
+ };
304
+ this._didMount = function () {
305
+ _this.measureElementCache.forEach(_this.observer.observe);
306
+ return function () {
307
+ _this.observer.disconnect();
308
+ _this.cleanup();
309
+ };
310
+ };
311
+ this._willUpdate = function () {
312
+ var scrollElement = _this.options.getScrollElement();
313
+ if (_this.scrollElement !== scrollElement) {
314
+ _this.cleanup();
315
+ _this.scrollElement = scrollElement;
316
+ _this._scrollToOffset(_this.scrollOffset, {
317
+ adjustments: undefined,
318
+ behavior: undefined
343
319
  });
344
- }, {
345
- key: 'getIndexes'
346
- });
347
- this.getVirtualItems = memo(() => [this.getIndexes(), this.getMeasurements(), this.options.measureElement], (indexes, measurements, measureElement) => {
348
- const makeMeasureElement = index => measurableItem => {
349
- var _this$itemMeasurement;
350
-
351
- const item = this.measurementsCache[index];
352
-
353
- if (!measurableItem) {
320
+ _this.unsubs.push(_this.options.observeElementRect(_this, function (rect) {
321
+ _this.scrollRect = rect;
322
+ _this.maybeNotify();
323
+ }));
324
+ _this.unsubs.push(_this.options.observeElementOffset(_this, function (offset) {
325
+ _this.scrollAdjustments = 0;
326
+ if (_this.scrollOffset === offset) {
354
327
  return;
355
328
  }
356
-
357
- const measuredItemSize = measureElement(measurableItem, this);
358
- const itemSize = (_this$itemMeasurement = this.itemMeasurementsCache[item.key]) != null ? _this$itemMeasurement : item.size;
359
-
360
- if (measuredItemSize !== itemSize) {
361
- if (item.start < this.scrollOffset) {
362
- if (this.options.debug) {
363
- console.info('correction', measuredItemSize - itemSize);
364
- }
365
-
366
- if (!this.destinationOffset) {
367
- this._scrollToOffset(this.scrollOffset + (measuredItemSize - itemSize), false);
368
- }
369
- }
370
-
371
- this.pendingMeasuredCacheIndexes.push(index);
372
- this.itemMeasurementsCache = { ...this.itemMeasurementsCache,
373
- [item.key]: measuredItemSize
374
- };
375
- this.notify();
329
+ if (_this.isScrollingTimeoutId !== null) {
330
+ clearTimeout(_this.isScrollingTimeoutId);
331
+ _this.isScrollingTimeoutId = null;
376
332
  }
377
- };
378
-
379
- const virtualItems = [];
380
- const currentMeasureElements = {};
381
-
382
- for (let k = 0, len = indexes.length; k < len; k++) {
383
- var _this$measureElementC;
384
-
385
- const i = indexes[k];
386
- const measurement = measurements[i];
387
- const item = { ...measurement,
388
- measureElement: currentMeasureElements[i] = (_this$measureElementC = this.measureElementCache[i]) != null ? _this$measureElementC : makeMeasureElement(i)
389
- };
390
- virtualItems.push(item);
333
+ _this.isScrolling = true;
334
+ _this.scrollDirection = _this.scrollOffset < offset ? 'forward' : 'backward';
335
+ _this.scrollOffset = offset;
336
+ _this.maybeNotify();
337
+ _this.isScrollingTimeoutId = setTimeout(function () {
338
+ _this.isScrollingTimeoutId = null;
339
+ _this.isScrolling = false;
340
+ _this.scrollDirection = null;
341
+ _this.maybeNotify();
342
+ }, _this.options.scrollingDelay);
343
+ }));
344
+ }
345
+ };
346
+ this.getSize = function () {
347
+ return _this.scrollRect[_this.options.horizontal ? 'width' : 'height'];
348
+ };
349
+ this.memoOptions = memo(function () {
350
+ return [_this.options.count, _this.options.paddingStart, _this.options.scrollMargin, _this.options.getItemKey];
351
+ }, function (count, paddingStart, scrollMargin, getItemKey) {
352
+ _this.pendingMeasuredCacheIndexes = [];
353
+ return {
354
+ count: count,
355
+ paddingStart: paddingStart,
356
+ scrollMargin: scrollMargin,
357
+ getItemKey: getItemKey
358
+ };
359
+ }, {
360
+ key: false
361
+ });
362
+ this.getFurthestMeasurement = function (measurements, index) {
363
+ var furthestMeasurementsFound = new Map();
364
+ var furthestMeasurements = new Map();
365
+ for (var m = index - 1; m >= 0; m--) {
366
+ var measurement = measurements[m];
367
+ if (furthestMeasurementsFound.has(measurement.lane)) {
368
+ continue;
391
369
  }
392
-
393
- this.measureElementCache = currentMeasureElements;
394
- return virtualItems;
395
- }, {
396
- key: 'getIndexes'
397
- });
398
-
399
- this.scrollToOffset = function (toOffset, _temp) {
400
- let {
401
- align
402
- } = _temp === void 0 ? {
403
- align: 'start'
404
- } : _temp;
405
-
406
- const attempt = () => {
407
- const offset = _this.scrollOffset;
408
-
409
- const size = _this.getSize();
410
-
411
- if (align === 'auto') {
412
- if (toOffset <= offset) {
413
- align = 'start';
414
- } else if (toOffset >= offset + size) {
415
- align = 'end';
416
- } else {
417
- align = 'start';
418
- }
419
- }
420
-
421
- if (align === 'start') {
422
- _this._scrollToOffset(toOffset, true);
423
- } else if (align === 'end') {
424
- _this._scrollToOffset(toOffset - size, true);
425
- } else if (align === 'center') {
426
- _this._scrollToOffset(toOffset - size / 2, true);
427
- }
370
+ var previousFurthestMeasurement = furthestMeasurements.get(measurement.lane);
371
+ if (previousFurthestMeasurement == null || measurement.end > previousFurthestMeasurement.end) {
372
+ furthestMeasurements.set(measurement.lane, measurement);
373
+ } else if (measurement.end < previousFurthestMeasurement.end) {
374
+ furthestMeasurementsFound.set(measurement.lane, true);
375
+ }
376
+ if (furthestMeasurementsFound.size === _this.options.lanes) {
377
+ break;
378
+ }
379
+ }
380
+ return furthestMeasurements.size === _this.options.lanes ? Array.from(furthestMeasurements.values()).sort(function (a, b) {
381
+ return a.end - b.end;
382
+ })[0] : undefined;
383
+ };
384
+ this.getMeasurements = memo(function () {
385
+ return [_this.memoOptions(), _this.itemSizeCache];
386
+ }, function (_ref4, itemSizeCache) {
387
+ var count = _ref4.count,
388
+ paddingStart = _ref4.paddingStart,
389
+ scrollMargin = _ref4.scrollMargin,
390
+ getItemKey = _ref4.getItemKey;
391
+ var min = _this.pendingMeasuredCacheIndexes.length > 0 ? Math.min.apply(Math, _this.pendingMeasuredCacheIndexes) : 0;
392
+ _this.pendingMeasuredCacheIndexes = [];
393
+ var measurements = _this.measurementsCache.slice(0, min);
394
+ for (var _i2 = min; _i2 < count; _i2++) {
395
+ var key = getItemKey(_i2);
396
+ var furthestMeasurement = _this.options.lanes === 1 ? measurements[_i2 - 1] : _this.getFurthestMeasurement(measurements, _i2);
397
+ var start = furthestMeasurement ? furthestMeasurement.end : paddingStart + scrollMargin;
398
+ var measuredSize = itemSizeCache.get(key);
399
+ var size = typeof measuredSize === 'number' ? measuredSize : _this.options.estimateSize(_i2);
400
+ var end = start + size;
401
+ var lane = furthestMeasurement ? furthestMeasurement.lane : _i2 % _this.options.lanes;
402
+ measurements[_i2] = {
403
+ index: _i2,
404
+ start: start,
405
+ size: size,
406
+ end: end,
407
+ key: key,
408
+ lane: lane
428
409
  };
429
-
430
- attempt();
431
- requestAnimationFrame(() => {
432
- attempt();
410
+ }
411
+ _this.measurementsCache = measurements;
412
+ return measurements;
413
+ }, {
414
+ key: 'getMeasurements',
415
+ debug: function debug() {
416
+ return _this.options.debug;
417
+ }
418
+ });
419
+ this.calculateRange = memo(function () {
420
+ return [_this.getMeasurements(), _this.getSize(), _this.scrollOffset];
421
+ }, function (measurements, outerSize, scrollOffset) {
422
+ return _this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({
423
+ measurements: measurements,
424
+ outerSize: outerSize,
425
+ scrollOffset: scrollOffset
426
+ }) : null;
427
+ }, {
428
+ key: 'calculateRange',
429
+ debug: function debug() {
430
+ return _this.options.debug;
431
+ }
432
+ });
433
+ this.getIndexes = memo(function () {
434
+ return [_this.options.rangeExtractor, _this.calculateRange(), _this.options.overscan, _this.options.count];
435
+ }, function (rangeExtractor, range, overscan, count) {
436
+ return range === null ? [] : rangeExtractor(_extends({}, range, {
437
+ overscan: overscan,
438
+ count: count
439
+ }));
440
+ }, {
441
+ key: 'getIndexes',
442
+ debug: function debug() {
443
+ return _this.options.debug;
444
+ }
445
+ });
446
+ this.indexFromElement = function (node) {
447
+ var attributeName = _this.options.indexAttribute;
448
+ var indexStr = node.getAttribute(attributeName);
449
+ if (!indexStr) {
450
+ console.warn("Missing attribute name '" + attributeName + "={index}' on measured element.");
451
+ return -1;
452
+ }
453
+ return parseInt(indexStr, 10);
454
+ };
455
+ this._measureElement = function (node, entry) {
456
+ var item = _this.measurementsCache[_this.indexFromElement(node)];
457
+ if (!item || !node.isConnected) {
458
+ _this.measureElementCache.forEach(function (cached, key) {
459
+ if (cached === node) {
460
+ _this.observer.unobserve(node);
461
+ _this.measureElementCache["delete"](key);
462
+ }
433
463
  });
434
- };
435
-
436
- this.scrollToIndex = function (index, _temp2) {
437
- let {
438
- align,
439
- ...rest
440
- } = _temp2 === void 0 ? {
441
- align: 'auto'
442
- } : _temp2;
443
-
444
- const measurements = _this.getMeasurements();
445
-
446
- const offset = _this.scrollOffset;
447
-
448
- const size = _this.getSize();
449
-
450
- const {
451
- count
452
- } = _this.options;
453
- const measurement = measurements[Math.max(0, Math.min(index, count - 1))];
454
-
455
- if (!measurement) {
456
- return;
464
+ return;
465
+ }
466
+ var prevNode = _this.measureElementCache.get(item.key);
467
+ if (prevNode !== node) {
468
+ if (prevNode) {
469
+ _this.observer.unobserve(prevNode);
457
470
  }
458
-
459
- if (align === 'auto') {
460
- if (measurement.end >= offset + size - _this.options.scrollPaddingEnd) {
461
- align = 'end';
462
- } else if (measurement.start <= offset + _this.options.scrollPaddingStart) {
463
- align = 'start';
464
- } else {
465
- return;
471
+ _this.observer.observe(node);
472
+ _this.measureElementCache.set(item.key, node);
473
+ }
474
+ var measuredItemSize = _this.options.measureElement(node, entry, _this);
475
+ _this.resizeItem(item, measuredItemSize);
476
+ };
477
+ this.resizeItem = function (item, size) {
478
+ var _this$itemSizeCache$g;
479
+ var itemSize = (_this$itemSizeCache$g = _this.itemSizeCache.get(item.key)) != null ? _this$itemSizeCache$g : item.size;
480
+ var delta = size - itemSize;
481
+ if (delta !== 0) {
482
+ if (item.start < _this.scrollOffset) {
483
+ if (_this.options.debug) {
484
+ console.info('correction', delta);
466
485
  }
486
+ _this._scrollToOffset(_this.scrollOffset, {
487
+ adjustments: _this.scrollAdjustments += delta,
488
+ behavior: undefined
489
+ });
467
490
  }
468
-
469
- const toOffset = align === 'end' ? measurement.end + _this.options.scrollPaddingEnd : measurement.start - _this.options.scrollPaddingStart;
470
-
471
- _this.scrollToOffset(toOffset, {
472
- align,
473
- ...rest
474
- });
475
- };
476
-
477
- this.getTotalSize = () => {
478
- var _this$getMeasurements;
479
-
480
- return (((_this$getMeasurements = this.getMeasurements()[this.options.count - 1]) == null ? void 0 : _this$getMeasurements.end) || this.options.paddingStart) + this.options.paddingEnd;
481
- };
482
-
483
- this._scrollToOffset = (offset, canSmooth) => {
484
- clearTimeout(this.scrollCheckFrame);
485
- this.destinationOffset = offset;
486
- this.options.scrollToFn(offset, this.options.enableSmoothScroll && canSmooth, this);
487
- let scrollCheckFrame;
488
-
489
- const check = () => {
490
- let lastOffset = this.scrollOffset;
491
- this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {
492
- if (this.scrollCheckFrame !== scrollCheckFrame) {
493
- return;
494
- }
495
-
496
- if (this.scrollOffset === lastOffset) {
497
- this.destinationOffset = undefined;
498
- return;
491
+ _this.pendingMeasuredCacheIndexes.push(item.index);
492
+ _this.itemSizeCache = new Map(_this.itemSizeCache.set(item.key, size));
493
+ _this.notify(false);
494
+ }
495
+ };
496
+ this.measureElement = function (node) {
497
+ if (!node) {
498
+ return;
499
+ }
500
+ _this._measureElement(node, undefined);
501
+ };
502
+ this.getVirtualItems = memo(function () {
503
+ return [_this.getIndexes(), _this.getMeasurements()];
504
+ }, function (indexes, measurements) {
505
+ var virtualItems = [];
506
+ for (var k = 0, len = indexes.length; k < len; k++) {
507
+ var _i3 = indexes[k];
508
+ var measurement = measurements[_i3];
509
+ virtualItems.push(measurement);
510
+ }
511
+ return virtualItems;
512
+ }, {
513
+ key: 'getIndexes',
514
+ debug: function debug() {
515
+ return _this.options.debug;
516
+ }
517
+ });
518
+ this.getVirtualItemForOffset = function (offset) {
519
+ var measurements = _this.getMeasurements();
520
+ return notUndefined(measurements[findNearestBinarySearch(0, measurements.length - 1, function (index) {
521
+ return notUndefined(measurements[index]).start;
522
+ }, offset)]);
523
+ };
524
+ this.getOffsetForAlignment = function (toOffset, align) {
525
+ var size = _this.getSize();
526
+ if (align === 'auto') {
527
+ if (toOffset <= _this.scrollOffset) {
528
+ align = 'start';
529
+ } else if (toOffset >= _this.scrollOffset + size) {
530
+ align = 'end';
531
+ } else {
532
+ align = 'start';
533
+ }
534
+ }
535
+ if (align === 'start') {
536
+ toOffset = toOffset;
537
+ } else if (align === 'end') {
538
+ toOffset = toOffset - size;
539
+ } else if (align === 'center') {
540
+ toOffset = toOffset - size / 2;
541
+ }
542
+ var scrollSizeProp = _this.options.horizontal ? 'scrollWidth' : 'scrollHeight';
543
+ var scrollSize = _this.scrollElement ? 'document' in _this.scrollElement ? _this.scrollElement.document.documentElement[scrollSizeProp] : _this.scrollElement[scrollSizeProp] : 0;
544
+ var maxOffset = scrollSize - _this.getSize();
545
+ return Math.max(Math.min(maxOffset, toOffset), 0);
546
+ };
547
+ this.getOffsetForIndex = function (index, align) {
548
+ if (align === void 0) {
549
+ align = 'auto';
550
+ }
551
+ index = Math.max(0, Math.min(index, _this.options.count - 1));
552
+ var measurement = notUndefined(_this.getMeasurements()[index]);
553
+ if (align === 'auto') {
554
+ if (measurement.end >= _this.scrollOffset + _this.getSize() - _this.options.scrollPaddingEnd) {
555
+ align = 'end';
556
+ } else if (measurement.start <= _this.scrollOffset + _this.options.scrollPaddingStart) {
557
+ align = 'start';
558
+ } else {
559
+ return [_this.scrollOffset, align];
560
+ }
561
+ }
562
+ var toOffset = align === 'end' ? measurement.end + _this.options.scrollPaddingEnd : measurement.start - _this.options.scrollPaddingStart;
563
+ return [_this.getOffsetForAlignment(toOffset, align), align];
564
+ };
565
+ this.isDynamicMode = function () {
566
+ return _this.measureElementCache.size > 0;
567
+ };
568
+ this.cancelScrollToIndex = function () {
569
+ if (_this.scrollToIndexTimeoutId !== null) {
570
+ clearTimeout(_this.scrollToIndexTimeoutId);
571
+ _this.scrollToIndexTimeoutId = null;
572
+ }
573
+ };
574
+ this.scrollToOffset = function (toOffset, _temp) {
575
+ var _ref5 = _temp === void 0 ? {} : _temp,
576
+ _ref5$align = _ref5.align,
577
+ align = _ref5$align === void 0 ? 'start' : _ref5$align,
578
+ behavior = _ref5.behavior;
579
+ _this.cancelScrollToIndex();
580
+ if (behavior === 'smooth' && _this.isDynamicMode()) {
581
+ console.warn('The `smooth` scroll behavior is not fully supported with dynamic size.');
582
+ }
583
+ _this._scrollToOffset(_this.getOffsetForAlignment(toOffset, align), {
584
+ adjustments: undefined,
585
+ behavior: behavior
586
+ });
587
+ };
588
+ this.scrollToIndex = function (index, _temp2) {
589
+ var _ref6 = _temp2 === void 0 ? {} : _temp2,
590
+ _ref6$align = _ref6.align,
591
+ initialAlign = _ref6$align === void 0 ? 'auto' : _ref6$align,
592
+ behavior = _ref6.behavior;
593
+ index = Math.max(0, Math.min(index, _this.options.count - 1));
594
+ _this.cancelScrollToIndex();
595
+ if (behavior === 'smooth' && _this.isDynamicMode()) {
596
+ console.warn('The `smooth` scroll behavior is not fully supported with dynamic size.');
597
+ }
598
+ var _this$getOffsetForInd = _this.getOffsetForIndex(index, initialAlign),
599
+ toOffset = _this$getOffsetForInd[0],
600
+ align = _this$getOffsetForInd[1];
601
+ _this._scrollToOffset(toOffset, {
602
+ adjustments: undefined,
603
+ behavior: behavior
604
+ });
605
+ if (behavior !== 'smooth' && _this.isDynamicMode()) {
606
+ _this.scrollToIndexTimeoutId = setTimeout(function () {
607
+ _this.scrollToIndexTimeoutId = null;
608
+ var elementInDOM = _this.measureElementCache.has(_this.options.getItemKey(index));
609
+ if (elementInDOM) {
610
+ var _this$getOffsetForInd2 = _this.getOffsetForIndex(index, align),
611
+ _toOffset = _this$getOffsetForInd2[0];
612
+ if (!approxEqual(_toOffset, _this.scrollOffset)) {
613
+ _this.scrollToIndex(index, {
614
+ align: align,
615
+ behavior: behavior
616
+ });
499
617
  }
500
-
501
- lastOffset = this.scrollOffset;
502
- check();
503
- }, 100);
504
- };
505
-
506
- check();
507
- };
508
-
509
- this.measure = () => {
510
- this.itemMeasurementsCache = {};
511
- this.notify();
512
- };
513
-
514
- this.setOptions(_opts);
515
- this.scrollRect = this.options.initialRect;
516
- this.scrollOffset = this.options.initialOffset;
517
- }
518
-
519
- }
520
-
521
- const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
618
+ } else {
619
+ _this.scrollToIndex(index, {
620
+ align: align,
621
+ behavior: behavior
622
+ });
623
+ }
624
+ });
625
+ }
626
+ };
627
+ this.scrollBy = function (delta, _temp3) {
628
+ var _ref7 = _temp3 === void 0 ? {} : _temp3,
629
+ behavior = _ref7.behavior;
630
+ _this.cancelScrollToIndex();
631
+ if (behavior === 'smooth' && _this.isDynamicMode()) {
632
+ console.warn('The `smooth` scroll behavior is not fully supported with dynamic size.');
633
+ }
634
+ _this._scrollToOffset(_this.scrollOffset + delta, {
635
+ adjustments: undefined,
636
+ behavior: behavior
637
+ });
638
+ };
639
+ this.getTotalSize = function () {
640
+ var _this$getMeasurements;
641
+ return (((_this$getMeasurements = _this.getMeasurements()[_this.options.count - 1]) == null ? void 0 : _this$getMeasurements.end) || _this.options.paddingStart) - _this.options.scrollMargin + _this.options.paddingEnd;
642
+ };
643
+ this._scrollToOffset = function (offset, _ref8) {
644
+ var adjustments = _ref8.adjustments,
645
+ behavior = _ref8.behavior;
646
+ _this.options.scrollToFn(offset, {
647
+ behavior: behavior,
648
+ adjustments: adjustments
649
+ }, _this);
650
+ };
651
+ this.measure = function () {
652
+ _this.itemSizeCache = new Map();
653
+ _this.notify(false);
654
+ };
655
+ this.setOptions(_opts);
656
+ this.scrollRect = this.options.initialRect;
657
+ this.scrollOffset = this.options.initialOffset;
658
+ this.measurementsCache = this.options.initialMeasurementsCache;
659
+ this.measurementsCache.forEach(function (item) {
660
+ _this.itemSizeCache.set(item.key, item.size);
661
+ });
662
+ this.maybeNotify();
663
+ };
664
+ var findNearestBinarySearch = function findNearestBinarySearch(low, high, getCurrentValue, value) {
522
665
  while (low <= high) {
523
- const middle = (low + high) / 2 | 0;
524
- const currentValue = getCurrentValue(middle);
525
-
666
+ var middle = (low + high) / 2 | 0;
667
+ var currentValue = getCurrentValue(middle);
526
668
  if (currentValue < value) {
527
669
  low = middle + 1;
528
670
  } else if (currentValue > value) {
@@ -531,43 +673,39 @@
531
673
  return middle;
532
674
  }
533
675
  }
534
-
535
676
  if (low > 0) {
536
677
  return low - 1;
537
678
  } else {
538
679
  return 0;
539
680
  }
540
681
  };
541
-
542
- function calculateRange(_ref2) {
543
- let {
544
- measurements,
545
- outerSize,
546
- scrollOffset
547
- } = _ref2;
548
- const count = measurements.length - 1;
549
-
550
- const getOffset = index => measurements[index].start;
551
-
552
- const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
553
- let endIndex = startIndex;
554
-
682
+ function calculateRange(_ref9) {
683
+ var measurements = _ref9.measurements,
684
+ outerSize = _ref9.outerSize,
685
+ scrollOffset = _ref9.scrollOffset;
686
+ var count = measurements.length - 1;
687
+ var getOffset = function getOffset(index) {
688
+ return measurements[index].start;
689
+ };
690
+ var startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
691
+ var endIndex = startIndex;
555
692
  while (endIndex < count && measurements[endIndex].end < scrollOffset + outerSize) {
556
693
  endIndex++;
557
694
  }
558
-
559
695
  return {
560
- startIndex,
561
- endIndex
696
+ startIndex: startIndex,
697
+ endIndex: endIndex
562
698
  };
563
699
  }
564
700
 
565
701
  exports.Virtualizer = Virtualizer;
702
+ exports.approxEqual = approxEqual;
566
703
  exports.defaultKeyExtractor = defaultKeyExtractor;
567
704
  exports.defaultRangeExtractor = defaultRangeExtractor;
568
705
  exports.elementScroll = elementScroll;
569
706
  exports.measureElement = measureElement;
570
707
  exports.memo = memo;
708
+ exports.notUndefined = notUndefined;
571
709
  exports.observeElementOffset = observeElementOffset;
572
710
  exports.observeElementRect = observeElementRect;
573
711
  exports.observeWindowOffset = observeWindowOffset;