@tanstack/virtual-core 3.3.0 → 3.5.0

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.
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { memo, notUndefined, approxEqual } from "./utils.js";
1
+ import { debounce, memo, notUndefined, approxEqual } from "./utils.js";
2
2
  const defaultKeyExtractor = (index) => index;
3
3
  const defaultRangeExtractor = (range) => {
4
4
  const start = Math.max(range.startIndex - range.overscan, 0);
@@ -39,6 +39,9 @@ const observeElementRect = (instance, cb) => {
39
39
  observer.unobserve(element);
40
40
  };
41
41
  };
42
+ const addEventListenerOptions = {
43
+ passive: true
44
+ };
42
45
  const observeWindowRect = (instance, cb) => {
43
46
  const element = instance.scrollElement;
44
47
  if (!element) {
@@ -48,27 +51,34 @@ const observeWindowRect = (instance, cb) => {
48
51
  cb({ width: element.innerWidth, height: element.innerHeight });
49
52
  };
50
53
  handler();
51
- element.addEventListener("resize", handler, {
52
- passive: true
53
- });
54
+ element.addEventListener("resize", handler, addEventListenerOptions);
54
55
  return () => {
55
56
  element.removeEventListener("resize", handler);
56
57
  };
57
58
  };
59
+ const supportsScrollend = typeof window == "undefined" ? true : "onscrollend" in window;
58
60
  const observeElementOffset = (instance, cb) => {
59
61
  const element = instance.scrollElement;
60
62
  if (!element) {
61
63
  return;
62
64
  }
63
- const handler = () => {
64
- cb(element[instance.options.horizontal ? "scrollLeft" : "scrollTop"]);
65
+ let offset = 0;
66
+ const fallback = supportsScrollend ? () => void 0 : debounce(() => {
67
+ cb(offset, false);
68
+ }, instance.options.isScrollingResetDelay);
69
+ const createHandler = (isScrolling) => () => {
70
+ offset = element[instance.options.horizontal ? "scrollLeft" : "scrollTop"];
71
+ fallback();
72
+ cb(offset, isScrolling);
65
73
  };
66
- handler();
67
- element.addEventListener("scroll", handler, {
68
- passive: true
69
- });
74
+ const handler = createHandler(true);
75
+ const endHandler = createHandler(false);
76
+ endHandler();
77
+ element.addEventListener("scroll", handler, addEventListenerOptions);
78
+ element.addEventListener("scrollend", endHandler, addEventListenerOptions);
70
79
  return () => {
71
80
  element.removeEventListener("scroll", handler);
81
+ element.removeEventListener("scrollend", endHandler);
72
82
  };
73
83
  };
74
84
  const observeWindowOffset = (instance, cb) => {
@@ -76,15 +86,23 @@ const observeWindowOffset = (instance, cb) => {
76
86
  if (!element) {
77
87
  return;
78
88
  }
79
- const handler = () => {
80
- cb(element[instance.options.horizontal ? "scrollX" : "scrollY"]);
89
+ let offset = 0;
90
+ const fallback = supportsScrollend ? () => void 0 : debounce(() => {
91
+ cb(offset, false);
92
+ }, instance.options.isScrollingResetDelay);
93
+ const createHandler = (isScrolling) => () => {
94
+ offset = element[instance.options.horizontal ? "scrollX" : "scrollY"];
95
+ fallback();
96
+ cb(offset, isScrolling);
81
97
  };
82
- handler();
83
- element.addEventListener("scroll", handler, {
84
- passive: true
85
- });
98
+ const handler = createHandler(true);
99
+ const endHandler = createHandler(false);
100
+ endHandler();
101
+ element.addEventListener("scroll", handler, addEventListenerOptions);
102
+ element.addEventListener("scrollend", endHandler, addEventListenerOptions);
86
103
  return () => {
87
104
  element.removeEventListener("scroll", handler);
105
+ element.removeEventListener("scrollend", endHandler);
88
106
  };
89
107
  };
90
108
  const measureElement = (element, entry, instance) => {
@@ -128,7 +146,6 @@ class Virtualizer {
128
146
  this.unsubs = [];
129
147
  this.scrollElement = null;
130
148
  this.isScrolling = false;
131
- this.isScrollingTimeoutId = null;
132
149
  this.scrollToIndexTimeoutId = null;
133
150
  this.measurementsCache = [];
134
151
  this.itemSizeCache = /* @__PURE__ */ new Map();
@@ -189,39 +206,24 @@ class Virtualizer {
189
206
  initialRect: { width: 0, height: 0 },
190
207
  scrollMargin: 0,
191
208
  gap: 0,
192
- scrollingDelay: 150,
193
209
  indexAttribute: "data-index",
194
210
  initialMeasurementsCache: [],
195
211
  lanes: 1,
212
+ isScrollingResetDelay: 150,
196
213
  ...opts2
197
214
  };
198
215
  };
199
- this.notify = (sync) => {
216
+ this.notify = (force, sync) => {
200
217
  var _a, _b;
201
- (_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a, this, sync);
202
- };
203
- this.maybeNotify = memo(
204
- () => {
205
- this.calculateRange();
206
- return [
207
- this.isScrolling,
208
- this.range ? this.range.startIndex : null,
209
- this.range ? this.range.endIndex : null
210
- ];
211
- },
212
- (isScrolling) => {
213
- this.notify(isScrolling);
214
- },
215
- {
216
- key: process.env.NODE_ENV !== "production" && "maybeNotify",
217
- debug: () => this.options.debug,
218
- initialDeps: [
219
- this.isScrolling,
220
- this.range ? this.range.startIndex : null,
221
- this.range ? this.range.endIndex : null
222
- ]
218
+ const { startIndex, endIndex } = this.range ?? {
219
+ startIndex: void 0,
220
+ endIndex: void 0
221
+ };
222
+ const range = this.calculateRange();
223
+ if (force || startIndex !== (range == null ? void 0 : range.startIndex) || endIndex !== (range == null ? void 0 : range.endIndex)) {
224
+ (_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a, this, sync);
223
225
  }
224
- );
226
+ };
225
227
  this.cleanup = () => {
226
228
  this.unsubs.filter(Boolean).forEach((d) => d());
227
229
  this.unsubs = [];
@@ -246,29 +248,17 @@ class Virtualizer {
246
248
  this.unsubs.push(
247
249
  this.options.observeElementRect(this, (rect) => {
248
250
  this.scrollRect = rect;
249
- this.maybeNotify();
251
+ this.notify(false, false);
250
252
  })
251
253
  );
252
254
  this.unsubs.push(
253
- this.options.observeElementOffset(this, (offset) => {
255
+ this.options.observeElementOffset(this, (offset, isScrolling) => {
254
256
  this.scrollAdjustments = 0;
255
- if (this.scrollOffset === offset) {
256
- return;
257
- }
258
- if (this.isScrollingTimeoutId !== null) {
259
- clearTimeout(this.isScrollingTimeoutId);
260
- this.isScrollingTimeoutId = null;
261
- }
262
- this.isScrolling = true;
263
- this.scrollDirection = this.scrollOffset < offset ? "forward" : "backward";
257
+ this.scrollDirection = isScrolling ? this.scrollOffset < offset ? "forward" : "backward" : null;
264
258
  this.scrollOffset = offset;
265
- this.maybeNotify();
266
- this.isScrollingTimeoutId = setTimeout(() => {
267
- this.isScrollingTimeoutId = null;
268
- this.isScrolling = false;
269
- this.scrollDirection = null;
270
- this.maybeNotify();
271
- }, this.options.scrollingDelay);
259
+ const prevIsScrolling = this.isScrolling;
260
+ this.isScrolling = isScrolling;
261
+ this.notify(prevIsScrolling !== isScrolling, isScrolling);
272
262
  })
273
263
  );
274
264
  }
@@ -276,7 +266,7 @@ class Virtualizer {
276
266
  this.getSize = () => {
277
267
  return this.scrollRect[this.options.horizontal ? "width" : "height"];
278
268
  };
279
- this.memoOptions = memo(
269
+ this.getMeasurementOptions = memo(
280
270
  () => [
281
271
  this.options.count,
282
272
  this.options.paddingStart,
@@ -324,7 +314,7 @@ class Virtualizer {
324
314
  })[0] : void 0;
325
315
  };
326
316
  this.getMeasurements = memo(
327
- () => [this.memoOptions(), this.itemSizeCache],
317
+ () => [this.getMeasurementOptions(), this.itemSizeCache],
328
318
  ({ count, paddingStart, scrollMargin, getItemKey }, itemSizeCache) => {
329
319
  const min = this.pendingMeasuredCacheIndexes.length > 0 ? Math.min(...this.pendingMeasuredCacheIndexes) : 0;
330
320
  this.pendingMeasuredCacheIndexes = [];
@@ -377,7 +367,8 @@ class Virtualizer {
377
367
  ],
378
368
  (rangeExtractor, range, overscan, count) => {
379
369
  return range === null ? [] : rangeExtractor({
380
- ...range,
370
+ startIndex: range.startIndex,
371
+ endIndex: range.endIndex,
381
372
  overscan,
382
373
  count
383
374
  });
@@ -435,7 +426,7 @@ class Virtualizer {
435
426
  }
436
427
  this.pendingMeasuredCacheIndexes.push(item.index);
437
428
  this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size));
438
- this.notify(false);
429
+ this.notify(true, false);
439
430
  }
440
431
  };
441
432
  this.measureElement = (node) => {
@@ -587,8 +578,9 @@ class Virtualizer {
587
578
  this.options.scrollToFn(offset, { behavior, adjustments }, this);
588
579
  };
589
580
  this.measure = () => {
581
+ var _a, _b;
590
582
  this.itemSizeCache = /* @__PURE__ */ new Map();
591
- this.notify(false);
583
+ (_b = (_a = this.options).onChange) == null ? void 0 : _b.call(_a, this, false);
592
584
  };
593
585
  this.setOptions(opts);
594
586
  this.scrollRect = this.options.initialRect;
@@ -597,7 +589,7 @@ class Virtualizer {
597
589
  this.measurementsCache.forEach((item) => {
598
590
  this.itemSizeCache.set(item.key, item.size);
599
591
  });
600
- this.maybeNotify();
592
+ this.notify(false, false);
601
593
  }
602
594
  }
603
595
  const findNearestBinarySearch = (low, high, getCurrentValue, value) => {
@@ -635,6 +627,7 @@ function calculateRange({
635
627
  export {
636
628
  Virtualizer,
637
629
  approxEqual,
630
+ debounce,
638
631
  defaultKeyExtractor,
639
632
  defaultRangeExtractor,
640
633
  elementScroll,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { approxEqual, memo, notUndefined } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollDirection = 'forward' | 'backward'\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ntype ScrollBehavior = 'auto' | 'smooth'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n behavior?: ScrollBehavior\n}\n\ntype ScrollToOffsetOptions = ScrollToOptions\n\ntype ScrollToIndexOptions = ScrollToOptions\n\nexport interface Range {\n startIndex: number\n endIndex: number\n overscan: number\n count: number\n}\n\ntype Key = number | string\n\nexport interface VirtualItem {\n key: Key\n index: number\n start: number\n end: number\n size: number\n lane: number\n}\n\nexport interface Rect {\n width: number\n height: number\n}\n\n//\n\nexport const defaultKeyExtractor = (index: number) => index\n\nexport const defaultRangeExtractor = (range: Range) => {\n const start = Math.max(range.startIndex - range.overscan, 0)\n const end = Math.min(range.endIndex + range.overscan, range.count - 1)\n\n const arr = []\n\n for (let i = start; i <= end; i++) {\n arr.push(i)\n }\n\n return arr\n}\n\nexport const observeElementRect = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = (rect: Rect) => {\n const { width, height } = rect\n cb({ width: Math.round(width), height: Math.round(height) })\n }\n\n handler(element.getBoundingClientRect())\n\n if (typeof ResizeObserver === 'undefined') {\n return () => {}\n }\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n handler({ width: box.inlineSize, height: box.blockSize })\n return\n }\n }\n handler(element.getBoundingClientRect())\n })\n\n observer.observe(element, { box: 'border-box' })\n\n return () => {\n observer.unobserve(element)\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<Window, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight })\n }\n handler()\n\n element.addEventListener('resize', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('resize', handler)\n }\n}\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollX' : 'scrollY'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const measureElement = <TItemElement extends Element>(\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer<any, TItemElement>,\n) => {\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n const size = Math.round(\n box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],\n )\n return size\n }\n }\n return Math.round(\n element.getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ],\n )\n}\n\nexport const windowScroll = <T extends Window>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport const elementScroll = <T extends Element>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement | null\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n options: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => void\n observeElementRect: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (offset: number) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n sync: boolean,\n ) => void\n measureElement?: (\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => number\n overscan?: number\n horizontal?: boolean\n paddingStart?: number\n paddingEnd?: number\n scrollPaddingStart?: number\n scrollPaddingEnd?: number\n initialOffset?: number | (() => number)\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => number[]\n scrollMargin?: number\n gap?: number\n scrollingDelay?: number\n indexAttribute?: string\n initialMeasurementsCache?: VirtualItem[]\n lanes?: number\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: (void | (() => void))[] = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n isScrolling: boolean = false\n private isScrollingTimeoutId: ReturnType<typeof setTimeout> | null = null\n private scrollToIndexTimeoutId: ReturnType<typeof setTimeout> | null = null\n measurementsCache: VirtualItem[] = []\n private itemSizeCache = new Map<Key, number>()\n private pendingMeasuredCacheIndexes: number[] = []\n scrollRect: Rect\n scrollOffset: number\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments: number = 0\n shouldAdjustScrollPositionOnItemSizeChange:\n | undefined\n | ((\n item: VirtualItem,\n delta: number,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => boolean)\n measureElementCache = new Map<Key, TItemElement>()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n } else if (typeof ResizeObserver !== 'undefined') {\n return (_ro = new ResizeObserver((entries) => {\n entries.forEach((entry) => {\n this._measureElement(entry.target as TItemElement, entry)\n })\n }))\n } else {\n return null\n }\n }\n\n return {\n disconnect: () => get()?.disconnect(),\n observe: (target: Element) =>\n get()?.observe(target, { box: 'border-box' }),\n unobserve: (target: Element) => get()?.unobserve(target),\n }\n })()\n range: { startIndex: number; endIndex: number } | null = null\n\n constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {\n this.setOptions(opts)\n this.scrollRect = this.options.initialRect\n this.scrollOffset =\n typeof this.options.initialOffset === 'function'\n ? this.options.initialOffset()\n : this.options.initialOffset\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n\n this.maybeNotify()\n }\n\n setOptions = (opts: VirtualizerOptions<TScrollElement, TItemElement>) => {\n Object.entries(opts).forEach(([key, value]) => {\n if (typeof value === 'undefined') delete (opts as any)[key]\n })\n\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n gap: 0,\n scrollingDelay: 150,\n indexAttribute: 'data-index',\n initialMeasurementsCache: [],\n lanes: 1,\n ...opts,\n }\n }\n\n private notify = (sync: boolean) => {\n this.options.onChange?.(this, sync)\n }\n\n private maybeNotify = memo(\n () => {\n this.calculateRange()\n\n return [\n this.isScrolling,\n this.range ? this.range.startIndex : null,\n this.range ? this.range.endIndex : null,\n ]\n },\n (isScrolling) => {\n this.notify(isScrolling)\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'maybeNotify',\n debug: () => this.options.debug,\n initialDeps: [\n this.isScrolling,\n this.range ? this.range.startIndex : null,\n this.range ? this.range.endIndex : null,\n ] as [boolean, number | null, number | null],\n },\n )\n\n private cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d!())\n this.unsubs = []\n this.scrollElement = null\n }\n\n _didMount = () => {\n this.measureElementCache.forEach(this.observer.observe)\n return () => {\n this.observer.disconnect()\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.getScrollElement()\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n this.scrollElement = scrollElement\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: undefined,\n behavior: undefined,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect\n this.maybeNotify()\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n this.scrollAdjustments = 0\n\n if (this.scrollOffset === offset) {\n return\n }\n\n if (this.isScrollingTimeoutId !== null) {\n clearTimeout(this.isScrollingTimeoutId)\n this.isScrollingTimeoutId = null\n }\n\n this.isScrolling = true\n this.scrollDirection =\n this.scrollOffset < offset ? 'forward' : 'backward'\n this.scrollOffset = offset\n\n this.maybeNotify()\n\n this.isScrollingTimeoutId = setTimeout(() => {\n this.isScrollingTimeoutId = null\n this.isScrolling = false\n this.scrollDirection = null\n\n this.maybeNotify()\n }, this.options.scrollingDelay)\n }),\n )\n }\n }\n\n private getSize = () => {\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private memoOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n ],\n (count, paddingStart, scrollMargin, getItemKey) => {\n this.pendingMeasuredCacheIndexes = []\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n }\n },\n {\n key: false,\n },\n )\n\n private getFurthestMeasurement = (\n measurements: VirtualItem[],\n index: number,\n ) => {\n const furthestMeasurementsFound = new Map<number, true>()\n const furthestMeasurements = new Map<number, VirtualItem>()\n for (let m = index - 1; m >= 0; m--) {\n const measurement = measurements[m]!\n\n if (furthestMeasurementsFound.has(measurement.lane)) {\n continue\n }\n\n const previousFurthestMeasurement = furthestMeasurements.get(\n measurement.lane,\n )\n if (\n previousFurthestMeasurement == null ||\n measurement.end > previousFurthestMeasurement.end\n ) {\n furthestMeasurements.set(measurement.lane, measurement)\n } else if (measurement.end < previousFurthestMeasurement.end) {\n furthestMeasurementsFound.set(measurement.lane, true)\n }\n\n if (furthestMeasurementsFound.size === this.options.lanes) {\n break\n }\n }\n\n return furthestMeasurements.size === this.options.lanes\n ? Array.from(furthestMeasurements.values()).sort((a, b) => {\n if (a.end === b.end) {\n return a.index - b.index\n }\n\n return a.end - b.end\n })[0]\n : undefined\n }\n\n private getMeasurements = memo(\n () => [this.memoOptions(), this.itemSizeCache],\n ({ count, paddingStart, scrollMargin, getItemKey }, itemSizeCache) => {\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n\n const furthestMeasurement =\n this.options.lanes === 1\n ? measurements[i - 1]\n : this.getFurthestMeasurement(measurements, i)\n\n const start = furthestMeasurement\n ? furthestMeasurement.end + this.options.gap\n : paddingStart + scrollMargin\n\n const measuredSize = itemSizeCache.get(key)\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n\n const end = start + size\n\n const lane = furthestMeasurement\n ? furthestMeasurement.lane\n : i % this.options.lanes\n\n measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane,\n }\n }\n\n this.measurementsCache = measurements\n\n return measurements\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.scrollOffset],\n (measurements, outerSize, scrollOffset) => {\n return (this.range =\n measurements.length > 0 && outerSize > 0\n ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n })\n : null)\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.calculateRange(),\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return range === null\n ? []\n : rangeExtractor({\n ...range,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n indexFromElement = (node: TItemElement) => {\n const attributeName = this.options.indexAttribute\n const indexStr = node.getAttribute(attributeName)\n\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`,\n )\n return -1\n }\n\n return parseInt(indexStr, 10)\n }\n\n private _measureElement = (\n node: TItemElement,\n entry: ResizeObserverEntry | undefined,\n ) => {\n const item = this.measurementsCache[this.indexFromElement(node)]\n\n if (!item || !node.isConnected) {\n this.measureElementCache.forEach((cached, key) => {\n if (cached === node) {\n this.observer.unobserve(node)\n this.measureElementCache.delete(key)\n }\n })\n return\n }\n\n const prevNode = this.measureElementCache.get(item.key)\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.measureElementCache.set(item.key, node)\n }\n\n const measuredItemSize = this.options.measureElement(node, entry, this)\n\n this.resizeItem(item, measuredItemSize)\n }\n\n resizeItem = (item: VirtualItem, size: number) => {\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n const delta = size - itemSize\n\n if (delta !== 0) {\n if (\n this.shouldAdjustScrollPositionOnItemSizeChange !== undefined\n ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this)\n : item.start < this.scrollOffset + this.scrollAdjustments\n ) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: (this.scrollAdjustments += delta),\n behavior: undefined,\n })\n }\n\n this.pendingMeasuredCacheIndexes.push(item.index)\n this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size))\n\n this.notify(false)\n }\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n return\n }\n\n this._measureElement(node, undefined)\n }\n\n getVirtualItems = memo(\n () => [this.getIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: VirtualItem[] = []\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n virtualItems.push(measurement)\n }\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n\n return notUndefined(\n measurements[\n findNearestBinarySearch(\n 0,\n measurements.length - 1,\n (index: number) => notUndefined(measurements[index]).start,\n offset,\n )\n ],\n )\n }\n\n getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= this.scrollOffset) {\n align = 'start'\n } else if (toOffset >= this.scrollOffset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n toOffset = toOffset\n } else if (align === 'end') {\n toOffset = toOffset - size\n } else if (align === 'center') {\n toOffset = toOffset - size / 2\n }\n\n const scrollSizeProp = this.options.horizontal\n ? 'scrollWidth'\n : 'scrollHeight'\n const scrollSize = this.scrollElement\n ? 'document' in this.scrollElement\n ? this.scrollElement.document.documentElement[scrollSizeProp]\n : this.scrollElement[scrollSizeProp]\n : 0\n\n const maxOffset = scrollSize - this.getSize()\n\n return Math.max(Math.min(maxOffset, toOffset), 0)\n }\n\n getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const measurement = notUndefined(this.getMeasurements()[index])\n\n if (align === 'auto') {\n if (\n measurement.end >=\n this.scrollOffset + this.getSize() - this.options.scrollPaddingEnd\n ) {\n align = 'end'\n } else if (\n measurement.start <=\n this.scrollOffset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return [this.scrollOffset, align] as const\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n return [this.getOffsetForAlignment(toOffset, align), align] as const\n }\n\n private isDynamicMode = () => this.measureElementCache.size > 0\n\n private cancelScrollToIndex = () => {\n if (this.scrollToIndexTimeoutId !== null) {\n clearTimeout(this.scrollToIndexTimeoutId)\n this.scrollToIndexTimeoutId = null\n }\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior }: ScrollToOffsetOptions = {},\n ) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {\n adjustments: undefined,\n behavior,\n })\n }\n\n scrollToIndex = (\n index: number,\n { align: initialAlign = 'auto', behavior }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n const [toOffset, align] = this.getOffsetForIndex(index, initialAlign)\n\n this._scrollToOffset(toOffset, { adjustments: undefined, behavior })\n\n if (behavior !== 'smooth' && this.isDynamicMode()) {\n this.scrollToIndexTimeoutId = setTimeout(() => {\n this.scrollToIndexTimeoutId = null\n\n const elementInDOM = this.measureElementCache.has(\n this.options.getItemKey(index),\n )\n\n if (elementInDOM) {\n const [toOffset] = this.getOffsetForIndex(index, align)\n\n if (!approxEqual(toOffset, this.scrollOffset)) {\n this.scrollToIndex(index, { align, behavior })\n }\n } else {\n this.scrollToIndex(index, { align, behavior })\n }\n })\n }\n }\n\n scrollBy = (delta: number, { behavior }: ScrollToOffsetOptions = {}) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.scrollOffset + delta, {\n adjustments: undefined,\n behavior,\n })\n }\n\n getTotalSize = () => {\n const measurements = this.getMeasurements()\n\n let end: number\n // If there are no measurements, set the end to paddingStart\n if (measurements.length === 0) {\n end = this.options.paddingStart\n } else {\n // If lanes is 1, use the last measurement's end, otherwise find the maximum end value among all measurements\n end =\n this.options.lanes === 1\n ? measurements[measurements.length - 1]?.end ?? 0\n : Math.max(\n ...measurements.slice(-this.options.lanes).map((m) => m.end),\n )\n }\n\n return end - this.options.scrollMargin + this.options.paddingEnd\n }\n\n private _scrollToOffset = (\n offset: number,\n {\n adjustments,\n behavior,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this)\n }\n\n measure = () => {\n this.itemSizeCache = new Map()\n this.notify(false)\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: VirtualItem[]\n outerSize: number\n scrollOffset: number\n}) {\n const count = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset)\n let endIndex = startIndex\n\n while (\n endIndex < count &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["opts","toOffset"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { approxEqual, memo, notUndefined, debounce } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollDirection = 'forward' | 'backward'\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ntype ScrollBehavior = 'auto' | 'smooth'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n behavior?: ScrollBehavior\n}\n\ntype ScrollToOffsetOptions = ScrollToOptions\n\ntype ScrollToIndexOptions = ScrollToOptions\n\nexport interface Range {\n startIndex: number\n endIndex: number\n overscan: number\n count: number\n}\n\ntype Key = number | string\n\nexport interface VirtualItem {\n key: Key\n index: number\n start: number\n end: number\n size: number\n lane: number\n}\n\nexport interface Rect {\n width: number\n height: number\n}\n\n//\n\nexport const defaultKeyExtractor = (index: number) => index\n\nexport const defaultRangeExtractor = (range: Range) => {\n const start = Math.max(range.startIndex - range.overscan, 0)\n const end = Math.min(range.endIndex + range.overscan, range.count - 1)\n\n const arr = []\n\n for (let i = start; i <= end; i++) {\n arr.push(i)\n }\n\n return arr\n}\n\nexport const observeElementRect = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = (rect: Rect) => {\n const { width, height } = rect\n cb({ width: Math.round(width), height: Math.round(height) })\n }\n\n handler(element.getBoundingClientRect())\n\n if (typeof ResizeObserver === 'undefined') {\n return () => {}\n }\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n handler({ width: box.inlineSize, height: box.blockSize })\n return\n }\n }\n handler(element.getBoundingClientRect())\n })\n\n observer.observe(element, { box: 'border-box' })\n\n return () => {\n observer.unobserve(element)\n }\n}\n\nconst addEventListenerOptions = {\n passive: true,\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<Window, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight })\n }\n handler()\n\n element.addEventListener('resize', handler, addEventListenerOptions)\n\n return () => {\n element.removeEventListener('resize', handler)\n }\n}\n\nconst supportsScrollend =\n typeof window == 'undefined' ? true : 'onscrollend' in window\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (offset: number, isScrolling: boolean) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n let offset = 0\n const fallback = supportsScrollend\n ? () => undefined\n : debounce(() => {\n cb(offset, false)\n }, instance.options.isScrollingResetDelay)\n\n const createHandler = (isScrolling: boolean) => () => {\n offset = element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop']\n fallback()\n cb(offset, isScrolling)\n }\n const handler = createHandler(true)\n const endHandler = createHandler(false)\n endHandler()\n\n element.addEventListener('scroll', handler, addEventListenerOptions)\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n\n return () => {\n element.removeEventListener('scroll', handler)\n element.removeEventListener('scrollend', endHandler)\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: (offset: number, isScrolling: boolean) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n let offset = 0\n const fallback = supportsScrollend\n ? () => undefined\n : debounce(() => {\n cb(offset, false)\n }, instance.options.isScrollingResetDelay)\n\n const createHandler = (isScrolling: boolean) => () => {\n offset = element[instance.options.horizontal ? 'scrollX' : 'scrollY']\n fallback()\n cb(offset, isScrolling)\n }\n const handler = createHandler(true)\n const endHandler = createHandler(false)\n endHandler()\n\n element.addEventListener('scroll', handler, addEventListenerOptions)\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n\n return () => {\n element.removeEventListener('scroll', handler)\n element.removeEventListener('scrollend', endHandler)\n }\n}\n\nexport const measureElement = <TItemElement extends Element>(\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer<any, TItemElement>,\n) => {\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n const size = Math.round(\n box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],\n )\n return size\n }\n }\n return Math.round(\n element.getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ],\n )\n}\n\nexport const windowScroll = <T extends Window>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport const elementScroll = <T extends Element>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement | null\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n options: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => void\n observeElementRect: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (offset: number, isScrolling: boolean) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n sync: boolean,\n ) => void\n measureElement?: (\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => number\n overscan?: number\n horizontal?: boolean\n paddingStart?: number\n paddingEnd?: number\n scrollPaddingStart?: number\n scrollPaddingEnd?: number\n initialOffset?: number | (() => number)\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => number[]\n scrollMargin?: number\n gap?: number\n indexAttribute?: string\n initialMeasurementsCache?: VirtualItem[]\n lanes?: number\n isScrollingResetDelay?: number\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: (void | (() => void))[] = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n isScrolling: boolean = false\n private scrollToIndexTimeoutId: ReturnType<typeof setTimeout> | null = null\n measurementsCache: VirtualItem[] = []\n private itemSizeCache = new Map<Key, number>()\n private pendingMeasuredCacheIndexes: number[] = []\n scrollRect: Rect\n scrollOffset: number\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments: number = 0\n shouldAdjustScrollPositionOnItemSizeChange:\n | undefined\n | ((\n item: VirtualItem,\n delta: number,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => boolean)\n measureElementCache = new Map<Key, TItemElement>()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n } else if (typeof ResizeObserver !== 'undefined') {\n return (_ro = new ResizeObserver((entries) => {\n entries.forEach((entry) => {\n this._measureElement(entry.target as TItemElement, entry)\n })\n }))\n } else {\n return null\n }\n }\n\n return {\n disconnect: () => get()?.disconnect(),\n observe: (target: Element) =>\n get()?.observe(target, { box: 'border-box' }),\n unobserve: (target: Element) => get()?.unobserve(target),\n }\n })()\n range: { startIndex: number; endIndex: number } | null = null\n\n constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {\n this.setOptions(opts)\n this.scrollRect = this.options.initialRect\n this.scrollOffset =\n typeof this.options.initialOffset === 'function'\n ? this.options.initialOffset()\n : this.options.initialOffset\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n\n this.notify(false, false)\n }\n\n setOptions = (opts: VirtualizerOptions<TScrollElement, TItemElement>) => {\n Object.entries(opts).forEach(([key, value]) => {\n if (typeof value === 'undefined') delete (opts as any)[key]\n })\n\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n gap: 0,\n indexAttribute: 'data-index',\n initialMeasurementsCache: [],\n lanes: 1,\n isScrollingResetDelay: 150,\n ...opts,\n }\n }\n\n private notify = (force: boolean, sync: boolean) => {\n const { startIndex, endIndex } = this.range ?? {\n startIndex: undefined,\n endIndex: undefined,\n }\n const range = this.calculateRange()\n\n if (\n force ||\n startIndex !== range?.startIndex ||\n endIndex !== range?.endIndex\n ) {\n this.options.onChange?.(this, sync)\n }\n }\n\n private cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d!())\n this.unsubs = []\n this.scrollElement = null\n }\n\n _didMount = () => {\n this.measureElementCache.forEach(this.observer.observe)\n return () => {\n this.observer.disconnect()\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.getScrollElement()\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n this.scrollElement = scrollElement\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: undefined,\n behavior: undefined,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect\n this.notify(false, false)\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset, isScrolling) => {\n this.scrollAdjustments = 0\n this.scrollDirection = isScrolling\n ? this.scrollOffset < offset\n ? 'forward'\n : 'backward'\n : null\n this.scrollOffset = offset\n\n const prevIsScrolling = this.isScrolling\n this.isScrolling = isScrolling\n\n this.notify(prevIsScrolling !== isScrolling, isScrolling)\n }),\n )\n }\n }\n\n private getSize = () => {\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private getMeasurementOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n ],\n (count, paddingStart, scrollMargin, getItemKey) => {\n this.pendingMeasuredCacheIndexes = []\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n }\n },\n {\n key: false,\n },\n )\n\n private getFurthestMeasurement = (\n measurements: VirtualItem[],\n index: number,\n ) => {\n const furthestMeasurementsFound = new Map<number, true>()\n const furthestMeasurements = new Map<number, VirtualItem>()\n for (let m = index - 1; m >= 0; m--) {\n const measurement = measurements[m]!\n\n if (furthestMeasurementsFound.has(measurement.lane)) {\n continue\n }\n\n const previousFurthestMeasurement = furthestMeasurements.get(\n measurement.lane,\n )\n if (\n previousFurthestMeasurement == null ||\n measurement.end > previousFurthestMeasurement.end\n ) {\n furthestMeasurements.set(measurement.lane, measurement)\n } else if (measurement.end < previousFurthestMeasurement.end) {\n furthestMeasurementsFound.set(measurement.lane, true)\n }\n\n if (furthestMeasurementsFound.size === this.options.lanes) {\n break\n }\n }\n\n return furthestMeasurements.size === this.options.lanes\n ? Array.from(furthestMeasurements.values()).sort((a, b) => {\n if (a.end === b.end) {\n return a.index - b.index\n }\n\n return a.end - b.end\n })[0]\n : undefined\n }\n\n private getMeasurements = memo(\n () => [this.getMeasurementOptions(), this.itemSizeCache],\n ({ count, paddingStart, scrollMargin, getItemKey }, itemSizeCache) => {\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n\n const furthestMeasurement =\n this.options.lanes === 1\n ? measurements[i - 1]\n : this.getFurthestMeasurement(measurements, i)\n\n const start = furthestMeasurement\n ? furthestMeasurement.end + this.options.gap\n : paddingStart + scrollMargin\n\n const measuredSize = itemSizeCache.get(key)\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n\n const end = start + size\n\n const lane = furthestMeasurement\n ? furthestMeasurement.lane\n : i % this.options.lanes\n\n measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane,\n }\n }\n\n this.measurementsCache = measurements\n\n return measurements\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.scrollOffset],\n (measurements, outerSize, scrollOffset) => {\n return (this.range =\n measurements.length > 0 && outerSize > 0\n ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n })\n : null)\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.calculateRange(),\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return range === null\n ? []\n : rangeExtractor({\n startIndex: range.startIndex,\n endIndex: range.endIndex,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n indexFromElement = (node: TItemElement) => {\n const attributeName = this.options.indexAttribute\n const indexStr = node.getAttribute(attributeName)\n\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`,\n )\n return -1\n }\n\n return parseInt(indexStr, 10)\n }\n\n private _measureElement = (\n node: TItemElement,\n entry: ResizeObserverEntry | undefined,\n ) => {\n const item = this.measurementsCache[this.indexFromElement(node)]\n\n if (!item || !node.isConnected) {\n this.measureElementCache.forEach((cached, key) => {\n if (cached === node) {\n this.observer.unobserve(node)\n this.measureElementCache.delete(key)\n }\n })\n return\n }\n\n const prevNode = this.measureElementCache.get(item.key)\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.measureElementCache.set(item.key, node)\n }\n\n const measuredItemSize = this.options.measureElement(node, entry, this)\n\n this.resizeItem(item, measuredItemSize)\n }\n\n resizeItem = (item: VirtualItem, size: number) => {\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n const delta = size - itemSize\n\n if (delta !== 0) {\n if (\n this.shouldAdjustScrollPositionOnItemSizeChange !== undefined\n ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this)\n : item.start < this.scrollOffset + this.scrollAdjustments\n ) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: (this.scrollAdjustments += delta),\n behavior: undefined,\n })\n }\n\n this.pendingMeasuredCacheIndexes.push(item.index)\n this.itemSizeCache = new Map(this.itemSizeCache.set(item.key, size))\n\n this.notify(true, false)\n }\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n return\n }\n\n this._measureElement(node, undefined)\n }\n\n getVirtualItems = memo(\n () => [this.getIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: VirtualItem[] = []\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n virtualItems.push(measurement)\n }\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n\n return notUndefined(\n measurements[\n findNearestBinarySearch(\n 0,\n measurements.length - 1,\n (index: number) => notUndefined(measurements[index]).start,\n offset,\n )\n ],\n )\n }\n\n getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= this.scrollOffset) {\n align = 'start'\n } else if (toOffset >= this.scrollOffset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n toOffset = toOffset\n } else if (align === 'end') {\n toOffset = toOffset - size\n } else if (align === 'center') {\n toOffset = toOffset - size / 2\n }\n\n const scrollSizeProp = this.options.horizontal\n ? 'scrollWidth'\n : 'scrollHeight'\n const scrollSize = this.scrollElement\n ? 'document' in this.scrollElement\n ? this.scrollElement.document.documentElement[scrollSizeProp]\n : this.scrollElement[scrollSizeProp]\n : 0\n\n const maxOffset = scrollSize - this.getSize()\n\n return Math.max(Math.min(maxOffset, toOffset), 0)\n }\n\n getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const measurement = notUndefined(this.getMeasurements()[index])\n\n if (align === 'auto') {\n if (\n measurement.end >=\n this.scrollOffset + this.getSize() - this.options.scrollPaddingEnd\n ) {\n align = 'end'\n } else if (\n measurement.start <=\n this.scrollOffset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return [this.scrollOffset, align] as const\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n return [this.getOffsetForAlignment(toOffset, align), align] as const\n }\n\n private isDynamicMode = () => this.measureElementCache.size > 0\n\n private cancelScrollToIndex = () => {\n if (this.scrollToIndexTimeoutId !== null) {\n clearTimeout(this.scrollToIndexTimeoutId)\n this.scrollToIndexTimeoutId = null\n }\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior }: ScrollToOffsetOptions = {},\n ) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {\n adjustments: undefined,\n behavior,\n })\n }\n\n scrollToIndex = (\n index: number,\n { align: initialAlign = 'auto', behavior }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n const [toOffset, align] = this.getOffsetForIndex(index, initialAlign)\n\n this._scrollToOffset(toOffset, { adjustments: undefined, behavior })\n\n if (behavior !== 'smooth' && this.isDynamicMode()) {\n this.scrollToIndexTimeoutId = setTimeout(() => {\n this.scrollToIndexTimeoutId = null\n\n const elementInDOM = this.measureElementCache.has(\n this.options.getItemKey(index),\n )\n\n if (elementInDOM) {\n const [toOffset] = this.getOffsetForIndex(index, align)\n\n if (!approxEqual(toOffset, this.scrollOffset)) {\n this.scrollToIndex(index, { align, behavior })\n }\n } else {\n this.scrollToIndex(index, { align, behavior })\n }\n })\n }\n }\n\n scrollBy = (delta: number, { behavior }: ScrollToOffsetOptions = {}) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.scrollOffset + delta, {\n adjustments: undefined,\n behavior,\n })\n }\n\n getTotalSize = () => {\n const measurements = this.getMeasurements()\n\n let end: number\n // If there are no measurements, set the end to paddingStart\n if (measurements.length === 0) {\n end = this.options.paddingStart\n } else {\n // If lanes is 1, use the last measurement's end, otherwise find the maximum end value among all measurements\n end =\n this.options.lanes === 1\n ? measurements[measurements.length - 1]?.end ?? 0\n : Math.max(\n ...measurements.slice(-this.options.lanes).map((m) => m.end),\n )\n }\n\n return end - this.options.scrollMargin + this.options.paddingEnd\n }\n\n private _scrollToOffset = (\n offset: number,\n {\n adjustments,\n behavior,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this)\n }\n\n measure = () => {\n this.itemSizeCache = new Map()\n this.options.onChange?.(this, false)\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: VirtualItem[]\n outerSize: number\n scrollOffset: number\n}) {\n const count = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset)\n let endIndex = startIndex\n\n while (\n endIndex < count &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["opts","toOffset"],"mappings":"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"}
@@ -8,3 +8,4 @@ export declare function memo<TDeps extends readonly any[], TResult>(getDeps: ()
8
8
  }): () => TResult;
9
9
  export declare function notUndefined<T>(value: T | undefined, msg?: string): T;
10
10
  export declare const approxEqual: (a: number, b: number) => boolean;
11
+ export declare const debounce: (fn: Function, ms: number) => (this: any, ...args: any[]) => void;
package/dist/esm/utils.js CHANGED
@@ -51,8 +51,16 @@ function notUndefined(value, msg) {
51
51
  }
52
52
  }
53
53
  const approxEqual = (a, b) => Math.abs(a - b) < 1;
54
+ const debounce = (fn, ms) => {
55
+ let timeoutId;
56
+ return function(...args) {
57
+ clearTimeout(timeoutId);
58
+ timeoutId = setTimeout(() => fn.apply(this, args), ms);
59
+ };
60
+ };
54
61
  export {
55
62
  approxEqual,
63
+ debounce,
56
64
  memo,
57
65
  notUndefined
58
66
  };
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: false | string\n debug?: () => any\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n\n return (): TResult => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n opts?.onChange?.(result)\n\n return result!\n }\n}\n\nexport function notUndefined<T>(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1\n"],"names":[],"mappings":"AAIgB,SAAA,KACd,SACA,IACA,MAMA;AACI,MAAA,OAAO,KAAK,eAAe;AAC3B,MAAA;AAEJ,SAAO,MAAe;AAbR;AAcR,QAAA;AACA,QAAA,KAAK,SAAO,UAAK,UAAL;AAAgB,gBAAU,KAAK;AAE/C,UAAM,UAAU;AAEhB,UAAM,cACJ,QAAQ,WAAW,KAAK,UACxB,QAAQ,KAAK,CAAC,KAAU,UAAkB,KAAK,KAAK,MAAM,GAAG;AAE/D,QAAI,CAAC,aAAa;AACT,aAAA;AAAA,IACT;AAEO,WAAA;AAEH,QAAA;AACA,QAAA,KAAK,SAAO,UAAK,UAAL;AAAgB,mBAAa,KAAK;AAEzC,aAAA,GAAG,GAAG,OAAO;AAEtB,QAAI,KAAK,SAAO,UAAK,UAAL,gCAAgB;AACxB,YAAA,aAAa,KAAK,OAAO,KAAK,QAAQ,WAAY,GAAG,IAAI;AACzD,YAAA,gBAAgB,KAAK,OAAO,KAAK,QAAQ,cAAe,GAAG,IAAI;AACrE,YAAM,sBAAsB,gBAAgB;AAEtC,YAAA,MAAM,CAAC,KAAsB,QAAgB;AACjD,cAAM,OAAO,GAAG;AACT,eAAA,IAAI,SAAS,KAAK;AACvB,gBAAM,MAAM;AAAA,QACd;AACO,eAAA;AAAA,MAAA;AAGD,cAAA;AAAA,QACN,OAAO,IAAI,eAAe,CAAC,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;AAAA,QACnD;AAAA;AAAA;AAAA,yBAGiB,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,IAAI,MAAM,MAAM,qBAAqB,GAAG;AAAA,QAC9C,CAAA;AAAA,QACL,6BAAM;AAAA,MAAA;AAAA,IAEV;AAEA,uCAAM,aAAN,8BAAiB;AAEV,WAAA;AAAA,EAAA;AAEX;AAEgB,SAAA,aAAgB,OAAsB,KAAiB;AACrE,MAAI,UAAU,QAAW;AACjB,UAAA,IAAI,MAAM,uBAAuB,MAAM,KAAK,GAAG,KAAK,EAAE,EAAE;AAAA,EAAA,OACzD;AACE,WAAA;AAAA,EACT;AACF;AAEa,MAAA,cAAc,CAAC,GAAW,MAAc,KAAK,IAAI,IAAI,CAAC,IAAI;"}
1
+ {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: false | string\n debug?: () => any\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n\n return (): TResult => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n opts?.onChange?.(result)\n\n return result!\n }\n}\n\nexport function notUndefined<T>(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1\n\nexport const debounce = (fn: Function, ms: number) => {\n let timeoutId: ReturnType<typeof setTimeout>\n return function (this: any, ...args: any[]) {\n clearTimeout(timeoutId)\n timeoutId = setTimeout(() => fn.apply(this, args), ms)\n }\n}\n"],"names":[],"mappings":"AAIgB,SAAA,KACd,SACA,IACA,MAMA;AACI,MAAA,OAAO,KAAK,eAAe;AAC3B,MAAA;AAEJ,SAAO,MAAe;AAbR;AAcR,QAAA;AACA,QAAA,KAAK,SAAO,UAAK,UAAL;AAAgB,gBAAU,KAAK;AAE/C,UAAM,UAAU;AAEhB,UAAM,cACJ,QAAQ,WAAW,KAAK,UACxB,QAAQ,KAAK,CAAC,KAAU,UAAkB,KAAK,KAAK,MAAM,GAAG;AAE/D,QAAI,CAAC,aAAa;AACT,aAAA;AAAA,IACT;AAEO,WAAA;AAEH,QAAA;AACA,QAAA,KAAK,SAAO,UAAK,UAAL;AAAgB,mBAAa,KAAK;AAEzC,aAAA,GAAG,GAAG,OAAO;AAEtB,QAAI,KAAK,SAAO,UAAK,UAAL,gCAAgB;AACxB,YAAA,aAAa,KAAK,OAAO,KAAK,QAAQ,WAAY,GAAG,IAAI;AACzD,YAAA,gBAAgB,KAAK,OAAO,KAAK,QAAQ,cAAe,GAAG,IAAI;AACrE,YAAM,sBAAsB,gBAAgB;AAEtC,YAAA,MAAM,CAAC,KAAsB,QAAgB;AACjD,cAAM,OAAO,GAAG;AACT,eAAA,IAAI,SAAS,KAAK;AACvB,gBAAM,MAAM;AAAA,QACd;AACO,eAAA;AAAA,MAAA;AAGD,cAAA;AAAA,QACN,OAAO,IAAI,eAAe,CAAC,CAAC,KAAK,IAAI,YAAY,CAAC,CAAC;AAAA,QACnD;AAAA;AAAA;AAAA,yBAGiB,KAAK;AAAA,UAChB;AAAA,UACA,KAAK,IAAI,MAAM,MAAM,qBAAqB,GAAG;AAAA,QAC9C,CAAA;AAAA,QACL,6BAAM;AAAA,MAAA;AAAA,IAEV;AAEA,uCAAM,aAAN,8BAAiB;AAEV,WAAA;AAAA,EAAA;AAEX;AAEgB,SAAA,aAAgB,OAAsB,KAAiB;AACrE,MAAI,UAAU,QAAW;AACjB,UAAA,IAAI,MAAM,uBAAuB,MAAM,KAAK,GAAG,KAAK,EAAE,EAAE;AAAA,EAAA,OACzD;AACE,WAAA;AAAA,EACT;AACF;AAEa,MAAA,cAAc,CAAC,GAAW,MAAc,KAAK,IAAI,IAAI,CAAC,IAAI;AAE1D,MAAA,WAAW,CAAC,IAAc,OAAe;AAChD,MAAA;AACJ,SAAO,YAAwB,MAAa;AAC1C,iBAAa,SAAS;AACtB,gBAAY,WAAW,MAAM,GAAG,MAAM,MAAM,IAAI,GAAG,EAAE;AAAA,EAAA;AAEzD;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/virtual-core",
3
- "version": "3.3.0",
3
+ "version": "3.5.0",
4
4
  "description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",