@@ -36,6 +36,7 @@ import type {
3636 CellMouseEvent ,
3737 CellNavigationMode ,
3838 Column ,
39+ ColumnOrColumnGroup ,
3940 CopyEvent ,
4041 Direction ,
4142 FillEvent ,
@@ -54,6 +55,7 @@ import {
5455} from './DataGridDefaultRenderersProvider' ;
5556import DragHandle from './DragHandle' ;
5657import EditCell from './EditCell' ;
58+ import GroupedColumnHeaderRow from './GroupedColumnHeaderRow' ;
5759import HeaderRow from './HeaderRow' ;
5860import { defaultRenderRow } from './Row' ;
5961import type { PartialPosition } from './ScrollToCell' ;
@@ -105,7 +107,7 @@ export interface DataGridProps<R, SR = unknown, K extends Key = Key> extends Sha
105107 * Grid and data Props
106108 */
107109 /** An array of objects representing each column on the grid */
108- columns : readonly Column < R , SR > [ ] ;
110+ columns : readonly ColumnOrColumnGroup < R , SR > [ ] ;
109111 /** A function called for each rendered row that should return a plain key/value pair object */
110112 rows : readonly R [ ] ;
111113 /**
@@ -258,14 +260,6 @@ function DataGrid<R, SR, K extends Key>(
258260 const enableVirtualization = rawEnableVirtualization ?? true ;
259261 const direction = rawDirection ?? 'ltr' ;
260262
261- const headerRowsCount = 1 ;
262- const topSummaryRowsCount = topSummaryRows ?. length ?? 0 ;
263- const bottomSummaryRowsCount = bottomSummaryRows ?. length ?? 0 ;
264- const summaryRowsCount = topSummaryRowsCount + bottomSummaryRowsCount ;
265- const headerAndTopSummaryRowsCount = headerRowsCount + topSummaryRowsCount ;
266- const minRowIdx = - headerAndTopSummaryRowsCount ;
267- const maxRowIdx = rows . length + bottomSummaryRowsCount - 1 ;
268-
269263 /**
270264 * states
271265 */
@@ -277,14 +271,45 @@ function DataGrid<R, SR, K extends Key>(
277271 const [ measuredColumnWidths , setMeasuredColumnWidths ] = useState (
278272 ( ) : ReadonlyMap < string , number > => new Map ( )
279273 ) ;
280- const [ selectedPosition , setSelectedPosition ] = useState (
281- ( ) : SelectCellState | EditCellState < R > => ( { idx : - 1 , rowIdx : minRowIdx - 1 , mode : 'SELECT' } )
282- ) ;
283274 const [ copiedCell , setCopiedCell ] = useState < { row : R ; columnKey : string } | null > ( null ) ;
284275 const [ isDragging , setDragging ] = useState ( false ) ;
285276 const [ draggedOverRowIdx , setOverRowIdx ] = useState < number | undefined > ( undefined ) ;
286277 const [ scrollToPosition , setScrollToPosition ] = useState < PartialPosition | null > ( null ) ;
287278
279+ const [ gridRef , gridWidth , gridHeight ] = useGridDimensions ( ) ;
280+ const {
281+ columns,
282+ colSpanColumns,
283+ lastFrozenColumnIndex,
284+ headerRowsCount,
285+ colOverscanStartIdx,
286+ colOverscanEndIdx,
287+ templateColumns,
288+ layoutCssVars,
289+ totalFrozenColumnWidth
290+ } = useCalculatedColumns ( {
291+ rawColumns,
292+ defaultColumnOptions,
293+ measuredColumnWidths,
294+ resizedColumnWidths,
295+ scrollLeft,
296+ viewportWidth : gridWidth ,
297+ enableVirtualization
298+ } ) ;
299+
300+ const topSummaryRowsCount = topSummaryRows ?. length ?? 0 ;
301+ const bottomSummaryRowsCount = bottomSummaryRows ?. length ?? 0 ;
302+ const summaryRowsCount = topSummaryRowsCount + bottomSummaryRowsCount ;
303+ const headerAndTopSummaryRowsCount = headerRowsCount + topSummaryRowsCount ;
304+ const groupedColumnHeaderRowsCount = headerRowsCount - 1 ;
305+ const minRowIdx = - headerAndTopSummaryRowsCount ;
306+ const mainHeaderIndex = minRowIdx + groupedColumnHeaderRowsCount ;
307+ const maxRowIdx = rows . length + bottomSummaryRowsCount - 1 ;
308+
309+ const [ selectedPosition , setSelectedPosition ] = useState (
310+ ( ) : SelectCellState | EditCellState < R > => ( { idx : - 1 , rowIdx : minRowIdx - 1 , mode : 'SELECT' } )
311+ ) ;
312+
288313 /**
289314 * refs
290315 */
@@ -298,8 +323,8 @@ function DataGrid<R, SR, K extends Key>(
298323 * computed values
299324 */
300325 const isTreeGrid = role === 'treegrid' ;
301- const [ gridRef , gridWidth , gridHeight ] = useGridDimensions ( ) ;
302- const clientHeight = gridHeight - headerRowHeight - summaryRowsCount * summaryRowHeight ;
326+ const headerRowsHeight = headerRowsCount * headerRowHeight ;
327+ const clientHeight = gridHeight - headerRowsHeight - summaryRowsCount * summaryRowHeight ;
303328 const isSelectable = selectedRows != null && onSelectedRowsChange != null ;
304329 const isRtl = direction === 'rtl' ;
305330 const leftKey = isRtl ? 'ArrowRight' : 'ArrowLeft' ;
@@ -326,25 +351,6 @@ function DataGrid<R, SR, K extends Key>(
326351 ) ;
327352 } , [ rows , selectedRows , rowKeyGetter ] ) ;
328353
329- const {
330- columns,
331- colSpanColumns,
332- colOverscanStartIdx,
333- colOverscanEndIdx,
334- templateColumns,
335- layoutCssVars,
336- lastFrozenColumnIndex,
337- totalFrozenColumnWidth
338- } = useCalculatedColumns ( {
339- rawColumns,
340- measuredColumnWidths,
341- resizedColumnWidths,
342- scrollLeft,
343- viewportWidth : gridWidth ,
344- defaultColumnOptions,
345- enableVirtualization
346- } ) ;
347-
348354 const {
349355 rowOverscanStartIdx,
350356 rowOverscanEndIdx,
@@ -403,8 +409,8 @@ function DataGrid<R, SR, K extends Key>(
403409 const selectRowLatest = useLatestFunc ( selectRow ) ;
404410 const handleFormatterRowChangeLatest = useLatestFunc ( updateRow ) ;
405411 const selectCellLatest = useLatestFunc ( selectCell ) ;
406- const selectHeaderCellLatest = useLatestFunc ( ( idx : number ) => {
407- selectCell ( { rowIdx : minRowIdx , idx } ) ;
412+ const selectHeaderCellLatest = useLatestFunc ( ( { idx, rowIdx } : Position ) => {
413+ selectCell ( { rowIdx : minRowIdx + rowIdx - 1 , idx } ) ;
408414 } ) ;
409415
410416 /**
@@ -958,7 +964,7 @@ function DataGrid<R, SR, K extends Key>(
958964 setDraggedOverRowIdx ( undefined ) ;
959965 }
960966
961- let templateRows = `${ headerRowHeight } px` ;
967+ let templateRows = `repeat( ${ headerRowsCount } , ${ headerRowHeight } px) ` ;
962968 if ( topSummaryRowsCount > 0 ) {
963969 templateRows += ` repeat(${ topSummaryRowsCount } , ${ summaryRowHeight } px)` ;
964970 }
@@ -999,7 +1005,7 @@ function DataGrid<R, SR, K extends Key>(
9991005 scrollPaddingBlock :
10001006 isRowIdxWithinViewportBounds ( selectedPosition . rowIdx ) ||
10011007 scrollToPosition ?. rowIdx !== undefined
1002- ? `${ headerRowHeight + topSummaryRowsCount * summaryRowHeight } px ${
1008+ ? `${ headerRowsHeight + topSummaryRowsCount * summaryRowHeight } px ${
10031009 bottomSummaryRowsCount * summaryRowHeight
10041010 } px`
10051011 : undefined ,
@@ -1020,14 +1026,27 @@ function DataGrid<R, SR, K extends Key>(
10201026 < DataGridDefaultRenderersProvider value = { defaultGridComponents } >
10211027 < RowSelectionChangeProvider value = { selectRowLatest } >
10221028 < RowSelectionProvider value = { allRowsSelected } >
1029+ { Array . from ( { length : groupedColumnHeaderRowsCount } , ( _ , index ) => (
1030+ < GroupedColumnHeaderRow
1031+ key = { index }
1032+ rowIdx = { index + 1 }
1033+ level = { - groupedColumnHeaderRowsCount + index }
1034+ columns = { getRowViewportColumns ( minRowIdx + index ) }
1035+ selectedCellIdx = {
1036+ selectedPosition . rowIdx === minRowIdx + index ? selectedPosition . idx : undefined
1037+ }
1038+ selectCell = { selectHeaderCellLatest }
1039+ />
1040+ ) ) }
10231041 < HeaderRow
1024- columns = { getRowViewportColumns ( minRowIdx ) }
1042+ rowIdx = { headerRowsCount }
1043+ columns = { getRowViewportColumns ( mainHeaderIndex ) }
10251044 onColumnResize = { handleColumnResizeLatest }
10261045 sortColumns = { sortColumns }
10271046 onSortColumnsChange = { onSortColumnsChangeLatest }
10281047 lastFrozenColumnIndex = { lastFrozenColumnIndex }
10291048 selectedCellIdx = {
1030- selectedPosition . rowIdx === minRowIdx ? selectedPosition . idx : undefined
1049+ selectedPosition . rowIdx === mainHeaderIndex ? selectedPosition . idx : undefined
10311050 }
10321051 selectCell = { selectHeaderCellLatest }
10331052 shouldFocusGrid = { ! selectedCellIsWithinSelectionBounds }
@@ -1039,15 +1058,15 @@ function DataGrid<R, SR, K extends Key>(
10391058 ) : (
10401059 < >
10411060 { topSummaryRows ?. map ( ( row , rowIdx ) => {
1042- const gridRowStart = headerRowsCount + rowIdx + 1 ;
1043- const summaryRowIdx = rowIdx + minRowIdx + 1 ;
1061+ const gridRowStart = headerRowsCount + 1 + rowIdx ;
1062+ const summaryRowIdx = mainHeaderIndex + 1 + rowIdx ;
10441063 const isSummaryRowSelected = selectedPosition . rowIdx === summaryRowIdx ;
1045- const top = headerRowHeight + summaryRowHeight * rowIdx ;
1064+ const top = headerRowsHeight + summaryRowHeight * rowIdx ;
10461065
10471066 return (
10481067 < SummaryRow
1049- aria-rowindex = { gridRowStart }
10501068 key = { rowIdx }
1069+ aria-rowindex = { gridRowStart }
10511070 rowIdx = { summaryRowIdx }
10521071 gridRowStart = { gridRowStart }
10531072 row = { row }
0 commit comments