@tanstack/virtual-core 3.0.0-beta.6 → 3.0.0-beta.61

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 (36) hide show
  1. package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js +27 -0
  2. package/build/lib/_virtual/_rollupPluginBabelHelpers.esm.js.map +1 -0
  3. package/build/lib/_virtual/_rollupPluginBabelHelpers.js +31 -0
  4. package/build/lib/_virtual/_rollupPluginBabelHelpers.js.map +1 -0
  5. package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs +27 -0
  6. package/build/lib/_virtual/_rollupPluginBabelHelpers.mjs.map +1 -0
  7. package/build/lib/index.d.ts +126 -0
  8. package/build/lib/index.esm.js +652 -0
  9. package/build/lib/index.esm.js.map +1 -0
  10. package/build/lib/index.js +667 -0
  11. package/build/lib/index.js.map +1 -0
  12. package/build/lib/index.mjs +652 -0
  13. package/build/lib/index.mjs.map +1 -0
  14. package/build/lib/utils.d.ts +10 -0
  15. package/build/lib/utils.esm.js +58 -0
  16. package/build/lib/utils.esm.js.map +1 -0
  17. package/build/{cjs/packages/virtual-core/src → lib}/utils.js +28 -21
  18. package/build/lib/utils.js.map +1 -0
  19. package/build/lib/utils.mjs +58 -0
  20. package/build/lib/utils.mjs.map +1 -0
  21. package/build/umd/index.development.js +604 -452
  22. package/build/umd/index.development.js.map +1 -1
  23. package/build/umd/index.production.js +1 -1
  24. package/build/umd/index.production.js.map +1 -1
  25. package/package.json +15 -13
  26. package/src/index.ts +546 -233
  27. package/src/utils.ts +17 -5
  28. package/build/cjs/packages/virtual-core/src/index.js +0 -465
  29. package/build/cjs/packages/virtual-core/src/index.js.map +0 -1
  30. package/build/cjs/packages/virtual-core/src/utils.js.map +0 -1
  31. package/build/esm/index.js +0 -559
  32. package/build/esm/index.js.map +0 -1
  33. package/build/stats-html.html +0 -2689
  34. package/build/stats.json +0 -101
  35. package/build/types/index.d.ts +0 -88
  36. package/build/types/utils.d.ts +0 -7
@@ -14,514 +14,670 @@
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 ? void 0 : opts.onChange == null ? void 0 : 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 ? 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));
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 ? 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));
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
- };
274
-
275
- this._didMount = () => {
276
- return () => {
277
- this.cleanup();
278
- };
279
- };
280
-
281
- this._willUpdate = () => {
282
- const scrollElement = this.options.getScrollElement();
283
-
284
- if (this.scrollElement !== scrollElement) {
285
- this.cleanup();
286
- this.scrollElement = scrollElement;
287
- this.unsubs.push(this.options.observeElementRect(this, rect => {
288
- this.scrollRect = rect;
289
- this.notify();
290
- }));
291
- this.unsubs.push(this.options.observeElementOffset(this, offset => {
292
- this.scrollOffset = offset;
293
- this.notify();
294
- }));
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;
295
232
  }
296
233
  };
