@tanstack/virtual-core 3.0.0-beta.45 → 3.0.0-beta.48

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: any\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 = () => {\n const { width, height } = element.getBoundingClientRect()\n cb({ width: Math.round(width), height: Math.round(height) })\n }\n handler()\n\n const observer = new ResizeObserver(() => {\n handler()\n })\n\n observer.observe(element)\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 instance: Virtualizer<any, TItemElement>,\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 el: TItemElement,\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: Record<Key, number> = {}\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n scrollOffset: number\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments: number = 0\n private measureElementCache: Record<\n Key,\n TItemElement & { __virtualizerSkipFirstNotSync?: boolean }\n > = {}\n private getResizeObserver = (() => {\n let _ro: ResizeObserver | null = null\n\n return () => {\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, false)\n })\n }))\n } else {\n return null\n }\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[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 const ro = this.getResizeObserver()\n Object.values(this.measureElementCache).forEach((node) => ro?.observe(node))\n\n return () => {\n ro?.disconnect()\n\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 getMeasurements = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.itemSizeCache,\n ],\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[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 () => [...Object.values(this.calculateRange()), this.isScrolling],\n () => {\n this.notify()\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'maybeNotify',\n debug: () => this.options.debug,\n initialDeps: [...Object.values(this.range), this.isScrolling],\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 = (node: TItemElement, sync: boolean) => {\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[item.key]\n\n const ro = this.getResizeObserver()\n\n if (!node.isConnected) {\n ro?.unobserve(node)\n if (node === prevNode) {\n delete this.measureElementCache[item.key]\n }\n return\n }\n\n if (prevNode !== node) {\n if (prevNode) {\n ro?.unobserve(prevNode)\n }\n ro?.observe(node)\n this.measureElementCache[item.key] = node\n } else {\n if (!sync && !prevNode.__virtualizerSkipFirstNotSync) {\n prevNode.__virtualizerSkipFirstNotSync = true\n return\n }\n }\n\n const measuredItemSize = this.options.measureElement(node, this)\n\n const itemSize = this.itemSizeCache[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 this.itemSizeCache = {\n ...this.itemSizeCache,\n [item.key]: measuredItemSize,\n }\n this.notify()\n }\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n return\n }\n\n this._measureElement(node, true)\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 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 = () => Object.keys(this.measureElementCache).length > 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 =\n !!this.measureElementCache[this.options.getItemKey(index)]\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 = {}\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","instance","getBoundingClientRect","options","horizontal","_ro","_this","this","unsubs","scrollElement","isScrolling","isScrollingTimeoutId","scrollToIndexTimeoutId","measurementsCache","itemSizeCache","pendingMeasuredCacheIndexes","scrollDirection","scrollAdjustments","measureElementCache","getResizeObserver","ResizeObserver","entries","forEach","entry","_measureElement","target","setOptions","Object","_ref3","_extends","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","initialRect","width","height","scrollMargin","scrollingDelay","indexAttribute","initialMeasurementsCache","notify","cleanup","filter","Boolean","d","_didMount","ro","values","node","observe","disconnect","_willUpdate","getScrollElement","_scrollToOffset","scrollOffset","adjustments","behavior","observeElementRect","rect","prev","scrollRect","maybeNotify","observeElementOffset","offset","clearTimeout","setTimeout","getSize","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","calculateRange","outerSize","_ref8","low","high","getCurrentValue","middle","currentValue","findNearestBinarySearch","concat","getIndexes","indexFromElement","attributeName","indexStr","getAttribute","parseInt","warn","sync","_this$itemSizeCache$i","item","prevNode","isConnected","unobserve","__virtualizerSkipFirstNotSync","_extends2","measuredItemSize","delta","getVirtualItems","indexes","virtualItems","k","len","measurement","getOffsetForAlignment","toOffset","align","scrollSizeProp","maxOffset","document","documentElement","getOffsetForIndex","isDynamicMode","keys","cancelScrollToIndex","scrollToOffset","_temp","_ref4","_ref4$align","scrollToIndex","_temp2","_ref5","_ref5$align","initialAlign","_this$getOffsetForInd","scrollBy","_temp3","getTotalSize","_this$getMeasurements","_ref7","scrollToFn","measure","_instance$scrollEleme3","_instance$scrollEleme4","_ref2$adjustments","_ref2","scrollTo","cb","handler","addEventListener","passive","removeEventListener","observer","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: any\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: { width: number; height: number }) => {\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) {\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) {\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 getMeasurements = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.itemSizeCache,\n ],\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 () => [...Object.values(this.calculateRange()), this.isScrolling],\n () => {\n this.notify()\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'maybeNotify',\n debug: () => this.options.debug,\n initialDeps: [...Object.values(this.range), this.isScrolling],\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","box","borderBoxSize","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","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","calculateRange","outerSize","_ref8","concat","values","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","_ref4","_ref4$align","scrollToIndex","_temp2","_ref5","_ref5$align","initialAlign","_this$getOffsetForInd","has","scrollBy","_temp3","getTotalSize","_this$getMeasurements","_ref7","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.45",
4
+ "version": "3.0.0-beta.48",
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
@@ -67,17 +67,26 @@ export const observeElementRect = <T extends Element>(
67
67
  return
68
68
  }
69
69
 
70
- const handler = () => {
71
- const { width, height } = element.getBoundingClientRect()
70
+ const handler = (rect: { width: number; height: number }) => {
71
+ const { width, height } = rect
72
72
  cb({ width: Math.round(width), height: Math.round(height) })
73
73
  }
74
- handler()
75
74
 
76
- const observer = new ResizeObserver(() => {
77
- handler()
75
+ handler(element.getBoundingClientRect())
76
+
77
+ const observer = new ResizeObserver((entries) => {
78
+ const entry = entries[0]
79
+ if (entry) {
80
+ const box = entry.borderBoxSize[0]
81
+ if (box) {
82
+ handler({ width: box.inlineSize, height: box.blockSize })
83
+ return
84
+ }
85
+ }
86
+ handler(element.getBoundingClientRect())
78
87
  })
79
88
 
80
- observer.observe(element)
89
+ observer.observe(element, { box: 'border-box' })
81
90
 
82
91
  return () => {
83
92
  observer.unobserve(element)
@@ -155,8 +164,18 @@ export const observeWindowOffset = (
155
164
 
156
165
  export const measureElement = <TItemElement extends Element>(
157
166
  element: TItemElement,
167
+ entry: ResizeObserverEntry | undefined,
158
168
  instance: Virtualizer<any, TItemElement>,
159
169
  ) => {
170
+ if (entry) {
171
+ const box = entry.borderBoxSize[0]
172
+ if (box) {
173
+ const size = Math.round(
174
+ box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],
175
+ )
176
+ return size
177
+ }
178
+ }
160
179
  return Math.round(
161
180
  element.getBoundingClientRect()[
162
181
  instance.options.horizontal ? 'width' : 'height'
@@ -225,7 +244,8 @@ export interface VirtualizerOptions<
225
244
  initialRect?: Rect
226
245
  onChange?: (instance: Virtualizer<TScrollElement, TItemElement>) => void
227
246
  measureElement?: (
228
- el: TItemElement,
247
+ element: TItemElement,
248
+ entry: ResizeObserverEntry | undefined,
229
249
  instance: Virtualizer<TScrollElement, TItemElement>,
230
250
  ) => number
231
251
  overscan?: number
@@ -254,32 +274,36 @@ export class Virtualizer<
254
274
  private isScrollingTimeoutId: ReturnType<typeof setTimeout> | null = null
255
275
  private scrollToIndexTimeoutId: ReturnType<typeof setTimeout> | null = null
256
276
  measurementsCache: VirtualItem[] = []
257
- private itemSizeCache: Record<Key, number> = {}
277
+ private itemSizeCache = new Map<Key, number>()
258
278
  private pendingMeasuredCacheIndexes: number[] = []
259
279
  private scrollRect: Rect
260
280
  scrollOffset: number
261
281
  scrollDirection: ScrollDirection | null = null
262
282
  private scrollAdjustments: number = 0
263
- private measureElementCache: Record<
264
- Key,
265
- TItemElement & { __virtualizerSkipFirstNotSync?: boolean }
266
- > = {}
267
- private getResizeObserver = (() => {
283
+ measureElementCache = new Map<Key, TItemElement>()
284
+ private observer = (() => {
268
285
  let _ro: ResizeObserver | null = null
269
286
 
270
- return () => {
287
+ const get = () => {
271
288
  if (_ro) {
272
289
  return _ro
273
290
  } else if (typeof ResizeObserver !== 'undefined') {
274
291
  return (_ro = new ResizeObserver((entries) => {
275
292
  entries.forEach((entry) => {
276
- this._measureElement(entry.target as TItemElement, false)
293
+ this._measureElement(entry.target as TItemElement, entry)
277
294
  })
278
295
  }))
279
296
  } else {
280
297
  return null
281
298
  }
282
299
  }
300
+
301
+ return {
302
+ disconnect: () => get()?.disconnect(),
303
+ observe: (target: Element) =>
304
+ get()?.observe(target, { box: 'border-box' }),
305
+ unobserve: (target: Element) => get()?.unobserve(target),
306
+ }
283
307
  })()
284
308
  range: { startIndex: number; endIndex: number } = {
285
309
  startIndex: 0,
@@ -292,7 +316,7 @@ export class Virtualizer<
292
316
  this.scrollOffset = this.options.initialOffset
293
317
  this.measurementsCache = this.options.initialMeasurementsCache
294
318
  this.measurementsCache.forEach((item) => {
295
- this.itemSizeCache[item.key] = item.size
319
+ this.itemSizeCache.set(item.key, item.size)
296
320
  })
297
321
 
298
322
  this.maybeNotify()
@@ -336,12 +360,9 @@ export class Virtualizer<
336
360
  }
337
361
 
338
362
  _didMount = () => {
339
- const ro = this.getResizeObserver()
340
- Object.values(this.measureElementCache).forEach((node) => ro?.observe(node))
341
-
363
+ this.measureElementCache.forEach(this.observer.observe)
342
364
  return () => {
343
- ro?.disconnect()
344
-
365
+ this.observer.disconnect()
345
366
  this.cleanup()
346
367
  }
347
368
  }
@@ -428,7 +449,7 @@ export class Virtualizer<
428
449
 
429
450
  for (let i = min; i < count; i++) {
430
451
  const key = getItemKey(i)
431
- const measuredSize = itemSizeCache[key]
452
+ const measuredSize = itemSizeCache.get(key)
432
453
  const start = measurements[i - 1]
433
454
  ? measurements[i - 1]!.end
434
455
  : paddingStart + scrollMargin
@@ -511,7 +532,10 @@ export class Virtualizer<
511
532
  return parseInt(indexStr, 10)
512
533
  }
513
534
 
514
- private _measureElement = (node: TItemElement, sync: boolean) => {
535
+ private _measureElement = (
536
+ node: TItemElement,
537
+ entry: ResizeObserverEntry | undefined,
538
+ ) => {
515
539
  const index = this.indexFromElement(node)
516
540
 
517
541
  const item = this.measurementsCache[index]
@@ -519,34 +543,27 @@ export class Virtualizer<
519
543
  return
520
544
  }
521
545
 
522
- const prevNode = this.measureElementCache[item.key]
523
-
524
- const ro = this.getResizeObserver()
546
+ const prevNode = this.measureElementCache.get(item.key)
525
547
 
526
548
  if (!node.isConnected) {
527
- ro?.unobserve(node)
549
+ this.observer.unobserve(node)
528
550
  if (node === prevNode) {
529
- delete this.measureElementCache[item.key]
551
+ this.measureElementCache.delete(item.key)
530
552
  }
531
553
  return
532
554
  }
533
555
 
534
556
  if (prevNode !== node) {
535
557
  if (prevNode) {
536
- ro?.unobserve(prevNode)
537
- }
538
- ro?.observe(node)
539
- this.measureElementCache[item.key] = node
540
- } else {
541
- if (!sync && !prevNode.__virtualizerSkipFirstNotSync) {
542
- prevNode.__virtualizerSkipFirstNotSync = true
543
- return
558
+ this.observer.unobserve(prevNode)
544
559
  }
560
+ this.observer.observe(node)
561
+ this.measureElementCache.set(item.key, node)
545
562
  }
546
563
 
547
- const measuredItemSize = this.options.measureElement(node, this)
564
+ const measuredItemSize = this.options.measureElement(node, entry, this)
548
565
 
549
- const itemSize = this.itemSizeCache[item.key] ?? item.size
566
+ const itemSize = this.itemSizeCache.get(item.key) ?? item.size
550
567
 
551
568
  const delta = measuredItemSize - itemSize
552
569
 
@@ -563,10 +580,11 @@ export class Virtualizer<
563
580
  }
564
581
 
565
582
  this.pendingMeasuredCacheIndexes.push(index)
566
- this.itemSizeCache = {
567
- ...this.itemSizeCache,
568
- [item.key]: measuredItemSize,
569
- }
583
+
584
+ this.itemSizeCache = new Map(
585
+ this.itemSizeCache.set(item.key, measuredItemSize),
586
+ )
587
+
570
588
  this.notify()
571
589
  }
572
590
  }
@@ -576,7 +594,7 @@ export class Virtualizer<
576
594
  return
577
595
  }
578
596
 
579
- this._measureElement(node, true)
597
+ this._measureElement(node, undefined)
580
598
  }
581
599
 
582
600
  getVirtualItems = memo(
@@ -599,6 +617,21 @@ export class Virtualizer<
599
617
  },
600
618
  )
601
619
 
620
+ getVirtualItemForOffset = (offset: number) => {
621
+ const measurements = this.getMeasurements()
622
+
623
+ return notUndefined(
624
+ measurements[
625
+ findNearestBinarySearch(
626
+ 0,
627
+ measurements.length - 1,
628
+ (index: number) => notUndefined(measurements[index]).start,
629
+ offset,
630
+ )
631
+ ],
632
+ )
633
+ }
634
+
602
635
  getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {
603
636
  const size = this.getSize()
604
637
 
@@ -663,7 +696,7 @@ export class Virtualizer<
663
696
  return [this.getOffsetForAlignment(toOffset, align), align] as const
664
697
  }
665
698
 
666
- private isDynamicMode = () => Object.keys(this.measureElementCache).length > 0
699
+ private isDynamicMode = () => this.measureElementCache.size > 0
667
700
 
668
701
  private cancelScrollToIndex = () => {
669
702
  if (this.scrollToIndexTimeoutId !== null) {
@@ -712,8 +745,9 @@ export class Virtualizer<
712
745
  this.scrollToIndexTimeoutId = setTimeout(() => {
713
746
  this.scrollToIndexTimeoutId = null
714
747
 
715
- const elementInDOM =
716
- !!this.measureElementCache[this.options.getItemKey(index)]
748
+ const elementInDOM = this.measureElementCache.has(
749
+ this.options.getItemKey(index),
750
+ )
717
751
 
718
752
  if (elementInDOM) {
719
753
  const [toOffset] = this.getOffsetForIndex(index, align)
@@ -763,7 +797,7 @@ export class Virtualizer<
763
797
  }
764
798
 
765
799
  measure = () => {
766
- this.itemSizeCache = {}
800
+ this.itemSizeCache = new Map()
767
801
  this.notify()
768
802
  }
769
803
  }