diff --git a/docs/data/data-grid/style/StripedGrid.js b/docs/data/data-grid/style/StripedGrid.js new file mode 100644 index 000000000000..3b0524776ee1 --- /dev/null +++ b/docs/data/data-grid/style/StripedGrid.js @@ -0,0 +1,58 @@ +import * as React from 'react'; +import { alpha, styled } from '@mui/material/styles'; +import { DataGrid, gridClasses } from '@mui/x-data-grid'; +import { useDemoData } from '@mui/x-data-grid-generator'; + +const ODD_OPACITY = 0.2; + +const StripedDataGrid = styled(DataGrid)(({ theme }) => ({ + [`& .${gridClasses.row}.even`]: { + backgroundColor: theme.palette.grey[200], + '&:hover, &.Mui-hovered': { + backgroundColor: alpha(theme.palette.primary.main, ODD_OPACITY), + '@media (hover: none)': { + backgroundColor: 'transparent', + }, + }, + '&.Mui-selected': { + backgroundColor: alpha( + theme.palette.primary.main, + ODD_OPACITY + theme.palette.action.selectedOpacity, + ), + '&:hover, &.Mui-hovered': { + backgroundColor: alpha( + theme.palette.primary.main, + ODD_OPACITY + + theme.palette.action.selectedOpacity + + theme.palette.action.hoverOpacity, + ), + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: alpha( + theme.palette.primary.main, + ODD_OPACITY + theme.palette.action.selectedOpacity, + ), + }, + }, + }, + }, +})); + +export default function StripedGrid() { + const { data, loading } = useDemoData({ + dataSet: 'Employee', + rowLength: 200, + }); + + return ( +
+ + params.indexRelativeToCurrentPage % 2 === 0 ? 'even' : 'odd' + } + /> +
+ ); +} diff --git a/docs/data/data-grid/style/StripedGrid.tsx b/docs/data/data-grid/style/StripedGrid.tsx new file mode 100644 index 000000000000..3b0524776ee1 --- /dev/null +++ b/docs/data/data-grid/style/StripedGrid.tsx @@ -0,0 +1,58 @@ +import * as React from 'react'; +import { alpha, styled } from '@mui/material/styles'; +import { DataGrid, gridClasses } from '@mui/x-data-grid'; +import { useDemoData } from '@mui/x-data-grid-generator'; + +const ODD_OPACITY = 0.2; + +const StripedDataGrid = styled(DataGrid)(({ theme }) => ({ + [`& .${gridClasses.row}.even`]: { + backgroundColor: theme.palette.grey[200], + '&:hover, &.Mui-hovered': { + backgroundColor: alpha(theme.palette.primary.main, ODD_OPACITY), + '@media (hover: none)': { + backgroundColor: 'transparent', + }, + }, + '&.Mui-selected': { + backgroundColor: alpha( + theme.palette.primary.main, + ODD_OPACITY + theme.palette.action.selectedOpacity, + ), + '&:hover, &.Mui-hovered': { + backgroundColor: alpha( + theme.palette.primary.main, + ODD_OPACITY + + theme.palette.action.selectedOpacity + + theme.palette.action.hoverOpacity, + ), + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: alpha( + theme.palette.primary.main, + ODD_OPACITY + theme.palette.action.selectedOpacity, + ), + }, + }, + }, + }, +})); + +export default function StripedGrid() { + const { data, loading } = useDemoData({ + dataSet: 'Employee', + rowLength: 200, + }); + + return ( +
+ + params.indexRelativeToCurrentPage % 2 === 0 ? 'even' : 'odd' + } + /> +
+ ); +} diff --git a/docs/data/data-grid/style/StripedGrid.tsx.preview b/docs/data/data-grid/style/StripedGrid.tsx.preview new file mode 100644 index 000000000000..73eed7717645 --- /dev/null +++ b/docs/data/data-grid/style/StripedGrid.tsx.preview @@ -0,0 +1,7 @@ + + params.indexRelativeToCurrentPage % 2 === 0 ? 'even' : 'odd' + } +/> \ No newline at end of file diff --git a/docs/data/data-grid/style/style.md b/docs/data/data-grid/style/style.md index cad6e47923ee..7959ebaf04df 100644 --- a/docs/data/data-grid/style/style.md +++ b/docs/data/data-grid/style/style.md @@ -117,9 +117,17 @@ Choose between one of the following values: 'left' | 'right' | 'center'. **Note**: You must use `headerAlign` to align the content of the header. +## Striped rows + +The following demo illustrates how the rows of the grid can be stripped. + +{{"demo": "StripedGrid.js", "bg": "inline"}} + ## Custom theme -The following demo leverages the CSS customization API to match the Ant Design specification. +You can use the `indexRelativeToCurrentPage` param passed to `getRowClassName` to apply alternating styles to the rows. + +The following demo illustrates how this can be achieved. {{"demo": "AntDesignGrid.js", "defaultCodeOpen": false}} diff --git a/docs/pages/x/api/data-grid/grid-row-class-name-params.md b/docs/pages/x/api/data-grid/grid-row-class-name-params.md index 63b47636b634..dae66bcad724 100644 --- a/docs/pages/x/api/data-grid/grid-row-class-name-params.md +++ b/docs/pages/x/api/data-grid/grid-row-class-name-params.md @@ -12,11 +12,12 @@ import { GridRowClassNameParams } from '@mui/x-data-grid'; ## Properties -| Name | Type | Description | -| :-------------------------------------------- | :---------------------------------------------------------------------- | :--------------------------------------------------------- | -| columns | GridColumns | All grid columns. | -| getValue | (id: GridRowId, field: string) => any | Get the cell value of a row and field. | -| id | GridRowId | The grid row id. | -| isFirstVisible | boolean | Whether this row is the first visible or not. | -| isLastVisible | boolean | Whether this row is the last visible or not. | -| row | R | The row model of the row that the current cell belongs to. | +| Name | Type | Description | +| :-------------------------------------------------------- | :---------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | +| columns | GridColumns | All grid columns. | +| getValue | (id: GridRowId, field: string) => any | Get the cell value of a row and field. | +| id | GridRowId | The grid row id. | +| indexRelativeToCurrentPage | number | Index of the row in the current page.
If the pagination is disabled, it will be the index relative to all filtered rows. | +| isFirstVisible | boolean | Whether this row is the first visible or not. | +| isLastVisible | boolean | Whether this row is the last visible or not. | +| row | R | The row model of the row that the current cell belongs to. | diff --git a/docs/pages/x/api/data-grid/grid-row-spacing-params.md b/docs/pages/x/api/data-grid/grid-row-spacing-params.md index c06eba15b42b..828bc621478a 100644 --- a/docs/pages/x/api/data-grid/grid-row-spacing-params.md +++ b/docs/pages/x/api/data-grid/grid-row-spacing-params.md @@ -12,9 +12,10 @@ import { GridRowSpacingParams } from '@mui/x-data-grid'; ## Properties -| Name | Type | Description | -| :-------------------------------------------- | :--------------------------------------- | :-------------------------------------------- | -| id | GridRowId | The row id. | -| isFirstVisible | boolean | Whether this row is the first visible or not. | -| isLastVisible | boolean | Whether this row is the last visible or not. | -| model | R | The row model. | +| Name | Type | Description | +| :-------------------------------------------------------- | :--------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------- | +| id | GridRowId | The row id. | +| indexRelativeToCurrentPage | number | Index of the row in the current page.
If the pagination is disabled, it will be the index relative to all filtered rows. | +| isFirstVisible | boolean | Whether this row is the first visible or not. | +| isLastVisible | boolean | Whether this row is the last visible or not. | +| model | R | The row model. | diff --git a/packages/grid/x-data-grid/src/components/GridRow.tsx b/packages/grid/x-data-grid/src/components/GridRow.tsx index 9396b9d45a2b..ac3b74988cb6 100644 --- a/packages/grid/x-data-grid/src/components/GridRow.tsx +++ b/packages/grid/x-data-grid/src/components/GridRow.tsx @@ -25,10 +25,15 @@ import { useGridVisibleRows } from '../hooks/utils/useGridVisibleRows'; import { findParentElementFromClassName } from '../utils/domUtils'; import { GRID_CHECKBOX_SELECTION_COL_DEF } from '../colDef/gridCheckboxSelectionColDef'; import { GRID_ACTIONS_COLUMN_TYPE } from '../colDef/gridActionsColDef'; +import { GridRenderEditCellParams } from '../models/params/gridCellParams'; export interface GridRowProps { rowId: GridRowId; selected: boolean; + /** + * Index of the row in the whole sorted and filtered dataset. + * If some rows above have expanded children, this index also take those children into account. + */ index: number; rowHeight: number; containerWidth: number; @@ -214,6 +219,7 @@ function GridRow(props: React.HTMLAttributes & GridRowProps) { ...apiRef.current.getRowParams(rowId), isFirstVisible: indexRelativeToCurrentPage === 0, isLastVisible: indexRelativeToCurrentPage === currentPage.rows.length - 1, + indexRelativeToCurrentPage, }; rowClassName = rootProps.getRowClassName(rowParams); @@ -257,7 +263,12 @@ function GridRow(props: React.HTMLAttributes & GridRowProps) { } if (editCellState != null && column.renderEditCell) { - const params = { ...cellParams, ...editCellState, api: apiRef.current }; + const params: GridRenderEditCellParams = { + ...cellParams, + ...editCellState, + api: apiRef.current, + }; + content = column.renderEditCell(params); // TODO move to GridCell classNames.push(clsx(gridClasses['cell--editing'], rootProps.classes?.['cell--editing'])); @@ -336,6 +347,10 @@ GridRow.propTypes = { containerWidth: PropTypes.number.isRequired, editRowsState: PropTypes.object.isRequired, firstColumnToRender: PropTypes.number.isRequired, + /** + * Index of the row in the whole sorted and filtered dataset. + * If some rows above have expanded children, this index also take those children into account. + */ index: PropTypes.number.isRequired, isLastVisible: PropTypes.bool, lastColumnToRender: PropTypes.number.isRequired, diff --git a/packages/grid/x-data-grid/src/hooks/features/rows/useGridRowsMeta.ts b/packages/grid/x-data-grid/src/hooks/features/rows/useGridRowsMeta.ts index e24fc695c1ee..c37064490155 100644 --- a/packages/grid/x-data-grid/src/hooks/features/rows/useGridRowsMeta.ts +++ b/packages/grid/x-data-grid/src/hooks/features/rows/useGridRowsMeta.ts @@ -75,12 +75,15 @@ export const useGridRowsMeta = ( const initialHeights: Record = { base: baseRowHeight }; if (getRowSpacing) { - const index = apiRef.current.getRowIndexRelativeToVisibleRows(row.id); + const indexRelativeToCurrentPage = apiRef.current.getRowIndexRelativeToVisibleRows( + row.id, + ); const spacing = getRowSpacing({ ...row, - isFirstVisible: index === 0, - isLastVisible: index === currentPage.rows.length - 1, + isFirstVisible: indexRelativeToCurrentPage === 0, + isLastVisible: indexRelativeToCurrentPage === currentPage.rows.length - 1, + indexRelativeToCurrentPage, }); initialHeights.spacingTop = spacing.top ?? 0; diff --git a/packages/grid/x-data-grid/src/models/params/gridRowParams.ts b/packages/grid/x-data-grid/src/models/params/gridRowParams.ts index ae2314fb4e97..99129adbb822 100644 --- a/packages/grid/x-data-grid/src/models/params/gridRowParams.ts +++ b/packages/grid/x-data-grid/src/models/params/gridRowParams.ts @@ -36,6 +36,11 @@ interface GridRowVisibilityParams { * Whether this row is the last visible or not. */ isLastVisible: boolean; + /** + * Index of the row in the current page. + * If the pagination is disabled, it will be the index relative to all filtered rows. + */ + indexRelativeToCurrentPage: number; } /** diff --git a/packages/grid/x-data-grid/src/tests/rows.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/rows.DataGrid.test.tsx index 7a9cf4a3554d..6da1c5e0574c 100644 --- a/packages/grid/x-data-grid/src/tests/rows.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/rows.DataGrid.test.tsx @@ -374,16 +374,17 @@ describe(' - Rows', () => { it('should be called with the correct params', () => { const getRowSpacing = stub().returns({}); render(); - expect(getRowSpacing.args[0][0]).to.deep.equal({ isFirstVisible: true, isLastVisible: false, + indexRelativeToCurrentPage: 0, id: 0, model: rows[0], }); expect(getRowSpacing.args[1][0]).to.deep.equal({ isFirstVisible: false, isLastVisible: true, + indexRelativeToCurrentPage: 1, id: 1, model: rows[1], }); @@ -394,12 +395,14 @@ describe(' - Rows', () => { expect(getRowSpacing.args[0][0]).to.deep.equal({ isFirstVisible: true, isLastVisible: false, + indexRelativeToCurrentPage: 0, id: 2, model: rows[2], }); expect(getRowSpacing.args[1][0]).to.deep.equal({ isFirstVisible: false, isLastVisible: true, + indexRelativeToCurrentPage: 1, id: 3, model: rows[3], });