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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"index.production.js","sources":["../../src/utils.ts","../../src/index.ts"],"sourcesContent":["export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: any\n debug?: () => any\n onChange?: (result: TResult) => void\n initialDeps?: TDeps\n },\n) {\n let deps = opts.initialDeps ?? []\n let result: TResult | undefined\n\n return (): TResult => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n opts?.onChange?.(result)\n\n return result!\n }\n}\n\nexport function notUndefined<T>(value: T | undefined, msg?: string): T {\n if (value === undefined) {\n throw new Error(`Unexpected undefined${msg ? `: ${msg}` : ''}`)\n } else {\n return value\n }\n}\n\nexport const approxEqual = (a: number, b: number) => Math.abs(a - b) < 1\n","import { approxEqual, memo, notUndefined } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollDirection = 'forward' | 'backward'\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ntype ScrollBehavior = 'auto' | 'smooth'\n\nexport interface ScrollToOptions {\n align?: ScrollAlignment\n behavior?: ScrollBehavior\n}\n\ntype ScrollToOffsetOptions = ScrollToOptions\n\ntype ScrollToIndexOptions = ScrollToOptions\n\nexport interface Range {\n startIndex: number\n endIndex: number\n overscan: number\n count: number\n}\n\ntype Key = number | string\n\nexport interface VirtualItem {\n key: Key\n index: number\n start: number\n end: number\n size: number\n}\n\ninterface Rect {\n width: number\n height: number\n}\n\n//\n\nexport const defaultKeyExtractor = (index: number) => index\n\nexport const defaultRangeExtractor = (range: Range) => {\n const start = Math.max(range.startIndex - range.overscan, 0)\n const end = Math.min(range.endIndex + range.overscan, range.count - 1)\n\n const arr = []\n\n for (let i = start; i <= end; i++) {\n arr.push(i)\n }\n\n return arr\n}\n\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 const entry = entries[0]\n if (entry) {\n const { width, height } = entry.contentRect\n cb({\n width: Math.round(width),\n height: Math.round(height),\n })\n } else {\n cb({ width: 0, height: 0 })\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(offset)\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 = 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 this.scrollRect = rect\n this.maybeNotify()\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 scrollToOffset = (\n toOffset: number,\n { align = 'start', behavior }: ScrollToOffsetOptions = {},\n ) => {\n const isDynamic = Object.keys(this.measureElementCache).length > 0\n\n if (isDynamic && behavior === 'smooth') {\n console.warn(\n 'The `smooth` scroll behavior is not supported with dynamic size.',\n )\n return\n }\n\n const options = {\n adjustments: undefined,\n behavior,\n sync: false,\n }\n this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), options)\n }\n\n scrollToIndex = (\n index: number,\n { align = 'auto', behavior }: ScrollToIndexOptions = {},\n ) => {\n index = Math.max(0, Math.min(index, this.options.count - 1))\n\n if (this.scrollToIndexTimeoutId !== null) {\n clearTimeout(this.scrollToIndexTimeoutId)\n this.scrollToIndexTimeoutId = null\n }\n\n const isDynamic = Object.keys(this.measureElementCache).length > 0\n\n if (isDynamic && behavior === 'smooth') {\n console.warn(\n 'The `smooth` scroll behavior is not supported with dynamic size.',\n )\n return\n }\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\n }\n }\n\n const getOffsetForIndexAndAlignment = (measurement: VirtualItem) => {\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)\n }\n\n const toOffset = getOffsetForIndexAndAlignment(measurement)\n\n const options = {\n adjustments: undefined,\n behavior,\n }\n this._scrollToOffset(toOffset, options)\n\n if (isDynamic) {\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 = getOffsetForIndexAndAlignment(\n notUndefined(this.getMeasurements()[index]),\n )\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 const isDynamic = Object.keys(this.measureElementCache).length > 0\n\n if (isDynamic && behavior === 'smooth') {\n console.warn(\n 'The `smooth` scroll behavior is not supported with dynamic size.',\n )\n return\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","scrollProps","element","window","createOffsetObserver","mode","instance","cb","scrollElement","propX","propY","prevX","prevY","scroll","offset","options","horizontal","onScroll","e","target","currentTarget","scrollX","scrollY","addEventListener","capture","passive","removeEventListener","observeElementOffset","observeWindowOffset","measureElement","getBoundingClientRect","_ro","_this","this","unsubs","isScrolling","isScrollingTimeoutId","scrollToIndexTimeoutId","measurementsCache","itemSizeCache","pendingMeasuredCacheIndexes","scrollDirection","scrollAdjustments","measureElementCache","getResizeObserver","ResizeObserver","entries","forEach","entry","_measureElement","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","scrollRect","maybeNotify","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","scrollToOffset","_temp","_ref4","_ref4$align","keys","scrollToIndex","_temp2","_ref5","_ref5$align","isDynamic","getOffsetForIndexAndAlignment","scrollBy","_temp3","getTotalSize","_this$getMeasurements","_ref7","scrollToFn","measure","_instance$scrollEleme3","_instance$scrollEleme4","_ref2$adjustments","_ref2","scrollTo","observer","contentRect","memoizedCallback","prev","memoRectCallback","onResize","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 = () => {\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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"}
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.43",
4
+ "version": "3.0.0-beta.45",
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
@@ -58,137 +58,101 @@ export const defaultRangeExtractor = (range: Range) => {
58
58
  return arr
59
59
  }
