Skip to content

Commit 0e97599

Browse files
authored
Add columnWidths and onColumnWidthsChange props (adazzle#3761)
These new props can be used to reset widths when needed for example ``` const [columnWidths, setColumnWidths] = useState((): ColumnWidths => new Map()); function addNewRow() { setRows(...); setColumnWidths(new Map()); } ... function toggleColumnVisibility(..) { setVisibleColumns(...); setColumnWidths(new Map()); } ,, return <DataGrid columnWidths={columnWidths} onColumnWidthsChange={setColumnWidths} ../> ``` If these props are not provided then the grid uses internal state. `onColumnWidthsChange` at the end of the resize operation whereas `onColumnResize` fires as the column is being resized
1 parent 1254335 commit 0e97599

File tree

10 files changed

+287
-84
lines changed

10 files changed

+287
-84
lines changed

README.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ yarn add react-data-grid
6565

6666
Additionally, import the default styles in your application:
6767

68-
```jsx
68+
```tsx
6969
import 'react-data-grid/lib/styles.css';
7070
```
7171

@@ -75,7 +75,7 @@ import 'react-data-grid/lib/styles.css';
7575

7676
Here is a basic example of how to use `react-data-grid` in your React application:
7777

78-
```jsx
78+
```tsx
7979
import 'react-data-grid/lib/styles.css';
8080

8181
import { DataGrid } from 'react-data-grid';
@@ -182,6 +182,26 @@ Height of the header row in pixels.
182182

183183
Height of each summary row in pixels.
184184

185+
###### `columnWidths?: Maybe<ColumnWidths>`
186+
187+
A map of column widths containing both measured and resized widths. If not provided then an internal state is used.
188+
189+
```tsx
190+
const [columnWidths, setColumnWidths] = useState((): ColumnWidths => new Map());
191+
192+
function addNewRow() {
193+
setRows(...);
194+
// reset column widths after adding a new row
195+
setColumnWidths(new Map());
196+
}
197+
198+
return <DataGrid columnWidths={columnWidths} onColumnWidthsChange={setColumnWidths} ../>
199+
```
200+
201+
###### `onColumnWidthsChange?: Maybe<(columnWidths: ColumnWidths) => void>`
202+
203+
Callback triggered when column widths change. If not provided then an internal state is used.
204+
185205
###### `selectedRows?: Maybe<ReadonlySet<K>>`
186206

187207
A set of selected row keys. `rowKeyGetter` is required for row selection to work.

src/DataGrid.tsx

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import type {
5050
CellSelectArgs,
5151
Column,
5252
ColumnOrColumnGroup,
53+
ColumnWidths,
5354
Direction,
5455
FillEvent,
5556
Maybe,
@@ -159,6 +160,10 @@ export interface DataGridProps<R, SR = unknown, K extends Key = Key> extends Sha
159160
* @default 35
160161
*/
161162
summaryRowHeight?: Maybe<number>;
163+
/** A map of column widths */
164+
columnWidths?: Maybe<ColumnWidths>;
165+
/** Callback triggered when column widths change */
166+
onColumnWidthsChange?: Maybe<(columnWidths: ColumnWidths) => void>;
162167

163168
/**
164169
* Feature props
@@ -258,6 +263,8 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
258263
rowHeight: rawRowHeight,
259264
headerRowHeight: rawHeaderRowHeight,
260265
summaryRowHeight: rawSummaryRowHeight,
266+
columnWidths: columnWidthsRaw,
267+
onColumnWidthsChange: onColumnWidthsChangeRaw,
261268
// Feature props
262269
selectedRows,
263270
isRowSelectionDisabled,
@@ -320,25 +327,32 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
320327
*/
321328
const [scrollTop, setScrollTop] = useState(0);
322329
const [scrollLeft, setScrollLeft] = useState(0);
323-
const [resizedColumnWidths, setResizedColumnWidths] = useState(
324-
(): ReadonlyMap<string, number> => new Map()
325-
);
326-
const [measuredColumnWidths, setMeasuredColumnWidths] = useState(
327-
(): ReadonlyMap<string, number> => new Map()
330+
const [columnWidthsInternal, setColumnWidthsInternal] = useState(
331+
(): ColumnWidths => columnWidthsRaw ?? new Map()
328332
);
333+
const [isColumnResizing, setColumnResizing] = useState(false);
329334
const [isDragging, setDragging] = useState(false);
330335
const [draggedOverRowIdx, setOverRowIdx] = useState<number | undefined>(undefined);
331336
const [scrollToPosition, setScrollToPosition] = useState<PartialPosition | null>(null);
332337
const [shouldFocusCell, setShouldFocusCell] = useState(false);
333338
const [previousRowIdx, setPreviousRowIdx] = useState(-1);
334339

340+
const isColumnWidthsControlled =
341+
columnWidthsRaw != null && onColumnWidthsChangeRaw != null && !isColumnResizing;
342+
const columnWidths = isColumnWidthsControlled ? columnWidthsRaw : columnWidthsInternal;
343+
const onColumnWidthsChange = isColumnWidthsControlled
344+
? (columnWidths: ColumnWidths) => {
345+
// we keep the internal state in sync with the prop but this prevents an extra render
346+
setColumnWidthsInternal(columnWidths);
347+
onColumnWidthsChangeRaw(columnWidths);
348+
}
349+
: setColumnWidthsInternal;
350+
335351
const getColumnWidth = useCallback(
336352
(column: CalculatedColumn<R, SR>) => {
337-
return (
338-
resizedColumnWidths.get(column.key) ?? measuredColumnWidths.get(column.key) ?? column.width
339-
);
353+
return columnWidths.get(column.key)?.width ?? column.width;
340354
},
341-
[measuredColumnWidths, resizedColumnWidths]
355+
[columnWidths]
342356
);
343357

344358
const [gridRef, gridWidth, gridHeight, horizontalScrollbarHeight] = useGridDimensions();
@@ -458,11 +472,10 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
458472
templateColumns,
459473
gridRef,
460474
gridWidth,
461-
resizedColumnWidths,
462-
measuredColumnWidths,
463-
setResizedColumnWidths,
464-
setMeasuredColumnWidths,
465-
onColumnResize
475+
columnWidths,
476+
onColumnWidthsChange,
477+
onColumnResize,
478+
setColumnResizing
466479
);
467480

468481
const minColIdx = isTreeGrid ? -1 : 0;
@@ -476,6 +489,7 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
476489
* The identity of the wrapper function is stable so it won't break memoization
477490
*/
478491
const handleColumnResizeLatest = useLatestFunc(handleColumnResize);
492+
const handleColumnResizeEndLatest = useLatestFunc(handleColumnResizeEnd);
479493
const onColumnsReorderLastest = useLatestFunc(onColumnsReorder);
480494
const onSortColumnsChangeLatest = useLatestFunc(onSortColumnsChange);
481495
const onCellClickLatest = useLatestFunc(onCellClick);
@@ -714,6 +728,14 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
714728
}
715729
}
716730

731+
function handleColumnResizeEnd() {
732+
// This check is needed as double click on the resize handle triggers onPointerMove
733+
if (isColumnResizing) {
734+
onColumnWidthsChangeRaw?.(columnWidths);
735+
setColumnResizing(false);
736+
}
737+
}
738+
717739
/**
718740
* utils
719741
*/
@@ -1052,6 +1074,11 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
10521074
setDraggedOverRowIdx(undefined);
10531075
}
10541076

1077+
// Keep the state and prop in sync
1078+
if (isColumnWidthsControlled && columnWidthsInternal !== columnWidthsRaw) {
1079+
setColumnWidthsInternal(columnWidthsRaw);
1080+
}
1081+
10551082
let templateRows = `repeat(${headerRowsCount}, ${headerRowHeight}px)`;
10561083
if (topSummaryRowsCount > 0) {
10571084
templateRows += ` repeat(${topSummaryRowsCount}, ${summaryRowHeight}px)`;
@@ -1135,6 +1162,7 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
11351162
rowIdx={headerRowsCount}
11361163
columns={getRowViewportColumns(mainHeaderRowIdx)}
11371164
onColumnResize={handleColumnResizeLatest}
1165+
onColumnResizeEnd={handleColumnResizeEndLatest}
11381166
onColumnsReorder={onColumnsReorderLastest}
11391167
sortColumns={sortColumns}
11401168
onSortColumnsChange={onSortColumnsChangeLatest}

src/HeaderCell.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ type SharedHeaderRowProps<R, SR> = Pick<
6060
| 'onSortColumnsChange'
6161
| 'selectCell'
6262
| 'onColumnResize'
63+
| 'onColumnResizeEnd'
6364
| 'shouldFocusGrid'
6465
| 'direction'
6566
| 'onColumnsReorder'
@@ -79,6 +80,7 @@ export default function HeaderCell<R, SR>({
7980
rowIdx,
8081
isCellSelected,
8182
onColumnResize,
83+
onColumnResizeEnd,
8284
onColumnsReorder,
8385
sortColumns,
8486
onSortColumnsChange,
@@ -272,18 +274,28 @@ export default function HeaderCell<R, SR>({
272274
})}
273275

274276
{resizable && (
275-
<ResizeHandle column={column} onColumnResize={onColumnResize} direction={direction} />
277+
<ResizeHandle
278+
direction={direction}
279+
column={column}
280+
onColumnResize={onColumnResize}
281+
onColumnResizeEnd={onColumnResizeEnd}
282+
/>
276283
)}
277284
</div>
278285
);
279286
}
280287

281288
type ResizeHandleProps<R, SR> = Pick<
282289
HeaderCellProps<R, SR>,
283-
'column' | 'onColumnResize' | 'direction'
290+
'direction' | 'column' | 'onColumnResize' | 'onColumnResizeEnd'
284291
>;
285292

286-
function ResizeHandle<R, SR>({ column, onColumnResize, direction }: ResizeHandleProps<R, SR>) {
293+
function ResizeHandle<R, SR>({
294+
direction,
295+
column,
296+
onColumnResize,
297+
onColumnResizeEnd
298+
}: ResizeHandleProps<R, SR>) {
287299
const resizingOffsetRef = useRef<number>(undefined);
288300
const isRtl = direction === 'rtl';
289301

@@ -314,6 +326,7 @@ function ResizeHandle<R, SR>({ column, onColumnResize, direction }: ResizeHandle
314326
}
315327

316328
function onLostPointerCapture() {
329+
onColumnResizeEnd();
317330
resizingOffsetRef.current = undefined;
318331
}
319332

src/HeaderRow.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface HeaderRowProps<R, SR, K extends React.Key> extends SharedDataGr
1818
rowIdx: number;
1919
columns: readonly CalculatedColumn<R, SR>[];
2020
onColumnResize: (column: CalculatedColumn<R, SR>, width: ResizedWidth) => void;
21+
onColumnResizeEnd: () => void;
2122
selectCell: (position: Position) => void;
2223
lastFrozenColumnIndex: number;
2324
selectedCellIdx: number | undefined;
@@ -51,6 +52,7 @@ function HeaderRow<R, SR, K extends React.Key>({
5152
rowIdx,
5253
columns,
5354
onColumnResize,
55+
onColumnResizeEnd,
5456
onColumnsReorder,
5557
sortColumns,
5658
onSortColumnsChange,
@@ -78,6 +80,7 @@ function HeaderRow<R, SR, K extends React.Key>({
7880
rowIdx={rowIdx}
7981
isCellSelected={selectedCellIdx === column.idx}
8082
onColumnResize={onColumnResize}
83+
onColumnResizeEnd={onColumnResizeEnd}
8184
onColumnsReorder={onColumnsReorder}
8285
onSortColumnsChange={onSortColumnsChange}
8386
sortColumns={sortColumns}

0 commit comments

Comments
 (0)