@tanstack/solid-virtual 3.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,94 @@
1
+ /**
2
+ * solid-virtual
3
+ *
4
+ * Copyright (c) TanStack
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE.md file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ 'use strict';
12
+
13
+ Object.defineProperty(exports, '__esModule', { value: true });
14
+
15
+ var index = require('../../virtual-core/build/esm/index.js');
16
+ var solidJs = require('solid-js');
17
+ var store = require('solid-js/store');
18
+
19
+ function createVirtualizerBase(options) {
20
+ const resolvedOptions = solidJs.mergeProps(options);
21
+ const instance = new index.Virtualizer(resolvedOptions);
22
+ const [virtualItems, setVirtualItems] = store.createStore(instance.getVirtualItems());
23
+ const [totalSize, setTotalSize] = solidJs.createSignal(instance.getTotalSize());
24
+ const handler = {
25
+ get(target, prop) {
26
+ switch (prop) {
27
+ case 'getVirtualItems':
28
+ return () => virtualItems;
29
+
30
+ case 'getTotalSize':
31
+ return () => totalSize();
32
+
33
+ default:
34
+ return Reflect.get(target, prop);
35
+ }
36
+ }
37
+
38
+ };
39
+ const virtualizer = new Proxy(instance, handler);
40
+ virtualizer.setOptions(resolvedOptions);
41
+ solidJs.onMount(() => {
42
+ const cleanup = virtualizer._didMount();
43
+
44
+ virtualizer._willUpdate();
45
+
46
+ solidJs.onCleanup(cleanup);
47
+ });
48
+ solidJs.createComputed(() => {
49
+ virtualizer.setOptions(solidJs.mergeProps(resolvedOptions, options, {
50
+ onChange: instance => {
51
+ instance._willUpdate();
52
+
53
+ setVirtualItems(store.reconcile(instance.getVirtualItems(), {
54
+ key: 'index'
55
+ }));
56
+ setTotalSize(instance.getTotalSize());
57
+ options.onChange == null ? void 0 : options.onChange(instance);
58
+ }
59
+ }));
60
+ virtualizer.measure();
61
+ });
62
+ return virtualizer;
63
+ }
64
+
65
+ function createVirtualizer(options) {
66
+ return createVirtualizerBase(solidJs.mergeProps({
67
+ observeElementRect: index.observeElementRect,
68
+ observeElementOffset: index.observeElementOffset,
69
+ scrollToFn: index.elementScroll
70
+ }, options));
71
+ }
72
+ function createWindowVirtualizer(options) {
73
+ return createVirtualizerBase(solidJs.mergeProps({
74
+ getScrollElement: () => typeof window !== 'undefined' ? window : null,
75
+ observeElementRect: index.observeWindowRect,
76
+ observeElementOffset: index.observeWindowOffset,
77
+ scrollToFn: index.windowScroll
78
+ }, options));
79
+ }
80
+
81
+ exports.Virtualizer = index.Virtualizer;
82
+ exports.defaultKeyExtractor = index.defaultKeyExtractor;
83
+ exports.defaultRangeExtractor = index.defaultRangeExtractor;
84
+ exports.elementScroll = index.elementScroll;
85
+ exports.measureElement = index.measureElement;
86
+ exports.memo = index.memo;
87
+ exports.observeElementOffset = index.observeElementOffset;
88
+ exports.observeElementRect = index.observeElementRect;
89
+ exports.observeWindowOffset = index.observeWindowOffset;
90
+ exports.observeWindowRect = index.observeWindowRect;
91
+ exports.windowScroll = index.windowScroll;
92
+ exports.createVirtualizer = createVirtualizer;
93
+ exports.createWindowVirtualizer = createWindowVirtualizer;
94
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../../../src/index.tsx"],"sourcesContent":["import {\n elementScroll,\n observeElementOffset,\n observeElementRect,\n observeWindowOffset,\n observeWindowRect,\n PartialKeys,\n Virtualizer,\n VirtualizerOptions,\n windowScroll,\n} from '@tanstack/virtual-core';\nexport * from '@tanstack/virtual-core';\n\nimport { createSignal, onMount, onCleanup, createComputed, mergeProps } from 'solid-js';\nimport { createStore, reconcile } from 'solid-js/store';\n\nfunction createVirtualizerBase<TScrollElement, TItemElement = unknown>(\n options: VirtualizerOptions<TScrollElement, TItemElement>\n): Virtualizer<TScrollElement, TItemElement> {\n const resolvedOptions: VirtualizerOptions<TScrollElement, TItemElement> = mergeProps(options);\n\n const instance = new Virtualizer<TScrollElement, TItemElement>(\n resolvedOptions\n );\n\n const [virtualItems, setVirtualItems] = createStore(\n instance.getVirtualItems()\n );\n const [totalSize, setTotalSize] = createSignal(instance.getTotalSize());\n\n const handler = {\n get(\n target: Virtualizer<TScrollElement, TItemElement>,\n prop: keyof Virtualizer<TScrollElement, TItemElement>\n ) {\n switch (prop) {\n case 'getVirtualItems':\n return () => virtualItems;\n case 'getTotalSize':\n return () => totalSize();\n default:\n return Reflect.get(target, prop);\n }\n },\n };\n\n const virtualizer = new Proxy(instance, handler);\n virtualizer.setOptions(resolvedOptions);\n\n onMount(() => {\n const cleanup = virtualizer._didMount();\n virtualizer._willUpdate();\n onCleanup(cleanup);\n });\n\n createComputed(() => {\n virtualizer.setOptions(mergeProps(resolvedOptions, options, {\n onChange: (instance: Virtualizer<TScrollElement, TItemElement> ) => {\n instance._willUpdate();\n setVirtualItems(\n reconcile(instance.getVirtualItems(), {\n key: 'index',\n })\n );\n setTotalSize(instance.getTotalSize());\n options.onChange?.(instance);\n }}))\n virtualizer.measure()\n })\n\n return virtualizer;\n}\n\nexport function createVirtualizer<TScrollElement, TItemElement = unknown>(\n options: PartialKeys<\n VirtualizerOptions<TScrollElement, TItemElement>,\n 'observeElementRect' | 'observeElementOffset' | 'scrollToFn'\n >\n): Virtualizer<TScrollElement, TItemElement> {\n \n return createVirtualizerBase<TScrollElement, TItemElement>(mergeProps({\n observeElementRect: observeElementRect,\n observeElementOffset: observeElementOffset,\n scrollToFn: elementScroll\n }, options));\n}\n\nexport function createWindowVirtualizer<TItemElement = unknown>(\n options: PartialKeys<\n VirtualizerOptions<Window, TItemElement>,\n | 'getScrollElement'\n | 'observeElementRect'\n | 'observeElementOffset'\n | 'scrollToFn'\n >\n): Virtualizer<Window, TItemElement> {\n return createVirtualizerBase<Window, TItemElement>(mergeProps({\n getScrollElement: () => (typeof window !== 'undefined' ? window : null!),\n observeElementRect: observeWindowRect,\n observeElementOffset: observeWindowOffset,\n scrollToFn: windowScroll,\n },options,\n ));\n}\n"],"names":["createVirtualizerBase","options","resolvedOptions","mergeProps","instance","Virtualizer","virtualItems","setVirtualItems","createStore","getVirtualItems","totalSize","setTotalSize","createSignal","getTotalSize","handler","get","target","prop","Reflect","virtualizer","Proxy","setOptions","onMount","cleanup","_didMount","_willUpdate","onCleanup","createComputed","onChange","reconcile","key","measure","createVirtualizer","observeElementRect","observeElementOffset","scrollToFn","elementScroll","createWindowVirtualizer","getScrollElement","window","observeWindowRect","observeWindowOffset","windowScroll"],"mappings":"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"}
@@ -0,0 +1,583 @@
1
+ /**
2
+ * solid-virtual
3
+ *
4
+ * Copyright (c) TanStack
5
+ *
6
+ * This source code is licensed under the MIT license found in the
7
+ * LICENSE.md file in the root directory of this source tree.
8
+ *
9
+ * @license MIT
10
+ */
11
+ 'use strict';
12
+
13
+ Object.defineProperty(exports, '__esModule', { value: true });
14
+
15
+ /**
16
+ * virtual-core
17
+ *
18
+ * Copyright (c) TanStack
19
+ *
20
+ * This source code is licensed under the MIT license found in the
21
+ * LICENSE.md file in the root directory of this source tree.
22
+ *
23
+ * @license MIT
24
+ */
25
+ var props = ["bottom", "height", "left", "right", "top", "width"];
26
+
27
+ var rectChanged = function rectChanged(a, b) {
28
+ if (a === void 0) {
29
+ a = {};
30
+ }
31
+
32
+ if (b === void 0) {
33
+ b = {};
34
+ }
35
+
36
+ return props.some(function (prop) {
37
+ return a[prop] !== b[prop];
38
+ });
39
+ };
40
+
41
+ var observedNodes = /*#__PURE__*/new Map();
42
+ var rafId;
43
+
44
+ var run = function run() {
45
+ var changedStates = [];
46
+ observedNodes.forEach(function (state, node) {
47
+ var newRect = node.getBoundingClientRect();
48
+
49
+ if (rectChanged(newRect, state.rect)) {
50
+ state.rect = newRect;
51
+ changedStates.push(state);
52
+ }
53
+ });
54
+ changedStates.forEach(function (state) {
55
+ state.callbacks.forEach(function (cb) {
56
+ return cb(state.rect);
57
+ });
58
+ });
59
+ rafId = window.requestAnimationFrame(run);
60
+ };
61
+
62
+ function observeRect(node, cb) {
63
+ return {
64
+ observe: function observe() {
65
+ var wasEmpty = observedNodes.size === 0;
66
+
67
+ if (observedNodes.has(node)) {
68
+ observedNodes.get(node).callbacks.push(cb);
69
+ } else {
70
+ observedNodes.set(node, {
71
+ rect: undefined,
72
+ hasRectChanged: false,
73
+ callbacks: [cb]
74
+ });
75
+ }
76
+
77
+ if (wasEmpty) run();
78
+ },
79
+ unobserve: function unobserve() {
80
+ var state = observedNodes.get(node);
81
+
82
+ if (state) {
83
+ // Remove the callback
84
+ var index = state.callbacks.indexOf(cb);
85
+ if (index >= 0) state.callbacks.splice(index, 1); // Remove the node reference
86
+
87
+ if (!state.callbacks.length) observedNodes["delete"](node); // Stop the loop
88
+
89
+ if (!observedNodes.size) cancelAnimationFrame(rafId);
90
+ }
91
+ }
92
+ };
93
+ }
94
+
95
+ function memo(getDeps, fn, opts) {
96
+ let deps = [];
97
+ let result;
98
+ return () => {
99
+ let depTime;
100
+ if (opts.key && opts.debug != null && opts.debug()) depTime = Date.now();
101
+ const newDeps = getDeps();
102
+ const depsChanged = newDeps.length !== deps.length || newDeps.some((dep, index) => deps[index] !== dep);
103
+
104
+ if (!depsChanged) {
105
+ return result;
106
+ }
107
+
108
+ deps = newDeps;
109
+ let resultTime;
110
+ if (opts.key && opts.debug != null && opts.debug()) resultTime = Date.now();
111
+ result = fn(...newDeps);
112
+ opts == null ? void 0 : opts.onChange == null ? void 0 : opts.onChange(result);
113
+
114
+ if (opts.key && opts.debug != null && opts.debug()) {
115
+ const depEndTime = Math.round((Date.now() - depTime) * 100) / 100;
116
+ const resultEndTime = Math.round((Date.now() - resultTime) * 100) / 100;
117
+ const resultFpsPercentage = resultEndTime / 16;
118
+
119
+ const pad = (str, num) => {
120
+ str = String(str);
121
+
122
+ while (str.length < num) {
123
+ str = ' ' + str;
124
+ }
125
+
126
+ return str;
127
+ };
128
+
129
+ 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);
130
+ }
131
+
132
+ return result;
133
+ };
134
+ }
135
+
136
+ //
137
+ const defaultKeyExtractor = index => index;
138
+ const defaultRangeExtractor = range => {
139
+ const start = Math.max(range.startIndex - range.overscan, 0);
140
+ const end = Math.min(range.endIndex + range.overscan, range.count - 1);
141
+ const arr = [];
142
+
143
+ for (let i = start; i <= end; i++) {
144
+ arr.push(i);
145
+ }
146
+
147
+ return arr;
148
+ };
149
+ const observeElementRect = (instance, cb) => {
150
+ const observer = observeRect(instance.scrollElement, rect => {
151
+ cb(rect);
152
+ });
153
+
154
+ if (!instance.scrollElement) {
155
+ return;
156
+ }
157
+
158
+ cb(instance.scrollElement.getBoundingClientRect());
159
+ observer.observe();
160
+ return () => {
161
+ observer.unobserve();
162
+ };
163
+ };
164
+ const observeWindowRect = (instance, cb) => {
165
+ const onResize = () => {
166
+ cb({
167
+ width: instance.scrollElement.innerWidth,
168
+ height: instance.scrollElement.innerHeight
169
+ });
170
+ };
171
+
172
+ if (!instance.scrollElement) {
173
+ return;
174
+ }
175
+
176
+ onResize();
177
+ instance.scrollElement.addEventListener('resize', onResize, {
178
+ capture: false,
179
+ passive: true
180
+ });
181
+ return () => {
182
+ instance.scrollElement.removeEventListener('resize', onResize);
183
+ };
184
+ };
185
+ const observeElementOffset = (instance, cb) => {
186
+ const onScroll = () => cb(instance.scrollElement[instance.options.horizontal ? 'scrollLeft' : 'scrollTop']);
187
+
188
+ if (!instance.scrollElement) {
189
+ return;
190
+ }
191
+
192
+ onScroll();
193
+ instance.scrollElement.addEventListener('scroll', onScroll, {
194
+ capture: false,
195
+ passive: true
196
+ });
197
+ return () => {
198
+ instance.scrollElement.removeEventListener('scroll', onScroll);
199
+ };
200
+ };
201
+ const observeWindowOffset = (instance, cb) => {
202
+ const onScroll = () => cb(instance.scrollElement[instance.options.horizontal ? 'scrollX' : 'scrollY']);
203
+
204
+ if (!instance.scrollElement) {
205
+ return;
206
+ }
207
+
208
+ onScroll();
209
+ instance.scrollElement.addEventListener('scroll', onScroll, {
210
+ capture: false,
211
+ passive: true
212
+ });
213
+ return () => {
214
+ instance.scrollElement.removeEventListener('scroll', onScroll);
215
+ };
216
+ };
217
+ const measureElement = (element, instance) => {
218
+ return element.getBoundingClientRect()[instance.options.horizontal ? 'width' : 'height'];
219
+ };
220
+ const windowScroll = (offset, canSmooth, instance) => {
221
+ var _instance$scrollEleme;
222
+ (_instance$scrollEleme = instance.scrollElement) == null ? void 0 : _instance$scrollEleme.scrollTo({
223
+ [instance.options.horizontal ? 'left' : 'top']: offset,
224
+ behavior: canSmooth ? 'smooth' : undefined
225
+ });
226
+ };
227
+ const elementScroll = (offset, canSmooth, instance) => {
228
+ var _instance$scrollEleme2;
229
+ (_instance$scrollEleme2 = instance.scrollElement) == null ? void 0 : _instance$scrollEleme2.scrollTo({
230
+ [instance.options.horizontal ? 'left' : 'top']: offset,
231
+ behavior: canSmooth ? 'smooth' : undefined
232
+ });
233
+ };
234
+ class Virtualizer {
235
+ constructor(_opts) {
236
+ var _this = this;
237
+
238
+ this.unsubs = [];
239
+ this.scrollElement = null;
240
+ this.measurementsCache = [];
241
+ this.itemMeasurementsCache = {};
242
+ this.pendingMeasuredCacheIndexes = [];
243
+ this.measureElementCache = {};
244
+
245
+ this.setOptions = opts => {
246
+ Object.entries(opts).forEach(_ref => {
247
+ let [key, value] = _ref;
248
+ if (typeof value === 'undefined') delete opts[key];
249
+ });
250
+ this.options = {
251
+ debug: false,
252
+ initialOffset: 0,
253
+ overscan: 1,
254
+ paddingStart: 0,
255
+ paddingEnd: 0,
256
+ scrollPaddingStart: 0,
257
+ scrollPaddingEnd: 0,
258
+ horizontal: false,
259
+ getItemKey: defaultKeyExtractor,
260
+ rangeExtractor: defaultRangeExtractor,
261
+ enableSmoothScroll: true,
262
+ onChange: () => {},
263
+ measureElement,
264
+ initialRect: {
265
+ width: 0,
266
+ height: 0
267
+ },
268
+ ...opts
269
+ };
270
+ };
271
+
272
+ this.notify = () => {
273
+ var _this$options$onChang, _this$options;
274
+
275
+ (_this$options$onChang = (_this$options = this.options).onChange) == null ? void 0 : _this$options$onChang.call(_this$options, this);
276
+ };
277
+
278
+ this.cleanup = () => {
279
+ this.unsubs.filter(Boolean).forEach(d => d());
280
+ this.unsubs = [];
281
+ };
282
+
283
+ this._didMount = () => {
284
+ return () => {
285
+ this.cleanup();
286
+ };
287
+ };
288
+
289
+ this._willUpdate = () => {
290
+ const scrollElement = this.options.getScrollElement();
291
+
292
+ if (this.scrollElement !== scrollElement) {
293
+ this.cleanup();
294
+ this.scrollElement = scrollElement;
295
+ this.unsubs.push(this.options.observeElementRect(this, rect => {
296
+ this.scrollRect = rect;
297
+ this.notify();
298
+ }));
299
+ this.unsubs.push(this.options.observeElementOffset(this, offset => {
300
+ this.scrollOffset = offset;
301
+ this.notify();
302
+ }));
303
+ }
304
+ };
305
+
306
+ this.getSize = () => {
307
+ return this.scrollRect[this.options.horizontal ? 'width' : 'height'];
308
+ };
309
+
310
+ this.getMeasurements = memo(() => [this.options.count, this.options.paddingStart, this.options.getItemKey, this.itemMeasurementsCache], (count, paddingStart, getItemKey, measurementsCache) => {
311
+ const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
312
+ this.pendingMeasuredCacheIndexes = [];
313
+ const measurements = this.measurementsCache.slice(0, min);
314
+
315
+ for (let i = min; i < count; i++) {
316
+ const key = getItemKey(i);
317
+ const measuredSize = measurementsCache[key];
318
+ const start = measurements[i - 1] ? measurements[i - 1].end : paddingStart;
319
+ const size = typeof measuredSize === 'number' ? measuredSize : this.options.estimateSize(i);
320
+ const end = start + size;
321
+ measurements[i] = {
322
+ index: i,
323
+ start,
324
+ size,
325
+ end,
326
+ key
327
+ };
328
+ }
329
+
330
+ this.measurementsCache = measurements;
331
+ return measurements;
332
+ }, {
333
+ key: process.env.NODE_ENV === 'development' && 'getMeasurements',
334
+ debug: () => this.options.debug
335
+ });
336
+ this.calculateRange = memo(() => [this.getMeasurements(), this.getSize(), this.scrollOffset], (measurements, outerSize, scrollOffset) => {
337
+ return calculateRange({
338
+ measurements,
339
+ outerSize,
340
+ scrollOffset
341
+ });
342
+ }, {
343
+ key: process.env.NODE_ENV === 'development' && 'calculateRange',
344
+ debug: () => this.options.debug
345
+ });
346
+ this.getIndexes = memo(() => [this.options.rangeExtractor, this.calculateRange(), this.options.overscan, this.options.count], (rangeExtractor, range, overscan, count) => {
347
+ return rangeExtractor({ ...range,
348
+ overscan,
349
+ count: count
350
+ });
351
+ }, {
352
+ key: process.env.NODE_ENV === 'development' && 'getIndexes'
353
+ });
354
+ this.getVirtualItems = memo(() => [this.getIndexes(), this.getMeasurements(), this.options.measureElement], (indexes, measurements, measureElement) => {
355
+ const makeMeasureElement = index => measurableItem => {
356
+ var _this$itemMeasurement;
357
+
358
+ const item = this.measurementsCache[index];
359
+
360
+ if (!measurableItem) {
361
+ return;
362
+ }
363
+
364
+ const measuredItemSize = measureElement(measurableItem, this);
365
+ const itemSize = (_this$itemMeasurement = this.itemMeasurementsCache[item.key]) != null ? _this$itemMeasurement : item.size;
366
+
367
+ if (measuredItemSize !== itemSize) {
368
+ if (item.start < this.scrollOffset) {
369
+ if (process.env.NODE_ENV === 'development' && this.options.debug) {
370
+ console.info('correction', measuredItemSize - itemSize);
371
+ }
372
+
373
+ if (!this.destinationOffset) {
374
+ this._scrollToOffset(this.scrollOffset + (measuredItemSize - itemSize), false);
375
+ }
376
+ }
377
+
378
+ this.pendingMeasuredCacheIndexes.push(index);
379
+ this.itemMeasurementsCache = { ...this.itemMeasurementsCache,
380
+ [item.key]: measuredItemSize
381
+ };
382
+ this.notify();
383
+ }
384
+ };
385
+
386
+ const virtualItems = [];
387
+ const currentMeasureElements = {};
388
+
389
+ for (let k = 0, len = indexes.length; k < len; k++) {
390
+ var _this$measureElementC;
391
+
392
+ const i = indexes[k];
393
+ const measurement = measurements[i];
394
+ const item = { ...measurement,
395
+ measureElement: currentMeasureElements[i] = (_this$measureElementC = this.measureElementCache[i]) != null ? _this$measureElementC : makeMeasureElement(i)
396
+ };
397
+ virtualItems.push(item);
398
+ }
399
+
400
+ this.measureElementCache = currentMeasureElements;
401
+ return virtualItems;
402
+ }, {
403
+ key: process.env.NODE_ENV === 'development' && 'getIndexes'
404
+ });
405
+
406
+ this.scrollToOffset = function (toOffset, _temp) {
407
+ let {
408
+ align
409
+ } = _temp === void 0 ? {
410
+ align: 'start'
411
+ } : _temp;
412
+
413
+ const attempt = () => {
414
+ const offset = _this.scrollOffset;
415
+
416
+ const size = _this.getSize();
417
+
418
+ if (align === 'auto') {
419
+ if (toOffset <= offset) {
420
+ align = 'start';
421
+ } else if (toOffset >= offset + size) {
422
+ align = 'end';
423
+ } else {
424
+ align = 'start';
425
+ }
426
+ }
427
+
428
+ if (align === 'start') {
429
+ _this._scrollToOffset(toOffset, true);
430
+ } else if (align === 'end') {
431
+ _this._scrollToOffset(toOffset - size, true);
432
+ } else if (align === 'center') {
433
+ _this._scrollToOffset(toOffset - size / 2, true);
434
+ }
435
+ };
436
+
437
+ attempt();
438
+ requestAnimationFrame(() => {
439
+ attempt();
440
+ });
441
+ };
442
+
443
+ this.scrollToIndex = function (index, _temp2) {
444
+ let {
445
+ align,
446
+ ...rest
447
+ } = _temp2 === void 0 ? {
448
+ align: 'auto'
449
+ } : _temp2;
450
+
451
+ const measurements = _this.getMeasurements();
452
+
453
+ const offset = _this.scrollOffset;
454
+
455
+ const size = _this.getSize();
456
+
457
+ const {
458
+ count
459
+ } = _this.options;
460
+ const measurement = measurements[Math.max(0, Math.min(index, count - 1))];
461
+
462
+ if (!measurement) {
463
+ return;
464
+ }
465
+
466
+ if (align === 'auto') {
467
+ if (measurement.end >= offset + size - _this.options.scrollPaddingEnd) {
468
+ align = 'end';
469
+ } else if (measurement.start <= offset + _this.options.scrollPaddingStart) {
470
+ align = 'start';
471
+ } else {
472
+ return;
473
+ }
474
+ }
475
+
476
+ const toOffset = align === 'end' ? measurement.end + _this.options.scrollPaddingEnd : measurement.start - _this.options.scrollPaddingStart;
477
+
478
+ _this.scrollToOffset(toOffset, {
479
+ align,
480
+ ...rest
481
+ });
482
+ };
483
+
484
+ this.getTotalSize = () => {
485
+ var _this$getMeasurements;
486
+
487
+ return (((_this$getMeasurements = this.getMeasurements()[this.options.count - 1]) == null ? void 0 : _this$getMeasurements.end) || this.options.paddingStart) + this.options.paddingEnd;
488
+ };
489
+
490
+ this._scrollToOffset = (offset, canSmooth) => {
491
+ clearTimeout(this.scrollCheckFrame);
492
+ this.destinationOffset = offset;
493
+ this.options.scrollToFn(offset, this.options.enableSmoothScroll && canSmooth, this);
494
+ let scrollCheckFrame;
495
+
496
+ const check = () => {
497
+ let lastOffset = this.scrollOffset;
498
+ this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {
499
+ if (this.scrollCheckFrame !== scrollCheckFrame) {
500
+ return;
501
+ }
502
+
503
+ if (this.scrollOffset === lastOffset) {
504
+ this.destinationOffset = undefined;
505
+ return;
506
+ }
507
+
508
+ lastOffset = this.scrollOffset;
509
+ check();
510
+ }, 100);
511
+ };
512
+
513
+ check();
514
+ };
515
+
516
+ this.measure = () => {
517
+ this.itemMeasurementsCache = {};
518
+ this.notify();
519
+ };
520
+
521
+ this.setOptions(_opts);
522
+ this.scrollRect = this.options.initialRect;
523
+ this.scrollOffset = this.options.initialOffset;
524
+ }
525
+
526
+ }
527
+
528
+ const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
529
+ while (low <= high) {
530
+ const middle = (low + high) / 2 | 0;
531
+ const currentValue = getCurrentValue(middle);
532
+
533
+ if (currentValue < value) {
534
+ low = middle + 1;
535
+ } else if (currentValue > value) {
536
+ high = middle - 1;
537
+ } else {
538
+ return middle;
539
+ }
540
+ }
541
+
542
+ if (low > 0) {
543
+ return low - 1;
544
+ } else {
545
+ return 0;
546
+ }
547
+ };
548
+
549
+ function calculateRange(_ref2) {
550
+ let {
551
+ measurements,
552
+ outerSize,
553
+ scrollOffset
554
+ } = _ref2;
555
+ const count = measurements.length - 1;
556
+
557
+ const getOffset = index => measurements[index].start;
558
+
559
+ const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset);
560
+ let endIndex = startIndex;
561
+
562
+ while (endIndex < count && measurements[endIndex].end < scrollOffset + outerSize) {
563
+ endIndex++;
564
+ }
565
+
566
+ return {
567
+ startIndex,
568
+ endIndex
569
+ };
570
+ }
571
+
572
+ exports.Virtualizer = Virtualizer;
573
+ exports.defaultKeyExtractor = defaultKeyExtractor;
574
+ exports.defaultRangeExtractor = defaultRangeExtractor;
575
+ exports.elementScroll = elementScroll;
576
+ exports.measureElement = measureElement;
577
+ exports.memo = memo;
578
+ exports.observeElementOffset = observeElementOffset;
579
+ exports.observeElementRect = observeElementRect;
580
+ exports.observeWindowOffset = observeWindowOffset;
581
+ exports.observeWindowRect = observeWindowRect;
582
+ exports.windowScroll = windowScroll;
583
+ //# sourceMappingURL=index.js.map