@tanstack/virtual-core 3.0.0-beta.0 → 3.0.0-beta.6

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":["../../../../node_modules/@reach/observe-rect/dist/observe-rect.esm.js","../../src/utils.ts","../../src/index.ts"],"sourcesContent":["var props = [\"bottom\", \"height\", \"left\", \"right\", \"top\", \"width\"];\n\nvar rectChanged = function rectChanged(a, b) {\n if (a === void 0) {\n a = {};\n }\n\n if (b === void 0) {\n b = {};\n }\n\n return props.some(function (prop) {\n return a[prop] !== b[prop];\n });\n};\n\nvar observedNodes = /*#__PURE__*/new Map();\nvar rafId;\n\nvar run = function run() {\n var changedStates = [];\n observedNodes.forEach(function (state, node) {\n var newRect = node.getBoundingClientRect();\n\n if (rectChanged(newRect, state.rect)) {\n state.rect = newRect;\n changedStates.push(state);\n }\n });\n changedStates.forEach(function (state) {\n state.callbacks.forEach(function (cb) {\n return cb(state.rect);\n });\n });\n rafId = window.requestAnimationFrame(run);\n};\n\nfunction observeRect(node, cb) {\n return {\n observe: function observe() {\n var wasEmpty = observedNodes.size === 0;\n\n if (observedNodes.has(node)) {\n observedNodes.get(node).callbacks.push(cb);\n } else {\n observedNodes.set(node, {\n rect: undefined,\n hasRectChanged: false,\n callbacks: [cb]\n });\n }\n\n if (wasEmpty) run();\n },\n unobserve: function unobserve() {\n var state = observedNodes.get(node);\n\n if (state) {\n // Remove the callback\n var index = state.callbacks.indexOf(cb);\n if (index >= 0) state.callbacks.splice(index, 1); // Remove the node reference\n\n if (!state.callbacks.length) observedNodes[\"delete\"](node); // Stop the loop\n\n if (!observedNodes.size) cancelAnimationFrame(rafId);\n }\n }\n };\n}\n\nexport default observeRect;\n//# sourceMappingURL=observe-rect.esm.js.map\n","export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: any\n debug?: () => any\n onChange?: (result: TResult) => void\n },\n): () => TResult {\n let deps: any[] = []\n let result: TResult | undefined\n\n return () => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n opts?.onChange?.(result)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n return result!\n }\n}\n","import observeRect from '@reach/observe-rect'\nimport { check } from 'prettier'\nimport React from 'react'\nimport { memo } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ninterface ScrollToOptions {\n align: ScrollAlignment\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\ninterface Item {\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\nexport interface VirtualItem<TItemElement> extends Item {\n measureElement: (el: TItemElement | null) => void\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 = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n const observer = observeRect(instance.scrollElement as Element, (rect) => {\n cb(rect)\n })\n\n if (!instance.scrollElement) {\n return\n }\n\n cb(instance.scrollElement.getBoundingClientRect())\n\n observer.observe()\n\n return () => {\n observer.unobserve()\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n const onResize = () => {\n cb({\n width: instance.scrollElement.innerWidth,\n height: instance.scrollElement.innerHeight,\n })\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\nexport const observeElementOffset = (\n instance: Virtualizer<any, any>,\n cb: (offset: number) => void,\n) => {\n const onScroll = () =>\n cb(\n instance.scrollElement[\n instance.options.horizontal ? 'scrollLeft' : 'scrollTop'\n ],\n )\n\n if (!instance.scrollElement) {\n return\n }\n\n onScroll()\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\nexport const observeWindowOffset = (\n instance: Virtualizer<any, any>,\n cb: (offset: number) => void,\n) => {\n const onScroll = () =>\n cb(\n instance.scrollElement[\n instance.options.horizontal ? 'scrollX' : 'scrollY'\n ],\n )\n\n if (!instance.scrollElement) {\n return\n }\n\n onScroll()\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\nexport const measureElement = (\n element: unknown,\n instance: Virtualizer<any, any>,\n) => {\n return (element as Element).getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ]\n}\n\nexport const windowScroll = (\n offset: number,\n canSmooth: boolean,\n instance: Virtualizer<any, any>,\n) => {\n ;(instance.scrollElement as Window)?.scrollTo({\n [instance.options.horizontal ? 'left' : 'top']: offset,\n behavior: canSmooth ? 'smooth' : undefined,\n })\n}\n\nexport const elementScroll = (\n offset: number,\n canSmooth: boolean,\n instance: Virtualizer<any, any>,\n) => {\n ;(instance.scrollElement as Element)?.scrollTo({\n [instance.options.horizontal ? 'left' : 'top']: offset,\n behavior: canSmooth ? 'smooth' : undefined,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement = unknown,\n TItemElement = unknown,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n canSmooth: boolean,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => void\n observeElementRect: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (offset: number) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (instance: Virtualizer<TScrollElement, TItemElement>) => void\n measureElement?: (\n el: TItemElement,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => number\n overscan?: number\n horizontal?: boolean\n paddingStart?: number\n paddingEnd?: number\n initialOffset?: number\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => number[]\n enableSmoothScroll?: boolean\n}\n\nexport class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {\n private unsubs: (void | (() => void))[] = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n private measurementsCache: Item[] = []\n private itemMeasurementsCache: Record<Key, number> = {}\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n private scrollOffset: number\n private destinationOffset: undefined | number\n private scrollCheckFrame!: ReturnType<typeof setTimeout>\n\n constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {\n this.setOptions(opts)\n this.scrollRect = this.options.initialRect\n this.scrollOffset = this.options.initialOffset\n }\n\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 horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n enableSmoothScroll: false,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\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 }\n\n _didMount = () => {\n return () => {\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.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect\n this.notify()\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n this.scrollOffset = offset\n this.notify()\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.getItemKey,\n this.itemMeasurementsCache,\n ],\n (count, paddingStart, getItemKey, measurementsCache) => {\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n const measuredSize = measurementsCache[key]\n const start = measurements[i - 1]\n ? measurements[i - 1]!.end\n : paddingStart\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n const end = start + size\n measurements[i] = { index: i, start, size, end, key }\n }\n\n this.measurementsCache = measurements\n return measurements\n },\n {\n key: process.env.NODE_ENV === 'development' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n private calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.scrollOffset],\n (measurements, outerSize, scrollOffset) => {\n return calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n })\n },\n {\n key: process.env.NODE_ENV === 'development' && 'calculateRange',\n debug: () => this.options.debug,\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: count,\n })\n },\n {\n key: process.env.NODE_ENV === 'development' && 'getIndexes',\n },\n )\n\n getVirtualItems = memo(\n () => [\n this.getIndexes(),\n this.getMeasurements(),\n this.options.measureElement,\n ],\n (indexes, measurements, measureElement) => {\n const virtualItems: VirtualItem<TItemElement>[] = []\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n const item = {\n ...measurement,\n measureElement: (measurableItem: TItemElement | null) => {\n if (measurableItem) {\n const measuredItemSize = measureElement(measurableItem, this)\n\n if (measuredItemSize !== item.size) {\n if (item.start < this.scrollOffset) {\n if (\n process.env.NODE_ENV === 'development' &&\n this.options.debug\n )\n console.info('correction', measuredItemSize - item.size)\n\n if (!this.destinationOffset) {\n this._scrollToOffset(\n this.scrollOffset + (measuredItemSize - item.size),\n false,\n )\n }\n }\n\n this.pendingMeasuredCacheIndexes.push(i)\n this.itemMeasurementsCache = {\n ...this.itemMeasurementsCache,\n [item.key]: measuredItemSize,\n }\n this.notify()\n }\n }\n },\n }\n\n virtualItems.push(item)\n }\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV === 'development' && 'getIndexes',\n },\n )\n\n scrollToOffset = (\n toOffset: number,\n { align }: ScrollToOffsetOptions = { align: 'start' },\n ) => {\n const attempt = () => {\n const offset = this.scrollOffset\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= offset) {\n align = 'start'\n } else if (toOffset >= offset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n this._scrollToOffset(toOffset, true)\n } else if (align === 'end') {\n this._scrollToOffset(toOffset - size, true)\n } else if (align === 'center') {\n this._scrollToOffset(toOffset - size / 2, true)\n }\n }\n\n attempt()\n requestAnimationFrame(() => {\n attempt()\n })\n }\n\n scrollToIndex = (\n index: number,\n { align, ...rest }: ScrollToIndexOptions = { align: 'auto' },\n ) => {\n const measurements = this.getMeasurements()\n const offset = this.scrollOffset\n const size = this.getSize()\n const { count } = this.options\n\n const measurement = measurements[Math.max(0, Math.min(index, count - 1))]\n\n if (!measurement) {\n return\n }\n\n if (align === 'auto') {\n if (measurement.end >= offset + size) {\n align = 'end'\n } else if (measurement.start <= offset) {\n align = 'start'\n } else {\n return\n }\n }\n\n const toOffset =\n align === 'center'\n ? measurement.start + measurement.size / 2\n : align === 'end'\n ? measurement.end\n : measurement.start\n\n this.scrollToOffset(toOffset, { align, ...rest })\n }\n\n getTotalSize = () =>\n (this.getMeasurements()[this.options.count - 1]?.end ||\n this.options.paddingStart) + this.options.paddingEnd\n\n private _scrollToOffset = (offset: number, canSmooth: boolean) => {\n clearTimeout(this.scrollCheckFrame)\n\n this.destinationOffset = offset\n this.options.scrollToFn(offset, canSmooth, this)\n\n let scrollCheckFrame: ReturnType<typeof setTimeout>\n\n const check = () => {\n let lastOffset = this.scrollOffset\n this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {\n if (this.scrollCheckFrame !== scrollCheckFrame) {\n return\n }\n\n if (this.scrollOffset === lastOffset) {\n this.destinationOffset = undefined\n return\n }\n lastOffset = this.scrollOffset\n check()\n }, 100)\n }\n\n check()\n }\n\n measure = () => {\n this.itemMeasurementsCache = {}\n this.notify()\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: Item[]\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":["rafId","props","observedNodes","Map","run","changedStates","forEach","state","node","a","b","newRect","getBoundingClientRect","rect","some","prop","push","callbacks","cb","window","requestAnimationFrame","memo","getDeps","fn","opts","result","deps","depTime","key","debug","Date","now","newDeps","length","dep","index","resultTime","onChange","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min","defaultKeyExtractor","defaultRangeExtractor","range","start","startIndex","overscan","end","endIndex","count","arr","i","measureElement","element","instance","options","horizontal","constructor","_this","this","unsubs","scrollElement","measurementsCache","itemMeasurementsCache","pendingMeasuredCacheIndexes","setOptions","Object","entries","_ref","value","initialOffset","paddingStart","paddingEnd","getItemKey","rangeExtractor","enableSmoothScroll","initialRect","width","height","notify","_this$options$onChang","_this$options","call","cleanup","filter","Boolean","d","_didMount","_willUpdate","getScrollElement","observeElementRect","scrollRect","observeElementOffset","offset","scrollOffset","getSize","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","calculateRange","outerSize","_ref2","low","high","getCurrentValue","middle","currentValue","findNearestBinarySearch","getIndexes","getVirtualItems","indexes","virtualItems","k","len","item","measurableItem","measuredItemSize","destinationOffset","_scrollToOffset","scrollToOffset","toOffset","_temp","align","attempt","scrollToIndex","_temp2","rest","measurement","getTotalSize","_this$getMeasurements","canSmooth","scrollCheckFrame","clearTimeout","scrollToFn","check","lastOffset","setTimeout","undefined","measure","_instance$scrollEleme2","scrollTo","behavior","onScroll","addEventListener","capture","passive","removeEventListener","observer","observe","wasEmpty","has","get","set","hasRectChanged","unobserve","indexOf","splice","cancelAnimationFrame","observeRect","onResize","innerWidth","innerHeight","_instance$scrollEleme"],"mappings":"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"}
1
+ {"version":3,"file":"index.production.js","sources":["../../../../node_modules/@reach/observe-rect/dist/observe-rect.esm.js","../../src/utils.ts","../../src/index.ts"],"sourcesContent":["var props = [\"bottom\", \"height\", \"left\", \"right\", \"top\", \"width\"];\n\nvar rectChanged = function rectChanged(a, b) {\n if (a === void 0) {\n a = {};\n }\n\n if (b === void 0) {\n b = {};\n }\n\n return props.some(function (prop) {\n return a[prop] !== b[prop];\n });\n};\n\nvar observedNodes = /*#__PURE__*/new Map();\nvar rafId;\n\nvar run = function run() {\n var changedStates = [];\n observedNodes.forEach(function (state, node) {\n var newRect = node.getBoundingClientRect();\n\n if (rectChanged(newRect, state.rect)) {\n state.rect = newRect;\n changedStates.push(state);\n }\n });\n changedStates.forEach(function (state) {\n state.callbacks.forEach(function (cb) {\n return cb(state.rect);\n });\n });\n rafId = window.requestAnimationFrame(run);\n};\n\nfunction observeRect(node, cb) {\n return {\n observe: function observe() {\n var wasEmpty = observedNodes.size === 0;\n\n if (observedNodes.has(node)) {\n observedNodes.get(node).callbacks.push(cb);\n } else {\n observedNodes.set(node, {\n rect: undefined,\n hasRectChanged: false,\n callbacks: [cb]\n });\n }\n\n if (wasEmpty) run();\n },\n unobserve: function unobserve() {\n var state = observedNodes.get(node);\n\n if (state) {\n // Remove the callback\n var index = state.callbacks.indexOf(cb);\n if (index >= 0) state.callbacks.splice(index, 1); // Remove the node reference\n\n if (!state.callbacks.length) observedNodes[\"delete\"](node); // Stop the loop\n\n if (!observedNodes.size) cancelAnimationFrame(rafId);\n }\n }\n };\n}\n\nexport default observeRect;\n//# sourceMappingURL=observe-rect.esm.js.map\n","export type NoInfer<A extends any> = [A][A extends any ? 0 : never]\n\nexport type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>\n\nexport function memo<TDeps extends readonly any[], TResult>(\n getDeps: () => [...TDeps],\n fn: (...args: NoInfer<[...TDeps]>) => TResult,\n opts: {\n key: any\n debug?: () => any\n onChange?: (result: TResult) => void\n },\n): () => TResult {\n let deps: any[] = []\n let result: TResult | undefined\n\n return () => {\n let depTime: number\n if (opts.key && opts.debug?.()) depTime = Date.now()\n\n const newDeps = getDeps()\n\n const depsChanged =\n newDeps.length !== deps.length ||\n newDeps.some((dep: any, index: number) => deps[index] !== dep)\n\n if (!depsChanged) {\n return result!\n }\n\n deps = newDeps\n\n let resultTime: number\n if (opts.key && opts.debug?.()) resultTime = Date.now()\n\n result = fn(...newDeps)\n opts?.onChange?.(result)\n\n if (opts.key && opts.debug?.()) {\n const depEndTime = Math.round((Date.now() - depTime!) * 100) / 100\n const resultEndTime = Math.round((Date.now() - resultTime!) * 100) / 100\n const resultFpsPercentage = resultEndTime / 16\n\n const pad = (str: number | string, num: number) => {\n str = String(str)\n while (str.length < num) {\n str = ' ' + str\n }\n return str\n }\n\n console.info(\n `%c⏱ ${pad(resultEndTime, 5)} /${pad(depEndTime, 5)} ms`,\n `\n font-size: .6rem;\n font-weight: bold;\n color: hsl(${Math.max(\n 0,\n Math.min(120 - 120 * resultFpsPercentage, 120),\n )}deg 100% 31%);`,\n opts?.key,\n )\n }\n\n return result!\n }\n}\n","import observeRect from '@reach/observe-rect'\nimport { memo } from './utils'\n\nexport * from './utils'\n\n//\n\ntype ScrollAlignment = 'start' | 'center' | 'end' | 'auto'\n\ninterface ScrollToOptions {\n align: ScrollAlignment\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\ninterface Item {\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\nexport interface VirtualItem<TItemElement> extends Item {\n measureElement: (el: TItemElement | null) => void\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 = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n const observer = observeRect(instance.scrollElement as Element, (rect) => {\n cb(rect)\n })\n\n if (!instance.scrollElement) {\n return\n }\n\n cb(instance.scrollElement.getBoundingClientRect())\n\n observer.observe()\n\n return () => {\n observer.unobserve()\n }\n}\n\nexport const observeWindowRect = (\n instance: Virtualizer<any, any>,\n cb: (rect: Rect) => void,\n) => {\n const onResize = () => {\n cb({\n width: instance.scrollElement.innerWidth,\n height: instance.scrollElement.innerHeight,\n })\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\nexport const observeElementOffset = (\n instance: Virtualizer<any, any>,\n cb: (offset: number) => void,\n) => {\n const onScroll = () =>\n cb(\n instance.scrollElement[\n instance.options.horizontal ? 'scrollLeft' : 'scrollTop'\n ],\n )\n\n if (!instance.scrollElement) {\n return\n }\n\n onScroll()\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\nexport const observeWindowOffset = (\n instance: Virtualizer<any, any>,\n cb: (offset: number) => void,\n) => {\n const onScroll = () =>\n cb(\n instance.scrollElement[\n instance.options.horizontal ? 'scrollX' : 'scrollY'\n ],\n )\n\n if (!instance.scrollElement) {\n return\n }\n\n onScroll()\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\nexport const measureElement = (\n element: unknown,\n instance: Virtualizer<any, any>,\n) => {\n return (element as Element).getBoundingClientRect()[\n instance.options.horizontal ? 'width' : 'height'\n ]\n}\n\nexport const windowScroll = (\n offset: number,\n canSmooth: boolean,\n instance: Virtualizer<any, any>,\n) => {\n ;(instance.scrollElement as Window)?.scrollTo({\n [instance.options.horizontal ? 'left' : 'top']: offset,\n behavior: canSmooth ? 'smooth' : undefined,\n })\n}\n\nexport const elementScroll = (\n offset: number,\n canSmooth: boolean,\n instance: Virtualizer<any, any>,\n) => {\n ;(instance.scrollElement as Element)?.scrollTo({\n [instance.options.horizontal ? 'left' : 'top']: offset,\n behavior: canSmooth ? 'smooth' : undefined,\n })\n}\n\nexport interface VirtualizerOptions<\n TScrollElement = unknown,\n TItemElement = unknown,\n> {\n // Required from the user\n count: number\n getScrollElement: () => TScrollElement\n estimateSize: (index: number) => number\n\n // Required from the framework adapter (but can be overridden)\n scrollToFn: (\n offset: number,\n canSmooth: boolean,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => void\n observeElementRect: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (rect: Rect) => void,\n ) => void | (() => void)\n observeElementOffset: (\n instance: Virtualizer<TScrollElement, TItemElement>,\n cb: (offset: number) => void,\n ) => void | (() => void)\n\n // Optional\n debug?: any\n initialRect?: Rect\n onChange?: (instance: Virtualizer<TScrollElement, TItemElement>) => void\n measureElement?: (\n el: TItemElement,\n instance: Virtualizer<TScrollElement, TItemElement>,\n ) => number\n overscan?: number\n horizontal?: boolean\n paddingStart?: number\n paddingEnd?: number\n scrollPaddingStart?: number\n scrollPaddingEnd?: number\n initialOffset?: number\n getItemKey?: (index: number) => Key\n rangeExtractor?: (range: Range) => number[]\n enableSmoothScroll?: boolean\n}\n\nexport class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {\n private unsubs: (void | (() => void))[] = []\n options!: Required<VirtualizerOptions<TScrollElement, TItemElement>>\n scrollElement: TScrollElement | null = null\n private measurementsCache: Item[] = []\n private itemMeasurementsCache: Record<Key, number> = {}\n private pendingMeasuredCacheIndexes: number[] = []\n private scrollRect: Rect\n private scrollOffset: number\n private destinationOffset: undefined | number\n private scrollCheckFrame!: ReturnType<typeof setTimeout>\n private measureElementCache: Record<\n number,\n (measurableItem: TItemElement | null) => void\n > = {}\n\n constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {\n this.setOptions(opts)\n this.scrollRect = this.options.initialRect\n this.scrollOffset = this.options.initialOffset\n }\n\n setOptions = (opts: VirtualizerOptions<TScrollElement, TItemElement>) => {\n Object.entries(opts).forEach(([key, value]) => {\n if (typeof value === 'undefined') delete (opts as any)[key]\n })\n\n this.options = {\n debug: false,\n initialOffset: 0,\n overscan: 1,\n paddingStart: 0,\n paddingEnd: 0,\n scrollPaddingStart: 0,\n scrollPaddingEnd: 0,\n horizontal: false,\n getItemKey: defaultKeyExtractor,\n rangeExtractor: defaultRangeExtractor,\n enableSmoothScroll: true,\n onChange: () => {},\n measureElement,\n initialRect: { width: 0, height: 0 },\n ...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 }\n\n _didMount = () => {\n return () => {\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.unsubs.push(\n this.options.observeElementRect(this, (rect) => {\n this.scrollRect = rect\n this.notify()\n }),\n )\n\n this.unsubs.push(\n this.options.observeElementOffset(this, (offset) => {\n this.scrollOffset = offset\n this.notify()\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.getItemKey,\n this.itemMeasurementsCache,\n ],\n (count, paddingStart, getItemKey, measurementsCache) => {\n const min =\n this.pendingMeasuredCacheIndexes.length > 0\n ? Math.min(...this.pendingMeasuredCacheIndexes)\n : 0\n this.pendingMeasuredCacheIndexes = []\n\n const measurements = this.measurementsCache.slice(0, min)\n\n for (let i = min; i < count; i++) {\n const key = getItemKey(i)\n const measuredSize = measurementsCache[key]\n const start = measurements[i - 1]\n ? measurements[i - 1]!.end\n : paddingStart\n const size =\n typeof measuredSize === 'number'\n ? measuredSize\n : this.options.estimateSize(i)\n const end = start + size\n measurements[i] = { index: i, start, size, end, key }\n }\n\n this.measurementsCache = measurements\n return measurements\n },\n {\n key: process.env.NODE_ENV === 'development' && 'getMeasurements',\n debug: () => this.options.debug,\n },\n )\n\n private calculateRange = memo(\n () => [this.getMeasurements(), this.getSize(), this.scrollOffset],\n (measurements, outerSize, scrollOffset) => {\n return calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n })\n },\n {\n key: process.env.NODE_ENV === 'development' && 'calculateRange',\n debug: () => this.options.debug,\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: count,\n })\n },\n {\n key: process.env.NODE_ENV === 'development' && 'getIndexes',\n },\n )\n\n getVirtualItems = memo(\n () => [\n this.getIndexes(),\n this.getMeasurements(),\n this.options.measureElement,\n ],\n (indexes, measurements, measureElement) => {\n const makeMeasureElement =\n (index: number) => (measurableItem: TItemElement | null) => {\n const item = this.measurementsCache[index]!\n\n if (!measurableItem) {\n return\n }\n\n const measuredItemSize = measureElement(measurableItem, this)\n const itemSize = this.itemMeasurementsCache[item.key] ?? item.size\n\n if (measuredItemSize !== itemSize) {\n if (item.start < this.scrollOffset) {\n if (\n process.env.NODE_ENV === 'development' &&\n this.options.debug\n ) {\n console.info('correction', measuredItemSize - itemSize)\n }\n\n if (!this.destinationOffset) {\n this._scrollToOffset(\n this.scrollOffset + (measuredItemSize - itemSize),\n false,\n )\n }\n }\n\n this.pendingMeasuredCacheIndexes.push(index)\n this.itemMeasurementsCache = {\n ...this.itemMeasurementsCache,\n [item.key]: measuredItemSize,\n }\n this.notify()\n }\n }\n\n const virtualItems: VirtualItem<TItemElement>[] = []\n\n const currentMeasureElements: typeof this.measureElementCache = {}\n\n for (let k = 0, len = indexes.length; k < len; k++) {\n const i = indexes[k]!\n const measurement = measurements[i]!\n\n const item = {\n ...measurement,\n measureElement: (currentMeasureElements[i] =\n this.measureElementCache[i] ?? makeMeasureElement(i)),\n }\n virtualItems.push(item)\n }\n\n this.measureElementCache = currentMeasureElements\n\n return virtualItems\n },\n {\n key: process.env.NODE_ENV === 'development' && 'getIndexes',\n },\n )\n\n scrollToOffset = (\n toOffset: number,\n { align }: ScrollToOffsetOptions = { align: 'start' },\n ) => {\n const attempt = () => {\n const offset = this.scrollOffset\n const size = this.getSize()\n\n if (align === 'auto') {\n if (toOffset <= offset) {\n align = 'start'\n } else if (toOffset >= offset + size) {\n align = 'end'\n } else {\n align = 'start'\n }\n }\n\n if (align === 'start') {\n this._scrollToOffset(toOffset, true)\n } else if (align === 'end') {\n this._scrollToOffset(toOffset - size, true)\n } else if (align === 'center') {\n this._scrollToOffset(toOffset - size / 2, true)\n }\n }\n\n attempt()\n requestAnimationFrame(() => {\n attempt()\n })\n }\n\n scrollToIndex = (\n index: number,\n { align, ...rest }: ScrollToIndexOptions = { align: 'auto' },\n ) => {\n const measurements = this.getMeasurements()\n const offset = this.scrollOffset\n const size = this.getSize()\n const { count } = this.options\n\n const measurement = measurements[Math.max(0, Math.min(index, count - 1))]\n\n if (!measurement) {\n return\n }\n\n if (align === 'auto') {\n if (measurement.end >= offset + size - this.options.scrollPaddingEnd) {\n align = 'end'\n } else if (\n measurement.start <=\n offset + this.options.scrollPaddingStart\n ) {\n align = 'start'\n } else {\n return\n }\n }\n\n const toOffset =\n align === 'end'\n ? measurement.end + this.options.scrollPaddingEnd\n : measurement.start - this.options.scrollPaddingStart\n\n this.scrollToOffset(toOffset, { align, ...rest })\n }\n\n getTotalSize = () =>\n (this.getMeasurements()[this.options.count - 1]?.end ||\n this.options.paddingStart) + this.options.paddingEnd\n\n private _scrollToOffset = (offset: number, canSmooth: boolean) => {\n clearTimeout(this.scrollCheckFrame)\n\n this.destinationOffset = offset\n this.options.scrollToFn(\n offset,\n this.options.enableSmoothScroll && canSmooth,\n this,\n )\n\n let scrollCheckFrame: ReturnType<typeof setTimeout>\n\n const check = () => {\n let lastOffset = this.scrollOffset\n this.scrollCheckFrame = scrollCheckFrame = setTimeout(() => {\n if (this.scrollCheckFrame !== scrollCheckFrame) {\n return\n }\n\n if (this.scrollOffset === lastOffset) {\n this.destinationOffset = undefined\n return\n }\n lastOffset = this.scrollOffset\n check()\n }, 100)\n }\n\n check()\n }\n\n measure = () => {\n this.itemMeasurementsCache = {}\n this.notify()\n }\n}\n\nconst findNearestBinarySearch = (\n low: number,\n high: number,\n getCurrentValue: (i: number) => number,\n value: number,\n) => {\n while (low <= high) {\n const middle = ((low + high) / 2) | 0\n const currentValue = getCurrentValue(middle)\n\n if (currentValue < value) {\n low = middle + 1\n } else if (currentValue > value) {\n high = middle - 1\n } else {\n return middle\n }\n }\n\n if (low > 0) {\n return low - 1\n } else {\n return 0\n }\n}\n\nfunction calculateRange({\n measurements,\n outerSize,\n scrollOffset,\n}: {\n measurements: Item[]\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":["rafId","props","observedNodes","Map","run","changedStates","forEach","state","node","a","b","newRect","getBoundingClientRect","rect","some","prop","push","callbacks","cb","window","requestAnimationFrame","memo","getDeps","fn","opts","result","deps","depTime","key","debug","Date","now","newDeps","length","dep","index","resultTime","onChange","depEndTime","Math","round","resultEndTime","resultFpsPercentage","pad","str","num","String","console","info","max","min","defaultKeyExtractor","defaultRangeExtractor","range","start","startIndex","overscan","end","endIndex","count","arr","i","measureElement","element","instance","options","horizontal","constructor","_this","this","unsubs","scrollElement","measurementsCache","itemMeasurementsCache","pendingMeasuredCacheIndexes","measureElementCache","setOptions","Object","entries","_ref","value","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","enableSmoothScroll","initialRect","width","height","notify","_this$options$onChang","_this$options","call","cleanup","filter","Boolean","d","_didMount","_willUpdate","getScrollElement","observeElementRect","scrollRect","observeElementOffset","offset","scrollOffset","getSize","getMeasurements","measurements","slice","measuredSize","size","estimateSize","process","calculateRange","outerSize","_ref2","low","high","getCurrentValue","middle","currentValue","findNearestBinarySearch","getIndexes","getVirtualItems","indexes","makeMeasureElement","measurableItem","_this$itemMeasurement","item","measuredItemSize","itemSize","destinationOffset","_scrollToOffset","virtualItems","currentMeasureElements","k","len","_this$measureElementC","scrollToOffset","toOffset","_temp","align","attempt","scrollToIndex","_temp2","rest","measurement","getTotalSize","_this$getMeasurements","canSmooth","scrollCheckFrame","clearTimeout","scrollToFn","check","lastOffset","setTimeout","undefined","measure","_instance$scrollEleme2","scrollTo","behavior","onScroll","addEventListener","capture","passive","removeEventListener","observer","observe","wasEmpty","has","get","set","hasRectChanged","unobserve","indexOf","splice","cancelAnimationFrame","observeRect","onResize","innerWidth","innerHeight","_instance$scrollEleme"],"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.0",
4
+ "version": "3.0.0-beta.6",
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
@@ -1,6 +1,4 @@
1
1
  import observeRect from '@reach/observe-rect'
2
- import { check } from 'prettier'
3
- import React from 'react'
4
2
  import { memo } from './utils'
5
3
 
6
4
  export * from './utils'
@@ -229,6 +227,8 @@ export interface VirtualizerOptions<
229
227
  horizontal?: boolean
230
228
  paddingStart?: number
231
229
  paddingEnd?: number
230
+ scrollPaddingStart?: number
231
+ scrollPaddingEnd?: number
232
232
  initialOffset?: number
233
233
  getItemKey?: (index: number) => Key
234
234
  rangeExtractor?: (range: Range) => number[]
@@ -246,6 +246,10 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
246
246
  private scrollOffset: number
247
247
  private destinationOffset: undefined | number
248
248
  private scrollCheckFrame!: ReturnType<typeof setTimeout>
249
+ private measureElementCache: Record<
250
+ number,
251
+ (measurableItem: TItemElement | null) => void
252
+ > = {}
249
253
 
250
254
  constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {
251
255
  this.setOptions(opts)
@@ -264,10 +268,12 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
264
268
  overscan: 1,
265
269
  paddingStart: 0,
266
270
  paddingEnd: 0,
271
+ scrollPaddingStart: 0,
272
+ scrollPaddingEnd: 0,
267
273
  horizontal: false,
268
274
  getItemKey: defaultKeyExtractor,
269
275
  rangeExtractor: defaultRangeExtractor,
270
- enableSmoothScroll: false,
276
+ enableSmoothScroll: true,
271
277
  onChange: () => {},
272
278
  measureElement,
273
279
  initialRect: { width: 0, height: 0 },
@@ -398,48 +404,61 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
398
404
  this.options.measureElement,
399
405
  ],
400
406
  (indexes, measurements, measureElement) => {
407
+ const makeMeasureElement =
408
+ (index: number) => (measurableItem: TItemElement | null) => {
409
+ const item = this.measurementsCache[index]!
410
+
411
+ if (!measurableItem) {
412
+ return
413
+ }
414
+
415
+ const measuredItemSize = measureElement(measurableItem, this)
416
+ const itemSize = this.itemMeasurementsCache[item.key] ?? item.size
417
+
418
+ if (measuredItemSize !== itemSize) {
419
+ if (item.start < this.scrollOffset) {
420
+ if (
421
+ process.env.NODE_ENV === 'development' &&
422
+ this.options.debug
423
+ ) {
424
+ console.info('correction', measuredItemSize - itemSize)
425
+ }
426
+
427
+ if (!this.destinationOffset) {
428
+ this._scrollToOffset(
429
+ this.scrollOffset + (measuredItemSize - itemSize),
430
+ false,
431
+ )
432
+ }
433
+ }
434
+
435
+ this.pendingMeasuredCacheIndexes.push(index)
436
+ this.itemMeasurementsCache = {
437
+ ...this.itemMeasurementsCache,
438
+ [item.key]: measuredItemSize,
439
+ }
440
+ this.notify()
441
+ }
442
+ }
443
+
401
444
  const virtualItems: VirtualItem<TItemElement>[] = []
402
445
 
446
+ const currentMeasureElements: typeof this.measureElementCache = {}
447
+
403
448
  for (let k = 0, len = indexes.length; k < len; k++) {
404
449
  const i = indexes[k]!
405
450
  const measurement = measurements[i]!
406
451
 
407
452
  const item = {
408
453
  ...measurement,
409
- measureElement: (measurableItem: TItemElement | null) => {
410
- if (measurableItem) {
411
- const measuredItemSize = measureElement(measurableItem, this)
412
-
413
- if (measuredItemSize !== item.size) {
414
- if (item.start < this.scrollOffset) {
415
- if (
416
- process.env.NODE_ENV === 'development' &&
417
- this.options.debug
418
- )
419
- console.info('correction', measuredItemSize - item.size)
420
-
421
- if (!this.destinationOffset) {
422
- this._scrollToOffset(
423
- this.scrollOffset + (measuredItemSize - item.size),
424
- false,
425
- )
426
- }
427
- }
428
-
429
- this.pendingMeasuredCacheIndexes.push(i)
430
- this.itemMeasurementsCache = {
431
- ...this.itemMeasurementsCache,
432
- [item.key]: measuredItemSize,
433
- }
434
- this.notify()
435
- }
436
- }
437
- },
454
+ measureElement: (currentMeasureElements[i] =
455
+ this.measureElementCache[i] ?? makeMeasureElement(i)),
438
456
  }
439
-
440
457
  virtualItems.push(item)
441
458
  }
442
459
 
460
+ this.measureElementCache = currentMeasureElements
461
+
443
462
  return virtualItems
444
463
  },
445
464
  {
@@ -496,9 +515,12 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
496
515
  }
497
516
 
498
517
  if (align === 'auto') {
499
- if (measurement.end >= offset + size) {
518
+ if (measurement.end >= offset + size - this.options.scrollPaddingEnd) {
500
519
  align = 'end'
501
- } else if (measurement.start <= offset) {
520
+ } else if (
521
+ measurement.start <=
522
+ offset + this.options.scrollPaddingStart
523
+ ) {
502
524
  align = 'start'
503
525
  } else {
504
526
  return
@@ -506,11 +528,9 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
506
528
  }
507
529
 
508
530
  const toOffset =
509
- align === 'center'
510
- ? measurement.start + measurement.size / 2
511
- : align === 'end'
512
- ? measurement.end
513
- : measurement.start
531
+ align === 'end'
532
+ ? measurement.end + this.options.scrollPaddingEnd
533
+ : measurement.start - this.options.scrollPaddingStart
514
534
 
515
535
  this.scrollToOffset(toOffset, { align, ...rest })
516
536
  }
@@ -523,7 +543,11 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
523
543
  clearTimeout(this.scrollCheckFrame)
524
544
 
525
545
  this.destinationOffset = offset
526
- this.options.scrollToFn(offset, canSmooth, this)
546
+ this.options.scrollToFn(
547
+ offset,
548
+ this.options.enableSmoothScroll && canSmooth,
549
+ this,
550
+ )
527
551
 
528
552
  let scrollCheckFrame: ReturnType<typeof setTimeout>
529
553
 
@@ -1,49 +0,0 @@
1
- /**
2
- * virtual-core
3
- *
4
- * Copyright (c) TanStack
5
- *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE.md file in the root directory of this source tree.
8
- *
9
- * @license MIT
10
- */
11
- 'use strict';
12
-
13
- Object.defineProperty(exports, '__esModule', { value: true });
14
-
15
- function _extends() {
16
- _extends = Object.assign ? Object.assign.bind() : function (target) {
17
- for (var i = 1; i < arguments.length; i++) {
18
- var source = arguments[i];
19
-
20
- for (var key in source) {
21
- if (Object.prototype.hasOwnProperty.call(source, key)) {
22
- target[key] = source[key];
23
- }
24
- }
25
- }
26
-
27
- return target;
28
- };
29
- return _extends.apply(this, arguments);
30
- }
31
-
32
- function _objectWithoutPropertiesLoose(source, excluded) {
33
- if (source == null) return {};
34
- var target = {};
35
- var sourceKeys = Object.keys(source);
36
- var key, i;
37
-
38
- for (i = 0; i < sourceKeys.length; i++) {
39
- key = sourceKeys[i];
40
- if (excluded.indexOf(key) >= 0) continue;
41
- target[key] = source[key];
42
- }
43
-
44
- return target;
45
- }
46
-
47
- exports["extends"] = _extends;
48
- exports.objectWithoutPropertiesLoose = _objectWithoutPropertiesLoose;
49
- //# sourceMappingURL=_rollupPluginBabelHelpers.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"_rollupPluginBabelHelpers.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}