fix(grid): keep new top row visible after a toolbar refresh

This commit is contained in:
Melody Ruch
2026-09-07 21:25:51 +08:00
committed by GitHub
parent fcc7dfb896
commit e3b9bae67e
2 changed files with 28 additions and 0 deletions
@@ -5997,6 +5997,11 @@ function captureViewportAnchorForRefresh(): { row?: PersistedDataGridSelection;
if (showTranspose.value || displayItems.value.length === 0) return null;
const scroller = useCanvasGridRows.value ? canvasScrollerElement() : gridScrollerElement();
if (!scroller) return null;
// Already viewing the top of the grid: don't anchor to the row currently
// there. Anchoring would re-pin that row to the same on-screen offset even
// after a refresh prepends new rows above it (e.g. newly inserted rows
// under a DESC sort), pushing the new rows above the visible area (#8339).
if (scroller.scrollTop <= 0) return null;
const rowHeight = useCanvasGridRows.value ? CANVAS_DATA_GRID_ROW_HEIGHT : DOM_DATA_GRID_ROW_HEIGHT;
const fallbackDisplayIndex = Math.max(0, Math.min(displayItems.value.length - 1, Math.floor(scroller.scrollTop / rowHeight)));
const item = displayItems.value[fallbackDisplayIndex];
@@ -11,6 +11,14 @@ function resultWatchSource(): string {
return dataGridSource.slice(start, end);
}
function captureViewportAnchorForRefreshSource(): string {
const start = dataGridSource.indexOf("function captureViewportAnchorForRefresh()");
const end = dataGridSource.indexOf("function restoreViewportAnchorAfterRefresh(");
expect(start).toBeGreaterThanOrEqual(0);
expect(end).toBeGreaterThan(start);
return dataGridSource.slice(start, end);
}
describe("DataGrid result-replacement vertical scroll", () => {
it("resets to the first row when the result is replaced without an internal grid action", () => {
const watchSource = resultWatchSource();
@@ -53,4 +61,19 @@ describe("DataGrid result-replacement vertical scroll", () => {
expect(appendEarlyReturn).toBeGreaterThan(appendReturn);
expect(resetBranch).toBeGreaterThan(appendEarlyReturn);
});
it("does not anchor a toolbar refresh to the current top row when already scrolled to the top (#8339)", () => {
// Anchoring the row that happens to be at scrollTop 0 would re-pin it to the
// same on-screen offset after refresh, which pushes newly inserted rows
// (e.g. rows prepended by an external insert under a DESC sort) above the
// visible viewport instead of showing them. Skipping the anchor when already
// at the top lets the toolbar-refresh path land on the freshest first row.
const anchorSource = captureViewportAnchorForRefreshSource();
expect(anchorSource).toContain("#8339");
const guard = anchorSource.indexOf("if (scroller.scrollTop <= 0) return null;");
const rowHeightUse = anchorSource.indexOf("const rowHeight =");
expect(guard).toBeGreaterThanOrEqual(0);
expect(rowHeightUse).toBeGreaterThan(guard);
});
});