@tanstack/virtual-core 3.0.0-beta.45 → 3.0.0-beta.47
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.
- package/build/lib/index.d.ts +4 -4
- package/build/lib/index.esm.js +68 -43
- package/build/lib/index.esm.js.map +1 -1
- package/build/lib/index.js +68 -43
- package/build/lib/index.js.map +1 -1
- package/build/lib/index.mjs +68 -43
- package/build/lib/index.mjs.map +1 -1
- package/build/umd/index.development.js +68 -43
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +66 -47
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.production.js","sources":["../../src/utils.ts","../../src/index.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: any\n debug?: () => any\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n\n return (): TResult => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n opts?.onChange?.(result)\n\n return result!\n }\n}\n\nexport function notUndefined<T>(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1\n","import { approxEqual, memo, notUndefined } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollDirection = 'forward' | 'backward'\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ntype ScrollBehavior = 'auto' | 'smooth'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n behavior?: ScrollBehavior\n}\n\ntype ScrollToOffsetOptions = ScrollToOptions\n\ntype ScrollToIndexOptions = ScrollToOptions\n\nexport interface Range {\n startIndex: number\n endIndex: number\n overscan: number\n count: number\n}\n\ntype Key = number | string\n\nexport interface VirtualItem {\n key: Key\n index: number\n start: number\n end: number\n size: number\n}\n\ninterface Rect {\n width: number\n height: number\n}\n\n//\n\nexport const defaultKeyExtractor = (index: number) => index\n\nexport const defaultRangeExtractor = (range: Range) => {\n const start = Math.max(range.startIndex - range.overscan, 0)\n const end = Math.min(range.endIndex + range.overscan, range.count - 1)\n\n const arr = []\n\n for (let i = start; i <= end; i++) {\n arr.push(i)\n }\n\n return arr\n}\n\nexport const observeElementRect = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n const { width, height } = element.getBoundingClientRect()\n cb({ width: Math.round(width), height: Math.round(height) })\n }\n handler()\n\n const observer = new ResizeObserver(() => {\n handler()\n })\n\n observer.observe(element)\n\n return () => {\n observer.unobserve(element)\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<Window, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight })\n }\n handler()\n\n element.addEventListener('resize', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('resize', handler)\n }\n}\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollX' : 'scrollY'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const measureElement = <TItemElement extends Element>(\n element: TItemElement,\n instance: Virtualizer<any, TItemElement>,\n) => {\n return Math.round(\n element.getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ],\n )\n}\n\nexport const windowScroll = <T extends Window>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport const elementScroll = <T extends Element>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement | null\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n options: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => void\n observeElementRect: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (offset: number) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (instance: Virtualizer<TScrollElement, TItemElement>) => void\n measureElement?: (\n el: TItemElement,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => number\n overscan?: number\n horizontal?: boolean\n paddingStart?: number\n paddingEnd?: number\n scrollPaddingStart?: number\n scrollPaddingEnd?: number\n initialOffset?: number\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => number[]\n scrollMargin?: number\n scrollingDelay?: number\n indexAttribute?: string\n initialMeasurementsCache?: VirtualItem[]\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: (void | (() => void))[] = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n isScrolling: boolean = false\n private isScrollingTimeoutId: ReturnType<typeof setTimeout> | null = null\n private scrollToIndexTimeoutId: ReturnType<typeof setTimeout> | null = null\n measurementsCache: VirtualItem[] = []\n private itemSizeCache: Record<Key, number> = {}\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n scrollOffset: number\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments: number = 0\n private measureElementCache: Record<\n Key,\n TItemElement & { __virtualizerSkipFirstNotSync?: boolean }\n > = {}\n private getResizeObserver = (() => {\n let _ro: ResizeObserver | null = null\n\n return () => {\n if (_ro) {\n return _ro\n } else if (typeof ResizeObserver !== 'undefined') {\n return (_ro = new ResizeObserver((entries) => {\n entries.forEach((entry) => {\n this._measureElement(entry.target as TItemElement, false)\n })\n }))\n } else {\n return null\n }\n }\n })()\n range: { startIndex: number; endIndex: number } = {\n startIndex: 0,\n endIndex: 0,\n }\n\n constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {\n this.setOptions(opts)\n this.scrollRect = this.options.initialRect\n this.scrollOffset = this.options.initialOffset\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache[item.key] = item.size\n })\n\n this.maybeNotify()\n }\n\n setOptions = (opts: VirtualizerOptions<TScrollElement, TItemElement>) => {\n Object.entries(opts).forEach(([key, value]) => {\n if (typeof value === 'undefined') delete (opts as any)[key]\n })\n\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n scrollingDelay: 150,\n indexAttribute: 'data-index',\n initialMeasurementsCache: [],\n ...opts,\n }\n }\n\n private notify = () => {\n this.options.onChange?.(this)\n }\n\n private cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d!())\n this.unsubs = []\n this.scrollElement = null\n }\n\n _didMount = () => {\n const ro = this.getResizeObserver()\n Object.values(this.measureElementCache).forEach((node) => ro?.observe(node))\n\n return () => {\n ro?.disconnect()\n\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.getScrollElement()\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n this.scrollElement = scrollElement\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: undefined,\n behavior: undefined,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n const prev = this.scrollRect\n this.scrollRect = rect\n if (\n this.options.horizontal\n ? rect.width !== prev.width\n : rect.height !== prev.height\n ) {\n this.maybeNotify()\n }\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n this.scrollAdjustments = 0\n\n if (this.scrollOffset === offset) {\n return\n }\n\n if (this.isScrollingTimeoutId !== null) {\n clearTimeout(this.isScrollingTimeoutId)\n this.isScrollingTimeoutId = null\n }\n\n this.isScrolling = true\n this.scrollDirection =\n this.scrollOffset < offset ? 'forward' : 'backward'\n this.scrollOffset = offset\n\n this.maybeNotify()\n\n this.isScrollingTimeoutId = setTimeout(() => {\n this.isScrollingTimeoutId = null\n this.isScrolling = false\n this.scrollDirection = null\n\n this.maybeNotify()\n }, this.options.scrollingDelay)\n }),\n )\n }\n }\n\n private getSize = () => {\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private getMeasurements = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.itemSizeCache,\n ],\n (count, paddingStart, scrollMargin, getItemKey, itemSizeCache) => {\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n const measuredSize = itemSizeCache[key]\n const start = measurements[i - 1]\n ? measurements[i - 1]!.end\n : paddingStart + scrollMargin\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n const end = start + size\n measurements[i] = { index: i, start, size, end, key }\n }\n\n this.measurementsCache = measurements\n\n return measurements\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.scrollOffset],\n (measurements, outerSize, scrollOffset) => {\n return (this.range = calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n }))\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private maybeNotify = memo(\n () => [...Object.values(this.calculateRange()), this.isScrolling],\n () => {\n this.notify()\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'maybeNotify',\n debug: () => this.options.debug,\n initialDeps: [...Object.values(this.range), this.isScrolling],\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.calculateRange(),\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return rangeExtractor({\n ...range,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n indexFromElement = (node: TItemElement) => {\n const attributeName = this.options.indexAttribute\n const indexStr = node.getAttribute(attributeName)\n\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`,\n )\n return -1\n }\n\n return parseInt(indexStr, 10)\n }\n\n private _measureElement = (node: TItemElement, sync: boolean) => {\n const index = this.indexFromElement(node)\n\n const item = this.measurementsCache[index]\n if (!item) {\n return\n }\n\n const prevNode = this.measureElementCache[item.key]\n\n const ro = this.getResizeObserver()\n\n if (!node.isConnected) {\n ro?.unobserve(node)\n if (node === prevNode) {\n delete this.measureElementCache[item.key]\n }\n return\n }\n\n if (prevNode !== node) {\n if (prevNode) {\n ro?.unobserve(prevNode)\n }\n ro?.observe(node)\n this.measureElementCache[item.key] = node\n } else {\n if (!sync && !prevNode.__virtualizerSkipFirstNotSync) {\n prevNode.__virtualizerSkipFirstNotSync = true\n return\n }\n }\n\n const measuredItemSize = this.options.measureElement(node, this)\n\n const itemSize = this.itemSizeCache[item.key] ?? item.size\n\n const delta = measuredItemSize - itemSize\n\n if (delta !== 0) {\n if (item.start < this.scrollOffset) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: (this.scrollAdjustments += delta),\n behavior: undefined,\n })\n }\n\n this.pendingMeasuredCacheIndexes.push(index)\n this.itemSizeCache = {\n ...this.itemSizeCache,\n [item.key]: measuredItemSize,\n }\n this.notify()\n }\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n return\n }\n\n this._measureElement(node, true)\n }\n\n getVirtualItems = memo(\n () => [this.getIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: VirtualItem[] = []\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n virtualItems.push(measurement)\n }\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= this.scrollOffset) {\n align = 'start'\n } else if (toOffset >= this.scrollOffset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n toOffset = toOffset\n } else if (align === 'end') {\n toOffset = toOffset - size\n } else if (align === 'center') {\n toOffset = toOffset - size / 2\n }\n\n const scrollSizeProp = this.options.horizontal\n ? 'scrollWidth'\n : 'scrollHeight'\n const scrollSize = this.scrollElement\n ? 'document' in this.scrollElement\n ? this.scrollElement.document.documentElement[scrollSizeProp]\n : this.scrollElement[scrollSizeProp]\n : 0\n\n const maxOffset = scrollSize - this.getSize()\n\n return Math.max(Math.min(maxOffset, toOffset), 0)\n }\n\n getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const measurement = notUndefined(this.getMeasurements()[index])\n\n if (align === 'auto') {\n if (\n measurement.end >=\n this.scrollOffset + this.getSize() - this.options.scrollPaddingEnd\n ) {\n align = 'end'\n } else if (\n measurement.start <=\n this.scrollOffset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return [this.scrollOffset, align] as const\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n return [this.getOffsetForAlignment(toOffset, align), align] as const\n }\n\n private isDynamicMode = () => Object.keys(this.measureElementCache).length > 0\n\n private cancelScrollToIndex = () => {\n if (this.scrollToIndexTimeoutId !== null) {\n clearTimeout(this.scrollToIndexTimeoutId)\n this.scrollToIndexTimeoutId = null\n }\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior }: ScrollToOffsetOptions = {},\n ) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {\n adjustments: undefined,\n behavior,\n })\n }\n\n scrollToIndex = (\n index: number,\n { align: initialAlign = 'auto', behavior }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n const [toOffset, align] = this.getOffsetForIndex(index, initialAlign)\n\n this._scrollToOffset(toOffset, { adjustments: undefined, behavior })\n\n if (behavior !== 'smooth' && this.isDynamicMode()) {\n this.scrollToIndexTimeoutId = setTimeout(() => {\n this.scrollToIndexTimeoutId = null\n\n const elementInDOM =\n !!this.measureElementCache[this.options.getItemKey(index)]\n\n if (elementInDOM) {\n const [toOffset] = this.getOffsetForIndex(index, align)\n\n if (!approxEqual(toOffset, this.scrollOffset)) {\n this.scrollToIndex(index, { align, behavior })\n }\n } else {\n this.scrollToIndex(index, { align, behavior })\n }\n })\n }\n }\n\n scrollBy = (delta: number, { behavior }: ScrollToOffsetOptions = {}) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.scrollOffset + delta, {\n adjustments: undefined,\n behavior,\n })\n }\n\n getTotalSize = () =>\n (this.getMeasurements()[this.options.count - 1]?.end ||\n this.options.paddingStart) -\n this.options.scrollMargin +\n this.options.paddingEnd\n\n private _scrollToOffset = (\n offset: number,\n {\n adjustments,\n behavior,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this)\n }\n\n measure = () => {\n this.itemSizeCache = {}\n this.notify()\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: VirtualItem[]\n outerSize: number\n scrollOffset: number\n}) {\n const count = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset)\n let endIndex = startIndex\n\n while (\n endIndex < count &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["memo","getDeps","fn","opts","_opts$initialDeps","result","deps","initialDeps","depTime","key","debug","Date","now","resultTime","newDeps","length","some","dep","index","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min","onChange","notUndefined","value","msg","undefined","Error","approxEqual","a","b","abs","defaultKeyExtractor","defaultRangeExtractor","range","start","startIndex","overscan","end","endIndex","count","arr","i","push","measureElement","element","instance","getBoundingClientRect","options","horizontal","_ro","_this","this","unsubs","scrollElement","isScrolling","isScrollingTimeoutId","scrollToIndexTimeoutId","measurementsCache","itemSizeCache","pendingMeasuredCacheIndexes","scrollDirection","scrollAdjustments","measureElementCache","getResizeObserver","ResizeObserver","entries","forEach","entry","_measureElement","target","setOptions","Object","_ref3","_extends","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","initialRect","width","height","scrollMargin","scrollingDelay","indexAttribute","initialMeasurementsCache","notify","cleanup","filter","Boolean","d","_didMount","ro","values","node","observe","disconnect","_willUpdate","getScrollElement","_scrollToOffset","scrollOffset","adjustments","behavior","observeElementRect","rect","prev","scrollRect","maybeNotify","observeElementOffset","offset","clearTimeout","setTimeout","getSize","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","calculateRange","outerSize","_ref8","low","high","getCurrentValue","middle","currentValue","findNearestBinarySearch","concat","getIndexes","indexFromElement","attributeName","indexStr","getAttribute","parseInt","warn","sync","_this$itemSizeCache$i","item","prevNode","isConnected","unobserve","__virtualizerSkipFirstNotSync","_extends2","measuredItemSize","delta","getVirtualItems","indexes","virtualItems","k","len","measurement","getOffsetForAlignment","toOffset","align","scrollSizeProp","maxOffset","document","documentElement","getOffsetForIndex","isDynamicMode","keys","cancelScrollToIndex","scrollToOffset","_temp","_ref4","_ref4$align","scrollToIndex","_temp2","_ref5","_ref5$align","initialAlign","_this$getOffsetForInd","scrollBy","_temp3","getTotalSize","_this$getMeasurements","_ref7","scrollToFn","measure","_instance$scrollEleme3","_instance$scrollEleme4","_ref2$adjustments","_ref2","scrollTo","cb","handler","addEventListener","passive","removeEventListener","observer","innerWidth","innerHeight","_instance$scrollEleme","_instance$scrollEleme2","_ref$adjustments","_ref"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.production.js","sources":["../../src/utils.ts","../../src/index.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: any\n debug?: () => any\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n\n return (): TResult => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n opts?.onChange?.(result)\n\n return result!\n }\n}\n\nexport function notUndefined<T>(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1\n","import { approxEqual, memo, notUndefined } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollDirection = 'forward' | 'backward'\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ntype ScrollBehavior = 'auto' | 'smooth'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n behavior?: ScrollBehavior\n}\n\ntype ScrollToOffsetOptions = ScrollToOptions\n\ntype ScrollToIndexOptions = ScrollToOptions\n\nexport interface Range {\n startIndex: number\n endIndex: number\n overscan: number\n count: number\n}\n\ntype Key = number | string\n\nexport interface VirtualItem {\n key: Key\n index: number\n start: number\n end: number\n size: number\n}\n\ninterface Rect {\n width: number\n height: number\n}\n\n//\n\nexport const defaultKeyExtractor = (index: number) => index\n\nexport const defaultRangeExtractor = (range: Range) => {\n const start = Math.max(range.startIndex - range.overscan, 0)\n const end = Math.min(range.endIndex + range.overscan, range.count - 1)\n\n const arr = []\n\n for (let i = start; i <= end; i++) {\n arr.push(i)\n }\n\n return arr\n}\n\nexport const observeElementRect = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = (rect: { width: number; height: number }) => {\n const { width, height } = rect\n cb({ width: Math.round(width), height: Math.round(height) })\n }\n\n handler(element.getBoundingClientRect())\n\n const observer = new ResizeObserver((entries) => {\n const entry = entries[0]\n if (entry) {\n const box = entry.borderBoxSize[0]\n if (box) {\n handler({ width: box.inlineSize, height: box.blockSize })\n return\n }\n }\n handler(element.getBoundingClientRect())\n })\n\n observer.observe(element, { box: 'border-box' })\n\n return () => {\n observer.unobserve(element)\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<Window, any>,\n cb: (rect: Rect) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb({ width: element.innerWidth, height: element.innerHeight })\n }\n handler()\n\n element.addEventListener('resize', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('resize', handler)\n }\n}\n\nexport const observeElementOffset = <T extends Element>(\n instance: Virtualizer<T, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const observeWindowOffset = (\n instance: Virtualizer<Window, any>,\n cb: (offset: number) => void,\n) => {\n const element = instance.scrollElement\n if (!element) {\n return\n }\n\n const handler = () => {\n cb(element[instance.options.horizontal ? 'scrollX' : 'scrollY'])\n }\n handler()\n\n element.addEventListener('scroll', handler, {\n passive: true,\n })\n\n return () => {\n element.removeEventListener('scroll', handler)\n }\n}\n\nexport const measureElement = <TItemElement extends Element>(\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer<any, TItemElement>,\n) => {\n if (entry) {\n const box = entry.borderBoxSize[0]\n if (box) {\n const size = Math.round(\n box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],\n )\n return size\n }\n }\n return Math.round(\n element.getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ],\n )\n}\n\nexport const windowScroll = <T extends Window>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport const elementScroll = <T extends Element>(\n offset: number,\n {\n adjustments = 0,\n behavior,\n }: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<T, any>,\n) => {\n const toOffset = offset + adjustments\n\n instance.scrollElement?.scrollTo?.({\n [instance.options.horizontal ? 'left' : 'top']: toOffset,\n behavior,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement | null\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n options: { adjustments?: number; behavior?: ScrollBehavior },\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => void\n observeElementRect: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (offset: number) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (instance: Virtualizer<TScrollElement, TItemElement>) => void\n measureElement?: (\n element: TItemElement,\n entry: ResizeObserverEntry | undefined,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => number\n overscan?: number\n horizontal?: boolean\n paddingStart?: number\n paddingEnd?: number\n scrollPaddingStart?: number\n scrollPaddingEnd?: number\n initialOffset?: number\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => number[]\n scrollMargin?: number\n scrollingDelay?: number\n indexAttribute?: string\n initialMeasurementsCache?: VirtualItem[]\n}\n\nexport class Virtualizer<\n TScrollElement extends Element | Window,\n TItemElement extends Element,\n> {\n private unsubs: (void | (() => void))[] = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n isScrolling: boolean = false\n private isScrollingTimeoutId: ReturnType<typeof setTimeout> | null = null\n private scrollToIndexTimeoutId: ReturnType<typeof setTimeout> | null = null\n measurementsCache: VirtualItem[] = []\n private itemSizeCache = new Map<Key, number>()\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n scrollOffset: number\n scrollDirection: ScrollDirection | null = null\n private scrollAdjustments: number = 0\n measureElementCache = new Map<Key, TItemElement>()\n private observer = (() => {\n let _ro: ResizeObserver | null = null\n\n const get = () => {\n if (_ro) {\n return _ro\n } else if (typeof ResizeObserver !== 'undefined') {\n return (_ro = new ResizeObserver((entries) => {\n entries.forEach((entry) => {\n this._measureElement(entry.target as TItemElement, entry)\n })\n }))\n } else {\n return null\n }\n }\n\n return {\n disconnect: () => get()?.disconnect(),\n observe: (target: Element) =>\n get()?.observe(target, { box: 'border-box' }),\n unobserve: (target: Element) => get()?.unobserve(target),\n }\n })()\n range: { startIndex: number; endIndex: number } = {\n startIndex: 0,\n endIndex: 0,\n }\n\n constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {\n this.setOptions(opts)\n this.scrollRect = this.options.initialRect\n this.scrollOffset = this.options.initialOffset\n this.measurementsCache = this.options.initialMeasurementsCache\n this.measurementsCache.forEach((item) => {\n this.itemSizeCache.set(item.key, item.size)\n })\n\n this.maybeNotify()\n }\n\n setOptions = (opts: VirtualizerOptions<TScrollElement, TItemElement>) => {\n Object.entries(opts).forEach(([key, value]) => {\n if (typeof value === 'undefined') delete (opts as any)[key]\n })\n\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n scrollMargin: 0,\n scrollingDelay: 150,\n indexAttribute: 'data-index',\n initialMeasurementsCache: [],\n ...opts,\n }\n }\n\n private notify = () => {\n this.options.onChange?.(this)\n }\n\n private cleanup = () => {\n this.unsubs.filter(Boolean).forEach((d) => d!())\n this.unsubs = []\n this.scrollElement = null\n }\n\n _didMount = () => {\n this.measureElementCache.forEach(this.observer.observe)\n return () => {\n this.observer.disconnect()\n this.cleanup()\n }\n }\n\n _willUpdate = () => {\n const scrollElement = this.options.getScrollElement()\n\n if (this.scrollElement !== scrollElement) {\n this.cleanup()\n\n this.scrollElement = scrollElement\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: undefined,\n behavior: undefined,\n })\n\n this.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n const prev = this.scrollRect\n this.scrollRect = rect\n if (\n this.options.horizontal\n ? rect.width !== prev.width\n : rect.height !== prev.height\n ) {\n this.maybeNotify()\n }\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n this.scrollAdjustments = 0\n\n if (this.scrollOffset === offset) {\n return\n }\n\n if (this.isScrollingTimeoutId !== null) {\n clearTimeout(this.isScrollingTimeoutId)\n this.isScrollingTimeoutId = null\n }\n\n this.isScrolling = true\n this.scrollDirection =\n this.scrollOffset < offset ? 'forward' : 'backward'\n this.scrollOffset = offset\n\n this.maybeNotify()\n\n this.isScrollingTimeoutId = setTimeout(() => {\n this.isScrollingTimeoutId = null\n this.isScrolling = false\n this.scrollDirection = null\n\n this.maybeNotify()\n }, this.options.scrollingDelay)\n }),\n )\n }\n }\n\n private getSize = () => {\n return this.scrollRect[this.options.horizontal ? 'width' : 'height']\n }\n\n private getMeasurements = memo(\n () => [\n this.options.count,\n this.options.paddingStart,\n this.options.scrollMargin,\n this.options.getItemKey,\n this.itemSizeCache,\n ],\n (count, paddingStart, scrollMargin, getItemKey, itemSizeCache) => {\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n const measuredSize = itemSizeCache.get(key)\n const start = measurements[i - 1]\n ? measurements[i - 1]!.end\n : paddingStart + scrollMargin\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n const end = start + size\n measurements[i] = { index: i, start, size, end, key }\n }\n\n this.measurementsCache = measurements\n\n return measurements\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.scrollOffset],\n (measurements, outerSize, scrollOffset) => {\n return (this.range = calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n }))\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'calculateRange',\n debug: () => this.options.debug,\n },\n )\n\n private maybeNotify = memo(\n () => [...Object.values(this.calculateRange()), this.isScrolling],\n () => {\n this.notify()\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'maybeNotify',\n debug: () => this.options.debug,\n initialDeps: [...Object.values(this.range), this.isScrolling],\n },\n )\n\n private getIndexes = memo(\n () => [\n this.options.rangeExtractor,\n this.calculateRange(),\n this.options.overscan,\n this.options.count,\n ],\n (rangeExtractor, range, overscan, count) => {\n return rangeExtractor({\n ...range,\n overscan,\n count,\n })\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n indexFromElement = (node: TItemElement) => {\n const attributeName = this.options.indexAttribute\n const indexStr = node.getAttribute(attributeName)\n\n if (!indexStr) {\n console.warn(\n `Missing attribute name '${attributeName}={index}' on measured element.`,\n )\n return -1\n }\n\n return parseInt(indexStr, 10)\n }\n\n private _measureElement = (\n node: TItemElement,\n entry: ResizeObserverEntry | undefined,\n ) => {\n const index = this.indexFromElement(node)\n\n const item = this.measurementsCache[index]\n if (!item) {\n return\n }\n\n const prevNode = this.measureElementCache.get(item.key)\n\n if (!node.isConnected) {\n this.observer.unobserve(node)\n if (node === prevNode) {\n this.measureElementCache.delete(item.key)\n }\n return\n }\n\n if (prevNode !== node) {\n if (prevNode) {\n this.observer.unobserve(prevNode)\n }\n this.observer.observe(node)\n this.measureElementCache.set(item.key, node)\n }\n\n const measuredItemSize = this.options.measureElement(node, entry, this)\n\n const itemSize = this.itemSizeCache.get(item.key) ?? item.size\n\n const delta = measuredItemSize - itemSize\n\n if (delta !== 0) {\n if (item.start < this.scrollOffset) {\n if (process.env.NODE_ENV !== 'production' && this.options.debug) {\n console.info('correction', delta)\n }\n\n this._scrollToOffset(this.scrollOffset, {\n adjustments: (this.scrollAdjustments += delta),\n behavior: undefined,\n })\n }\n\n this.pendingMeasuredCacheIndexes.push(index)\n\n this.itemSizeCache = new Map(\n this.itemSizeCache.set(item.key, measuredItemSize),\n )\n\n this.notify()\n }\n }\n\n measureElement = (node: TItemElement | null) => {\n if (!node) {\n return\n }\n\n this._measureElement(node, undefined)\n }\n\n getVirtualItems = memo(\n () => [this.getIndexes(), this.getMeasurements()],\n (indexes, measurements) => {\n const virtualItems: VirtualItem[] = []\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n virtualItems.push(measurement)\n }\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV !== 'production' && 'getIndexes',\n debug: () => this.options.debug,\n },\n )\n\n getOffsetForAlignment = (toOffset: number, align: ScrollAlignment) => {\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= this.scrollOffset) {\n align = 'start'\n } else if (toOffset >= this.scrollOffset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n toOffset = toOffset\n } else if (align === 'end') {\n toOffset = toOffset - size\n } else if (align === 'center') {\n toOffset = toOffset - size / 2\n }\n\n const scrollSizeProp = this.options.horizontal\n ? 'scrollWidth'\n : 'scrollHeight'\n const scrollSize = this.scrollElement\n ? 'document' in this.scrollElement\n ? this.scrollElement.document.documentElement[scrollSizeProp]\n : this.scrollElement[scrollSizeProp]\n : 0\n\n const maxOffset = scrollSize - this.getSize()\n\n return Math.max(Math.min(maxOffset, toOffset), 0)\n }\n\n getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n const measurement = notUndefined(this.getMeasurements()[index])\n\n if (align === 'auto') {\n if (\n measurement.end >=\n this.scrollOffset + this.getSize() - this.options.scrollPaddingEnd\n ) {\n align = 'end'\n } else if (\n measurement.start <=\n this.scrollOffset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return [this.scrollOffset, align] as const\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n return [this.getOffsetForAlignment(toOffset, align), align] as const\n }\n\n private isDynamicMode = () => this.measureElementCache.size > 0\n\n private cancelScrollToIndex = () => {\n if (this.scrollToIndexTimeoutId !== null) {\n clearTimeout(this.scrollToIndexTimeoutId)\n this.scrollToIndexTimeoutId = null\n }\n }\n\n scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior }: ScrollToOffsetOptions = {},\n ) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {\n adjustments: undefined,\n behavior,\n })\n }\n\n scrollToIndex = (\n index: number,\n { align: initialAlign = 'auto', behavior }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n const [toOffset, align] = this.getOffsetForIndex(index, initialAlign)\n\n this._scrollToOffset(toOffset, { adjustments: undefined, behavior })\n\n if (behavior !== 'smooth' && this.isDynamicMode()) {\n this.scrollToIndexTimeoutId = setTimeout(() => {\n this.scrollToIndexTimeoutId = null\n\n const elementInDOM = this.measureElementCache.has(\n this.options.getItemKey(index),\n )\n\n if (elementInDOM) {\n const [toOffset] = this.getOffsetForIndex(index, align)\n\n if (!approxEqual(toOffset, this.scrollOffset)) {\n this.scrollToIndex(index, { align, behavior })\n }\n } else {\n this.scrollToIndex(index, { align, behavior })\n }\n })\n }\n }\n\n scrollBy = (delta: number, { behavior }: ScrollToOffsetOptions = {}) => {\n this.cancelScrollToIndex()\n\n if (behavior === 'smooth' && this.isDynamicMode()) {\n console.warn(\n 'The `smooth` scroll behavior is not fully supported with dynamic size.',\n )\n }\n\n this._scrollToOffset(this.scrollOffset + delta, {\n adjustments: undefined,\n behavior,\n })\n }\n\n getTotalSize = () =>\n (this.getMeasurements()[this.options.count - 1]?.end ||\n this.options.paddingStart) -\n this.options.scrollMargin +\n this.options.paddingEnd\n\n private _scrollToOffset = (\n offset: number,\n {\n adjustments,\n behavior,\n }: {\n adjustments: number | undefined\n behavior: ScrollBehavior | undefined\n },\n ) => {\n this.options.scrollToFn(offset, { behavior, adjustments }, this)\n }\n\n measure = () => {\n this.itemSizeCache = new Map()\n this.notify()\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: VirtualItem[]\n outerSize: number\n scrollOffset: number\n}) {\n const count = measurements.length - 1\n const getOffset = (index: number) => measurements[index]!.start\n\n const startIndex = findNearestBinarySearch(0, count, getOffset, scrollOffset)\n let endIndex = startIndex\n\n while (\n endIndex < count &&\n measurements[endIndex]!.end < scrollOffset + outerSize\n ) {\n endIndex++\n }\n\n return { startIndex, endIndex }\n}\n"],"names":["memo","getDeps","fn","opts","_opts$initialDeps","result","deps","initialDeps","depTime","key","debug","Date","now","resultTime","newDeps","length","some","dep","index","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min","onChange","notUndefined","value","msg","undefined","Error","approxEqual","a","b","abs","defaultKeyExtractor","defaultRangeExtractor","range","start","startIndex","overscan","end","endIndex","count","arr","i","push","measureElement","element","entry","instance","box","borderBoxSize","options","horizontal","getBoundingClientRect","_ro","get","_this","this","unsubs","scrollElement","isScrolling","isScrollingTimeoutId","scrollToIndexTimeoutId","measurementsCache","itemSizeCache","Map","pendingMeasuredCacheIndexes","scrollDirection","scrollAdjustments","measureElementCache","observer","ResizeObserver","entries","forEach","_measureElement","target","disconnect","_get","observe","_get2","unobserve","_get3","setOptions","Object","_ref3","_extends","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","initialRect","width","height","scrollMargin","scrollingDelay","indexAttribute","initialMeasurementsCache","notify","cleanup","filter","Boolean","d","_didMount","_willUpdate","getScrollElement","_scrollToOffset","scrollOffset","adjustments","behavior","observeElementRect","rect","prev","scrollRect","maybeNotify","observeElementOffset","offset","clearTimeout","setTimeout","getSize","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","calculateRange","outerSize","_ref8","low","high","getCurrentValue","middle","currentValue","findNearestBinarySearch","concat","values","getIndexes","indexFromElement","node","attributeName","indexStr","getAttribute","parseInt","warn","_this$itemSizeCache$g","item","prevNode","isConnected","set","measuredItemSize","delta","getVirtualItems","indexes","virtualItems","k","len","measurement","getOffsetForAlignment","toOffset","align","scrollSizeProp","maxOffset","document","documentElement","getOffsetForIndex","isDynamicMode","cancelScrollToIndex","scrollToOffset","_temp","_ref4","_ref4$align","scrollToIndex","_temp2","_ref5","_ref5$align","initialAlign","_this$getOffsetForInd","has","scrollBy","_temp3","getTotalSize","_this$getMeasurements","_ref7","scrollToFn","measure","_instance$scrollEleme3","_instance$scrollEleme4","_ref2$adjustments","_ref2","scrollTo","cb","handler","addEventListener","passive","removeEventListener","inlineSize","blockSize","innerWidth","innerHeight","_instance$scrollEleme","_instance$scrollEleme2","_ref$adjustments","_ref"],"mappings":";;;;;;;;;;udAIO,SAASA,EACdC,EACAC,EACAC,GAMA,IAAAC,EAEIC,EADAC,SAAOH,EAAAA,EAAKI,eAAe,GAG/B,OAAO,WACL,IAAIC,EACAL,EAAKM,KAAON,MAAAA,EAAKO,OAALP,EAAKO,UAAWF,EAAUG,KAAKC,OAE/C,IAYIC,EAZEC,EAAUb,IAMhB,KAHEa,EAAQC,SAAWT,EAAKS,QACxBD,EAAQE,MAAK,SAACC,EAAUC,GAAa,OAAKZ,EAAKY,KAAWD,MAG1D,OAAOZ,EAUT,GAPAC,EAAOQ,EAGHX,EAAKM,KAAON,MAAAA,EAAKO,OAALP,EAAKO,UAAWG,EAAaF,KAAKC,OAElDP,EAASH,EAAMY,WAAAA,EAAAA,GAEXX,EAAKM,KAAiB,MAAVN,EAAKO,OAALP,EAAKO,QAAW,CAC9B,IAAMS,EAAaC,KAAKC,MAAgC,KAAzBV,KAAKC,MAAQJ,IAAmB,IACzDc,EAAgBF,KAAKC,MAAmC,KAA5BV,KAAKC,MAAQC,IAAsB,IAC/DU,EAAsBD,EAAgB,GAEtCE,EAAM,SAACC,EAAsBC,GAEjC,IADAD,EAAME,OAAOF,GACNA,EAAIV,OAASW,GAClBD,EAAM,IAAMA,EAEd,OAAOA,GAGTG,QAAQC,KAAI,OACHL,EAAIF,EAAe,QAAOE,EAAIL,EAAY,GAIhCC,MAAAA,2FAAAA,KAAKU,IAChB,EACAV,KAAKW,IAAI,IAAM,IAAMR,EAAqB,MAEhDpB,uBAAAA,SAAAA,EAAMM,IAEV,CAIA,OAFI,MAAJN,GAAc,MAAdA,EAAM6B,UAAN7B,EAAM6B,SAAW3B,GAEVA,EAEX,CAEO,SAAS4B,EAAgBC,EAAsBC,GACpD,QAAcC,IAAVF,EACF,MAAM,IAAIG,MAA6BF,wBAAAA,OAAWA,EAAQ,KAE1D,OAAOD,CAEX,CAEaI,IAAAA,EAAc,SAACC,EAAWC,GAAS,OAAKpB,KAAKqB,IAAIF,EAAIC,GAAK,CAAC,ECjC3DE,EAAsB,SAACxB,GAAa,OAAKA,CAAK,EAE9CyB,EAAwB,SAACC,GAMpC,IALA,IAAMC,EAAQzB,KAAKU,IAAIc,EAAME,WAAaF,EAAMG,SAAU,GACpDC,EAAM5B,KAAKW,IAAIa,EAAMK,SAAWL,EAAMG,SAAUH,EAAMM,MAAQ,GAE9DC,EAAM,GAEHC,EAAIP,EAAOO,GAAKJ,EAAKI,IAC5BD,EAAIE,KAAKD,GAGX,OAAOD,CACT,EA0GaG,EAAiB,SAC5BC,EACAC,EACAC,GAEA,GAAID,EAAO,CACT,IAAME,EAAMF,EAAMG,cAAc,GAChC,GAAID,EAIF,OAHatC,KAAKC,MAChBqC,EAAID,EAASG,QAAQC,WAAa,aAAe,aAIvD,CACA,OAAOzC,KAAKC,MACVkC,EAAQO,wBACNL,EAASG,QAAQC,WAAa,QAAU,UAG9C,gBAiIE,SAAY1D,GAAwD,IA5B9D4D,EAEEC,EA0B4DC,EAAAC,KAAAA,KA3C5DC,OAAkC,GAAED,KAE5CE,cAAuC,KAAIF,KAC3CG,aAAuB,EAAKH,KACpBI,qBAA6D,KAAIJ,KACjEK,uBAA+D,KAAIL,KAC3EM,kBAAmC,GAAEN,KAC7BO,cAAgB,IAAIC,IAAkBR,KACtCS,4BAAwC,GAAET,KAGlDU,gBAA0C,KAAIV,KACtCW,kBAA4B,EAACX,KACrCY,oBAAsB,IAAIJ,IAAwBR,KAC1Ca,UACFhB,EAA6B,KAE3BC,EAAM,WACV,OAAID,IAEiC,oBAAnBiB,eACRjB,EAAM,IAAIiB,gBAAe,SAACC,GAChCA,EAAQC,SAAQ,SAAC1B,GACfS,EAAKkB,gBAAgB3B,EAAM4B,OAAwB5B,EACrD,GACF,IAEO,OAIJ,CACL6B,WAAY,WAAA,IAAAC,EAAA,OAAM,OAANA,EAAMtB,UAAA,EAAAsB,EAAOD,YAAY,EACrCE,QAAS,SAACH,GAAe,IAAAI,EAAA,OAClB,OADkBA,EACvBxB,UAAK,EAALwB,EAAOD,QAAQH,EAAQ,CAAE1B,IAAK,cAAe,EAC/C+B,UAAW,SAACL,GAAe,IAAAM,EAAA,OAAU,OAAVA,EAAK1B,UAAK,EAAL0B,EAAOD,UAAUL,EAAO,IAExDlB,KACJtB,MAAkD,CAChDE,WAAY,EACZG,SAAU,GACXiB,KAcDyB,WAAa,SAACxF,GACZyF,OAAOX,QAAQ9E,GAAM+E,SAAQ,SAAkBW,GAAA,IAAhBpF,EAAGoF,EAAA,QACX,IADkBA,EAAA,WACG1F,EAAaM,EACzD,IAEAwD,EAAKL,QAAOkC,EAAA,CACVpF,OAAO,EACPqF,cAAe,EACfhD,SAAU,EACViD,aAAc,EACdC,WAAY,EACZC,mBAAoB,EACpBC,iBAAkB,EAClBtC,YAAY,EACZuC,WAAY1D,EACZ2D,eAAgB1D,EAChBX,SAAU,WAAQ,EAClBsB,eAAAA,EACAgD,YAAa,CAAEC,MAAO,EAAGC,OAAQ,GACjCC,aAAc,EACdC,eAAgB,IAChBC,eAAgB,aAChBC,yBAA0B,IACvBzG,IAEN+D,KAEO2C,OAAS,WACf,MAAA5C,EAAKL,QAAQ5B,UAAbiC,EAAKL,QAAQ5B,SAAWiC,IACzBC,KAEO4C,QAAU,WAChB7C,EAAKE,OAAO4C,OAAOC,SAAS9B,SAAQ,SAAC+B,GAAC,OAAKA,OAC3ChD,EAAKE,OAAS,GACdF,EAAKG,cAAgB,MACtBF,KAEDgD,UAAY,WAEV,OADAjD,EAAKa,oBAAoBI,QAAQjB,EAAKc,SAASQ,SACxC,WACLtB,EAAKc,SAASM,aACdpB,EAAK6C,YAER5C,KAEDiD,YAAc,WACZ,IAAM/C,EAAgBH,EAAKL,QAAQwD,mBAE/BnD,EAAKG,gBAAkBA,IACzBH,EAAK6C,UAEL7C,EAAKG,cAAgBA,EAErBH,EAAKoD,gBAAgBpD,EAAKqD,aAAc,CACtCC,iBAAanF,EACboF,cAAUpF,IAGZ6B,EAAKE,OAAOd,KACVY,EAAKL,QAAQ6D,mBAAmBxD,GAAM,SAACyD,GACrC,IAAMC,EAAO1D,EAAK2D,WAClB3D,EAAK2D,WAAaF,GAEhBzD,EAAKL,QAAQC,WACT6D,EAAKnB,QAAUoB,EAAKpB,MACpBmB,EAAKlB,SAAWmB,EAAKnB,SAEzBvC,EAAK4D,aAER,KAGH5D,EAAKE,OAAOd,KACVY,EAAKL,QAAQkE,qBAAqB7D,GAAM,SAAC8D,GACvC9D,EAAKY,kBAAoB,EAErBZ,EAAKqD,eAAiBS,IAIQ,OAA9B9D,EAAKK,uBACP0D,aAAa/D,EAAKK,sBAClBL,EAAKK,qBAAuB,MAG9BL,EAAKI,aAAc,EACnBJ,EAAKW,gBACHX,EAAKqD,aAAeS,EAAS,UAAY,WAC3C9D,EAAKqD,aAAeS,EAEpB9D,EAAK4D,cAEL5D,EAAKK,qBAAuB2D,YAAW,WACrChE,EAAKK,qBAAuB,KAC5BL,EAAKI,aAAc,EACnBJ,EAAKW,gBAAkB,KAEvBX,EAAK4D,aACP,GAAG5D,EAAKL,QAAQ8C,gBACjB,OAGNxC,KAEOgE,QAAU,WAChB,OAAOjE,EAAK2D,WAAW3D,EAAKL,QAAQC,WAAa,QAAU,WAC5DK,KAEOiE,gBAAkBnI,GACxB,WAAA,MAAM,CACJiE,EAAKL,QAAQV,MACbe,EAAKL,QAAQoC,aACb/B,EAAKL,QAAQ6C,aACbxC,EAAKL,QAAQwC,WACbnC,EAAKQ,cAEP,IAAA,SAACvB,EAAO8C,EAAcS,EAAcL,EAAY3B,GAC9C,IAAM1C,EACJkC,EAAKU,4BAA4B5D,OAAS,EACtCK,KAAKW,UAALX,KAAY6C,EAAKU,6BACjB,EACNV,EAAKU,4BAA8B,GAInC,IAFA,IAAMyD,EAAenE,EAAKO,kBAAkB6D,MAAM,EAAGtG,GAE5CqB,EAAIrB,EAAKqB,EAAIF,EAAOE,IAAK,CAChC,IAAM3C,EAAM2F,EAAWhD,GACjBkF,EAAe7D,EAAcT,IAAIvD,GACjCoC,EAAQuF,EAAahF,EAAI,GAC3BgF,EAAahF,EAAI,GAAIJ,IACrBgD,EAAeS,EACb8B,EACoB,iBAAjBD,EACHA,EACArE,EAAKL,QAAQ4E,aAAapF,GAC1BJ,EAAMH,EAAQ0F,EACpBH,EAAahF,GAAK,CAAElC,MAAOkC,EAAGP,MAAAA,EAAO0F,KAAAA,EAAMvF,IAAAA,EAAKvC,IAAAA,EAClD,CAIA,OAFAwD,EAAKO,kBAAoB4D,EAElBA,CACT,GACA,CACE3H,KAAKgI,EACL/H,MAAO,WAAA,OAAMuD,EAAKL,QAAQlD,KAAK,IAElCwD,KAEDwE,eAAiB1I,GACf,WAAA,MAAM,CAACiE,EAAKkE,kBAAmBlE,EAAKiE,UAAWjE,EAAKqD,aAAa,IACjE,SAACc,EAAcO,EAAWrB,GACxB,OAAQrD,EAAKrB,MAmVnB,SAQGgG,GAAA,IAPDR,IAAAA,aACAO,IAAAA,UACArB,IAAAA,aAMMpE,EAAQkF,EAAarH,OAAS,EAG9B+B,EAtCwB,SAC9B+F,EACAC,EACAC,EACA7G,GAEA,KAAO2G,GAAOC,GAAM,CAClB,IAAME,GAAWH,EAAMC,GAAQ,EAAK,EAC9BG,EAAeF,EAAgBC,GAErC,GAAIC,EAAe/G,EACjB2G,EAAMG,EAAS,MACV,MAAIC,EAAe/G,GAGxB,OAAO8G,EAFPF,EAAOE,EAAS,CAGlB,CACF,CAEA,OAAIH,EAAM,EACDA,EAAM,EAEN,CAEX,CAcqBK,CAAwB,EAAGhG,GAF5B,SAAChC,GAAa,OAAKkH,EAAalH,GAAQ2B,KAAK,GAECyE,GAC5DrE,EAAWH,EAEf,KACEG,EAAWC,GACXkF,EAAanF,GAAWD,IAAMsE,EAAeqB,GAE7C1F,IAGF,MAAO,CAAEH,WAAAA,EAAYG,SAAAA,EACvB,CA1W2ByF,CAAe,CAClCN,aAAAA,EACAO,UAAAA,EACArB,aAAAA,GAEJ,GACA,CACE7G,KAAKgI,EACL/H,MAAO,WAAA,OAAMuD,EAAKL,QAAQlD,KAAK,IAElCwD,KAEO2D,YAAc7H,GACpB,WAAA,MAAA,GAAAmJ,OAAUvD,OAAOwD,OAAOnF,EAAKyE,kBAAiB,CAAEzE,EAAKI,aAAW,IAChE,WACEJ,EAAK4C,QACP,GACA,CACEpG,KAAKgI,EACL/H,MAAO,WAAA,OAAMuD,EAAKL,QAAQlD,KAAK,EAC/BH,YAAiBqF,GAAAA,OAAAA,OAAOwD,OAAOlF,KAAKtB,OAAM,CAAEsB,KAAKG,gBAEpDH,KAEOmF,WAAarJ,GACnB,WAAA,MAAM,CACJiE,EAAKL,QAAQyC,eACbpC,EAAKyE,iBACLzE,EAAKL,QAAQb,SACbkB,EAAKL,QAAQV,MAEf,IAAA,SAACmD,EAAgBzD,EAAOG,EAAUG,GAChC,OAAOmD,OACFzD,EAAK,CACRG,SAAAA,EACAG,MAAAA,IAEJ,GACA,CACEzC,KAAKgI,EACL/H,MAAO,WAAA,OAAMuD,EAAKL,QAAQlD,KAAK,IAElCwD,KAEDoF,iBAAmB,SAACC,GAClB,IAAMC,EAAgBvF,EAAKL,QAAQ+C,eAC7B8C,EAAWF,EAAKG,aAAaF,GAEnC,OAAKC,EAOEE,SAASF,EAAU,KANxB7H,QAAQgI,KACqBJ,2BAAAA,EAC5B,mCACO,IAIXtF,KAEOiB,gBAAkB,SACxBoE,EACA/F,GACG,IAAAqG,EACG3I,EAAQ+C,EAAKqF,iBAAiBC,GAE9BO,EAAO7F,EAAKO,kBAAkBtD,GACpC,GAAK4I,EAAL,CAIA,IAAMC,EAAW9F,EAAKa,oBAAoBd,IAAI8F,EAAKrJ,KAEnD,IAAK8I,EAAKS,YAKR,OAJA/F,EAAKc,SAASU,UAAU8D,QACpBA,IAASQ,GACX9F,EAAKa,oBAAmB,OAAQgF,EAAKrJ,MAKrCsJ,IAAaR,IACXQ,GACF9F,EAAKc,SAASU,UAAUsE,GAE1B9F,EAAKc,SAASQ,QAAQgE,GACtBtF,EAAKa,oBAAoBmF,IAAIH,EAAKrJ,IAAK8I,IAGzC,IAAMW,EAAmBjG,EAAKL,QAAQN,eAAeiG,EAAM/F,EAAOS,GAI5DkG,EAAQD,GAFuCJ,OAAvCD,EAAG5F,EAAKQ,cAAcT,IAAI8F,EAAKrJ,MAAQqJ,EAAAA,EAAKvB,MAI5C,IAAV4B,IACEL,EAAKjH,MAAQoB,EAAKqD,cAKpBrD,EAAKoD,gBAAgBpD,EAAKqD,aAAc,CACtCC,YAActD,EAAKY,mBAAqBsF,EACxC3C,cAAUpF,IAId6B,EAAKU,4BAA4BtB,KAAKnC,GAEtC+C,EAAKQ,cAAgB,IAAIC,IACvBT,EAAKQ,cAAcwF,IAAIH,EAAKrJ,IAAKyJ,IAGnCjG,EAAK4C,SA5CP,GA8CD3C,KAEDZ,eAAiB,SAACiG,GACXA,GAILtF,EAAKkB,gBAAgBoE,OAAMnH,IAC5B8B,KAEDkG,gBAAkBpK,GAChB,WAAA,MAAM,CAACiE,EAAKoF,aAAcpF,EAAKkE,kBAAkB,IACjD,SAACkC,EAASjC,GAGR,IAFA,IAAMkC,EAA8B,GAE3BC,EAAI,EAAGC,EAAMH,EAAQtJ,OAAQwJ,EAAIC,EAAKD,IAAK,CAClD,IACME,EAAcrC,EADViC,EAAQE,IAGlBD,EAAajH,KAAKoH,EACpB,CAEA,OAAOH,CACT,GACA,CACE7J,KAAKgI,EACL/H,MAAO,WAAA,OAAMuD,EAAKL,QAAQlD,KAAK,IAElCwD,KAEDwG,sBAAwB,SAACC,EAAkBC,GACzC,IAAMrC,EAAOtE,EAAKiE,UAEJ,SAAV0C,IAEAA,EADED,GAAY1G,EAAKqD,aACX,QACCqD,GAAY1G,EAAKqD,aAAeiB,EACjC,MAEA,SAIE,UAAVqC,IAEiB,QAAVA,EACTD,GAAsBpC,EACH,WAAVqC,IACTD,GAAsBpC,EAAO,IAG/B,IAAMsC,EAAiB5G,EAAKL,QAAQC,WAChC,cACA,eAOEiH,GANa7G,EAAKG,cACpB,aAAcH,EAAKG,cACjBH,EAAKG,cAAc2G,SAASC,gBAAgBH,GAC5C5G,EAAKG,cAAcyG,GACrB,GAE2B5G,EAAKiE,UAEpC,OAAO9G,KAAKU,IAAIV,KAAKW,IAAI+I,EAAWH,GAAW,IAChDzG,KAED+G,kBAAoB,SAAC/J,EAAe0J,QAAsB,IAAtBA,IAAAA,EAAyB,QAC3D1J,EAAQE,KAAKU,IAAI,EAAGV,KAAKW,IAAIb,EAAO+C,EAAKL,QAAQV,MAAQ,IAEzD,IAAMuH,EAAcxI,EAAagC,EAAKkE,kBAAkBjH,IAExD,GAAc,SAAV0J,EACF,GACEH,EAAYzH,KACZiB,EAAKqD,aAAerD,EAAKiE,UAAYjE,EAAKL,QAAQuC,iBAElDyE,EAAQ,UACH,MACLH,EAAY5H,OACZoB,EAAKqD,aAAerD,EAAKL,QAAQsC,oBAIjC,MAAO,CAACjC,EAAKqD,aAAcsD,GAF3BA,EAAQ,OAGV,CAGF,IAAMD,EACM,QAAVC,EACIH,EAAYzH,IAAMiB,EAAKL,QAAQuC,iBAC/BsE,EAAY5H,MAAQoB,EAAKL,QAAQsC,mBAEvC,MAAO,CAACjC,EAAKyG,sBAAsBC,EAAUC,GAAQA,IACtD1G,KAEOgH,cAAgB,WAAA,OAAMjH,EAAKa,oBAAoByD,KAAO,CAAC,EAAArE,KAEvDiH,oBAAsB,WACQ,OAAhClH,EAAKM,yBACPyD,aAAa/D,EAAKM,wBAClBN,EAAKM,uBAAyB,OAEjCL,KAEDkH,eAAiB,SACfT,EAEGU,GAAA,IAAAC,OAAA,IAAAD,EADoD,CAAE,EAAAA,EAAAE,EAAAD,EAAvDV,MAAAA,aAAQ,QAAOW,EAAE/D,IAAAA,SAEnBvD,EAAKkH,sBAEY,WAAb3D,GAAyBvD,EAAKiH,iBAChCtJ,QAAQgI,KACN,0EAIJ3F,EAAKoD,gBAAgBpD,EAAKyG,sBAAsBC,EAAUC,GAAQ,CAChErD,iBAAanF,EACboF,SAAAA,KAEHtD,KAEDsH,cAAgB,SACdtK,EAEGuK,GAAA,IAAAC,OAAA,IAAAD,EADgE,CAAE,EAAAA,EAAAE,EAAAD,EAAnEd,MAAOgB,aAAe,OAAMD,EAAEnE,IAAAA,SAEhCtG,EAAQE,KAAKU,IAAI,EAAGV,KAAKW,IAAIb,EAAO+C,EAAKL,QAAQV,MAAQ,IAEzDe,EAAKkH,sBAEY,WAAb3D,GAAyBvD,EAAKiH,iBAChCtJ,QAAQgI,KACN,0EAIJ,IAAAiC,EAA0B5H,EAAKgH,kBAAkB/J,EAAO0K,GAAjDjB,EAAQkB,EAAA,GAAEjB,EAAKiB,EAAA,GAEtB5H,EAAKoD,gBAAgBsD,EAAU,CAAEpD,iBAAanF,EAAWoF,SAAAA,IAExC,WAAbA,GAAyBvD,EAAKiH,kBAChCjH,EAAKM,uBAAyB0D,YAAW,WAOvC,GANAhE,EAAKM,uBAAyB,KAETN,EAAKa,oBAAoBgH,IAC5C7H,EAAKL,QAAQwC,WAAWlF,IAGR,CAChB,IAAOyJ,EAAY1G,EAAKgH,kBAAkB/J,EAAO0J,GAAlC,GAEVtI,EAAYqI,EAAU1G,EAAKqD,eAC9BrD,EAAKuH,cAActK,EAAO,CAAE0J,MAAAA,EAAOpD,SAAAA,GAEvC,MACEvD,EAAKuH,cAActK,EAAO,CAAE0J,MAAAA,EAAOpD,SAAAA,GAEvC,MAEHtD,KAED6H,SAAW,SAAC5B,EAA4D6B,GAAA,IAA3CxE,QAA2C,IAAAwE,EAAP,CAAE,EAAAA,GAAtCxE,SAC3BvD,EAAKkH,sBAEY,WAAb3D,GAAyBvD,EAAKiH,iBAChCtJ,QAAQgI,KACN,0EAIJ3F,EAAKoD,gBAAgBpD,EAAKqD,aAAe6C,EAAO,CAC9C5C,iBAAanF,EACboF,SAAAA,KAEHtD,KAED+H,aAAe,WAAA,IAAAC,EAAA,eACZA,EAAAjI,EAAKkE,kBAAkBlE,EAAKL,QAAQV,MAAQ,WAA5CgJ,EAAgDlJ,MAC/CiB,EAAKL,QAAQoC,cACf/B,EAAKL,QAAQ6C,aACbxC,EAAKL,QAAQqC,UAAU,EAAA/B,KAEjBmD,gBAAkB,SACxBU,EAQGoE,GAAA,IAND5E,IAAAA,YACAC,IAAAA,SAMFvD,EAAKL,QAAQwI,WAAWrE,EAAQ,CAAEP,SAAAA,EAAUD,YAAAA,GAAetD,IAC5DC,KAEDmI,QAAU,WACRpI,EAAKQ,cAAgB,IAAIC,IACzBT,EAAK4C,UAxdL3C,KAAKyB,WAAWxF,GAChB+D,KAAK0D,WAAa1D,KAAKN,QAAQ0C,YAC/BpC,KAAKoD,aAAepD,KAAKN,QAAQmC,cACjC7B,KAAKM,kBAAoBN,KAAKN,QAAQgD,yBACtC1C,KAAKM,kBAAkBU,SAAQ,SAAC4E,GAC9B7F,EAAKQ,cAAcwF,IAAIH,EAAKrJ,IAAKqJ,EAAKvB,KACxC,IAEArE,KAAK2D,aACP,oFAzH2B,SAC3BE,EAKAtE,EAAAA,GACG,IAAA6I,EAAAC,EAAAC,EAAAC,EAJDlF,YAAAA,aAAc,EAACiF,EACfhF,IAAAA,SAIImD,EAAW5C,EAASR,EAE1B,OAAA9D,EAAAA,EAASW,gBAAT,MAAAkI,EAAwBI,UAAxBJ,EAAwBI,WAAQH,EAAA,CAAA,GAC7B9I,EAASG,QAAQC,WAAa,OAAS,OAAQ8G,EAChDnD,EAAAA,SAAAA,EACA+E,GACJ,sEAjGoC,SAClC9I,EACAkJ,GAEA,IAAMpJ,EAAUE,EAASW,cACzB,GAAKb,EAAL,CAIA,IAAMqJ,EAAU,WACdD,EAAGpJ,EAAQE,EAASG,QAAQC,WAAa,aAAe,eAQ1D,OANA+I,IAEArJ,EAAQsJ,iBAAiB,SAAUD,EAAS,CAC1CE,SAAS,IAGJ,WACLvJ,EAAQwJ,oBAAoB,SAAUH,GAZxC,CAcF,uBA/EkC,SAChCnJ,EACAkJ,GAEA,IAAMpJ,EAAUE,EAASW,cACzB,GAAKb,EAAL,CAIA,IAAMqJ,EAAU,SAAClF,GACf,IAAQnB,EAAkBmB,EAAlBnB,MAAOC,EAAWkB,EAAXlB,OACfmG,EAAG,CAAEpG,MAAOnF,KAAKC,MAAMkF,GAAQC,OAAQpF,KAAKC,MAAMmF,MAGpDoG,EAAQrJ,EAAQO,yBAEhB,IAAMiB,EAAW,IAAIC,gBAAe,SAACC,GACnC,IAAMzB,EAAQyB,EAAQ,GACtB,GAAIzB,EAAO,CACT,IAAME,EAAMF,EAAMG,cAAc,GAChC,GAAID,EAEF,YADAkJ,EAAQ,CAAErG,MAAO7C,EAAIsJ,WAAYxG,OAAQ9C,EAAIuJ,WAGjD,CACAL,EAAQrJ,EAAQO,wBAClB,IAIA,OAFAiB,EAASQ,QAAQhC,EAAS,CAAEG,IAAK,eAE1B,WACLqB,EAASU,UAAUlC,GAxBrB,CA0BF,wBAgDmC,SACjCE,EACAkJ,GAEA,IAAMpJ,EAAUE,EAASW,cACzB,GAAKb,EAAL,CAIA,IAAMqJ,EAAU,WACdD,EAAGpJ,EAAQE,EAASG,QAAQC,WAAa,UAAY,aAQvD,OANA+I,IAEArJ,EAAQsJ,iBAAiB,SAAUD,EAAS,CAC1CE,SAAS,IAGJ,WACLvJ,EAAQwJ,oBAAoB,SAAUH,GAZxC,CAcF,sBAnEiC,SAC/BnJ,EACAkJ,GAEA,IAAMpJ,EAAUE,EAASW,cACzB,GAAKb,EAAL,CAIA,IAAMqJ,EAAU,WACdD,EAAG,CAAEpG,MAAOhD,EAAQ2J,WAAY1G,OAAQjD,EAAQ4J,eAQlD,OANAP,IAEArJ,EAAQsJ,iBAAiB,SAAUD,EAAS,CAC1CE,SAAS,IAGJ,WACLvJ,EAAQwJ,oBAAoB,SAAUH,GAZxC,CAcF,iBAqE4B,SAC1B7E,EAKAtE,EAAAA,GACG,IAAA2J,EAAAC,EAAAC,EAAAC,EAJDhG,YAAAA,aAAc,EAAC+F,EACf9F,IAAAA,SAIImD,EAAW5C,EAASR,EAE1B,OAAA9D,EAAAA,EAASW,gBAAT,MAAAgJ,EAAwBV,UAAxBU,EAAwBV,WAAQW,EAAA,CAAA,GAC7B5J,EAASG,QAAQC,WAAa,OAAS,OAAQ8G,EAChDnD,EAAAA,SAAAA,EACA6F,GACJ"}
|
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.
|
|
4
|
+
"version": "3.0.0-beta.47",
|
|
5
5
|
"description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/tanstack/virtual#readme",
|
package/src/index.ts
CHANGED
|
@@ -67,17 +67,26 @@ export const observeElementRect = <T extends Element>(
|
|
|
67
67
|
return
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
const handler = () => {
|
|
71
|
-
const { width, height } =
|
|
70
|
+
const handler = (rect: { width: number; height: number }) => {
|
|
71
|
+
const { width, height } = rect
|
|
72
72
|
cb({ width: Math.round(width), height: Math.round(height) })
|
|
73
73
|
}
|
|
74
|
-
handler()
|
|
75
74
|
|
|
76
|
-
|
|
77
|
-
|
|
75
|
+
handler(element.getBoundingClientRect())
|
|
76
|
+
|
|
77
|
+
const observer = new ResizeObserver((entries) => {
|
|
78
|
+
const entry = entries[0]
|
|
79
|
+
if (entry) {
|
|
80
|
+
const box = entry.borderBoxSize[0]
|
|
81
|
+
if (box) {
|
|
82
|
+
handler({ width: box.inlineSize, height: box.blockSize })
|
|
83
|
+
return
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
handler(element.getBoundingClientRect())
|
|
78
87
|
})
|
|
79
88
|
|
|
80
|
-
observer.observe(element)
|
|
89
|
+
observer.observe(element, { box: 'border-box' })
|
|
81
90
|
|
|
82
91
|
return () => {
|
|
83
92
|
observer.unobserve(element)
|
|
@@ -155,8 +164,18 @@ export const observeWindowOffset = (
|
|
|
155
164
|
|
|
156
165
|
export const measureElement = <TItemElement extends Element>(
|
|
157
166
|
element: TItemElement,
|
|
167
|
+
entry: ResizeObserverEntry | undefined,
|
|
158
168
|
instance: Virtualizer<any, TItemElement>,
|
|
159
169
|
) => {
|
|
170
|
+
if (entry) {
|
|
171
|
+
const box = entry.borderBoxSize[0]
|
|
172
|
+
if (box) {
|
|
173
|
+
const size = Math.round(
|
|
174
|
+
box[instance.options.horizontal ? 'inlineSize' : 'blockSize'],
|
|
175
|
+
)
|
|
176
|
+
return size
|
|
177
|
+
}
|
|
178
|
+
}
|
|
160
179
|
return Math.round(
|
|
161
180
|
element.getBoundingClientRect()[
|
|
162
181
|
instance.options.horizontal ? 'width' : 'height'
|
|
@@ -225,7 +244,8 @@ export interface VirtualizerOptions<
|
|
|
225
244
|
initialRect?: Rect
|
|
226
245
|
onChange?: (instance: Virtualizer<TScrollElement, TItemElement>) => void
|
|
227
246
|
measureElement?: (
|
|
228
|
-
|
|
247
|
+
element: TItemElement,
|
|
248
|
+
entry: ResizeObserverEntry | undefined,
|
|
229
249
|
instance: Virtualizer<TScrollElement, TItemElement>,
|
|
230
250
|
) => number
|
|
231
251
|
overscan?: number
|
|
@@ -254,32 +274,36 @@ export class Virtualizer<
|
|
|
254
274
|
private isScrollingTimeoutId: ReturnType<typeof setTimeout> | null = null
|
|
255
275
|
private scrollToIndexTimeoutId: ReturnType<typeof setTimeout> | null = null
|
|
256
276
|
measurementsCache: VirtualItem[] = []
|
|
257
|
-
private itemSizeCache
|
|
277
|
+
private itemSizeCache = new Map<Key, number>()
|
|
258
278
|
private pendingMeasuredCacheIndexes: number[] = []
|
|
259
279
|
private scrollRect: Rect
|
|
260
280
|
scrollOffset: number
|
|
261
281
|
scrollDirection: ScrollDirection | null = null
|
|
262
282
|
private scrollAdjustments: number = 0
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
TItemElement & { __virtualizerSkipFirstNotSync?: boolean }
|
|
266
|
-
> = {}
|
|
267
|
-
private getResizeObserver = (() => {
|
|
283
|
+
measureElementCache = new Map<Key, TItemElement>()
|
|
284
|
+
private observer = (() => {
|
|
268
285
|
let _ro: ResizeObserver | null = null
|
|
269
286
|
|
|
270
|
-
|
|
287
|
+
const get = () => {
|
|
271
288
|
if (_ro) {
|
|
272
289
|
return _ro
|
|
273
290
|
} else if (typeof ResizeObserver !== 'undefined') {
|
|
274
291
|
return (_ro = new ResizeObserver((entries) => {
|
|
275
292
|
entries.forEach((entry) => {
|
|
276
|
-
this._measureElement(entry.target as TItemElement,
|
|
293
|
+
this._measureElement(entry.target as TItemElement, entry)
|
|
277
294
|
})
|
|
278
295
|
}))
|
|
279
296
|
} else {
|
|
280
297
|
return null
|
|
281
298
|
}
|
|
282
299
|
}
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
disconnect: () => get()?.disconnect(),
|
|
303
|
+
observe: (target: Element) =>
|
|
304
|
+
get()?.observe(target, { box: 'border-box' }),
|
|
305
|
+
unobserve: (target: Element) => get()?.unobserve(target),
|
|
306
|
+
}
|
|
283
307
|
})()
|
|
284
308
|
range: { startIndex: number; endIndex: number } = {
|
|
285
309
|
startIndex: 0,
|
|
@@ -292,7 +316,7 @@ export class Virtualizer<
|
|
|
292
316
|
this.scrollOffset = this.options.initialOffset
|
|
293
317
|
this.measurementsCache = this.options.initialMeasurementsCache
|
|
294
318
|
this.measurementsCache.forEach((item) => {
|
|
295
|
-
this.itemSizeCache
|
|
319
|
+
this.itemSizeCache.set(item.key, item.size)
|
|
296
320
|
})
|
|
297
321
|
|
|
298
322
|
this.maybeNotify()
|
|
@@ -336,12 +360,9 @@ export class Virtualizer<
|
|
|
336
360
|
}
|
|
337
361
|
|
|
338
362
|
_didMount = () => {
|
|
339
|
-
|
|
340
|
-
Object.values(this.measureElementCache).forEach((node) => ro?.observe(node))
|
|
341
|
-
|
|
363
|
+
this.measureElementCache.forEach(this.observer.observe)
|
|
342
364
|
return () => {
|
|
343
|
-
|
|
344
|
-
|
|
365
|
+
this.observer.disconnect()
|
|
345
366
|
this.cleanup()
|
|
346
367
|
}
|
|
347
368
|
}
|
|
@@ -428,7 +449,7 @@ export class Virtualizer<
|
|
|
428
449
|
|
|
429
450
|
for (let i = min; i < count; i++) {
|
|
430
451
|
const key = getItemKey(i)
|
|
431
|
-
const measuredSize = itemSizeCache
|
|
452
|
+
const measuredSize = itemSizeCache.get(key)
|
|
432
453
|
const start = measurements[i - 1]
|
|
433
454
|
? measurements[i - 1]!.end
|
|
434
455
|
: paddingStart + scrollMargin
|
|
@@ -511,7 +532,10 @@ export class Virtualizer<
|
|
|
511
532
|
return parseInt(indexStr, 10)
|
|
512
533
|
}
|
|
513
534
|
|
|
514
|
-
private _measureElement = (
|
|
535
|
+
private _measureElement = (
|
|
536
|
+
node: TItemElement,
|
|
537
|
+
entry: ResizeObserverEntry | undefined,
|
|
538
|
+
) => {
|
|
515
539
|
const index = this.indexFromElement(node)
|
|
516
540
|
|
|
517
541
|
const item = this.measurementsCache[index]
|
|
@@ -519,34 +543,27 @@ export class Virtualizer<
|
|
|
519
543
|
return
|
|
520
544
|
}
|
|
521
545
|
|
|
522
|
-
const prevNode = this.measureElementCache
|
|
523
|
-
|
|
524
|
-
const ro = this.getResizeObserver()
|
|
546
|
+
const prevNode = this.measureElementCache.get(item.key)
|
|
525
547
|
|
|
526
548
|
if (!node.isConnected) {
|
|
527
|
-
|
|
549
|
+
this.observer.unobserve(node)
|
|
528
550
|
if (node === prevNode) {
|
|
529
|
-
|
|
551
|
+
this.measureElementCache.delete(item.key)
|
|
530
552
|
}
|
|
531
553
|
return
|
|
532
554
|
}
|
|
533
555
|
|
|
534
556
|
if (prevNode !== node) {
|
|
535
557
|
if (prevNode) {
|
|
536
|
-
|
|
537
|
-
}
|
|
538
|
-
ro?.observe(node)
|
|
539
|
-
this.measureElementCache[item.key] = node
|
|
540
|
-
} else {
|
|
541
|
-
if (!sync && !prevNode.__virtualizerSkipFirstNotSync) {
|
|
542
|
-
prevNode.__virtualizerSkipFirstNotSync = true
|
|
543
|
-
return
|
|
558
|
+
this.observer.unobserve(prevNode)
|
|
544
559
|
}
|
|
560
|
+
this.observer.observe(node)
|
|
561
|
+
this.measureElementCache.set(item.key, node)
|
|
545
562
|
}
|
|
546
563
|
|
|
547
|
-
const measuredItemSize = this.options.measureElement(node, this)
|
|
564
|
+
const measuredItemSize = this.options.measureElement(node, entry, this)
|
|
548
565
|
|
|
549
|
-
const itemSize = this.itemSizeCache
|
|
566
|
+
const itemSize = this.itemSizeCache.get(item.key) ?? item.size
|
|
550
567
|
|
|
551
568
|
const delta = measuredItemSize - itemSize
|
|
552
569
|
|
|
@@ -563,10 +580,11 @@ export class Virtualizer<
|
|
|
563
580
|
}
|
|
564
581
|
|
|
565
582
|
this.pendingMeasuredCacheIndexes.push(index)
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
583
|
+
|
|
584
|
+
this.itemSizeCache = new Map(
|
|
585
|
+
this.itemSizeCache.set(item.key, measuredItemSize),
|
|
586
|
+
)
|
|
587
|
+
|
|
570
588
|
this.notify()
|
|
571
589
|
}
|
|
572
590
|
}
|
|
@@ -576,7 +594,7 @@ export class Virtualizer<
|
|
|
576
594
|
return
|
|
577
595
|
}
|
|
578
596
|
|
|
579
|
-
this._measureElement(node,
|
|
597
|
+
this._measureElement(node, undefined)
|
|
580
598
|
}
|
|
581
599
|
|
|
582
600
|
getVirtualItems = memo(
|
|
@@ -663,7 +681,7 @@ export class Virtualizer<
|
|
|
663
681
|
return [this.getOffsetForAlignment(toOffset, align), align] as const
|
|
664
682
|
}
|
|
665
683
|
|
|
666
|
-
private isDynamicMode = () =>
|
|
684
|
+
private isDynamicMode = () => this.measureElementCache.size > 0
|
|
667
685
|
|
|
668
686
|
private cancelScrollToIndex = () => {
|
|
669
687
|
if (this.scrollToIndexTimeoutId !== null) {
|
|
@@ -712,8 +730,9 @@ export class Virtualizer<
|
|
|
712
730
|
this.scrollToIndexTimeoutId = setTimeout(() => {
|
|
713
731
|
this.scrollToIndexTimeoutId = null
|
|
714
732
|
|
|
715
|
-
const elementInDOM =
|
|
716
|
-
|
|
733
|
+
const elementInDOM = this.measureElementCache.has(
|
|
734
|
+
this.options.getItemKey(index),
|
|
735
|
+
)
|
|
717
736
|
|
|
718
737
|
if (elementInDOM) {
|
|
719
738
|
const [toOffset] = this.getOffsetForIndex(index, align)
|
|
@@ -763,7 +782,7 @@ export class Virtualizer<
|
|
|
763
782
|
}
|
|
764
783
|
|
|
765
784
|
measure = () => {
|
|
766
|
-
this.itemSizeCache =
|
|
785
|
+
this.itemSizeCache = new Map()
|
|
767
786
|
this.notify()
|
|
768
787
|
}
|
|
769
788
|
}
|