lkd-web-kit 0.4.0 → 0.4.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.
@@ -0,0 +1,744 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
4
+
5
+ const utils = require('./utils.cjs');
6
+
7
+ const getRect = (element) => {
8
+ const { offsetWidth, offsetHeight } = element;
9
+ return { width: offsetWidth, height: offsetHeight };
10
+ };
11
+ const defaultKeyExtractor = (index) => index;
12
+ const defaultRangeExtractor = (range) => {
13
+ const start = Math.max(range.startIndex - range.overscan, 0);
14
+ const end = Math.min(range.endIndex + range.overscan, range.count - 1);
15
+ const arr = [];
16
+ for (let i = start; i <= end; i++) {
17
+ arr.push(i);
18
+ }
19
+ return arr;
20
+ };
21
+ const observeElementRect = (instance, cb) => {
22
+ const element = instance.scrollElement;
23
+ if (!element) {
24
+ return;
25
+ }
26
+ const targetWindow = instance.targetWindow;
27
+ if (!targetWindow) {
28
+ return;
29
+ }
30
+ const handler = (rect) => {
31
+ const { width, height } = rect;
32
+ cb({ width: Math.round(width), height: Math.round(height) });
33
+ };
34
+ handler(getRect(element));
35
+ if (!targetWindow.ResizeObserver) {
36
+ return () => {
37
+ };
38
+ }
39
+ const observer = new targetWindow.ResizeObserver((entries) => {
40
+ const run = () => {
41
+ const entry = entries[0];
42
+ if (entry == null ? void 0 : entry.borderBoxSize) {
43
+ const box = entry.borderBoxSize[0];
44
+ if (box) {
45
+ handler({ width: box.inlineSize, height: box.blockSize });
46
+ return;
47
+ }
48
+ }
49
+ handler(getRect(element));
50
+ };
51
+ instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
52
+ });
53
+ observer.observe(element, { box: "border-box" });
54
+ return () => {
55
+ observer.unobserve(element);
56
+ };
57
+ };
58
+ const addEventListenerOptions = {
59
+ passive: true
60
+ };
61
+ const supportsScrollend = typeof window == "undefined" ? true : "onscrollend" in window;
62
+ const observeElementOffset = (instance, cb) => {
63
+ const element = instance.scrollElement;
64
+ if (!element) {
65
+ return;
66
+ }
67
+ const targetWindow = instance.targetWindow;
68
+ if (!targetWindow) {
69
+ return;
70
+ }
71
+ let offset = 0;
72
+ const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : utils.debounce(
73
+ targetWindow,
74
+ () => {
75
+ cb(offset, false);
76
+ },
77
+ instance.options.isScrollingResetDelay
78
+ );
79
+ const createHandler = (isScrolling) => () => {
80
+ const { horizontal, isRtl } = instance.options;
81
+ offset = horizontal ? element["scrollLeft"] * (isRtl && -1 || 1) : element["scrollTop"];
82
+ fallback();
83
+ cb(offset, isScrolling);
84
+ };
85
+ const handler = createHandler(true);
86
+ const endHandler = createHandler(false);
87
+ endHandler();
88
+ element.addEventListener("scroll", handler, addEventListenerOptions);
89
+ const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;
90
+ if (registerScrollendEvent) {
91
+ element.addEventListener("scrollend", endHandler, addEventListenerOptions);
92
+ }
93
+ return () => {
94
+ element.removeEventListener("scroll", handler);
95
+ if (registerScrollendEvent) {
96
+ element.removeEventListener("scrollend", endHandler);
97
+ }
98
+ };
99
+ };
100
+ const measureElement = (element, entry, instance) => {
101
+ if (entry == null ? void 0 : entry.borderBoxSize) {
102
+ const box = entry.borderBoxSize[0];
103
+ if (box) {
104
+ const size = Math.round(
105
+ box[instance.options.horizontal ? "inlineSize" : "blockSize"]
106
+ );
107
+ return size;
108
+ }
109
+ }
110
+ return element[instance.options.horizontal ? "offsetWidth" : "offsetHeight"];
111
+ };
112
+ const elementScroll = (offset, {
113
+ adjustments = 0,
114
+ behavior
115
+ }, instance) => {
116
+ var _a, _b;
117
+ const toOffset = offset + adjustments;
118
+ (_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null ? void 0 : _b.call(_a, {
119
+ [instance.options.horizontal ? "left" : "top"]: toOffset,
120
+ behavior
121
+ });
122
+ };
123
+ class Virtualizer {
124
+ constructor(opts) {
125
+ this.unsubs = [];
126
+ this.scrollElement = null;
127
+ this.targetWindow = null;
128
+ this.isScrolling = false;
129
+ this.scrollToIndexTimeoutId = null;
130
+ this.measurementsCache = [];
131
+ this.itemSizeCache = /* @__PURE__ */ new Map();
132
+ this.pendingMeasuredCacheIndexes = [];
133
+ this.scrollRect = null;
134
+ this.scrollOffset = null;
135
+ this.scrollDirection = null;
136
+ this.scrollAdjustments = 0;
137
+ this.elementsCache = /* @__PURE__ */ new Map();
138
+ this.observer = /* @__PURE__ */ (() => {
139
+ let _ro = null;
140
+ const get = () => {
141
+ if (_ro) {
142
+ return _ro;
143
+ }
144
+ if (!this.targetWindow || !this.targetWindow.ResizeObserver) {
145
+ return null;
146
+ }
147
+ return _ro = new this.targetWindow.ResizeObserver((entries) => {
148
+ entries.forEach((entry) => {
149
+ const run = () => {
150
+ this._measureElement(entry.target, entry);
151
+ };
152
+ this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
153
+ });
154
+ });
155
+ };
156
+ return {
157
+ disconnect: () => {
158
+ var _a;
159
+ (_a = get()) == null ? void 0 : _a.disconnect();
160
+ _ro = null;
161
+ },
162
+ observe: (target) => {
163
+ var _a;
164
+ return (_a = get()) == null ? void 0 : _a.observe(target, { box: "border-box" });
165
+ },
166
+ unobserve: (target) => {
167
+ var _a;
168
+ return (_a = get()) == null ? void 0 : _a.unobserve(target);
169
+ }
170
+ };
171
+ })();
172
+ this.range = null;
173
+ this.setOptions = (opts2) => {
174
+ Object.entries(opts2).forEach(([key, value]) => {
175
+ if (typeof value === "undefined") delete opts2[key];
176
+ });
177
+ this.options = {
178
+ debug: false,
179
+ initialOffset: 0,
180
+ overscan: 1,
181
+ paddingStart: 0,
182
+ paddingEnd: 0,
183
+ scrollPaddingStart: 0,
184
+ scrollPaddingEnd: 0,
185
+ horizontal: false,
186
+ getItemKey: defaultKeyExtractor,
187
+ rangeExtractor: defaultRangeExtractor,
188
+ onChange: () => {
189
+ },
190
+ measureElement,
191
+ initialRect: { width: 0, height: 0 },
192
+ scrollMargin: 0,
193
+ gap: 0,
194
+ indexAttribute: "data-index",
195
+ initialMeasurementsCache: [],
196
+ lanes: 1,
197
+ isScrollingResetDelay: 150,
198
+ enabled: true,
199
+ isRtl: false,
200
+ useScrollendEvent: false,
201
+ useAnimationFrameWithResizeObserver: false,
202
+ ...opts2
203
+ };
204
+ };
205
+ this.notify = (sync) => {
206
+ var _a, _b;
207
+ (_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a, this, sync);
208
+ };
209
+ this.maybeNotify = utils.memo(
210
+ () => {
211
+ this.calculateRange();
212
+ return [
213
+ this.isScrolling,
214
+ this.range ? this.range.startIndex : null,
215
+ this.range ? this.range.endIndex : null
216
+ ];
217
+ },
218
+ (isScrolling) => {
219
+ this.notify(isScrolling);
220
+ },
221
+ {
222
+ key: process.env.NODE_ENV !== "production" && "maybeNotify",
223
+ debug: () => this.options.debug,
224
+ initialDeps: [
225
+ this.isScrolling,
226
+ this.range ? this.range.startIndex : null,
227
+ this.range ? this.range.endIndex : null
228
+ ]
229
+ }
230
+ );
231
+ this.cleanup = () => {
232
+ this.unsubs.filter(Boolean).forEach((d) => d());
233
+ this.unsubs = [];
234
+ this.observer.disconnect();
235
+ this.scrollElement = null;
236
+ this.targetWindow = null;
237
+ };
238
+ this._didMount = () => {
239
+ return () => {
240
+ this.cleanup();
241
+ };
242
+ };
243
+ this._willUpdate = () => {
244
+ var _a;
245
+ const scrollElement = this.options.enabled ? this.options.getScrollElement() : null;
246
+ if (this.scrollElement !== scrollElement) {
247
+ this.cleanup();
248
+ if (!scrollElement) {
249
+ this.maybeNotify();
250
+ return;
251
+ }
252
+ this.scrollElement = scrollElement;
253
+ if (this.scrollElement && "ownerDocument" in this.scrollElement) {
254
+ this.targetWindow = this.scrollElement.ownerDocument.defaultView;
255
+ } else {
256
+ this.targetWindow = ((_a = this.scrollElement) == null ? void 0 : _a.window) ?? null;
257
+ }
258
+ this.elementsCache.forEach((cached) => {
259
+ this.observer.observe(cached);
260
+ });
261
+ this._scrollToOffset(this.getScrollOffset(), {
262
+ adjustments: void 0,
263
+ behavior: void 0
264
+ });
265
+ this.unsubs.push(
266
+ this.options.observeElementRect(this, (rect) => {
267
+ this.scrollRect = rect;
268
+ this.maybeNotify();
269
+ })
270
+ );
271
+ this.unsubs.push(
272
+ this.options.observeElementOffset(this, (offset, isScrolling) => {
273
+ this.scrollAdjustments = 0;
274
+ this.scrollDirection = isScrolling ? this.getScrollOffset() < offset ? "forward" : "backward" : null;
275
+ this.scrollOffset = offset;
276
+ this.isScrolling = isScrolling;
277
+ this.maybeNotify();
278
+ })
279
+ );
280
+ }
281
+ };
282
+ this.getSize = () => {
283
+ if (!this.options.enabled) {
284
+ this.scrollRect = null;
285
+ return 0;
286
+ }
287
+ this.scrollRect = this.scrollRect ?? this.options.initialRect;
288
+ return this.scrollRect[this.options.horizontal ? "width" : "height"];
289
+ };
290
+ this.getScrollOffset = () => {
291
+ if (!this.options.enabled) {
292
+ this.scrollOffset = null;
293
+ return 0;
294
+ }
295
+ this.scrollOffset = this.scrollOffset ?? (typeof this.options.initialOffset === "function" ? this.options.initialOffset() : this.options.initialOffset);
296
+ return this.scrollOffset;
297
+ };
298
+ this.getFurthestMeasurement = (measurements, index) => {
299
+ const furthestMeasurementsFound = /* @__PURE__ */ new Map();
300
+ const furthestMeasurements = /* @__PURE__ */ new Map();
301
+ for (let m = index - 1; m >= 0; m--) {
302
+ const measurement = measurements[m];
303
+ if (furthestMeasurementsFound.has(measurement.lane)) {
304
+ continue;
305
+ }
306
+ const previousFurthestMeasurement = furthestMeasurements.get(
307
+ measurement.lane
308
+ );
309
+ if (previousFurthestMeasurement == null || measurement.end > previousFurthestMeasurement.end) {
310
+ furthestMeasurements.set(measurement.lane, measurement);
311
+ } else if (measurement.end < previousFurthestMeasurement.end) {
312
+ furthestMeasurementsFound.set(measurement.lane, true);
313
+ }
314
+ if (furthestMeasurementsFound.size === this.options.lanes) {
315
+ break;
316
+ }
317
+ }
318
+ return furthestMeasurements.size === this.options.lanes ? Array.from(furthestMeasurements.values()).sort((a, b) => {
319
+ if (a.end === b.end) {
320
+ return a.index - b.index;
321
+ }
322
+ return a.end - b.end;
323
+ })[0] : void 0;
324
+ };
325
+ this.getMeasurementOptions = utils.memo(
326
+ () => [
327
+ this.options.count,
328
+ this.options.paddingStart,
329
+ this.options.scrollMargin,
330
+ this.options.getItemKey,
331
+ this.options.enabled
332
+ ],
333
+ (count, paddingStart, scrollMargin, getItemKey, enabled) => {
334
+ this.pendingMeasuredCacheIndexes = [];
335
+ return {
336
+ count,
337
+ paddingStart,
338
+ scrollMargin,
339
+ getItemKey,
340
+ enabled
341
+ };
342
+ },
343
+ {
344
+ key: false
345
+ }
346
+ );
347
+ this.getMeasurements = utils.memo(
348
+ () => [this.getMeasurementOptions(), this.itemSizeCache],
349
+ ({ count, paddingStart, scrollMargin, getItemKey, enabled }, itemSizeCache) => {
350
+ if (!enabled) {
351
+ this.measurementsCache = [];
352
+ this.itemSizeCache.clear();
353
+ return [];
354
+ }
355
+ if (this.measurementsCache.length === 0) {
356
+ this.measurementsCache = this.options.initialMeasurementsCache;
357
+ this.measurementsCache.forEach((item) => {
358
+ this.itemSizeCache.set(item.key, item.size);
359
+ });
360
+ }
361
+ const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
362
+ this.pendingMeasuredCacheIndexes = [];
363
+ const measurements = this.measurementsCache.slice(0, min);
364
+ for (let i = min; i < count; i++) {
365
+ const key = getItemKey(i);
366
+ const furthestMeasurement = this.options.lanes === 1 ? measurements[i - 1] : this.getFurthestMeasurement(measurements, i);
367
+ const start = furthestMeasurement ? furthestMeasurement.end + this.options.gap : paddingStart + scrollMargin;
368
+ const measuredSize = itemSizeCache.get(key);
369
+ const size = typeof measuredSize === "number" ? measuredSize : this.options.estimateSize(i);
370
+ const end = start + size;
371
+ const lane = furthestMeasurement ? furthestMeasurement.lane : i % this.options.lanes;
372
+ measurements[i] = {
373
+ index: i,
374
+ start,
375
+ size,
376
+ end,
377
+ key,
378
+ lane
379
+ };
380
+ }
381
+ this.measurementsCache = measurements;
382
+ return measurements;
383
+ },
384
+ {
385
+ key: process.env.NODE_ENV !== "production" && "getMeasurements",
386
+ debug: () => this.options.debug
387
+ }
388
+ );
389
+ this.calculateRange = utils.memo(
390
+ () => [
391
+ this.getMeasurements(),
392
+ this.getSize(),
393
+ this.getScrollOffset(),
394
+ this.options.lanes
395
+ ],
396
+ (measurements, outerSize, scrollOffset, lanes) => {
397
+ return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({
398
+ measurements,
399
+ outerSize,
400
+ scrollOffset,
401
+ lanes
402
+ }) : null;
403
+ },
404
+ {
405
+ key: process.env.NODE_ENV !== "production" && "calculateRange",
406
+ debug: () => this.options.debug
407
+ }
408
+ );
409
+ this.getVirtualIndexes = utils.memo(
410
+ () => {
411
+ let startIndex = null;
412
+ let endIndex = null;
413
+ const range = this.calculateRange();
414
+ if (range) {
415
+ startIndex = range.startIndex;
416
+ endIndex = range.endIndex;
417
+ }
418
+ this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);
419
+ return [
420
+ this.options.rangeExtractor,
421
+ this.options.overscan,
422
+ this.options.count,
423
+ startIndex,
424
+ endIndex
425
+ ];
426
+ },
427
+ (rangeExtractor, overscan, count, startIndex, endIndex) => {
428
+ return startIndex === null || endIndex === null ? [] : rangeExtractor({
429
+ startIndex,
430
+ endIndex,
431
+ overscan,
432
+ count
433
+ });
434
+ },
435
+ {
436
+ key: process.env.NODE_ENV !== "production" && "getVirtualIndexes",
437
+ debug: () => this.options.debug
438
+ }
439
+ );
440
+ this.indexFromElement = (node) => {
441
+ const attributeName = this.options.indexAttribute;
442
+ const indexStr = node.getAttribute(attributeName);
443
+ if (!indexStr) {
444
+ console.warn(
445
+ `Missing attribute name '${attributeName}={index}' on measured element.`
446
+ );
447
+ return -1;
448
+ }
449
+ return parseInt(indexStr, 10);
450
+ };
451
+ this._measureElement = (node, entry) => {
452
+ const index = this.indexFromElement(node);
453
+ const item = this.measurementsCache[index];
454
+ if (!item) {
455
+ return;
456
+ }
457
+ const key = item.key;
458
+ const prevNode = this.elementsCache.get(key);
459
+ if (prevNode !== node) {
460
+ if (prevNode) {
461
+ this.observer.unobserve(prevNode);
462
+ }
463
+ this.observer.observe(node);
464
+ this.elementsCache.set(key, node);
465
+ }
466
+ if (node.isConnected) {
467
+ this.resizeItem(index, this.options.measureElement(node, entry, this));
468
+ }
469
+ };
470
+ this.resizeItem = (index, size) => {
471
+ const item = this.measurementsCache[index];
472
+ if (!item) {
473
+ return;
474
+ }
475
+ const itemSize = this.itemSizeCache.get(item.key) ?? item.size;
476
+ const delta = size - itemSize;
477
+ if (delta !== 0) {
478
+ if (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments) {
479
+ if (process.env.NODE_ENV !== "production" && this.options.debug) {
480
+ console.info("correction", delta);
481
+ }
482
+ this._scrollToOffset(this.getScrollOffset(), {
483
+ adjustments: this.scrollAdjustments += delta,
484
+ behavior: void 0
485
+ });
486
+ }
487
+ this.pendingMeasuredCacheIndexes.push(item.index);
488
+ this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size));
489
+ this.notify(false);
490
+ }
491
+ };
492
+ this.measureElement = (node) => {
493
+ if (!node) {
494
+ this.elementsCache.forEach((cached, key) => {
495
+ if (!cached.isConnected) {
496
+ this.observer.unobserve(cached);
497
+ this.elementsCache.delete(key);
498
+ }
499
+ });
500
+ return;
501
+ }
502
+ this._measureElement(node, void 0);
503
+ };
504
+ this.getVirtualItems = utils.memo(
505
+ () => [this.getVirtualIndexes(), this.getMeasurements()],
506
+ (indexes, measurements) => {
507
+ const virtualItems = [];
508
+ for (let k = 0, len = indexes.length; k < len; k++) {
509
+ const i = indexes[k];
510
+ const measurement = measurements[i];
511
+ virtualItems.push(measurement);
512
+ }
513
+ return virtualItems;
514
+ },
515
+ {
516
+ key: process.env.NODE_ENV !== "production" && "getVirtualItems",
517
+ debug: () => this.options.debug
518
+ }
519
+ );
520
+ this.getVirtualItemForOffset = (offset) => {
521
+ const measurements = this.getMeasurements();
522
+ if (measurements.length === 0) {
523
+ return void 0;
524
+ }
525
+ return utils.notUndefined(
526
+ measurements[findNearestBinarySearch(
527
+ 0,
528
+ measurements.length - 1,
529
+ (index) => utils.notUndefined(measurements[index]).start,
530
+ offset
531
+ )]
532
+ );
533
+ };
534
+ this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
535
+ const size = this.getSize();
536
+ const scrollOffset = this.getScrollOffset();
537
+ if (align === "auto") {
538
+ align = toOffset >= scrollOffset + size ? "end" : "start";
539
+ }
540
+ if (align === "center") {
541
+ toOffset += (itemSize - size) / 2;
542
+ } else if (align === "end") {
543
+ toOffset -= size;
544
+ }
545
+ const maxOffset = this.getTotalSize() - size;
546
+ return Math.max(Math.min(maxOffset, toOffset), 0);
547
+ };
548
+ this.getOffsetForIndex = (index, align = "auto") => {
549
+ index = Math.max(0, Math.min(index, this.options.count - 1));
550
+ const item = this.measurementsCache[index];
551
+ if (!item) {
552
+ return void 0;
553
+ }
554
+ const size = this.getSize();
555
+ const scrollOffset = this.getScrollOffset();
556
+ if (align === "auto") {
557
+ if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {
558
+ align = "end";
559
+ } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {
560
+ align = "start";
561
+ } else {
562
+ return [scrollOffset, align];
563
+ }
564
+ }
565
+ const toOffset = align === "end" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart;
566
+ return [
567
+ this.getOffsetForAlignment(toOffset, align, item.size),
568
+ align
569
+ ];
570
+ };
571
+ this.isDynamicMode = () => this.elementsCache.size > 0;
572
+ this.cancelScrollToIndex = () => {
573
+ if (this.scrollToIndexTimeoutId !== null && this.targetWindow) {
574
+ this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId);
575
+ this.scrollToIndexTimeoutId = null;
576
+ }
577
+ };
578
+ this.scrollToOffset = (toOffset, { align = "start", behavior } = {}) => {
579
+ this.cancelScrollToIndex();
580
+ if (behavior === "smooth" && this.isDynamicMode()) {
581
+ console.warn(
582
+ "The `smooth` scroll behavior is not fully supported with dynamic size."
583
+ );
584
+ }
585
+ this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {
586
+ adjustments: void 0,
587
+ behavior
588
+ });
589
+ };
590
+ this.scrollToIndex = (index, { align: initialAlign = "auto", behavior } = {}) => {
591
+ index = Math.max(0, Math.min(index, this.options.count - 1));
592
+ this.cancelScrollToIndex();
593
+ if (behavior === "smooth" && this.isDynamicMode()) {
594
+ console.warn(
595
+ "The `smooth` scroll behavior is not fully supported with dynamic size."
596
+ );
597
+ }
598
+ const offsetAndAlign = this.getOffsetForIndex(index, initialAlign);
599
+ if (!offsetAndAlign) return;
600
+ const [offset, align] = offsetAndAlign;
601
+ this._scrollToOffset(offset, { adjustments: void 0, behavior });
602
+ if (behavior !== "smooth" && this.isDynamicMode() && this.targetWindow) {
603
+ this.scrollToIndexTimeoutId = this.targetWindow.setTimeout(() => {
604
+ this.scrollToIndexTimeoutId = null;
605
+ const elementInDOM = this.elementsCache.has(
606
+ this.options.getItemKey(index)
607
+ );
608
+ if (elementInDOM) {
609
+ const result = this.getOffsetForIndex(index, align);
610
+ if (!result) return;
611
+ const [latestOffset] = result;
612
+ const currentScrollOffset = this.getScrollOffset();
613
+ if (!utils.approxEqual(latestOffset, currentScrollOffset)) {
614
+ this.scrollToIndex(index, { align, behavior });
615
+ }
616
+ } else {
617
+ this.scrollToIndex(index, { align, behavior });
618
+ }
619
+ });
620
+ }
621
+ };
622
+ this.scrollBy = (delta, { behavior } = {}) => {
623
+ this.cancelScrollToIndex();
624
+ if (behavior === "smooth" && this.isDynamicMode()) {
625
+ console.warn(
626
+ "The `smooth` scroll behavior is not fully supported with dynamic size."
627
+ );
628
+ }
629
+ this._scrollToOffset(this.getScrollOffset() + delta, {
630
+ adjustments: void 0,
631
+ behavior
632
+ });
633
+ };
634
+ this.getTotalSize = () => {
635
+ var _a;
636
+ const measurements = this.getMeasurements();
637
+ let end;
638
+ if (measurements.length === 0) {
639
+ end = this.options.paddingStart;
640
+ } else if (this.options.lanes === 1) {
641
+ end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;
642
+ } else {
643
+ const endByLane = Array(this.options.lanes).fill(null);
644
+ let endIndex = measurements.length - 1;
645
+ while (endIndex >= 0 && endByLane.some((val) => val === null)) {
646
+ const item = measurements[endIndex];
647
+ if (endByLane[item.lane] === null) {
648
+ endByLane[item.lane] = item.end;
649
+ }
650
+ endIndex--;
651
+ }
652
+ end = Math.max(...endByLane.filter((val) => val !== null));
653
+ }
654
+ return Math.max(
655
+ end - this.options.scrollMargin + this.options.paddingEnd,
656
+ 0
657
+ );
658
+ };
659
+ this._scrollToOffset = (offset, {
660
+ adjustments,
661
+ behavior
662
+ }) => {
663
+ this.options.scrollToFn(offset, { behavior, adjustments }, this);
664
+ };
665
+ this.measure = () => {
666
+ this.itemSizeCache = /* @__PURE__ */ new Map();
667
+ this.notify(false);
668
+ };
669
+ this.setOptions(opts);
670
+ }
671
+ }
672
+ const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
673
+ while (low <= high) {
674
+ const middle = (low + high) / 2 | 0;
675
+ const currentValue = getCurrentValue(middle);
676
+ if (currentValue < value) {
677
+ low = middle + 1;
678
+ } else if (currentValue > value) {
679
+ high = middle - 1;
680
+ } else {
681
+ return middle;
682
+ }
683
+ }
684
+ if (low > 0) {
685
+ return low - 1;
686
+ } else {
687
+ return 0;
688
+ }
689
+ };
690
+ function calculateRange({
691
+ measurements,
692
+ outerSize,
693
+ scrollOffset,
694
+ lanes
695
+ }) {
696
+ const lastIndex = measurements.length - 1;
697
+ const getOffset = (index) => measurements[index].start;
698
+ if (measurements.length <= lanes) {
699
+ return {
700
+ startIndex: 0,
701
+ endIndex: lastIndex
702
+ };
703
+ }
704
+ let startIndex = findNearestBinarySearch(
705
+ 0,
706
+ lastIndex,
707
+ getOffset,
708
+ scrollOffset
709
+ );
710
+ let endIndex = startIndex;
711
+ if (lanes === 1) {
712
+ while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) {
713
+ endIndex++;
714
+ }
715
+ } else if (lanes > 1) {
716
+ const endPerLane = Array(lanes).fill(0);
717
+ while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {
718
+ const item = measurements[endIndex];
719
+ endPerLane[item.lane] = item.end;
720
+ endIndex++;
721
+ }
722
+ const startPerLane = Array(lanes).fill(scrollOffset + outerSize);
723
+ while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
724
+ const item = measurements[startIndex];
725
+ startPerLane[item.lane] = item.start;
726
+ startIndex--;
727
+ }
728
+ startIndex = Math.max(0, startIndex - startIndex % lanes);
729
+ endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));
730
+ }
731
+ return { startIndex, endIndex };
732
+ }
733
+
734
+ exports.approxEqual = utils.approxEqual;
735
+ exports.debounce = utils.debounce;
736
+ exports.memo = utils.memo;
737
+ exports.notUndefined = utils.notUndefined;
738
+ exports.Virtualizer = Virtualizer;
739
+ exports.defaultKeyExtractor = defaultKeyExtractor;
740
+ exports.defaultRangeExtractor = defaultRangeExtractor;
741
+ exports.elementScroll = elementScroll;
742
+ exports.measureElement = measureElement;
743
+ exports.observeElementOffset = observeElementOffset;
744
+ exports.observeElementRect = observeElementRect;