@@ -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 }
0 commit comments