Skip to content

Commit 2b338b0

Browse files
committed
use clamp and max css functions
1 parent 2650ccb commit 2b338b0

6 files changed

Lines changed: 34 additions & 45 deletions

File tree

src/hooks/useCalculatedColumns.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useMemo } from 'react';
22

3-
import { clampColumnWidth, max, min } from '../utils';
3+
import { max, min } from '../utils';
44
import type { CalculatedColumn, CalculatedColumnParent, ColumnOrColumnGroup, Omit } from '../types';
55
import { renderValue } from '../cellRenderers';
66
import { SELECT_COLUMN_KEY } from '../Columns';
@@ -177,10 +177,7 @@ export function useCalculatedColumns<R, SR>({
177177
for (const column of columns) {
178178
let width = getColumnWidth(column);
179179

180-
if (typeof width === 'number') {
181-
// if width is a number then we do not measure it so it needs to be clamped manually
182-
width = clampColumnWidth(width, column);
183-
} else {
180+
if (typeof width === 'string') {
184181
// This is a placeholder width so we can continue to use virtualization.
185182
// The actual value is set after the column is rendered
186183
width = column.minWidth;

src/hooks/useColumnWidths.ts

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useLayoutEffect, useState } from 'react';
22

3-
import { clampColumnWidth, getColumnWidthForMeasurement } from '../utils';
3+
import { getColumnWidthForMeasurement } from '../utils';
44
import type { CalculatedColumn, StateSetter } from '../types';
55
import type { DataGridProps } from '../DataGrid';
66

@@ -16,7 +16,10 @@ export function useColumnWidths<R, SR>(
1616
setMeasuredColumnWidths: StateSetter<ReadonlyMap<string, number>>,
1717
onColumnResize: DataGridProps<R, SR>['onColumnResize']
1818
) {
19-
const [columnToAutoResize, setColumnToAutoResize] = useState<string | null>(null);
19+
const [columnToAutoResize, setColumnToAutoResize] = useState<{
20+
readonly key: string;
21+
readonly width: number | 'max-content';
22+
} | null>(null);
2023
const [prevGridWidth, setPreviousGridWidth] = useState(gridWidth);
2124
const columnsCanFlex: boolean = columns.length === viewportColumns.length;
2225
// Allow columns to flex again when...
@@ -28,11 +31,10 @@ export function useColumnWidths<R, SR>(
2831

2932
for (const column of viewportColumns) {
3033
const { key, idx, width } = column;
31-
if (key === columnToAutoResize) {
32-
newTemplateColumns[idx] = getColumnWidthForMeasurement('max-content', column);
34+
if (key === columnToAutoResize?.key) {
35+
newTemplateColumns[idx] = getColumnWidthForMeasurement(columnToAutoResize.width, column);
3336
columnsToMeasure.push(key);
3437
} else if (
35-
typeof width === 'string' &&
3638
(ignorePreviouslyMeasuredColumns || !measuredColumnWidths.has(key)) &&
3739
// If the column is resized by the user, we don't want to measure it again
3840
!resizedColumnWidths.has(key)
@@ -71,12 +73,13 @@ export function useColumnWidths<R, SR>(
7173
if (columnToAutoResize !== null) {
7274
setColumnToAutoResize(null);
7375
setResizedColumnWidths((resizedColumnWidths) => {
74-
const oldWidth = resizedColumnWidths.get(columnToAutoResize);
75-
const newWidth = measureColumnWidth(gridRef, columnToAutoResize);
76+
const resizingKey = columnToAutoResize.key;
77+
const oldWidth = resizedColumnWidths.get(resizingKey);
78+
const newWidth = measureColumnWidth(gridRef, resizingKey);
7679
if (newWidth !== undefined && oldWidth !== newWidth) {
7780
const newResizedColumnWidths = new Map(resizedColumnWidths);
78-
newResizedColumnWidths.set(columnToAutoResize, newWidth);
79-
onColumnResize?.(viewportColumns.find((c) => c.key === columnToAutoResize)!, newWidth);
81+
newResizedColumnWidths.set(resizingKey, newWidth);
82+
onColumnResize?.(viewportColumns.find((c) => c.key === resizingKey)!, newWidth);
8083
return newResizedColumnWidths;
8184
}
8285
return resizedColumnWidths;
@@ -110,17 +113,10 @@ export function useColumnWidths<R, SR>(
110113
});
111114
}
112115

113-
if (typeof nextWidth === 'number') {
114-
const clampedNextWidth = clampColumnWidth(nextWidth, column);
115-
setResizedColumnWidths((resizedColumnWidths) => {
116-
const newResizedColumnWidths = new Map(resizedColumnWidths);
117-
newResizedColumnWidths.set(resizingKey, clampedNextWidth);
118-
return newResizedColumnWidths;
119-
});
120-
onColumnResize?.(column, clampedNextWidth);
121-
} else {
122-
setColumnToAutoResize(resizingKey);
123-
}
116+
setColumnToAutoResize({
117+
key: resizingKey,
118+
width: nextWidth
119+
});
124120
}
125121

126122
return {

src/utils/index.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,17 @@ export function assertIsValidKeyGetter<R, K extends React.Key>(
1717
throw new Error('Please specify the rowKeyGetter prop to use selection');
1818
}
1919
}
20-
21-
export function clampColumnWidth<R, SR>(
22-
width: number,
23-
{ minWidth, maxWidth }: CalculatedColumn<R, SR>
24-
): number {
25-
width = max(width, minWidth);
26-
27-
// ignore maxWidth if it less than minWidth
28-
if (typeof maxWidth === 'number' && maxWidth >= minWidth) {
29-
return min(width, maxWidth);
30-
}
31-
32-
return width;
33-
}
34-
3520
export function getColumnWidthForMeasurement<R, SR>(
36-
width: string,
21+
width: number | string,
3722
{ minWidth, maxWidth }: CalculatedColumn<R, SR>
3823
): string {
24+
if (typeof width === 'number') {
25+
if (maxWidth != null) {
26+
return `clamp(${minWidth}px, ${width}px, ${maxWidth}px)`;
27+
}
28+
return `max(${minWidth}px, ${width}px)`;
29+
}
30+
3931
if (
4032
maxWidth != null &&
4133
// ignore maxWidth if it less than minWidth

src/utils/renderMeasuringCells.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ const measuringCellClassname = css`
1111
`;
1212

1313
export function renderMeasuringCells<R, SR>(viewportColumns: readonly CalculatedColumn<R, SR>[]) {
14-
return viewportColumns.map(({ key, idx, minWidth, maxWidth }) => (
14+
return viewportColumns.map(({ key, idx, minWidth }) => (
1515
<div
1616
key={key}
1717
className={measuringCellClassname}
18-
style={{ gridColumnStart: idx + 1, minWidth, maxWidth }}
18+
style={{ gridColumnStart: idx + 1, minWidth }}
1919
data-measuring-cell-key={key}
2020
/>
2121
));

test/browser/column/resizable.test.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,19 @@ test('should resize column when dragging the handle', async () => {
7272
const [, col2] = getHeaderCells();
7373
await resize({ column: col2, resizeBy: -50 });
7474
await expect.element(grid).toHaveStyle({ gridTemplateColumns: '100px 150px' });
75-
expect(onColumnResize).toHaveBeenCalledExactlyOnceWith(expect.objectContaining(columns[1]), 150);
75+
expect(onColumnResize).toHaveBeenCalledWith(expect.objectContaining(columns[1]), 150);
7676
});
7777

7878
test('should use the maxWidth if specified', async () => {
79-
setup<Row, unknown>({ columns, rows: [] });
79+
const onColumnResize = vi.fn();
80+
setup<Row, unknown>({ columns, rows: [], onColumnResize });
8081
const grid = getGrid();
82+
expect(onColumnResize).not.toHaveBeenCalled();
8183
await expect.element(grid).toHaveStyle({ gridTemplateColumns: '100px 200px ' });
8284
const [, col2] = getHeaderCells();
8385
await resize({ column: col2, resizeBy: 1000 });
8486
await expect.element(grid).toHaveStyle({ gridTemplateColumns: '100px 400px' });
87+
expect(onColumnResize).toHaveBeenCalledWith(expect.objectContaining(columns[1]), 400);
8588
});
8689

8790
test('should use the minWidth if specified', async () => {

website/routes/CommonFeatures.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ function getColumns(
117117
{
118118
key: 'country',
119119
name: 'Country',
120+
width: 800,
120121
maxWidth: 150,
121122
renderEditCell: (p) => (
122123
<select

0 commit comments

Comments
 (0)