@tanstack/virtual-core 3.0.0-beta.21 → 3.0.0-beta.22

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 },\n): () => TResult {\n let deps: any[] = []\n let result: TResult | undefined\n\n return () => {\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 opts?.onChange?.(result)\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 return result!\n }\n}\n","import { memo } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n smoothScroll?: boolean\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\nconst memoRectCallback = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n let prev: Rect = { height: -1, width: -1 }\n\n return (rect: Rect) => {\n if (\n instance.options.horizontal\n ? rect.width !== prev.width\n : rect.height !== prev.height\n ) {\n cb(rect)\n }\n\n prev = rect\n }\n}\n\nexport const observeElementRect = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n const observer = new ResizeObserver((entries) => {\n cb({\n width: entries[0]?.contentRect.width as number,\n height: entries[0]?.contentRect.height as number,\n })\n })\n\n if (!instance.scrollElement) {\n return\n }\n\n cb(instance.scrollElement.getBoundingClientRect())\n\n observer.observe(instance.scrollElement)\n\n return () => {\n observer.unobserve(instance.scrollElement)\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n const memoizedCallback = memoRectCallback(instance, cb)\n const onResize = () =>\n memoizedCallback({\n width: instance.scrollElement.innerWidth,\n height: instance.scrollElement.innerHeight,\n })\n\n if (!instance.scrollElement) {\n return\n }\n\n onResize()\n\n instance.scrollElement.addEventListener('resize', onResize, {\n capture: false,\n passive: true,\n })\n\n return () => {\n instance.scrollElement.removeEventListener('resize', onResize)\n }\n}\n\ntype ObserverMode = 'element' | 'window'\n\nconst scrollProps = {\n element: ['scrollLeft', 'scrollTop'],\n window: ['scrollX', 'scrollY'],\n} as const\n\nconst createOffsetObserver = (mode: ObserverMode) => {\n return (instance: Virtualizer<any, any>, cb: (offset: number) => void) => {\n if (!instance.scrollElement) {\n return\n }\n\n const propX = scrollProps[mode][0]\n const propY = scrollProps[mode][1]\n\n let prevX: number = instance.scrollElement[propX]\n let prevY: number = instance.scrollElement[propY]\n\n const scroll = () => {\n const offset =\n instance.scrollElement[instance.options.horizontal ? propX : propY]\n\n cb(Math.max(0, offset - instance.options.scrollMargin))\n }\n\n scroll()\n\n const onScroll = (e: Event) => {\n const target = e.currentTarget as HTMLElement & Window\n const scrollX = target[propX]\n const scrollY = target[propY]\n\n if (instance.options.horizontal ? prevX - scrollX : prevY - scrollY) {\n scroll()\n }\n\n prevX = scrollX\n prevY = scrollY\n }\n\n instance.scrollElement.addEventListener('scroll', onScroll, {\n capture: false,\n passive: true,\n })\n\n return () => {\n instance.scrollElement.removeEventListener('scroll', onScroll)\n }\n }\n}\n\nexport const observeElementOffset = createOffsetObserver('element')\nexport const observeWindowOffset = createOffsetObserver('window')\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 = (\n offset: number,\n { canSmooth, sync }: { canSmooth: boolean; sync: boolean },\n instance: Virtualizer<any, any>,\n) => {\n const toOffset = sync ? offset : offset + instance.options.scrollMargin\n\n ;(instance.scrollElement as Window)?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior: canSmooth ? 'smooth' : undefined,\n })\n}\n\nexport const elementScroll = (\n offset: number,\n { canSmooth, sync }: { canSmooth: boolean; sync: boolean },\n instance: Virtualizer<any, any>,\n) => {\n const toOffset = sync ? offset : offset + instance.options.scrollMargin\n\n ;(instance.scrollElement as Element)?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior: canSmooth ? 'smooth' : undefined,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends unknown,\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: { canSmooth: boolean; sync: boolean },\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 enableSmoothScroll?: boolean\n scrollMargin?: number\n scrollingDelay?: number\n indexAttribute?: string\n}\n\nexport class Virtualizer<\n TScrollElement extends unknown,\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 measurementsCache: VirtualItem[] = []\n private itemMeasurementsCache: Record<Key, number> = {}\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n private scrollOffset: number\n private scrollDelta: number = 0\n private destinationOffset: undefined | number\n private scrollCheckFrame!: ReturnType<typeof setTimeout>\n private measureElementCache: Record<string, TItemElement> = {}\n private ro = new ResizeObserver((entries) => {\n entries.forEach((entry) => {\n this._measureElement(entry.target as TItemElement, false)\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\n this.calculateRange()\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 enableSmoothScroll: true,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n scrollingDelay: 150,\n indexAttribute: 'data-index',\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 return () => {\n this.ro.disconnect()\n this.measureElementCache = {}\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 this._scrollToOffset(this.scrollOffset, {\n canSmooth: false,\n sync: true,\n requested: false,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect\n this.calculateRange()\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n if (this.isScrollingTimeoutId !== null) {\n clearTimeout(this.isScrollingTimeoutId)\n this.isScrollingTimeoutId = null\n }\n\n if (this.scrollOffset !== offset) {\n this.scrollOffset = offset\n this.isScrolling = true\n this.scrollDelta = 0\n\n this.isScrollingTimeoutId = setTimeout(() => {\n this.isScrollingTimeoutId = null\n this.isScrolling = false\n\n this.notify()\n }, this.options.scrollingDelay)\n } else {\n this.isScrolling = false\n this.scrollDelta = 0\n }\n\n this.calculateRange()\n }),\n )\n } else if (!this.isScrolling) {\n this.calculateRange()\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.getItemKey,\n this.itemMeasurementsCache,\n ],\n (count, paddingStart, getItemKey, measurementsCache) => {\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 = measurementsCache[key]\n const start = measurements[i - 1]\n ? measurements[i - 1]!.end\n : paddingStart\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 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 const range = calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n })\n if (\n range.startIndex !== this.range.startIndex ||\n range.endIndex !== this.range.endIndex\n ) {\n this.range = range\n this.notify()\n }\n return this.range\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.range,\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return rangeExtractor({\n ...range,\n overscan,\n count: 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 _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 const key = String(item.key)\n\n const prevNode = this.measureElementCache[key]\n\n if (!node.isConnected) {\n if (prevNode) {\n this.ro.unobserve(prevNode)\n delete this.measureElementCache[key]\n }\n return\n }\n\n if (!prevNode || prevNode !== node) {\n if (prevNode) {\n this.ro.unobserve(prevNode)\n }\n this.measureElementCache[key] = node\n this.ro.observe(node)\n }\n\n const measuredItemSize = this.options.measureElement(node, this)\n\n const itemSize = this.itemMeasurementsCache[item.key] ?? item.size\n\n if (measuredItemSize !== itemSize) {\n if (item.start < this.scrollOffset) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', measuredItemSize - itemSize)\n }\n\n if (this.destinationOffset === undefined) {\n this.scrollDelta += measuredItemSize - itemSize\n\n this._scrollToOffset(this.scrollOffset + this.scrollDelta, {\n canSmooth: false,\n sync: false,\n requested: false,\n })\n }\n }\n\n this.pendingMeasuredCacheIndexes.push(index)\n this.itemMeasurementsCache = {\n ...this.itemMeasurementsCache,\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 scrollToOffset = (\n toOffset: number,\n {\n align = 'start',\n smoothScroll = this.options.enableSmoothScroll,\n }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.scrollOffset\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= offset) {\n align = 'start'\n } else if (toOffset >= offset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n const options = {\n canSmooth: smoothScroll,\n sync: false,\n requested: true,\n }\n if (align === 'start') {\n this._scrollToOffset(toOffset, options)\n } else if (align === 'end') {\n this._scrollToOffset(toOffset - size, options)\n } else if (align === 'center') {\n this._scrollToOffset(toOffset - size / 2, options)\n }\n }\n\n scrollToIndex = (\n index: number,\n {\n align = 'auto',\n smoothScroll = this.options.enableSmoothScroll,\n ...rest\n }: ScrollToIndexOptions = {},\n ) => {\n const measurements = this.getMeasurements()\n const offset = this.scrollOffset\n const size = this.getSize()\n const { count } = this.options\n\n const measurement = measurements[Math.max(0, Math.min(index, count - 1))]\n\n if (!measurement) {\n return\n }\n\n if (align === 'auto') {\n if (measurement.end >= offset + size - this.options.scrollPaddingEnd) {\n align = 'end'\n } else if (\n measurement.start <=\n offset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n this.scrollToOffset(toOffset, { align, smoothScroll, ...rest })\n }\n\n getTotalSize = () =>\n (this.getMeasurements()[this.options.count - 1]?.end ||\n this.options.paddingStart) + this.options.paddingEnd\n\n private _scrollToOffset = (\n offset: number,\n {\n requested,\n canSmooth,\n sync,\n }: { canSmooth: boolean; sync: boolean; requested: boolean },\n ) => {\n clearTimeout(this.scrollCheckFrame)\n\n if (requested) {\n this.destinationOffset = offset\n }\n this.options.scrollToFn(offset, { canSmooth, sync }, this)\n\n let scrollCheckFrame: ReturnType<typeof setTimeout>\n\n const check = () => {\n let lastOffset = this.scrollOffset\n this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {\n if (this.scrollCheckFrame !== scrollCheckFrame) {\n return\n }\n\n if (this.scrollOffset === lastOffset) {\n this.destinationOffset = undefined\n return\n }\n lastOffset = this.scrollOffset\n check()\n }, 100)\n }\n\n check()\n }\n\n measure = () => {\n this.itemMeasurementsCache = {}\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","result","deps","depTime","key","debug","Date","now","newDeps","length","some","dep","index","resultTime","onChange","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min","defaultKeyExtractor","defaultRangeExtractor","range","start","startIndex","overscan","end","endIndex","count","arr","i","push","scrollProps","element","window","createOffsetObserver","mode","instance","cb","scrollElement","propX","propY","prevX","prevY","scroll","offset","options","horizontal","scrollMargin","onScroll","e","target","currentTarget","scrollX","scrollY","addEventListener","capture","passive","removeEventListener","observeElementOffset","observeWindowOffset","measureElement","getBoundingClientRect","constructor","_this","this","unsubs","isScrolling","isScrollingTimeoutId","measurementsCache","itemMeasurementsCache","pendingMeasuredCacheIndexes","scrollDelta","measureElementCache","ro","ResizeObserver","entries","forEach","entry","_measureElement","setOptions","Object","_ref3","value","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","enableSmoothScroll","initialRect","width","height","scrollingDelay","indexAttribute","notify","_this$options$onChang","_this$options","call","cleanup","filter","Boolean","d","_didMount","disconnect","_willUpdate","getScrollElement","_scrollToOffset","scrollOffset","canSmooth","sync","requested","observeElementRect","rect","scrollRect","calculateRange","clearTimeout","setTimeout","getSize","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","outerSize","_ref5","low","high","getCurrentValue","middle","currentValue","findNearestBinarySearch","getIndexes","indexFromElement","node","attributeName","indexStr","getAttribute","parseInt","warn","_sync","_this$itemMeasurement","item","prevNode","isConnected","unobserve","observe","measuredItemSize","itemSize","undefined","destinationOffset","getVirtualItems","indexes","virtualItems","k","len","measurement","scrollToOffset","toOffset","_temp","align","smoothScroll","scrollToIndex","_temp2","rest","getTotalSize","_this$getMeasurements","_ref4","scrollCheckFrame","scrollToFn","check","lastOffset","measure","_ref2","_instance$scrollEleme2","scrollTo","behavior","observer","_entries$","_entries$2","contentRect","memoizedCallback","prev","memoRectCallback","onResize","innerWidth","innerHeight","_ref","_instance$scrollEleme"],"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 },\n): () => TResult {\n let deps: any[] = []\n let result: TResult | undefined\n\n return () => {\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 opts?.onChange?.(result)\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 return result!\n }\n}\n","import { memo } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n smoothScroll?: boolean\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\nconst memoRectCallback = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n let prev: Rect = { height: -1, width: -1 }\n\n return (rect: Rect) => {\n if (\n instance.options.horizontal\n ? rect.width !== prev.width\n : rect.height !== prev.height\n ) {\n cb(rect)\n }\n\n prev = rect\n }\n}\n\nexport const observeElementRect = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n const observer = new ResizeObserver((entries) => {\n cb({\n width: entries[0]?.contentRect.width as number,\n height: entries[0]?.contentRect.height as number,\n })\n })\n\n if (!instance.scrollElement) {\n return\n }\n\n cb(instance.scrollElement.getBoundingClientRect())\n\n observer.observe(instance.scrollElement)\n\n return () => {\n observer.unobserve(instance.scrollElement)\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n const memoizedCallback = memoRectCallback(instance, cb)\n const onResize = () =>\n memoizedCallback({\n width: instance.scrollElement.innerWidth,\n height: instance.scrollElement.innerHeight,\n })\n\n if (!instance.scrollElement) {\n return\n }\n\n onResize()\n\n instance.scrollElement.addEventListener('resize', onResize, {\n capture: false,\n passive: true,\n })\n\n return () => {\n instance.scrollElement.removeEventListener('resize', onResize)\n }\n}\n\ntype ObserverMode = 'element' | 'window'\n\nconst scrollProps = {\n element: ['scrollLeft', 'scrollTop'],\n window: ['scrollX', 'scrollY'],\n} as const\n\nconst createOffsetObserver = (mode: ObserverMode) => {\n return (instance: Virtualizer<any, any>, cb: (offset: number) => void) => {\n if (!instance.scrollElement) {\n return\n }\n\n const propX = scrollProps[mode][0]\n const propY = scrollProps[mode][1]\n\n let prevX: number = instance.scrollElement[propX]\n let prevY: number = instance.scrollElement[propY]\n\n const scroll = () => {\n const offset =\n instance.scrollElement[instance.options.horizontal ? propX : propY]\n\n cb(Math.max(0, offset - instance.options.scrollMargin))\n }\n\n scroll()\n\n const onScroll = (e: Event) => {\n const target = e.currentTarget as HTMLElement & Window\n const scrollX = target[propX]\n const scrollY = target[propY]\n\n if (instance.options.horizontal ? prevX - scrollX : prevY - scrollY) {\n scroll()\n }\n\n prevX = scrollX\n prevY = scrollY\n }\n\n instance.scrollElement.addEventListener('scroll', onScroll, {\n capture: false,\n passive: true,\n })\n\n return () => {\n instance.scrollElement.removeEventListener('scroll', onScroll)\n }\n }\n}\n\nexport const observeElementOffset = createOffsetObserver('element')\nexport const observeWindowOffset = createOffsetObserver('window')\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 = (\n offset: number,\n { canSmooth, sync }: { canSmooth: boolean; sync: boolean },\n instance: Virtualizer<any, any>,\n) => {\n const toOffset = sync ? offset : offset + instance.options.scrollMargin\n\n ;(instance.scrollElement as Window)?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior: canSmooth ? 'smooth' : undefined,\n })\n}\n\nexport const elementScroll = (\n offset: number,\n { canSmooth, sync }: { canSmooth: boolean; sync: boolean },\n instance: Virtualizer<any, any>,\n) => {\n const toOffset = sync ? offset : offset + instance.options.scrollMargin\n\n ;(instance.scrollElement as Element)?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior: canSmooth ? 'smooth' : undefined,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends unknown,\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: { canSmooth: boolean; sync: boolean },\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 enableSmoothScroll?: boolean\n scrollMargin?: number\n scrollingDelay?: number\n indexAttribute?: string\n}\n\nexport class Virtualizer<\n TScrollElement extends unknown,\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 measurementsCache: VirtualItem[] = []\n private itemMeasurementsCache: Record<Key, number> = {}\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n private scrollOffset: number\n private scrollDelta: number = 0\n private destinationOffset: undefined | number\n private scrollCheckFrame!: ReturnType<typeof setTimeout>\n private measureElementCache: Record<Key, TItemElement> = {}\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\n this.calculateRange()\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 enableSmoothScroll: true,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n scrollingDelay: 150,\n indexAttribute: 'data-index',\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 return () => {\n this.getResizeObserver()?.disconnect()\n this.measureElementCache = {}\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 this._scrollToOffset(this.scrollOffset, {\n canSmooth: false,\n sync: true,\n requested: false,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect\n this.calculateRange()\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n if (this.isScrollingTimeoutId !== null) {\n clearTimeout(this.isScrollingTimeoutId)\n this.isScrollingTimeoutId = null\n }\n\n if (this.scrollOffset !== offset) {\n this.scrollOffset = offset\n this.isScrolling = true\n this.scrollDelta = 0\n\n this.isScrollingTimeoutId = setTimeout(() => {\n this.isScrollingTimeoutId = null\n this.isScrolling = false\n\n this.notify()\n }, this.options.scrollingDelay)\n } else {\n this.isScrolling = false\n this.scrollDelta = 0\n }\n\n this.calculateRange()\n }),\n )\n } else if (!this.isScrolling) {\n this.calculateRange()\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.getItemKey,\n this.itemMeasurementsCache,\n ],\n (count, paddingStart, getItemKey, measurementsCache) => {\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 = measurementsCache[key]\n const start = measurements[i - 1]\n ? measurements[i - 1]!.end\n : paddingStart\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 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 const range = calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n })\n if (\n range.startIndex !== this.range.startIndex ||\n range.endIndex !== this.range.endIndex\n ) {\n this.range = range\n this.notify()\n }\n return this.range\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.range,\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return rangeExtractor({\n ...range,\n overscan,\n count: 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 if (prevNode) {\n ro?.unobserve(prevNode)\n delete this.measureElementCache[item.key]\n }\n return\n }\n\n if (!prevNode || prevNode !== node) {\n if (prevNode) {\n ro?.unobserve(prevNode)\n }\n this.measureElementCache[item.key] = node\n ro?.observe(node)\n }\n\n const measuredItemSize = this.options.measureElement(node, this)\n\n const itemSize = this.itemMeasurementsCache[item.key] ?? item.size\n\n if (measuredItemSize !== itemSize) {\n if (item.start < this.scrollOffset) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', measuredItemSize - itemSize)\n }\n\n if (this.destinationOffset === undefined) {\n this.scrollDelta += measuredItemSize - itemSize\n\n this._scrollToOffset(this.scrollOffset + this.scrollDelta, {\n canSmooth: false,\n sync: false,\n requested: false,\n })\n }\n }\n\n this.pendingMeasuredCacheIndexes.push(index)\n this.itemMeasurementsCache = {\n ...this.itemMeasurementsCache,\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 scrollToOffset = (\n toOffset: number,\n {\n align = 'start',\n smoothScroll = this.options.enableSmoothScroll,\n }: ScrollToOffsetOptions = {},\n ) => {\n const offset = this.scrollOffset\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= offset) {\n align = 'start'\n } else if (toOffset >= offset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n const options = {\n canSmooth: smoothScroll,\n sync: false,\n requested: true,\n }\n if (align === 'start') {\n this._scrollToOffset(toOffset, options)\n } else if (align === 'end') {\n this._scrollToOffset(toOffset - size, options)\n } else if (align === 'center') {\n this._scrollToOffset(toOffset - size / 2, options)\n }\n }\n\n scrollToIndex = (\n index: number,\n {\n align = 'auto',\n smoothScroll = this.options.enableSmoothScroll,\n ...rest\n }: ScrollToIndexOptions = {},\n ) => {\n const measurements = this.getMeasurements()\n const offset = this.scrollOffset\n const size = this.getSize()\n const { count } = this.options\n\n const measurement = measurements[Math.max(0, Math.min(index, count - 1))]\n\n if (!measurement) {\n return\n }\n\n if (align === 'auto') {\n if (measurement.end >= offset + size - this.options.scrollPaddingEnd) {\n align = 'end'\n } else if (\n measurement.start <=\n offset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n this.scrollToOffset(toOffset, { align, smoothScroll, ...rest })\n }\n\n getTotalSize = () =>\n (this.getMeasurements()[this.options.count - 1]?.end ||\n this.options.paddingStart) + this.options.paddingEnd\n\n private _scrollToOffset = (\n offset: number,\n {\n requested,\n canSmooth,\n sync,\n }: { canSmooth: boolean; sync: boolean; requested: boolean },\n ) => {\n clearTimeout(this.scrollCheckFrame)\n\n if (requested) {\n this.destinationOffset = offset\n }\n this.options.scrollToFn(offset, { canSmooth, sync }, this)\n\n let scrollCheckFrame: ReturnType<typeof setTimeout>\n\n const check = () => {\n let lastOffset = this.scrollOffset\n this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {\n if (this.scrollCheckFrame !== scrollCheckFrame) {\n return\n }\n\n if (this.scrollOffset === lastOffset) {\n this.destinationOffset = undefined\n return\n }\n lastOffset = this.scrollOffset\n check()\n }, 100)\n }\n\n check()\n }\n\n measure = () => {\n this.itemMeasurementsCache = {}\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","result","deps","depTime","key","debug","Date","now","newDeps","length","some","dep","index","resultTime","onChange","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min","defaultKeyExtractor","defaultRangeExtractor","range","start","startIndex","overscan","end","endIndex","count","arr","i","push","scrollProps","element","window","createOffsetObserver","mode","instance","cb","scrollElement","propX","propY","prevX","prevY","scroll","offset","options","horizontal","scrollMargin","onScroll","e","target","currentTarget","scrollX","scrollY","addEventListener","capture","passive","removeEventListener","observeElementOffset","observeWindowOffset","measureElement","getBoundingClientRect","constructor","_this","this","unsubs","isScrolling","isScrollingTimeoutId","measurementsCache","itemMeasurementsCache","pendingMeasuredCacheIndexes","scrollDelta","measureElementCache","getResizeObserver","_ro","ResizeObserver","entries","forEach","entry","_measureElement","setOptions","Object","_ref3","value","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","enableSmoothScroll","initialRect","width","height","scrollingDelay","indexAttribute","notify","_this$options$onChang","_this$options","call","cleanup","filter","Boolean","d","_didMount","_this$getResizeObserv","disconnect","_willUpdate","getScrollElement","_scrollToOffset","scrollOffset","canSmooth","sync","requested","observeElementRect","rect","scrollRect","calculateRange","clearTimeout","setTimeout","getSize","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","outerSize","_ref5","low","high","getCurrentValue","middle","currentValue","findNearestBinarySearch","getIndexes","indexFromElement","node","attributeName","indexStr","getAttribute","parseInt","warn","_sync","_this$itemMeasurement","item","prevNode","ro","isConnected","unobserve","observe","measuredItemSize","itemSize","undefined","destinationOffset","getVirtualItems","indexes","virtualItems","k","len","measurement","scrollToOffset","toOffset","_temp","align","smoothScroll","scrollToIndex","_temp2","rest","getTotalSize","_this$getMeasurements","_ref4","scrollCheckFrame","scrollToFn","check","lastOffset","measure","_ref2","_instance$scrollEleme2","scrollTo","behavior","observer","_entries$","_entries$2","contentRect","memoizedCallback","prev","memoRectCallback","onResize","innerWidth","innerHeight","_ref","_instance$scrollEleme"],"mappings":";;;;;;;;;;mPAIO,SAASA,EACdC,EACAC,EACAC,GAMA,IACIC,EADAC,EAAc,GAGlB,MAAO,KACL,IAAIC,EACAH,EAAKI,KAAOJ,MAAAA,EAAKK,OAALL,EAAKK,UAAWF,EAAUG,KAAKC,OAE/C,MAAMC,EAAUV,IAMhB,KAHEU,EAAQC,SAAWP,EAAKO,QACxBD,EAAQE,MAAK,CAACC,EAAUC,IAAkBV,EAAKU,KAAWD,KAG1D,OAAOV,EAKT,IAAIY,EAMJ,GARAX,EAAOM,EAGHR,EAAKI,KAAOJ,MAAAA,EAAKK,OAALL,EAAKK,UAAWQ,EAAaP,KAAKC,OAElDN,EAASF,KAAMS,GACX,MAAJR,SAAAA,EAAMc,UAANd,EAAMc,SAAWb,GAEbD,EAAKI,KAAL,MAAYJ,EAAKK,OAALL,EAAKK,QAAW,CAC9B,MAAMU,EAAaC,KAAKC,MAAgC,KAAzBX,KAAKC,MAAQJ,IAAmB,IACzDe,EAAgBF,KAAKC,MAAmC,KAA5BX,KAAKC,MAAQM,IAAsB,IAC/DM,EAAsBD,EAAgB,GAEtCE,EAAM,CAACC,EAAsBC,KAEjC,IADAD,EAAME,OAAOF,GACNA,EAAIZ,OAASa,GAClBD,EAAM,IAAMA,EAEd,OAAOA,CAAP,EAGFG,QAAQC,KAAR,OACSL,EAAIF,EAAe,GAD5B,KACmCE,EAAIL,EAAY,oGAIhCC,KAAKU,IAChB,EACAV,KAAKW,IAAI,IAAM,IAAMR,EAAqB,MAPlD,iBASEnB,MAAAA,OAAAA,EAAAA,EAAMI,IAET,CAED,OAAOH,CAAP,CAEH,CCzBY2B,MAAAA,EAAuBhB,GAAkBA,EAEzCiB,EAAyBC,IACpC,MAAMC,EAAQf,KAAKU,IAAII,EAAME,WAAaF,EAAMG,SAAU,GACpDC,EAAMlB,KAAKW,IAAIG,EAAMK,SAAWL,EAAMG,SAAUH,EAAMM,MAAQ,GAE9DC,EAAM,GAEZ,IAAK,IAAIC,EAAIP,EAAOO,GAAKJ,EAAKI,IAC5BD,EAAIE,KAAKD,GAGX,OAAOD,CAAP,EA2EIG,EAAc,CAClBC,QAAS,CAAC,aAAc,aACxBC,OAAQ,CAAC,UAAW,YAGhBC,EAAwBC,GACrB,CAACC,EAAiCC,KACvC,IAAKD,EAASE,cACZ,OAGF,MAAMC,EAAQR,EAAYI,GAAM,GAC1BK,EAAQT,EAAYI,GAAM,GAEhC,IAAIM,EAAgBL,EAASE,cAAcC,GACvCG,EAAgBN,EAASE,cAAcE,GAE3C,MAAMG,EAAS,KACb,MAAMC,EACJR,EAASE,cAAcF,EAASS,QAAQC,WAAaP,EAAQC,GAE/DH,EAAG9B,KAAKU,IAAI,EAAG2B,EAASR,EAASS,QAAQE,cAAzC,EAGFJ,IAEA,MAAMK,EAAYC,IAChB,MAAMC,EAASD,EAAEE,cACXC,EAAUF,EAAOX,GACjBc,EAAUH,EAAOV,IAEnBJ,EAASS,QAAQC,WAAaL,EAAQW,EAAUV,EAAQW,IAC1DV,IAGFF,EAAQW,EACRV,EAAQW,CAAR,EAQF,OALAjB,EAASE,cAAcgB,iBAAiB,SAAUN,EAAU,CAC1DO,SAAS,EACTC,SAAS,IAGJ,KACLpB,EAASE,cAAcmB,oBAAoB,SAAUT,EAArD,CADF,EAMSU,EAAuBxB,EAAqB,WAC5CyB,EAAsBzB,EAAqB,UAE3C0B,EAAiB,CAC5B5B,EACAI,IAEO7B,KAAKC,MACVwB,EAAQ6B,wBACNzB,EAASS,QAAQC,WAAa,QAAU,yBA8EvC,MAwCLgB,YAAYvE,GAAwD,IAAAwE,EAAAC,KAAAA,KApC5DC,OAAkC,GAoC0BD,KAlCpE1B,cAAuC,KAkC6B0B,KAjCpEE,aAAuB,EAiC6CF,KAhC5DG,qBAA6D,KAgCDH,KA/BpEI,kBAAmC,GA+BiCJ,KA9B5DK,sBAA6C,GA8BeL,KA7B5DM,4BAAwC,GA6BoBN,KA1B5DO,YAAsB,EA0BsCP,KAvB5DQ,oBAAiD,GAuBWR,KAtB5DS,kBAAoB,MAC1B,IAAIC,EAA6B,KAEjC,MAAO,IACDA,IAEiC,oBAAnBC,eACRD,EAAM,IAAIC,gBAAgBC,IAChCA,EAAQC,SAASC,IACfd,KAAKe,gBAAgBD,EAAM5B,QAAwB,EAAnD,GADF,IAKK,KAbe,EAAA,GAsBwCc,KALpE3C,MAAkD,CAChDE,WAAY,EACZG,SAAU,GAGwDsC,KAQpEgB,WAAczF,IACZ0F,OAAOL,QAAQrF,GAAMsF,SAAQK,IAAkB,IAAhBvF,EAAKwF,GAAWD,OACxB,IAAVC,UAA+B5F,EAAaI,EAArB,IAGpCqE,KAAKnB,QAAU,CACbjD,OAAO,EACPwF,cAAe,EACf5D,SAAU,EACV6D,aAAc,EACdC,WAAY,EACZC,mBAAoB,EACpBC,iBAAkB,EAClB1C,YAAY,EACZ2C,WAAYtE,EACZuE,eAAgBtE,EAChBuE,oBAAoB,EACpBtF,SAAU,OACVuD,iBACAgC,YAAa,CAAEC,MAAO,EAAGC,OAAQ,GACjC/C,aAAc,EACdgD,eAAgB,IAChBC,eAAgB,gBACbzG,EAlBL,EAbkEyE,KAmC5DiC,OAAS,KAAM,IAAAC,EAAAC,EACrB,OAAAD,GAAAC,EAAAnC,KAAKnB,SAAQxC,WAAb6F,EAAAE,KAAAD,EAAwBnC,KAAxB,EApCkEA,KAuC5DqC,QAAU,KAChBrC,KAAKC,OAAOqC,OAAOC,SAAS1B,SAAS2B,GAAMA,MAC3CxC,KAAKC,OAAS,GACdD,KAAK1B,cAAgB,IAArB,EA1CkE0B,KA6CpEyC,UAAY,IACH,KAAM,IAAAC,SACNjC,EAAAA,KAAAA,wBAAqBkC,aAC1B3C,KAAKQ,oBAAsB,GAE3BR,KAAKqC,SAAL,EAlDgErC,KAsDpE4C,YAAc,KACZ,MAAMtE,EAAgB0B,KAAKnB,QAAQgE,mBAE/B7C,KAAK1B,gBAAkBA,GACzB0B,KAAKqC,UAELrC,KAAK1B,cAAgBA,EACrB0B,KAAK8C,gBAAgB9C,KAAK+C,aAAc,CACtCC,WAAW,EACXC,MAAM,EACNC,WAAW,IAGblD,KAAKC,OAAOnC,KACVkC,KAAKnB,QAAQsE,mBAAmBnD,MAAOoD,IACrCpD,KAAKqD,WAAaD,EAClBpD,KAAKsD,gBAAL,KAIJtD,KAAKC,OAAOnC,KACVkC,KAAKnB,QAAQa,qBAAqBM,MAAOpB,IACL,OAA9BoB,KAAKG,uBACPoD,aAAavD,KAAKG,sBAClBH,KAAKG,qBAAuB,MAG1BH,KAAK+C,eAAiBnE,GACxBoB,KAAK+C,aAAenE,EACpBoB,KAAKE,aAAc,EACnBF,KAAKO,YAAc,EAEnBP,KAAKG,qBAAuBqD,YAAW,KACrCxD,KAAKG,qBAAuB,KAC5BH,KAAKE,aAAc,EAEnBF,KAAKiC,QAAL,GACCjC,KAAKnB,QAAQkD,kBAEhB/B,KAAKE,aAAc,EACnBF,KAAKO,YAAc,GAGrBP,KAAKsD,gBAAL,MAGMtD,KAAKE,aACfF,KAAKsD,gBACN,EAtGiEtD,KAyG5DyD,QAAU,IACTzD,KAAKqD,WAAWrD,KAAKnB,QAAQC,WAAa,QAAU,UA1GOkB,KA6G5D0D,gBAAkBtI,GACxB,IAAM,CACJ4E,KAAKnB,QAAQlB,MACbqC,KAAKnB,QAAQwC,aACbrB,KAAKnB,QAAQ4C,WACbzB,KAAKK,yBAEP,CAAC1C,EAAO0D,EAAcI,EAAYrB,KAChC,MAAMlD,EACJ8C,KAAKM,4BAA4BtE,OAAS,EACtCO,KAAKW,OAAO8C,KAAKM,6BACjB,EACNN,KAAKM,4BAA8B,GAEnC,MAAMqD,EAAe3D,KAAKI,kBAAkBwD,MAAM,EAAG1G,GAErD,IAAK,IAAIW,EAAIX,EAAKW,EAAIF,EAAOE,IAAK,CAChC,MAAMlC,EAAM8F,EAAW5D,GACjBgG,EAAezD,EAAkBzE,GACjC2B,EAAQqG,EAAa9F,EAAI,GAC3B8F,EAAa9F,EAAI,GAAIJ,IACrB4D,EACEyC,EACoB,iBAAjBD,EACHA,EACA7D,KAAKnB,QAAQkF,aAAalG,GAC1BJ,EAAMH,EAAQwG,EACpBH,EAAa9F,GAAK,CAAE1B,MAAO0B,EAAGP,QAAOwG,OAAMrG,MAAK9B,MACjD,CAGD,OADAqE,KAAKI,kBAAoBuD,EAClBA,CAAP,GAEF,CACEhI,KAAKqI,EACLpI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAhJsCoE,KAoJpEsD,eAAiBlI,GACf,IAAM,CAAC4E,KAAK0D,kBAAmB1D,KAAKyD,UAAWzD,KAAK+C,gBACpD,CAACY,EAAcM,EAAWlB,KACxB,MAAM1F,EA8RZ,SAQG6G,GAAA,IARqBP,aACtBA,EADsBM,UAEtBA,EAFsBlB,aAGtBA,GAKCmB,EACD,MAAMvG,EAAQgG,EAAa3H,OAAS,EAG9BuB,EAtCwB,EAC9B4G,EACAC,EACAC,EACAlD,KAEA,KAAOgD,GAAOC,GAAM,CAClB,MAAME,GAAWH,EAAMC,GAAQ,EAAK,EAC9BG,EAAeF,EAAgBC,GAErC,GAAIC,EAAepD,EACjBgD,EAAMG,EAAS,MACV,MAAIC,EAAepD,GAGxB,OAAOmD,EAFPF,EAAOE,EAAS,CAGjB,CACF,CAED,OAAIH,EAAM,EACDA,EAAM,EAEN,CACR,EAekBK,CAAwB,EAAG7G,GAF3BxB,GAAkBwH,EAAaxH,GAAQmB,OAEMyF,GAChE,IAAIrF,EAAWH,EAEf,KACEG,EAAWC,GACXgG,EAAajG,GAAWD,IAAMsF,EAAekB,GAE7CvG,IAGF,MAAO,CAAEH,aAAYG,WACtB,CArTmB4F,CAAe,CAC3BK,eACAM,YACAlB,iBASF,OANE1F,EAAME,aAAeyC,KAAK3C,MAAME,YAChCF,EAAMK,WAAasC,KAAK3C,MAAMK,WAE9BsC,KAAK3C,MAAQA,EACb2C,KAAKiC,UAEAjC,KAAK3C,KAAZ,GAEF,CACE1B,KAAKqI,EACLpI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAvKsCoE,KA2K5DyE,WAAarJ,GACnB,IAAM,CACJ4E,KAAKnB,QAAQ6C,eACb1B,KAAK3C,MACL2C,KAAKnB,QAAQrB,SACbwC,KAAKnB,QAAQlB,SAEf,CAAC+D,EAAgBrE,EAAOG,EAAUG,IACzB+D,EAAe,IACjBrE,EACHG,WACAG,MAAOA,KAGX,CACEhC,KAAKqI,EACLpI,MAAO,IAAMoE,KAAKnB,QAAQjD,QA3LsCoE,KA+LpE0E,iBAAoBC,IAClB,MAAMC,EAAgB5E,KAAKnB,QAAQmD,eAC7B6C,EAAWF,EAAKG,aAAaF,GAEnC,OAAKC,EAOEE,SAASF,EAAU,KANxB9H,QAAQiI,KAAR,2BAC6BJ,EAD7B,mCAGQ,EAGV,EA1MkE5E,KA6M5De,gBAAkB,CAAC4D,EAAoBM,KAAmB,IAAAC,EAChE,MAAM/I,EAAQ6D,KAAK0E,iBAAiBC,GAE9BQ,EAAOnF,KAAKI,kBAAkBjE,GACpC,IAAKgJ,EACH,OAGF,MAAMC,EAAWpF,KAAKQ,oBAAoB2E,EAAKxJ,KAEzC0J,EAAKrF,KAAKS,oBAEhB,IAAKkE,EAAKW,YAKR,YAJIF,UACFC,GAAAA,EAAIE,UAAUH,UACPpF,KAAKQ,oBAAoB2E,EAAKxJ,OAKpCyJ,GAAYA,IAAaT,IACxBS,UACFC,GAAAA,EAAIE,UAAUH,IAEhBpF,KAAKQ,oBAAoB2E,EAAKxJ,KAAOgJ,QACrCU,GAAAA,EAAIG,QAAQb,IAGd,MAAMc,EAAmBzF,KAAKnB,QAAQe,eAAe+E,EAAM3E,MAErD0F,EAAQ,OAAAR,EAAGlF,KAAKK,sBAAsB8E,EAAKxJ,MAAnCuJ,EAA2CC,EAAKrB,KAE1D2B,IAAqBC,IACnBP,EAAK7H,MAAQ0C,KAAK+C,mBAKW4C,IAA3B3F,KAAK4F,oBACP5F,KAAKO,aAAekF,EAAmBC,EAEvC1F,KAAK8C,gBAAgB9C,KAAK+C,aAAe/C,KAAKO,YAAa,CACzDyC,WAAW,EACXC,MAAM,EACNC,WAAW,KAKjBlD,KAAKM,4BAA4BxC,KAAK3B,GACtC6D,KAAKK,sBAAwB,IACxBL,KAAKK,sBACR,CAAC8E,EAAKxJ,KAAM8J,GAEdzF,KAAKiC,SACN,EApQiEjC,KAuQpEJ,eAAkB+E,IACXA,GAIL3E,KAAKe,gBAAgB4D,GAAM,EAA3B,EA5QkE3E,KA+QpE6F,gBAAkBzK,GAChB,IAAM,CAAC4E,KAAKyE,aAAczE,KAAK0D,qBAC/B,CAACoC,EAASnC,KACR,MAAMoC,EAA8B,GAEpC,IAAK,IAAIC,EAAI,EAAGC,EAAMH,EAAQ9J,OAAQgK,EAAIC,EAAKD,IAAK,CAClD,MACME,EAAcvC,EADVmC,EAAQE,IAGlBD,EAAajI,KAAKoI,EACnB,CAED,OAAOH,CAAP,GAEF,CACEpK,KAAKqI,EACLpI,MAAO,IAAMoE,KAAKnB,QAAQjD,QA/RsCoE,KAmSpEmG,eAAiB,SACfC,EAKGC,GAAA,IAJHC,MACEA,EAAQ,QADVC,aAEEA,EAAexG,EAAKlB,QAAQ8C,+BACH,CAAA,EACxB0E,EACH,MAAMzH,EAASmB,EAAKgD,aACde,EAAO/D,EAAK0D,UAEJ,SAAV6C,IAEAA,EADEF,GAAYxH,EACN,QACCwH,GAAYxH,EAASkF,EACtB,MAEA,SAIZ,MAAMjF,EAAU,CACdmE,UAAWuD,EACXtD,MAAM,EACNC,WAAW,GAEC,UAAVoD,EACFvG,EAAK+C,gBAAgBsD,EAAUvH,GACZ,QAAVyH,EACTvG,EAAK+C,gBAAgBsD,EAAWtC,EAAMjF,GACnB,WAAVyH,GACTvG,EAAK+C,gBAAgBsD,EAAWtC,EAAO,EAAGjF,IAjUsBmB,KAqUpEwG,cAAgB,SACdrK,EAMGsK,GAAA,IALHH,MACEA,EAAQ,OADVC,aAEEA,EAAexG,EAAKlB,QAAQ8C,sBACzB+E,cACqB,CAAA,EACvBD,EACH,MAAM9C,EAAe5D,EAAK2D,kBACpB9E,EAASmB,EAAKgD,aACde,EAAO/D,EAAK0D,WACZ9F,MAAEA,GAAUoC,EAAKlB,QAEjBqH,EAAcvC,EAAapH,KAAKU,IAAI,EAAGV,KAAKW,IAAIf,EAAOwB,EAAQ,KAErE,IAAKuI,EACH,OAGF,GAAc,SAAVI,EACF,GAAIJ,EAAYzI,KAAOmB,EAASkF,EAAO/D,EAAKlB,QAAQ2C,iBAClD8E,EAAQ,UACH,MACLJ,EAAY5I,OACZsB,EAASmB,EAAKlB,QAAQ0C,oBAItB,OAFA+E,EAAQ,OAGT,CAGH,MAAMF,EACM,QAAVE,EACIJ,EAAYzI,IAAMsC,EAAKlB,QAAQ2C,iBAC/B0E,EAAY5I,MAAQyC,EAAKlB,QAAQ0C,mBAEvCxB,EAAKoG,eAAeC,EAAU,CAAEE,QAAOC,kBAAiBG,KA1WU1G,KA6WpE2G,aAAe,KAAA,IAAAC,EAAA,sBACPlD,kBAAkB1D,KAAKnB,QAAQlB,MAAQ,aAAIF,MAC/CuC,KAAKnB,QAAQwC,cAAgBrB,KAAKnB,QAAQyC,UAF/B,EA7WqDtB,KAiX5D8C,gBAAkB,CACxBlE,EAMGiI,KAAA,IAQCC,GAbJ5D,UACEA,EADFF,UAEEA,EAFFC,KAGEA,GAEC4D,EACHtD,aAAavD,KAAK8G,kBAEd5D,IACFlD,KAAK4F,kBAAoBhH,GAE3BoB,KAAKnB,QAAQkI,WAAWnI,EAAQ,CAAEoE,YAAWC,QAAQjD,MAIrD,MAAMgH,EAAQ,KACZ,IAAIC,EAAajH,KAAK+C,aACtB/C,KAAK8G,iBAAmBA,EAAmBtD,YAAW,KAChDxD,KAAK8G,mBAAqBA,IAI1B9G,KAAK+C,eAAiBkE,GAI1BA,EAAajH,KAAK+C,aAClBiE,KAJEhH,KAAK4F,uBAAoBD,EAItB,GACJ,IAXH,EAcFqB,GAAK,EAlZ6DhH,KAqZpEkH,QAAU,KACRlH,KAAKK,sBAAwB,GAC7BL,KAAKiC,QAAL,EAtZAjC,KAAKgB,WAAWzF,GAChByE,KAAKqD,WAAarD,KAAKnB,QAAQ+C,YAC/B5B,KAAK+C,aAAe/C,KAAKnB,QAAQuC,cAEjCpB,KAAKsD,gBACN,qEA1G0B,CAC3B1E,EAD2BuI,EAG3B/I,KACG,IAAAgJ,EAAA,IAFHpE,UAAEA,EAAFC,KAAaA,GAEVkE,EACH,MAAMf,EAAWnD,EAAOrE,EAASA,EAASR,EAASS,QAAQE,oBAE1DqI,EAAChJ,EAASE,gBAAV,QAAqC+I,UAArCD,EAAqCC,SAAW,CAC/C,CAACjJ,EAASS,QAAQC,WAAa,OAAS,OAAQsH,EAChDkB,SAAUtE,EAAY,cAAW2C,GAFlC,4EAzI+B,CAChCvH,EACAC,KAEA,MAAMkJ,EAAW,IAAI5G,gBAAgBC,IAAY,IAAA4G,EAAAC,EAC/CpJ,EAAG,CACDwD,MAAO,OAAF2F,EAAE5G,EAAQ,SAAR,EAAA4G,EAAYE,YAAY7F,MAC/BC,OAAQ,OAAF2F,EAAE7G,EAAQ,SAAR,EAAA6G,EAAYC,YAAY5F,QAFlC,IAMF,GAAK1D,EAASE,cAQd,OAJAD,EAAGD,EAASE,cAAcuB,yBAE1B0H,EAAS/B,QAAQpH,EAASE,eAEnB,KACLiJ,EAAShC,UAAUnH,EAASE,cAA5B,CADF,8CAK+B,CAC/BF,EACAC,KAEA,MAAMsJ,EA/CiB,EACvBvJ,EACAC,KAEA,IAAIuJ,EAAa,CAAE9F,QAAS,EAAGD,OAAQ,GAEvC,OAAQuB,KAEJhF,EAASS,QAAQC,WACbsE,EAAKvB,QAAU+F,EAAK/F,MACpBuB,EAAKtB,SAAW8F,EAAK9F,SAEzBzD,EAAG+E,GAGLwE,EAAOxE,CAAP,CATF,EAyCyByE,CAAiBzJ,EAAUC,GAC9CyJ,EAAW,IACfH,EAAiB,CACf9F,MAAOzD,EAASE,cAAcyJ,WAC9BjG,OAAQ1D,EAASE,cAAc0J,cAGnC,GAAK5J,EAASE,cAWd,OAPAwJ,IAEA1J,EAASE,cAAcgB,iBAAiB,SAAUwI,EAAU,CAC1DvI,SAAS,EACTC,SAAS,IAGJ,KACLpB,EAASE,cAAcmB,oBAAoB,SAAUqI,EAArD,CADF,iBAuE0B,CAC1BlJ,EAD0BqJ,EAG1B7J,KACG,IAAA8J,EAAA,IAFHlF,UAAEA,EAAFC,KAAaA,GAEVgF,EACH,MAAM7B,EAAWnD,EAAOrE,EAASA,EAASR,EAASS,QAAQE,oBAE1DmJ,EAAC9J,EAASE,gBAAV,QAAoC+I,UAApCa,EAAoCb,SAAW,CAC9C,CAACjJ,EAASS,QAAQC,WAAa,OAAS,OAAQsH,EAChDkB,SAAUtE,EAAY,cAAW2C,GAFlC"}
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.21",
4
+ "version": "3.0.0-beta.22",
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
@@ -280,12 +280,24 @@ export class Virtualizer<
280
280
  private scrollDelta: number = 0
281
281
  private destinationOffset: undefined | number
282
282
  private scrollCheckFrame!: ReturnType<typeof setTimeout>
283
- private measureElementCache: Record<string, TItemElement> = {}
284
- private ro = new ResizeObserver((entries) => {
285
- entries.forEach((entry) => {
286
- this._measureElement(entry.target as TItemElement, false)
287
- })
288
- })
283
+ private measureElementCache: Record<Key, TItemElement> = {}
284
+ private getResizeObserver = (() => {
285
+ let _ro: ResizeObserver | null = null
286
+
287
+ return () => {
288
+ if (_ro) {
289
+ return _ro
290
+ } else if (typeof ResizeObserver !== 'undefined') {
291
+ return (_ro = new ResizeObserver((entries) => {
292
+ entries.forEach((entry) => {
293
+ this._measureElement(entry.target as TItemElement, false)
294
+ })
295
+ }))
296
+ } else {
297
+ return null
298
+ }
299
+ }
300
+ })()
289
301
  range: { startIndex: number; endIndex: number } = {
290
302
  startIndex: 0,
291
303
  endIndex: 0,
@@ -338,7 +350,7 @@ export class Virtualizer<
338
350
 
339
351
  _didMount = () => {
340
352
  return () => {
341
- this.ro.disconnect()
353
+ this.getResizeObserver()?.disconnect()
342
354
  this.measureElementCache = {}
343
355
 
344
356
  this.cleanup()
@@ -496,31 +508,32 @@ export class Virtualizer<
496
508
  return parseInt(indexStr, 10)
497
509
  }
498
510
 
499
- _measureElement = (node: TItemElement, _sync: boolean) => {
511
+ private _measureElement = (node: TItemElement, _sync: boolean) => {
500
512
  const index = this.indexFromElement(node)
501
513
 
502
514
  const item = this.measurementsCache[index]
503
515
  if (!item) {
504
516
  return
505
517
  }
506
- const key = String(item.key)
507
518
 
508
- const prevNode = this.measureElementCache[key]
519
+ const prevNode = this.measureElementCache[item.key]
520
+
521
+ const ro = this.getResizeObserver()
509
522
 
510
523
  if (!node.isConnected) {
511
524
  if (prevNode) {
512
- this.ro.unobserve(prevNode)
513
- delete this.measureElementCache[key]
525
+ ro?.unobserve(prevNode)
526
+ delete this.measureElementCache[item.key]
514
527
  }
515
528
  return
516
529
  }
517
530
 
518
531
  if (!prevNode || prevNode !== node) {
519
532
  if (prevNode) {
520
- this.ro.unobserve(prevNode)
533
+ ro?.unobserve(prevNode)
521
534
  }
522
- this.measureElementCache[key] = node
523
- this.ro.observe(node)
535
+ this.measureElementCache[item.key] = node
536
+ ro?.observe(node)
524
537
  }
525
538
 
526
539
  const measuredItemSize = this.options.measureElement(node, this)