@tanstack/virtual-core 3.0.0-beta.9 → 3.0.1

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 +600 -493
  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 +566 -278
  28. package/src/utils.ts +17 -5
  29. package/build/cjs/packages/virtual-core/src/index.js +0 -497
  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 -591
  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,546 +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
-
142
- const memoRectCallback = (instance, cb) => {
143
- let prev = {
144
- height: -1,
145
- width: -1
146
- };
147
- return rect => {
148
- if (instance.options.horizontal ? rect.width !== prev.width : rect.height !== prev.height) {
149
- cb(rect);
94
+ var observeElementRect = function observeElementRect(instance, cb) {
95
+ var element = instance.scrollElement;
96
+ if (!element) {
97
+ return;
98
+ }
99
+ var handler = function handler(rect) {
100
+ var width = rect.width,
101
+ height = rect.height;
102
+ cb({
103
+ width: Math.round(width),
104
+ height: Math.round(height)
105
+ });
106
+ };
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
+ }
150
119
  }
151
-
152
- prev = rect;
120
+ handler(element.getBoundingClientRect());
121
+ });
122
+ observer.observe(element, {
123
+ box: 'border-box'
124
+ });
125
+ return function () {
126
+ observer.unobserve(element);
153
127
  };
154
128
  };
155
-
156
- const observeElementRect = (instance, cb) => {
157
- const onResize = memoRectCallback(instance, cb);
158
- const observer = observeRect(instance.scrollElement, rect => {
159
- onResize(rect);
160
- });
161
-
162
- if (!instance.scrollElement) {
129
+ var observeWindowRect = function observeWindowRect(instance, cb) {
130
+ var element = instance.scrollElement;
131
+ if (!element) {
163
132
  return;
164
133
  }
165
-
166
- onResize(instance.scrollElement.getBoundingClientRect());
167
- observer.observe();
168
- return () => {
169
- observer.unobserve();
134
+ var handler = function handler() {
135
+ cb({
136
+ width: element.innerWidth,
137
+ height: element.innerHeight
138
+ });
170
139
  };
171
- };
172
- const observeWindowRect = (instance, cb) => {
173
- const memoizedCallback = memoRectCallback(instance, cb);
174
-
175
- const onResize = () => memoizedCallback({
176
- width: instance.scrollElement.innerWidth,
177
- height: instance.scrollElement.innerHeight
140
+ handler();
141
+ element.addEventListener('resize', handler, {
142
+ passive: true
178
143
  });
179
-
180
- if (!instance.scrollElement) {
144
+ return function () {
145
+ element.removeEventListener('resize', handler);
146
+ };
147
+ };
148
+ var observeElementOffset = function observeElementOffset(instance, cb) {
149
+ var element = instance.scrollElement;
150
+ if (!element) {
181
151
  return;
182
152
  }
183
-
184
- onResize();
185
- instance.scrollElement.addEventListener('resize', onResize, {
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('resize', onResize);
160
+ return function () {
161
+ element.removeEventListener('scroll', handler);
191
162
  };
192
163
  };
193
- const scrollProps = {
194
- element: ['scrollLeft', 'scrollTop'],
195
- window: ['scrollX', 'scrollY']
196
- };
197
-
198
- const createOffsetObserver = mode => {
199
- return (instance, cb) => {
200
- if (!instance.scrollElement) {
201
- return;
202
- }
203
-
204
- const propX = scrollProps[mode][0];
205
- const propY = scrollProps[mode][1];
206
- let prevX = instance.scrollElement[propX];
207
- let prevY = instance.scrollElement[propY];
208
-
209
- const scroll = () => {
210
- cb(instance.scrollElement[instance.options.horizontal ? propX : propY]);
211
- };
212
-
213
- scroll();
214
-
215
- const onScroll = e => {
216
- const target = e.currentTarget;
217
- const scrollX = target[propX];
218
- const scrollY = target[propY];
219
-
220
- if (instance.options.horizontal ? prevX - scrollX : prevY - scrollY) {
221
- scroll();
222
- }
223
-
224
- prevX = scrollX;
225
- prevY = scrollY;
226
- };
227
-
228
- instance.scrollElement.addEventListener('scroll', onScroll, {
229
- capture: false,
230
- passive: true
231
- });
232
- return () => {
233
- instance.scrollElement.removeEventListener('scroll', onScroll);
234
- };
164
+ var observeWindowOffset = function observeWindowOffset(instance, cb) {
165
+ var element = instance.scrollElement;
166
+ if (!element) {
167
+ return;
168
+ }
169
+ var handler = function handler() {
170
+ cb(element[instance.options.horizontal ? 'scrollX' : 'scrollY']);
171
+ };
172
+ handler();
173
+ element.addEventListener('scroll', handler, {
174
+ passive: true
175
+ });
176
+ return function () {
177
+ element.removeEventListener('scroll', handler);
235
178
  };
236
179
  };
237
-
238
- const observeElementOffset = createOffsetObserver('element');
239
- const observeWindowOffset = createOffsetObserver('window');
240
- const measureElement = (element, instance) => {
241
- 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']);
242
189
  };
243
- const windowScroll = (offset, canSmooth, instance) => {
244
- var _instance$scrollEleme;
245
- (_instance$scrollEleme = instance.scrollElement) == null ? void 0 : _instance$scrollEleme.scrollTo({
246
- [instance.options.horizontal ? 'left' : 'top']: offset,
247
- behavior: canSmooth ? 'smooth' : undefined
248
- });
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));
249
197
  };
250
- const elementScroll = (offset, canSmooth, instance) => {
251
- var _instance$scrollEleme2;
252
- (_instance$scrollEleme2 = instance.scrollElement) == null ? void 0 : _instance$scrollEleme2.scrollTo({
253
- [instance.options.horizontal ? 'left' : 'top']: offset,
254
- behavior: canSmooth ? 'smooth' : undefined
255
- });
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));
256
205
  };
257
- class Virtualizer {
258
- constructor(_opts) {
259
- var _this = this;
260
-
261
- this.unsubs = [];
262
- this.scrollElement = null;
263
- this.measurementsCache = [];
264
- this.itemMeasurementsCache = {};
265
- this.pendingMeasuredCacheIndexes = [];
266
- this.measureElementCache = {};
267
-
268
- this.setOptions = opts => {
269
- Object.entries(opts).forEach(_ref => {
270
- let [key, value] = _ref;
271
- if (typeof value === 'undefined') delete opts[key];
272
- });
273
- this.options = {
274
- debug: false,
275
- initialOffset: 0,
276
- overscan: 1,
277
- paddingStart: 0,
278
- paddingEnd: 0,
279
- scrollPaddingStart: 0,
280
- scrollPaddingEnd: 0,
281
- horizontal: false,
282
- getItemKey: defaultKeyExtractor,
283
- rangeExtractor: defaultRangeExtractor,
284
- enableSmoothScroll: true,
285
- onChange: () => {},
286
- measureElement,
287
- initialRect: {
288
- width: 0,
289
- height: 0
290
- },
291
- ...opts
292
- };
293
- };
294
-
295
- this.notify = () => {
296
- var _this$options$onChang, _this$options;
297
-
298
- (_this$options$onChang = (_this$options = this.options).onChange) == null ? void 0 : _this$options$onChang.call(_this$options, this);
299
- };
300
-
301
- this.cleanup = () => {
302
- this.unsubs.filter(Boolean).forEach(d => d());
303
- this.unsubs = [];
304
- this.scrollElement = null;
305
- };
306
-
307
- this._didMount = () => {
308
- return () => {
309
- this.cleanup();
310
- };
311
- };
312
-
313
- this._willUpdate = () => {
314
- const scrollElement = this.options.getScrollElement();
315
-
316
- if (this.scrollElement !== scrollElement) {
317
- this.cleanup();
318
- this.scrollElement = scrollElement;
319
- this.unsubs.push(this.options.observeElementRect(this, rect => {
320
- this.scrollRect = rect;
321
- this.notify();
322
- }));
323
- this.unsubs.push(this.options.observeElementOffset(this, offset => {
324
- this.scrollOffset = offset;
325
- this.notify();
326
- }));
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;
327
232
  }
328
233
  };
329
-
330
- this.getSize = () => {
331
- return this.scrollRect[this.options.horizontal ? 'width' : 'height'];
332
- };
333
-
334
- this.getMeasurements = memo(() => [this.options.count, this.options.paddingStart, this.options.getItemKey, this.itemMeasurementsCache], (count, paddingStart, getItemKey, measurementsCache) => {
335
- const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
336
- this.pendingMeasuredCacheIndexes = [];
337
- const measurements = this.measurementsCache.slice(0, min);
338
-
339
- for (let i = min; i < count; i++) {
340
- const key = getItemKey(i);
341
- const measuredSize = measurementsCache[key];
342
- const start = measurements[i - 1] ? measurements[i - 1].end : paddingStart;
343
- const size = typeof measuredSize === 'number' ? measuredSize : this.options.estimateSize(i);
344
- const end = start + size;
345
- measurements[i] = {
346
- index: i,
347
- start,
348
- size,
349
- end,
350
- key
351
- };
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);
352
248
  }
353
-
354
- this.measurementsCache = measurements;
355
- return measurements;
356
- }, {
357
- key: 'getMeasurements',
358
- 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];
359
257
  });
360
- this.calculateRange = memo(() => [this.getMeasurements(), this.getSize(), this.scrollOffset], (measurements, outerSize, scrollOffset) => {
361
- return calculateRange({
362
- measurements,
363
- outerSize,
364
- scrollOffset
365
- });
366
- }, {
367
- key: 'calculateRange',
368
- 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();
369
300
  });
370
- this.getIndexes = memo(() => [this.options.rangeExtractor, this.calculateRange(), this.options.overscan, this.options.count], (rangeExtractor, range, overscan, count) => {
371
- return rangeExtractor({ ...range,
372
- overscan,
373
- 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
374
319
  });
375
- }, {
376
- key: 'getIndexes'
377
- });
378
- this.getVirtualItems = memo(() => [this.getIndexes(), this.getMeasurements(), this.options.measureElement], (indexes, measurements, measureElement) => {
379
- const makeMeasureElement = index => measurableItem => {
380
- var _this$itemMeasurement;
381
-
382
- const item = this.measurementsCache[index];
383
-
384
- 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) {
385
327
  return;
386
328
  }
387
-
388
- const measuredItemSize = measureElement(measurableItem, this);
389
- const itemSize = (_this$itemMeasurement = this.itemMeasurementsCache[item.key]) != null ? _this$itemMeasurement : item.size;
390
-
391
- if (measuredItemSize !== itemSize) {
392
- if (item.start < this.scrollOffset) {
393
- if (this.options.debug) {
394
- console.info('correction', measuredItemSize - itemSize);
395
- }
396
-
397
- if (!this.destinationOffset) {
398
- this._scrollToOffset(this.scrollOffset + (measuredItemSize - itemSize), false);
399
- }
400
- }
401
-
402
- this.pendingMeasuredCacheIndexes.push(index);
403
- this.itemMeasurementsCache = { ...this.itemMeasurementsCache,
404
- [item.key]: measuredItemSize
405
- };
406
- this.notify();
329
+ if (_this.isScrollingTimeoutId !== null) {
330
+ clearTimeout(_this.isScrollingTimeoutId);
331
+ _this.isScrollingTimeoutId = null;
407
332
  }
408
- };
409
-
410
- const virtualItems = [];
411
- const currentMeasureElements = {};
412
-
413
- for (let k = 0, len = indexes.length; k < len; k++) {
414
- var _this$measureElementC;
415
-
416
- const i = indexes[k];
417
- const measurement = measurements[i];
418
- const item = { ...measurement,
419
- measureElement: currentMeasureElements[i] = (_this$measureElementC = this.measureElementCache[i]) != null ? _this$measureElementC : makeMeasureElement(i)
420
- };
421
- 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;
422
369
  }
423
-
424
- this.measureElementCache = currentMeasureElements;
425
- return virtualItems;
426
- }, {
427
- key: 'getIndexes'
428
- });
429
-
430
- this.scrollToOffset = function (toOffset, _temp) {
431
- let {
432
- align
433
- } = _temp === void 0 ? {
434
- align: 'start'
435
- } : _temp;
436
-
437
- const attempt = () => {
438
- const offset = _this.scrollOffset;
439
-
440
- const size = _this.getSize();
441
-
442
- if (align === 'auto') {
443
- if (toOffset <= offset) {
444
- align = 'start';
445
- } else if (toOffset >= offset + size) {
446
- align = 'end';
447
- } else {
448
- align = 'start';
449
- }
450
- }
451
-
452
- if (align === 'start') {
453
- _this._scrollToOffset(toOffset, true);
454
- } else if (align === 'end') {
455
- _this._scrollToOffset(toOffset - size, true);
456
- } else if (align === 'center') {
457
- _this._scrollToOffset(toOffset - size / 2, true);
458
- }
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
459
409
  };
460
-
461
- attempt();
462
- requestAnimationFrame(() => {
463
- 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
+ }
464
463
  });
465
- };
466
-
467
- this.scrollToIndex = function (index, _temp2) {
468
- let {
469
- align,
470
- ...rest
471
- } = _temp2 === void 0 ? {
472
- align: 'auto'
473
- } : _temp2;
474
-
475
- const measurements = _this.getMeasurements();
476
-
477
- const offset = _this.scrollOffset;
478
-
479
- const size = _this.getSize();
480
-
481
- const {
482
- count
483
- } = _this.options;
484
- const measurement = measurements[Math.max(0, Math.min(index, count - 1))];
485
-
486
- if (!measurement) {
487
- return;
464
+ return;
465
+ }
466
+ var prevNode = _this.measureElementCache.get(item.key);
467
+ if (prevNode !== node) {
468
+ if (prevNode) {
469
+ _this.observer.unobserve(prevNode);
488
470
  }
489
-
490
- if (align === 'auto') {
491
- if (measurement.end >= offset + size - _this.options.scrollPaddingEnd) {
492
- align = 'end';
493
- } else if (measurement.start <= offset + _this.options.scrollPaddingStart) {
494
- align = 'start';
495
- } else {
496
- 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);
497
485
  }
486
+ _this._scrollToOffset(_this.scrollOffset, {
487
+ adjustments: _this.scrollAdjustments += delta,
488
+ behavior: undefined
489
+ });
498
490
  }
499
-
500
- const toOffset = align === 'end' ? measurement.end + _this.options.scrollPaddingEnd : measurement.start - _this.options.scrollPaddingStart;
501
-
502
- _this.scrollToOffset(toOffset, {
503
- align,
504
- ...rest
505
- });
506
- };
507
-
508
- this.getTotalSize = () => {
509
- var _this$getMeasurements;
510
-
511
- return (((_this$getMeasurements = this.getMeasurements()[this.options.count - 1]) == null ? void 0 : _this$getMeasurements.end) || this.options.paddingStart) + this.options.paddingEnd;
512
- };
513
-
514
- this._scrollToOffset = (offset, canSmooth) => {
515
- clearTimeout(this.scrollCheckFrame);
516
- this.destinationOffset = offset;
517
- this.options.scrollToFn(offset, this.options.enableSmoothScroll && canSmooth, this);
518
- let scrollCheckFrame;
519
-
520
- const check = () => {
521
- let lastOffset = this.scrollOffset;
522
- this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {
523
- if (this.scrollCheckFrame !== scrollCheckFrame) {
524
- return;
525
- }
526
-
527
- if (this.scrollOffset === lastOffset) {
528
- this.destinationOffset = undefined;
529
- 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
+ });
530
617
  }
531
-
532
- lastOffset = this.scrollOffset;
533
- check();
534
- }, 100);
535
- };
536
-
537
- check();
538
- };
539
-
540
- this.measure = () => {
541
- this.itemMeasurementsCache = {};
542
- this.notify();
543
- };
544
-
545
- this.setOptions(_opts);
546
- this.scrollRect = this.options.initialRect;
547
- this.scrollOffset = this.options.initialOffset;
548
- }
549
-
550
- }
551
-
552
- 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) {
553
665
  while (low <= high) {
554
- const middle = (low + high) / 2 | 0;
555
- const currentValue = getCurrentValue(middle);
556
-
666
+ var middle = (low + high) / 2 | 0;
667
+ var currentValue = getCurrentValue(middle);
557
668
  if (currentValue < value) {
558
669
  low = middle + 1;
559
670
  } else if (currentValue > value) {
@@ -562,43 +673,39 @@
562
673
  return middle;
563
674
  }
564
675
  }
565
-
566
676
  if (low > 0) {
567
677
  return low - 1;
568
678
  } else {
569
679
  return 0;
570
680
  }
571
681
  };