297
-
298
- this.getSize = () => {
299
- return this.scrollRect[this.options.horizontal ? 'width' : 'height'];
300
- };
301
-
302
- this.getMeasurements = memo(() => [this.options.count, this.options.paddingStart, this.options.getItemKey, this.itemMeasurementsCache], (count, paddingStart, getItemKey, measurementsCache) => {
303
- const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
304
- this.pendingMeasuredCacheIndexes = [];
305
- const measurements = this.measurementsCache.slice(0, min);
306
-
307
- for (let i = min; i < count; i++) {
308
- const key = getItemKey(i);
309
- const measuredSize = measurementsCache[key];
310
- const start = measurements[i - 1] ? measurements[i - 1].end : paddingStart;
311
- const size = typeof measuredSize === 'number' ? measuredSize : this.options.estimateSize(i);
312
- const end = start + size;
313
- measurements[i] = {
314
- index: i,
315
- start,
316
- size,
317
- end,
318
- key
319
- };
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);
320
248
  }
321
-
322
- this.measurementsCache = measurements;
323
- return measurements;
324
- }, {
325
- key: 'getMeasurements',
326
- debug: () => this.options.debug
249
+ };
250
+ }();
251
+ this.range = {
252
+ startIndex: 0,
253
+ endIndex: 0
254
+ };
255
+ this.setOptions = function (opts) {
256
+ Object.entries(opts).forEach(function (_ref3) {
257
+ var key = _ref3[0],
258
+ value = _ref3[1];
259
+ if (typeof value === 'undefined') delete opts[key];
327
260
  });
328
- this.calculateRange = memo(() => [this.getMeasurements(), this.getSize(), this.scrollOffset], (measurements, outerSize, scrollOffset) => {
329
- return calculateRange({
330
- measurements,
331
- outerSize,
332
- scrollOffset
333
- });
334
- }, {
335
- key: 'calculateRange',
336
- debug: () => this.options.debug
261
+ _this.options = _extends({
262
+ debug: false,
263
+ initialOffset: 0,
264
+ overscan: 1,
265
+ paddingStart: 0,
266
+ paddingEnd: 0,
267
+ scrollPaddingStart: 0,
268
+ scrollPaddingEnd: 0,
269
+ horizontal: false,
270
+ getItemKey: defaultKeyExtractor,
271
+ rangeExtractor: defaultRangeExtractor,
272
+ onChange: function onChange() {},
273
+ measureElement: measureElement,
274
+ initialRect: {
275
+ width: 0,
276
+ height: 0
277
+ },
278
+ scrollMargin: 0,
279
+ scrollingDelay: 150,
280
+ indexAttribute: 'data-index',
281
+ initialMeasurementsCache: [],
282
+ lanes: 1
283
+ }, opts);
284
+ };
285
+ this.notify = function () {
286
+ _this.options.onChange == null ? void 0 : _this.options.onChange(_this);
287
+ };
288
+ this.cleanup = function () {
289
+ _this.unsubs.filter(Boolean).forEach(function (d) {
290
+ return d();
337
291
  });
338
- this.getIndexes = memo(() => [this.options.rangeExtractor, this.calculateRange(), this.options.overscan, this.options.count], (rangeExtractor, range, overscan, count) => {
339
- return rangeExtractor({ ...range,
340
- overscan,
341
- count: count
292
+ _this.unsubs = [];
293
+ _this.scrollElement = null;
294
+ };
295
+ this._didMount = function () {
296
+ _this.measureElementCache.forEach(_this.observer.observe);
297
+ return function () {
298
+ _this.observer.disconnect();
299
+ _this.cleanup();
300
+ };
301
+ };
302
+ this._willUpdate = function () {
303
+ var scrollElement = _this.options.getScrollElement();
304
+ if (_this.scrollElement !== scrollElement) {
305
+ _this.cleanup();
306
+ _this.scrollElement = scrollElement;
307
+ _this._scrollToOffset(_this.scrollOffset, {
308
+ adjustments: undefined,
309
+ behavior: undefined
342
310
  });
343
- }, {
344
- key: 'getIndexes'
345
- });
346
- this.getVirtualItems = memo(() => [this.getIndexes(), this.getMeasurements(), this.options.measureElement], (indexes, measurements, measureElement) => {
347
- const makeMeasureElement = index => measurableItem => {
348
- var _this$itemMeasurement;
349
-
350
- const item = this.measurementsCache[index];
351
-
352
- if (!measurableItem) {
311
+ _this.unsubs.push(_this.options.observeElementRect(_this, function (rect) {
312
+ var prev = _this.scrollRect;
313
+ _this.scrollRect = rect;
314
+ if (_this.options.horizontal ? rect.width !== prev.width : rect.height !== prev.height) {
315
+ _this.maybeNotify();
316
+ }
317
+ }));
318
+ _this.unsubs.push(_this.options.observeElementOffset(_this, function (offset) {
319
+ _this.scrollAdjustments = 0;
320
+ if (_this.scrollOffset === offset) {
353
321
  return;
354
322
  }
355
-
356
- const measuredItemSize = measureElement(measurableItem, this);
357
- const itemSize = (_this$itemMeasurement = this.itemMeasurementsCache[item.key]) != null ? _this$itemMeasurement : item.size;
358
-
359
- if (measuredItemSize !== itemSize) {
360
- if (item.start < this.scrollOffset) {
361
- if (this.options.debug) {
362
- console.info('correction', measuredItemSize - itemSize);
363
- }
364
-
365
- if (!this.destinationOffset) {
366
- this._scrollToOffset(this.scrollOffset + (measuredItemSize - itemSize), false);
367
- }
368
- }
369
-
370
- this.pendingMeasuredCacheIndexes.push(index);
371
- this.itemMeasurementsCache = { ...this.itemMeasurementsCache,
372
- [item.key]: measuredItemSize
373
- };
374
- this.notify();
323
+ if (_this.isScrollingTimeoutId !== null) {
324
+ clearTimeout(_this.isScrollingTimeoutId);
325
+ _this.isScrollingTimeoutId = null;
375
326
  }
376
- };
377
-
378
- const virtualItems = [];
379
- const currentMeasureElements = {};
380
-
381
- for (let k = 0, len = indexes.length; k < len; k++) {
382
- var _this$measureElementC;
383
-
384
- const i = indexes[k];
385
- const measurement = measurements[i];
386
- const item = { ...measurement,
387
- measureElement: currentMeasureElements[i] = (_this$measureElementC = this.measureElementCache[i]) != null ? _this$measureElementC : makeMeasureElement(i)
388
- };
389
- virtualItems.push(item);
327
+ _this.isScrolling = true;
328
+ _this.scrollDirection = _this.scrollOffset < offset ? 'forward' : 'backward';
329
+ _this.scrollOffset = offset;
330
+ _this.maybeNotify();
331
+ _this.isScrollingTimeoutId = setTimeout(function () {
332
+ _this.isScrollingTimeoutId = null;
333
+ _this.isScrolling = false;
334
+ _this.scrollDirection = null;
335
+ _this.maybeNotify();
336
+ }, _this.options.scrollingDelay);
337
+ }));
338
+ }
339
+ };
340
+ this.getSize = function () {
341
+ return _this.scrollRect[_this.options.horizontal ? 'width' : 'height'];
342
+ };
343
+ this.memoOptions = memo(function () {
344
+ return [_this.options.count, _this.options.paddingStart, _this.options.scrollMargin, _this.options.getItemKey];
345
+ }, function (count, paddingStart, scrollMargin, getItemKey) {
346
+ _this.pendingMeasuredCacheIndexes = [];
347
+ return {
348
+ count: count,
349
+ paddingStart: paddingStart,
350
+ scrollMargin: scrollMargin,
351
+ getItemKey: getItemKey
352
+ };
353
+ }, {
354
+ key: false
355
+ });
356
+ this.getFurthestMeasurement = function (measurements, index) {
357
+ var furthestMeasurementsFound = new Map();
358
+ var furthestMeasurements = new Map();
359
+ for (var m = index - 1; m >= 0; m--) {
360
+ var measurement = measurements[m];
361
+ if (furthestMeasurementsFound.has(measurement.lane)) {
362
+ continue;
390
363
  }
391
-
392
- this.measureElementCache = currentMeasureElements;
393
- return virtualItems;
394
- }, {
395
- key: 'getIndexes'
364
+ var previousFurthestMeasurement = furthestMeasurements.get(measurement.lane);
365
+ if (previousFurthestMeasurement == null || measurement.end > previousFurthestMeasurement.end) {
366
+ furthestMeasurements.set(measurement.lane, measurement);
367
+ } else if (measurement.end < previousFurthestMeasurement.end) {
368
+ furthestMeasurementsFound.set(measurement.lane, true);
369
+ }
370
+ if (furthestMeasurementsFound.size === _this.options.lanes) {
371
+ break;
372
+ }
373
+ }
374
+ return furthestMeasurements.size === _this.options.lanes ? Array.from(furthestMeasurements.values()).sort(function (a, b) {
375
+ return a.end - b.end;
376
+ })[0] : undefined;
377
+ };
378
+ this.getMeasurements = memo(function () {
379
+ return [_this.memoOptions(), _this.itemSizeCache];
380
+ }, function (_ref4, itemSizeCache) {
381
+ var count = _ref4.count,
382
+ paddingStart = _ref4.paddingStart,
383
+ scrollMargin = _ref4.scrollMargin,
384
+ getItemKey = _ref4.getItemKey;
385
+ var min = _this.pendingMeasuredCacheIndexes.length > 0 ? Math.min.apply(Math, _this.pendingMeasuredCacheIndexes) : 0;
386
+ _this.pendingMeasuredCacheIndexes = [];
387
+ var measurements = _this.measurementsCache.slice(0, min);
388
+ for (var _i2 = min; _i2 < count; _i2++) {
389
+ var key = getItemKey(_i2);
390
+ var furthestMeasurement = _this.options.lanes === 1 ? measurements[_i2 - 1] : _this.getFurthestMeasurement(measurements, _i2);
391
+ var start = furthestMeasurement ? furthestMeasurement.end : paddingStart + scrollMargin;
392
+ var measuredSize = itemSizeCache.get(key);
393
+ var size = typeof measuredSize === 'number' ? measuredSize : _this.options.estimateSize(_i2);
394
+ var end = start + size;
395
+ var lane = furthestMeasurement ? furthestMeasurement.lane : _i2 % _this.options.lanes;
396
+ measurements[_i2] = {
397
+ index: _i2,
398
+ start: start,
399
+ size: size,
400
+ end: end,
401
+ key: key,
402
+ lane: lane
403
+ };
404
+ }
405
+ _this.measurementsCache = measurements;
406
+ return measurements;
407
+ }, {
408
+ key: 'getMeasurements',
409
+ debug: function debug() {
410
+ return _this.options.debug;
411
+ }
412
+ });
413
+ this.calculateRange = memo(function () {
414
+ return [_this.getMeasurements(), _this.getSize(), _this.scrollOffset];
415
+ }, function (measurements, outerSize, scrollOffset) {
416
+ return _this.range = calculateRange({
417
+ measurements: measurements,
418
+ outerSize: outerSize,
419
+ scrollOffset: scrollOffset
396
420
  });
397
-
398
- this.scrollToOffset = function (toOffset, _temp) {
399
- let {
400
- align
401
- } = _temp === void 0 ? {
402
- align: 'start'
403
- } : _temp;
404
-
405
- const attempt = () => {
406
- const offset = _this.scrollOffset;
407
-
408
- const size = _this.getSize();
409
-
410
- if (align === 'auto') {
411
- if (toOffset <= offset) {
412
- align = 'start';
413
- } else if (toOffset >= offset + size) {
414
- align = 'end';
415
- } else {
416
- align = 'start';
417
- }
418
- }
419
-
420
- if (align === 'start') {
421
- _this._scrollToOffset(toOffset, true);
422
- } else if (align === 'end') {
423
- _this._scrollToOffset(toOffset - size, true);
424
- } else if (align === 'center') {
425
- _this._scrollToOffset(toOffset - size / 2, true);
421
+ }, {
422
+ key: 'calculateRange',
423
+ debug: function debug() {
424
+ return _this.options.debug;
425
+ }
426
+ });
427
+ this.maybeNotify = memo(function () {
428
+ var range = _this.calculateRange();
429
+ return [range.startIndex, range.endIndex, _this.isScrolling];
430
+ }, function () {
431
+ _this.notify();
432
+ }, {
433
+ key: 'maybeNotify',
434
+ debug: function debug() {
435
+ return _this.options.debug;
436
+ },
437
+ initialDeps: [this.range.startIndex, this.range.endIndex, this.isScrolling]
438
+ });
439
+ this.getIndexes = memo(function () {
440
+ return [_this.options.rangeExtractor, _this.calculateRange(), _this.options.overscan, _this.options.count];
441
+ }, function (rangeExtractor, range, overscan, count) {
442
+ return rangeExtractor(_extends({}, range, {
443
+ overscan: overscan,
444
+ count: count
445
+ }));
446
+ }, {
447
+ key: 'getIndexes',
448
+ debug: function debug() {
449
+ return _this.options.debug;
450
+ }
451
+ });
452
+ this.indexFromElement = function (node) {
453
+ var attributeName = _this.options.indexAttribute;
454
+ var indexStr = node.getAttribute(attributeName);
455
+ if (!indexStr) {
456
+ console.warn("Missing attribute name '" + attributeName + "={index}' on measured element.");
457
+ return -1;
458
+ }
459
+ return parseInt(indexStr, 10);
460
+ };
461
+ this._measureElement = function (node, entry) {
462
+ var item = _this.measurementsCache[_this.indexFromElement(node)];
463
+ if (!item) {
464
+ _this.measureElementCache.forEach(function (cached, key) {
465
+ if (cached === node) {
466
+ _this.observer.unobserve(node);
467
+ _this.measureElementCache["delete"](key);
426
468
  }
427
- };
428
-
429
- attempt();
430
- requestAnimationFrame(() => {
431
- attempt();
432
469
  });
433
- };
434
-
435
- this.scrollToIndex = function (index, _temp2) {
436
- let {
437
- align,
438
- ...rest
439
- } = _temp2 === void 0 ? {
440
- align: 'auto'
441
- } : _temp2;
442
-
443
- const measurements = _this.getMeasurements();
444
-
445
- const offset = _this.scrollOffset;
446
-
447
- const size = _this.getSize();
448
-
449
- const {
450
- count
451
- } = _this.options;
452
- const measurement = measurements[Math.max(0, Math.min(index, count - 1))];
453
-
454
- if (!measurement) {
455
- return;
470
+ return;
471
+ }
472
+ var prevNode = _this.measureElementCache.get(item.key);
473
+ if (!node.isConnected) {
474
+ if (prevNode) {
475
+ _this.observer.unobserve(prevNode);
476
+ _this.measureElementCache["delete"](item.key);
456
477
  }
457
-
458
- if (align === 'auto') {
459
- if (measurement.end >= offset + size - _this.options.scrollPaddingEnd) {
460
- align = 'end';
461
- } else if (measurement.start <= offset + _this.options.scrollPaddingStart) {
462
- align = 'start';
463
- } else {
464
- return;
478
+ return;
479
+ }
480
+ if (prevNode !== node) {
481
+ if (prevNode) {
482
+ _this.observer.unobserve(prevNode);
483
+ }
484
+ _this.observer.observe(node);
485
+ _this.measureElementCache.set(item.key, node);
486
+ }
487
+ var measuredItemSize = _this.options.measureElement(node, entry, _this);
488
+ _this.resizeItem(item, measuredItemSize);
489
+ };
490
+ this.resizeItem = function (item, size) {
491
+ var _this$itemSizeCache$g;
492
+ var itemSize = (_this$itemSizeCache$g = _this.itemSizeCache.get(item.key)) != null ? _this$itemSizeCache$g : item.size;
493
+ var delta = size - itemSize;
494
+ if (delta !== 0) {
495
+ if (item.start < _this.scrollOffset) {
496
+ if (_this.options.debug) {
497
+ console.info('correction', delta);
465
498
  }
499
+ _this._scrollToOffset(_this.scrollOffset, {
500
+ adjustments: _this.scrollAdjustments += delta,
501
+ behavior: undefined
502
+ });
466
503
  }
467
-
468
- const toOffset = align === 'end' ? measurement.end + _this.options.scrollPaddingEnd : measurement.start - _this.options.scrollPaddingStart;
469
-
470
- _this.scrollToOffset(toOffset, {
471
- align,
472
- ...rest
473
- });
474
- };
475
-
476
- this.getTotalSize = () => {
477
- var _this$getMeasurements;
478
-
479
- return (((_this$getMeasurements = this.getMeasurements()[this.options.count - 1]) == null ? void 0 : _this$getMeasurements.end) || this.options.paddingStart) + this.options.paddingEnd;
480
- };
481
-
482
- this._scrollToOffset = (offset, canSmooth) => {
483
- clearTimeout(this.scrollCheckFrame);
484
- this.destinationOffset = offset;
485
- this.options.scrollToFn(offset, this.options.enableSmoothScroll && canSmooth, this);
486
- let scrollCheckFrame;
487
-
488
- const check = () => {
489
- let lastOffset = this.scrollOffset;
490
- this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {
491
- if (this.scrollCheckFrame !== scrollCheckFrame) {
492
- return;
493
- }
494
-
495
- if (this.scrollOffset === lastOffset) {
496
- this.destinationOffset = undefined;
497
- return;
504
+ _this.pendingMeasuredCacheIndexes.push(item.index);
505
+ _this.itemSizeCache = new Map(_this.itemSizeCache.set(item.key, size));
506
+ _this.notify();
507
+ }
508
+ };
509
+ this.measureElement = function (node) {
510
+ if (!node) {
511
+ return;
512
+ }
513
+ _this._measureElement(node, undefined);
514
+ };
515
+ this.getVirtualItems = memo(function () {
516
+ return [_this.getIndexes(), _this.getMeasurements()];
517
+ }, function (indexes, measurements) {
518
+ var virtualItems = [];
519
+ for (var k = 0, len = indexes.length; k < len; k++) {
520
+ var _i3 = indexes[k];
521
+ var measurement = measurements[_i3];
522
+ virtualItems.push(measurement);
523
+ }
524
+ return virtualItems;
525
+ }, {
526
+ key: 'getIndexes',
527
+ debug: function debug() {
528
+ return _this.options.debug;
529
+ }
530
+ });
531
+ this.getVirtualItemForOffset = function (offset) {
532
+ var measurements = _this.getMeasurements();
533
+ return notUndefined(measurements[findNearestBinarySearch(0, measurements.length - 1, function (index) {
534
+ return notUndefined(measurements[index]).start;
535
+ }, offset)]);
536
+ };
537
+ this.getOffsetForAlignment = function (toOffset, align) {
538
+ var size = _this.getSize();
539
+ if (align === 'auto') {
540
+ if (toOffset <= _this.scrollOffset) {
541
+ align = 'start';
542
+ } else if (toOffset >= _this.scrollOffset + size) {
543
+ align = 'end';
544
+ } else {
545
+ align = 'start';
546
+ }
547
+ }
548
+ if (align === 'start') {
549
+ toOffset = toOffset;
550
+ } else if (align === 'end') {
551
+ toOffset = toOffset - size;
552
+ } else if (align === 'center') {
553
+ toOffset = toOffset - size / 2;
554
+ }
555
+ var scrollSizeProp = _this.options.horizontal ? 'scrollWidth' : 'scrollHeight';
556
+ var scrollSize = _this.scrollElement ? 'document' in _this.scrollElement ? _this.scrollElement.document.documentElement[scrollSizeProp] : _this.scrollElement[scrollSizeProp] : 0;
557
+ var maxOffset = scrollSize - _this.getSize();
558
+ return Math.max(Math.min(maxOffset, toOffset), 0);
559
+ };
560
+ this.getOffsetForIndex = function (index, align) {
561
+ if (align === void 0) {
562
+ align = 'auto';
563
+ }
564
+ index = Math.max(0, Math.min(index, _this.options.count - 1));
565
+ var measurement = notUndefined(_this.getMeasurements()[index]);
566
+ if (align === 'auto') {
567
+ if (measurement.end >= _this.scrollOffset + _this.getSize() - _this.options.scrollPaddingEnd) {
568
+ align = 'end';
569
+ } else if (measurement.start <= _this.scrollOffset + _this.options.scrollPaddingStart) {
570
+ align = 'start';
571
+ } else {
572
+ return [_this.scrollOffset, align];
573
+ }
574
+ }
575
+ var toOffset = align === 'end' ? measurement.end + _this.options.scrollPaddingEnd : measurement.start - _this.options.scrollPaddingStart;
576
+ return [_this.getOffsetForAlignment(toOffset, align), align];
577
+ };
578
+ this.isDynamicMode = function () {
579
+ return _this.measureElementCache.size > 0;
580
+ };
581
+ this.cancelScrollToIndex = function () {
582
+ if (_this.scrollToIndexTimeoutId !== null) {
583
+ clearTimeout(_this.scrollToIndexTimeoutId);
584
+ _this.scrollToIndexTimeoutId = null;
585
+ }
586
+ };
587
+ this.scrollToOffset = function (toOffset, _temp) {
588
+ var _ref5 = _temp === void 0 ? {} : _temp,
589
+ _ref5$align = _ref5.align,
590
+ align = _ref5$align === void 0 ? 'start' : _ref5$align,
591
+ behavior = _ref5.behavior;
592
+ _this.cancelScrollToIndex();
593
+ if (behavior === 'smooth' && _this.isDynamicMode()) {
594
+ console.warn('The `smooth` scroll behavior is not fully supported with dynamic size.');
595
+ }
596
+ _this._scrollToOffset(_this.getOffsetForAlignment(toOffset, align), {
597
+ adjustments: undefined,
598
+ behavior: behavior
599
+ });
600
+ };
601
+ this.scrollToIndex = function (index, _temp2) {
602
+ var _ref6 = _temp2 === void 0 ? {} : _temp2,
603
+ _ref6$align = _ref6.align,
604
+ initialAlign = _ref6$align === void 0 ? 'auto' : _ref6$align,
605
+ behavior = _ref6.behavior;
606
+ index = Math.max(0, Math.min(index, _this.options.count - 1));
607
+ _this.cancelScrollToIndex();
608
+ if (behavior === 'smooth' && _this.isDynamicMode()) {
609
+ console.warn('The `smooth` scroll behavior is not fully supported with dynamic size.');
610
+ }
611
+ var _this$getOffsetForInd = _this.getOffsetForIndex(index, initialAlign),
612
+ toOffset = _this$getOffsetForInd[0],
613
+ align = _this$getOffsetForInd[1];
614
+ _this._scrollToOffset(toOffset, {
615
+ adjustments: undefined,
616
+ behavior: behavior
617
+ });
618
+ if (behavior !== 'smooth' && _this.isDynamicMode()) {
619
+ _this.scrollToIndexTimeoutId = setTimeout(function () {
620
+ _this.scrollToIndexTimeoutId = null;
621
+ var elementInDOM = _this.measureElementCache.has(_this.options.getItemKey(index));
622
+ if (elementInDOM) {
623
+ var _this$getOffsetForInd2 = _this.getOffsetForIndex(index, align),
624
+ _toOffset = _this$getOffsetForInd2[0];
625
+ if (!approxEqual(_toOffset, _this.scrollOffset)) {
626
+ _this.scrollToIndex(index, {
627
+ align: align,
628
+ behavior: behavior
629
+ });
498
630
  }
499
-
500
- lastOffset = this.scrollOffset;
501
- check();
502
- }, 100);
503
- };
504
-
505
- check();
506
- };
507
-
508
- this.measure = () => {
509
- this.itemMeasurementsCache = {};
510
- this.notify();
511
- };
512
-
513
- this.setOptions(_opts);
514
- this.scrollRect = this.options.initialRect;
515
- this.scrollOffset = this.options.initialOffset;
516
- }
517
-
518
- }
519
-
520
- const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
631
+ } else {
632
+ _this.scrollToIndex(index, {
633
+ align: align,
634
+ behavior: behavior
635
+ });
636
+ }
637
+ });
638
+ }
639
+ };
640
+ this.scrollBy = function (delta, _temp3) {
641
+ var _ref7 = _temp3 === void 0 ? {} : _temp3,
642
+ behavior = _ref7.behavior;
643
+ _this.cancelScrollToIndex();
644
+ if (behavior === 'smooth' && _this.isDynamicMode()) {
645
+ console.warn('The `smooth` scroll behavior is not fully supported with dynamic size.');
646
+ }
647
+ _this._scrollToOffset(_this.scrollOffset + delta, {
648
+ adjustments: undefined,
649
+ behavior: behavior
650
+ });
651
+ };
652
+ this.getTotalSize = function () {
653
+ var _this$getMeasurements;
654
+ return (((_this$getMeasurements = _this.getMeasurements()[_this.options.count - 1]) == null ? void 0 : _this$getMeasurements.end) || _this.options.paddingStart) - _this.options.scrollMargin + _this.options.paddingEnd;
655
+ };
656
+ this._scrollToOffset = function (offset, _ref8) {
657
+ var adjustments = _ref8.adjustments,
658
+ behavior = _ref8.behavior;
659
+ _this.options.scrollToFn(offset, {
660
+ behavior: behavior,
661
+ adjustments: adjustments
662
+ }, _this);
663
+ };
664
+ this.measure = function () {
665
+ _this.itemSizeCache = new Map();
666
+ _this.notify();
667
+ };
668
+ this.setOptions(_opts);
669
+ this.scrollRect = this.options.initialRect;
670
+ this.scrollOffset = this.options.initialOffset;
671
+ this.measurementsCache = this.options.initialMeasurementsCache;
672
+ this.measurementsCache.forEach(function (item) {
673
+ _this.itemSizeCache.set(item.key, item.size);
674
+ });
675
+ this.maybeNotify();
676
+ };
677
+ var findNearestBinarySearch = function findNearestBinarySearch(low, high, getCurrentValue, value) {
521
678
  while (low <= high) {
522
- const middle = (low + high) / 2 | 0;
523
- const currentValue = getCurrentValue(middle);
524
-
679
+ var middle = (low + high) / 2 | 0;
680
+ var currentValue = getCurrentValue(middle);
525
681
  if (currentValue < value) {
526
682
  low = middle + 1;
527
683
  } else if (currentValue > value) {
@@ -530,43 +686,39 @@
530
686
  return middle;
531
687
  }
532
688
  }
533
-
534
689
  if (low > 0) {
535
690
  return low - 1;
536
691
  } else {
537
692
  return 0;
538
693
  }
539
694
  };
540
-
541
- function calculateRange(_ref2) {
542
- let {
543
- measurements,
544
- outerSize,
545
- scrollOffset
546
- } = _ref2;
547
- const count = measurements.length - 1;
548
-
549
- const getOffset = index => measurements[index].start;
550
-
551
- const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
552
- let endIndex = startIndex;
553
-
695
+ function calculateRange(_ref9) {
696
+ var measurements = _ref9.measurements,
697
+ outerSize = _ref9.outerSize,
698
+ scrollOffset = _ref9.scrollOffset;
699
+ var count = measurements.length - 1;
700
+ var getOffset = function getOffset(index) {
701
+ return measurements[index].start;
702
+ };
703
+ var startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
704
+ var endIndex = startIndex;
554
705
  while (endIndex < count && measurements[endIndex].end < scrollOffset + outerSize) {
555
706
  endIndex++;
556
707
  }
557
-
558
708
  return {
559
- startIndex,
560
- endIndex
709
+ startIndex: startIndex,
710
+ endIndex: endIndex
561
711
  };
562
712
  }
563
713
 
564
714
  exports.Virtualizer = Virtualizer;
715
+ exports.approxEqual = approxEqual;
565
716
  exports.defaultKeyExtractor = defaultKeyExtractor;
566
717
  exports.defaultRangeExtractor = defaultRangeExtractor;
567
718
  exports.elementScroll = elementScroll;
568
719
  exports.measureElement = measureElement;
569
720
  exports.memo = memo;
721
+ exports.notUndefined = notUndefined;
570
722
  exports.observeElementOffset = observeElementOffset;
571
723
  exports.observeElementRect = observeElementRect;
572
724
  exports.observeWindowOffset = observeWindowOffset;