@tanstack/virtual-core 3.0.0-beta.1 → 3.0.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/node_modules/@reach/observe-rect/dist/observe-rect.esm.js +86 -0
- package/build/cjs/node_modules/@reach/observe-rect/dist/observe-rect.esm.js.map +1 -0
- package/build/cjs/packages/virtual-core/src/index.js +103 -55
- package/build/cjs/packages/virtual-core/src/index.js.map +1 -1
- package/build/esm/index.js +103 -55
- package/build/esm/index.js.map +1 -1
- package/build/{stats-html.html → stats.html} +1 -1
- package/build/{stats-react.json → stats.json} +21 -21
- package/build/types/index.d.ts +34 -14
- package/build/umd/index.development.js +103 -55
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +115 -80
- package/build/types/utils.d.ts +0 -7
|
@@ -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 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\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 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 - 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","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","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\nexport interface 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\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 onResize = memoRectCallback(instance, cb)\n\n const observer = observeRect(instance.scrollElement as Element, (rect) => {\n onResize(rect)\n })\n\n if (!instance.scrollElement) {\n return\n }\n\n onResize(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 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 cb(instance.scrollElement[instance.options.horizontal ? propX : propY])\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 = (\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 this.scrollElement = null\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","memoRectCallback","instance","prev","height","width","options","horizontal","scrollProps","element","createOffsetObserver","mode","scrollElement","propX","propY","prevX","prevY","scroll","onScroll","e","target","currentTarget","scrollX","scrollY","addEventListener","capture","passive","removeEventListener","observeElementOffset","observeWindowOffset","measureElement","constructor","_this","this","unsubs","measurementsCache","itemMeasurementsCache","pendingMeasuredCacheIndexes","measureElementCache","setOptions","Object","entries","_ref","value","initialOffset","paddingStart","paddingEnd","scrollPaddingStart","scrollPaddingEnd","getItemKey","rangeExtractor","enableSmoothScroll","initialRect","notify","_this$options$onChang","_this$options","call","cleanup","filter","Boolean","d","_didMount","_willUpdate","getScrollElement","observeElementRect","scrollRect","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","onResize","observer","observe","wasEmpty","has","get","set","hasRectChanged","unobserve","indexOf","splice","cancelAnimationFrame","observeRect","memoizedCallback","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.
|
|
4
|
+
"version": "3.0.0-beta.13",
|
|
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",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"node": ">=12"
|
|
34
34
|
},
|
|
35
35
|
"files": [
|
|
36
|
-
"build",
|
|
36
|
+
"build/**",
|
|
37
37
|
"src"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
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'
|
|
@@ -9,7 +7,7 @@ export * from './utils'
|
|
|
9
7
|
|
|
10
8
|
type ScrollAlignment = 'start' | 'center' | 'end' | 'auto'
|
|
11
9
|
|
|
12
|
-
interface ScrollToOptions {
|
|
10
|
+
export interface ScrollToOptions {
|
|
13
11
|
align: ScrollAlignment
|
|
14
12
|
}
|
|
15
13
|
|
|
@@ -60,19 +58,40 @@ export const defaultRangeExtractor = (range: Range) => {
|
|
|
60
58
|
return arr
|
|
61
59
|
}
|
|
62
60
|
|
|
61
|
+
const memoRectCallback = (
|
|
62
|
+
instance: Virtualizer<any, any>,
|
|
63
|
+
cb: (rect: Rect) => void,
|
|
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
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
63
80
|
export const observeElementRect = (
|
|
64
81
|
instance: Virtualizer<any, any>,
|
|
65
82
|
cb: (rect: Rect) => void,
|
|
66
83
|
) => {
|
|
84
|
+
const onResize = memoRectCallback(instance, cb)
|
|
85
|
+
|
|
67
86
|
const observer = observeRect(instance.scrollElement as Element, (rect) => {
|
|
68
|
-
|
|
87
|
+
onResize(rect)
|
|
69
88
|
})
|
|
70
89
|
|
|
71
90
|
if (!instance.scrollElement) {
|
|
72
91
|
return
|
|
73
92
|
}
|
|
74
93
|
|
|
75
|
-
|
|
94
|
+
onResize(instance.scrollElement.getBoundingClientRect())
|
|
76
95
|
|
|
77
96
|
observer.observe()
|
|
78
97
|
|
|
@@ -85,12 +104,12 @@ export const observeWindowRect = (
|
|
|
85
104
|
instance: Virtualizer<any, any>,
|
|
86
105
|
cb: (rect: Rect) => void,
|
|
87
106
|
) => {
|
|
88
|
-
const
|
|
89
|
-
|
|
107
|
+
const memoizedCallback = memoRectCallback(instance, cb)
|
|
108
|
+
const onResize = () =>
|
|
109
|
+
memoizedCallback({
|
|
90
110
|
width: instance.scrollElement.innerWidth,
|
|
91
111
|
height: instance.scrollElement.innerHeight,
|
|
92
112
|
})
|
|
93
|
-
}
|
|
94
113
|
|
|
95
114
|
if (!instance.scrollElement) {
|
|
96
115
|
return
|
|
@@ -108,60 +127,58 @@ export const observeWindowRect = (
|
|
|
108
127
|
}
|
|
109
128
|
}
|
|
110
129
|
|
|
111
|
-
|
|
112
|
-
instance: Virtualizer<any, any>,
|
|
113
|
-
cb: (offset: number) => void,
|
|
114
|
-
) => {
|
|
115
|
-
const onScroll = () =>
|
|
116
|
-
cb(
|
|
117
|
-
instance.scrollElement[
|
|
118
|
-
instance.options.horizontal ? 'scrollLeft' : 'scrollTop'
|
|
119
|
-
],
|
|
120
|
-
)
|
|
130
|
+
type ObserverMode = 'element' | 'window'
|
|
121
131
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
132
|
+
const scrollProps = {
|
|
133
|
+
element: ['scrollLeft', 'scrollTop'],
|
|
134
|
+
window: ['scrollX', 'scrollY'],
|
|
135
|
+
} as const
|
|
125
136
|
|
|
126
|
-
|
|
137
|
+
const createOffsetObserver = (mode: ObserverMode) => {
|
|
138
|
+
return (instance: Virtualizer<any, any>, cb: (offset: number) => void) => {
|
|
139
|
+
if (!instance.scrollElement) {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
127
142
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
passive: true,
|
|
131
|
-
})
|
|
143
|
+
const propX = scrollProps[mode][0]
|
|
144
|
+
const propY = scrollProps[mode][1]
|
|
132
145
|
|
|
133
|
-
|
|
134
|
-
instance.scrollElement
|
|
135
|
-
}
|
|
136
|
-
}
|
|
146
|
+
let prevX: number = instance.scrollElement[propX]
|
|
147
|
+
let prevY: number = instance.scrollElement[propY]
|
|
137
148
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
) => {
|
|
142
|
-
const onScroll = () =>
|
|
143
|
-
cb(
|
|
144
|
-
instance.scrollElement[
|
|
145
|
-
instance.options.horizontal ? 'scrollX' : 'scrollY'
|
|
146
|
-
],
|
|
147
|
-
)
|
|
149
|
+
const scroll = () => {
|
|
150
|
+
cb(instance.scrollElement[instance.options.horizontal ? propX : propY])
|
|
151
|
+
}
|
|
148
152
|
|
|
149
|
-
|
|
150
|
-
return
|
|
151
|
-
}
|
|
153
|
+
scroll()
|
|
152
154
|
|
|
153
|
-
|
|
155
|
+
const onScroll = (e: Event) => {
|
|
156
|
+
const target = e.currentTarget as HTMLElement & Window
|
|
157
|
+
const scrollX = target[propX]
|
|
158
|
+
const scrollY = target[propY]
|
|
154
159
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
})
|
|
160
|
+
if (instance.options.horizontal ? prevX - scrollX : prevY - scrollY) {
|
|
161
|
+
scroll()
|
|
162
|
+
}
|
|
159
163
|
|
|
160
|
-
|
|
161
|
-
|
|
164
|
+
prevX = scrollX
|
|
165
|
+
prevY = scrollY
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
instance.scrollElement.addEventListener('scroll', onScroll, {
|
|
169
|
+
capture: false,
|
|
170
|
+
passive: true,
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
return () => {
|
|
174
|
+
instance.scrollElement.removeEventListener('scroll', onScroll)
|
|
175
|
+
}
|
|
162
176
|
}
|
|
163
177
|
}
|
|
164
178
|
|
|
179
|
+
export const observeElementOffset = createOffsetObserver('element')
|
|
180
|
+
export const observeWindowOffset = createOffsetObserver('window')
|
|
181
|
+
|
|
165
182
|
export const measureElement = (
|
|
166
183
|
element: unknown,
|
|
167
184
|
instance: Virtualizer<any, any>,
|
|
@@ -248,6 +265,10 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
|
|
|
248
265
|
private scrollOffset: number
|
|
249
266
|
private destinationOffset: undefined | number
|
|
250
267
|
private scrollCheckFrame!: ReturnType<typeof setTimeout>
|
|
268
|
+
private measureElementCache: Record<
|
|
269
|
+
number,
|
|
270
|
+
(measurableItem: TItemElement | null) => void
|
|
271
|
+
> = {}
|
|
251
272
|
|
|
252
273
|
constructor(opts: VirtualizerOptions<TScrollElement, TItemElement>) {
|
|
253
274
|
this.setOptions(opts)
|
|
@@ -286,6 +307,7 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
|
|
|
286
307
|
private cleanup = () => {
|
|
287
308
|
this.unsubs.filter(Boolean).forEach((d) => d!())
|
|
288
309
|
this.unsubs = []
|
|
310
|
+
this.scrollElement = null
|
|
289
311
|
}
|
|
290
312
|
|
|
291
313
|
_didMount = () => {
|
|
@@ -402,48 +424,61 @@ export class Virtualizer<TScrollElement = unknown, TItemElement = unknown> {
|
|
|
402
424
|
this.options.measureElement,
|
|
403
425
|
],
|
|
404
426
|
(indexes, measurements, measureElement) => {
|
|
427
|
+
const makeMeasureElement =
|
|
428
|
+
(index: number) => (measurableItem: TItemElement | null) => {
|
|
429
|
+
const item = this.measurementsCache[index]!
|
|
430
|
+
|
|
431
|
+
if (!measurableItem) {
|
|
432
|
+
return
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
const measuredItemSize = measureElement(measurableItem, this)
|
|
436
|
+
const itemSize = this.itemMeasurementsCache[item.key] ?? item.size
|
|
437
|
+
|
|
438
|
+
if (measuredItemSize !== itemSize) {
|
|
439
|
+
if (item.start < this.scrollOffset) {
|
|
440
|
+
if (
|
|
441
|
+
process.env.NODE_ENV === 'development' &&
|
|
442
|
+
this.options.debug
|
|
443
|
+
) {
|
|
444
|
+
console.info('correction', measuredItemSize - itemSize)
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (!this.destinationOffset) {
|
|
448
|
+
this._scrollToOffset(
|
|
449
|
+
this.scrollOffset + (measuredItemSize - itemSize),
|
|
450
|
+
false,
|
|
451
|
+
)
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
this.pendingMeasuredCacheIndexes.push(index)
|
|
456
|
+
this.itemMeasurementsCache = {
|
|
457
|
+
...this.itemMeasurementsCache,
|
|
458
|
+
[item.key]: measuredItemSize,
|
|
459
|
+
}
|
|
460
|
+
this.notify()
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
405
464
|
const virtualItems: VirtualItem<TItemElement>[] = []
|
|
406
465
|
|
|
466
|
+
const currentMeasureElements: typeof this.measureElementCache = {}
|
|
467
|
+
|
|
407
468
|
for (let k = 0, len = indexes.length; k < len; k++) {
|
|
408
469
|
const i = indexes[k]!
|
|
409
470
|
const measurement = measurements[i]!
|
|
410
471
|
|
|
411
472
|
const item = {
|
|
412
473
|
...measurement,
|
|
413
|
-
measureElement: (
|
|
414
|
-
|
|
415
|
-
const measuredItemSize = measureElement(measurableItem, this)
|
|
416
|
-
|
|
417
|
-
if (measuredItemSize !== item.size) {
|
|
418
|
-
if (item.start < this.scrollOffset) {
|
|
419
|
-
if (
|
|
420
|
-
process.env.NODE_ENV === 'development' &&
|
|
421
|
-
this.options.debug
|
|
422
|
-
)
|
|
423
|
-
console.info('correction', measuredItemSize - item.size)
|
|
424
|
-
|
|
425
|
-
if (!this.destinationOffset) {
|
|
426
|
-
this._scrollToOffset(
|
|
427
|
-
this.scrollOffset + (measuredItemSize - item.size),
|
|
428
|
-
false,
|
|
429
|
-
)
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
this.pendingMeasuredCacheIndexes.push(i)
|
|
434
|
-
this.itemMeasurementsCache = {
|
|
435
|
-
...this.itemMeasurementsCache,
|
|
436
|
-
[item.key]: measuredItemSize,
|
|
437
|
-
}
|
|
438
|
-
this.notify()
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
},
|
|
474
|
+
measureElement: (currentMeasureElements[i] =
|
|
475
|
+
this.measureElementCache[i] ?? makeMeasureElement(i)),
|
|
442
476
|
}
|
|
443
|
-
|
|
444
477
|
virtualItems.push(item)
|
|
445
478
|
}
|
|
446
479
|
|
|
480
|
+
this.measureElementCache = currentMeasureElements
|
|
481
|
+
|
|
447
482
|
return virtualItems
|
|
448
483
|
},
|
|
449
484
|
{
|
package/build/types/utils.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export declare type NoInfer<A extends any> = [A][A extends any ? 0 : never];
|
|
2
|
-
export declare type PartialKeys<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
3
|
-
export declare function memo<TDeps extends readonly any[], TResult>(getDeps: () => [...TDeps], fn: (...args: NoInfer<[...TDeps]>) => TResult, opts: {
|
|
4
|
-
key: any;
|
|
5
|
-
debug?: () => any;
|
|
6
|
-
onChange?: (result: TResult) => void;
|
|
7
|
-
}): () => TResult;
|