fix(grid): restore column jump in transposed table view

This commit is contained in:
zipg
2026-09-15 17:52:53 +08:00
committed by GitHub
parent 5a0e74eec6
commit b06e952ba0
2 changed files with 32 additions and 17 deletions
+20 -17
View File
@@ -2176,8 +2176,13 @@ function scrollToColumnIndex(columnIndex: number) {
nextTick(() => {
const visibleColIdx = visibleColumnIndexes.value.indexOf(columnIndex);
if (visibleColIdx < 0) return;
if (isTransposeMode.value) {
scrollTransposeFieldIntoView(visibleColIdx);
return;
}
const scroller = gridRef.value?.querySelector<HTMLElement>(".data-grid-scroller");
if (visibleColIdx < 0 || !scroller) return;
if (!scroller) return;
const targetLeft = Math.max(0, columnContentOffsetLeft(visibleColIdx) - scroller.clientWidth / 2 + (renderedColumnWidths.value[visibleColIdx] ?? 0) / 2);
scroller.scrollLeft = targetLeft;
@@ -4647,21 +4652,23 @@ function scrollToCurrentMatch() {
if (rowEl) rowEl.scrollIntoView({ block: "center" });
}
// In transpose view records are columns (horizontal) and fields are rows
// (vertical). Bring the matched record column into the horizontal viewport and
// the matched field row into the vertical viewport.
function scrollTransposeFieldIntoView(visibleFieldIndex: number) {
const scroller = transposeScrollRef.value;
if (scroller && !(scroller instanceof HTMLElement)) {
(scroller as { scrollToItem?: (index: number) => void }).scrollToItem?.(visibleFieldIndex);
} else if (scroller instanceof HTMLElement) {
scroller.scrollTop = visibleFieldIndex * transposeRowHeight.value;
}
}
// Transpose fields are vertical rows, while records are horizontal columns.
function scrollTransposeMatchIntoView(match: DataGridSearchMatch) {
nextTick(() => {
const scroller = transposeScrollRef.value;
// Both match kinds use `col` as the field (transpose row) index: cell
// matches store the field/value index, column-name matches store the field.
const fieldIndex = match.col;
if (scroller && !(scroller instanceof HTMLElement)) {
// RecycleScroller component instance exposes scrollToItem via vue-virtual-scroller.
(scroller as { scrollToItem?: (index: number) => void }).scrollToItem?.(fieldIndex);
} else if (scroller instanceof HTMLElement) {
scroller.scrollTop = fieldIndex * 30;
}
const visibleFieldIndex = visibleColumnIndexes.value.indexOf(fieldIndex);
if (visibleFieldIndex >= 0) scrollTransposeFieldIntoView(visibleFieldIndex);
if (match.kind === "cell") {
scrollTransposeRecordIntoView(match.displayRow);
}
@@ -8430,12 +8437,7 @@ const DOM_DATA_GRID_ROW_HEIGHT = 26;
function scrollCellIntoView(rowIndex: number, colIndex: number, block: DataGridScrollAlignment = "nearest", previousPageRowIndex?: number) {
if (isTransposeMode.value) {
nextTick(() => {
const scroller = transposeScrollRef.value;
if (scroller && !(scroller instanceof HTMLElement)) {
(scroller as { scrollToItem?: (index: number) => void }).scrollToItem?.(colIndex);
} else if (scroller instanceof HTMLElement) {
scroller.scrollTop = colIndex * 30;
}
scrollTransposeFieldIntoView(colIndex);
scrollTransposeRecordIntoView(rowIndex);
});
return;
@@ -11917,6 +11919,7 @@ useUpdateBlocker(() => (hasPendingChanges.value || hasPendingDataEditorDraft.val
data-native-clipboard
class="sticky left-0 z-10 flex shrink-0 flex-col items-start justify-center overflow-hidden border-r border-border bg-background px-3 py-0"
:class="{
'ring-2 ring-inset ring-primary': highlightedColumnIndex === visibleColumnIndexes[index],
'bg-yellow-200/60 dark:bg-yellow-500/20': transposeHeaderIsSearchMatch(visibleColumnIndexes[index]),
'ring-2 ring-inset ring-yellow-500 bg-yellow-300/60 dark:bg-yellow-500/40': transposeHeaderIsCurrentMatch(visibleColumnIndexes[index]),
}"
+12
View File
@@ -164,3 +164,15 @@ test("error result recovery participates in canvas observer remounts", () => {
const source = readFileSync("apps/desktop/src/components/grid/DataGrid.vue", "utf8");
assert.match(source, /watch\(\s*\[useCanvasGridRows, hasVisibleRows, isErrorResult\]/);
});
test("column navigation scrolls visible transpose fields before looking for the normal grid", () => {
const source = readFileSync("apps/desktop/src/components/grid/DataGrid.vue", "utf8");
const navigation = source.slice(source.indexOf("function scrollToColumnIndex("), source.indexOf("// --- Column resize composable ---"));
assert.match(navigation, /showColumn\(columnIndex\)/);
assert.match(navigation, /visibleColumnIndexes\.value\.indexOf\(columnIndex\)/);
assert.match(navigation, /if \(isTransposeMode\.value\) \{\s*scrollTransposeFieldIntoView\(visibleColIdx\);\s*return;/);
assert.ok(navigation.indexOf("scrollTransposeFieldIntoView") < navigation.indexOf('".data-grid-scroller"'));
assert.match(source, /scrollToItem\?\.\(visibleFieldIndex\)/);
assert.match(source, /scroller\.scrollTop = visibleFieldIndex \* transposeRowHeight\.value/);
assert.match(source, /'ring-2 ring-inset ring-primary': highlightedColumnIndex === visibleColumnIndexes\[index\]/);
});