60
60
 
61
- const memoRectCallback = (
62
- instance: Virtualizer<any, any>,
61
+ export const observeElementRect = <T extends Element>(
62
+ instance: Virtualizer<T, any>,
63
63
  cb: (rect: Rect) => void,
64
64
  ) => {
65
- let prev: Rect = { height: -1, width: -1 }
66
-
67
- return (rect: Rect) => {
68
- if (
69
- instance.options.horizontal
70
- ? rect.width !== prev.width
71
- : rect.height !== prev.height
72
- ) {
73
- cb(rect)
74
- }
75
-
76
- prev = rect
65
+ const element = instance.scrollElement
66
+ if (!element) {
67
+ return
77
68
  }
78
- }
79
-
80
- export const observeElementRect = (
81
- instance: Virtualizer<any, any>,
82
- cb: (rect: Rect) => void,
83
- ) => {
84
- const observer = new ResizeObserver((entries) => {
85
- const entry = entries[0]
86
- if (entry) {
87
- const { width, height } = entry.contentRect
88
- cb({
89
- width: Math.round(width),
90
- height: Math.round(height),
91
- })
92
- } else {
93
- cb({ width: 0, height: 0 })
94
- }
95
- })
96
69
 
97
- if (!instance.scrollElement) {
98
- return
70
+ const handler = () => {
71
+ const { width, height } = element.getBoundingClientRect()
72
+ cb({ width: Math.round(width), height: Math.round(height) })
99
73
  }
74
+ handler()
100
75
 
101
- cb(instance.scrollElement.getBoundingClientRect())
76
+ const observer = new ResizeObserver(() => {
77
+ handler()
78
+ })
102
79
 
103
- observer.observe(instance.scrollElement)
80
+ observer.observe(element)
104
81
 
105
82
  return () => {
106
- observer.unobserve(instance.scrollElement)
83
+ observer.unobserve(element)
107
84
  }
108
85
  }
109
86
 
110
87
  export const observeWindowRect = (
111
- instance: Virtualizer<any, any>,
88
+ instance: Virtualizer<Window, any>,
112
89
  cb: (rect: Rect) => void,
113
90
  ) => {
114
- const memoizedCallback = memoRectCallback(instance, cb)
115
- const onResize = () =>
116
- memoizedCallback({
117
- width: instance.scrollElement.innerWidth,
118
- height: instance.scrollElement.innerHeight,
119
- })
120
-
121
- if (!instance.scrollElement) {
91
+ const element = instance.scrollElement
92
+ if (!element) {
122
93
  return
123
94
  }
124
95
 
125
- onResize()
96
+ const handler = () => {
97
+ cb({ width: element.innerWidth, height: element.innerHeight })
98
+ }
99
+ handler()
126
100
 
127
- instance.scrollElement.addEventListener('resize', onResize, {
128
- capture: false,
101
+ element.addEventListener('resize', handler, {
129
102
  passive: true,
130
103
  })
131
104
 
132
105
  return () => {
133
- instance.scrollElement.removeEventListener('resize', onResize)
106
+ element.removeEventListener('resize', handler)
134
107
  }
135
108
  }
136
109
 
137
- type ObserverMode = 'element' | 'window'
138
-
139
- const scrollProps = {
140
- element: ['scrollLeft', 'scrollTop'],
141
- window: ['scrollX', 'scrollY'],
142
- } as const
143
-
144
- const createOffsetObserver = (mode: ObserverMode) => {
145
- return (instance: Virtualizer<any, any>, cb: (offset: number) => void) => {
146
- if (!instance.scrollElement) {
147
- return
148
- }
149
-
150
- const propX = scrollProps[mode][0]
151
- const propY = scrollProps[mode][1]
152
-
153
- let prevX: number = instance.scrollElement[propX]
154
- let prevY: number = instance.scrollElement[propY]
155
-
156
- const scroll = () => {
157
- const offset =
158
- instance.scrollElement[instance.options.horizontal ? propX : propY]
110
+ export const observeElementOffset = <T extends Element>(
111
+ instance: Virtualizer<T, any>,
112
+ cb: (offset: number) => void,
113
+ ) => {
114
+ const element = instance.scrollElement
115
+ if (!element) {
116
+ return
117
+ }
159
118
 
160
- cb(offset)
161
- }
119
+ const handler = () => {
120
+ cb(element[instance.options.horizontal ? 'scrollLeft' : 'scrollTop'])
121
+ }
122
+ handler()
162
123
 
163
- scroll()
124
+ element.addEventListener('scroll', handler, {
125
+ passive: true,
126
+ })
164
127
 
165
- const onScroll = (e: Event) => {
166
- const target = e.currentTarget as HTMLElement & Window
167
- const scrollX = target[propX]
168
- const scrollY = target[propY]
128
+ return () => {
129
+ element.removeEventListener('scroll', handler)
130
+ }
131
+ }
169
132
 
170
- if (instance.options.horizontal ? prevX - scrollX : prevY - scrollY) {
171
- scroll()
172
- }
133
+ export const observeWindowOffset = (
134
+ instance: Virtualizer<Window, any>,
135
+ cb: (offset: number) => void,
136
+ ) => {
137
+ const element = instance.scrollElement
138
+ if (!element) {
139
+ return
140
+ }
173
141
 
174
- prevX = scrollX
175
- prevY = scrollY
176
- }
142
+ const handler = () => {
143
+ cb(element[instance.options.horizontal ? 'scrollX' : 'scrollY'])
144
+ }
145
+ handler()
177
146
 
178
- instance.scrollElement.addEventListener('scroll', onScroll, {
179
- capture: false,
180
- passive: true,
181
- })
147
+ element.addEventListener('scroll', handler, {
148
+ passive: true,
149
+ })
182
150
 
183
- return () => {
184
- instance.scrollElement.removeEventListener('scroll', onScroll)
185
- }
151
+ return () => {
152
+ element.removeEventListener('scroll', handler)
186
153
  }
187
154
  }
188
155
 
189
- export const observeElementOffset = createOffsetObserver('element')
190
- export const observeWindowOffset = createOffsetObserver('window')
191
-
192
156
  export const measureElement = <TItemElement extends Element>(
193
157
  element: TItemElement,
194
158
  instance: Virtualizer<any, TItemElement>,
@@ -397,8 +361,15 @@ export class Virtualizer<
397
361
 
398
362
  this.unsubs.push(
399
363
  this.options.observeElementRect(this, (rect) => {
364
+ const prev = this.scrollRect
400
365
  this.scrollRect = rect
401
- this.maybeNotify()
366
+ if (
367
+ this.options.horizontal
368
+ ? rect.width !== prev.width
369
+ : rect.height !== prev.height
370
+ ) {
371
+ this.maybeNotify()
372
+ }
402
373
  }),
403
374
  )
404
375
 
@@ -663,47 +634,9 @@ export class Virtualizer<
663
634
  return Math.max(Math.min(maxOffset, toOffset), 0)
664
635
  }
665
636
 
666
- scrollToOffset = (
667
- toOffset: number,
668
- { align = 'start', behavior }: ScrollToOffsetOptions = {},
669
- ) => {
670
- const isDynamic = Object.keys(this.measureElementCache).length > 0
671
-
672
- if (isDynamic && behavior === 'smooth') {
673
- console.warn(
674
- 'The `smooth` scroll behavior is not supported with dynamic size.',
675
- )
676
- return
677
- }
678
-
679
- const options = {
680
- adjustments: undefined,
681
- behavior,
682
- sync: false,
683
- }
684
- this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), options)
685
- }
686
-
687
- scrollToIndex = (
688
- index: number,
689
- { align = 'auto', behavior }: ScrollToIndexOptions = {},
690
- ) => {
637
+ getOffsetForIndex = (index: number, align: ScrollAlignment = 'auto') => {
691
638
  index = Math.max(0, Math.min(index, this.options.count - 1))
692
639
 
693
- if (this.scrollToIndexTimeoutId !== null) {
694
- clearTimeout(this.scrollToIndexTimeoutId)
695
- this.scrollToIndexTimeoutId = null
696
- }
697
-
698
- const isDynamic = Object.keys(this.measureElementCache).length > 0
699
-
700
- if (isDynamic && behavior === 'smooth') {
701
- console.warn(
702
- 'The `smooth` scroll behavior is not supported with dynamic size.',
703
- )
704
- return
705
- }
706
-
707
640
  const measurement = notUndefined(this.getMeasurements()[index])
708
641
 
709
642
  if (align === 'auto') {
@@ -718,28 +651,64 @@ export class Virtualizer<
718
651
  ) {
719
652
  align = 'start'
720
653
  } else {
721
- return
654
+ return [this.scrollOffset, align] as const
722
655
  }
723
656
  }
724
657
 
725
- const getOffsetForIndexAndAlignment = (measurement: VirtualItem) => {
726
- const toOffset =
727
- align === 'end'
728
- ? measurement.end + this.options.scrollPaddingEnd
729
- : measurement.start - this.options.scrollPaddingStart
658
+ const toOffset =
659
+ align === 'end'
660
+ ? measurement.end + this.options.scrollPaddingEnd
661
+ : measurement.start - this.options.scrollPaddingStart
662
+
663
+ return [this.getOffsetForAlignment(toOffset, align), align] as const
664
+ }
730
665
 
731
- return this.getOffsetForAlignment(toOffset, align)
666
+ private isDynamicMode = () => Object.keys(this.measureElementCache).length > 0
667
+
668
+ private cancelScrollToIndex = () => {
669
+ if (this.scrollToIndexTimeoutId !== null) {
670
+ clearTimeout(this.scrollToIndexTimeoutId)
671
+ this.scrollToIndexTimeoutId = null
732
672
  }
673
+ }
674
+
675
+ scrollToOffset = (
676
+ toOffset: number,
677
+ { align = 'start', behavior }: ScrollToOffsetOptions = {},
678
+ ) => {
679
+ this.cancelScrollToIndex()
733
680
 
734
- const toOffset = getOffsetForIndexAndAlignment(measurement)
681
+ if (behavior === 'smooth' && this.isDynamicMode()) {
682
+ console.warn(
683
+ 'The `smooth` scroll behavior is not fully supported with dynamic size.',
684
+ )
685
+ }
735
686
 
736
- const options = {
687
+ this._scrollToOffset(this.getOffsetForAlignment(toOffset, align), {
737
688
  adjustments: undefined,
738
689
  behavior,
690
+ })
691
+ }
692
+
693
+ scrollToIndex = (
694
+ index: number,
695
+ { align: initialAlign = 'auto', behavior }: ScrollToIndexOptions = {},
696
+ ) => {
697
+ index = Math.max(0, Math.min(index, this.options.count - 1))
698
+
699
+ this.cancelScrollToIndex()
700
+
701
+ if (behavior === 'smooth' && this.isDynamicMode()) {
702
+ console.warn(
703
+ 'The `smooth` scroll behavior is not fully supported with dynamic size.',
704
+ )
739
705
  }
740
- this._scrollToOffset(toOffset, options)
741
706
 
742
- if (isDynamic) {
707
+ const [toOffset, align] = this.getOffsetForIndex(index, initialAlign)
708
+
709
+ this._scrollToOffset(toOffset, { adjustments: undefined, behavior })
710
+
711
+ if (behavior !== 'smooth' && this.isDynamicMode()) {
743
712
  this.scrollToIndexTimeoutId = setTimeout(() => {
744
713
  this.scrollToIndexTimeoutId = null
745
714
 
@@ -747,9 +716,7 @@ export class Virtualizer<
747
716
  !!this.measureElementCache[this.options.getItemKey(index)]
748
717
 
749
718
  if (elementInDOM) {
750
- const toOffset = getOffsetForIndexAndAlignment(
751
- notUndefined(this.getMeasurements()[index]),
752
- )
719
+ const [toOffset] = this.getOffsetForIndex(index, align)
753
720
 
754
721
  if (!approxEqual(toOffset, this.scrollOffset)) {
755
722
  this.scrollToIndex(index, { align, behavior })
@@ -762,13 +729,12 @@ export class Virtualizer<
762
729
  }
763
730
 
764
731
  scrollBy = (delta: number, { behavior }: ScrollToOffsetOptions = {}) => {
765
- const isDynamic = Object.keys(this.measureElementCache).length > 0
732
+ this.cancelScrollToIndex()
766
733
 
767
- if (isDynamic && behavior === 'smooth') {
734
+ if (behavior === 'smooth' && this.isDynamicMode()) {
768
735
  console.warn(
769
- 'The `smooth` scroll behavior is not supported with dynamic size.',
736
+ 'The `smooth` scroll behavior is not fully supported with dynamic size.',
770
737
  )
771
- return
772
738
  }
773
739
 
774
740
  this._scrollToOffset(this.scrollOffset + delta, {