@usefragments/ui 1.0.0 → 1.0.2

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.
@@ -1,822 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
- const utils = require("./utils.cjs");
4
- const getRect = (element) => {
5
- const { offsetWidth, offsetHeight } = element;
6
- return { width: offsetWidth, height: offsetHeight };
7
- };
8
- const defaultKeyExtractor = (index) => index;
9
- const defaultRangeExtractor = (range) => {
10
- const start = Math.max(range.startIndex - range.overscan, 0);
11
- const end = Math.min(range.endIndex + range.overscan, range.count - 1);
12
- const arr = [];
13
- for (let i = start; i <= end; i++) {
14
- arr.push(i);
15
- }
16
- return arr;
17
- };
18
- const observeElementRect = (instance, cb) => {
19
- const element = instance.scrollElement;
20
- if (!element) {
21
- return;
22
- }
23
- const targetWindow = instance.targetWindow;
24
- if (!targetWindow) {
25
- return;
26
- }
27
- const handler = (rect) => {
28
- const { width, height } = rect;
29
- cb({ width: Math.round(width), height: Math.round(height) });
30
- };
31
- handler(getRect(element));
32
- if (!targetWindow.ResizeObserver) {
33
- return () => {
34
- };
35
- }
36
- const observer = new targetWindow.ResizeObserver((entries) => {
37
- const run = () => {
38
- const entry = entries[0];
39
- if (entry == null ? void 0 : entry.borderBoxSize) {
40
- const box = entry.borderBoxSize[0];
41
- if (box) {
42
- handler({ width: box.inlineSize, height: box.blockSize });
43
- return;
44
- }
45
- }
46
- handler(getRect(element));
47
- };
48
- instance.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
49
- });
50
- observer.observe(element, { box: "border-box" });
51
- return () => {
52
- observer.unobserve(element);
53
- };
54
- };
55
- const addEventListenerOptions = {
56
- passive: true
57
- };
58
- const supportsScrollend = typeof window == "undefined" ? true : "onscrollend" in window;
59
- const observeElementOffset = (instance, cb) => {
60
- const element = instance.scrollElement;
61
- if (!element) {
62
- return;
63
- }
64
- const targetWindow = instance.targetWindow;
65
- if (!targetWindow) {
66
- return;
67
- }
68
- let offset = 0;
69
- const fallback = instance.options.useScrollendEvent && supportsScrollend ? () => void 0 : utils.debounce(
70
- targetWindow,
71
- () => {
72
- cb(offset, false);
73
- },
74
- instance.options.isScrollingResetDelay
75
- );
76
- const createHandler = (isScrolling) => () => {
77
- const { horizontal, isRtl } = instance.options;
78
- offset = horizontal ? element["scrollLeft"] * (isRtl && -1 || 1) : element["scrollTop"];
79
- fallback();
80
- cb(offset, isScrolling);
81
- };
82
- const handler = createHandler(true);
83
- const endHandler = createHandler(false);
84
- element.addEventListener("scroll", handler, addEventListenerOptions);
85
- const registerScrollendEvent = instance.options.useScrollendEvent && supportsScrollend;
86
- if (registerScrollendEvent) {
87
- element.addEventListener("scrollend", endHandler, addEventListenerOptions);
88
- }
89
- return () => {
90
- element.removeEventListener("scroll", handler);
91
- if (registerScrollendEvent) {
92
- element.removeEventListener("scrollend", endHandler);
93
- }
94
- };
95
- };
96
- const measureElement = (element, entry, instance) => {
97
- if (entry == null ? void 0 : entry.borderBoxSize) {
98
- const box = entry.borderBoxSize[0];
99
- if (box) {
100
- const size = Math.round(
101
- box[instance.options.horizontal ? "inlineSize" : "blockSize"]
102
- );
103
- return size;
104
- }
105
- }
106
- return element[instance.options.horizontal ? "offsetWidth" : "offsetHeight"];
107
- };
108
- const elementScroll = (offset, {
109
- adjustments = 0,
110
- behavior
111
- }, instance) => {
112
- var _a, _b;
113
- const toOffset = offset + adjustments;
114
- (_b = (_a = instance.scrollElement) == null ? void 0 : _a.scrollTo) == null ? void 0 : _b.call(_a, {
115
- [instance.options.horizontal ? "left" : "top"]: toOffset,
116
- behavior
117
- });
118
- };
119
- class Virtualizer {
120
- constructor(opts) {
121
- this.unsubs = [];
122
- this.scrollElement = null;
123
- this.targetWindow = null;
124
- this.isScrolling = false;
125
- this.currentScrollToIndex = null;
126
- this.measurementsCache = [];
127
- this.itemSizeCache = /* @__PURE__ */ new Map();
128
- this.laneAssignments = /* @__PURE__ */ new Map();
129
- this.pendingMeasuredCacheIndexes = [];
130
- this.prevLanes = void 0;
131
- this.lanesChangedFlag = false;
132
- this.lanesSettling = false;
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.unsubs.push(
262
- this.options.observeElementRect(this, (rect) => {
263
- this.scrollRect = rect;
264
- this.maybeNotify();
265
- })
266
- );
267
- this.unsubs.push(
268
- this.options.observeElementOffset(this, (offset, isScrolling) => {
269
- this.scrollAdjustments = 0;
270
- this.scrollDirection = isScrolling ? this.getScrollOffset() < offset ? "forward" : "backward" : null;
271
- this.scrollOffset = offset;
272
- this.isScrolling = isScrolling;
273
- this.maybeNotify();
274
- })
275
- );
276
- this._scrollToOffset(this.getScrollOffset(), {
277
- adjustments: void 0,
278
- behavior: void 0
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
- this.options.lanes
333
- ],
334
- (count, paddingStart, scrollMargin, getItemKey, enabled, lanes) => {
335
- const lanesChanged = this.prevLanes !== void 0 && this.prevLanes !== lanes;
336
- if (lanesChanged) {
337
- this.lanesChangedFlag = true;
338
- }
339
- this.prevLanes = lanes;
340
- this.pendingMeasuredCacheIndexes = [];
341
- return {
342
- count,
343
- paddingStart,
344
- scrollMargin,
345
- getItemKey,
346
- enabled,
347
- lanes
348
- };
349
- },
350
- {
351
- key: false
352
- }
353
- );
354
- this.getMeasurements = utils.memo(
355
- () => [this.getMeasurementOptions(), this.itemSizeCache],
356
- ({ count, paddingStart, scrollMargin, getItemKey, enabled, lanes }, itemSizeCache) => {
357
- if (!enabled) {
358
- this.measurementsCache = [];
359
- this.itemSizeCache.clear();
360
- this.laneAssignments.clear();
361
- return [];
362
- }
363
- if (this.laneAssignments.size > count) {
364
- for (const index of this.laneAssignments.keys()) {
365
- if (index >= count) {
366
- this.laneAssignments.delete(index);
367
- }
368
- }
369
- }
370
- if (this.lanesChangedFlag) {
371
- this.lanesChangedFlag = false;
372
- this.lanesSettling = true;
373
- this.measurementsCache = [];
374
- this.itemSizeCache.clear();
375
- this.laneAssignments.clear();
376
- this.pendingMeasuredCacheIndexes = [];
377
- }
378
- if (this.measurementsCache.length === 0 && !this.lanesSettling) {
379
- this.measurementsCache = this.options.initialMeasurementsCache;
380
- this.measurementsCache.forEach((item) => {
381
- this.itemSizeCache.set(item.key, item.size);
382
- });
383
- }
384
- const min = this.lanesSettling ? 0 : this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
385
- this.pendingMeasuredCacheIndexes = [];
386
- if (this.lanesSettling && this.measurementsCache.length === count) {
387
- this.lanesSettling = false;
388
- }
389
- const measurements = this.measurementsCache.slice(0, min);
390
- const laneLastIndex = new Array(lanes).fill(
391
- void 0
392
- );
393
- for (let m = 0; m < min; m++) {
394
- const item = measurements[m];
395
- if (item) {
396
- laneLastIndex[item.lane] = m;
397
- }
398
- }
399
- for (let i = min; i < count; i++) {
400
- const key = getItemKey(i);
401
- const cachedLane = this.laneAssignments.get(i);
402
- let lane;
403
- let start;
404
- if (cachedLane !== void 0 && this.options.lanes > 1) {
405
- lane = cachedLane;
406
- const prevIndex = laneLastIndex[lane];
407
- const prevInLane = prevIndex !== void 0 ? measurements[prevIndex] : void 0;
408
- start = prevInLane ? prevInLane.end + this.options.gap : paddingStart + scrollMargin;
409
- } else {
410
- const furthestMeasurement = this.options.lanes === 1 ? measurements[i - 1] : this.getFurthestMeasurement(measurements, i);
411
- start = furthestMeasurement ? furthestMeasurement.end + this.options.gap : paddingStart + scrollMargin;
412
- lane = furthestMeasurement ? furthestMeasurement.lane : i % this.options.lanes;
413
- if (this.options.lanes > 1) {
414
- this.laneAssignments.set(i, lane);
415
- }
416
- }
417
- const measuredSize = itemSizeCache.get(key);
418
- const size = typeof measuredSize === "number" ? measuredSize : this.options.estimateSize(i);
419
- const end = start + size;
420
- measurements[i] = {
421
- index: i,
422
- start,
423
- size,
424
- end,
425
- key,
426
- lane
427
- };
428
- laneLastIndex[lane] = i;
429
- }
430
- this.measurementsCache = measurements;
431
- return measurements;
432
- },
433
- {
434
- key: process.env.NODE_ENV !== "production" && "getMeasurements",
435
- debug: () => this.options.debug
436
- }
437
- );
438
- this.calculateRange = utils.memo(
439
- () => [
440
- this.getMeasurements(),
441
- this.getSize(),
442
- this.getScrollOffset(),
443
- this.options.lanes
444
- ],
445
- (measurements, outerSize, scrollOffset, lanes) => {
446
- return this.range = measurements.length > 0 && outerSize > 0 ? calculateRange({
447
- measurements,
448
- outerSize,
449
- scrollOffset,
450
- lanes
451
- }) : null;
452
- },
453
- {
454
- key: process.env.NODE_ENV !== "production" && "calculateRange",
455
- debug: () => this.options.debug
456
- }
457
- );
458
- this.getVirtualIndexes = utils.memo(
459
- () => {
460
- let startIndex = null;
461
- let endIndex = null;
462
- const range = this.calculateRange();
463
- if (range) {
464
- startIndex = range.startIndex;
465
- endIndex = range.endIndex;
466
- }
467
- this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex]);
468
- return [
469
- this.options.rangeExtractor,
470
- this.options.overscan,
471
- this.options.count,
472
- startIndex,
473
- endIndex
474
- ];
475
- },
476
- (rangeExtractor, overscan, count, startIndex, endIndex) => {
477
- return startIndex === null || endIndex === null ? [] : rangeExtractor({
478
- startIndex,
479
- endIndex,
480
- overscan,
481
- count
482
- });
483
- },
484
- {
485
- key: process.env.NODE_ENV !== "production" && "getVirtualIndexes",
486
- debug: () => this.options.debug
487
- }
488
- );
489
- this.indexFromElement = (node) => {
490
- const attributeName = this.options.indexAttribute;
491
- const indexStr = node.getAttribute(attributeName);
492
- if (!indexStr) {
493
- console.warn(
494
- `Missing attribute name '${attributeName}={index}' on measured element.`
495
- );
496
- return -1;
497
- }
498
- return parseInt(indexStr, 10);
499
- };
500
- this._measureElement = (node, entry) => {
501
- const index = this.indexFromElement(node);
502
- const item = this.measurementsCache[index];
503
- if (!item) {
504
- return;
505
- }
506
- const key = item.key;
507
- const prevNode = this.elementsCache.get(key);
508
- if (prevNode !== node) {
509
- if (prevNode) {
510
- this.observer.unobserve(prevNode);
511
- }
512
- this.observer.observe(node);
513
- this.elementsCache.set(key, node);
514
- }
515
- if (node.isConnected) {
516
- this.resizeItem(index, this.options.measureElement(node, entry, this));
517
- }
518
- };
519
- this.resizeItem = (index, size) => {
520
- const item = this.measurementsCache[index];
521
- if (!item) {
522
- return;
523
- }
524
- const itemSize = this.itemSizeCache.get(item.key) ?? item.size;
525
- const delta = size - itemSize;
526
- if (delta !== 0) {
527
- if (this.shouldAdjustScrollPositionOnItemSizeChange !== void 0 ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this) : item.start < this.getScrollOffset() + this.scrollAdjustments) {
528
- if (process.env.NODE_ENV !== "production" && this.options.debug) {
529
- console.info("correction", delta);
530
- }
531
- this._scrollToOffset(this.getScrollOffset(), {
532
- adjustments: this.scrollAdjustments += delta,
533
- behavior: void 0
534
- });
535
- }
536
- this.pendingMeasuredCacheIndexes.push(item.index);
537
- this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size));
538
- this.notify(false);
539
- }
540
- };
541
- this.measureElement = (node) => {
542
- if (!node) {
543
- this.elementsCache.forEach((cached, key) => {
544
- if (!cached.isConnected) {
545
- this.observer.unobserve(cached);
546
- this.elementsCache.delete(key);
547
- }
548
- });
549
- return;
550
- }
551
- this._measureElement(node, void 0);
552
- };
553
- this.getVirtualItems = utils.memo(
554
- () => [this.getVirtualIndexes(), this.getMeasurements()],
555
- (indexes, measurements) => {
556
- const virtualItems = [];
557
- for (let k = 0, len = indexes.length; k < len; k++) {
558
- const i = indexes[k];
559
- const measurement = measurements[i];
560
- virtualItems.push(measurement);
561
- }
562
- return virtualItems;
563
- },
564
- {
565
- key: process.env.NODE_ENV !== "production" && "getVirtualItems",
566
- debug: () => this.options.debug
567
- }
568
- );
569
- this.getVirtualItemForOffset = (offset) => {
570
- const measurements = this.getMeasurements();
571
- if (measurements.length === 0) {
572
- return void 0;
573
- }
574
- return utils.notUndefined(
575
- measurements[findNearestBinarySearch(
576
- 0,
577
- measurements.length - 1,
578
- (index) => utils.notUndefined(measurements[index]).start,
579
- offset
580
- )]
581
- );
582
- };
583
- this.getMaxScrollOffset = () => {
584
- if (!this.scrollElement) return 0;
585
- if ("scrollHeight" in this.scrollElement) {
586
- return this.options.horizontal ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth : this.scrollElement.scrollHeight - this.scrollElement.clientHeight;
587
- } else {
588
- const doc = this.scrollElement.document.documentElement;
589
- return this.options.horizontal ? doc.scrollWidth - this.scrollElement.innerWidth : doc.scrollHeight - this.scrollElement.innerHeight;
590
- }
591
- };
592
- this.getOffsetForAlignment = (toOffset, align, itemSize = 0) => {
593
- if (!this.scrollElement) return 0;
594
- const size = this.getSize();
595
- const scrollOffset = this.getScrollOffset();
596
- if (align === "auto") {
597
- align = toOffset >= scrollOffset + size ? "end" : "start";
598
- }
599
- if (align === "center") {
600
- toOffset += (itemSize - size) / 2;
601
- } else if (align === "end") {
602
- toOffset -= size;
603
- }
604
- const maxOffset = this.getMaxScrollOffset();
605
- return Math.max(Math.min(maxOffset, toOffset), 0);
606
- };
607
- this.getOffsetForIndex = (index, align = "auto") => {
608
- index = Math.max(0, Math.min(index, this.options.count - 1));
609
- const item = this.measurementsCache[index];
610
- if (!item) {
611
- return void 0;
612
- }
613
- const size = this.getSize();
614
- const scrollOffset = this.getScrollOffset();
615
- if (align === "auto") {
616
- if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {
617
- align = "end";
618
- } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {
619
- align = "start";
620
- } else {
621
- return [scrollOffset, align];
622
- }
623
- }
624
- if (align === "end" && index === this.options.count - 1) {
625
- return [this.getMaxScrollOffset(), align];
626
- }
627
- const toOffset = align === "end" ? item.end + this.options.scrollPaddingEnd : item.start - this.options.scrollPaddingStart;
628
- return [
629
- this.getOffsetForAlignment(toOffset, align, item.size),
630
- align
631
- ];
632
- };
633
- this.isDynamicMode = () => this.elementsCache.size > 0;
634
- this.scrollToOffset = (toOffset, { align = "start", behavior } = {}) => {
635
- if (behavior === "smooth" && this.isDynamicMode()) {
636
- console.warn(
637
- "The `smooth` scroll behavior is not fully supported with dynamic size."
638
- );
639
- }
640
- this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {
641
- adjustments: void 0,
642
- behavior
643
- });
644
- };
645
- this.scrollToIndex = (index, { align: initialAlign = "auto", behavior } = {}) => {
646
- if (behavior === "smooth" && this.isDynamicMode()) {
647
- console.warn(
648
- "The `smooth` scroll behavior is not fully supported with dynamic size."
649
- );
650
- }
651
- index = Math.max(0, Math.min(index, this.options.count - 1));
652
- this.currentScrollToIndex = index;
653
- let attempts = 0;
654
- const maxAttempts = 10;
655
- const tryScroll = (currentAlign) => {
656
- if (!this.targetWindow) return;
657
- const offsetInfo = this.getOffsetForIndex(index, currentAlign);
658
- if (!offsetInfo) {
659
- console.warn("Failed to get offset for index:", index);
660
- return;
661
- }
662
- const [offset, align] = offsetInfo;
663
- this._scrollToOffset(offset, { adjustments: void 0, behavior });
664
- this.targetWindow.requestAnimationFrame(() => {
665
- const verify = () => {
666
- if (this.currentScrollToIndex !== index) return;
667
- const currentOffset = this.getScrollOffset();
668
- const afterInfo = this.getOffsetForIndex(index, align);
669
- if (!afterInfo) {
670
- console.warn("Failed to get offset for index:", index);
671
- return;
672
- }
673
- if (!utils.approxEqual(afterInfo[0], currentOffset)) {
674
- scheduleRetry(align);
675
- }
676
- };
677
- if (this.isDynamicMode()) {
678
- this.targetWindow.requestAnimationFrame(verify);
679
- } else {
680
- verify();
681
- }
682
- });
683
- };
684
- const scheduleRetry = (align) => {
685
- if (!this.targetWindow) return;
686
- if (this.currentScrollToIndex !== index) return;
687
- attempts++;
688
- if (attempts < maxAttempts) {
689
- if (process.env.NODE_ENV !== "production" && this.options.debug) {
690
- console.info("Schedule retry", attempts, maxAttempts);
691
- }
692
- this.targetWindow.requestAnimationFrame(() => tryScroll(align));
693
- } else {
694
- console.warn(
695
- `Failed to scroll to index ${index} after ${maxAttempts} attempts.`
696
- );
697
- }
698
- };
699
- tryScroll(initialAlign);
700
- };
701
- this.scrollBy = (delta, { behavior } = {}) => {
702
- if (behavior === "smooth" && this.isDynamicMode()) {
703
- console.warn(
704
- "The `smooth` scroll behavior is not fully supported with dynamic size."
705
- );
706
- }
707
- this._scrollToOffset(this.getScrollOffset() + delta, {
708
- adjustments: void 0,
709
- behavior
710
- });
711
- };
712
- this.getTotalSize = () => {
713
- var _a;
714
- const measurements = this.getMeasurements();
715
- let end;
716
- if (measurements.length === 0) {
717
- end = this.options.paddingStart;
718
- } else if (this.options.lanes === 1) {
719
- end = ((_a = measurements[measurements.length - 1]) == null ? void 0 : _a.end) ?? 0;
720
- } else {
721
- const endByLane = Array(this.options.lanes).fill(null);
722
- let endIndex = measurements.length - 1;
723
- while (endIndex >= 0 && endByLane.some((val) => val === null)) {
724
- const item = measurements[endIndex];
725
- if (endByLane[item.lane] === null) {
726
- endByLane[item.lane] = item.end;
727
- }
728
- endIndex--;
729
- }
730
- end = Math.max(...endByLane.filter((val) => val !== null));
731
- }
732
- return Math.max(
733
- end - this.options.scrollMargin + this.options.paddingEnd,
734
- 0
735
- );
736
- };
737
- this._scrollToOffset = (offset, {
738
- adjustments,
739
- behavior
740
- }) => {
741
- this.options.scrollToFn(offset, { behavior, adjustments }, this);
742
- };
743
- this.measure = () => {
744
- this.itemSizeCache = /* @__PURE__ */ new Map();
745
- this.laneAssignments = /* @__PURE__ */ new Map();
746
- this.notify(false);
747
- };
748
- this.setOptions(opts);
749
- }
750
- }
751
- const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
752
- while (low <= high) {
753
- const middle = (low + high) / 2 | 0;
754
- const currentValue = getCurrentValue(middle);
755
- if (currentValue < value) {
756
- low = middle + 1;
757
- } else if (currentValue > value) {
758
- high = middle - 1;
759
- } else {
760
- return middle;
761
- }
762
- }
763
- if (low > 0) {
764
- return low - 1;
765
- } else {
766
- return 0;
767
- }
768
- };
769
- function calculateRange({
770
- measurements,
771
- outerSize,
772
- scrollOffset,
773
- lanes
774
- }) {
775
- const lastIndex = measurements.length - 1;
776
- const getOffset = (index) => measurements[index].start;
777
- if (measurements.length <= lanes) {
778
- return {
779
- startIndex: 0,
780
- endIndex: lastIndex
781
- };
782
- }
783
- let startIndex = findNearestBinarySearch(
784
- 0,
785
- lastIndex,
786
- getOffset,
787
- scrollOffset
788
- );
789
- let endIndex = startIndex;
790
- if (lanes === 1) {
791
- while (endIndex < lastIndex && measurements[endIndex].end < scrollOffset + outerSize) {
792
- endIndex++;
793
- }
794
- } else if (lanes > 1) {
795
- const endPerLane = Array(lanes).fill(0);
796
- while (endIndex < lastIndex && endPerLane.some((pos) => pos < scrollOffset + outerSize)) {
797
- const item = measurements[endIndex];
798
- endPerLane[item.lane] = item.end;
799
- endIndex++;
800
- }
801
- const startPerLane = Array(lanes).fill(scrollOffset + outerSize);
802
- while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {
803
- const item = measurements[startIndex];
804
- startPerLane[item.lane] = item.start;
805
- startIndex--;
806
- }
807
- startIndex = Math.max(0, startIndex - startIndex % lanes);
808
- endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - endIndex % lanes));
809
- }
810
- return { startIndex, endIndex };
811
- }
812
- exports.approxEqual = utils.approxEqual;
813
- exports.debounce = utils.debounce;
814
- exports.memo = utils.memo;
815
- exports.notUndefined = utils.notUndefined;
816
- exports.Virtualizer = Virtualizer;
817
- exports.defaultKeyExtractor = defaultKeyExtractor;
818
- exports.defaultRangeExtractor = defaultRangeExtractor;
819
- exports.elementScroll = elementScroll;
820
- exports.measureElement = measureElement;
821
- exports.observeElementOffset = observeElementOffset;
822
- exports.observeElementRect = observeElementRect;