@tanstack/virtual-core
Advanced tools
Comparing version 3.6.0 to 3.7.0
@@ -18,3 +18,3 @@ export * from './utils.js'; | ||
type Key = number | string; | ||
export interface VirtualItem { | ||
export interface VirtualItem<TItemElement extends Element> { | ||
key: Key; | ||
@@ -26,2 +26,3 @@ index: number; | ||
lane: number; | ||
measureElement: (node: TItemElement | null | undefined) => void; | ||
} | ||
@@ -73,3 +74,3 @@ export interface Rect { | ||
indexAttribute?: string; | ||
initialMeasurementsCache?: VirtualItem[]; | ||
initialMeasurementsCache?: VirtualItem<TItemElement>[]; | ||
lanes?: number; | ||
@@ -86,3 +87,3 @@ isScrollingResetDelay?: number; | ||
private scrollToIndexTimeoutId; | ||
measurementsCache: VirtualItem[]; | ||
measurementsCache: VirtualItem<TItemElement>[]; | ||
private itemSizeCache; | ||
@@ -94,4 +95,4 @@ private pendingMeasuredCacheIndexes; | ||
private scrollAdjustments; | ||
shouldAdjustScrollPositionOnItemSizeChange: undefined | ((item: VirtualItem, delta: number, instance: Virtualizer<TScrollElement, TItemElement>) => boolean); | ||
measureElementCache: Map<Key, TItemElement>; | ||
shouldAdjustScrollPositionOnItemSizeChange: undefined | ((item: VirtualItem<TItemElement>, delta: number, instance: Virtualizer<TScrollElement, TItemElement>) => boolean); | ||
elementsCache: Map<Key, TItemElement>; | ||
private observer; | ||
@@ -120,6 +121,6 @@ range: { | ||
private _measureElement; | ||
resizeItem: (item: VirtualItem, size: number) => void; | ||
measureElement: (node: TItemElement | null) => void; | ||
getVirtualItems: () => VirtualItem[]; | ||
getVirtualItemForOffset: (offset: number) => VirtualItem | undefined; | ||
resizeItem: (index: number, size: number) => void; | ||
measureElement: (node: TItemElement | null | undefined) => void; | ||
getVirtualItems: () => VirtualItem<TItemElement>[]; | ||
getVirtualItemForOffset: (offset: number) => VirtualItem<TItemElement> | undefined; | ||
getOffsetForAlignment: (toOffset: number, align: ScrollAlignment) => number; | ||
@@ -126,0 +127,0 @@ getOffsetForIndex: (index: number, align?: ScrollAlignment) => readonly [number, "auto"] | readonly [number, "start" | "center" | "end"] | undefined; |
@@ -178,3 +178,3 @@ import { debounce, memo, notUndefined, approxEqual } from "./utils.js"; | ||
this.scrollAdjustments = 0; | ||
this.measureElementCache = /* @__PURE__ */ new Map(); | ||
this.elementsCache = /* @__PURE__ */ new Map(); | ||
this.observer = /* @__PURE__ */ (() => { | ||
@@ -258,3 +258,3 @@ let _ro = null; | ||
this.observer.disconnect(); | ||
this.measureElementCache.clear(); | ||
this.elementsCache.clear(); | ||
}; | ||
@@ -371,2 +371,3 @@ this._didMount = () => { | ||
({ count, paddingStart, scrollMargin, getItemKey, enabled }, itemSizeCache) => { | ||
var _a; | ||
if (!enabled) { | ||
@@ -387,2 +388,29 @@ this.measurementsCache = []; | ||
for (let i = min; i < count; i++) { | ||
let measureElement2 = (_a = this.measurementsCache[i]) == null ? void 0 : _a.measureElement; | ||
if (!measureElement2) { | ||
measureElement2 = (node) => { | ||
const key2 = getItemKey(i); | ||
const prevNode = this.elementsCache.get(key2); | ||
if (!node) { | ||
if (prevNode) { | ||
this.observer.unobserve(prevNode); | ||
this.elementsCache.delete(key2); | ||
} | ||
return; | ||
} | ||
if (prevNode !== node) { | ||
if (prevNode) { | ||
this.observer.unobserve(prevNode); | ||
} | ||
this.observer.observe(node); | ||
this.elementsCache.set(key2, node); | ||
} | ||
if (node.isConnected) { | ||
this.resizeItem( | ||
i, | ||
this.options.measureElement(node, void 0, this) | ||
); | ||
} | ||
}; | ||
} | ||
const key = getItemKey(i); | ||
@@ -401,3 +429,4 @@ const furthestMeasurement = this.options.lanes === 1 ? measurements[i - 1] : this.getFurthestMeasurement(measurements, i); | ||
key, | ||
lane | ||
lane, | ||
measureElement: measureElement2 | ||
}; | ||
@@ -459,8 +488,9 @@ } | ||
this._measureElement = (node, entry) => { | ||
const item = this.getMeasurements()[this.indexFromElement(node)]; | ||
const i = this.indexFromElement(node); | ||
const item = this.getMeasurements()[i]; | ||
if (!item || !node.isConnected) { | ||
this.measureElementCache.forEach((cached, key) => { | ||
this.elementsCache.forEach((cached, key) => { | ||
if (cached === node) { | ||
this.observer.unobserve(node); | ||
this.measureElementCache.delete(key); | ||
this.elementsCache.delete(key); | ||
} | ||
@@ -470,3 +500,3 @@ }); | ||
} | ||
const prevNode = this.measureElementCache.get(item.key); | ||
const prevNode = this.elementsCache.get(item.key); | ||
if (prevNode !== node) { | ||
@@ -477,8 +507,11 @@ if (prevNode) { | ||
this.observer.observe(node); | ||
this.measureElementCache.set(item.key, node); | ||
this.elementsCache.set(item.key, node); | ||
} | ||
const measuredItemSize = this.options.measureElement(node, entry, this); | ||
this.resizeItem(item, measuredItemSize); | ||
this.resizeItem(i, this.options.measureElement(node, entry, this)); | ||
}; | ||
this.resizeItem = (item, size) => { | ||
this.resizeItem = (index, size) => { | ||
const item = this.getMeasurements()[index]; | ||
if (!item) { | ||
return; | ||
} | ||
const itemSize = this.itemSizeCache.get(item.key) ?? item.size; | ||
@@ -581,3 +614,3 @@ const delta = size - itemSize; | ||
}; | ||
this.isDynamicMode = () => this.measureElementCache.size > 0; | ||
this.isDynamicMode = () => this.elementsCache.size > 0; | ||
this.cancelScrollToIndex = () => { | ||
@@ -617,3 +650,3 @@ if (this.scrollToIndexTimeoutId !== null && this.targetWindow) { | ||
this.scrollToIndexTimeoutId = null; | ||
const elementInDOM = this.measureElementCache.has( | ||
const elementInDOM = this.elementsCache.has( | ||
this.options.getItemKey(index) | ||
@@ -620,0 +653,0 @@ ); |
{ | ||
"name": "@tanstack/virtual-core", | ||
"version": "3.6.0", | ||
"version": "3.7.0", | ||
"description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks", | ||
@@ -5,0 +5,0 @@ "author": "Tanner Linsley", |
@@ -31,3 +31,3 @@ import { approxEqual, memo, notUndefined, debounce } from './utils' | ||
export interface VirtualItem { | ||
export interface VirtualItem<TItemElement extends Element> { | ||
key: Key | ||
@@ -39,2 +39,3 @@ index: number | ||
lane: number | ||
measureElement: (node: TItemElement | null | undefined) => void | ||
} | ||
@@ -320,3 +321,3 @@ | ||
indexAttribute?: string | ||
initialMeasurementsCache?: VirtualItem[] | ||
initialMeasurementsCache?: VirtualItem<TItemElement>[] | ||
lanes?: number | ||
@@ -337,3 +338,3 @@ isScrollingResetDelay?: number | ||
private scrollToIndexTimeoutId: number | null = null | ||
measurementsCache: VirtualItem[] = [] | ||
measurementsCache: VirtualItem<TItemElement>[] = [] | ||
private itemSizeCache = new Map<Key, number>() | ||
@@ -348,7 +349,7 @@ private pendingMeasuredCacheIndexes: number[] = [] | ||
| (( | ||
item: VirtualItem, | ||
item: VirtualItem<TItemElement>, | ||
delta: number, | ||
instance: Virtualizer<TScrollElement, TItemElement>, | ||
) => boolean) | ||
measureElementCache = new Map<Key, TItemElement>() | ||
elementsCache = new Map<Key, TItemElement>() | ||
private observer = (() => { | ||
@@ -438,3 +439,3 @@ let _ro: ResizeObserver | null = null | ||
this.observer.disconnect() | ||
this.measureElementCache.clear() | ||
this.elementsCache.clear() | ||
} | ||
@@ -527,7 +528,7 @@ | ||
private getFurthestMeasurement = ( | ||
measurements: VirtualItem[], | ||
measurements: VirtualItem<TItemElement>[], | ||
index: number, | ||
) => { | ||
const furthestMeasurementsFound = new Map<number, true>() | ||
const furthestMeasurements = new Map<number, VirtualItem>() | ||
const furthestMeasurements = new Map<number, VirtualItem<TItemElement>>() | ||
for (let m = index - 1; m >= 0; m--) { | ||
@@ -619,2 +620,34 @@ const measurement = measurements[m]! | ||
for (let i = min; i < count; i++) { | ||
let measureElement = this.measurementsCache[i]?.measureElement | ||
if (!measureElement) { | ||
measureElement = (node: TItemElement | null | undefined) => { | ||
const key = getItemKey(i) | ||
const prevNode = this.elementsCache.get(key) | ||
if (!node) { | ||
if (prevNode) { | ||
this.observer.unobserve(prevNode) | ||
this.elementsCache.delete(key) | ||
} | ||
return | ||
} | ||
if (prevNode !== node) { | ||
if (prevNode) { | ||
this.observer.unobserve(prevNode) | ||
} | ||
this.observer.observe(node) | ||
this.elementsCache.set(key, node) | ||
} | ||
if (node.isConnected) { | ||
this.resizeItem( | ||
i, | ||
this.options.measureElement(node, undefined, this), | ||
) | ||
} | ||
} | ||
} | ||
const key = getItemKey(i) | ||
@@ -650,2 +683,3 @@ | ||
lane, | ||
measureElement, | ||
} | ||
@@ -723,9 +757,10 @@ } | ||
) => { | ||
const item = this.getMeasurements()[this.indexFromElement(node)] | ||
const i = this.indexFromElement(node) | ||
const item = this.getMeasurements()[i] | ||
if (!item || !node.isConnected) { | ||
this.measureElementCache.forEach((cached, key) => { | ||
this.elementsCache.forEach((cached, key) => { | ||
if (cached === node) { | ||
this.observer.unobserve(node) | ||
this.measureElementCache.delete(key) | ||
this.elementsCache.delete(key) | ||
} | ||
@@ -736,3 +771,3 @@ }) | ||
const prevNode = this.measureElementCache.get(item.key) | ||
const prevNode = this.elementsCache.get(item.key) | ||
@@ -744,11 +779,13 @@ if (prevNode !== node) { | ||
this.observer.observe(node) | ||
this.measureElementCache.set(item.key, node) | ||
this.elementsCache.set(item.key, node) | ||
} | ||
const measuredItemSize = this.options.measureElement(node, entry, this) | ||
this.resizeItem(item, measuredItemSize) | ||
this.resizeItem(i, this.options.measureElement(node, entry, this)) | ||
} | ||
resizeItem = (item: VirtualItem, size: number) => { | ||
resizeItem = (index: number, size: number) => { | ||
const item = this.getMeasurements()[index] | ||
if (!item) { | ||
return | ||
} | ||
const itemSize = this.itemSizeCache.get(item.key) ?? item.size | ||
@@ -780,3 +817,3 @@ const delta = size - itemSize | ||
measureElement = (node: TItemElement | null) => { | ||
measureElement = (node: TItemElement | null | undefined) => { | ||
if (!node) { | ||
@@ -792,3 +829,3 @@ return | ||
(indexes, measurements) => { | ||
const virtualItems: VirtualItem[] = [] | ||
const virtualItems: VirtualItem<TItemElement>[] = [] | ||
@@ -892,3 +929,3 @@ for (let k = 0, len = indexes.length; k < len; k++) { | ||
private isDynamicMode = () => this.measureElementCache.size > 0 | ||
private isDynamicMode = () => this.elementsCache.size > 0 | ||
@@ -945,3 +982,3 @@ private cancelScrollToIndex = () => { | ||
const elementInDOM = this.measureElementCache.has( | ||
const elementInDOM = this.elementsCache.has( | ||
this.options.getItemKey(index), | ||
@@ -1045,3 +1082,3 @@ ) | ||
function calculateRange({ | ||
function calculateRange<TItemElement extends Element>({ | ||
measurements, | ||
@@ -1051,3 +1088,3 @@ outerSize, | ||
}: { | ||
measurements: VirtualItem[] | ||
measurements: VirtualItem<TItemElement>[] | ||
outerSize: number | ||
@@ -1054,0 +1091,0 @@ scrollOffset: number |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
198500
2760