This commit is contained in:
2025-07-26 21:54:04 +03:30
parent f720424180
commit 615dc6a033
682 changed files with 6709 additions and 15232 deletions
+33 -38
View File
@@ -183,6 +183,7 @@ class Virtualizer {
this.scrollElement = null;
this.targetWindow = null;
this.isScrolling = false;
this.scrollToIndexTimeoutId = null;
this.measurementsCache = [];
this.itemSizeCache = /* @__PURE__ */ new Map();
this.pendingMeasuredCacheIndexes = [];
@@ -598,7 +599,7 @@ class Virtualizer {
} else if (align === "end") {
toOffset -= size;
}
const maxOffset = this.getTotalSize() + this.options.scrollMargin - size;
const maxOffset = this.getTotalSize() - size;
return Math.max(Math.min(maxOffset, toOffset), 0);
};
this.getOffsetForIndex = (index, align = "auto") => {
@@ -625,7 +626,14 @@ class Virtualizer {
];
};
this.isDynamicMode = () => this.elementsCache.size > 0;
this.cancelScrollToIndex = () => {
if (this.scrollToIndexTimeoutId !== null && this.targetWindow) {
this.targetWindow.clearTimeout(this.scrollToIndexTimeoutId);
this.scrollToIndexTimeoutId = null;
}
};
this.scrollToOffset = (toOffset, { align = "start", behavior } = {}) => {
this.cancelScrollToIndex();
if (behavior === "smooth" && this.isDynamicMode()) {
console.warn(
"The `smooth` scroll behavior is not fully supported with dynamic size."
@@ -637,52 +645,39 @@ class Virtualizer {
});
};
this.scrollToIndex = (index, { align: initialAlign = "auto", behavior } = {}) => {
index = Math.max(0, Math.min(index, this.options.count - 1));
this.cancelScrollToIndex();
if (behavior === "smooth" && this.isDynamicMode()) {
console.warn(
"The `smooth` scroll behavior is not fully supported with dynamic size."
);
}
index = Math.max(0, Math.min(index, this.options.count - 1));
let attempts = 0;
const maxAttempts = 10;
const tryScroll = (currentAlign) => {
if (!this.targetWindow) return;
const offsetInfo = this.getOffsetForIndex(index, currentAlign);
if (!offsetInfo) {
console.warn("Failed to get offset for index:", index);
return;
}
const [offset, align] = offsetInfo;
this._scrollToOffset(offset, { adjustments: void 0, behavior });
this.targetWindow.requestAnimationFrame(() => {
const currentOffset = this.getScrollOffset();
const afterInfo = this.getOffsetForIndex(index, align);
if (!afterInfo) {
console.warn("Failed to get offset for index:", index);
return;
}
if (!approxEqual(afterInfo[0], currentOffset)) {
scheduleRetry(align);
const offsetAndAlign = this.getOffsetForIndex(index, initialAlign);
if (!offsetAndAlign) return;
const [offset, align] = offsetAndAlign;
this._scrollToOffset(offset, { adjustments: void 0, behavior });
if (behavior !== "smooth" && this.isDynamicMode() && this.targetWindow) {
this.scrollToIndexTimeoutId = this.targetWindow.setTimeout(() => {
this.scrollToIndexTimeoutId = null;
const elementInDOM = this.elementsCache.has(
this.options.getItemKey(index)
);
if (elementInDOM) {
const result = this.getOffsetForIndex(index, align);
if (!result) return;
const [latestOffset] = result;
const currentScrollOffset = this.getScrollOffset();
if (!approxEqual(latestOffset, currentScrollOffset)) {
this.scrollToIndex(index, { align, behavior });
}
} else {
this.scrollToIndex(index, { align, behavior });
}
});
};
const scheduleRetry = (align) => {
if (!this.targetWindow) return;
attempts++;
if (attempts < maxAttempts) {
if (process.env.NODE_ENV !== "production" && this.options.debug) {
console.info("Schedule retry", attempts, maxAttempts);
}
this.targetWindow.requestAnimationFrame(() => tryScroll(align));
} else {
console.warn(
`Failed to scroll to index ${index} after ${maxAttempts} attempts.`
);
}
};
tryScroll(initialAlign);
}
};
this.scrollBy = (delta, { behavior } = {}) => {
this.cancelScrollToIndex();
if (behavior === "smooth" && this.isDynamicMode()) {
console.warn(
"The `smooth` scroll behavior is not fully supported with dynamic size."
+1 -1
View File
@@ -52,7 +52,7 @@ function notUndefined(value, msg) {
return value;
}
}
const approxEqual = (a, b) => Math.abs(a - b) < 1.01;
const approxEqual = (a, b) => Math.abs(a - b) <= 1;
const debounce = (targetWindow, fn, ms) => {
let timeoutId;
return function(...args) {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@tanstack/virtual-core",
"version": "3.13.12",
"version": "3.13.9",
"description": "Headless UI for virtualizing scrollable elements in TS/JS + Frameworks",
"author": "Tanner Linsley",
"license": "MIT",
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@tanstack/vue-virtual",
"version": "3.13.12",
"version": "3.13.9",
"description": "Headless UI for virtualizing scrollable elements in Vue",
"author": "Tanner Linsley",
"license": "MIT",
@@ -49,11 +49,11 @@
"src"
],
"dependencies": {
"@tanstack/virtual-core": "3.13.12"
"@tanstack/virtual-core": "3.13.9"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.2.4",
"vue": "^3.5.16"
"vue": "^3.5.14"
},
"peerDependencies": {
"vue": "^2.7.0 || ^3.0.0"