Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@ By default, the row count in the footer is the number of top level rows that are
In the demo below, a `CustomFooterRowCount` component is added to the `footerRowCount` slot. This component uses the `gridFilteredDescendantRowCountSelector` to get the number of child rows and display it alongside the number of groups.

{{"demo": "RowGroupingChildRowCount.js", "bg": "inline", "defaultCodeOpen": false}}

## Styling row groups based on child conditions

You can check the [styling row groups](/x/react-data-grid/style/#styling-row-groups) section for more information.
4 changes: 4 additions & 0 deletions docs/data/data-grid/row-definition/row-definition.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ Otherwise, the Data Grid will re-apply heavy work like sorting and filtering.
It could be achieved by either defining the prop outside the component scope or by memoizing using the `React.useCallback` hook if the function reuses something from the component scope.
:::

## Selectors

{{"component": "modules/components/SelectorsDocs.js", "category": "Rows"}}

## Styling rows

You can check the [styling rows](/x/react-data-grid/style/#styling-rows) section for more information.
Expand Down
89 changes: 89 additions & 0 deletions docs/data/data-grid/style/RowGroupingStyling.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import * as React from 'react';
import {
DataGridPremium,
useGridApiRef,
useKeepGroupedColumnsHidden,
gridRowNodeSelector,
gridRowSelector,
gridRowHeightSelector,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';

const EXPECTED_GROSS = 2000000000;

export default function RowGroupingStyling() {
const apiRef = useGridApiRef();
const data = useMovieData();
const rowHeight = apiRef.current ? gridRowHeightSelector(apiRef) : 52;
const getRowClassName = React.useCallback((params) => {
const node = gridRowNodeSelector(apiRef, params.id);

if (!node) {
return '';
}

if (node.type === 'group') {
for (const childId of node.children) {
const childNode = gridRowNodeSelector(apiRef, childId);
if (childNode && childNode.type === 'leaf') {
const childRow = gridRowSelector(apiRef, childId);
if (childRow?.gross && childRow.gross > EXPECTED_GROSS) {
return 'highlighted-group';
}
}
}

return '';
}

const row = params.row;

if (row.gross > EXPECTED_GROSS) {
return 'highlighted-child';
}

return '';
}, []);

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company'],
},
},
});

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPremium
{...data}
apiRef={apiRef}
initialState={initialState}
getRowClassName={getRowClassName}
sx={(theme) => ({
'& .highlighted-group': {
'&::before': {
content: '""',
display: 'block',
position: 'absolute',
left: 0,
width: 4,
height: `calc(${rowHeight}px * 0.8)`,
marginTop: `calc(${rowHeight}px * 0.1)`,
backgroundColor: 'success.main',
borderTopRightRadius: 4,
borderBottomRightRadius: 4,
},
},
'& .highlighted-child': {
backgroundColor: `color-mix(in srgb, ${(theme.vars || theme).palette.success.main} 8%, transparent)`,
'&:hover': {
backgroundColor: `color-mix(in srgb, ${(theme.vars || theme).palette.success.main} 12%, transparent)`,
},
},
})}
/>
</div>
);
}
95 changes: 95 additions & 0 deletions docs/data/data-grid/style/RowGroupingStyling.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as React from 'react';
import {
DataGridPremium,
useGridApiRef,
useKeepGroupedColumnsHidden,
GridRowClassNameParams,
gridRowNodeSelector,
gridRowSelector,
gridRowHeightSelector,
} from '@mui/x-data-grid-premium';
import { useMovieData } from '@mui/x-data-grid-generator';

type Movie = ReturnType<typeof useMovieData>['rows'][number];

const EXPECTED_GROSS = 2000000000;

export default function RowGroupingStyling() {
const apiRef = useGridApiRef();
const data = useMovieData();
const rowHeight = apiRef.current ? gridRowHeightSelector(apiRef) : 52;
const getRowClassName = React.useCallback(
(params: GridRowClassNameParams<Movie>) => {
const node = gridRowNodeSelector(apiRef, params.id);

if (!node) {
return '';
}

if (node.type === 'group') {
for (const childId of node.children) {
const childNode = gridRowNodeSelector(apiRef, childId);
if (childNode && childNode.type === 'leaf') {
const childRow = gridRowSelector(apiRef, childId) as Movie;
if (childRow?.gross && childRow.gross > EXPECTED_GROSS) {
return 'highlighted-group';
}
}
}

return '';
}

const row = params.row;

if (row.gross > EXPECTED_GROSS) {
return 'highlighted-child';
}

return '';
},
[],
);

const initialState = useKeepGroupedColumnsHidden({
apiRef,
initialState: {
rowGrouping: {
model: ['company'],
},
},
});

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPremium
{...data}
apiRef={apiRef}
initialState={initialState}
getRowClassName={getRowClassName}
sx={(theme) => ({
'& .highlighted-group': {
'&::before': {
content: '""',
display: 'block',
position: 'absolute',
left: 0,
width: 4,
height: `calc(${rowHeight}px * 0.8)`,
marginTop: `calc(${rowHeight}px * 0.1)`,
backgroundColor: 'success.main',
borderTopRightRadius: 4,
borderBottomRightRadius: 4,
},
},
'& .highlighted-child': {
backgroundColor: `color-mix(in srgb, ${(theme.vars || theme).palette.success.main} 8%, transparent)`,
'&:hover': {
backgroundColor: `color-mix(in srgb, ${(theme.vars || theme).palette.success.main} 12%, transparent)`,
},
},
})}
/>
</div>
);
}
12 changes: 12 additions & 0 deletions docs/data/data-grid/style/style.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,18 @@ The following demo leverages the CSS customization API to match the Ant Design s

