@tanstack/virtual-core 3.13.21 → 3.13.23

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.
@@ -212,7 +212,18 @@ class Virtualizer {
212
212
  return _ro = new this.targetWindow.ResizeObserver((entries) => {
213
213
  entries.forEach((entry) => {
214
214
  const run = () => {
215
- this._measureElement(entry.target, entry);
215
+ const node = entry.target;
216
+ const index = this.indexFromElement(node);
217
+ if (!node.isConnected) {
218
+ this.observer.unobserve(node);
219
+ return;
220
+ }
221
+ if (this.shouldMeasureDuringScroll(index)) {
222
+ this.resizeItem(
223
+ index,
224
+ this.options.measureElement(node, entry, this)
225
+ );
226
+ }
216
227
  };
217
228
  this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
218
229
  });
@@ -591,17 +602,18 @@ class Virtualizer {
591
602
  }
592
603
  return true;
593
604
  };
594
- this._measureElement = (node, entry) => {
595
- if (!node.isConnected) {
596
- this.observer.unobserve(node);
605
+ this.measureElement = (node) => {
606
+ if (!node) {
607
+ this.elementsCache.forEach((cached, key2) => {
608
+ if (!cached.isConnected) {
609
+ this.observer.unobserve(cached);
610
+ this.elementsCache.delete(key2);
611
+ }
612
+ });
597
613
  return;
598
614
  }
599
615
  const index = this.indexFromElement(node);
600
- const item = this.measurementsCache[index];
601
- if (!item) {
602
- return;
603
- }
604
- const key = item.key;
616
+ const key = this.options.getItemKey(index);
605
617
  const prevNode = this.elementsCache.get(key);
606
618
  if (prevNode !== node) {
607
619
  if (prevNode) {
@@ -610,16 +622,14 @@ class Virtualizer {
610
622
  this.observer.observe(node);
611
623
  this.elementsCache.set(key, node);
612
624
  }
613
- if (this.shouldMeasureDuringScroll(index)) {
614
- this.resizeItem(index, this.options.measureElement(node, entry, this));
625
+ if ((!this.isScrolling || this.scrollState) && this.shouldMeasureDuringScroll(index)) {
626
+ this.resizeItem(index, this.options.measureElement(node, void 0, this));
615
627
  }
616
628
  };
617
629
  this.resizeItem = (index, size) => {
618
630
  var _a;
619
631
  const item = this.measurementsCache[index];
620
- if (!item) {
621
- return;
622
- }
632
+ if (!item) return;
623
633
  const itemSize = this.itemSizeCache.get(item.key) ?? item.size;
624
634
  const delta = size - itemSize;
625
635
  if (delta !== 0) {
@@ -637,18 +647,6 @@ class Virtualizer {
637
647
  this.notify(false);
638
648
  }
639
649
  };
640
- this.measureElement = (node) => {
641
- if (!node) {
642
- this.elementsCache.forEach((cached, key) => {
643
- if (!cached.isConnected) {
644
- this.observer.unobserve(cached);
645
- this.elementsCache.delete(key);
646
- }
647
- });
648
- return;
649
- }
650
- this._measureElement(node, void 0);
651
- };
652
650
  this.getVirtualItems = utils.memo(
653
651
  () => [this.getVirtualIndexes(), this.getMeasurements()],
654
652
  (indexes, measurements) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { approxEqual, debounce, 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 | bigint\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\nconst getRect = (element: HTMLElement): Rect => {\n const { offsetWidth, offsetHeight } = element\n return { width: offsetWidth, height: offsetHeight }\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 const targetWindow = instance.targetWindow\n if (!targetWindow) {\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(getRect(element as unknown as HTMLElement))\n\n if (!targetWindow.ResizeObserver) {\n return () => {}\n }\n\n const observer = new targetWindow.ResizeObserver((entries) => {\n const run = () => {\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(getRect(element as unknown as HTMLElement))\n }\n\n instance.options.useAnimationFrameWithResizeObserver\n ? requestAnimationFrame(run)\n : run()\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\ntype ObserveOffsetCallBack = (offset: number, isScrolling: boolean) => void\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: ObserveOffsetCallBack,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback =\n instance.options.useScrollendEvent && supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\n\n const createHandler = (isScrolling: boolean) => () => {\n const { horizontal, isRtl } = instance.options\n offset = horizontal\n ? element['scrollLeft'] * ((isRtl && -1) || 1)\n : element['scrollTop']\n fallback()\n cb(offset, isScrolling)\n }\n const handler = createHandler(true)\n const endHandler = createHandler(false)\n\n element.addEventListener('scroll', handler, addEventListenerOptions)\n const registerScrollendEvent =\n instance.options.useScrollendEvent && supportsScrollend\n if (registerScrollendEvent) {\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n }\n return () => {\n element.removeEventListener('scroll', handler)\n if (registerScrollendEvent) {\n element.removeEventListener('scrollend', endHandler)\n }\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: ObserveOffsetCallBack,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback =\n instance.options.useScrollendEvent && supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\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\n element.addEventListener('scroll', handler, addEventListenerOptions)\n const registerScrollendEvent =\n instance.options.useScrollendEvent && supportsScrollend\n if (registerScrollendEvent) {\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n }\n return () => {\n element.removeEventListener('scroll', handler)\n if (registerScrollendEvent) {\n element.removeEventListener('scrollend', endHandler)\n }\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\n return (element as unknown as HTMLElement)[\n instance.options.horizontal ? 'offsetWidth' : 'offsetHeight'\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: ObserveOffsetCallBack,\n ) => void | (() => void)\n // Optional\n debug?: boolean\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) => Array<number>\n scrollMargin?: number\n gap?: number\n indexAttribute?: string\n initialMeasurementsCache?: Array<VirtualItem>\n lanes?: number\n isScrollingResetDelay?: number\n useScrollendEvent?: boolean\n enabled?: boolean\n isRtl?: boolean\n useAnimationFrameWithResizeObserver?: boolean\n}\n\ntype ScrollState = {\n // what we want\n index: number | null\n align: ScrollAlignment\n behavior: ScrollBehavior\n\n // lifecycle\n startedAt: number\n\n // target tracking\n lastTargetOffset: number\n\n // settling\n stableFrames: number\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: Array<void | (() => void)> = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n targetWindow: (Window & typeof globalThis) | null = null\n isScrolling = false\n private scrollState: ScrollState | null = null\n measurementsCache: Array<VirtualItem> = []\n private itemSizeCache = new Map<Key, number>()\n private laneAssignments = new Map<number, number>() // index → lane cache\n private pendingMeasuredCacheIndexes: Array<number> = []\n private prevLanes: number | undefined = undefined\n private lanesChangedFlag = false\n private lanesSettling = false\n scrollRect: Rect | null = null\n scrollOffset: number | null = null\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments = 0\n shouldAdjustScrollPositionOnItemSizeChange:\n | undefined\n | ((\n item: VirtualItem,\n delta: number,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => boolean)\n elementsCache = new Map<Key, TItemElement>()\n private now = () => this.targetWindow?.performance?.now?.() ?? Date.now()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n }\n\n if (!this.targetWindow || !this.targetWindow.ResizeObserver) {\n return null\n }\n\n return (_ro = new this.targetWindow.ResizeObserver((entries) => {\n entries.forEach((entry) => {\n const run = () => {\n this._measureElement(entry.target as TItemElement, entry)\n }\n this.options.useAnimationFrameWithResizeObserver\n ? requestAnimationFrame(run)\n : run()\n })\n }))\n }\n\n return {\n disconnect: () => {\n get()?.disconnect()\n _ro = null\n },\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 }\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 enabled: true,\n isRtl: false,\n useScrollendEvent: false,\n useAnimationFrameWithResizeObserver: false,\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.observer.disconnect()\n if (this.rafId != null && this.targetWindow) {\n this.targetWindow.cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n this.scrollState = null\n this.scrollElement = null\n this.targetWindow = null\n }\n\n _didMount = () => {\n return () => {\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.enabled\n ? this.options.getScrollElement()\n : null\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n if (!scrollElement) {\n this.maybeNotify()\n return\n }\n\n this.scrollElement = scrollElement\n\n if (this.scrollElement && 'ownerDocument' in this.scrollElement) {\n this.targetWindow = this.scrollElement.ownerDocument.defaultView\n } else {\n this.targetWindow = this.scrollElement?.window ?? null\n }\n\n this.elementsCache.forEach((cached) => {\n this.observer.observe(cached)\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, isScrolling) => {\n this.scrollAdjustments = 0\n this.scrollDirection = isScrolling\n ? this.getScrollOffset() < offset\n ? 'forward'\n : 'backward'\n : null\n this.scrollOffset = offset\n this.isScrolling = isScrolling\n\n if (this.scrollState) {\n this.scheduleScrollReconcile()\n }\n this.maybeNotify()\n }),\n )\n\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: undefined,\n behavior: undefined,\n })\n }\n }\n\n private rafId: number | null = null\n private scheduleScrollReconcile() {\n if (!this.targetWindow) {\n this.scrollState = null\n return\n }\n if (this.rafId != null) return\n this.rafId = this.targetWindow.requestAnimationFrame(() => {\n this.rafId = null\n this.reconcileScroll()\n })\n }\n private reconcileScroll() {\n if (!this.scrollState) return\n\n const el = this.scrollElement\n if (!el) return\n\n // Safety valve: bail out if reconciliation has been running too long\n const MAX_RECONCILE_MS = 5000\n if (this.now() - this.scrollState.startedAt > MAX_RECONCILE_MS) {\n this.scrollState = null\n return\n }\n\n const offsetInfo =\n this.scrollState.index != null\n ? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align)\n : undefined\n const targetOffset = offsetInfo\n ? offsetInfo[0]\n : this.scrollState.lastTargetOffset\n\n // Require one stable frame where target matches scroll offset.\n // approxEqual() already tolerates minor fluctuations, so one frame is sufficient\n // to confirm scroll has reached its target without premature cleanup.\n const STABLE_FRAMES = 1\n\n const targetChanged = targetOffset !== this.scrollState.lastTargetOffset\n\n if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) {\n this.scrollState.stableFrames++\n if (this.scrollState.stableFrames >= STABLE_FRAMES) {\n this.scrollState = null\n return\n }\n } else {\n this.scrollState.stableFrames = 0\n\n if (targetChanged) {\n this.scrollState.lastTargetOffset = targetOffset\n // Switch to 'auto' behavior once measurements cause target to change\n // We want to jump directly to the correct position, not smoothly animate to it\n this.scrollState.behavior = 'auto'\n\n this._scrollToOffset(targetOffset, {\n adjustments: undefined,\n behavior: 'auto',\n })\n }\n }\n\n // Always reschedule while scrollState is active to guarantee\n // the safety valve timeout runs even if no scroll events fire\n // (e.g. no-op scrollToFn, detached element)\n this.scheduleScrollReconcile()\n }\n\n private getSize = () => {\n if (!this.options.enabled) {\n this.scrollRect = null\n return 0\n }\n\n this.scrollRect = this.scrollRect ?? this.options.initialRect\n\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private getScrollOffset = () => {\n if (!this.options.enabled) {\n this.scrollOffset = null\n return 0\n }\n\n this.scrollOffset =\n this.scrollOffset ??\n (typeof this.options.initialOffset === 'function'\n ? this.options.initialOffset()\n : this.options.initialOffset)\n\n return this.scrollOffset\n }\n\n private getFurthestMeasurement = (\n measurements: Array<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 getMeasurementOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.options.enabled,\n this.options.lanes,\n ],\n (count, paddingStart, scrollMargin, getItemKey, enabled, lanes) => {\n const lanesChanged =\n this.prevLanes !== undefined && this.prevLanes !== lanes\n\n if (lanesChanged) {\n // Set flag for getMeasurements to handle\n this.lanesChangedFlag = true\n }\n\n this.prevLanes = lanes\n this.pendingMeasuredCacheIndexes = []\n\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n enabled,\n lanes,\n }\n },\n {\n key: false,\n },\n )\n\n private getMeasurements = memo(\n () => [this.getMeasurementOptions(), this.itemSizeCache],\n (\n { count, paddingStart, scrollMargin, getItemKey, enabled, lanes },\n itemSizeCache,\n ) => {\n if (!enabled) {\n this.measurementsCache = []\n this.itemSizeCache.clear()\n this.laneAssignments.clear()\n return []\n }\n\n // Clean up stale lane cache entries when count decreases\n if (this.laneAssignments.size > count) {\n for (const index of this.laneAssignments.keys()) {\n if (index >= count) {\n this.laneAssignments.delete(index)\n }\n }\n }\n\n // ✅ Force complete recalculation when lanes change\n if (this.lanesChangedFlag) {\n this.lanesChangedFlag = false // Reset immediately\n this.lanesSettling = true // Start settling period\n this.measurementsCache = []\n this.itemSizeCache.clear()\n this.laneAssignments.clear() // Clear lane cache for new lane count\n // Clear pending indexes to force min = 0\n this.pendingMeasuredCacheIndexes = []\n }\n\n // Don't restore from initialMeasurementsCache during lane changes\n // as it contains stale lane assignments from the previous lane count\n if (this.measurementsCache.length === 0 && !this.lanesSettling) {\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n }\n\n // ✅ During lanes settling, ignore pendingMeasuredCacheIndexes to prevent repositioning\n const min = this.lanesSettling\n ? 0\n : this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n // ✅ End settling period when cache is fully built\n if (this.lanesSettling && this.measurementsCache.length === count) {\n this.lanesSettling = false\n }\n\n const measurements = this.measurementsCache.slice(0, min)\n\n // ✅ Performance: Track last item index per lane for O(1) lookup\n const laneLastIndex: Array<number | undefined> = new Array(lanes).fill(\n undefined,\n )\n\n // Initialize from existing measurements (before min)\n for (let m = 0; m < min; m++) {\n const item = measurements[m]\n if (item) {\n laneLastIndex[item.lane] = m\n }\n }\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n\n // Check for cached lane assignment\n const cachedLane = this.laneAssignments.get(i)\n let lane: number\n let start: number\n\n if (cachedLane !== undefined && this.options.lanes > 1) {\n // Use cached lane - O(1) lookup for previous item in same lane\n lane = cachedLane\n const prevIndex = laneLastIndex[lane]\n const prevInLane =\n prevIndex !== undefined ? measurements[prevIndex] : undefined\n start = prevInLane\n ? prevInLane.end + this.options.gap\n : paddingStart + scrollMargin\n } else {\n // No cache - use original logic (find shortest lane)\n const furthestMeasurement =\n this.options.lanes === 1\n ? measurements[i - 1]\n : this.getFurthestMeasurement(measurements, i)\n\n start = furthestMeasurement\n ? furthestMeasurement.end + this.options.gap\n : paddingStart + scrollMargin\n\n lane = furthestMeasurement\n ? furthestMeasurement.lane\n : i % this.options.lanes\n\n // Cache the lane assignment\n if (this.options.lanes > 1) {\n this.laneAssignments.set(i, lane)\n }\n }\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 measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane,\n }\n\n // ✅ Performance: Update lane's last item index\n laneLastIndex[lane] = i\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 () => [\n this.getMeasurements(),\n this.getSize(),\n this.getScrollOffset(),\n this.options.lanes,\n ],\n (measurements, outerSize, scrollOffset, lanes) => {\n return (this.range =\n measurements.length > 0 && outerSize > 0\n ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n lanes,\n })\n : null)\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualIndexes = memo(\n () => {\n let startIndex: number | null = null\n let endIndex: number | null = null\n const range = this.calculateRange()\n if (range) {\n startIndex = range.startIndex\n endIndex = range.endIndex\n }\n this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex])\n return [\n this.options.rangeExtractor,\n this.options.overscan,\n this.options.count,\n startIndex,\n endIndex,\n ]\n },\n (rangeExtractor, overscan, count, startIndex, endIndex) => {\n return startIndex === null || endIndex === null\n ? []\n : rangeExtractor({\n startIndex,\n endIndex,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getVirtualIndexes',\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 /**\n * Determines if an item at the given index should be measured during smooth scroll.\n * During smooth scroll, only items within a buffer range around the target are measured\n * to prevent items far from the target from pushing it away.\n */\n private shouldMeasureDuringScroll = (index: number): boolean => {\n // No scroll state or not smooth scroll - always allow measurements\n if (!this.scrollState || this.scrollState.behavior !== 'smooth') {\n return true\n }\n\n const scrollIndex =\n this.scrollState.index ??\n this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)?.index\n\n if (scrollIndex !== undefined && this.range) {\n // Allow measurements within a buffer range around the scroll target\n const bufferSize = Math.max(\n this.options.overscan,\n Math.ceil((this.range.endIndex - this.range.startIndex) / 2),\n )\n const minIndex = Math.max(0, scrollIndex - bufferSize)\n const maxIndex = Math.min(\n this.options.count - 1,\n scrollIndex + bufferSize,\n )\n return index >= minIndex && index <= maxIndex\n }\n\n return true\n }\n\n private _measureElement = (\n node: TItemElement,\n entry: ResizeObserverEntry | undefined,\n ) => {\n if (!node.isConnected) {\n this.observer.unobserve(node)\n return\n }\n\n const index = this.indexFromElement(node)\n const item = this.measurementsCache[index]\n if (!item) {\n return\n }\n const key = item.key\n const prevNode = this.elementsCache.get(key)\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.elementsCache.set(key, node)\n }\n\n if (this.shouldMeasureDuringScroll(index)) {\n this.resizeItem(index, this.options.measureElement(node, entry, this))\n }\n }\n\n resizeItem = (index: number, size: number) => {\n const item = this.measurementsCache[index]\n if (!item) {\n return\n }\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n const delta = size - itemSize\n\n if (delta !== 0) {\n if (\n this.scrollState?.behavior !== 'smooth' &&\n (this.shouldAdjustScrollPositionOnItemSizeChange !== undefined\n ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this)\n : item.start < this.getScrollOffset() + this.scrollAdjustments)\n ) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n this._scrollToOffset(this.getScrollOffset(), {\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 | undefined) => {\n if (!node) {\n this.elementsCache.forEach((cached, key) => {\n if (!cached.isConnected) {\n this.observer.unobserve(cached)\n this.elementsCache.delete(key)\n }\n })\n return\n }\n\n this._measureElement(node, undefined)\n }\n\n getVirtualItems = memo(\n () => [this.getVirtualIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: Array<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' && 'getVirtualItems',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n if (measurements.length === 0) {\n return undefined\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 private getMaxScrollOffset = () => {\n if (!this.scrollElement) return 0\n\n if ('scrollHeight' in this.scrollElement) {\n // Element\n return this.options.horizontal\n ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth\n : this.scrollElement.scrollHeight - this.scrollElement.clientHeight\n } else {\n // Window\n const doc = this.scrollElement.document.documentElement\n return this.options.horizontal\n ? doc.scrollWidth - this.scrollElement.innerWidth\n : doc.scrollHeight - this.scrollElement.innerHeight\n }\n }\n\n getOffsetForAlignment = (\n toOffset: number,\n align: ScrollAlignment,\n itemSize = 0,\n ) => {\n if (!this.scrollElement) return 0\n\n const size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n if (align === 'auto') {\n align = toOffset >= scrollOffset + size ? 'end' : 'start'\n }\n\n if (align === 'center') {\n // When aligning to a particular item (e.g. with scrollToIndex),\n // adjust offset by the size of the item to center on the item\n toOffset += (itemSize - size) / 2\n } else if (align === 'end') {\n toOffset -= size\n }\n\n const maxOffset = this.getMaxScrollOffset()\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 size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n const item = this.measurementsCache[index]\n if (!item) return\n\n if (align === 'auto') {\n if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {\n align = 'end'\n } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {\n align = 'start'\n } else {\n return [scrollOffset, align] as const\n }\n }\n\n // For the last item with 'end' alignment, use browser's actual max scroll\n // to account for borders/padding that aren't in our measurements\n if (align === 'end' && index === this.options.count - 1) {\n return [this.getMaxScrollOffset(), align] as const\n }\n\n const toOffset =\n align === 'end'\n ? item.end + this.options.scrollPaddingEnd\n : item.start - this.options.scrollPaddingStart\n\n return [\n this.getOffsetForAlignment(toOffset, align, item.size),\n align,\n ] as const\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior = 'auto' }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.getOffsetForAlignment(toOffset, align)\n\n const now = this.now()\n this.scrollState = {\n index: null,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\n }\n\n scrollToIndex = (\n index: number,\n {\n align: initialAlign = 'auto',\n behavior = 'auto',\n }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const offsetInfo = this.getOffsetForIndex(index, initialAlign)\n if (!offsetInfo) {\n return\n }\n const [offset, align] = offsetInfo\n\n const now = this.now()\n this.scrollState = {\n index,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\n }\n\n scrollBy = (\n delta: number,\n { behavior = 'auto' }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.getScrollOffset() + delta\n const now = this.now()\n\n this.scrollState = {\n index: null,\n align: 'start',\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\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 there is only one lane, use the last measurement's end\n // Otherwise find the maximum end value among all measurements\n if (measurements.length === 0) {\n end = this.options.paddingStart\n } else if (this.options.lanes === 1) {\n end = measurements[measurements.length - 1]?.end ?? 0\n } else {\n const endByLane = Array<number | null>(this.options.lanes).fill(null)\n let endIndex = measurements.length - 1\n while (endIndex >= 0 && endByLane.some((val) => val === null)) {\n const item = measurements[endIndex]!\n if (endByLane[item.lane] === null) {\n endByLane[item.lane] = item.end\n }\n\n endIndex--\n }\n\n end = Math.max(...endByLane.filter((val): val is number => val !== null))\n }\n\n return Math.max(\n end - this.options.scrollMargin + this.options.paddingEnd,\n 0,\n )\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.laneAssignments = new Map() // Clear lane cache for full re-layout\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 lanes,\n}: {\n measurements: Array<VirtualItem>\n outerSize: number\n scrollOffset: number\n lanes: number\n}) {\n const lastIndex = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n // handle case when item count is less than or equal to lanes\n if (measurements.length <= lanes) {\n return {\n startIndex: 0,\n endIndex: lastIndex,\n }\n }\n\n let startIndex = findNearestBinarySearch(\n 0,\n lastIndex,\n getOffset,\n scrollOffset,\n )\n let endIndex = startIndex\n\n if (lanes === 1) {\n while (\n endIndex < lastIndex &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n } else if (lanes > 1) {\n // Expand forward until we include the visible items from all lanes\n // which are closer to the end of the virtualizer window\n const endPerLane = Array(lanes).fill(0)\n while (\n endIndex < lastIndex &&\n endPerLane.some((pos) => pos < scrollOffset + outerSize)\n ) {\n const item = measurements[endIndex]!\n endPerLane[item.lane] = item.end\n endIndex++\n }\n\n // Expand backward until we include all lanes' visible items\n // closer to the top\n const startPerLane = Array(lanes).fill(scrollOffset + outerSize)\n while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {\n const item = measurements[startIndex]!\n startPerLane[item.lane] = item.start\n startIndex--\n }\n\n // Align startIndex to the beginning of its lane\n startIndex = Math.max(0, startIndex - (startIndex % lanes))\n // Align endIndex to the end of its lane\n endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - (endIndex % lanes)))\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["debounce","opts","memo","notUndefined","approxEqual"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { approxEqual, debounce, 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' | 'instant'\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 | bigint\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\nconst getRect = (element: HTMLElement): Rect => {\n const { offsetWidth, offsetHeight } = element\n return { width: offsetWidth, height: offsetHeight }\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 const targetWindow = instance.targetWindow\n if (!targetWindow) {\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(getRect(element as unknown as HTMLElement))\n\n if (!targetWindow.ResizeObserver) {\n return () => {}\n }\n\n const observer = new targetWindow.ResizeObserver((entries) => {\n const run = () => {\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(getRect(element as unknown as HTMLElement))\n }\n\n instance.options.useAnimationFrameWithResizeObserver\n ? requestAnimationFrame(run)\n : run()\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\ntype ObserveOffsetCallBack = (offset: number, isScrolling: boolean) => void\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: ObserveOffsetCallBack,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback =\n instance.options.useScrollendEvent && supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\n\n const createHandler = (isScrolling: boolean) => () => {\n const { horizontal, isRtl } = instance.options\n offset = horizontal\n ? element['scrollLeft'] * ((isRtl && -1) || 1)\n : element['scrollTop']\n fallback()\n cb(offset, isScrolling)\n }\n const handler = createHandler(true)\n const endHandler = createHandler(false)\n\n element.addEventListener('scroll', handler, addEventListenerOptions)\n const registerScrollendEvent =\n instance.options.useScrollendEvent && supportsScrollend\n if (registerScrollendEvent) {\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n }\n return () => {\n element.removeEventListener('scroll', handler)\n if (registerScrollendEvent) {\n element.removeEventListener('scrollend', endHandler)\n }\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: ObserveOffsetCallBack,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback =\n instance.options.useScrollendEvent && supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\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\n element.addEventListener('scroll', handler, addEventListenerOptions)\n const registerScrollendEvent =\n instance.options.useScrollendEvent && supportsScrollend\n if (registerScrollendEvent) {\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n }\n return () => {\n element.removeEventListener('scroll', handler)\n if (registerScrollendEvent) {\n element.removeEventListener('scrollend', endHandler)\n }\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\n return (element as unknown as HTMLElement)[\n instance.options.horizontal ? 'offsetWidth' : 'offsetHeight'\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: ObserveOffsetCallBack,\n ) => void | (() => void)\n // Optional\n debug?: boolean\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) => Array<number>\n scrollMargin?: number\n gap?: number\n indexAttribute?: string\n initialMeasurementsCache?: Array<VirtualItem>\n lanes?: number\n isScrollingResetDelay?: number\n useScrollendEvent?: boolean\n enabled?: boolean\n isRtl?: boolean\n useAnimationFrameWithResizeObserver?: boolean\n}\n\ntype ScrollState = {\n // what we want\n index: number | null\n align: ScrollAlignment\n behavior: ScrollBehavior\n\n // lifecycle\n startedAt: number\n\n // target tracking\n lastTargetOffset: number\n\n // settling\n stableFrames: number\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: Array<void | (() => void)> = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n targetWindow: (Window & typeof globalThis) | null = null\n isScrolling = false\n private scrollState: ScrollState | null = null\n measurementsCache: Array<VirtualItem> = []\n private itemSizeCache = new Map<Key, number>()\n private laneAssignments = new Map<number, number>() // index → lane cache\n private pendingMeasuredCacheIndexes: Array<number> = []\n private prevLanes: number | undefined = undefined\n private lanesChangedFlag = false\n private lanesSettling = false\n scrollRect: Rect | null = null\n scrollOffset: number | null = null\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments = 0\n shouldAdjustScrollPositionOnItemSizeChange:\n | undefined\n | ((\n item: VirtualItem,\n delta: number,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => boolean)\n elementsCache = new Map<Key, TItemElement>()\n private now = () => this.targetWindow?.performance?.now?.() ?? Date.now()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n }\n\n if (!this.targetWindow || !this.targetWindow.ResizeObserver) {\n return null\n }\n\n return (_ro = new this.targetWindow.ResizeObserver((entries) => {\n entries.forEach((entry) => {\n const run = () => {\n const node = entry.target as TItemElement\n const index = this.indexFromElement(node)\n\n if (!node.isConnected) {\n this.observer.unobserve(node)\n return\n }\n\n if (this.shouldMeasureDuringScroll(index)) {\n this.resizeItem(\n index,\n this.options.measureElement(node, entry, this),\n )\n }\n }\n this.options.useAnimationFrameWithResizeObserver\n ? requestAnimationFrame(run)\n : run()\n })\n }))\n }\n\n return {\n disconnect: () => {\n get()?.disconnect()\n _ro = null\n },\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 }\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 enabled: true,\n isRtl: false,\n useScrollendEvent: false,\n useAnimationFrameWithResizeObserver: false,\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.observer.disconnect()\n if (this.rafId != null && this.targetWindow) {\n this.targetWindow.cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n this.scrollState = null\n this.scrollElement = null\n this.targetWindow = null\n }\n\n _didMount = () => {\n return () => {\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.enabled\n ? this.options.getScrollElement()\n : null\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n if (!scrollElement) {\n this.maybeNotify()\n return\n }\n\n this.scrollElement = scrollElement\n\n if (this.scrollElement && 'ownerDocument' in this.scrollElement) {\n this.targetWindow = this.scrollElement.ownerDocument.defaultView\n } else {\n this.targetWindow = this.scrollElement?.window ?? null\n }\n\n this.elementsCache.forEach((cached) => {\n this.observer.observe(cached)\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, isScrolling) => {\n this.scrollAdjustments = 0\n this.scrollDirection = isScrolling\n ? this.getScrollOffset() < offset\n ? 'forward'\n : 'backward'\n : null\n this.scrollOffset = offset\n this.isScrolling = isScrolling\n\n if (this.scrollState) {\n this.scheduleScrollReconcile()\n }\n this.maybeNotify()\n }),\n )\n\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: undefined,\n behavior: undefined,\n })\n }\n }\n\n private rafId: number | null = null\n private scheduleScrollReconcile() {\n if (!this.targetWindow) {\n this.scrollState = null\n return\n }\n if (this.rafId != null) return\n this.rafId = this.targetWindow.requestAnimationFrame(() => {\n this.rafId = null\n this.reconcileScroll()\n })\n }\n private reconcileScroll() {\n if (!this.scrollState) return\n\n const el = this.scrollElement\n if (!el) return\n\n // Safety valve: bail out if reconciliation has been running too long\n const MAX_RECONCILE_MS = 5000\n if (this.now() - this.scrollState.startedAt > MAX_RECONCILE_MS) {\n this.scrollState = null\n return\n }\n\n const offsetInfo =\n this.scrollState.index != null\n ? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align)\n : undefined\n const targetOffset = offsetInfo\n ? offsetInfo[0]\n : this.scrollState.lastTargetOffset\n\n // Require one stable frame where target matches scroll offset.\n // approxEqual() already tolerates minor fluctuations, so one frame is sufficient\n // to confirm scroll has reached its target without premature cleanup.\n const STABLE_FRAMES = 1\n\n const targetChanged = targetOffset !== this.scrollState.lastTargetOffset\n\n if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) {\n this.scrollState.stableFrames++\n if (this.scrollState.stableFrames >= STABLE_FRAMES) {\n this.scrollState = null\n return\n }\n } else {\n this.scrollState.stableFrames = 0\n\n if (targetChanged) {\n this.scrollState.lastTargetOffset = targetOffset\n // Switch to 'auto' behavior once measurements cause target to change\n // We want to jump directly to the correct position, not smoothly animate to it\n this.scrollState.behavior = 'auto'\n\n this._scrollToOffset(targetOffset, {\n adjustments: undefined,\n behavior: 'auto',\n })\n }\n }\n\n // Always reschedule while scrollState is active to guarantee\n // the safety valve timeout runs even if no scroll events fire\n // (e.g. no-op scrollToFn, detached element)\n this.scheduleScrollReconcile()\n }\n\n private getSize = () => {\n if (!this.options.enabled) {\n this.scrollRect = null\n return 0\n }\n\n this.scrollRect = this.scrollRect ?? this.options.initialRect\n\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private getScrollOffset = () => {\n if (!this.options.enabled) {\n this.scrollOffset = null\n return 0\n }\n\n this.scrollOffset =\n this.scrollOffset ??\n (typeof this.options.initialOffset === 'function'\n ? this.options.initialOffset()\n : this.options.initialOffset)\n\n return this.scrollOffset\n }\n\n private getFurthestMeasurement = (\n measurements: Array<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 getMeasurementOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.options.enabled,\n this.options.lanes,\n ],\n (count, paddingStart, scrollMargin, getItemKey, enabled, lanes) => {\n const lanesChanged =\n this.prevLanes !== undefined && this.prevLanes !== lanes\n\n if (lanesChanged) {\n // Set flag for getMeasurements to handle\n this.lanesChangedFlag = true\n }\n\n this.prevLanes = lanes\n this.pendingMeasuredCacheIndexes = []\n\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n enabled,\n lanes,\n }\n },\n {\n key: false,\n },\n )\n\n private getMeasurements = memo(\n () => [this.getMeasurementOptions(), this.itemSizeCache],\n (\n { count, paddingStart, scrollMargin, getItemKey, enabled, lanes },\n itemSizeCache,\n ) => {\n if (!enabled) {\n this.measurementsCache = []\n this.itemSizeCache.clear()\n this.laneAssignments.clear()\n return []\n }\n\n // Clean up stale lane cache entries when count decreases\n if (this.laneAssignments.size > count) {\n for (const index of this.laneAssignments.keys()) {\n if (index >= count) {\n this.laneAssignments.delete(index)\n }\n }\n }\n\n // ✅ Force complete recalculation when lanes change\n if (this.lanesChangedFlag) {\n this.lanesChangedFlag = false // Reset immediately\n this.lanesSettling = true // Start settling period\n this.measurementsCache = []\n this.itemSizeCache.clear()\n this.laneAssignments.clear() // Clear lane cache for new lane count\n // Clear pending indexes to force min = 0\n this.pendingMeasuredCacheIndexes = []\n }\n\n // Don't restore from initialMeasurementsCache during lane changes\n // as it contains stale lane assignments from the previous lane count\n if (this.measurementsCache.length === 0 && !this.lanesSettling) {\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n }\n\n // ✅ During lanes settling, ignore pendingMeasuredCacheIndexes to prevent repositioning\n const min = this.lanesSettling\n ? 0\n : this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n // ✅ End settling period when cache is fully built\n if (this.lanesSettling && this.measurementsCache.length === count) {\n this.lanesSettling = false\n }\n\n const measurements = this.measurementsCache.slice(0, min)\n\n // ✅ Performance: Track last item index per lane for O(1) lookup\n const laneLastIndex: Array<number | undefined> = new Array(lanes).fill(\n undefined,\n )\n\n // Initialize from existing measurements (before min)\n for (let m = 0; m < min; m++) {\n const item = measurements[m]\n if (item) {\n laneLastIndex[item.lane] = m\n }\n }\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n\n // Check for cached lane assignment\n const cachedLane = this.laneAssignments.get(i)\n let lane: number\n let start: number\n\n if (cachedLane !== undefined && this.options.lanes > 1) {\n // Use cached lane - O(1) lookup for previous item in same lane\n lane = cachedLane\n const prevIndex = laneLastIndex[lane]\n const prevInLane =\n prevIndex !== undefined ? measurements[prevIndex] : undefined\n start = prevInLane\n ? prevInLane.end + this.options.gap\n : paddingStart + scrollMargin\n } else {\n // No cache - use original logic (find shortest lane)\n const furthestMeasurement =\n this.options.lanes === 1\n ? measurements[i - 1]\n : this.getFurthestMeasurement(measurements, i)\n\n start = furthestMeasurement\n ? furthestMeasurement.end + this.options.gap\n : paddingStart + scrollMargin\n\n lane = furthestMeasurement\n ? furthestMeasurement.lane\n : i % this.options.lanes\n\n // Cache the lane assignment\n if (this.options.lanes > 1) {\n this.laneAssignments.set(i, lane)\n }\n }\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 measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane,\n }\n\n // ✅ Performance: Update lane's last item index\n laneLastIndex[lane] = i\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 () => [\n this.getMeasurements(),\n this.getSize(),\n this.getScrollOffset(),\n this.options.lanes,\n ],\n (measurements, outerSize, scrollOffset, lanes) => {\n return (this.range =\n measurements.length > 0 && outerSize > 0\n ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n lanes,\n })\n : null)\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualIndexes = memo(\n () => {\n let startIndex: number | null = null\n let endIndex: number | null = null\n const range = this.calculateRange()\n if (range) {\n startIndex = range.startIndex\n endIndex = range.endIndex\n }\n this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex])\n return [\n this.options.rangeExtractor,\n this.options.overscan,\n this.options.count,\n startIndex,\n endIndex,\n ]\n },\n (rangeExtractor, overscan, count, startIndex, endIndex) => {\n return startIndex === null || endIndex === null\n ? []\n : rangeExtractor({\n startIndex,\n endIndex,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getVirtualIndexes',\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 /**\n * Determines if an item at the given index should be measured during smooth scroll.\n * During smooth scroll, only items within a buffer range around the target are measured\n * to prevent items far from the target from pushing it away.\n */\n private shouldMeasureDuringScroll = (index: number): boolean => {\n // No scroll state or not smooth scroll - always allow measurements\n if (!this.scrollState || this.scrollState.behavior !== 'smooth') {\n return true\n }\n\n const scrollIndex =\n this.scrollState.index ??\n this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)?.index\n\n if (scrollIndex !== undefined && this.range) {\n // Allow measurements within a buffer range around the scroll target\n const bufferSize = Math.max(\n this.options.overscan,\n Math.ceil((this.range.endIndex - this.range.startIndex) / 2),\n )\n const minIndex = Math.max(0, scrollIndex - bufferSize)\n const maxIndex = Math.min(\n this.options.count - 1,\n scrollIndex + bufferSize,\n )\n return index >= minIndex && index <= maxIndex\n }\n\n return true\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n this.elementsCache.forEach((cached, key) => {\n if (!cached.isConnected) {\n this.observer.unobserve(cached)\n this.elementsCache.delete(key)\n }\n })\n return\n }\n\n const index = this.indexFromElement(node)\n const key = this.options.getItemKey(index)\n const prevNode = this.elementsCache.get(key)\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.elementsCache.set(key, node)\n }\n\n // Sync-measure when idle (initial render) or during programmatic scrolling\n // (scrollToIndex/scrollToOffset) where reconcileScroll needs sizes in the same frame.\n // During normal user scrolling, skip sync measurement — the RO callback handles it async.\n if (\n (!this.isScrolling || this.scrollState) &&\n this.shouldMeasureDuringScroll(index)\n ) {\n this.resizeItem(index, this.options.measureElement(node, undefined, this))\n }\n }\n\n resizeItem = (index: number, size: number) => {\n const item = this.measurementsCache[index]\n if (!item) return\n\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n const delta = size - itemSize\n\n if (delta !== 0) {\n if (\n this.scrollState?.behavior !== 'smooth' &&\n (this.shouldAdjustScrollPositionOnItemSizeChange !== undefined\n ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this)\n : item.start < this.getScrollOffset() + this.scrollAdjustments)\n ) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n this._scrollToOffset(this.getScrollOffset(), {\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 getVirtualItems = memo(\n () => [this.getVirtualIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: Array<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' && 'getVirtualItems',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n if (measurements.length === 0) {\n return undefined\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 private getMaxScrollOffset = () => {\n if (!this.scrollElement) return 0\n\n if ('scrollHeight' in this.scrollElement) {\n // Element\n return this.options.horizontal\n ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth\n : this.scrollElement.scrollHeight - this.scrollElement.clientHeight\n } else {\n // Window\n const doc = this.scrollElement.document.documentElement\n return this.options.horizontal\n ? doc.scrollWidth - this.scrollElement.innerWidth\n : doc.scrollHeight - this.scrollElement.innerHeight\n }\n }\n\n getOffsetForAlignment = (\n toOffset: number,\n align: ScrollAlignment,\n itemSize = 0,\n ) => {\n if (!this.scrollElement) return 0\n\n const size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n if (align === 'auto') {\n align = toOffset >= scrollOffset + size ? 'end' : 'start'\n }\n\n if (align === 'center') {\n // When aligning to a particular item (e.g. with scrollToIndex),\n // adjust offset by the size of the item to center on the item\n toOffset += (itemSize - size) / 2\n } else if (align === 'end') {\n toOffset -= size\n }\n\n const maxOffset = this.getMaxScrollOffset()\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 size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n const item = this.measurementsCache[index]\n if (!item) return\n\n if (align === 'auto') {\n if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {\n align = 'end'\n } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {\n align = 'start'\n } else {\n return [scrollOffset, align] as const\n }\n }\n\n // For the last item with 'end' alignment, use browser's actual max scroll\n // to account for borders/padding that aren't in our measurements\n if (align === 'end' && index === this.options.count - 1) {\n return [this.getMaxScrollOffset(), align] as const\n }\n\n const toOffset =\n align === 'end'\n ? item.end + this.options.scrollPaddingEnd\n : item.start - this.options.scrollPaddingStart\n\n return [\n this.getOffsetForAlignment(toOffset, align, item.size),\n align,\n ] as const\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior = 'auto' }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.getOffsetForAlignment(toOffset, align)\n\n const now = this.now()\n this.scrollState = {\n index: null,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\n }\n\n scrollToIndex = (\n index: number,\n {\n align: initialAlign = 'auto',\n behavior = 'auto',\n }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const offsetInfo = this.getOffsetForIndex(index, initialAlign)\n if (!offsetInfo) {\n return\n }\n const [offset, align] = offsetInfo\n\n const now = this.now()\n this.scrollState = {\n index,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\n }\n\n scrollBy = (\n delta: number,\n { behavior = 'auto' }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.getScrollOffset() + delta\n const now = this.now()\n\n this.scrollState = {\n index: null,\n align: 'start',\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\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 there is only one lane, use the last measurement's end\n // Otherwise find the maximum end value among all measurements\n if (measurements.length === 0) {\n end = this.options.paddingStart\n } else if (this.options.lanes === 1) {\n end = measurements[measurements.length - 1]?.end ?? 0\n } else {\n const endByLane = Array<number | null>(this.options.lanes).fill(null)\n let endIndex = measurements.length - 1\n while (endIndex >= 0 && endByLane.some((val) => val === null)) {\n const item = measurements[endIndex]!\n if (endByLane[item.lane] === null) {\n endByLane[item.lane] = item.end\n }\n\n endIndex--\n }\n\n end = Math.max(...endByLane.filter((val): val is number => val !== null))\n }\n\n return Math.max(\n end - this.options.scrollMargin + this.options.paddingEnd,\n 0,\n )\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.laneAssignments = new Map() // Clear lane cache for full re-layout\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 lanes,\n}: {\n measurements: Array<VirtualItem>\n outerSize: number\n scrollOffset: number\n lanes: number\n}) {\n const lastIndex = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n // handle case when item count is less than or equal to lanes\n if (measurements.length <= lanes) {\n return {\n startIndex: 0,\n endIndex: lastIndex,\n }\n }\n\n let startIndex = findNearestBinarySearch(\n 0,\n lastIndex,\n getOffset,\n scrollOffset,\n )\n let endIndex = startIndex\n\n if (lanes === 1) {\n while (\n endIndex < lastIndex &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n } else if (lanes > 1) {\n // Expand forward until we include the visible items from all lanes\n // which are closer to the end of the virtualizer window\n const endPerLane = Array(lanes).fill(0)\n while (\n endIndex < lastIndex &&\n endPerLane.some((pos) => pos < scrollOffset + outerSize)\n ) {\n const item = measurements[endIndex]!\n endPerLane[item.lane] = item.end\n endIndex++\n }\n\n // Expand backward until we include all lanes' visible items\n // closer to the top\n const startPerLane = Array(lanes).fill(scrollOffset + outerSize)\n while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {\n const item = measurements[startIndex]!\n startPerLane[item.lane] = item.start\n startIndex--\n }\n\n // Align startIndex to the beginning of its lane\n startIndex = Math.max(0, startIndex - (startIndex % lanes))\n // Align endIndex to the end of its lane\n endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - (endIndex % lanes)))\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["debounce","opts","memo","key","notUndefined","approxEqual"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  export * from './utils.cjs';
2
2
  type ScrollDirection = 'forward' | 'backward';
3
3
  type ScrollAlignment = 'start' | 'center' | 'end' | 'auto';
4
- type ScrollBehavior = 'auto' | 'smooth';
4
+ type ScrollBehavior = 'auto' | 'smooth' | 'instant';
5
5
  export interface ScrollToOptions {
6
6
  align?: ScrollAlignment;
7
7
  behavior?: ScrollBehavior;
@@ -136,9 +136,8 @@ export declare class Virtualizer<TScrollElement extends Element | Window, TItemE
136
136
  * to prevent items far from the target from pushing it away.
137
137
  */
138
138
  private shouldMeasureDuringScroll;
139
- private _measureElement;
139
+ measureElement: (node: TItemElement | null) => void;
140
140
  resizeItem: (index: number, size: number) => void;
141
- measureElement: (node: TItemElement | null | undefined) => void;
142
141
  getVirtualItems: {
143
142
  (): VirtualItem[];
144
143
  updateDeps(newDeps: [number[], VirtualItem[]]): void;
@@ -1,7 +1,7 @@
1
1
  export * from './utils.js';
2
2
  type ScrollDirection = 'forward' | 'backward';
3
3
  type ScrollAlignment = 'start' | 'center' | 'end' | 'auto';
4
- type ScrollBehavior = 'auto' | 'smooth';
4
+ type ScrollBehavior = 'auto' | 'smooth' | 'instant';
5
5
  export interface ScrollToOptions {
6
6
  align?: ScrollAlignment;
7
7
  behavior?: ScrollBehavior;
@@ -136,9 +136,8 @@ export declare class Virtualizer<TScrollElement extends Element | Window, TItemE
136
136
  * to prevent items far from the target from pushing it away.
137
137
  */
138
138
  private shouldMeasureDuringScroll;
139
- private _measureElement;
139
+ measureElement: (node: TItemElement | null) => void;
140
140
  resizeItem: (index: number, size: number) => void;
141
- measureElement: (node: TItemElement | null | undefined) => void;
142
141
  getVirtualItems: {
143
142
  (): VirtualItem[];
144
143
  updateDeps(newDeps: [number[], VirtualItem[]]): void;
package/dist/esm/index.js CHANGED
@@ -210,7 +210,18 @@ class Virtualizer {
210
210
  return _ro = new this.targetWindow.ResizeObserver((entries) => {
211
211
  entries.forEach((entry) => {
212
212
  const run = () => {
213
- this._measureElement(entry.target, entry);
213
+ const node = entry.target;
214
+ const index = this.indexFromElement(node);
215
+ if (!node.isConnected) {
216
+ this.observer.unobserve(node);
217
+ return;
218
+ }
219
+ if (this.shouldMeasureDuringScroll(index)) {
220
+ this.resizeItem(
221
+ index,
222
+ this.options.measureElement(node, entry, this)
223
+ );
224
+ }
214
225
  };
215
226
  this.options.useAnimationFrameWithResizeObserver ? requestAnimationFrame(run) : run();
216
227
  });
@@ -589,17 +600,18 @@ class Virtualizer {
589
600
  }
590
601
  return true;
591
602
  };
592
- this._measureElement = (node, entry) => {
593
- if (!node.isConnected) {
594
- this.observer.unobserve(node);
603
+ this.measureElement = (node) => {
604
+ if (!node) {
605
+ this.elementsCache.forEach((cached, key2) => {
606
+ if (!cached.isConnected) {
607
+ this.observer.unobserve(cached);
608
+ this.elementsCache.delete(key2);
609
+ }
610
+ });
595
611
  return;
596
612
  }
597
613
  const index = this.indexFromElement(node);
598
- const item = this.measurementsCache[index];
599
- if (!item) {
600
- return;
601
- }
602
- const key = item.key;
614
+ const key = this.options.getItemKey(index);
603
615
  const prevNode = this.elementsCache.get(key);
604
616
  if (prevNode !== node) {
605
617
  if (prevNode) {
@@ -608,16 +620,14 @@ class Virtualizer {
608
620
  this.observer.observe(node);
609
621
  this.elementsCache.set(key, node);
610
622
  }
611
- if (this.shouldMeasureDuringScroll(index)) {
612
- this.resizeItem(index, this.options.measureElement(node, entry, this));
623
+ if ((!this.isScrolling || this.scrollState) && this.shouldMeasureDuringScroll(index)) {
624
+ this.resizeItem(index, this.options.measureElement(node, void 0, this));
613
625
  }
614
626
  };
615
627
  this.resizeItem = (index, size) => {
616
628
  var _a;
617
629
  const item = this.measurementsCache[index];
618
- if (!item) {
619
- return;
620
- }
630
+ if (!item) return;
621
631
  const itemSize = this.itemSizeCache.get(item.key) ?? item.size;
622
632
  const delta = size - itemSize;
623
633
  if (delta !== 0) {
@@ -635,18 +645,6 @@ class Virtualizer {
635
645
  this.notify(false);
636
646
  }
637
647
  };
638
- this.measureElement = (node) => {
639
- if (!node) {
640
- this.elementsCache.forEach((cached, key) => {
641
- if (!cached.isConnected) {
642
- this.observer.unobserve(cached);
643
- this.elementsCache.delete(key);
644
- }
645
- });
646
- return;
647
- }
648
- this._measureElement(node, void 0);
649
- };
650
648
  this.getVirtualItems = memo(
651
649
  () => [this.getVirtualIndexes(), this.getMeasurements()],
652
650
  (indexes, measurements) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { approxEqual, debounce, 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 | bigint\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\nconst getRect = (element: HTMLElement): Rect => {\n const { offsetWidth, offsetHeight } = element\n return { width: offsetWidth, height: offsetHeight }\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 const targetWindow = instance.targetWindow\n if (!targetWindow) {\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(getRect(element as unknown as HTMLElement))\n\n if (!targetWindow.ResizeObserver) {\n return () => {}\n }\n\n const observer = new targetWindow.ResizeObserver((entries) => {\n const run = () => {\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(getRect(element as unknown as HTMLElement))\n }\n\n instance.options.useAnimationFrameWithResizeObserver\n ? requestAnimationFrame(run)\n : run()\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\ntype ObserveOffsetCallBack = (offset: number, isScrolling: boolean) => void\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: ObserveOffsetCallBack,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback =\n instance.options.useScrollendEvent && supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\n\n const createHandler = (isScrolling: boolean) => () => {\n const { horizontal, isRtl } = instance.options\n offset = horizontal\n ? element['scrollLeft'] * ((isRtl && -1) || 1)\n : element['scrollTop']\n fallback()\n cb(offset, isScrolling)\n }\n const handler = createHandler(true)\n const endHandler = createHandler(false)\n\n element.addEventListener('scroll', handler, addEventListenerOptions)\n const registerScrollendEvent =\n instance.options.useScrollendEvent && supportsScrollend\n if (registerScrollendEvent) {\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n }\n return () => {\n element.removeEventListener('scroll', handler)\n if (registerScrollendEvent) {\n element.removeEventListener('scrollend', endHandler)\n }\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: ObserveOffsetCallBack,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback =\n instance.options.useScrollendEvent && supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\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\n element.addEventListener('scroll', handler, addEventListenerOptions)\n const registerScrollendEvent =\n instance.options.useScrollendEvent && supportsScrollend\n if (registerScrollendEvent) {\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n }\n return () => {\n element.removeEventListener('scroll', handler)\n if (registerScrollendEvent) {\n element.removeEventListener('scrollend', endHandler)\n }\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\n return (element as unknown as HTMLElement)[\n instance.options.horizontal ? 'offsetWidth' : 'offsetHeight'\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: ObserveOffsetCallBack,\n ) => void | (() => void)\n // Optional\n debug?: boolean\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) => Array<number>\n scrollMargin?: number\n gap?: number\n indexAttribute?: string\n initialMeasurementsCache?: Array<VirtualItem>\n lanes?: number\n isScrollingResetDelay?: number\n useScrollendEvent?: boolean\n enabled?: boolean\n isRtl?: boolean\n useAnimationFrameWithResizeObserver?: boolean\n}\n\ntype ScrollState = {\n // what we want\n index: number | null\n align: ScrollAlignment\n behavior: ScrollBehavior\n\n // lifecycle\n startedAt: number\n\n // target tracking\n lastTargetOffset: number\n\n // settling\n stableFrames: number\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: Array<void | (() => void)> = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n targetWindow: (Window & typeof globalThis) | null = null\n isScrolling = false\n private scrollState: ScrollState | null = null\n measurementsCache: Array<VirtualItem> = []\n private itemSizeCache = new Map<Key, number>()\n private laneAssignments = new Map<number, number>() // index → lane cache\n private pendingMeasuredCacheIndexes: Array<number> = []\n private prevLanes: number | undefined = undefined\n private lanesChangedFlag = false\n private lanesSettling = false\n scrollRect: Rect | null = null\n scrollOffset: number | null = null\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments = 0\n shouldAdjustScrollPositionOnItemSizeChange:\n | undefined\n | ((\n item: VirtualItem,\n delta: number,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => boolean)\n elementsCache = new Map<Key, TItemElement>()\n private now = () => this.targetWindow?.performance?.now?.() ?? Date.now()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n }\n\n if (!this.targetWindow || !this.targetWindow.ResizeObserver) {\n return null\n }\n\n return (_ro = new this.targetWindow.ResizeObserver((entries) => {\n entries.forEach((entry) => {\n const run = () => {\n this._measureElement(entry.target as TItemElement, entry)\n }\n this.options.useAnimationFrameWithResizeObserver\n ? requestAnimationFrame(run)\n : run()\n })\n }))\n }\n\n return {\n disconnect: () => {\n get()?.disconnect()\n _ro = null\n },\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 }\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 enabled: true,\n isRtl: false,\n useScrollendEvent: false,\n useAnimationFrameWithResizeObserver: false,\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.observer.disconnect()\n if (this.rafId != null && this.targetWindow) {\n this.targetWindow.cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n this.scrollState = null\n this.scrollElement = null\n this.targetWindow = null\n }\n\n _didMount = () => {\n return () => {\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.enabled\n ? this.options.getScrollElement()\n : null\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n if (!scrollElement) {\n this.maybeNotify()\n return\n }\n\n this.scrollElement = scrollElement\n\n if (this.scrollElement && 'ownerDocument' in this.scrollElement) {\n this.targetWindow = this.scrollElement.ownerDocument.defaultView\n } else {\n this.targetWindow = this.scrollElement?.window ?? null\n }\n\n this.elementsCache.forEach((cached) => {\n this.observer.observe(cached)\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, isScrolling) => {\n this.scrollAdjustments = 0\n this.scrollDirection = isScrolling\n ? this.getScrollOffset() < offset\n ? 'forward'\n : 'backward'\n : null\n this.scrollOffset = offset\n this.isScrolling = isScrolling\n\n if (this.scrollState) {\n this.scheduleScrollReconcile()\n }\n this.maybeNotify()\n }),\n )\n\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: undefined,\n behavior: undefined,\n })\n }\n }\n\n private rafId: number | null = null\n private scheduleScrollReconcile() {\n if (!this.targetWindow) {\n this.scrollState = null\n return\n }\n if (this.rafId != null) return\n this.rafId = this.targetWindow.requestAnimationFrame(() => {\n this.rafId = null\n this.reconcileScroll()\n })\n }\n private reconcileScroll() {\n if (!this.scrollState) return\n\n const el = this.scrollElement\n if (!el) return\n\n // Safety valve: bail out if reconciliation has been running too long\n const MAX_RECONCILE_MS = 5000\n if (this.now() - this.scrollState.startedAt > MAX_RECONCILE_MS) {\n this.scrollState = null\n return\n }\n\n const offsetInfo =\n this.scrollState.index != null\n ? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align)\n : undefined\n const targetOffset = offsetInfo\n ? offsetInfo[0]\n : this.scrollState.lastTargetOffset\n\n // Require one stable frame where target matches scroll offset.\n // approxEqual() already tolerates minor fluctuations, so one frame is sufficient\n // to confirm scroll has reached its target without premature cleanup.\n const STABLE_FRAMES = 1\n\n const targetChanged = targetOffset !== this.scrollState.lastTargetOffset\n\n if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) {\n this.scrollState.stableFrames++\n if (this.scrollState.stableFrames >= STABLE_FRAMES) {\n this.scrollState = null\n return\n }\n } else {\n this.scrollState.stableFrames = 0\n\n if (targetChanged) {\n this.scrollState.lastTargetOffset = targetOffset\n // Switch to 'auto' behavior once measurements cause target to change\n // We want to jump directly to the correct position, not smoothly animate to it\n this.scrollState.behavior = 'auto'\n\n this._scrollToOffset(targetOffset, {\n adjustments: undefined,\n behavior: 'auto',\n })\n }\n }\n\n // Always reschedule while scrollState is active to guarantee\n // the safety valve timeout runs even if no scroll events fire\n // (e.g. no-op scrollToFn, detached element)\n this.scheduleScrollReconcile()\n }\n\n private getSize = () => {\n if (!this.options.enabled) {\n this.scrollRect = null\n return 0\n }\n\n this.scrollRect = this.scrollRect ?? this.options.initialRect\n\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private getScrollOffset = () => {\n if (!this.options.enabled) {\n this.scrollOffset = null\n return 0\n }\n\n this.scrollOffset =\n this.scrollOffset ??\n (typeof this.options.initialOffset === 'function'\n ? this.options.initialOffset()\n : this.options.initialOffset)\n\n return this.scrollOffset\n }\n\n private getFurthestMeasurement = (\n measurements: Array<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 getMeasurementOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.options.enabled,\n this.options.lanes,\n ],\n (count, paddingStart, scrollMargin, getItemKey, enabled, lanes) => {\n const lanesChanged =\n this.prevLanes !== undefined && this.prevLanes !== lanes\n\n if (lanesChanged) {\n // Set flag for getMeasurements to handle\n this.lanesChangedFlag = true\n }\n\n this.prevLanes = lanes\n this.pendingMeasuredCacheIndexes = []\n\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n enabled,\n lanes,\n }\n },\n {\n key: false,\n },\n )\n\n private getMeasurements = memo(\n () => [this.getMeasurementOptions(), this.itemSizeCache],\n (\n { count, paddingStart, scrollMargin, getItemKey, enabled, lanes },\n itemSizeCache,\n ) => {\n if (!enabled) {\n this.measurementsCache = []\n this.itemSizeCache.clear()\n this.laneAssignments.clear()\n return []\n }\n\n // Clean up stale lane cache entries when count decreases\n if (this.laneAssignments.size > count) {\n for (const index of this.laneAssignments.keys()) {\n if (index >= count) {\n this.laneAssignments.delete(index)\n }\n }\n }\n\n // ✅ Force complete recalculation when lanes change\n if (this.lanesChangedFlag) {\n this.lanesChangedFlag = false // Reset immediately\n this.lanesSettling = true // Start settling period\n this.measurementsCache = []\n this.itemSizeCache.clear()\n this.laneAssignments.clear() // Clear lane cache for new lane count\n // Clear pending indexes to force min = 0\n this.pendingMeasuredCacheIndexes = []\n }\n\n // Don't restore from initialMeasurementsCache during lane changes\n // as it contains stale lane assignments from the previous lane count\n if (this.measurementsCache.length === 0 && !this.lanesSettling) {\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n }\n\n // ✅ During lanes settling, ignore pendingMeasuredCacheIndexes to prevent repositioning\n const min = this.lanesSettling\n ? 0\n : this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n // ✅ End settling period when cache is fully built\n if (this.lanesSettling && this.measurementsCache.length === count) {\n this.lanesSettling = false\n }\n\n const measurements = this.measurementsCache.slice(0, min)\n\n // ✅ Performance: Track last item index per lane for O(1) lookup\n const laneLastIndex: Array<number | undefined> = new Array(lanes).fill(\n undefined,\n )\n\n // Initialize from existing measurements (before min)\n for (let m = 0; m < min; m++) {\n const item = measurements[m]\n if (item) {\n laneLastIndex[item.lane] = m\n }\n }\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n\n // Check for cached lane assignment\n const cachedLane = this.laneAssignments.get(i)\n let lane: number\n let start: number\n\n if (cachedLane !== undefined && this.options.lanes > 1) {\n // Use cached lane - O(1) lookup for previous item in same lane\n lane = cachedLane\n const prevIndex = laneLastIndex[lane]\n const prevInLane =\n prevIndex !== undefined ? measurements[prevIndex] : undefined\n start = prevInLane\n ? prevInLane.end + this.options.gap\n : paddingStart + scrollMargin\n } else {\n // No cache - use original logic (find shortest lane)\n const furthestMeasurement =\n this.options.lanes === 1\n ? measurements[i - 1]\n : this.getFurthestMeasurement(measurements, i)\n\n start = furthestMeasurement\n ? furthestMeasurement.end + this.options.gap\n : paddingStart + scrollMargin\n\n lane = furthestMeasurement\n ? furthestMeasurement.lane\n : i % this.options.lanes\n\n // Cache the lane assignment\n if (this.options.lanes > 1) {\n this.laneAssignments.set(i, lane)\n }\n }\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 measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane,\n }\n\n // ✅ Performance: Update lane's last item index\n laneLastIndex[lane] = i\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 () => [\n this.getMeasurements(),\n this.getSize(),\n this.getScrollOffset(),\n this.options.lanes,\n ],\n (measurements, outerSize, scrollOffset, lanes) => {\n return (this.range =\n measurements.length > 0 && outerSize > 0\n ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n lanes,\n })\n : null)\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualIndexes = memo(\n () => {\n let startIndex: number | null = null\n let endIndex: number | null = null\n const range = this.calculateRange()\n if (range) {\n startIndex = range.startIndex\n endIndex = range.endIndex\n }\n this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex])\n return [\n this.options.rangeExtractor,\n this.options.overscan,\n this.options.count,\n startIndex,\n endIndex,\n ]\n },\n (rangeExtractor, overscan, count, startIndex, endIndex) => {\n return startIndex === null || endIndex === null\n ? []\n : rangeExtractor({\n startIndex,\n endIndex,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getVirtualIndexes',\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 /**\n * Determines if an item at the given index should be measured during smooth scroll.\n * During smooth scroll, only items within a buffer range around the target are measured\n * to prevent items far from the target from pushing it away.\n */\n private shouldMeasureDuringScroll = (index: number): boolean => {\n // No scroll state or not smooth scroll - always allow measurements\n if (!this.scrollState || this.scrollState.behavior !== 'smooth') {\n return true\n }\n\n const scrollIndex =\n this.scrollState.index ??\n this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)?.index\n\n if (scrollIndex !== undefined && this.range) {\n // Allow measurements within a buffer range around the scroll target\n const bufferSize = Math.max(\n this.options.overscan,\n Math.ceil((this.range.endIndex - this.range.startIndex) / 2),\n )\n const minIndex = Math.max(0, scrollIndex - bufferSize)\n const maxIndex = Math.min(\n this.options.count - 1,\n scrollIndex + bufferSize,\n )\n return index >= minIndex && index <= maxIndex\n }\n\n return true\n }\n\n private _measureElement = (\n node: TItemElement,\n entry: ResizeObserverEntry | undefined,\n ) => {\n if (!node.isConnected) {\n this.observer.unobserve(node)\n return\n }\n\n const index = this.indexFromElement(node)\n const item = this.measurementsCache[index]\n if (!item) {\n return\n }\n const key = item.key\n const prevNode = this.elementsCache.get(key)\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.elementsCache.set(key, node)\n }\n\n if (this.shouldMeasureDuringScroll(index)) {\n this.resizeItem(index, this.options.measureElement(node, entry, this))\n }\n }\n\n resizeItem = (index: number, size: number) => {\n const item = this.measurementsCache[index]\n if (!item) {\n return\n }\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n const delta = size - itemSize\n\n if (delta !== 0) {\n if (\n this.scrollState?.behavior !== 'smooth' &&\n (this.shouldAdjustScrollPositionOnItemSizeChange !== undefined\n ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this)\n : item.start < this.getScrollOffset() + this.scrollAdjustments)\n ) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n this._scrollToOffset(this.getScrollOffset(), {\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 | undefined) => {\n if (!node) {\n this.elementsCache.forEach((cached, key) => {\n if (!cached.isConnected) {\n this.observer.unobserve(cached)\n this.elementsCache.delete(key)\n }\n })\n return\n }\n\n this._measureElement(node, undefined)\n }\n\n getVirtualItems = memo(\n () => [this.getVirtualIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: Array<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' && 'getVirtualItems',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n if (measurements.length === 0) {\n return undefined\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 private getMaxScrollOffset = () => {\n if (!this.scrollElement) return 0\n\n if ('scrollHeight' in this.scrollElement) {\n // Element\n return this.options.horizontal\n ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth\n : this.scrollElement.scrollHeight - this.scrollElement.clientHeight\n } else {\n // Window\n const doc = this.scrollElement.document.documentElement\n return this.options.horizontal\n ? doc.scrollWidth - this.scrollElement.innerWidth\n : doc.scrollHeight - this.scrollElement.innerHeight\n }\n }\n\n getOffsetForAlignment = (\n toOffset: number,\n align: ScrollAlignment,\n itemSize = 0,\n ) => {\n if (!this.scrollElement) return 0\n\n const size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n if (align === 'auto') {\n align = toOffset >= scrollOffset + size ? 'end' : 'start'\n }\n\n if (align === 'center') {\n // When aligning to a particular item (e.g. with scrollToIndex),\n // adjust offset by the size of the item to center on the item\n toOffset += (itemSize - size) / 2\n } else if (align === 'end') {\n toOffset -= size\n }\n\n const maxOffset = this.getMaxScrollOffset()\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 size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n const item = this.measurementsCache[index]\n if (!item) return\n\n if (align === 'auto') {\n if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {\n align = 'end'\n } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {\n align = 'start'\n } else {\n return [scrollOffset, align] as const\n }\n }\n\n // For the last item with 'end' alignment, use browser's actual max scroll\n // to account for borders/padding that aren't in our measurements\n if (align === 'end' && index === this.options.count - 1) {\n return [this.getMaxScrollOffset(), align] as const\n }\n\n const toOffset =\n align === 'end'\n ? item.end + this.options.scrollPaddingEnd\n : item.start - this.options.scrollPaddingStart\n\n return [\n this.getOffsetForAlignment(toOffset, align, item.size),\n align,\n ] as const\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior = 'auto' }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.getOffsetForAlignment(toOffset, align)\n\n const now = this.now()\n this.scrollState = {\n index: null,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\n }\n\n scrollToIndex = (\n index: number,\n {\n align: initialAlign = 'auto',\n behavior = 'auto',\n }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const offsetInfo = this.getOffsetForIndex(index, initialAlign)\n if (!offsetInfo) {\n return\n }\n const [offset, align] = offsetInfo\n\n const now = this.now()\n this.scrollState = {\n index,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\n }\n\n scrollBy = (\n delta: number,\n { behavior = 'auto' }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.getScrollOffset() + delta\n const now = this.now()\n\n this.scrollState = {\n index: null,\n align: 'start',\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\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 there is only one lane, use the last measurement's end\n // Otherwise find the maximum end value among all measurements\n if (measurements.length === 0) {\n end = this.options.paddingStart\n } else if (this.options.lanes === 1) {\n end = measurements[measurements.length - 1]?.end ?? 0\n } else {\n const endByLane = Array<number | null>(this.options.lanes).fill(null)\n let endIndex = measurements.length - 1\n while (endIndex >= 0 && endByLane.some((val) => val === null)) {\n const item = measurements[endIndex]!\n if (endByLane[item.lane] === null) {\n endByLane[item.lane] = item.end\n }\n\n endIndex--\n }\n\n end = Math.max(...endByLane.filter((val): val is number => val !== null))\n }\n\n return Math.max(\n end - this.options.scrollMargin + this.options.paddingEnd,\n 0,\n )\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.laneAssignments = new Map() // Clear lane cache for full re-layout\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 lanes,\n}: {\n measurements: Array<VirtualItem>\n outerSize: number\n scrollOffset: number\n lanes: number\n}) {\n const lastIndex = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n // handle case when item count is less than or equal to lanes\n if (measurements.length <= lanes) {\n return {\n startIndex: 0,\n endIndex: lastIndex,\n }\n }\n\n let startIndex = findNearestBinarySearch(\n 0,\n lastIndex,\n getOffset,\n scrollOffset,\n )\n let endIndex = startIndex\n\n if (lanes === 1) {\n while (\n endIndex < lastIndex &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n } else if (lanes > 1) {\n // Expand forward until we include the visible items from all lanes\n // which are closer to the end of the virtualizer window\n const endPerLane = Array(lanes).fill(0)\n while (\n endIndex < lastIndex &&\n endPerLane.some((pos) => pos < scrollOffset + outerSize)\n ) {\n const item = measurements[endIndex]!\n endPerLane[item.lane] = item.end\n endIndex++\n }\n\n // Expand backward until we include all lanes' visible items\n // closer to the top\n const startPerLane = Array(lanes).fill(scrollOffset + outerSize)\n while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {\n const item = measurements[startIndex]!\n startPerLane[item.lane] = item.start\n startIndex--\n }\n\n // Align startIndex to the beginning of its lane\n startIndex = Math.max(0, startIndex - (startIndex % lanes))\n // Align endIndex to the end of its lane\n endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - (endIndex % lanes)))\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["opts"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { approxEqual, debounce, 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' | 'instant'\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 | bigint\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\nconst getRect = (element: HTMLElement): Rect => {\n const { offsetWidth, offsetHeight } = element\n return { width: offsetWidth, height: offsetHeight }\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 const targetWindow = instance.targetWindow\n if (!targetWindow) {\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(getRect(element as unknown as HTMLElement))\n\n if (!targetWindow.ResizeObserver) {\n return () => {}\n }\n\n const observer = new targetWindow.ResizeObserver((entries) => {\n const run = () => {\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(getRect(element as unknown as HTMLElement))\n }\n\n instance.options.useAnimationFrameWithResizeObserver\n ? requestAnimationFrame(run)\n : run()\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\ntype ObserveOffsetCallBack = (offset: number, isScrolling: boolean) => void\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: ObserveOffsetCallBack,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback =\n instance.options.useScrollendEvent && supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\n\n const createHandler = (isScrolling: boolean) => () => {\n const { horizontal, isRtl } = instance.options\n offset = horizontal\n ? element['scrollLeft'] * ((isRtl && -1) || 1)\n : element['scrollTop']\n fallback()\n cb(offset, isScrolling)\n }\n const handler = createHandler(true)\n const endHandler = createHandler(false)\n\n element.addEventListener('scroll', handler, addEventListenerOptions)\n const registerScrollendEvent =\n instance.options.useScrollendEvent && supportsScrollend\n if (registerScrollendEvent) {\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n }\n return () => {\n element.removeEventListener('scroll', handler)\n if (registerScrollendEvent) {\n element.removeEventListener('scrollend', endHandler)\n }\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: ObserveOffsetCallBack,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n const targetWindow = instance.targetWindow\n if (!targetWindow) {\n return\n }\n\n let offset = 0\n const fallback =\n instance.options.useScrollendEvent && supportsScrollend\n ? () => undefined\n : debounce(\n targetWindow,\n () => {\n cb(offset, false)\n },\n instance.options.isScrollingResetDelay,\n )\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\n element.addEventListener('scroll', handler, addEventListenerOptions)\n const registerScrollendEvent =\n instance.options.useScrollendEvent && supportsScrollend\n if (registerScrollendEvent) {\n element.addEventListener('scrollend', endHandler, addEventListenerOptions)\n }\n return () => {\n element.removeEventListener('scroll', handler)\n if (registerScrollendEvent) {\n element.removeEventListener('scrollend', endHandler)\n }\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\n return (element as unknown as HTMLElement)[\n instance.options.horizontal ? 'offsetWidth' : 'offsetHeight'\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: ObserveOffsetCallBack,\n ) => void | (() => void)\n // Optional\n debug?: boolean\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) => Array<number>\n scrollMargin?: number\n gap?: number\n indexAttribute?: string\n initialMeasurementsCache?: Array<VirtualItem>\n lanes?: number\n isScrollingResetDelay?: number\n useScrollendEvent?: boolean\n enabled?: boolean\n isRtl?: boolean\n useAnimationFrameWithResizeObserver?: boolean\n}\n\ntype ScrollState = {\n // what we want\n index: number | null\n align: ScrollAlignment\n behavior: ScrollBehavior\n\n // lifecycle\n startedAt: number\n\n // target tracking\n lastTargetOffset: number\n\n // settling\n stableFrames: number\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: Array<void | (() => void)> = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n targetWindow: (Window & typeof globalThis) | null = null\n isScrolling = false\n private scrollState: ScrollState | null = null\n measurementsCache: Array<VirtualItem> = []\n private itemSizeCache = new Map<Key, number>()\n private laneAssignments = new Map<number, number>() // index → lane cache\n private pendingMeasuredCacheIndexes: Array<number> = []\n private prevLanes: number | undefined = undefined\n private lanesChangedFlag = false\n private lanesSettling = false\n scrollRect: Rect | null = null\n scrollOffset: number | null = null\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments = 0\n shouldAdjustScrollPositionOnItemSizeChange:\n | undefined\n | ((\n item: VirtualItem,\n delta: number,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => boolean)\n elementsCache = new Map<Key, TItemElement>()\n private now = () => this.targetWindow?.performance?.now?.() ?? Date.now()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n }\n\n if (!this.targetWindow || !this.targetWindow.ResizeObserver) {\n return null\n }\n\n return (_ro = new this.targetWindow.ResizeObserver((entries) => {\n entries.forEach((entry) => {\n const run = () => {\n const node = entry.target as TItemElement\n const index = this.indexFromElement(node)\n\n if (!node.isConnected) {\n this.observer.unobserve(node)\n return\n }\n\n if (this.shouldMeasureDuringScroll(index)) {\n this.resizeItem(\n index,\n this.options.measureElement(node, entry, this),\n )\n }\n }\n this.options.useAnimationFrameWithResizeObserver\n ? requestAnimationFrame(run)\n : run()\n })\n }))\n }\n\n return {\n disconnect: () => {\n get()?.disconnect()\n _ro = null\n },\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 }\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 enabled: true,\n isRtl: false,\n useScrollendEvent: false,\n useAnimationFrameWithResizeObserver: false,\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.observer.disconnect()\n if (this.rafId != null && this.targetWindow) {\n this.targetWindow.cancelAnimationFrame(this.rafId)\n this.rafId = null\n }\n this.scrollState = null\n this.scrollElement = null\n this.targetWindow = null\n }\n\n _didMount = () => {\n return () => {\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.enabled\n ? this.options.getScrollElement()\n : null\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n if (!scrollElement) {\n this.maybeNotify()\n return\n }\n\n this.scrollElement = scrollElement\n\n if (this.scrollElement && 'ownerDocument' in this.scrollElement) {\n this.targetWindow = this.scrollElement.ownerDocument.defaultView\n } else {\n this.targetWindow = this.scrollElement?.window ?? null\n }\n\n this.elementsCache.forEach((cached) => {\n this.observer.observe(cached)\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, isScrolling) => {\n this.scrollAdjustments = 0\n this.scrollDirection = isScrolling\n ? this.getScrollOffset() < offset\n ? 'forward'\n : 'backward'\n : null\n this.scrollOffset = offset\n this.isScrolling = isScrolling\n\n if (this.scrollState) {\n this.scheduleScrollReconcile()\n }\n this.maybeNotify()\n }),\n )\n\n this._scrollToOffset(this.getScrollOffset(), {\n adjustments: undefined,\n behavior: undefined,\n })\n }\n }\n\n private rafId: number | null = null\n private scheduleScrollReconcile() {\n if (!this.targetWindow) {\n this.scrollState = null\n return\n }\n if (this.rafId != null) return\n this.rafId = this.targetWindow.requestAnimationFrame(() => {\n this.rafId = null\n this.reconcileScroll()\n })\n }\n private reconcileScroll() {\n if (!this.scrollState) return\n\n const el = this.scrollElement\n if (!el) return\n\n // Safety valve: bail out if reconciliation has been running too long\n const MAX_RECONCILE_MS = 5000\n if (this.now() - this.scrollState.startedAt > MAX_RECONCILE_MS) {\n this.scrollState = null\n return\n }\n\n const offsetInfo =\n this.scrollState.index != null\n ? this.getOffsetForIndex(this.scrollState.index, this.scrollState.align)\n : undefined\n const targetOffset = offsetInfo\n ? offsetInfo[0]\n : this.scrollState.lastTargetOffset\n\n // Require one stable frame where target matches scroll offset.\n // approxEqual() already tolerates minor fluctuations, so one frame is sufficient\n // to confirm scroll has reached its target without premature cleanup.\n const STABLE_FRAMES = 1\n\n const targetChanged = targetOffset !== this.scrollState.lastTargetOffset\n\n if (!targetChanged && approxEqual(targetOffset, this.getScrollOffset())) {\n this.scrollState.stableFrames++\n if (this.scrollState.stableFrames >= STABLE_FRAMES) {\n this.scrollState = null\n return\n }\n } else {\n this.scrollState.stableFrames = 0\n\n if (targetChanged) {\n this.scrollState.lastTargetOffset = targetOffset\n // Switch to 'auto' behavior once measurements cause target to change\n // We want to jump directly to the correct position, not smoothly animate to it\n this.scrollState.behavior = 'auto'\n\n this._scrollToOffset(targetOffset, {\n adjustments: undefined,\n behavior: 'auto',\n })\n }\n }\n\n // Always reschedule while scrollState is active to guarantee\n // the safety valve timeout runs even if no scroll events fire\n // (e.g. no-op scrollToFn, detached element)\n this.scheduleScrollReconcile()\n }\n\n private getSize = () => {\n if (!this.options.enabled) {\n this.scrollRect = null\n return 0\n }\n\n this.scrollRect = this.scrollRect ?? this.options.initialRect\n\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private getScrollOffset = () => {\n if (!this.options.enabled) {\n this.scrollOffset = null\n return 0\n }\n\n this.scrollOffset =\n this.scrollOffset ??\n (typeof this.options.initialOffset === 'function'\n ? this.options.initialOffset()\n : this.options.initialOffset)\n\n return this.scrollOffset\n }\n\n private getFurthestMeasurement = (\n measurements: Array<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 getMeasurementOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.options.enabled,\n this.options.lanes,\n ],\n (count, paddingStart, scrollMargin, getItemKey, enabled, lanes) => {\n const lanesChanged =\n this.prevLanes !== undefined && this.prevLanes !== lanes\n\n if (lanesChanged) {\n // Set flag for getMeasurements to handle\n this.lanesChangedFlag = true\n }\n\n this.prevLanes = lanes\n this.pendingMeasuredCacheIndexes = []\n\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n enabled,\n lanes,\n }\n },\n {\n key: false,\n },\n )\n\n private getMeasurements = memo(\n () => [this.getMeasurementOptions(), this.itemSizeCache],\n (\n { count, paddingStart, scrollMargin, getItemKey, enabled, lanes },\n itemSizeCache,\n ) => {\n if (!enabled) {\n this.measurementsCache = []\n this.itemSizeCache.clear()\n this.laneAssignments.clear()\n return []\n }\n\n // Clean up stale lane cache entries when count decreases\n if (this.laneAssignments.size > count) {\n for (const index of this.laneAssignments.keys()) {\n if (index >= count) {\n this.laneAssignments.delete(index)\n }\n }\n }\n\n // ✅ Force complete recalculation when lanes change\n if (this.lanesChangedFlag) {\n this.lanesChangedFlag = false // Reset immediately\n this.lanesSettling = true // Start settling period\n this.measurementsCache = []\n this.itemSizeCache.clear()\n this.laneAssignments.clear() // Clear lane cache for new lane count\n // Clear pending indexes to force min = 0\n this.pendingMeasuredCacheIndexes = []\n }\n\n // Don't restore from initialMeasurementsCache during lane changes\n // as it contains stale lane assignments from the previous lane count\n if (this.measurementsCache.length === 0 && !this.lanesSettling) {\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n }\n\n // ✅ During lanes settling, ignore pendingMeasuredCacheIndexes to prevent repositioning\n const min = this.lanesSettling\n ? 0\n : this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n // ✅ End settling period when cache is fully built\n if (this.lanesSettling && this.measurementsCache.length === count) {\n this.lanesSettling = false\n }\n\n const measurements = this.measurementsCache.slice(0, min)\n\n // ✅ Performance: Track last item index per lane for O(1) lookup\n const laneLastIndex: Array<number | undefined> = new Array(lanes).fill(\n undefined,\n )\n\n // Initialize from existing measurements (before min)\n for (let m = 0; m < min; m++) {\n const item = measurements[m]\n if (item) {\n laneLastIndex[item.lane] = m\n }\n }\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n\n // Check for cached lane assignment\n const cachedLane = this.laneAssignments.get(i)\n let lane: number\n let start: number\n\n if (cachedLane !== undefined && this.options.lanes > 1) {\n // Use cached lane - O(1) lookup for previous item in same lane\n lane = cachedLane\n const prevIndex = laneLastIndex[lane]\n const prevInLane =\n prevIndex !== undefined ? measurements[prevIndex] : undefined\n start = prevInLane\n ? prevInLane.end + this.options.gap\n : paddingStart + scrollMargin\n } else {\n // No cache - use original logic (find shortest lane)\n const furthestMeasurement =\n this.options.lanes === 1\n ? measurements[i - 1]\n : this.getFurthestMeasurement(measurements, i)\n\n start = furthestMeasurement\n ? furthestMeasurement.end + this.options.gap\n : paddingStart + scrollMargin\n\n lane = furthestMeasurement\n ? furthestMeasurement.lane\n : i % this.options.lanes\n\n // Cache the lane assignment\n if (this.options.lanes > 1) {\n this.laneAssignments.set(i, lane)\n }\n }\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 measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane,\n }\n\n // ✅ Performance: Update lane's last item index\n laneLastIndex[lane] = i\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 () => [\n this.getMeasurements(),\n this.getSize(),\n this.getScrollOffset(),\n this.options.lanes,\n ],\n (measurements, outerSize, scrollOffset, lanes) => {\n return (this.range =\n measurements.length > 0 && outerSize > 0\n ? calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n lanes,\n })\n : null)\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualIndexes = memo(\n () => {\n let startIndex: number | null = null\n let endIndex: number | null = null\n const range = this.calculateRange()\n if (range) {\n startIndex = range.startIndex\n endIndex = range.endIndex\n }\n this.maybeNotify.updateDeps([this.isScrolling, startIndex, endIndex])\n return [\n this.options.rangeExtractor,\n this.options.overscan,\n this.options.count,\n startIndex,\n endIndex,\n ]\n },\n (rangeExtractor, overscan, count, startIndex, endIndex) => {\n return startIndex === null || endIndex === null\n ? []\n : rangeExtractor({\n startIndex,\n endIndex,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getVirtualIndexes',\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 /**\n * Determines if an item at the given index should be measured during smooth scroll.\n * During smooth scroll, only items within a buffer range around the target are measured\n * to prevent items far from the target from pushing it away.\n */\n private shouldMeasureDuringScroll = (index: number): boolean => {\n // No scroll state or not smooth scroll - always allow measurements\n if (!this.scrollState || this.scrollState.behavior !== 'smooth') {\n return true\n }\n\n const scrollIndex =\n this.scrollState.index ??\n this.getVirtualItemForOffset(this.scrollState.lastTargetOffset)?.index\n\n if (scrollIndex !== undefined && this.range) {\n // Allow measurements within a buffer range around the scroll target\n const bufferSize = Math.max(\n this.options.overscan,\n Math.ceil((this.range.endIndex - this.range.startIndex) / 2),\n )\n const minIndex = Math.max(0, scrollIndex - bufferSize)\n const maxIndex = Math.min(\n this.options.count - 1,\n scrollIndex + bufferSize,\n )\n return index >= minIndex && index <= maxIndex\n }\n\n return true\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n this.elementsCache.forEach((cached, key) => {\n if (!cached.isConnected) {\n this.observer.unobserve(cached)\n this.elementsCache.delete(key)\n }\n })\n return\n }\n\n const index = this.indexFromElement(node)\n const key = this.options.getItemKey(index)\n const prevNode = this.elementsCache.get(key)\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.elementsCache.set(key, node)\n }\n\n // Sync-measure when idle (initial render) or during programmatic scrolling\n // (scrollToIndex/scrollToOffset) where reconcileScroll needs sizes in the same frame.\n // During normal user scrolling, skip sync measurement — the RO callback handles it async.\n if (\n (!this.isScrolling || this.scrollState) &&\n this.shouldMeasureDuringScroll(index)\n ) {\n this.resizeItem(index, this.options.measureElement(node, undefined, this))\n }\n }\n\n resizeItem = (index: number, size: number) => {\n const item = this.measurementsCache[index]\n if (!item) return\n\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n const delta = size - itemSize\n\n if (delta !== 0) {\n if (\n this.scrollState?.behavior !== 'smooth' &&\n (this.shouldAdjustScrollPositionOnItemSizeChange !== undefined\n ? this.shouldAdjustScrollPositionOnItemSizeChange(item, delta, this)\n : item.start < this.getScrollOffset() + this.scrollAdjustments)\n ) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n this._scrollToOffset(this.getScrollOffset(), {\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 getVirtualItems = memo(\n () => [this.getVirtualIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: Array<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' && 'getVirtualItems',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n if (measurements.length === 0) {\n return undefined\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 private getMaxScrollOffset = () => {\n if (!this.scrollElement) return 0\n\n if ('scrollHeight' in this.scrollElement) {\n // Element\n return this.options.horizontal\n ? this.scrollElement.scrollWidth - this.scrollElement.clientWidth\n : this.scrollElement.scrollHeight - this.scrollElement.clientHeight\n } else {\n // Window\n const doc = this.scrollElement.document.documentElement\n return this.options.horizontal\n ? doc.scrollWidth - this.scrollElement.innerWidth\n : doc.scrollHeight - this.scrollElement.innerHeight\n }\n }\n\n getOffsetForAlignment = (\n toOffset: number,\n align: ScrollAlignment,\n itemSize = 0,\n ) => {\n if (!this.scrollElement) return 0\n\n const size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n if (align === 'auto') {\n align = toOffset >= scrollOffset + size ? 'end' : 'start'\n }\n\n if (align === 'center') {\n // When aligning to a particular item (e.g. with scrollToIndex),\n // adjust offset by the size of the item to center on the item\n toOffset += (itemSize - size) / 2\n } else if (align === 'end') {\n toOffset -= size\n }\n\n const maxOffset = this.getMaxScrollOffset()\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 size = this.getSize()\n const scrollOffset = this.getScrollOffset()\n\n const item = this.measurementsCache[index]\n if (!item) return\n\n if (align === 'auto') {\n if (item.end >= scrollOffset + size - this.options.scrollPaddingEnd) {\n align = 'end'\n } else if (item.start <= scrollOffset + this.options.scrollPaddingStart) {\n align = 'start'\n } else {\n return [scrollOffset, align] as const\n }\n }\n\n // For the last item with 'end' alignment, use browser's actual max scroll\n // to account for borders/padding that aren't in our measurements\n if (align === 'end' && index === this.options.count - 1) {\n return [this.getMaxScrollOffset(), align] as const\n }\n\n const toOffset =\n align === 'end'\n ? item.end + this.options.scrollPaddingEnd\n : item.start - this.options.scrollPaddingStart\n\n return [\n this.getOffsetForAlignment(toOffset, align, item.size),\n align,\n ] as const\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior = 'auto' }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.getOffsetForAlignment(toOffset, align)\n\n const now = this.now()\n this.scrollState = {\n index: null,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\n }\n\n scrollToIndex = (\n index: number,\n {\n align: initialAlign = 'auto',\n behavior = 'auto',\n }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const offsetInfo = this.getOffsetForIndex(index, initialAlign)\n if (!offsetInfo) {\n return\n }\n const [offset, align] = offsetInfo\n\n const now = this.now()\n this.scrollState = {\n index,\n align,\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\n }\n\n scrollBy = (\n delta: number,\n { behavior = 'auto' }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.getScrollOffset() + delta\n const now = this.now()\n\n this.scrollState = {\n index: null,\n align: 'start',\n behavior,\n startedAt: now,\n lastTargetOffset: offset,\n stableFrames: 0,\n }\n\n this._scrollToOffset(offset, { adjustments: undefined, behavior })\n\n this.scheduleScrollReconcile()\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 there is only one lane, use the last measurement's end\n // Otherwise find the maximum end value among all measurements\n if (measurements.length === 0) {\n end = this.options.paddingStart\n } else if (this.options.lanes === 1) {\n end = measurements[measurements.length - 1]?.end ?? 0\n } else {\n const endByLane = Array<number | null>(this.options.lanes).fill(null)\n let endIndex = measurements.length - 1\n while (endIndex >= 0 && endByLane.some((val) => val === null)) {\n const item = measurements[endIndex]!\n if (endByLane[item.lane] === null) {\n endByLane[item.lane] = item.end\n }\n\n endIndex--\n }\n\n end = Math.max(...endByLane.filter((val): val is number => val !== null))\n }\n\n return Math.max(\n end - this.options.scrollMargin + this.options.paddingEnd,\n 0,\n )\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.laneAssignments = new Map() // Clear lane cache for full re-layout\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 lanes,\n}: {\n measurements: Array<VirtualItem>\n outerSize: number\n scrollOffset: number\n lanes: number\n}) {\n const lastIndex = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n // handle case when item count is less than or equal to lanes\n if (measurements.length <= lanes) {\n return {\n startIndex: 0,\n endIndex: lastIndex,\n }\n }\n\n let startIndex = findNearestBinarySearch(\n 0,\n lastIndex,\n getOffset,\n scrollOffset,\n )\n let endIndex = startIndex\n\n if (lanes === 1) {\n while (\n endIndex < lastIndex &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n } else if (lanes > 1) {\n // Expand forward until we include the visible items from all lanes\n // which are closer to the end of the virtualizer window\n const endPerLane = Array(lanes).fill(0)\n while (\n endIndex < lastIndex &&\n endPerLane.some((pos) => pos < scrollOffset + outerSize)\n ) {\n const item = measurements[endIndex]!\n endPerLane[item.lane] = item.end\n endIndex++\n }\n\n // Expand backward until we include all lanes' visible items\n // closer to the top\n const startPerLane = Array(lanes).fill(scrollOffset + outerSize)\n while (startIndex >= 0 && startPerLane.some((pos) => pos >= scrollOffset)) {\n const item = measurements[startIndex]!\n startPerLane[item.lane] = item.start\n startIndex--\n }\n\n // Align startIndex to the beginning of its lane\n startIndex = Math.max(0, startIndex - (startIndex % lanes))\n // Align endIndex to the end of its lane\n endIndex = Math.min(lastIndex, endIndex + (lanes - 1 - (endIndex % lanes)))\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["opts","key"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/virtual-core",
3
- "version": "3.13.21",
3
+ "version": "3.13.23",
4
4
  "description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
package/src/index.ts CHANGED
@@ -8,7 +8,7 @@ type ScrollDirection = 'forward' | 'backward'
8
8
 
9
9
  type ScrollAlignment = 'start' | 'center' | 'end' | 'auto'
10
10
 
11
- type ScrollBehavior = 'auto' | 'smooth'
11
+ type ScrollBehavior = 'auto' | 'smooth' | 'instant'
12
12
 
13
13
  export interface ScrollToOptions {
14
14
  align?: ScrollAlignment
@@ -409,7 +409,20 @@ export class Virtualizer<
409
409
  return (_ro = new this.targetWindow.ResizeObserver((entries) => {
410
410
  entries.forEach((entry) => {
411
411
  const run = () => {
412
- this._measureElement(entry.target as TItemElement, entry)
412
+ const node = entry.target as TItemElement
413
+ const index = this.indexFromElement(node)
414
+
415
+ if (!node.isConnected) {
416
+ this.observer.unobserve(node)
417
+ return
418
+ }
419
+
420
+ if (this.shouldMeasureDuringScroll(index)) {
421
+ this.resizeItem(
422
+ index,
423
+ this.options.measureElement(node, entry, this),
424
+ )
425
+ }
413
426
  }
414
427
  this.options.useAnimationFrameWithResizeObserver
415
428
  ? requestAnimationFrame(run)
@@ -984,21 +997,19 @@ export class Virtualizer<
984
997
  return true
985
998
  }
986
999
 
987
- private _measureElement = (
988
- node: TItemElement,
989
- entry: ResizeObserverEntry | undefined,
990
- ) => {
991
- if (!node.isConnected) {
992
- this.observer.unobserve(node)
1000
+ measureElement = (node: TItemElement | null) => {
1001
+ if (!node) {
1002
+ this.elementsCache.forEach((cached, key) => {
1003
+ if (!cached.isConnected) {
1004
+ this.observer.unobserve(cached)
1005
+ this.elementsCache.delete(key)
1006
+ }
1007
+ })
993
1008
  return
994
1009
  }
995
1010
 
996
1011
  const index = this.indexFromElement(node)
997
- const item = this.measurementsCache[index]
998
- if (!item) {
999
- return
1000
- }
1001
- const key = item.key
1012
+ const key = this.options.getItemKey(index)
1002
1013
  const prevNode = this.elementsCache.get(key)
1003
1014
 
1004
1015
  if (prevNode !== node) {
@@ -1009,16 +1020,21 @@ export class Virtualizer<
1009
1020
  this.elementsCache.set(key, node)
1010
1021
  }
1011
1022
 
1012
- if (this.shouldMeasureDuringScroll(index)) {
1013
- this.resizeItem(index, this.options.measureElement(node, entry, this))
1023
+ // Sync-measure when idle (initial render) or during programmatic scrolling
1024
+ // (scrollToIndex/scrollToOffset) where reconcileScroll needs sizes in the same frame.
1025
+ // During normal user scrolling, skip sync measurement — the RO callback handles it async.
1026
+ if (
1027
+ (!this.isScrolling || this.scrollState) &&
1028
+ this.shouldMeasureDuringScroll(index)
1029
+ ) {
1030
+ this.resizeItem(index, this.options.measureElement(node, undefined, this))
1014
1031
  }
1015
1032
  }
1016
1033
 
1017
1034
  resizeItem = (index: number, size: number) => {
1018
1035
  const item = this.measurementsCache[index]
1019
- if (!item) {
1020
- return
1021
- }
1036
+ if (!item) return
1037
+
1022
1038
  const itemSize = this.itemSizeCache.get(item.key) ?? item.size
1023
1039
  const delta = size - itemSize
1024
1040
 
@@ -1045,20 +1061,6 @@ export class Virtualizer<
1045
1061
  }
1046
1062
  }
1047
1063
 
1048
- measureElement = (node: TItemElement | null | undefined) => {
1049
- if (!node) {
1050
- this.elementsCache.forEach((cached, key) => {
1051
- if (!cached.isConnected) {
1052
- this.observer.unobserve(cached)
1053
- this.elementsCache.delete(key)
1054
- }
1055
- })
1056
- return
1057
- }
1058
-
1059
- this._measureElement(node, undefined)
1060
- }
1061
-
1062
1064
  getVirtualItems = memo(
1063
1065
  () => [this.getVirtualIndexes(), this.getMeasurements()],
1064
1066
  (indexes, measurements) => {