feat(data-grid): improve transpose view record location and last-column alignment

This commit is contained in:
二丫讲梵 authored and GitHub committed 2026-08-09 14:14:08 +08:00
1 parent 72ff141f02
commit b1fcb23625
4 files changed
+198 -23

No files matched your search

@@ -7,6 +7,7 @@ import {
minTransposeFieldWidth,
shouldAutoTransposeSingleRow,
transposeAnchorRowIndex,
transposeEndAlignmentSpacerWidth,
transposeFieldWidth,
transposeScrollLeftForRecord,
transposeRecordWidthsForDensity,
@@ -107,6 +108,39 @@ describe("dataGridTranspose density widths", () => {
});
describe("transpose record scrolling", () => {
it("aligns the fifth record at the start while nearest keeps an already-visible record in place", () => {
const endSpacerWidth = transposeEndAlignmentSpacerWidth({
viewportWidth: 1200,
pinnedWidth: 104,
lastRecordWidth: 168,
});
expect(endSpacerWidth).toBe(928);
expect(
transposeScrollLeftForRecord({
recordIndex: 4,
totalRecords: 5,
viewportWidth: 1200,
pinnedWidth: 104,
recordWidth: 168,
currentScrollLeft: 0,
alignment: "start",
endSpacerWidth,
}),
).toBe(672);
expect(
transposeScrollLeftForRecord({
recordIndex: 4,
totalRecords: 5,
viewportWidth: 1200,
pinnedWidth: 104,
recordWidth: 168,
currentScrollLeft: 0,
endSpacerWidth,
}),
).toBe(0);
});
it("uses the scroll position after the sticky field for virtualization", () => {
expect(
visibleTransposeRecordWindow({
@@ -147,6 +181,42 @@ describe("transpose record scrolling", () => {
}),
).toBe(450);
});
it("uses the end spacer to align a variable-width final record exactly at the start", () => {
const recordOffsets = [0, 500, 596, 692];
const endSpacerWidth = transposeEndAlignmentSpacerWidth({
viewportWidth: 300,
pinnedWidth: 100,
lastRecordWidth: 96,
});
expect(endSpacerWidth).toBe(104);
expect(
transposeScrollLeftForRecord({
recordIndex: 2,
totalRecords: 3,
viewportWidth: 300,
pinnedWidth: 100,
recordWidth: 230,
recordOffsets,
currentScrollLeft: 0,
alignment: "start",
endSpacerWidth,
}),
).toBe(596);
expect(
transposeScrollLeftForRecord({
recordIndex: 2,
totalRecords: 3,
viewportWidth: 300,
pinnedWidth: 100,
recordWidth: 230,
recordOffsets,
currentScrollLeft: 596,
endSpacerWidth,
}),
).toBe(596);
});
});
describe("dataGridTranspose field metadata", () => {
@@ -166,6 +166,16 @@ export interface TransposeScrollLeftOptions {
recordWidth: number;
recordOffsets?: readonly number[];
currentScrollLeft?: number;
alignment?: TransposeScrollAlignment;
endSpacerWidth?: number;
}
export type TransposeScrollAlignment = "start" | "nearest";
export interface TransposeEndAlignmentSpacerOptions {
viewportWidth: number;
pinnedWidth: number;
lastRecordWidth: number;
}
export interface TransposeRecordIndexesForModeOptions {
@@ -339,6 +349,11 @@ export function transposeFieldWidth(columns: string[], options: TransposeFieldWi
return Math.min(maxWidth, Math.max(minWidth, Math.ceil(longest * charWidth + padding)));
}
export function transposeEndAlignmentSpacerWidth(options: TransposeEndAlignmentSpacerOptions): number {
const recordViewportWidth = Math.max(0, options.viewportWidth - options.pinnedWidth);
return Math.max(0, recordViewportWidth - Math.max(0, options.lastRecordWidth));
}
export function transposeScrollLeftForRecord(options: TransposeScrollLeftOptions): number {
if (options.recordWidth <= 0 || options.totalRecords <= 0) return 0;
const recordIndex = Math.max(0, Math.min(options.totalRecords - 1, options.recordIndex));
@@ -348,8 +363,8 @@ export function transposeScrollLeftForRecord(options: TransposeScrollLeftOptions
const recordsWidth = offsets ? offsets[options.totalRecords] : options.totalRecords * options.recordWidth;
const recordViewportWidth = Math.max(0, options.viewportWidth - options.pinnedWidth);
const currentScrollLeft = Math.max(0, options.currentScrollLeft ?? recordStart);
const desired = recordStart < currentScrollLeft ? recordStart : recordEnd > currentScrollLeft + recordViewportWidth ? recordEnd - recordViewportWidth : currentScrollLeft;
const totalWidth = options.pinnedWidth + recordsWidth;
const desired = options.alignment === "start" ? recordStart : recordStart < currentScrollLeft ? recordStart : recordEnd > currentScrollLeft + recordViewportWidth ? recordEnd - recordViewportWidth : currentScrollLeft;
const totalWidth = options.pinnedWidth + recordsWidth + Math.max(0, options.endSpacerWidth ?? 0);
const maxScrollLeft = Math.max(0, totalWidth - options.viewportWidth);
return Math.max(0, Math.min(desired, maxScrollLeft));
}