@tanstack/virtual-core 3.0.0-beta.26 → 3.0.0-beta.29

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\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\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 = <T extends Window>(\n offset: number,\n {\n adjustments,\n behavior,\n sync,\n }: { adjustments?: number; behavior?: ScrollBehavior; sync: boolean },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset =\n (sync ? offset : offset + instance.options.scrollMargin) +\n (adjustments ?? 0)\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,\n behavior,\n sync,\n }: { adjustments?: number; behavior?: ScrollBehavior; sync: boolean },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset =\n (sync ? offset : offset + instance.options.scrollMargin) +\n (adjustments ?? 0)\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; 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 scrollMargin?: number\n scrollingDelay?: number\n indexAttribute?: string\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 measurementsCache: VirtualItem[] = []\n private itemMeasurementsCache: Record<Key, number> = {}\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n private scrollOffset: number\n private scrollAdjustments: number = 0\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 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\n this._scrollToOffset(this.scrollOffset, {\n adjustments: undefined,\n behavior: undefined,\n sync: true,\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.scrollAdjustments = 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.scrollAdjustments = 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 const delta = measuredItemSize - itemSize\n\n if (delta !== 0) {\n if (item.start < this.scrollOffset && this.isScrolling) {\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 sync: false,\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 { align = 'start', behavior }: 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 adjustments: undefined,\n behavior,\n sync: false,\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 { align = 'auto', ...rest }: 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, ...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 adjustments,\n behavior,\n sync,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n sync: boolean\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, sync, adjustments }, this)\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","scrollAdjustments","measureElementCache","getResizeObserver","_ro","ResizeObserver","entries","forEach","entry","_measureElement","setOptions","Object","_ref3","value","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","initialRect","width","height","scrollingDelay","indexAttribute","notify","_this$options$onChang","_this$options","call","cleanup","filter","Boolean","d","_didMount","_this$getResizeObserv","disconnect","_willUpdate","getScrollElement","_scrollToOffset","scrollOffset","adjustments","undefined","behavior","sync","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","item","prevNode","ro","isConnected","unobserve","observe","measuredItemSize","delta","getVirtualItems","indexes","virtualItems","k","len","measurement","scrollToOffset","toOffset","_temp","align","scrollToIndex","_temp2","rest","getTotalSize","_this$getMeasurements","_ref4","scrollToFn","measure","_ref2","_instance$scrollEleme2","scrollTo","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,GAAc,MAAdA,EAAMc,UAANd,EAAMc,SAAWb,GAEbD,EAAKI,KAAiB,MAAVJ,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,CAAG,EAGZG,QAAQC,KACL,OAAML,EAAIF,EAAe,OAAOE,EAAIL,EAAY,QAChD,2FAGgBC,KAAKU,IAChB,EACAV,KAAKW,IAAI,IAAM,IAAMR,EAAqB,sBAEhDnB,MAAAA,OAAAA,EAAAA,EAAMI,IAEV,CAEA,OAAOH,CAAM,CAEjB,CCvBa2B,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,CAAG,EA2ENG,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,cAAc,EAGzDJ,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,CAAO,EAQjB,OALAjB,EAASE,cAAcgB,iBAAiB,SAAUN,EAAU,CAC1DO,SAAS,EACTC,SAAS,IAGJ,KACLpB,EAASE,cAAcmB,oBAAoB,SAAUT,EAAS,CAC/D,EAIQU,EAAuBxB,EAAqB,WAC5CyB,EAAsBzB,EAAqB,UAE3C0B,EAAiB,CAC5B5B,EACAI,IAEO7B,KAAKC,MACVwB,EAAQ6B,wBACNzB,EAASS,QAAQC,WAAa,QAAU,yBAyFvC,MAsCLgB,YAAYvE,GAAwD,IAAAwE,EAAAC,KAAAA,KAlC5DC,OAAkC,GAAED,KAE5C1B,cAAuC,KAAI0B,KAC3CE,aAAuB,EAAKF,KACpBG,qBAA6D,KAAIH,KACzEI,kBAAmC,GAAEJ,KAC7BK,sBAA6C,GAAEL,KAC/CM,4BAAwC,GAAEN,KAG1CO,kBAA4B,EAACP,KAC7BQ,oBAAiD,GAAER,KACnDS,kBAAoB,MAC1B,IAAIC,EAA6B,KAEjC,MAAO,IACDA,IAEiC,oBAAnBC,eACRD,EAAM,IAAIC,gBAAgBC,IAChCA,EAAQC,SAASC,IACfd,KAAKe,gBAAgBD,EAAM5B,QAAwB,EAAM,GACzD,IAGG,KAGZ,EAhB2B,GAgBxBc,KACJ3C,MAAkD,CAChDE,WAAY,EACZG,SAAU,GACXsC,KAUDgB,WAAczF,IACZ0F,OAAOL,QAAQrF,GAAMsF,SAAQK,IAAkB,IAAhBvF,EAAKwF,GAAMD,OACnB,IAAVC,UAA+B5F,EAAaI,EAAI,IAG7DqE,KAAKnB,QAAU,CACbjD,OAAO,EACPwF,cAAe,EACf5D,SAAU,EACV6D,aAAc,EACdC,WAAY,EACZC,mBAAoB,EACpBC,iBAAkB,EAClB1C,YAAY,EACZ2C,WAAYtE,EACZuE,eAAgBtE,EAChBf,SAAU,OACVuD,iBACA+B,YAAa,CAAEC,MAAO,EAAGC,OAAQ,GACjC9C,aAAc,EACd+C,eAAgB,IAChBC,eAAgB,gBACbxG,EACJ,EACFyE,KAEOgC,OAAS,KAAM,IAAAC,EAAAC,EACrB,OAAAD,GAAAC,EAAAlC,KAAKnB,SAAQxC,WAAb4F,EAAAE,KAAAD,EAAwBlC,KAAK,EAC9BA,KAEOoC,QAAU,KAChBpC,KAAKC,OAAOoC,OAAOC,SAASzB,SAAS0B,GAAMA,MAC3CvC,KAAKC,OAAS,GACdD,KAAK1B,cAAgB,IAAI,EAC1B0B,KAEDwC,UAAY,IACH,KAAM,IAAAC,EACX,OAAAA,EAAAzC,KAAKS,sBAALgC,EAA0BC,aAC1B1C,KAAKQ,oBAAsB,GAE3BR,KAAKoC,SAAS,EAEjBpC,KAED2C,YAAc,KACZ,MAAMrE,EAAgB0B,KAAKnB,QAAQ+D,mBAE/B5C,KAAK1B,gBAAkBA,GACzB0B,KAAKoC,UAELpC,KAAK1B,cAAgBA,EAErB0B,KAAK6C,gBAAgB7C,KAAK8C,aAAc,CACtCC,iBAAaC,EACbC,cAAUD,EACVE,MAAM,IAGRlD,KAAKC,OAAOnC,KACVkC,KAAKnB,QAAQsE,mBAAmBnD,MAAOoD,IACrCpD,KAAKqD,WAAaD,EAClBpD,KAAKsD,gBAAgB,KAIzBtD,KAAKC,OAAOnC,KACVkC,KAAKnB,QAAQa,qBAAqBM,MAAOpB,IACL,OAA9BoB,KAAKG,uBACPoD,aAAavD,KAAKG,sBAClBH,KAAKG,qBAAuB,MAG1BH,KAAK8C,eAAiBlE,GACxBoB,KAAK8C,aAAelE,EACpBoB,KAAKE,aAAc,EACnBF,KAAKO,kBAAoB,EAEzBP,KAAKG,qBAAuBqD,YAAW,KACrCxD,KAAKG,qBAAuB,KAC5BH,KAAKE,aAAc,EAEnBF,KAAKgC,QAAQ,GACZhC,KAAKnB,QAAQiD,kBAEhB9B,KAAKE,aAAc,EACnBF,KAAKO,kBAAoB,GAG3BP,KAAKsD,gBAAgB,MAGftD,KAAKE,aACfF,KAAKsD,gBACP,EACDtD,KAEOyD,QAAU,IACTzD,KAAKqD,WAAWrD,KAAKnB,QAAQC,WAAa,QAAU,UAC5DkB,KAEO0D,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,MAClD,CAGA,OADAqE,KAAKI,kBAAoBuD,EAClBA,CAAY,GAErB,CACEhI,KAAKqI,EACLpI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAE7BoE,KAEDsD,eAAiBlI,GACf,IAAM,CAAC4E,KAAK0D,kBAAmB1D,KAAKyD,UAAWzD,KAAK8C,gBACpD,CAACa,EAAcM,EAAWnB,KACxB,MAAMzF,EAgQZ,SAQG6G,GAAA,IARqBP,aACtBA,EAAYM,UACZA,EAASnB,aACTA,GAKDoB,EACC,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,CAGlB,CACF,CAEA,OAAIH,EAAM,EACDA,EAAM,EAEN,CACT,EAemBK,CAAwB,EAAG7G,GAF3BxB,GAAkBwH,EAAaxH,GAAQmB,OAEMwF,GAChE,IAAIpF,EAAWH,EAEf,KACEG,EAAWC,GACXgG,EAAajG,GAAWD,IAAMqF,EAAemB,GAE7CvG,IAGF,MAAO,CAAEH,aAAYG,WACvB,CAvRoB4F,CAAe,CAC3BK,eACAM,YACAnB,iBASF,OANEzF,EAAME,aAAeyC,KAAK3C,MAAME,YAChCF,EAAMK,WAAasC,KAAK3C,MAAMK,WAE9BsC,KAAK3C,MAAQA,EACb2C,KAAKgC,UAEAhC,KAAK3C,KAAK,GAEnB,CACE1B,KAAKqI,EACLpI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAE7BoE,KAEOyE,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,QAE7BoE,KAED0E,iBAAoBC,IAClB,MAAMC,EAAgB5E,KAAKnB,QAAQkD,eAC7B8C,EAAWF,EAAKG,aAAaF,GAEnC,OAAKC,EAOEE,SAASF,EAAU,KANxB9H,QAAQiI,KACL,2BAA0BJ,oCAErB,EAGmB,EAC9B5E,KAEOe,gBAAkB,CAAC4D,EAAoBM,KAC7C,MAAM9I,EAAQ6D,KAAK0E,iBAAiBC,GAE9BO,EAAOlF,KAAKI,kBAAkBjE,GACpC,IAAK+I,EACH,OAGF,MAAMC,EAAWnF,KAAKQ,oBAAoB0E,EAAKvJ,KAEzCyJ,EAAKpF,KAAKS,oBAEhB,IAAKkE,EAAKU,YAKR,YAJIF,UACFC,GAAAA,EAAIE,UAAUH,UACPnF,KAAKQ,oBAAoB0E,EAAKvJ,OAKpCwJ,GAAYA,IAAaR,IACxBQ,UACFC,GAAAA,EAAIE,UAAUH,IAEhBnF,KAAKQ,oBAAoB0E,EAAKvJ,KAAOgJ,QACrCS,GAAAA,EAAIG,QAAQZ,IAGd,MAAMa,EAAmBxF,KAAKnB,QAAQe,eAAe+E,EAAM3E,MAIrDyF,EAAQD,GAFGxF,KAAKK,sBAAsB6E,EAAKvJ,MAAQuJ,EAAKpB,MAIhD,IAAV2B,IACEP,EAAK5H,MAAQ0C,KAAK8C,cAAgB9C,KAAKE,aAKzCF,KAAK6C,gBAAgB7C,KAAK8C,aAAc,CACtCC,YAAc/C,KAAKO,mBAAqBkF,EACxCxC,cAAUD,EACVE,MAAM,IAIVlD,KAAKM,4BAA4BxC,KAAK3B,GACtC6D,KAAKK,sBAAwB,IACxBL,KAAKK,sBACR,CAAC6E,EAAKvJ,KAAM6J,GAEdxF,KAAKgC,SACP,EACDhC,KAEDJ,eAAkB+E,IACXA,GAIL3E,KAAKe,gBAAgB4D,GAAM,EAAK,EACjC3E,KAED0F,gBAAkBtK,GAChB,IAAM,CAAC4E,KAAKyE,aAAczE,KAAK0D,qBAC/B,CAACiC,EAAShC,KACR,MAAMiC,EAA8B,GAEpC,IAAK,IAAIC,EAAI,EAAGC,EAAMH,EAAQ3J,OAAQ6J,EAAIC,EAAKD,IAAK,CAClD,MACME,EAAcpC,EADVgC,EAAQE,IAGlBD,EAAa9H,KAAKiI,EACpB,CAEA,OAAOH,CAAY,GAErB,CACEjK,KAAKqI,EACLpI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAE7BoE,KAEDgG,eAAiB,SACfC,EAEGC,GAAA,IADHC,MAAEA,EAAQ,QAAOlD,SAAEA,QAAiC,IAAAiD,EAAG,CAAA,EAAEA,EAEzD,MAAMtH,EAASmB,EAAK+C,aACdgB,EAAO/D,EAAK0D,UAEJ,SAAV0C,IAEAA,EADEF,GAAYrH,EACN,QACCqH,GAAYrH,EAASkF,EACtB,MAEA,SAIZ,MAAMjF,EAAU,CACdkE,iBAAaC,EACbC,WACAC,MAAM,GAEM,UAAViD,EACFpG,EAAK8C,gBAAgBoD,EAAUpH,GACZ,QAAVsH,EACTpG,EAAK8C,gBAAgBoD,EAAWnC,EAAMjF,GACnB,WAAVsH,GACTpG,EAAK8C,gBAAgBoD,EAAWnC,EAAO,EAAGjF,IAE7CmB,KAEDoG,cAAgB,SACdjK,EAEGkK,GAAA,IADHF,MAAEA,EAAQ,UAAWG,QAA4B,IAAAD,EAAG,CAAA,EAAEA,EAEtD,MAAM1C,EAAe5D,EAAK2D,kBACpB9E,EAASmB,EAAK+C,aACdgB,EAAO/D,EAAK0D,WACZ9F,MAAEA,GAAUoC,EAAKlB,QAEjBkH,EAAcpC,EAAapH,KAAKU,IAAI,EAAGV,KAAKW,IAAIf,EAAOwB,EAAQ,KAErE,IAAKoI,EACH,OAGF,GAAc,SAAVI,EACF,GAAIJ,EAAYtI,KAAOmB,EAASkF,EAAO/D,EAAKlB,QAAQ2C,iBAClD2E,EAAQ,UACH,MACLJ,EAAYzI,OACZsB,EAASmB,EAAKlB,QAAQ0C,oBAItB,OAFA4E,EAAQ,OAGV,CAGF,MAAMF,EACM,QAAVE,EACIJ,EAAYtI,IAAMsC,EAAKlB,QAAQ2C,iBAC/BuE,EAAYzI,MAAQyC,EAAKlB,QAAQ0C,mBAEvCxB,EAAKiG,eAAeC,EAAU,CAAEE,WAAUG,KAC3CtG,KAEDuG,aAAe,KAAA,IAAAC,EAAA,QACZ,OAAAA,EAAAxG,KAAK0D,kBAAkB1D,KAAKnB,QAAQlB,MAAQ,SAA5C,EAAA6I,EAAgD/I,MAC/CuC,KAAKnB,QAAQwC,cAAgBrB,KAAKnB,QAAQyC,UAAU,EAAAtB,KAEhD6C,gBAAkB,CACxBjE,EAUG6H,KAAA,IATH1D,YACEA,EAAWE,SACXA,EAAQC,KACRA,GAKDuD,EAEDzG,KAAKnB,QAAQ6H,WAAW9H,EAAQ,CAAEqE,WAAUC,OAAMH,eAAe/C,KAAK,EACvEA,KAED2G,QAAU,KACR3G,KAAKK,sBAAwB,GAC7BL,KAAKgC,QAAQ,EAxXbhC,KAAKgB,WAAWzF,GAChByE,KAAKqD,WAAarD,KAAKnB,QAAQ8C,YAC/B3B,KAAK8C,aAAe9C,KAAKnB,QAAQuC,cAEjCpB,KAAKsD,gBACP,qEA7G2B,CAC3B1E,EAAcgI,EAMdxI,KACG,IAAAyI,EAAA,IANH9D,YACEA,EAAWE,SACXA,EAAQC,KACRA,GACmE0D,EAGrE,MAAMX,GACH/C,EAAOtE,EAASA,EAASR,EAASS,QAAQE,eAC1CgE,GAAe,GAEI,OAAtB3E,EAAAA,EAASE,gBAAuB,MAAhCuI,EAAwBC,UAAxBD,EAAwBC,SAAW,CACjC,CAAC1I,EAASS,QAAQC,WAAa,OAAS,OAAQmH,EAChDhD,YACA,4EAxJ8B,CAChC7E,EACAC,KAEA,MAAM0I,EAAW,IAAIpG,gBAAgBC,IAAY,IAAAoG,EAAAC,EAC/C5I,EAAG,CACDuD,MAAO,OAAFoF,EAAEpG,EAAQ,SAAR,EAAAoG,EAAYE,YAAYtF,MAC/BC,OAAQ,OAAFoF,EAAErG,EAAQ,SAAR,EAAAqG,EAAYC,YAAYrF,QAChC,IAGJ,GAAKzD,EAASE,cAQd,OAJAD,EAAGD,EAASE,cAAcuB,yBAE1BkH,EAASxB,QAAQnH,EAASE,eAEnB,KACLyI,EAASzB,UAAUlH,EAASE,cAAc,CAC3C,8CAG8B,CAC/BF,EACAC,KAEA,MAAM8I,EA/CiB,EACvB/I,EACAC,KAEA,IAAI+I,EAAa,CAAEvF,QAAS,EAAGD,OAAQ,GAEvC,OAAQwB,KAEJhF,EAASS,QAAQC,WACbsE,EAAKxB,QAAUwF,EAAKxF,MACpBwB,EAAKvB,SAAWuF,EAAKvF,SAEzBxD,EAAG+E,GAGLgE,EAAOhE,CAAI,CACZ,EA+BwBiE,CAAiBjJ,EAAUC,GAC9CiJ,EAAW,IACfH,EAAiB,CACfvF,MAAOxD,EAASE,cAAciJ,WAC9B1F,OAAQzD,EAASE,cAAckJ,cAGnC,GAAKpJ,EAASE,cAWd,OAPAgJ,IAEAlJ,EAASE,cAAcgB,iBAAiB,SAAUgI,EAAU,CAC1D/H,SAAS,EACTC,SAAS,IAGJ,KACLpB,EAASE,cAAcmB,oBAAoB,SAAU6H,EAAS,CAC/D,iBAqEyB,CAC1B1I,EAAc6I,EAMdrJ,KACG,IAAAsJ,EAAA,IANH3E,YACEA,EAAWE,SACXA,EAAQC,KACRA,GACmEuE,EAGrE,MAAMxB,GACH/C,EAAOtE,EAASA,EAASR,EAASS,QAAQE,eAC1CgE,GAAe,GAEI,OAAtB3E,EAAAA,EAASE,gBAAuB,MAAhCoJ,EAAwBZ,UAAxBY,EAAwBZ,SAAW,CACjC,CAAC1I,EAASS,QAAQC,WAAa,OAAS,OAAQmH,EAChDhD,YACA"}
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\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\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 = <T extends Window>(\n offset: number,\n {\n adjustments,\n behavior,\n sync,\n }: { adjustments?: number; behavior?: ScrollBehavior; sync: boolean },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset =\n (sync ? offset : offset + instance.options.scrollMargin) +\n (adjustments ?? 0)\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,\n behavior,\n sync,\n }: { adjustments?: number; behavior?: ScrollBehavior; sync: boolean },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset =\n (sync ? offset : offset + instance.options.scrollMargin) +\n (adjustments ?? 0)\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; 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 scrollMargin?: number\n scrollingDelay?: number\n indexAttribute?: string\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 measurementsCache: VirtualItem[] = []\n private itemMeasurementsCache: Record<Key, number> = {}\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n private scrollOffset: number\n private scrollAdjustments: number = 0\n private measureElementCache: Record<Key, TItemElement> = {}\n private pendingScrollToIndexCallback: (() => void) | null = null\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 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 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 this.pendingScrollToIndexCallback?.()\n\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 sync: true,\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.scrollAdjustments = 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.scrollAdjustments = 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 const delta = measuredItemSize - itemSize\n\n if (delta !== 0) {\n if (item.start < this.scrollOffset && this.isScrolling) {\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 sync: false,\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 { align = 'start', behavior }: 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 adjustments: undefined,\n behavior,\n sync: false,\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 { align = 'auto', ...rest }: ScrollToIndexOptions = {},\n ) => {\n this.pendingScrollToIndexCallback = null\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, ...rest })\n\n const isDynamic = Object.keys(this.measureElementCache).length > 0\n\n if (isDynamic) {\n const didSeen = () =>\n typeof this.itemMeasurementsCache[this.options.getItemKey(index)] ===\n 'number'\n\n if (!didSeen()) {\n this.pendingScrollToIndexCallback = () => {\n if (didSeen()) {\n this.pendingScrollToIndexCallback = null\n this.scrollToIndex(index, { align, ...rest })\n }\n }\n }\n }\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 adjustments,\n behavior,\n sync,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n sync: boolean\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, sync, adjustments }, this)\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","scrollAdjustments","measureElementCache","pendingScrollToIndexCallback","getResizeObserver","_ro","ResizeObserver","entries","forEach","entry","_measureElement","setOptions","Object","_ref3","value","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","initialRect","width","height","scrollingDelay","indexAttribute","notify","_this$options$onChang","_this$options","call","cleanup","filter","Boolean","d","_didMount","ro","values","node","observe","disconnect","_willUpdate","_this$pendingScrollTo","getScrollElement","_scrollToOffset","scrollOffset","adjustments","undefined","behavior","sync","observeElementRect","rect","scrollRect","calculateRange","clearTimeout","setTimeout","getSize","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","outerSize","_ref5","low","high","getCurrentValue","middle","currentValue","findNearestBinarySearch","getIndexes","indexFromElement","attributeName","indexStr","getAttribute","parseInt","warn","_sync","item","prevNode","isConnected","unobserve","measuredItemSize","delta","getVirtualItems","indexes","virtualItems","k","len","measurement","scrollToOffset","toOffset","_temp","align","scrollToIndex","_temp2","rest","keys","didSeen","getTotalSize","_this$getMeasurements","_ref4","scrollToFn","measure","_ref2","_instance$scrollEleme2","scrollTo","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,GAAc,MAAdA,EAAMc,UAANd,EAAMc,SAAWb,GAEbD,EAAKI,KAAiB,MAAVJ,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,CAAG,EAGZG,QAAQC,KACL,OAAML,EAAIF,EAAe,OAAOE,EAAIL,EAAY,QAChD,2FAGgBC,KAAKU,IAChB,EACAV,KAAKW,IAAI,IAAM,IAAMR,EAAqB,sBAEhDnB,MAAAA,OAAAA,EAAAA,EAAMI,IAEV,CAEA,OAAOH,CAAM,CAEjB,CCvBa2B,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,CAAG,EA2ENG,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,cAAc,EAGzDJ,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,CAAO,EAQjB,OALAjB,EAASE,cAAcgB,iBAAiB,SAAUN,EAAU,CAC1DO,SAAS,EACTC,SAAS,IAGJ,KACLpB,EAASE,cAAcmB,oBAAoB,SAAUT,EAAS,CAC/D,EAIQU,EAAuBxB,EAAqB,WAC5CyB,EAAsBzB,EAAqB,UAE3C0B,EAAiB,CAC5B5B,EACAI,IAEO7B,KAAKC,MACVwB,EAAQ6B,wBACNzB,EAASS,QAAQC,WAAa,QAAU,yBAyFvC,MAuCLgB,YAAYvE,GAAwD,IAAAwE,EAAAC,KAAAA,KAnC5DC,OAAkC,GAAED,KAE5C1B,cAAuC,KAAI0B,KAC3CE,aAAuB,EAAKF,KACpBG,qBAA6D,KAAIH,KACzEI,kBAAmC,GAAEJ,KAC7BK,sBAA6C,GAAEL,KAC/CM,4BAAwC,GAAEN,KAG1CO,kBAA4B,EAACP,KAC7BQ,oBAAiD,GAAER,KACnDS,6BAAoD,KAAIT,KACxDU,kBAAoB,MAC1B,IAAIC,EAA6B,KAEjC,MAAO,IACDA,IAEiC,oBAAnBC,eACRD,EAAM,IAAIC,gBAAgBC,IAChCA,EAAQC,SAASC,IACff,KAAKgB,gBAAgBD,EAAM7B,QAAwB,EAAM,GACzD,IAGG,KAGZ,EAhB2B,GAgBxBc,KACJ3C,MAAkD,CAChDE,WAAY,EACZG,SAAU,GACXsC,KAUDiB,WAAc1F,IACZ2F,OAAOL,QAAQtF,GAAMuF,SAAQK,IAAkB,IAAhBxF,EAAKyF,GAAMD,OACnB,IAAVC,UAA+B7F,EAAaI,EAAI,IAG7DqE,KAAKnB,QAAU,CACbjD,OAAO,EACPyF,cAAe,EACf7D,SAAU,EACV8D,aAAc,EACdC,WAAY,EACZC,mBAAoB,EACpBC,iBAAkB,EAClB3C,YAAY,EACZ4C,WAAYvE,EACZwE,eAAgBvE,EAChBf,SAAU,OACVuD,iBACAgC,YAAa,CAAEC,MAAO,EAAGC,OAAQ,GACjC/C,aAAc,EACdgD,eAAgB,IAChBC,eAAgB,gBACbzG,EACJ,EACFyE,KAEOiC,OAAS,KAAM,IAAAC,EAAAC,EACrB,OAAAD,GAAAC,EAAAnC,KAAKnB,SAAQxC,WAAb6F,EAAAE,KAAAD,EAAwBnC,KAAK,EAC9BA,KAEOqC,QAAU,KAChBrC,KAAKC,OAAOqC,OAAOC,SAASzB,SAAS0B,GAAMA,MAC3CxC,KAAKC,OAAS,GACdD,KAAK1B,cAAgB,IAAI,EAC1B0B,KAEDyC,UAAY,KACV,MAAMC,EAAK1C,KAAKU,oBAGhB,OAFAQ,OAAOyB,OAAO3C,KAAKQ,qBAAqBM,SAAS8B,SAASF,SAAAA,EAAIG,QAAQD,KAE/D,KACLF,MAAAA,GAAAA,EAAII,aAEJ9C,KAAKqC,SAAS,CACf,EACFrC,KAED+C,YAAc,KAAM,IAAAC,EAClB,OAAAA,EAAAhD,KAAKS,+BAALuC,EAAAZ,KAAApC,MAEA,MAAM1B,EAAgB0B,KAAKnB,QAAQoE,mBAE/BjD,KAAK1B,gBAAkBA,GACzB0B,KAAKqC,UAELrC,KAAK1B,cAAgBA,EAErB0B,KAAKkD,gBAAgBlD,KAAKmD,aAAc,CACtCC,iBAAaC,EACbC,cAAUD,EACVE,MAAM,IAGRvD,KAAKC,OAAOnC,KACVkC,KAAKnB,QAAQ2E,mBAAmBxD,MAAOyD,IACrCzD,KAAK0D,WAAaD,EAClBzD,KAAK2D,gBAAgB,KAIzB3D,KAAKC,OAAOnC,KACVkC,KAAKnB,QAAQa,qBAAqBM,MAAOpB,IACL,OAA9BoB,KAAKG,uBACPyD,aAAa5D,KAAKG,sBAClBH,KAAKG,qBAAuB,MAG1BH,KAAKmD,eAAiBvE,GACxBoB,KAAKmD,aAAevE,EACpBoB,KAAKE,aAAc,EACnBF,KAAKO,kBAAoB,EAEzBP,KAAKG,qBAAuB0D,YAAW,KACrC7D,KAAKG,qBAAuB,KAC5BH,KAAKE,aAAc,EAEnBF,KAAKiC,QAAQ,GACZjC,KAAKnB,QAAQkD,kBAEhB/B,KAAKE,aAAc,EACnBF,KAAKO,kBAAoB,GAG3BP,KAAK2D,gBAAgB,MAGf3D,KAAKE,aACfF,KAAK2D,gBACP,EACD3D,KAEO8D,QAAU,IACT9D,KAAK0D,WAAW1D,KAAKnB,QAAQC,WAAa,QAAU,UAC5DkB,KAEO+D,gBAAkB3I,GACxB,IAAM,CACJ4E,KAAKnB,QAAQlB,MACbqC,KAAKnB,QAAQyC,aACbtB,KAAKnB,QAAQ6C,WACb1B,KAAKK,yBAEP,CAAC1C,EAAO2D,EAAcI,EAAYtB,KAChC,MAAMlD,EACJ8C,KAAKM,4BAA4BtE,OAAS,EACtCO,KAAKW,OAAO8C,KAAKM,6BACjB,EACNN,KAAKM,4BAA8B,GAEnC,MAAM0D,EAAehE,KAAKI,kBAAkB6D,MAAM,EAAG/G,GAErD,IAAK,IAAIW,EAAIX,EAAKW,EAAIF,EAAOE,IAAK,CAChC,MAAMlC,EAAM+F,EAAW7D,GACjBqG,EAAe9D,EAAkBzE,GACjC2B,EAAQ0G,EAAanG,EAAI,GAC3BmG,EAAanG,EAAI,GAAIJ,IACrB6D,EACE6C,EACoB,iBAAjBD,EACHA,EACAlE,KAAKnB,QAAQuF,aAAavG,GAC1BJ,EAAMH,EAAQ6G,EACpBH,EAAanG,GAAK,CAAE1B,MAAO0B,EAAGP,QAAO6G,OAAM1G,MAAK9B,MAClD,CAGA,OADAqE,KAAKI,kBAAoB4D,EAClBA,CAAY,GAErB,CACErI,KAAK0I,EACLzI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAE7BoE,KAED2D,eAAiBvI,GACf,IAAM,CAAC4E,KAAK+D,kBAAmB/D,KAAK8D,UAAW9D,KAAKmD,gBACpD,CAACa,EAAcM,EAAWnB,KACxB,MAAM9F,EAmRZ,SAQGkH,GAAA,IARqBP,aACtBA,EAAYM,UACZA,EAASnB,aACTA,GAKDoB,EACC,MAAM5G,EAAQqG,EAAahI,OAAS,EAG9BuB,EAtCwB,EAC9BiH,EACAC,EACAC,EACAtD,KAEA,KAAOoD,GAAOC,GAAM,CAClB,MAAME,GAAWH,EAAMC,GAAQ,EAAK,EAC9BG,EAAeF,EAAgBC,GAErC,GAAIC,EAAexD,EACjBoD,EAAMG,EAAS,MACV,MAAIC,EAAexD,GAGxB,OAAOuD,EAFPF,EAAOE,EAAS,CAGlB,CACF,CAEA,OAAIH,EAAM,EACDA,EAAM,EAEN,CACT,EAemBK,CAAwB,EAAGlH,GAF3BxB,GAAkB6H,EAAa7H,GAAQmB,OAEM6F,GAChE,IAAIzF,EAAWH,EAEf,KACEG,EAAWC,GACXqG,EAAatG,GAAWD,IAAM0F,EAAemB,GAE7C5G,IAGF,MAAO,CAAEH,aAAYG,WACvB,CA1SoBiG,CAAe,CAC3BK,eACAM,YACAnB,iBASF,OANE9F,EAAME,aAAeyC,KAAK3C,MAAME,YAChCF,EAAMK,WAAasC,KAAK3C,MAAMK,WAE9BsC,KAAK3C,MAAQA,EACb2C,KAAKiC,UAEAjC,KAAK3C,KAAK,GAEnB,CACE1B,KAAK0I,EACLzI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAE7BoE,KAEO8E,WAAa1J,GACnB,IAAM,CACJ4E,KAAKnB,QAAQ8C,eACb3B,KAAK3C,MACL2C,KAAKnB,QAAQrB,SACbwC,KAAKnB,QAAQlB,SAEf,CAACgE,EAAgBtE,EAAOG,EAAUG,IACzBgE,EAAe,IACjBtE,EACHG,WACAG,MAAOA,KAGX,CACEhC,KAAK0I,EACLzI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAE7BoE,KAED+E,iBAAoBnC,IAClB,MAAMoC,EAAgBhF,KAAKnB,QAAQmD,eAC7BiD,EAAWrC,EAAKsC,aAAaF,GAEnC,OAAKC,EAOEE,SAASF,EAAU,KANxBlI,QAAQqI,KACL,2BAA0BJ,oCAErB,EAGmB,EAC9BhF,KAEOgB,gBAAkB,CAAC4B,EAAoByC,KAC7C,MAAMlJ,EAAQ6D,KAAK+E,iBAAiBnC,GAE9B0C,EAAOtF,KAAKI,kBAAkBjE,GACpC,IAAKmJ,EACH,OAGF,MAAMC,EAAWvF,KAAKQ,oBAAoB8E,EAAK3J,KAEzC+G,EAAK1C,KAAKU,oBAEhB,IAAKkC,EAAK4C,YAKR,YAJID,UACF7C,GAAAA,EAAI+C,UAAUF,UACPvF,KAAKQ,oBAAoB8E,EAAK3J,OAKpC4J,GAAYA,IAAa3C,IACxB2C,UACF7C,GAAAA,EAAI+C,UAAUF,IAEhBvF,KAAKQ,oBAAoB8E,EAAK3J,KAAOiH,QACrCF,GAAAA,EAAIG,QAAQD,IAGd,MAAM8C,EAAmB1F,KAAKnB,QAAQe,eAAegD,EAAM5C,MAIrD2F,EAAQD,GAFG1F,KAAKK,sBAAsBiF,EAAK3J,MAAQ2J,EAAKnB,MAIhD,IAAVwB,IACEL,EAAKhI,MAAQ0C,KAAKmD,cAAgBnD,KAAKE,aAKzCF,KAAKkD,gBAAgBlD,KAAKmD,aAAc,CACtCC,YAAcpD,KAAKO,mBAAqBoF,EACxCrC,cAAUD,EACVE,MAAM,IAIVvD,KAAKM,4BAA4BxC,KAAK3B,GACtC6D,KAAKK,sBAAwB,IACxBL,KAAKK,sBACR,CAACiF,EAAK3J,KAAM+J,GAEd1F,KAAKiC,SACP,EACDjC,KAEDJ,eAAkBgD,IACXA,GAIL5C,KAAKgB,gBAAgB4B,GAAM,EAAK,EACjC5C,KAED4F,gBAAkBxK,GAChB,IAAM,CAAC4E,KAAK8E,aAAc9E,KAAK+D,qBAC/B,CAAC8B,EAAS7B,KACR,MAAM8B,EAA8B,GAEpC,IAAK,IAAIC,EAAI,EAAGC,EAAMH,EAAQ7J,OAAQ+J,EAAIC,EAAKD,IAAK,CAClD,MACME,EAAcjC,EADV6B,EAAQE,IAGlBD,EAAahI,KAAKmI,EACpB,CAEA,OAAOH,CAAY,GAErB,CACEnK,KAAK0I,EACLzI,MAAO,IAAMoE,KAAKnB,QAAQjD,QAE7BoE,KAEDkG,eAAiB,SACfC,EAEGC,GAAA,IADHC,MAAEA,EAAQ,QAAO/C,SAAEA,QAAiC,IAAA8C,EAAG,CAAA,EAAEA,EAEzD,MAAMxH,EAASmB,EAAKoD,aACdgB,EAAOpE,EAAK+D,UAEJ,SAAVuC,IAEAA,EADEF,GAAYvH,EACN,QACCuH,GAAYvH,EAASuF,EACtB,MAEA,SAIZ,MAAMtF,EAAU,CACduE,iBAAaC,EACbC,WACAC,MAAM,GAEM,UAAV8C,EACFtG,EAAKmD,gBAAgBiD,EAAUtH,GACZ,QAAVwH,EACTtG,EAAKmD,gBAAgBiD,EAAWhC,EAAMtF,GACnB,WAAVwH,GACTtG,EAAKmD,gBAAgBiD,EAAWhC,EAAO,EAAGtF,IAE7CmB,KAEDsG,cAAgB,SACdnK,EAEGoK,GAAA,IADHF,MAAEA,EAAQ,UAAWG,QAA4B,IAAAD,EAAG,CAAA,EAAEA,EAEtDxG,EAAKU,6BAA+B,KAEpC,MAAMuD,EAAejE,EAAKgE,kBACpBnF,EAASmB,EAAKoD,aACdgB,EAAOpE,EAAK+D,WACZnG,MAAEA,GAAUoC,EAAKlB,QAEjBoH,EAAcjC,EAAazH,KAAKU,IAAI,EAAGV,KAAKW,IAAIf,EAAOwB,EAAQ,KAErE,IAAKsI,EACH,OAGF,GAAc,SAAVI,EACF,GAAIJ,EAAYxI,KAAOmB,EAASuF,EAAOpE,EAAKlB,QAAQ4C,iBAClD4E,EAAQ,UACH,MACLJ,EAAY3I,OACZsB,EAASmB,EAAKlB,QAAQ2C,oBAItB,OAFA6E,EAAQ,OAGV,CAGF,MAAMF,EACM,QAAVE,EACIJ,EAAYxI,IAAMsC,EAAKlB,QAAQ4C,iBAC/BwE,EAAY3I,MAAQyC,EAAKlB,QAAQ2C,mBAEvCzB,EAAKmG,eAAeC,EAAU,CAAEE,WAAUG,IAI1C,GAFkBtF,OAAOuF,KAAK1G,EAAKS,qBAAqBxE,OAAS,EAElD,CACb,MAAM0K,EAAU,IAEd,iBADO3G,EAAKM,sBAAsBN,EAAKlB,QAAQ6C,WAAWvF,IAGvDuK,MACH3G,EAAKU,6BAA+B,KAC9BiG,MACF3G,EAAKU,6BAA+B,KACpCV,EAAKuG,cAAcnK,EAAO,CAAEkK,WAAUG,IACxC,EAGN,GACDxG,KAED2G,aAAe,KAAA,IAAAC,EAAA,QACZ,OAAAA,EAAA5G,KAAK+D,kBAAkB/D,KAAKnB,QAAQlB,MAAQ,SAA5C,EAAAiJ,EAAgDnJ,MAC/CuC,KAAKnB,QAAQyC,cAAgBtB,KAAKnB,QAAQ0C,UAAU,EAAAvB,KAEhDkD,gBAAkB,CACxBtE,EAUGiI,KAAA,IATHzD,YACEA,EAAWE,SACXA,EAAQC,KACRA,GAKDsD,EAED7G,KAAKnB,QAAQiI,WAAWlI,EAAQ,CAAE0E,WAAUC,OAAMH,eAAepD,KAAK,EACvEA,KAED+G,QAAU,KACR/G,KAAKK,sBAAwB,GAC7BL,KAAKiC,QAAQ,EA/YbjC,KAAKiB,WAAW1F,GAChByE,KAAK0D,WAAa1D,KAAKnB,QAAQ+C,YAC/B5B,KAAKmD,aAAenD,KAAKnB,QAAQwC,cAEjCrB,KAAK2D,gBACP,qEA9G2B,CAC3B/E,EAAcoI,EAMd5I,KACG,IAAA6I,EAAA,IANH7D,YACEA,EAAWE,SACXA,EAAQC,KACRA,GACmEyD,EAGrE,MAAMb,GACH5C,EAAO3E,EAASA,EAASR,EAASS,QAAQE,eAC1CqE,GAAe,GAEI,OAAtBhF,EAAAA,EAASE,gBAAuB,MAAhC2I,EAAwBC,UAAxBD,EAAwBC,SAAW,CACjC,CAAC9I,EAASS,QAAQC,WAAa,OAAS,OAAQqH,EAChD7C,YACA,4EAxJ8B,CAChClF,EACAC,KAEA,MAAM8I,EAAW,IAAIvG,gBAAgBC,IAAY,IAAAuG,EAAAC,EAC/ChJ,EAAG,CACDwD,MAAO,OAAFuF,EAAEvG,EAAQ,SAAR,EAAAuG,EAAYE,YAAYzF,MAC/BC,OAAQ,OAAFuF,EAAExG,EAAQ,SAAR,EAAAwG,EAAYC,YAAYxF,QAChC,IAGJ,GAAK1D,EAASE,cAQd,OAJAD,EAAGD,EAASE,cAAcuB,yBAE1BsH,EAAStE,QAAQzE,EAASE,eAEnB,KACL6I,EAAS1B,UAAUrH,EAASE,cAAc,CAC3C,8CAG8B,CAC/BF,EACAC,KAEA,MAAMkJ,EA/CiB,EACvBnJ,EACAC,KAEA,IAAImJ,EAAa,CAAE1F,QAAS,EAAGD,OAAQ,GAEvC,OAAQ4B,KAEJrF,EAASS,QAAQC,WACb2E,EAAK5B,QAAU2F,EAAK3F,MACpB4B,EAAK3B,SAAW0F,EAAK1F,SAEzBzD,EAAGoF,GAGL+D,EAAO/D,CAAI,CACZ,EA+BwBgE,CAAiBrJ,EAAUC,GAC9CqJ,EAAW,IACfH,EAAiB,CACf1F,MAAOzD,EAASE,cAAcqJ,WAC9B7F,OAAQ1D,EAASE,cAAcsJ,cAGnC,GAAKxJ,EAASE,cAWd,OAPAoJ,IAEAtJ,EAASE,cAAcgB,iBAAiB,SAAUoI,EAAU,CAC1DnI,SAAS,EACTC,SAAS,IAGJ,KACLpB,EAASE,cAAcmB,oBAAoB,SAAUiI,EAAS,CAC/D,iBAqEyB,CAC1B9I,EAAciJ,EAMdzJ,KACG,IAAA0J,EAAA,IANH1E,YACEA,EAAWE,SACXA,EAAQC,KACRA,GACmEsE,EAGrE,MAAM1B,GACH5C,EAAO3E,EAASA,EAASR,EAASS,QAAQE,eAC1CqE,GAAe,GAEI,OAAtBhF,EAAAA,EAASE,gBAAuB,MAAhCwJ,EAAwBZ,UAAxBY,EAAwBZ,SAAW,CACjC,CAAC9I,EAASS,QAAQC,WAAa,OAAS,OAAQqH,EAChD7C,YACA"}
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.26",
4
+ "version": "3.0.0-beta.29",
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
@@ -292,6 +292,7 @@ export class Virtualizer<
292
292
  private scrollOffset: number