{{"demo": "AntDesignGrid.js", "defaultCodeOpen": false}}

## Styling row groups [<span class="plan-pro"></span>](/x/introduction/licensing/#pro-plan 'Pro plan')

Use `getRowClassName` to add a custom class to the row group and then write CSS to style it.

The example below demonstrates how to style a row group when any of the child rows has a "Gross" value greater than a specific value. The condition uses [`gridRowNodeSelector` and `gridRowSelector`](/x/react-data-grid/row-definition/#selectors) to check for the targeted row type and to get the row data respectively.

{{"demo": "RowGroupingStyling.js", "bg": "inline"}}

:::success
The styling method is not limited to the [`sx` prop](/x/react-data-grid/style/#using-the-sx-prop). You can use other styling solutions like plain CSS files or CSS modules.
:::

## API

- [DataGrid](/x/api/data-grid/data-grid/)
Expand Down
12 changes: 2 additions & 10 deletions docs/pages/x/api/charts/radar-axis.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,14 @@
"classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } },
"divisions": { "type": { "name": "number" }, "default": "1" },
"dominantBaseline": {
"type": {
"name": "union",
"description": "'alphabetic'<br>&#124;&nbsp;'auto'<br>&#124;&nbsp;'central'<br>&#124;&nbsp;'hanging'<br>&#124;&nbsp;'ideographic'<br>&#124;&nbsp;'inherit'<br>&#124;&nbsp;'mathematical'<br>&#124;&nbsp;'middle'<br>&#124;&nbsp;'no-change'<br>&#124;&nbsp;'reset-size'<br>&#124;&nbsp;'text-after-edge'<br>&#124;&nbsp;'text-before-edge'<br>&#124;&nbsp;'use-script'<br>&#124;&nbsp;func"
}
"type": { "name": "union", "description": "func<br>&#124;&nbsp;number<br>&#124;&nbsp;string" }
},
"labelOrientation": {
"type": { "name": "enum", "description": "'horizontal'<br>&#124;&nbsp;'rotated'" },
"default": "'horizontal'"
},
"metric": { "type": { "name": "string" } },
"textAnchor": {
"type": {
"name": "union",
"description": "'end'<br>&#124;&nbsp;'inherit'<br>&#124;&nbsp;'middle'<br>&#124;&nbsp;'start'<br>&#124;&nbsp;func"
}
}
"textAnchor": { "type": { "name": "union", "description": "func<br>&#124;&nbsp;string" } }
},
"name": "RadarAxis",
"imports": [
Expand Down
19 changes: 18 additions & 1 deletion docs/pages/x/api/data-grid/selectors.json
Original file line number Diff line number Diff line change
Expand Up @@ -291,14 +291,25 @@
},
{ "name": "gridRowGroupingNameSelector", "returnType": "string", "description": "" },
{ "name": "gridRowGroupingSanitizedModelSelector", "returnType": "string[]", "description": "" },
{
"name": "gridRowHeightSelector",
"returnType": "number",
"category": "Rows",
"description": "Get the row height."
},
{
"name": "gridRowIdSelector",
"returnType": "GridRowId",
"description": "Get the row id for a given row"
},
{ "name": "gridRowIsEditingSelector", "returnType": "boolean", "description": "" },
{ "name": "gridRowMaximumTreeDepthSelector", "returnType": "number", "description": "" },
{ "name": "gridRowNodeSelector", "returnType": "GridTreeNode", "description": "" },
{
"name": "gridRowNodeSelector",
"returnType": "GridTreeNode",
"category": "Rows",
"description": ""
},
{ "name": "gridRowSelectionCountSelector", "returnType": "number", "description": "" },
{
"name": "gridRowSelectionIdsSelector",
Expand All @@ -315,6 +326,12 @@
"returnType": "GridRowSelectionModel",
"description": ""
},
{
"name": "gridRowSelector",
"returnType": "GridValidRowModel",
"category": "Rows",
"description": ""
},
{ "name": "gridRowTreeDepthsSelector", "returnType": "GridTreeDepths", "description": "" },
{ "name": "gridRowTreeSelector", "returnType": "GridRowTreeConfig", "description": "" },
{ "name": "gridRowsLoadingSelector", "returnType": "boolean | undefined", "description": "" },
Expand Down
24 changes: 2 additions & 22 deletions packages/x-charts/src/RadarChart/RadarAxis/RadarAxis.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,7 @@ RadarAxis.propTypes = {
/**
* The labels dominant baseline or a function returning the dominant baseline for a given axis angle (in degree).
*/
dominantBaseline: PropTypes.oneOfType([
PropTypes.oneOf([
'alphabetic',
'auto',
'central',
'hanging',
'ideographic',
'inherit',
'mathematical',
'middle',
'no-change',
'reset-size',
'text-after-edge',
'text-before-edge',
'use-script',
]),
PropTypes.func,
]),
dominantBaseline: PropTypes.oneOfType([PropTypes.func, PropTypes.number, PropTypes.string]),
/**
* Defines how label align with the axis.
* - 'horizontal': labels stay horizontal and their placement change with the axis angle.
Expand All @@ -123,10 +106,7 @@ RadarAxis.propTypes = {
/**
* The labels text anchor or a function returning the text anchor for a given axis angle (in degree).
*/
textAnchor: PropTypes.oneOfType([
PropTypes.oneOf(['end', 'inherit', 'middle', 'start']),
PropTypes.func,
]),
textAnchor: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
} as any;

export { RadarAxis };
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export const gridColumnsTotalWidthSelector = createSelector(
(dimensions) => dimensions.columnsTotalWidth,
);

/**
* Get the row height.
* @category Rows
*/
export const gridRowHeightSelector = createSelector(
gridDimensionsSelector,
(dimensions) => dimensions.rowHeight,
Expand Down
6 changes: 5 additions & 1 deletion packages/x-data-grid/src/hooks/features/dimensions/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export type { GridDimensionsState } from './useGridDimensions';
export { gridDimensionsSelector, gridColumnsTotalWidthSelector } from './gridDimensionsSelectors';
export {
gridDimensionsSelector,
gridColumnsTotalWidthSelector,
gridRowHeightSelector,
} from './gridDimensionsSelectors';
export type { GridDimensions, GridDimensionsApi } from './gridDimensionsApi';
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,19 @@ export const gridRowsLookupSelector = createSelector(
(rows) => rows.dataRowIdToModelLookup,
);

/**
* @category Rows
*/
export const gridRowSelector = createSelector(
gridRowsLookupSelector,
(rows, id: GridRowId) => rows[id],
);

export const gridRowTreeSelector = createSelector(gridRowsStateSelector, (rows) => rows.tree);

/**
* @category Rows
*/
export const gridRowNodeSelector = createSelector(
gridRowTreeSelector,
(rowTree, rowId: GridRowId) => rowTree[rowId],
Expand Down
1 change: 1 addition & 0 deletions packages/x-data-grid/src/hooks/features/rows/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export {
gridRowMaximumTreeDepthSelector,
gridDataRowIdsSelector,
gridRowNodeSelector,
gridRowSelector,
} from './gridRowsSelector';
export type { GridRowsState, GridRowIdToModelLookup } from './gridRowsInterfaces';
export { GRID_ROOT_GROUP_ID, checkGridRowIdIsValid, isAutogeneratedRow } from './gridRowsUtils';
2 changes: 2 additions & 0 deletions scripts/x-data-grid-premium.exports.json
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@
{ "name": "GridRowGroupingState", "kind": "Interface" },
{ "name": "GridRowHeightParams", "kind": "Interface" },
{ "name": "GridRowHeightReturnValue", "kind": "TypeAlias" },
{ "name": "gridRowHeightSelector", "kind": "Variable" },
{ "name": "GridRowId", "kind": "TypeAlias" },
{ "name": "GridRowIdGetter", "kind": "TypeAlias" },
{ "name": "gridRowIdSelector", "kind": "Variable" },
Expand Down Expand Up @@ -594,6 +595,7 @@
{ "name": "GridRowSelectionModel", "kind": "TypeAlias" },
{ "name": "GridRowSelectionPropagation", "kind": "TypeAlias" },
{ "name": "gridRowSelectionStateSelector", "kind": "Variable" },
{ "name": "gridRowSelector", "kind": "Variable" },
{ "name": "gridRowsLoadingSelector", "kind": "Variable" },
{ "name": "gridRowsLookupSelector", "kind": "Variable" },
{ "name": "GridRowsMeta", "kind": "Interface" },
Expand Down
Loading
Loading