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

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 elementKeyAttribute?: string\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 elementKeyAttribute: 'data-element-key',\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 = notUndefined(this.measurementsCache[index])\n\n const elementKey =\n node.getAttribute(this.options.elementKeyAttribute) ?? item.key\n\n const prevNode = this.measureElementCache.get(elementKey)\n\n if (!node.isConnected) {\n this.observer.unobserve(node)\n if (node === prevNode) {\n this.measureElementCache.delete(elementKey)\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(elementKey, 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","elementKeyAttribute","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","_node$getAttribute","_this$itemSizeCache$g","item","elementKey","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.55",
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 {
@@ -259,8 +260,10 @@ export interface VirtualizerOptions<
259
260
  rangeExtractor?: (range: Range) => number[]
260
261
  scrollMargin?: number
261
262
  scrollingDelay?: number
263
+ elementKeyAttribute?: string
262
264
  indexAttribute?: string
263
265
  initialMeasurementsCache?: VirtualItem[]
266
+ lanes?: number
264
267
  }
265
268
 
266
269
  export class Virtualizer<
@@ -344,7 +347,9 @@ export class Virtualizer<
344
347
  scrollMargin: 0,
345
348
  scrollingDelay: 150,
346
349
  indexAttribute: 'data-index',
350
+ elementKeyAttribute: 'data-element-key',
347
351
  initialMeasurementsCache: [],
352
+ lanes: 1,
348
353
  ...opts,
349
354
  }
350
355
  }
@@ -451,6 +456,43 @@ export class Virtualizer<
451
456
  },
452
457
  )
453
458
 
459
+ private getFurthestMeasurement = (
460
+ measurements: VirtualItem[],
461
+ index: number,
462
+ ) => {
463
+ const furthestMeasurementsFound = new Map<number, true>()
464
+ const furthestMeasurements = new Map<number, VirtualItem>()
465
+ for (let m = index - 1; m >= 0; m--) {
466
+ const measurement = measurements[m]!
467
+
468
+ if (furthestMeasurementsFound.has(measurement.lane)) {
469
+ continue
470
+ }
471
+
472
+ const previousFurthestMeasurement = furthestMeasurements.get(
473
+ measurement.lane,
474
+ )
475
+ if (
476
+ previousFurthestMeasurement == null ||
477
+ measurement.end > previousFurthestMeasurement.end
478
+ ) {
479
+ furthestMeasurements.set(measurement.lane, measurement)
480
+ } else if (measurement.end < previousFurthestMeasurement.end) {
481
+ furthestMeasurementsFound.set(measurement.lane, true)
482
+ }
483
+
484
+ if (furthestMeasurementsFound.size === this.options.lanes) {
485
+ break
486
+ }
487
+ }
488
+
489
+ return furthestMeasurements.size === this.options.lanes
490
+ ? Array.from(furthestMeasurements.values()).sort(
491
+ (a, b) => a.end - b.end,
492
+ )[0]
493
+ : undefined
494
+ }
495
+
454
496
  private getMeasurements = memo(
455
497
  () => [this.memoOptions(), this.itemSizeCache],
456
498
  ({ count, paddingStart, scrollMargin, getItemKey }, itemSizeCache) => {
@@ -464,16 +506,36 @@ export class Virtualizer<
464
506
 
465
507
  for (let i = min; i < count; i++) {
466
508
  const key = getItemKey(i)
467
- const measuredSize = itemSizeCache.get(key)
468
- const start = measurements[i - 1]
469
- ? measurements[i - 1]!.end
509
+
510
+ const furthestMeasurement =
511
+ this.options.lanes === 1
512
+ ? measurements[i - 1]
513
+ : this.getFurthestMeasurement(measurements, i)
514
+
515
+ const start = furthestMeasurement
516
+ ? furthestMeasurement.end
470
517
  : paddingStart + scrollMargin
518
+
519
+ const measuredSize = itemSizeCache.get(key)
471
520
  const size =
472
521
  typeof measuredSize === 'number'
473
522
  ? measuredSize
474
523
  : this.options.estimateSize(i)
524
+
475
525
  const end = start + size
476
- measurements[i] = { index: i, start, size, end, key }
526
+
527
+ const lane = furthestMeasurement
528
+ ? furthestMeasurement.lane
529
+ : i % this.options.lanes
530
+
531
+ measurements[i] = {
532
+ index: i,
533
+ start,
534
+ size,
535
+ end,
536
+ key,
537
+ lane,
538
+ }
477
539
  }
478
540
 
479
541
  this.measurementsCache = measurements
@@ -561,17 +623,17 @@ export class Virtualizer<
561
623
  ) => {
562
624
  const index = this.indexFromElement(node)
563
625
 
564
- const item = this.measurementsCache[index]
565
- if (!item) {
566
- return
567
- }
626
+ const item = notUndefined(this.measurementsCache[index])
627
+
628
+ const elementKey =
629
+ node.getAttribute(this.options.elementKeyAttribute) ?? item.key
568
630
 
569
- const prevNode = this.measureElementCache.get(item.key)
631
+ const prevNode = this.measureElementCache.get(elementKey)
570
632
 
571
633
  if (!node.isConnected) {
572
634
  this.observer.unobserve(node)
573
635
  if (node === prevNode) {
574
- this.measureElementCache.delete(item.key)
636
+ this.measureElementCache.delete(elementKey)
575
637
  }
576
638
  return
577
639
  }
@@ -581,7 +643,7 @@ export class Virtualizer<
581
643
  this.observer.unobserve(prevNode)
582
644
  }
583
645
  this.observer.observe(node)
584
- this.measureElementCache.set(item.key, node)
646
+ this.measureElementCache.set(elementKey, node)
585
647
  }
586
648
 
587
649
  const measuredItemSize = this.options.measureElement(node, entry, this)