@tanstack/virtual-core 3.0.0-beta.53 → 3.0.0-beta.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.production.js","sources":["../../src/utils.ts","../../src/index.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: false | string\n debug?: () => any\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n\n return (): TResult => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n opts?.onChange?.(result)\n\n return result!\n }\n}\n\nexport function notUndefined<T>(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1\n","import { approxEqual, memo, notUndefined } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollDirection = 'forward' | 'backward'\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ntype ScrollBehavior = 'auto' | 'smooth'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n behavior?: ScrollBehavior\n}\n\ntype ScrollToOffsetOptions = ScrollToOptions\n\ntype ScrollToIndexOptions = ScrollToOptions\n\nexport interface Range {\n startIndex: number\n endIndex: number\n overscan: number\n count: number\n}\n\ntype Key = number | string\n\nexport interface VirtualItem {\n key: Key\n index: number\n start: number\n end: number\n size: number\n}\n\ninterface Rect {\n width: number\n height: number\n}\n\n//\n\nexport const defaultKeyExtractor = (index: number) => index\n\nexport const defaultRangeExtractor = (range: Range) => {\n const start = Math.max(range.startIndex - range.overscan, 0)\n const end = Math.min(range.endIndex + range.overscan, range.count - 1)\n\n const arr = []\n\n for (let i = start; i <= end; i++) {\n arr.push(i)\n }\n\n return arr\n}\n\nexport const observeElementRect = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = (rect: Rect) => {\n const { width, height } = rect\n cb({ width: Math.round(width), height: Math.round(height) })\n }\n\n handler(element.getBoundingClientRect())\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n handler({ width: box.inlineSize, height: box.blockSize })\n return\n }\n }\n handler(element.getBoundingClientRect())\n })\n\n observer.observe(element, { box: 'border-box' })\n\n return () => {\n observer.unobserve(element)\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<Window, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight })\n }\n handler()\n\n element.addEventListener('resize', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('resize', handler)\n }\n}\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollX' : 'scrollY'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const measureElement = <TItemElement extends Element>(\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer<any, TItemElement>,\n) => {\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n const size = Math.round(\n box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],\n )\n return size\n }\n }\n return Math.round(\n element.getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ],\n )\n}\n\nexport const windowScroll = <T extends Window>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport const elementScroll = <T extends Element>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement | null\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n options: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => void\n observeElementRect: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (offset: number) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (instance: Virtualizer<TScrollElement, TItemElement>) => 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\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => number[]\n scrollMargin?: number\n scrollingDelay?: number\n indexAttribute?: string\n initialMeasurementsCache?: VirtualItem[]\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: (void | (() => void))[] = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n isScrolling: boolean = false\n private isScrollingTimeoutId: ReturnType<typeof setTimeout> | null = null\n private scrollToIndexTimeoutId: ReturnType<typeof setTimeout> | null = null\n measurementsCache: VirtualItem[] = []\n private itemSizeCache = new Map<Key, number>()\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n scrollOffset: number\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments: number = 0\n measureElementCache = new Map<Key, TItemElement>()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n } else if (typeof ResizeObserver !== 'undefined') {\n return (_ro = new ResizeObserver((entries) => {\n entries.forEach((entry) => {\n this._measureElement(entry.target as TItemElement, entry)\n })\n }))\n } else {\n return null\n }\n }\n\n return {\n disconnect: () => get()?.disconnect(),\n observe: (target: Element) =>\n get()?.observe(target, { box: 'border-box' }),\n unobserve: (target: Element) => get()?.unobserve(target),\n }\n })()\n range: { startIndex: number; endIndex: number } = {\n startIndex: 0,\n endIndex: 0,\n }\n\n constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {\n this.setOptions(opts)\n this.scrollRect = this.options.initialRect\n this.scrollOffset = this.options.initialOffset\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n\n this.maybeNotify()\n }\n\n setOptions = (opts: VirtualizerOptions<TScrollElement, TItemElement>) => {\n Object.entries(opts).forEach(([key, value]) => {\n if (typeof value === 'undefined') delete (opts as any)[key]\n })\n\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n scrollingDelay: 150,\n indexAttribute: 'data-index',\n initialMeasurementsCache: [],\n ...opts,\n }\n }\n\n private notify = () => {\n this.options.onChange?.(this)\n }\n\n private cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d!())\n this.unsubs = []\n this.scrollElement = null\n }\n\n _didMount = () => {\n this.measureElementCache.forEach(this.observer.observe)\n return () => {\n this.observer.disconnect()\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.getScrollElement()\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n this.scrollElement = scrollElement\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: undefined,\n behavior: undefined,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n const prev = this.scrollRect\n this.scrollRect = rect\n if (\n this.options.horizontal\n ? rect.width !== prev.width\n : rect.height !== prev.height\n ) {\n this.maybeNotify()\n }\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n this.scrollAdjustments = 0\n\n if (this.scrollOffset === offset) {\n return\n }\n\n if (this.isScrollingTimeoutId !== null) {\n clearTimeout(this.isScrollingTimeoutId)\n this.isScrollingTimeoutId = null\n }\n\n this.isScrolling = true\n this.scrollDirection =\n this.scrollOffset < offset ? 'forward' : 'backward'\n this.scrollOffset = offset\n\n this.maybeNotify()\n\n this.isScrollingTimeoutId = setTimeout(() => {\n this.isScrollingTimeoutId = null\n this.isScrolling = false\n this.scrollDirection = null\n\n this.maybeNotify()\n }, this.options.scrollingDelay)\n }),\n )\n }\n }\n\n private getSize = () => {\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private memoOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n ],\n (count, paddingStart, scrollMargin, getItemKey) => {\n this.pendingMeasuredCacheIndexes = []\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n }\n },\n {\n key: false,\n },\n )\n\n private getMeasurements = memo(\n () => [this.memoOptions(), this.itemSizeCache],\n ({ count, paddingStart, scrollMargin, getItemKey }, itemSizeCache) => {\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n const measuredSize = itemSizeCache.get(key)\n const start = measurements[i - 1]\n ? measurements[i - 1]!.end\n : paddingStart + scrollMargin\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n const end = start + size\n measurements[i] = { index: i, start, size, end, key }\n }\n\n this.measurementsCache = measurements\n\n return measurements\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.scrollOffset],\n (measurements, outerSize, scrollOffset) => {\n return (this.range = calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n }))\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private maybeNotify = memo(\n () => {\n const range = this.calculateRange()\n\n return [range.startIndex, range.endIndex, this.isScrolling]\n },\n () => {\n this.notify()\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'maybeNotify',\n debug: () => this.options.debug,\n initialDeps: [\n this.range.startIndex,\n this.range.endIndex,\n this.isScrolling,\n ],\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.calculateRange(),\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return rangeExtractor({\n ...range,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n indexFromElement = (node: TItemElement) => {\n const attributeName = this.options.indexAttribute\n const indexStr = node.getAttribute(attributeName)\n\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`,\n )\n return -1\n }\n\n return parseInt(indexStr, 10)\n }\n\n private _measureElement = (\n node: TItemElement,\n entry: ResizeObserverEntry | undefined,\n ) => {\n const index = this.indexFromElement(node)\n\n const item = this.measurementsCache[index]\n if (!item) {\n return\n }\n\n const prevNode = this.measureElementCache.get(item.key)\n\n if (!node.isConnected) {\n this.observer.unobserve(node)\n if (node === prevNode) {\n this.measureElementCache.delete(item.key)\n }\n return\n }\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.measureElementCache.set(item.key, node)\n }\n\n const measuredItemSize = this.options.measureElement(node, entry, this)\n\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n\n const delta = measuredItemSize - itemSize\n\n if (delta !== 0) {\n if (item.start < this.scrollOffset) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: (this.scrollAdjustments += delta),\n behavior: undefined,\n })\n }\n\n this.pendingMeasuredCacheIndexes.push(index)\n\n this.itemSizeCache = new Map(\n this.itemSizeCache.set(item.key, measuredItemSize),\n )\n\n this.notify()\n }\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n return\n }\n\n this._measureElement(node, undefined)\n }\n\n getVirtualItems = memo(\n () => [this.getIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: VirtualItem[] = []\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n virtualItems.push(measurement)\n }\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n\n return notUndefined(\n measurements[\n findNearestBinarySearch(\n 0,\n measurements.length - 1,\n (index: number) => notUndefined(measurements[index]).start,\n offset,\n )\n ],\n )\n }\n\n getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= this.scrollOffset) {\n align = 'start'\n } else if (toOffset >= this.scrollOffset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n toOffset = toOffset\n } else if (align === 'end') {\n toOffset = toOffset - size\n } else if (align === 'center') {\n toOffset = toOffset - size / 2\n }\n\n const scrollSizeProp = this.options.horizontal\n ? 'scrollWidth'\n : 'scrollHeight'\n const scrollSize = this.scrollElement\n ? 'document' in this.scrollElement\n ? this.scrollElement.document.documentElement[scrollSizeProp]\n : this.scrollElement[scrollSizeProp]\n : 0\n\n const maxOffset = scrollSize - this.getSize()\n\n return Math.max(Math.min(maxOffset, toOffset), 0)\n }\n\n getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const measurement = notUndefined(this.getMeasurements()[index])\n\n if (align === 'auto') {\n if (\n measurement.end >=\n this.scrollOffset + this.getSize() - this.options.scrollPaddingEnd\n ) {\n align = 'end'\n } else if (\n measurement.start <=\n this.scrollOffset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return [this.scrollOffset, align] as const\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n return [this.getOffsetForAlignment(toOffset, align), align] as const\n }\n\n private isDynamicMode = () => this.measureElementCache.size > 0\n\n private cancelScrollToIndex = () => {\n if (this.scrollToIndexTimeoutId !== null) {\n clearTimeout(this.scrollToIndexTimeoutId)\n this.scrollToIndexTimeoutId = null\n }\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior }: ScrollToOffsetOptions = {},\n ) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {\n adjustments: undefined,\n behavior,\n })\n }\n\n scrollToIndex = (\n index: number,\n { align: initialAlign = 'auto', behavior }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n const [toOffset, align] = this.getOffsetForIndex(index, initialAlign)\n\n this._scrollToOffset(toOffset, { adjustments: undefined, behavior })\n\n if (behavior !== 'smooth' && this.isDynamicMode()) {\n this.scrollToIndexTimeoutId = setTimeout(() => {\n this.scrollToIndexTimeoutId = null\n\n const elementInDOM = this.measureElementCache.has(\n this.options.getItemKey(index),\n )\n\n if (elementInDOM) {\n const [toOffset] = this.getOffsetForIndex(index, align)\n\n if (!approxEqual(toOffset, this.scrollOffset)) {\n this.scrollToIndex(index, { align, behavior })\n }\n } else {\n this.scrollToIndex(index, { align, behavior })\n }\n })\n }\n }\n\n scrollBy = (delta: number, { behavior }: ScrollToOffsetOptions = {}) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.scrollOffset + delta, {\n adjustments: undefined,\n behavior,\n })\n }\n\n getTotalSize = () =>\n (this.getMeasurements()[this.options.count - 1]?.end ||\n this.options.paddingStart) -\n this.options.scrollMargin +\n this.options.paddingEnd\n\n private _scrollToOffset = (\n offset: number,\n {\n adjustments,\n behavior,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this)\n }\n\n measure = () => {\n this.itemSizeCache = new Map()\n this.notify()\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: VirtualItem[]\n outerSize: number\n scrollOffset: number\n}) {\n const count = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset)\n let endIndex = startIndex\n\n while (\n endIndex < count &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["memo","getDeps","fn","opts","_opts$initialDeps","result","deps","initialDeps","depTime","key","debug","Date","now","resultTime","newDeps","length","some","dep","index","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min","onChange","notUndefined","value","msg","undefined","Error","approxEqual","a","b","abs","defaultKeyExtractor","defaultRangeExtractor","range","start","startIndex","overscan","end","endIndex","count","arr","i","push","measureElement","element","entry","instance","borderBoxSize","box","options","horizontal","getBoundingClientRect","findNearestBinarySearch","low","high","getCurrentValue","middle","currentValue","_ro","get","_this","this","unsubs","scrollElement","isScrolling","isScrollingTimeoutId","scrollToIndexTimeoutId","measurementsCache","itemSizeCache","Map","pendingMeasuredCacheIndexes","scrollDirection","scrollAdjustments","measureElementCache","observer","ResizeObserver","entries","forEach","_measureElement","target","disconnect","_get","observe","_get2","unobserve","_get3","setOptions","Object","_ref3","_extends","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","initialRect","width","height","scrollMargin","scrollingDelay","indexAttribute","initialMeasurementsCache","notify","cleanup","filter","Boolean","d","_didMount","_willUpdate","getScrollElement","_scrollToOffset","scrollOffset","adjustments","behavior","observeElementRect","rect","prev","scrollRect","maybeNotify","observeElementOffset","offset","clearTimeout","setTimeout","getSize","memoOptions","getMeasurements","_ref4","measurements","slice","measuredSize","size","estimateSize","process","calculateRange","outerSize","_ref9","getIndexes","indexFromElement","node","attributeName","indexStr","getAttribute","parseInt","warn","_this$itemSizeCache$g","item","prevNode","isConnected","set","measuredItemSize","delta","getVirtualItems","indexes","virtualItems","k","len","measurement","getVirtualItemForOffset","getOffsetForAlignment","toOffset","align","scrollSizeProp","maxOffset","document","documentElement","getOffsetForIndex","isDynamicMode","cancelScrollToIndex","scrollToOffset","_temp","_ref5","_ref5$align","scrollToIndex","_temp2","_ref6","_ref6$align","initialAlign","_this$getOffsetForInd","has","scrollBy","_temp3","getTotalSize","_this$getMeasurements","_ref8","scrollToFn","measure","_instance$scrollEleme3","_instance$scrollEleme4","_ref2$adjustments","_ref2","scrollTo","cb","handler","addEventListener","passive","removeEventListener","inlineSize","blockSize","innerWidth","innerHeight","_instance$scrollEleme","_instance$scrollEleme2","_ref$adjustments","_ref"],"mappings":"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"}
1
+ {"version":3,"file":"index.production.js","sources":["../../src/utils.ts","../../src/index.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: false | string\n debug?: () => any\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n\n return (): TResult => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n opts?.onChange?.(result)\n\n return result!\n }\n}\n\nexport function notUndefined<T>(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1\n","import { approxEqual, memo, notUndefined } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollDirection = 'forward' | 'backward'\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ntype ScrollBehavior = 'auto' | 'smooth'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n behavior?: ScrollBehavior\n}\n\ntype ScrollToOffsetOptions = ScrollToOptions\n\ntype ScrollToIndexOptions = ScrollToOptions\n\nexport interface Range {\n startIndex: number\n endIndex: number\n overscan: number\n count: number\n}\n\ntype Key = number | string\n\nexport interface VirtualItem {\n key: Key\n index: number\n start: number\n end: number\n size: number\n lane: number\n}\n\ninterface Rect {\n width: number\n height: number\n}\n\n//\n\nexport const defaultKeyExtractor = (index: number) => index\n\nexport const defaultRangeExtractor = (range: Range) => {\n const start = Math.max(range.startIndex - range.overscan, 0)\n const end = Math.min(range.endIndex + range.overscan, range.count - 1)\n\n const arr = []\n\n for (let i = start; i <= end; i++) {\n arr.push(i)\n }\n\n return arr\n}\n\nexport const observeElementRect = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = (rect: Rect) => {\n const { width, height } = rect\n cb({ width: Math.round(width), height: Math.round(height) })\n }\n\n handler(element.getBoundingClientRect())\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n handler({ width: box.inlineSize, height: box.blockSize })\n return\n }\n }\n handler(element.getBoundingClientRect())\n })\n\n observer.observe(element, { box: 'border-box' })\n\n return () => {\n observer.unobserve(element)\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<Window, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight })\n }\n handler()\n\n element.addEventListener('resize', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('resize', handler)\n }\n}\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollX' : 'scrollY'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const measureElement = <TItemElement extends Element>(\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer<any, TItemElement>,\n) => {\n if (entry?.borderBoxSize) {\n const box = entry.borderBoxSize[0]\n if (box) {\n const size = Math.round(\n box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],\n )\n return size\n }\n }\n return Math.round(\n element.getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ],\n )\n}\n\nexport const windowScroll = <T extends Window>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport const elementScroll = <T extends Element>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement | null\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n options: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => void\n observeElementRect: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (offset: number) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (instance: Virtualizer<TScrollElement, TItemElement>) => 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\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => number[]\n scrollMargin?: number\n scrollingDelay?: number\n indexAttribute?: string\n initialMeasurementsCache?: VirtualItem[]\n lanes?: number\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: (void | (() => void))[] = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n isScrolling: boolean = false\n private isScrollingTimeoutId: ReturnType<typeof setTimeout> | null = null\n private scrollToIndexTimeoutId: ReturnType<typeof setTimeout> | null = null\n measurementsCache: VirtualItem[] = []\n private itemSizeCache = new Map<Key, number>()\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n scrollOffset: number\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments: number = 0\n measureElementCache = new Map<Key, TItemElement>()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n } else if (typeof ResizeObserver !== 'undefined') {\n return (_ro = new ResizeObserver((entries) => {\n entries.forEach((entry) => {\n this._measureElement(entry.target as TItemElement, entry)\n })\n }))\n } else {\n return null\n }\n }\n\n return {\n disconnect: () => get()?.disconnect(),\n observe: (target: Element) =>\n get()?.observe(target, { box: 'border-box' }),\n unobserve: (target: Element) => get()?.unobserve(target),\n }\n })()\n range: { startIndex: number; endIndex: number } = {\n startIndex: 0,\n endIndex: 0,\n }\n\n constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {\n this.setOptions(opts)\n this.scrollRect = this.options.initialRect\n this.scrollOffset = this.options.initialOffset\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n\n this.maybeNotify()\n }\n\n setOptions = (opts: VirtualizerOptions<TScrollElement, TItemElement>) => {\n Object.entries(opts).forEach(([key, value]) => {\n if (typeof value === 'undefined') delete (opts as any)[key]\n })\n\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n scrollingDelay: 150,\n indexAttribute: 'data-index',\n initialMeasurementsCache: [],\n lanes: 1,\n ...opts,\n }\n }\n\n private notify = () => {\n this.options.onChange?.(this)\n }\n\n private cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d!())\n this.unsubs = []\n this.scrollElement = null\n }\n\n _didMount = () => {\n this.measureElementCache.forEach(this.observer.observe)\n return () => {\n this.observer.disconnect()\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.getScrollElement()\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n this.scrollElement = scrollElement\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: undefined,\n behavior: undefined,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n const prev = this.scrollRect\n this.scrollRect = rect\n if (\n this.options.horizontal\n ? rect.width !== prev.width\n : rect.height !== prev.height\n ) {\n this.maybeNotify()\n }\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n this.scrollAdjustments = 0\n\n if (this.scrollOffset === offset) {\n return\n }\n\n if (this.isScrollingTimeoutId !== null) {\n clearTimeout(this.isScrollingTimeoutId)\n this.isScrollingTimeoutId = null\n }\n\n this.isScrolling = true\n this.scrollDirection =\n this.scrollOffset < offset ? 'forward' : 'backward'\n this.scrollOffset = offset\n\n this.maybeNotify()\n\n this.isScrollingTimeoutId = setTimeout(() => {\n this.isScrollingTimeoutId = null\n this.isScrolling = false\n this.scrollDirection = null\n\n this.maybeNotify()\n }, this.options.scrollingDelay)\n }),\n )\n }\n }\n\n private getSize = () => {\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private memoOptions = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n ],\n (count, paddingStart, scrollMargin, getItemKey) => {\n this.pendingMeasuredCacheIndexes = []\n return {\n count,\n paddingStart,\n scrollMargin,\n getItemKey,\n }\n },\n {\n key: false,\n },\n )\n\n private getFurthestMeasurement = (\n measurements: VirtualItem[],\n index: number,\n ) => {\n const furthestMeasurementsFound = new Map<number, true>()\n const furthestMeasurements = new Map<number, VirtualItem>()\n for (let m = index - 1; m >= 0; m--) {\n const measurement = measurements[m]!\n\n if (furthestMeasurementsFound.has(measurement.lane)) {\n continue\n }\n\n const previousFurthestMeasurement = furthestMeasurements.get(\n measurement.lane,\n )\n if (\n previousFurthestMeasurement == null ||\n measurement.end > previousFurthestMeasurement.end\n ) {\n furthestMeasurements.set(measurement.lane, measurement)\n } else if (measurement.end < previousFurthestMeasurement.end) {\n furthestMeasurementsFound.set(measurement.lane, true)\n }\n\n if (furthestMeasurementsFound.size === this.options.lanes) {\n break\n }\n }\n\n return furthestMeasurements.size === this.options.lanes\n ? Array.from(furthestMeasurements.values()).sort(\n (a, b) => a.end - b.end,\n )[0]\n : undefined\n }\n\n private getMeasurements = memo(\n () => [this.memoOptions(), this.itemSizeCache],\n ({ count, paddingStart, scrollMargin, getItemKey }, itemSizeCache) => {\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n\n const furthestMeasurement =\n this.options.lanes === 1\n ? measurements[i - 1]\n : this.getFurthestMeasurement(measurements, i)\n\n const start = furthestMeasurement\n ? furthestMeasurement.end\n : paddingStart + scrollMargin\n\n const measuredSize = itemSizeCache.get(key)\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n\n const end = start + size\n\n const lane = furthestMeasurement\n ? furthestMeasurement.lane\n : i % this.options.lanes\n\n measurements[i] = {\n index: i,\n start,\n size,\n end,\n key,\n lane,\n }\n }\n\n this.measurementsCache = measurements\n\n return measurements\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.scrollOffset],\n (measurements, outerSize, scrollOffset) => {\n return (this.range = calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n }))\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private maybeNotify = memo(\n () => {\n const range = this.calculateRange()\n\n return [range.startIndex, range.endIndex, this.isScrolling]\n },\n () => {\n this.notify()\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'maybeNotify',\n debug: () => this.options.debug,\n initialDeps: [\n this.range.startIndex,\n this.range.endIndex,\n this.isScrolling,\n ],\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.calculateRange(),\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return rangeExtractor({\n ...range,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n indexFromElement = (node: TItemElement) => {\n const attributeName = this.options.indexAttribute\n const indexStr = node.getAttribute(attributeName)\n\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`,\n )\n return -1\n }\n\n return parseInt(indexStr, 10)\n }\n\n private _measureElement = (\n node: TItemElement,\n entry: ResizeObserverEntry | undefined,\n ) => {\n const index = this.indexFromElement(node)\n\n const item = this.measurementsCache[index]\n if (!item) {\n return\n }\n\n const prevNode = this.measureElementCache.get(item.key)\n\n if (!node.isConnected) {\n this.observer.unobserve(node)\n if (node === prevNode) {\n this.measureElementCache.delete(item.key)\n }\n return\n }\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.measureElementCache.set(item.key, node)\n }\n\n const measuredItemSize = this.options.measureElement(node, entry, this)\n\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n\n const delta = measuredItemSize - itemSize\n\n if (delta !== 0) {\n if (item.start < this.scrollOffset) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: (this.scrollAdjustments += delta),\n behavior: undefined,\n })\n }\n\n this.pendingMeasuredCacheIndexes.push(index)\n\n this.itemSizeCache = new Map(\n this.itemSizeCache.set(item.key, measuredItemSize),\n )\n\n this.notify()\n }\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n return\n }\n\n this._measureElement(node, undefined)\n }\n\n getVirtualItems = memo(\n () => [this.getIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: VirtualItem[] = []\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n virtualItems.push(measurement)\n }\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n getVirtualItemForOffset = (offset: number) => {\n const measurements = this.getMeasurements()\n\n return notUndefined(\n measurements[\n findNearestBinarySearch(\n 0,\n measurements.length - 1,\n (index: number) => notUndefined(measurements[index]).start,\n offset,\n )\n ],\n )\n }\n\n getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= this.scrollOffset) {\n align = 'start'\n } else if (toOffset >= this.scrollOffset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n toOffset = toOffset\n } else if (align === 'end') {\n toOffset = toOffset - size\n } else if (align === 'center') {\n toOffset = toOffset - size / 2\n }\n\n const scrollSizeProp = this.options.horizontal\n ? 'scrollWidth'\n : 'scrollHeight'\n const scrollSize = this.scrollElement\n ? 'document' in this.scrollElement\n ? this.scrollElement.document.documentElement[scrollSizeProp]\n : this.scrollElement[scrollSizeProp]\n : 0\n\n const maxOffset = scrollSize - this.getSize()\n\n return Math.max(Math.min(maxOffset, toOffset), 0)\n }\n\n getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const measurement = notUndefined(this.getMeasurements()[index])\n\n if (align === 'auto') {\n if (\n measurement.end >=\n this.scrollOffset + this.getSize() - this.options.scrollPaddingEnd\n ) {\n align = 'end'\n } else if (\n measurement.start <=\n this.scrollOffset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return [this.scrollOffset, align] as const\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n return [this.getOffsetForAlignment(toOffset, align), align] as const\n }\n\n private isDynamicMode = () => this.measureElementCache.size > 0\n\n private cancelScrollToIndex = () => {\n if (this.scrollToIndexTimeoutId !== null) {\n clearTimeout(this.scrollToIndexTimeoutId)\n this.scrollToIndexTimeoutId = null\n }\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior }: ScrollToOffsetOptions = {},\n ) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {\n adjustments: undefined,\n behavior,\n })\n }\n\n scrollToIndex = (\n index: number,\n { align: initialAlign = 'auto', behavior }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n const [toOffset, align] = this.getOffsetForIndex(index, initialAlign)\n\n this._scrollToOffset(toOffset, { adjustments: undefined, behavior })\n\n if (behavior !== 'smooth' && this.isDynamicMode()) {\n this.scrollToIndexTimeoutId = setTimeout(() => {\n this.scrollToIndexTimeoutId = null\n\n const elementInDOM = this.measureElementCache.has(\n this.options.getItemKey(index),\n )\n\n if (elementInDOM) {\n const [toOffset] = this.getOffsetForIndex(index, align)\n\n if (!approxEqual(toOffset, this.scrollOffset)) {\n this.scrollToIndex(index, { align, behavior })\n }\n } else {\n this.scrollToIndex(index, { align, behavior })\n }\n })\n }\n }\n\n scrollBy = (delta: number, { behavior }: ScrollToOffsetOptions = {}) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.scrollOffset + delta, {\n adjustments: undefined,\n behavior,\n })\n }\n\n getTotalSize = () =>\n (this.getMeasurements()[this.options.count - 1]?.end ||\n this.options.paddingStart) -\n this.options.scrollMargin +\n this.options.paddingEnd\n\n private _scrollToOffset = (\n offset: number,\n {\n adjustments,\n behavior,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this)\n }\n\n measure = () => {\n this.itemSizeCache = new Map()\n this.notify()\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: VirtualItem[]\n outerSize: number\n scrollOffset: number\n}) {\n const count = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset)\n let endIndex = startIndex\n\n while (\n endIndex < count &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["memo","getDeps","fn","opts","_opts$initialDeps","result","deps","initialDeps","depTime","key","debug","Date","now","resultTime","newDeps","length","some","dep","index","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min","onChange","notUndefined","value","msg","undefined","Error","approxEqual","a","b","abs","defaultKeyExtractor","defaultRangeExtractor","range","start","startIndex","overscan","end","endIndex","count","arr","i","push","measureElement","element","entry","instance","borderBoxSize","box","options","horizontal","getBoundingClientRect","findNearestBinarySearch","low","high","getCurrentValue","middle","currentValue","_ro","get","_this","this","unsubs","scrollElement","isScrolling","isScrollingTimeoutId","scrollToIndexTimeoutId","measurementsCache","itemSizeCache","Map","pendingMeasuredCacheIndexes","scrollDirection","scrollAdjustments","measureElementCache","observer","ResizeObserver","entries","forEach","_measureElement","target","disconnect","_get","observe","_get2","unobserve","_get3","setOptions","Object","_ref3","_extends","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","initialRect","width","height","scrollMargin","scrollingDelay","indexAttribute","initialMeasurementsCache","lanes","notify","cleanup","filter","Boolean","d","_didMount","_willUpdate","getScrollElement","_scrollToOffset","scrollOffset","adjustments","behavior","observeElementRect","rect","prev","scrollRect","maybeNotify","observeElementOffset","offset","clearTimeout","setTimeout","getSize","memoOptions","getFurthestMeasurement","measurements","furthestMeasurementsFound","furthestMeasurements","m","measurement","has","lane","previousFurthestMeasurement","set","size","Array","from","values","sort","getMeasurements","_ref4","slice","furthestMeasurement","measuredSize","estimateSize","process","calculateRange","outerSize","_ref9","getIndexes","indexFromElement","node","attributeName","indexStr","getAttribute","parseInt","warn","_this$itemSizeCache$g","item","prevNode","isConnected","measuredItemSize","delta","getVirtualItems","indexes","virtualItems","k","len","getVirtualItemForOffset","getOffsetForAlignment","toOffset","align","scrollSizeProp","maxOffset","document","documentElement","getOffsetForIndex","isDynamicMode","cancelScrollToIndex","scrollToOffset","_temp","_ref5","_ref5$align","scrollToIndex","_temp2","_ref6","_ref6$align","initialAlign","_this$getOffsetForInd","scrollBy","_temp3","getTotalSize","_this$getMeasurements","_ref8","scrollToFn","measure","_instance$scrollEleme3","_instance$scrollEleme4","_ref2$adjustments","_ref2","scrollTo","cb","handler","addEventListener","passive","removeEventListener","inlineSize","blockSize","innerWidth","innerHeight","_instance$scrollEleme","_instance$scrollEleme2","_ref$adjustments","_ref"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tanstack/virtual-core",
3
3
  "author": "Tanner Linsley",
4
- "version": "3.0.0-beta.53",
4
+ "version": "3.0.0-beta.54",
5
5
  "description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks",
6
6
  "license": "MIT",
7
7
  "homepage": "https://github.com/tanstack/virtual#readme",
package/src/index.ts CHANGED
@@ -34,6 +34,7 @@ export interface VirtualItem {
34
34
  start: number
35
35
  end: number
36
36
  size: number
37
+ lane: number
37
38
  }
38
39
 
39
40
  interface Rect {
@@ -261,6 +262,7 @@ export interface VirtualizerOptions<
261
262
  scrollingDelay?: number
262
263
  indexAttribute?: string
263
264
  initialMeasurementsCache?: VirtualItem[]
265
+ lanes?: number
264
266
  }
265
267
 
266
268
  export class Virtualizer<
@@ -345,6 +347,7 @@ export class Virtualizer<
345
347
  scrollingDelay: 150,
346
348
  indexAttribute: 'data-index',
347
349
  initialMeasurementsCache: [],
350
+ lanes: 1,
348
351
  ...opts,
349
352
  }
350
353
  }
