Skip to content

Commit 54c213a

Browse files
Optimize grid template rows generation with CSS repeat() function (Comcast#3865)
* Optimize grid template rows generation with CSS repeat() function * Add comprehensive tests for grid template rows optimization * Add edge case tests for unique first and last row heights * Remove redundant trim() and added some comments * refactor: use map instead of forEach for row positions --------- Co-authored-by: Aman Mahajan <amahajan@stratag.com>
1 parent 04bc7f7 commit 54c213a

2 files changed

Lines changed: 90 additions & 5 deletions

File tree

src/hooks/useViewportRows.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,48 @@ export function useViewportRows<R>({
2828
};
2929
}
3030

31-
let totalRowHeight = 0;
32-
let gridTemplateRows = ' ';
3331
// Calcule the height of all the rows upfront. This can cause performance issues
3432
// and we can consider using a similar approach as react-window
3533
// https://github.com/bvaughn/react-window/blob/b0a470cc264e9100afcaa1b78ed59d88f7914ad4/src/VariableSizeList.js#L68
36-
const rowPositions = rows.map((row) => {
34+
let totalRowHeight = 0;
35+
let gridTemplateRows = '';
36+
let currentHeight: number | null = null;
37+
let repeatCount = 0;
38+
39+
const rowPositions = rows.map((row, index) => {
3740
const currentRowHeight = rowHeight(row);
38-
const position = { top: totalRowHeight, height: currentRowHeight };
39-
gridTemplateRows += `${currentRowHeight}px `;
41+
42+
const position = {
43+
top: totalRowHeight,
44+
height: currentRowHeight
45+
};
4046
totalRowHeight += currentRowHeight;
47+
48+
if (currentHeight === null) {
49+
currentHeight = currentRowHeight;
50+
repeatCount = 1;
51+
} else if (currentHeight === currentRowHeight) {
52+
// If the current row height is the same as the previous one, increment the repeat count
53+
repeatCount++;
54+
} else {
55+
if (repeatCount > 1) {
56+
gridTemplateRows += `repeat(${repeatCount}, ${currentHeight}px) `;
57+
} else {
58+
gridTemplateRows += `${currentHeight}px `;
59+
}
60+
61+
currentHeight = currentRowHeight;
62+
repeatCount = 1;
63+
}
64+
65+
if (index === rows.length - 1) {
66+
if (repeatCount > 1) {
67+
gridTemplateRows += `repeat(${repeatCount}, ${currentHeight}px)`;
68+
} else {
69+
gridTemplateRows += `${currentHeight}px`;
70+
}
71+
}
72+
4173
return position;
4274
});
4375

test/browser/rowHeight.test.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ function setupGrid(rowHeight: DataGridProps<Row>['rowHeight']) {
2020
setup({ columns, rows, rowHeight });
2121
}
2222

23+
function expectGridRows(rowHeightFn: (row: number) => number, expected: string) {
24+
setupGrid(rowHeightFn);
25+
26+
const grid = page.getByRole('grid').element() as HTMLDivElement;
27+
const gridTemplateRows = grid.style.gridTemplateRows;
28+
29+
expect(gridTemplateRows).toBe(expected);
30+
}
31+
2332
test('rowHeight is number', async () => {
2433
setupGrid(40);
2534

@@ -51,3 +60,47 @@ test('rowHeight is function', async () => {
5160
await userEvent.keyboard('{Control>}{end}');
5261
expect(grid.scrollTop + grid.clientHeight).toBe(grid.scrollHeight);
5362
});
63+
64+
test('rowHeight with repeat pattern - multiple identical heights', () => {
65+
expectGridRows(() => 40, 'repeat(1, 35px) repeat(50, 40px)');
66+
});
67+
68+
test('rowHeight with mixed heights - one unique in middle', () => {
69+
expectGridRows(
70+
(row) => (row === 25 ? 40 : 50),
71+
'repeat(1, 35px) repeat(25, 50px) 40px repeat(24, 50px)'
72+
);
73+
});
74+
75+
test('rowHeight with unique heights', () => {
76+
expectGridRows(
77+
(row) => row + 1,
78+
'repeat(1, 35px) 1px 2px 3px 4px 5px 6px 7px 8px 9px 10px 11px 12px 13px 14px 15px 16px 17px 18px 19px 20px 21px 22px 23px 24px 25px 26px 27px 28px 29px 30px 31px 32px 33px 34px 35px 36px 37px 38px 39px 40px 41px 42px 43px 44px 45px 46px 47px 48px 49px 50px'
79+
);
80+
});
81+
82+
test('rowHeight with unique first and unique last heights', () => {
83+
expectGridRows((row) => {
84+
if (row === 0) {
85+
return 10;
86+
}
87+
88+
if (row === 49) {
89+
return 20;
90+
}
91+
92+
return 50;
93+
}, 'repeat(1, 35px) 10px repeat(48, 50px) 20px');
94+
});
95+
96+
test('rowHeight with unique last height', () => {
97+
expectGridRows((row) => {
98+
return row === 49 ? 50 : 20;
99+
}, 'repeat(1, 35px) repeat(49, 20px) 50px');
100+
});
101+
102+
test('rowHeight with unique first height', () => {
103+
expectGridRows((row) => {
104+
return row === 0 ? 45 : 50;
105+
}, 'repeat(1, 35px) 45px repeat(49, 50px)');
106+
});

0 commit comments

Comments
 (0)