572
-
573
- function calculateRange(_ref2) {
574
- let {
575
- measurements,
576
- outerSize,
577
- scrollOffset
578
- } = _ref2;
579
- const count = measurements.length - 1;
580
-
581
- const getOffset = index => measurements[index].start;
582
-
583
- const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
584
- let endIndex = startIndex;
585
-
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;
586
692
  while (endIndex < count && measurements[endIndex].end < scrollOffset + outerSize) {
587
693
  endIndex++;
588
694
  }
589
-
590
695
  return {
591
- startIndex,
592
- endIndex
696
+ startIndex: startIndex,
697
+ endIndex: endIndex
593
698
  };
594
699
  }
595
700
 
596
701
  exports.Virtualizer = Virtualizer;
702
+ exports.approxEqual = approxEqual;
597
703
  exports.defaultKeyExtractor = defaultKeyExtractor;
598
704
  exports.defaultRangeExtractor = defaultRangeExtractor;
599
705
  exports.elementScroll = elementScroll;
600
706
  exports.measureElement = measureElement;
601
707
  exports.memo = memo;
708
+ exports.notUndefined = notUndefined;
602
709
  exports.observeElementOffset = observeElementOffset;
603
710
  exports.observeElementRect = observeElementRect;
604
711
  exports.observeWindowOffset = observeWindowOffset;