@@ -451,6 +454,43 @@ export class Virtualizer<
451
454
  },
452
455
  )
453
456
 
457
+ private getFurthestMeasurement = (
458
+ measurements: VirtualItem[],
459
+ index: number,
460
+ ) => {
461
+ const furthestMeasurementsFound = new Map<number, true>()
462
+ const furthestMeasurements = new Map<number, VirtualItem>()
463
+ for (let m = index - 1; m >= 0; m--) {
464
+ const measurement = measurements[m]!
465
+
466
+ if (furthestMeasurementsFound.has(measurement.lane)) {
467
+ continue
468
+ }
469
+
470
+ const previousFurthestMeasurement = furthestMeasurements.get(
471
+ measurement.lane,
472
+ )
473
+ if (
474
+ previousFurthestMeasurement == null ||
475
+ measurement.end > previousFurthestMeasurement.end
476
+ ) {
477
+ furthestMeasurements.set(measurement.lane, measurement)
478
+ } else if (measurement.end < previousFurthestMeasurement.end) {
479
+ furthestMeasurementsFound.set(measurement.lane, true)
480
+ }
481
+
482
+ if (furthestMeasurementsFound.size === this.options.lanes) {
483
+ break
484
+ }
485
+ }
486
+
487
+ return furthestMeasurements.size === this.options.lanes
488
+ ? Array.from(furthestMeasurements.values()).sort(
489
+ (a, b) => a.end - b.end,
490
+ )[0]
491
+ : undefined
492
+ }
493
+
454
494
  private getMeasurements = memo(
455
495
  () => [this.memoOptions(), this.itemSizeCache],
456
496
  ({ count, paddingStart, scrollMargin, getItemKey }, itemSizeCache) => {
@@ -464,16 +504,36 @@ export class Virtualizer<
464
504
 
465
505
  for (let i = min; i < count; i++) {
466
506
  const key = getItemKey(i)
467
- const measuredSize = itemSizeCache.get(key)
468
- const start = measurements[i - 1]
469
- ? measurements[i - 1]!.end
507
+
508
+ const furthestMeasurement =
509
+ this.options.lanes === 1
510
+ ? measurements[i - 1]
511
+ : this.getFurthestMeasurement(measurements, i)
512
+
513
+ const start = furthestMeasurement
514
+ ? furthestMeasurement.end
470
515
  : paddingStart + scrollMargin
516
+
517
+ const measuredSize = itemSizeCache.get(key)
471
518
  const size =
472
519
  typeof measuredSize === 'number'
473
520
  ? measuredSize
474
521
  : this.options.estimateSize(i)
522
+
475
523
  const end = start + size
476
- measurements[i] = { index: i, start, size, end, key }
524
+
525
+ const lane = furthestMeasurement
526
+ ? furthestMeasurement.lane
527
+ : i % this.options.lanes
528
+
529
+ measurements[i] = {
530
+ index: i,
531
+ start,
532
+ size,
533
+ end,
534
+ key,
535
+ lane,
536
+ }
477
537
  }
478
538
 
479
539
  this.measurementsCache = measurements