293
293
  private scrollAdjustments: number = 0
294
294
  private measureElementCache: Record<Key, TItemElement> = {}
295
+ private pendingScrollToIndexCallback: (() => void) | null = null
295
296
  private getResizeObserver = (() => {
296
297
  let _ro: ResizeObserver | null = null
297
298
 
@@ -359,15 +360,19 @@ export class Virtualizer<
359
360
  }
360
361
 
361
362
  _didMount = () => {
363
+ const ro = this.getResizeObserver()
364
+ Object.values(this.measureElementCache).forEach((node) => ro?.observe(node))
365
+
362
366
  return () => {
363
- this.getResizeObserver()?.disconnect()
364
- this.measureElementCache = {}
367
+ ro?.disconnect()
365
368
 
366
369
  this.cleanup()
367
370
  }
368
371
  }
369
372
 
370
373
  _willUpdate = () => {
374
+ this.pendingScrollToIndexCallback?.()
375
+
371
376
  const scrollElement = this.options.getScrollElement()
372
377
 
373
378
  if (this.scrollElement !== scrollElement) {
@@ -638,6 +643,8 @@ export class Virtualizer<
638
643
  index: number,
639
644
  { align = 'auto', ...rest }: ScrollToIndexOptions = {},
640
645
  ) => {
646
+ this.pendingScrollToIndexCallback = null
647
+
641
648
  const measurements = this.getMeasurements()
642
649
  const offset = this.scrollOffset
643
650
  const size = this.getSize()
@@ -668,6 +675,23 @@ export class Virtualizer<
668
675
  : measurement.start - this.options.scrollPaddingStart
669
676
 
670
677
  this.scrollToOffset(toOffset, { align, ...rest })
678
+
679
+ const isDynamic = Object.keys(this.measureElementCache).length > 0
680
+
681
+ if (isDynamic) {
682
+ const didSeen = () =>
683
+ typeof this.itemMeasurementsCache[this.options.getItemKey(index)] ===
684
+ 'number'
685
+
686
+ if (!didSeen()) {
687
+ this.pendingScrollToIndexCallback = () => {
688
+ if (didSeen()) {
689
+ this.pendingScrollToIndexCallback = null
690
+ this.scrollToIndex(index, { align, ...rest })
691
+ }
692
+ }
693
+ }
694
+ }
671
695
  }
672
696
 
673
697
  getTotalSize = () =>