From 1333b0add4b3c98d4baca15a10b2aa9690d363f6 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Thu, 23 Jun 2022 14:54:13 +0200 Subject: [PATCH 01/53] doc --- .../column-groups/BasicGroupingDemo.js | 71 +++++++++++ .../column-groups/BasicGroupingDemo.tsx | 71 +++++++++++ .../BasicGroupingDemo.tsx.preview | 9 ++ .../column-groups/BreakingGroupDemo.js | 76 ++++++++++++ .../column-groups/BreakingGroupDemo.tsx | 76 ++++++++++++ .../BreakingGroupDemo.tsx.preview | 9 ++ .../column-groups/CustomizationDemo.js | 113 ++++++++++++++++++ .../column-groups/CustomizationDemo.tsx | 111 +++++++++++++++++ .../CustomizationDemo.tsx.preview | 9 ++ .../data-grid/column-groups/column-groups.md | 90 +++++++++++++- docs/data/pages.ts | 2 +- 11 files changed, 632 insertions(+), 5 deletions(-) create mode 100644 docs/data/data-grid/column-groups/BasicGroupingDemo.js create mode 100644 docs/data/data-grid/column-groups/BasicGroupingDemo.tsx create mode 100644 docs/data/data-grid/column-groups/BasicGroupingDemo.tsx.preview create mode 100644 docs/data/data-grid/column-groups/BreakingGroupDemo.js create mode 100644 docs/data/data-grid/column-groups/BreakingGroupDemo.tsx create mode 100644 docs/data/data-grid/column-groups/BreakingGroupDemo.tsx.preview create mode 100644 docs/data/data-grid/column-groups/CustomizationDemo.js create mode 100644 docs/data/data-grid/column-groups/CustomizationDemo.tsx create mode 100644 docs/data/data-grid/column-groups/CustomizationDemo.tsx.preview diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.js b/docs/data/data-grid/column-groups/BasicGroupingDemo.js new file mode 100644 index 0000000000000..5d44b45aea362 --- /dev/null +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.js @@ -0,0 +1,71 @@ +import * as React from 'react'; +import { DataGridPro } from '@mui/x-data-grid-pro'; + +const columns = [ + { field: 'id', headerName: 'ID', width: 90 }, + { + field: 'firstName', + headerName: 'First name', + width: 150, + editable: true, + }, + { + field: 'lastName', + headerName: 'Last name', + width: 150, + editable: true, + }, + { + field: 'age', + headerName: 'Age', + type: 'number', + width: 110, + editable: true, + }, +]; + +const rows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, + { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, + { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, + { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, + { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, + { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, +]; + +const columnGroupingModel = [ + { + groupId: 'internal_data', + description: '', + children: [{ field: 'id' }], + }, + { + groupId: 'perso', + children: [ + { + groupId: 'naming', + children: [{ field: 'lastName' }, { field: 'firstName' }], + }, + { field: 'age' }, + ], + }, +]; + +export default function BasicGroupingDemo() { + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx new file mode 100644 index 0000000000000..ae59ef755a29e --- /dev/null +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx @@ -0,0 +1,71 @@ +import * as React from 'react'; +import { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'; +import { GridColumnGroupingModel } from '@mui/x-data-grid/models/gridColumnGrouping'; + +const columns: GridColDef[] = [ + { field: 'id', headerName: 'ID', width: 90 }, + { + field: 'firstName', + headerName: 'First name', + width: 150, + editable: true, + }, + { + field: 'lastName', + headerName: 'Last name', + width: 150, + editable: true, + }, + { + field: 'age', + headerName: 'Age', + type: 'number', + width: 110, + editable: true, + }, +]; + +const rows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, + { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, + { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, + { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, + { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, + { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, +]; + +const columnGroupingModel: GridColumnGroupingModel = [ + { + groupId: 'internal_data', + description: '', + children: [{ field: 'id' }], + }, + { + groupId: 'perso', + children: [ + { + groupId: 'naming', + children: [{ field: 'lastName' }, { field: 'firstName' }], + }, + { field: 'age' }, + ], + }, +]; +export default function BasicGroupingDemo() { + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx.preview b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx.preview new file mode 100644 index 0000000000000..6f02df2689295 --- /dev/null +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx.preview @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.js b/docs/data/data-grid/column-groups/BreakingGroupDemo.js new file mode 100644 index 0000000000000..ebb00387cb99e --- /dev/null +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.js @@ -0,0 +1,76 @@ +import * as React from 'react'; +import { DataGridPro } from '@mui/x-data-grid-pro'; + +const columns = [ + { field: 'id', headerName: 'ID', width: 90 }, + { + field: 'firstName', + headerName: 'First name', + width: 150, + editable: true, + }, + { + field: 'lastName', + headerName: 'Last name', + width: 150, + editable: true, + }, + { + field: 'age', + headerName: 'Age', + type: 'number', + width: 110, + editable: true, + }, +]; + +const rows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, + { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, + { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, + { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, + { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, + { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, +]; + +const columnGroupingModel = [ + { + groupId: 'internal_data', + headerName: 'Internal', + description: '', + children: [{ field: 'id' }], + }, + { + groupId: 'perso', + description: 'Information about the character', + headerName: 'Character (freeReordering)', + freeReordering: true, + children: [ + { + groupId: 'naming', + headerName: 'Names', + children: [{ field: 'lastName' }, { field: 'firstName' }], + }, + { field: 'age' }, + ], + }, +]; + +export default function BreakingGroupDemo() { + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx new file mode 100644 index 0000000000000..9f85d62d4417b --- /dev/null +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx @@ -0,0 +1,76 @@ +import * as React from 'react'; +import { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'; +import { GridColumnGroupingModel } from '@mui/x-data-grid/models/gridColumnGrouping'; + +const columns: GridColDef[] = [ + { field: 'id', headerName: 'ID', width: 90 }, + { + field: 'firstName', + headerName: 'First name', + width: 150, + editable: true, + }, + { + field: 'lastName', + headerName: 'Last name', + width: 150, + editable: true, + }, + { + field: 'age', + headerName: 'Age', + type: 'number', + width: 110, + editable: true, + }, +]; + +const rows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, + { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, + { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, + { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, + { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, + { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, +]; + +const columnGroupingModel: GridColumnGroupingModel = [ + { + groupId: 'internal_data', + headerName: 'Internal', + description: '', + children: [{ field: 'id' }], + }, + { + groupId: 'perso', + description: 'Information about the character', + headerName: 'Character (freeReordering)', + freeReordering: true, + children: [ + { + groupId: 'naming', + headerName: 'Names', + children: [{ field: 'lastName' }, { field: 'firstName' }], + }, + { field: 'age' }, + ], + }, +]; +export default function BreakingGroupDemo() { + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx.preview b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx.preview new file mode 100644 index 0000000000000..6f02df2689295 --- /dev/null +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx.preview @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.js b/docs/data/data-grid/column-groups/CustomizationDemo.js new file mode 100644 index 0000000000000..67887ee2b2242 --- /dev/null +++ b/docs/data/data-grid/column-groups/CustomizationDemo.js @@ -0,0 +1,113 @@ +import * as React from 'react'; +import PropTypes from 'prop-types'; +import { styled } from '@mui/material/styles'; +import { DataGridPro } from '@mui/x-data-grid-pro'; + +import BuildIcon from '@mui/icons-material/Build'; +import PersonIcon from '@mui/icons-material/Person'; + +const columns = [ + { field: 'id', headerName: 'ID', width: 150 }, + { + field: 'firstName', + headerName: 'First name', + width: 150, + editable: true, + }, + { + field: 'lastName', + headerName: 'Last name', + width: 150, + editable: true, + }, + { + field: 'age', + headerName: 'Age', + type: 'number', + width: 110, + editable: true, + }, +]; + +const rows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, + { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, + { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, + { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, + { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, + { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, +]; + +const HeaderWithIconRoot = styled('div')(({ theme }) => ({ + overflow: 'hidden', + display: 'flex', + alignItems: 'center', + '& span': { + overflow: 'hidden', + textOverflow: 'ellipsis', + marginRight: theme.spacing(0.5), + }, +})); + +const HeaderWithIcon = (props) => { + const { icon, ...params } = props; + + return ( + + {params.headerName ?? params.groupId} {icon} + + ); +}; + +HeaderWithIcon.propTypes = { + groupId: PropTypes.string.isRequired, + headerName: PropTypes.string.isRequired, + icon: PropTypes.node, +}; + +const columnGroupingModel = [ + { + groupId: 'internal_data', + headerName: 'Internal', + description: '', + renderHeaderGroup: (params) => ( + } /> + ), + children: [{ field: 'id' }], + }, + { + groupId: 'perso', + description: 'Information about the character', + headerName: 'Character', + renderHeaderGroup: (params) => ( + } /> + ), + children: [ + { + groupId: 'naming', + headerName: 'Names', + children: [{ field: 'lastName' }, { field: 'firstName' }], + }, + { field: 'age' }, + ], + }, +]; + +export default function CustomizationDemo() { + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.tsx b/docs/data/data-grid/column-groups/CustomizationDemo.tsx new file mode 100644 index 0000000000000..4bc85df6b74af --- /dev/null +++ b/docs/data/data-grid/column-groups/CustomizationDemo.tsx @@ -0,0 +1,111 @@ +import * as React from 'react'; +import { styled } from '@mui/material/styles'; +import { + DataGridPro, + GridColDef, + GridColumnGroupHeaderParams, + GridColumnGroupingModel, +} from '@mui/x-data-grid-pro'; + +import BuildIcon from '@mui/icons-material/Build'; +import PersonIcon from '@mui/icons-material/Person'; + +const columns: GridColDef[] = [ + { field: 'id', headerName: 'ID', width: 150 }, + { + field: 'firstName', + headerName: 'First name', + width: 150, + editable: true, + }, + { + field: 'lastName', + headerName: 'Last name', + width: 150, + editable: true, + }, + { + field: 'age', + headerName: 'Age', + type: 'number', + width: 110, + editable: true, + }, +]; + +const rows = [ + { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, + { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, + { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, + { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, + { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, + { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, + { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, + { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, + { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, +]; + +interface HeaderWithIconProps extends GridColumnGroupHeaderParams { + icon: React.ReactNode; +} +const HeaderWithIconRoot = styled('div')(({ theme }) => ({ + overflow: 'hidden', + display: 'flex', + alignItems: 'center', + '& span': { + overflow: 'hidden', + textOverflow: 'ellipsis', + marginRight: theme.spacing(0.5), + }, +})); +const HeaderWithIcon = (props: HeaderWithIconProps) => { + const { icon, ...params } = props; + + return ( + + {params.headerName ?? params.groupId} {icon} + + ); +}; +const columnGroupingModel: GridColumnGroupingModel = [ + { + groupId: 'internal_data', + headerName: 'Internal', + description: '', + renderHeaderGroup: (params) => ( + } /> + ), + children: [{ field: 'id' }], + }, + { + groupId: 'perso', + description: 'Information about the character', + headerName: 'Character', + renderHeaderGroup: (params) => ( + } /> + ), + children: [ + { + groupId: 'naming', + headerName: 'Names', + children: [{ field: 'lastName' }, { field: 'firstName' }], + }, + { field: 'age' }, + ], + }, +]; +export default function CustomizationDemo() { + return ( +
+ +
+ ); +} diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.tsx.preview b/docs/data/data-grid/column-groups/CustomizationDemo.tsx.preview new file mode 100644 index 0000000000000..6f02df2689295 --- /dev/null +++ b/docs/data/data-grid/column-groups/CustomizationDemo.tsx.preview @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 5532addd39b6f..ce72217471abe 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -1,18 +1,100 @@ --- -title: Data Grid - Column groups 🚧 +title: Data Grid - Column groups --- -# Data grid - Column groups 🚧 +# Data Grid - Column groups

Group your columns.

+Grouping columns allows you to have multiple levels of columns in your header and the ability, if needed, to 'open and close' column groups to show and hide additional columns. + +## Define column grouping + +You can define the column grouping structure by providing `columnGroupingModel` prop to the data grid. +This prop receives an array of column group. + +A column group is defined by at least two variables: + +- `groupId` a string used to identify the group +- `children` an array containing the children of the group + +The children can contains two types of objects: + +- leafs with type `{ field: string }`, which add the column with the corresponding `field` to this group. +- other column groups which allows you to have nested groups. + +:::warning +Since this is a tree structure, a column can be associated to only one group. +::: + +```jsx +/* +The grouping model of +- internal + * id +- perso + - naming + * last name + * first name + * age +*/ +columnGroupingModel={[ + { + groupId: "internal", + children: [{ field: "id" }] + }, + { + groupId: "perso", + children: [ + { + groupId: "naming", + children: [ + { field: "lastName" }, + { field: "firstName" }, + ] + }, + { field: "age" } + ] + } +]} +``` + +{{"demo": "BasicGroupingDemo.js", "bg": "inline"}} + +## Customize column group + +In addition to the `groupId`, and `children` properties which are mandatory, you can add extra properties to a column group object to customize it: + +- `headerName`: the sting displayed instead of `groupId`. +- `description`: a longer string displayed in a tooltip. +- `renderHeaderGroup`: a function returning custom React component. + +{{"demo": "CustomizationDemo.js", "bg": "inline"}} + +## Column reordering [](https://mui.com/store/items/mui-x-pro/) + +By default, column groups can not be divided when reordering columns. +This default behavior can be removed on specific group by setting `freeReordering: true` in the column group object. + +In the example bellow the `Character` column group can be divided, but not other column groups + +{{"demo": "BreakingGroupDemo.js", "disableAd": true, "bg": "inline"}} + +## Manage group visibility 🚧 + :::warning This feature isn't implemented yet. It's coming. +::: + +The column group should allow to switch between an extended/collapsed view which hide/show some columns + +## Reordering groups 🚧 -👍 Upvote [issue #195](https://github.com/mui/mui-x/issues/195) if you want to see it land faster. +:::warning +This feature isn't implemented yet. It's coming. ::: -Grouping columns allows you to have multiple levels of columns in your header and the ability, if needed, to 'open and close' column groups to show and hide additional columns. +Users could drag and drop group header to move all the group children at once ## API diff --git a/docs/data/pages.ts b/docs/data/pages.ts index 17b1e20300e56..f66875fac0901 100644 --- a/docs/data/pages.ts +++ b/docs/data/pages.ts @@ -28,7 +28,7 @@ const pages: MuiPage[] = [ { pathname: '/x/react-data-grid/column-ordering' }, { pathname: '/x/react-data-grid/column-pinning', plan: 'pro' }, { pathname: '/x/react-data-grid/column-spanning' }, - { pathname: '/x/react-data-grid/column-groups', title: 'Column groups 🚧' }, + { pathname: '/x/react-data-grid/column-groups' }, ], }, { pathname: '/x/react-data-grid/rows' }, From 395030b63c353af5005a8ccf51fd3c98e5123de6 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Thu, 23 Jun 2022 14:54:37 +0200 Subject: [PATCH 02/53] scripts --- .../x/api/data-grid/data-grid-premium.json | 4 ++++ docs/pages/x/api/data-grid/data-grid-pro.json | 4 ++++ docs/pages/x/api/data-grid/data-grid.json | 4 ++++ docs/pages/x/api/data-grid/grid-api.md | 5 +++- docs/pages/x/api/data-grid/selectors.json | 24 +++++++++++++++++++ .../data-grid/data-grid-premium-pt.json | 14 +++++++++++ .../data-grid/data-grid-premium-zh.json | 14 +++++++++++ .../api-docs/data-grid/data-grid-premium.json | 14 +++++++++++ .../api-docs/data-grid/data-grid-pro-pt.json | 14 +++++++++++ .../api-docs/data-grid/data-grid-pro-zh.json | 14 +++++++++++ .../api-docs/data-grid/data-grid-pro.json | 14 +++++++++++ .../api-docs/data-grid/data-grid-pt.json | 14 +++++++++++ .../api-docs/data-grid/data-grid-zh.json | 14 +++++++++++ .../api-docs/data-grid/data-grid.json | 14 +++++++++++ scripts/x-data-grid-premium.exports.json | 12 ++++++++++ scripts/x-data-grid-pro.exports.json | 12 ++++++++++ scripts/x-data-grid.exports.json | 12 ++++++++++ 17 files changed, 202 insertions(+), 1 deletion(-) diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index 94a95fc0e825b..211d3303349f0 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -82,6 +82,7 @@ "getRowSpacing": { "type": { "name": "func" } }, "getTreeDataPath": { "type": { "name": "func" } }, "groupingColDef": { "type": { "name": "union", "description": "func
| object" } }, + "headerGroupingRowHeight": { "type": { "name": "number" }, "default": "32" }, "headerHeight": { "type": { "name": "number" }, "default": "56" }, "hideFooter": { "type": { "name": "bool" } }, "hideFooterPagination": { "type": { "name": "bool" } }, @@ -258,6 +259,7 @@ "columnHeader--sorted", "columnHeader--filtered", "columnHeader", + "columnGroupHeader", "columnHeaderCheckbox", "columnHeaderDraggableContainer", "rowReorderCellPlaceholder", @@ -265,6 +267,8 @@ "columnHeaderTitle", "columnHeaderTitleContainer", "columnHeaderTitleContainerContent", + "columnGroupHeaderTitleContainerContent", + "columnGroupHeader--withName", "columnHeaders", "columnHeadersInner", "columnHeadersInner--scrollable", diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index 7ecac8a289572..b4f414824b38a 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -81,6 +81,7 @@ "getRowSpacing": { "type": { "name": "func" } }, "getTreeDataPath": { "type": { "name": "func" } }, "groupingColDef": { "type": { "name": "union", "description": "func
| object" } }, + "headerGroupingRowHeight": { "type": { "name": "number" }, "default": "32" }, "headerHeight": { "type": { "name": "number" }, "default": "56" }, "hideFooter": { "type": { "name": "bool" } }, "hideFooterPagination": { "type": { "name": "bool" } }, @@ -325,6 +326,7 @@ "columnHeader--sorted", "columnHeader--filtered", "columnHeader", + "columnGroupHeader", "columnHeaderCheckbox", "columnHeaderDraggableContainer", "rowReorderCellPlaceholder", @@ -332,6 +334,8 @@ "columnHeaderTitle", "columnHeaderTitleContainer", "columnHeaderTitleContainerContent", + "columnGroupHeaderTitleContainerContent", + "columnGroupHeader--withName", "columnHeaders", "columnHeadersInner", "columnHeadersInner--scrollable", diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 7c26938663fc4..59e97a0a69378 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -58,6 +58,7 @@ "getRowHeight": { "type": { "name": "func" } }, "getRowId": { "type": { "name": "func" } }, "getRowSpacing": { "type": { "name": "func" } }, + "headerGroupingRowHeight": { "type": { "name": "number" }, "default": "32" }, "headerHeight": { "type": { "name": "number" }, "default": "56" }, "hideFooter": { "type": { "name": "bool" } }, "hideFooterPagination": { "type": { "name": "bool" } }, @@ -280,6 +281,7 @@ "columnHeader--sorted", "columnHeader--filtered", "columnHeader", + "columnGroupHeader", "columnHeaderCheckbox", "columnHeaderDraggableContainer", "rowReorderCellPlaceholder", @@ -287,6 +289,8 @@ "columnHeaderTitle", "columnHeaderTitleContainer", "columnHeaderTitleContainerContent", + "columnGroupHeaderTitleContainerContent", + "columnGroupHeader--withName", "columnHeaders", "columnHeadersInner", "columnHeadersInner--scrollable", diff --git a/docs/pages/x/api/data-grid/grid-api.md b/docs/pages/x/api/data-grid/grid-api.md index 5a5f352ef47ec..f3eff6b12b1af 100644 --- a/docs/pages/x/api/data-grid/grid-api.md +++ b/docs/pages/x/api/data-grid/grid-api.md @@ -25,12 +25,14 @@ import { GridApi } from '@mui/x-data-grid-pro'; | exportState | () => InitialState | Generates a serializable object containing the exportable parts of the DataGrid state.
These values can then be passed to the `initialState` prop or injected using the `restoreState` method. | | forceUpdate | () => void | Forces the grid to rerender. It's often used after a state update. | | getAllColumns | () => GridStateColDef[] | Returns an array of [GridColDef](/x/api/data-grid/grid-col-def/) containing all the column definitions. | +| getAllGroupDetails | () => GridColumnGroupLookup | Returns the column group lookup. | | getAllRowIds | () => GridRowId[] | Gets the list of row ids. | | getCellElement | (id: GridRowId, field: string) => HTMLDivElement \| null | Gets the underlying DOM element for a cell at the given `id` and `field`. | | getCellMode | (id: GridRowId, field: string) => GridCellMode | Gets the mode of a cell. | | getCellParams | <V = any, R extends GridValidRowModel = any, F = V>(id: GridRowId, field: string) => GridCellParams<R, V, F> | Gets the [GridCellParams](/x/api/data-grid/grid-cell-params/) object that is passed as argument in events. | | getCellValue | <V extends any = any>(id: GridRowId, field: string) => V | Gets the value of a cell at the given `id` and `field`. | | getColumn | (field: string) => GridStateColDef | Returns the [GridColDef](/x/api/data-grid/grid-col-def/) for the given `field`. | +| getColumnGroupPath | (field: string) => GridColumnGroup['groupId'][] | Returns the array of groupId applied on the column `field`. | | getColumnHeaderElement | (field: string) => HTMLDivElement \| null | Gets the underlying DOM element for the column header with the given `field`. | | getColumnHeaderParams | (field: string) => GridColumnHeaderParams | Gets the GridColumnHeaderParams object that is passed as argument in events. | | getColumnIndex | (field: string, useVisibleColumns?: boolean) => number | Returns the index position of a column. By default, only the visible columns are considered.
Pass `false` to `useVisibleColumns` to consider all columns. | @@ -40,6 +42,7 @@ import { GridApi } from '@mui/x-data-grid-pro'; | getDataAsExcel [](https://mui.com/store/items/material-ui-premium/) | (options?: GridExcelExportOptions) => Promise<Excel.Workbook> \| null | Returns the grid data as an exceljs workbook.
This method is used internally by `exportDataAsExcel`. | | getEditRowsModel | () => GridEditRowsModel | Gets the edit rows model of the grid. | | getExpandedDetailPanels [](https://mui.com/store/items/mui-x-pro/) | () => GridRowId[] | Returns the rows whose detail panel is open. | +| getGroupDetails | (groupId: string) => Omit<GridColumnGroup, 'children'> \| null | Returns the details about a group corresponding to `groupId`. | | getLocaleText | <T extends GridTranslationKeys>(key: T) => GridLocaleText[T] | Returns the translation for the `key`. | | getPinnedColumns [](https://mui.com/store/items/mui-x-pro/) | () => GridPinnedColumns | Returns which columns are pinned. | | getRootDimensions | () => GridDimensions \| null | Returns the dimensions of the grid | @@ -84,7 +87,7 @@ import { GridApi } from '@mui/x-data-grid-pro'; | setColumnVisibility | (field: string, isVisible: boolean) => void | Changes the visibility of the column referred by `field`. | | setColumnVisibilityModel | (model: GridColumnVisibilityModel) => void | Sets the column visibility model to the one given by `model`. | | setColumnWidth | (field: string, width: number) => void | Updates the width of a column. | -| setDensity | (density: GridDensity, headerHeight?: number, rowHeight?: number) => void | Sets the density of the grid. | +| setDensity | (density: GridDensity, headerHeight?: number, rowHeight?: number, maxDepth?: number, headerGroupingRowHeight?: number) => void | Sets the density of the grid. | | setEditCellValue | (params: GridEditCellValueParams, event?: MuiBaseEvent) => Promise<boolean> \| void | Sets the value of the edit cell.
Commonly used inside the edit cell component. | | setEditRowsModel | (model: GridEditRowsModel) => void | Set the edit rows model of the grid. | | setExpandedDetailPanels [](https://mui.com/store/items/mui-x-pro/) | (ids: GridRowId[]) => void | Changes which rows to expand the detail panel. | diff --git a/docs/pages/x/api/data-grid/selectors.json b/docs/pages/x/api/data-grid/selectors.json index 06f1b15562e0b..961da78669f2c 100644 --- a/docs/pages/x/api/data-grid/selectors.json +++ b/docs/pages/x/api/data-grid/selectors.json @@ -13,6 +13,12 @@ "description": "Get the field of each column.", "supportsApiRef": true }, + { + "name": "gridColumnGroupsLookupSelector", + "returnType": "GridColumnGroupLookup", + "description": "", + "supportsApiRef": true + }, { "name": "gridColumnLookupSelector", "returnType": "GridColumnLookup", @@ -71,6 +77,18 @@ "description": "", "supportsApiRef": true }, + { + "name": "gridDensityHeaderGroupingMaxDepthSelector", + "returnType": "number", + "description": "", + "supportsApiRef": true + }, + { + "name": "gridDensityHeaderGroupingRowHeightSelector", + "returnType": "number", + "description": "", + "supportsApiRef": true + }, { "name": "gridDensityHeaderHeightSelector", "returnType": "number", @@ -89,6 +107,12 @@ "description": "", "supportsApiRef": false }, + { + "name": "gridDensityTotalHeaderHeightSelector", + "returnType": "number", + "description": "", + "supportsApiRef": true + }, { "name": "gridDensityValueSelector", "returnType": "GridDensity", diff --git a/docs/translations/api-docs/data-grid/data-grid-premium-pt.json b/docs/translations/api-docs/data-grid/data-grid-premium-pt.json index bb3e97ca3b0c9..098fa29991248 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium-pt.json @@ -52,6 +52,7 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -246,6 +247,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -272,6 +277,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-premium-zh.json b/docs/translations/api-docs/data-grid/data-grid-premium-zh.json index bb3e97ca3b0c9..098fa29991248 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium-zh.json @@ -52,6 +52,7 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -246,6 +247,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -272,6 +277,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium.json index bb3e97ca3b0c9..098fa29991248 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium.json @@ -52,6 +52,7 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -246,6 +247,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -272,6 +277,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json index c9d1cf250b698..c7e252f555d5d 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json @@ -51,6 +51,7 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -242,6 +243,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -268,6 +273,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json index c9d1cf250b698..c7e252f555d5d 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json @@ -51,6 +51,7 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -242,6 +243,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -268,6 +273,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro.json index c9d1cf250b698..c7e252f555d5d 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro.json @@ -51,6 +51,7 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -242,6 +243,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -268,6 +273,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-pt.json b/docs/translations/api-docs/data-grid/data-grid-pt.json index 2a4758e187d3f..91fd00b395766 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pt.json @@ -36,6 +36,7 @@ "getRowHeight": "Function that sets the row height per row.

Signature:
function(params: GridRowHeightParams) => GridRowHeightReturnValue
params: With all properties from GridRowHeightParams.
returns (GridRowHeightReturnValue): The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content.", "getRowId": "Return the id of a given GridRowModel.", "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -213,6 +214,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -239,6 +244,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-zh.json b/docs/translations/api-docs/data-grid/data-grid-zh.json index 2a4758e187d3f..91fd00b395766 100644 --- a/docs/translations/api-docs/data-grid/data-grid-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-zh.json @@ -36,6 +36,7 @@ "getRowHeight": "Function that sets the row height per row.

Signature:
function(params: GridRowHeightParams) => GridRowHeightReturnValue
params: With all properties from GridRowHeightParams.
returns (GridRowHeightReturnValue): The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content.", "getRowId": "Return the id of a given GridRowModel.", "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -213,6 +214,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -239,6 +244,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid.json index 2a4758e187d3f..91fd00b395766 100644 --- a/docs/translations/api-docs/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid.json @@ -36,6 +36,7 @@ "getRowHeight": "Function that sets the row height per row.

Signature:
function(params: GridRowHeightParams) => GridRowHeightReturnValue
params: With all properties from GridRowHeightParams.
returns (GridRowHeightReturnValue): The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content.", "getRowId": "Return the id of a given GridRowModel.", "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", + "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", @@ -213,6 +214,10 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header element" }, + "columnGroupHeader": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header element" + }, "columnHeaderCheckbox": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the header checkbox cell element" @@ -239,6 +244,15 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, + "columnGroupHeaderTitleContainerContent": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the column group header's title excepted buttons" + }, + "columnGroupHeader--withName": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "not empty" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index 19489ce4cd1bc..a564558a51336 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -107,6 +107,11 @@ { "name": "GridColumnApi", "kind": "Interface" }, { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, + { "name": "GridColumnGroup", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderParams", "kind": "TypeAlias" }, + { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, + { "name": "gridColumnGroupingSelector", "kind": "Variable" }, + { "name": "gridColumnGroupsLookupSelector", "kind": "Variable" }, { "name": "GridColumnHeaderClassFn", "kind": "TypeAlias" }, { "name": "GridColumnHeaderClassNamePropType", "kind": "TypeAlias" }, { "name": "GridColumnHeaderEventLookup", "kind": "Interface" }, @@ -133,6 +138,7 @@ { "name": "GridColumnMenuProps", "kind": "Interface" }, { "name": "gridColumnMenuSelector", "kind": "Variable" }, { "name": "GridColumnMenuState", "kind": "Interface" }, + { "name": "GridColumnNode", "kind": "TypeAlias" }, { "name": "GridColumnOrderChangeParams", "kind": "Interface" }, { "name": "GridColumnPinningApi", "kind": "Interface" }, { "name": "GridColumnPinningInternalCache", "kind": "Interface" }, @@ -146,6 +152,7 @@ { "name": "gridColumnResizeSelector", "kind": "Variable" }, { "name": "GridColumnResizeState", "kind": "Interface" }, { "name": "GridColumns", "kind": "TypeAlias" }, + { "name": "GridColumnsGroupingState", "kind": "Interface" }, { "name": "GridColumnsInitialState", "kind": "Interface" }, { "name": "GridColumnsMenuItem", "kind": "Variable" }, { "name": "GridColumnsMeta", "kind": "Interface" }, @@ -176,11 +183,14 @@ { "name": "GridDensity", "kind": "TypeAlias" }, { "name": "GridDensityApi", "kind": "Interface" }, { "name": "gridDensityFactorSelector", "kind": "Variable" }, + { "name": "gridDensityHeaderGroupingMaxDepthSelector", "kind": "Variable" }, + { "name": "gridDensityHeaderGroupingRowHeightSelector", "kind": "Variable" }, { "name": "gridDensityHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityOption", "kind": "Interface" }, { "name": "gridDensityRowHeightSelector", "kind": "Variable" }, { "name": "gridDensitySelector", "kind": "Variable" }, { "name": "GridDensityState", "kind": "Interface" }, + { "name": "gridDensityTotalHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityTypes", "kind": "Enum" }, { "name": "gridDensityValueSelector", "kind": "Variable" }, { "name": "GridDetailPanelApi", "kind": "Interface" }, @@ -492,9 +502,11 @@ { "name": "heIL", "kind": "Variable" }, { "name": "HideGridColMenuItem", "kind": "Variable" }, { "name": "huHU", "kind": "Variable" }, + { "name": "isLeaf", "kind": "Function" }, { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, + { "name": "LeafColumn", "kind": "TypeAlias" }, { "name": "LicenseInfo", "kind": "Class" }, { "name": "Logger", "kind": "Interface" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 365966358d4e6..05191842f09d8 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -104,6 +104,11 @@ { "name": "GridColumnApi", "kind": "Interface" }, { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, + { "name": "GridColumnGroup", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderParams", "kind": "TypeAlias" }, + { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, + { "name": "gridColumnGroupingSelector", "kind": "Variable" }, + { "name": "gridColumnGroupsLookupSelector", "kind": "Variable" }, { "name": "GridColumnHeaderClassFn", "kind": "TypeAlias" }, { "name": "GridColumnHeaderClassNamePropType", "kind": "TypeAlias" }, { "name": "GridColumnHeaderEventLookup", "kind": "Interface" }, @@ -130,6 +135,7 @@ { "name": "GridColumnMenuProps", "kind": "Interface" }, { "name": "gridColumnMenuSelector", "kind": "Variable" }, { "name": "GridColumnMenuState", "kind": "Interface" }, + { "name": "GridColumnNode", "kind": "TypeAlias" }, { "name": "GridColumnOrderChangeParams", "kind": "Interface" }, { "name": "GridColumnPinningApi", "kind": "Interface" }, { "name": "GridColumnPinningInternalCache", "kind": "Interface" }, @@ -143,6 +149,7 @@ { "name": "gridColumnResizeSelector", "kind": "Variable" }, { "name": "GridColumnResizeState", "kind": "Interface" }, { "name": "GridColumns", "kind": "TypeAlias" }, + { "name": "GridColumnsGroupingState", "kind": "Interface" }, { "name": "GridColumnsInitialState", "kind": "Interface" }, { "name": "GridColumnsMenuItem", "kind": "Variable" }, { "name": "GridColumnsMeta", "kind": "Interface" }, @@ -173,11 +180,14 @@ { "name": "GridDensity", "kind": "TypeAlias" }, { "name": "GridDensityApi", "kind": "Interface" }, { "name": "gridDensityFactorSelector", "kind": "Variable" }, + { "name": "gridDensityHeaderGroupingMaxDepthSelector", "kind": "Variable" }, + { "name": "gridDensityHeaderGroupingRowHeightSelector", "kind": "Variable" }, { "name": "gridDensityHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityOption", "kind": "Interface" }, { "name": "gridDensityRowHeightSelector", "kind": "Variable" }, { "name": "gridDensitySelector", "kind": "Variable" }, { "name": "GridDensityState", "kind": "Interface" }, + { "name": "gridDensityTotalHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityTypes", "kind": "Enum" }, { "name": "gridDensityValueSelector", "kind": "Variable" }, { "name": "GridDetailPanelApi", "kind": "Interface" }, @@ -475,9 +485,11 @@ { "name": "heIL", "kind": "Variable" }, { "name": "HideGridColMenuItem", "kind": "Variable" }, { "name": "huHU", "kind": "Variable" }, + { "name": "isLeaf", "kind": "Function" }, { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, + { "name": "LeafColumn", "kind": "TypeAlias" }, { "name": "LicenseInfo", "kind": "Class" }, { "name": "Logger", "kind": "Interface" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 5225077b4dee8..47b5962eb5016 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -99,6 +99,11 @@ { "name": "GridColumnApi", "kind": "Interface" }, { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, + { "name": "GridColumnGroup", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderParams", "kind": "TypeAlias" }, + { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, + { "name": "gridColumnGroupingSelector", "kind": "Variable" }, + { "name": "gridColumnGroupsLookupSelector", "kind": "Variable" }, { "name": "GridColumnHeaderClassFn", "kind": "TypeAlias" }, { "name": "GridColumnHeaderClassNamePropType", "kind": "TypeAlias" }, { "name": "GridColumnHeaderEventLookup", "kind": "Interface" }, @@ -125,10 +130,12 @@ { "name": "GridColumnMenuProps", "kind": "Interface" }, { "name": "gridColumnMenuSelector", "kind": "Variable" }, { "name": "GridColumnMenuState", "kind": "Interface" }, + { "name": "GridColumnNode", "kind": "TypeAlias" }, { "name": "GridColumnOrderChangeParams", "kind": "Interface" }, { "name": "gridColumnPositionsSelector", "kind": "Variable" }, { "name": "GridColumnResizeParams", "kind": "Interface" }, { "name": "GridColumns", "kind": "TypeAlias" }, + { "name": "GridColumnsGroupingState", "kind": "Interface" }, { "name": "GridColumnsInitialState", "kind": "Interface" }, { "name": "GridColumnsMenuItem", "kind": "Variable" }, { "name": "GridColumnsMeta", "kind": "Interface" }, @@ -159,11 +166,14 @@ { "name": "GridDensity", "kind": "TypeAlias" }, { "name": "GridDensityApi", "kind": "Interface" }, { "name": "gridDensityFactorSelector", "kind": "Variable" }, + { "name": "gridDensityHeaderGroupingMaxDepthSelector", "kind": "Variable" }, + { "name": "gridDensityHeaderGroupingRowHeightSelector", "kind": "Variable" }, { "name": "gridDensityHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityOption", "kind": "Interface" }, { "name": "gridDensityRowHeightSelector", "kind": "Variable" }, { "name": "gridDensitySelector", "kind": "Variable" }, { "name": "GridDensityState", "kind": "Interface" }, + { "name": "gridDensityTotalHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityTypes", "kind": "Enum" }, { "name": "gridDensityValueSelector", "kind": "Variable" }, { "name": "GridDimensions", "kind": "Interface" }, @@ -445,9 +455,11 @@ { "name": "heIL", "kind": "Variable" }, { "name": "HideGridColMenuItem", "kind": "Variable" }, { "name": "huHU", "kind": "Variable" }, + { "name": "isLeaf", "kind": "Function" }, { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, + { "name": "LeafColumn", "kind": "TypeAlias" }, { "name": "Logger", "kind": "Interface" }, { "name": "MAX_PAGE_SIZE", "kind": "Variable" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, From 4c513de8c6074eca2cc5fa0bbe3b7519859c3b2e Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Thu, 23 Jun 2022 14:58:10 +0200 Subject: [PATCH 03/53] first implementation --- .../src/DataGridPremium/DataGridPremium.tsx | 23 ++ .../src/DataGridPro/DataGridPro.tsx | 23 ++ .../DataGridPro/useDataGridProComponent.tsx | 4 + .../components/DataGridProColumnHeaders.tsx | 38 ++- .../columnReorder/useGridColumnReorder.tsx | 70 +++++ .../columnResize/useGridColumnResize.tsx | 15 +- .../x-data-grid/src/DataGrid/DataGrid.tsx | 23 ++ .../src/DataGrid/useDataGridComponent.tsx | 6 + .../src/DataGrid/useDataGridProps.ts | 1 + .../src/components/DataGridColumnHeaders.tsx | 10 +- .../x-data-grid/src/components/GridRow.tsx | 5 +- .../src/components/base/GridBody.tsx | 8 +- .../src/components/base/GridOverlays.tsx | 6 +- .../columnHeaders/GridColumnGroupHeader.tsx | 124 +++++++++ .../columnHeaders/GridColumnHeadersInner.tsx | 3 +- .../src/components/containers/GridRoot.tsx | 8 +- .../components/containers/GridRootStyles.ts | 23 +- .../x-data-grid/src/constants/gridClasses.ts | 15 ++ .../columnHeaders/useGridColumnHeaders.tsx | 239 +++++++++++++++++- .../features/columns/gridColumnsInterfaces.ts | 14 + .../features/columns/gridColumnsSelector.ts | 11 + .../src/hooks/features/columns/index.ts | 1 + .../features/columns/useGridColumnGrouping.ts | 212 ++++++++++++++++ .../hooks/features/density/densitySelector.ts | 16 ++ .../hooks/features/density/densityState.ts | 2 + .../hooks/features/density/useGridDensity.tsx | 104 +++++++- .../features/dimensions/useGridDimensions.ts | 8 +- .../features/export/useGridPrintExport.tsx | 6 +- .../grid/x-data-grid/src/internals/index.ts | 4 + .../src/models/api/gridApiCommon.ts | 4 +- .../src/models/api/gridColumnGroupingApi.ts | 25 ++ .../src/models/api/gridDensityApi.ts | 10 +- .../src/models/colDef/gridColDef.ts | 5 + .../src/models/gridColumnGrouping.ts | 54 ++++ .../src/models/gridStateCommunity.ts | 2 + packages/grid/x-data-grid/src/models/index.ts | 1 + .../src/models/props/DataGridProps.ts | 8 + 37 files changed, 1075 insertions(+), 56 deletions(-) create mode 100644 packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx create mode 100644 packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts create mode 100644 packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts create mode 100644 packages/grid/x-data-grid/src/models/gridColumnGrouping.ts diff --git a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index bfd8d17870383..97d9b870d70f5 100644 --- a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -118,6 +118,23 @@ DataGridPremiumRaw.propTypes = { * @default 3 */ columnBuffer: PropTypes.number, + columnGroupingModel: PropTypes.arrayOf( + PropTypes.shape({ + children: PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.object, + PropTypes.shape({ + field: PropTypes.string.isRequired, + }), + ]).isRequired, + ).isRequired, + description: PropTypes.string, + freeReordering: PropTypes.bool, + groupId: PropTypes.string.isRequired, + headerName: PropTypes.string, + renderHeaderGroup: PropTypes.func, + }), + ), /** * Set of columns of type [[GridColumns]]. */ @@ -354,6 +371,12 @@ DataGridPremiumRaw.propTypes = { * The grouping column used by the tree data. */ groupingColDef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + /** + * The height of a row of grouping column headers. + * TODO: choose correctly this value + * @default 32 + */ + headerGroupingRowHeight: PropTypes.number, /** * Set the height in pixel of the column headers in the grid. * @default 56 diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index cb9b69285fa17..7dbe240a3a4ed 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -115,6 +115,23 @@ DataGridProRaw.propTypes = { * @default 3 */ columnBuffer: PropTypes.number, + columnGroupingModel: PropTypes.arrayOf( + PropTypes.shape({ + children: PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.object, + PropTypes.shape({ + field: PropTypes.string.isRequired, + }), + ]).isRequired, + ).isRequired, + description: PropTypes.string, + freeReordering: PropTypes.bool, + groupId: PropTypes.string.isRequired, + headerName: PropTypes.string, + renderHeaderGroup: PropTypes.func, + }), + ), /** * Set of columns of type [[GridColumns]]. */ @@ -346,6 +363,12 @@ DataGridProRaw.propTypes = { * The grouping column used by the tree data. */ groupingColDef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), + /** + * The height of a row of grouping column headers. + * TODO: choose correctly this value + * @default 32 + */ + headerGroupingRowHeight: PropTypes.number, /** * Set the height in pixel of the column headers in the grid. * @default 56 diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx index 0cfa03c235052..a4a31168d98e9 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx @@ -40,6 +40,8 @@ import { preferencePanelStateInitializer, rowsMetaStateInitializer, selectionStateInitializer, + useGridColumnGrouping, + columnGroupsStateInitializer, } from '@mui/x-data-grid/internals'; import { GridApiPro } from '../models/gridApiPro'; import { DataGridProProcessedProps } from '../models/dataGridProProps'; @@ -111,6 +113,7 @@ export const useDataGridProComponent = ( useGridInitializeState(paginationStateInitializer, apiRef, props); useGridInitializeState(rowsMetaStateInitializer, apiRef, props); useGridInitializeState(columnMenuStateInitializer, apiRef, props); + useGridInitializeState(columnGroupsStateInitializer, apiRef, props); useGridTreeData(apiRef); useGridKeyboardNavigation(apiRef, props); @@ -121,6 +124,7 @@ export const useDataGridProComponent = ( useGridParamsApi(apiRef); useGridDetailPanel(apiRef, props); useGridColumnSpanning(apiRef); + useGridColumnGrouping(apiRef, props); const useGridEditing = props.experimentalFeatures?.newEditingApi ? useGridEditing_new diff --git a/packages/grid/x-data-grid-pro/src/components/DataGridProColumnHeaders.tsx b/packages/grid/x-data-grid-pro/src/components/DataGridProColumnHeaders.tsx index 52a41ecf67ea1..2006b658bb244 100644 --- a/packages/grid/x-data-grid-pro/src/components/DataGridProColumnHeaders.tsx +++ b/packages/grid/x-data-grid-pro/src/components/DataGridProColumnHeaders.tsx @@ -77,6 +77,7 @@ const GridColumnHeadersPinnedColumnHeaders = styled('div', { height: '100%', zIndex: 1, display: 'flex', + flexDirection: 'column', boxShadow: theme.shadows[2], backgroundColor: theme.palette.background.default, ...(theme.palette.mode === 'dark' && { @@ -120,11 +121,17 @@ export const DataGridProColumnHeaders = React.forwardRef< const pinnedColumns = useGridSelector(apiRef, gridPinnedColumnsSelector); const [leftPinnedColumns, rightPinnedColumns] = filterColumns(pinnedColumns, visibleColumnFields); - const { isDragging, renderContext, getRootProps, getInnerProps, getColumns } = - useGridColumnHeaders({ - innerRef, - minColumnIndex: leftPinnedColumns.length, - }); + const { + isDragging, + renderContext, + getRootProps, + getInnerProps, + getColumnsHeader, + getColumnsHeaderGroups, + } = useGridColumnHeaders({ + innerRef, + minColumnIndex: leftPinnedColumns.length, + }); const ownerState = { leftPinnedColumns, rightPinnedColumns, classes: rootProps.classes }; const classes = useUtilityClasses(ownerState); @@ -154,7 +161,12 @@ export const DataGridProColumnHeaders = React.forwardRef< className={classes.leftPinnedColumns} ownerState={{ side: GridPinnedPosition.left }} > - {getColumns( + {getColumnsHeaderGroups({ + renderContext: leftRenderContext, + minFirstColumn: leftRenderContext.firstColumnIndex, + maxLastColumn: leftRenderContext.lastColumnIndex, + })} + {getColumnsHeader( { renderContext: leftRenderContext, minFirstColumn: leftRenderContext.firstColumnIndex, @@ -165,7 +177,12 @@ export const DataGridProColumnHeaders = React.forwardRef< )} - {getColumns({ + {getColumnsHeaderGroups({ + renderContext, + minFirstColumn: leftPinnedColumns.length, + maxLastColumn: visibleColumnFields.length - rightPinnedColumns.length, + })} + {getColumnsHeader({ renderContext, minFirstColumn: leftPinnedColumns.length, maxLastColumn: visibleColumnFields.length - rightPinnedColumns.length, @@ -177,7 +194,12 @@ export const DataGridProColumnHeaders = React.forwardRef< className={classes.rightPinnedColumns} style={{ paddingRight: scrollbarSize }} > - {getColumns( + {getColumnsHeaderGroups({ + renderContext: rightRenderContext, + minFirstColumn: rightRenderContext.firstColumnIndex, + maxLastColumn: rightRenderContext.lastColumnIndex, + })} + {getColumnsHeader( { renderContext: rightRenderContext, minFirstColumn: rightRenderContext.firstColumnIndex, diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx index 673afb7bd7655..b4700de78cb85 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -62,6 +62,7 @@ export const useGridColumnReorder = ( y: 0, }); const originColumnIndex = React.useRef(null); + const forbiddenIndexes = React.useRef<{ [key: number]: boolean }>({}); const removeDnDStylesTimeout = React.useRef(); const ownerState = { classes: props.classes }; const classes = useUtilityClasses(ownerState); @@ -97,6 +98,71 @@ export const useGridColumnReorder = ( }); originColumnIndex.current = apiRef.current.getColumnIndex(params.field, false); + + const draggingColumnGroupPath = apiRef.current.getColumnGroupPath(params.field); + if (draggingColumnGroupPath.length === 0) { + forbiddenIndexes.current = {}; + return; + } + const visibleColumnIndex = apiRef.current.getColumnIndex(params.field, true); + const visibleColumns = apiRef.current.getVisibleColumns(); + const groupsLookup = apiRef.current.getAllGroupDetails(); + + let limitingGroupId: string | null = null; + + draggingColumnGroupPath.forEach((groupId) => { + if (!groupsLookup[groupId]?.freeReordering) { + // Only consider group that are made of more than one column + if ( + visibleColumnIndex > 0 && + visibleColumns[visibleColumnIndex - 1].groupPath?.includes(groupId) + ) { + limitingGroupId = groupId; + } else if ( + visibleColumnIndex + 1 < visibleColumns.length && + visibleColumns[visibleColumnIndex + 1].groupPath?.includes(groupId) + ) { + limitingGroupId = groupId; + } + } + }); + + forbiddenIndexes.current = {}; + + for (let indexToForbid = 0; indexToForbid < visibleColumns.length; indexToForbid += 1) { + const leftIndex = indexToForbid <= visibleColumnIndex ? indexToForbid - 1 : indexToForbid; + const rightIndex = indexToForbid < visibleColumnIndex ? indexToForbid : indexToForbid + 1; + + if (limitingGroupId !== null) { + // verify this indexToForbid will be linked to the limiting group. Otherwise forbid it + let allowIndex = false; + if (leftIndex >= 0 && visibleColumns[leftIndex].groupPath?.includes(limitingGroupId!)) { + allowIndex = true; + } else if ( + rightIndex < visibleColumns.length && + visibleColumns[rightIndex].groupPath?.includes(limitingGroupId!) + ) { + allowIndex = true; + } + if (!allowIndex) { + forbiddenIndexes.current[indexToForbid] = true; + } + } + + // Verify we are not splitting another group + if (leftIndex >= 0 && rightIndex < visibleColumns.length) { + visibleColumns[rightIndex]?.groupPath?.forEach((groupId) => { + if (visibleColumns[leftIndex].groupPath?.includes(groupId)) { + if (!draggingColumnGroupPath.includes(groupId)) { + // moving here split the group groupId in two distincts chunks + if (!groupsLookup[groupId]?.freeReordering) { + forbiddenIndexes.current[indexToForbid] = true; + } + } + } + }); + } + } }, [props.disableColumnReorder, classes.columnHeaderDragging, logger, apiRef], ); @@ -156,6 +222,10 @@ export const useGridColumnReorder = ( !visibleColumns[targetColIndex + 1].disableReorder; } + if (forbiddenIndexes.current[targetColIndex]) { + canBeReordered = false; + } + const canBeReorderedProcessed = apiRef.current.unstable_applyPipeProcessors( 'canBeReordered', canBeReordered, diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnResize/useGridColumnResize.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnResize/useGridColumnResize.tsx index adb2fd329b9f2..3dfaf9cb75366 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnResize/useGridColumnResize.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnResize/useGridColumnResize.tsx @@ -132,6 +132,7 @@ export const useGridColumnResize = ( const colDefRef = React.useRef(); const colElementRef = React.useRef(); + const colGroupingElementRef = React.useRef(); const colCellElementsRef = React.useRef(); const theme = useTheme(); @@ -158,7 +159,7 @@ export const useGridColumnResize = ( colElementRef.current!.style.minWidth = `${newWidth}px`; colElementRef.current!.style.maxWidth = `${newWidth}px`; - colCellElementsRef.current!.forEach((element) => { + [...colCellElementsRef.current!, ...colGroupingElementRef.current!].forEach((element) => { const div = element as HTMLDivElement; let finalWidth: `${number}px`; @@ -252,6 +253,12 @@ export const useGridColumnResize = ( `[data-field="${colDef.field}"]`, )!; + colGroupingElementRef.current = Array.from( + apiRef.current.columnHeadersContainerElementRef?.current!.querySelectorAll( + `[data-fields~="${colDef.field}"]`, + ) ?? [], + ); + colCellElementsRef.current = findGridCellElementsFromCol( colElementRef.current, apiRef.current, @@ -351,6 +358,12 @@ export const useGridColumnResize = ( const field = getFieldFromHeaderElem(colElementRef.current!); const colDef = apiRef.current.getColumn(field); + colGroupingElementRef.current = Array.from( + apiRef.current.columnHeadersContainerElementRef?.current!.querySelectorAll( + `[data-fields~="${colDef.field}"]`, + ) ?? [], + ); + logger.debug(`Start Resize on col ${colDef.field}`); apiRef.current.publishEvent('columnResizeStart', { field }, event); diff --git a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx index 3449052ee4897..3d134f97f85d2 100644 --- a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx @@ -89,6 +89,23 @@ DataGridRaw.propTypes = { * @default 3 */ columnBuffer: PropTypes.number, + columnGroupingModel: PropTypes.arrayOf( + PropTypes.shape({ + children: PropTypes.arrayOf( + PropTypes.oneOfType([ + PropTypes.object, + PropTypes.shape({ + field: PropTypes.string.isRequired, + }), + ]).isRequired, + ).isRequired, + description: PropTypes.string, + freeReordering: PropTypes.bool, + groupId: PropTypes.string.isRequired, + headerName: PropTypes.string, + renderHeaderGroup: PropTypes.func, + }), + ), /** * Set of columns of type [[GridColumns]]. */ @@ -254,6 +271,12 @@ DataGridRaw.propTypes = { * @returns {GridRowSpacing} The row spacing values. */ getRowSpacing: PropTypes.func, + /** + * The height of a row of grouping column headers. + * TODO: choose correctly this value + * @default 32 + */ + headerGroupingRowHeight: PropTypes.number, /** * Set the height in pixel of the column headers in the grid. * @default 56 diff --git a/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx b/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx index e24ad4e4665b2..d7d4d88752f64 100644 --- a/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx @@ -45,6 +45,10 @@ import { useGridDimensions } from '../hooks/features/dimensions/useGridDimension import { rowsMetaStateInitializer, useGridRowsMeta } from '../hooks/features/rows/useGridRowsMeta'; import { useGridStatePersistence } from '../hooks/features/statePersistence/useGridStatePersistence'; import { useGridColumnSpanning } from '../hooks/features/columns/useGridColumnSpanning'; +import { + useGridColumnGrouping, + columnGroupsStateInitializer, +} from '../hooks/features/columns/useGridColumnGrouping'; export const useDataGridComponent = (props: DataGridProcessedProps) => { const apiRef = useGridInitialization(undefined, props); @@ -60,6 +64,7 @@ export const useDataGridComponent = (props: DataGridProcessedProps) => { */ useGridInitializeState(selectionStateInitializer, apiRef, props); useGridInitializeState(columnsStateInitializer, apiRef, props); + useGridInitializeState(columnGroupsStateInitializer, apiRef, props); useGridInitializeState(rowsStateInitializer, apiRef, props); useGridInitializeState( props.experimentalFeatures?.newEditingApi @@ -83,6 +88,7 @@ export const useDataGridComponent = (props: DataGridProcessedProps) => { useGridRows(apiRef, props); useGridParamsApi(apiRef); useGridColumnSpanning(apiRef); + useGridColumnGrouping(apiRef, props); const useGridEditing = props.experimentalFeatures?.newEditingApi ? useGridEditing_new diff --git a/packages/grid/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/grid/x-data-grid/src/DataGrid/useDataGridProps.ts index 512386740ba73..edb356e389744 100644 --- a/packages/grid/x-data-grid/src/DataGrid/useDataGridProps.ts +++ b/packages/grid/x-data-grid/src/DataGrid/useDataGridProps.ts @@ -76,6 +76,7 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { disableColumnReorder: false, disableColumnResize: false, keepNonExistentRowsSelected: false, + headerGroupingRowHeight: 40, }; export const useDataGridProps = (inProps: DataGridProps) => { diff --git a/packages/grid/x-data-grid/src/components/DataGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/components/DataGridColumnHeaders.tsx index 5ceac2efb1ae2..3279611e5f67a 100644 --- a/packages/grid/x-data-grid/src/components/DataGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/components/DataGridColumnHeaders.tsx @@ -12,15 +12,17 @@ export const DataGridColumnHeaders = React.forwardRef - {getColumns()} + {getColumnsHeaderGroups()} + {getColumnsHeader()} diff --git a/packages/grid/x-data-grid/src/components/GridRow.tsx b/packages/grid/x-data-grid/src/components/GridRow.tsx index d6eb783d60722..a14c70214defd 100644 --- a/packages/grid/x-data-grid/src/components/GridRow.tsx +++ b/packages/grid/x-data-grid/src/components/GridRow.tsx @@ -29,6 +29,7 @@ import { GridRenderEditCellParams } from '../models/params/gridCellParams'; import { GRID_DETAIL_PANEL_TOGGLE_FIELD } from '../constants/gridDetailPanelToggleField'; import { gridSortModelSelector } from '../hooks/features/sorting/gridSortingSelector'; import { gridRowTreeDepthSelector } from '../hooks/features/rows/gridRowsSelector'; +import { gridDensityHeaderGroupingMaxDepthSelector } from '../hooks/features/density/densitySelector'; export interface GridRowProps { rowId: GridRowId; @@ -113,7 +114,6 @@ function GridRow(props: React.HTMLAttributes & GridRowProps) { onMouseLeave, ...other } = props; - const ariaRowIndex = index + 2; // 1 for the header row and 1 as it's 1-based const apiRef = useGridApiContext(); const ref = React.useRef(null); const rootProps = useGridRootProps(); @@ -121,6 +121,9 @@ function GridRow(props: React.HTMLAttributes & GridRowProps) { const columnsTotalWidth = useGridSelector(apiRef, gridColumnsTotalWidthSelector); const sortModel = useGridSelector(apiRef, gridSortModelSelector); const treeDepth = useGridSelector(apiRef, gridRowTreeDepthSelector); + const headerGroupingMaxDepth = useGridSelector(apiRef, gridDensityHeaderGroupingMaxDepthSelector); + + const ariaRowIndex = index + headerGroupingMaxDepth + 2; // 1 for the header row and 1 as it's 1-based const { hasScrollX, hasScrollY } = apiRef.current.getRootDimensions() ?? { hasScrollX: false, hasScrollY: false, diff --git a/packages/grid/x-data-grid/src/components/base/GridBody.tsx b/packages/grid/x-data-grid/src/components/base/GridBody.tsx index 7150071e596ed..83061a9b324f5 100644 --- a/packages/grid/x-data-grid/src/components/base/GridBody.tsx +++ b/packages/grid/x-data-grid/src/components/base/GridBody.tsx @@ -7,7 +7,7 @@ import { GridAutoSizer } from '../GridAutoSizer'; import { GridOverlays } from './GridOverlays'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; import { useGridSelector } from '../../hooks/utils/useGridSelector'; -import { gridDensityHeaderHeightSelector } from '../../hooks/features/density/densitySelector'; +import { gridDensityTotalHeaderHeightSelector } from '../../hooks/features/density/densitySelector'; interface GridBodyProps { children?: React.ReactNode; @@ -30,7 +30,7 @@ function GridBody(props: GridBodyProps) { const { children, VirtualScrollerComponent, ColumnHeadersComponent } = props; const apiRef = useGridApiContext(); const rootProps = useGridRootProps(); - const headerHeight = useGridSelector(apiRef, gridDensityHeaderHeightSelector); + const totalHeaderHeight = useGridSelector(apiRef, gridDensityTotalHeaderHeightSelector); const [isVirtualizationDisabled, setIsVirtualizationDisabled] = React.useState( rootProps.disableVirtualization, ); @@ -83,8 +83,8 @@ function GridBody(props: GridBodyProps) { width: size.width, // If `autoHeight` is on, there will be no height value. // In this case, let the container to grow whatever it needs. - height: size.height ? size.height - headerHeight : 'auto', - marginTop: headerHeight, + height: size.height ? size.height - totalHeaderHeight : 'auto', + marginTop: totalHeaderHeight, } as React.CSSProperties; return ( diff --git a/packages/grid/x-data-grid/src/components/base/GridOverlays.tsx b/packages/grid/x-data-grid/src/components/base/GridOverlays.tsx index ce3a618e5796b..ea5f54c56dc3a 100644 --- a/packages/grid/x-data-grid/src/components/base/GridOverlays.tsx +++ b/packages/grid/x-data-grid/src/components/base/GridOverlays.tsx @@ -8,12 +8,12 @@ import { } from '../../hooks/features/rows/gridRowsSelector'; import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; -import { gridDensityHeaderHeightSelector } from '../../hooks/features/density/densitySelector'; +import { gridDensityTotalHeaderHeightSelector } from '../../hooks/features/density/densitySelector'; function GridOverlayWrapper(props: React.PropsWithChildren<{}>) { const apiRef = useGridApiContext(); const rootProps = useGridRootProps(); - const headerHeight = useGridSelector(apiRef, gridDensityHeaderHeightSelector); + const totalHeaderHeight = useGridSelector(apiRef, gridDensityTotalHeaderHeightSelector); const [viewportInnerSize, setViewportInnerSize] = React.useState( () => apiRef.current.getRootDimensions()?.viewportInnerSize ?? null, @@ -42,7 +42,7 @@ function GridOverlayWrapper(props: React.PropsWithChildren<{}>) { height, width: viewportInnerSize?.width ?? 0, position: 'absolute', - top: headerHeight, + top: totalHeaderHeight, bottom: height === 'auto' ? 0 : undefined, }} {...props} diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx new file mode 100644 index 0000000000000..09cfc6f95072b --- /dev/null +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx @@ -0,0 +1,124 @@ +import * as React from 'react'; +import { unstable_composeClasses as composeClasses } from '@mui/material'; +import { GridColumnHeaderTitle } from './GridColumnHeaderTitle'; +import { getDataGridUtilityClass } from '../../constants/gridClasses'; +import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; +import { DataGridProcessedProps } from '../../models/props/DataGridProps'; +import { gridColumnGroupsLookupSelector } from '../../hooks/features/columns/gridColumnsSelector'; +import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; +import { useGridSelector } from '../../hooks/utils/useGridSelector'; + +interface GridColumnGroupHeaderProps { + groupId: string | null; + width: number; + fields: string[]; + colIndex: number; // TODO: use this prop to get accessible column group + isLastColumn: boolean; + extendRowFullWidth: boolean; + depth: number; + maxDepth: number; +} + +type OwnerState = GridColumnGroupHeaderProps & { + showRightBorder: boolean; + depth: number; + maxDepth: number; + classes?: DataGridProcessedProps['classes']; +}; + +const useUtilityClasses = (ownerState: OwnerState) => { + const { groupId, classes, showRightBorder } = ownerState; + + const slots = { + root: [ + 'columnGroupHeader', + showRightBorder && 'withBorder', + groupId ? 'columnGroupHeader--withName' : 'columnGroupHeader--withoutName', + ], + titleContainer: ['columnGroupHeaderTitleContainer'], + titleContainerContent: ['columnGroupHeaderTitleContainerContent'], + }; + + return composeClasses(slots, getDataGridUtilityClass, classes); +}; + +function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { + const { groupId, width, depth, maxDepth, fields, colIndex, isLastColumn, extendRowFullWidth } = + props; + + const rootProps = useGridRootProps(); + + const apiRef = useGridApiContext(); + const columnGroupsLookup = useGridSelector(apiRef, gridColumnGroupsLookupSelector); + const { hasScrollX, hasScrollY } = apiRef.current.getRootDimensions() ?? { + hasScrollX: false, + hasScrollY: false, + }; + + const { headerName = groupId ?? '', description = '' } = groupId + ? columnGroupsLookup[groupId] + : {}; + + let headerComponent: React.ReactNode = null; + + const render = groupId && columnGroupsLookup[groupId]?.renderHeaderGroup; + if (groupId && render) { + headerComponent = render({ + groupId, + headerName, + description, + depth, + maxDepth, + fields, + colIndex, + isLastColumn, + }); + } + + const headerCellRef = React.useRef(null); + + const removeLastBorderRight = isLastColumn && hasScrollX && !hasScrollY; + const showRightBorder = !isLastColumn + ? rootProps.showColumnRightBorder + : !removeLastBorderRight && !extendRowFullWidth; + + const ownerState = { + ...props, + classes: rootProps.classes, + showRightBorder, + depth, + }; + + const classes = useUtilityClasses(ownerState); + + return ( +
+
+
+ {headerComponent || ( + + )} +
+
+
+ ); +} + +export { GridColumnGroupHeader }; diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeadersInner.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeadersInner.tsx index ff12b3c2b7d41..df6a1ec961d93 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeadersInner.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeadersInner.tsx @@ -36,7 +36,8 @@ const GridColumnHeadersInnerRoot = styled('div', { ], })(() => ({ display: 'flex', - alignItems: 'center', + alignItems: 'flex-start', + flexDirection: 'column', [`&.${gridClasses.columnHeaderDropZone} .${gridClasses.columnHeaderDraggableContainer}`]: { cursor: 'move', }, diff --git a/packages/grid/x-data-grid/src/components/containers/GridRoot.tsx b/packages/grid/x-data-grid/src/components/containers/GridRoot.tsx index b0e37af9801e6..e197bfa79937c 100644 --- a/packages/grid/x-data-grid/src/components/containers/GridRoot.tsx +++ b/packages/grid/x-data-grid/src/components/containers/GridRoot.tsx @@ -17,7 +17,10 @@ import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; import { getDataGridUtilityClass } from '../../constants/gridClasses'; import { gridRowCountSelector } from '../../hooks/features/rows/gridRowsSelector'; -import { gridDensityValueSelector } from '../../hooks/features/density/densitySelector'; +import { + gridDensityHeaderGroupingMaxDepthSelector, + gridDensityValueSelector, +} from '../../hooks/features/density/densitySelector'; import { DataGridProcessedProps } from '../../models/props/DataGridProps'; import { GridDensity } from '../../models/gridDensity'; @@ -51,6 +54,7 @@ const GridRoot = React.forwardRef(function GridRo const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector); const totalRowCount = useGridSelector(apiRef, gridRowCountSelector); const densityValue = useGridSelector(apiRef, gridDensityValueSelector); + const headerGroupingMaxDepth = useGridSelector(apiRef, gridDensityHeaderGroupingMaxDepthSelector); const rootContainerRef: GridRootContainerRef = React.useRef(null); const handleRef = useForkRef(rootContainerRef, ref); @@ -86,7 +90,7 @@ const GridRoot = React.forwardRef(function GridRo className={clsx(className, classes.root)} role="grid" aria-colcount={visibleColumns.length} - aria-rowcount={totalRowCount} + aria-rowcount={headerGroupingMaxDepth + 1 + totalRowCount} aria-multiselectable={!rootProps.disableMultipleSelection} aria-label={rootProps['aria-label']} aria-labelledby={rootProps['aria-labelledby']} diff --git a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts index 7fee459168b91..036cf9b587c4a 100644 --- a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts +++ b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts @@ -85,12 +85,13 @@ export const GridRootStyles = styled('div', { { borderBottomColor: 'transparent', }, - [`& .${gridClasses.columnHeader}, & .${gridClasses.cell}`]: { - WebkitTapHighlightColor: 'transparent', - lineHeight: null, - padding: '0 10px', - boxSizing: 'border-box', - }, + [`& .${gridClasses.columnHeader}, & .${gridClasses.columnGroupHeader}, & .${gridClasses.cell}`]: + { + WebkitTapHighlightColor: 'transparent', + lineHeight: null, + padding: '0 10px', + boxSizing: 'border-box', + }, [`& .${gridClasses.columnHeader}:focus-within, & .${gridClasses.cell}:focus-within`]: { outline: `solid ${alpha(theme.palette.primary.main, 0.5)} 1px`, outlineWidth: 1, @@ -138,6 +139,16 @@ export const GridRootStyles = styled('div', { display: 'flex', alignItems: 'center', }, + [`& .${gridClasses['columnGroupHeader--withName']} .${gridClasses.columnGroupHeaderTitleContainerContent}`]: + { + borderBottom: `solid ${theme.palette.divider} 2px`, + }, + [`& .${gridClasses.withBorder} .${gridClasses.columnGroupHeaderTitleContainerContent}`]: { + borderBottom: `none`, + }, + [`& .${gridClasses.withBorder}.${gridClasses.columnGroupHeader}`]: { + borderBottom: `solid ${borderColor} 1px`, + }, [`& .${gridClasses.sortIcon}, & .${gridClasses.filterIcon}`]: { fontSize: 'inherit', }, diff --git a/packages/grid/x-data-grid/src/constants/gridClasses.ts b/packages/grid/x-data-grid/src/constants/gridClasses.ts index ccedb026890ce..b783b4734baf4 100644 --- a/packages/grid/x-data-grid/src/constants/gridClasses.ts +++ b/packages/grid/x-data-grid/src/constants/gridClasses.ts @@ -93,6 +93,10 @@ export interface GridClasses { * Styles applied to the column header element. */ columnHeader: string; + /** + * Styles applied to the column group header element. + */ + columnGroupHeader: string; /** * Styles applied to the header checkbox cell element. */ @@ -121,6 +125,14 @@ export interface GridClasses { * Styles applied to the column header's title excepted buttons. */ columnHeaderTitleContainerContent: string; + /** + * Styles applied to the column group header's title excepted buttons. + */ + columnGroupHeaderTitleContainerContent: string; + /** + * Styles applied to the column group header cell if not empty. + */ + 'columnGroupHeader--withName': string; /** * Styles applied to the column headers. */ @@ -459,7 +471,10 @@ export const gridClasses = generateUtilityClasses('MuiDataGrid', [ 'columnHeaderDropZone', 'columnHeaderTitle', 'columnHeaderTitleContainer', + 'columnGroupHeader', + 'columnGroupHeader--withName', 'columnHeaderTitleContainerContent', + 'columnGroupHeaderTitleContainerContent', 'columnHeaders', 'columnHeadersInner', 'columnHeadersInner--scrollable', diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index a1944563c1bfc..a081ad0e558f5 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import { useForkRef } from '@mui/material/utils'; +import { styled } from '@mui/material/styles'; import { defaultMemoize } from 'reselect'; import { useGridApiContext } from '../../utils/useGridApiContext'; import { useGridSelector } from '../../utils/useGridSelector'; @@ -13,7 +14,12 @@ import { gridTabIndexCellSelector, gridFocusColumnHeaderSelector, } from '../focus/gridFocusStateSelector'; -import { gridDensityHeaderHeightSelector } from '../density/densitySelector'; +import { + gridDensityHeaderHeightSelector, + gridDensityHeaderGroupingMaxDepthSelector, + gridDensityHeaderGroupingRowHeightSelector, + gridDensityTotalHeaderHeightSelector, +} from '../density/densitySelector'; import { gridFilterActiveItemsLookupSelector } from '../filter/gridFilterSelector'; import { gridSortColumnLookupSelector } from '../sorting/gridSortingSelector'; import { gridColumnMenuSelector } from '../columnMenu/columnMenuSelector'; @@ -25,6 +31,26 @@ import { GridColumnHeaderItem } from '../../../components/columnHeaders/GridColu import { getFirstColumnIndexToRender } from '../columns/gridColumnsUtils'; import { useGridVisibleRows } from '../../utils/useGridVisibleRows'; import { getRenderableIndexes } from '../virtualization/useGridVirtualScroller'; +import { GridColumnGroupHeader } from '../../../components/columnHeaders/GridColumnGroupHeader'; + +// TODO: add the possibility to switch this value if needed for customization +const MERGE_EMPTY_CELLS = true; + +const GridColumnHeaderRow = styled('div', { + name: 'MuiDataGrid', + slot: 'ColumnHeaderRow', + overridesResolver: (props, styles) => styles.columnHeaderRow, +})(() => ({ + display: 'flex', +})); + +interface HeaderInfo { + groupId: string | null; + width: number; + fields: string[]; + colIndex: number; + description?: string; +} interface UseGridColumnHeadersProps { innerRef?: React.Ref; @@ -48,6 +74,12 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { const cellTabIndexState = useGridSelector(apiRef, gridTabIndexCellSelector); const columnHeaderFocus = useGridSelector(apiRef, gridFocusColumnHeaderSelector); const headerHeight = useGridSelector(apiRef, gridDensityHeaderHeightSelector); + const headerGroupingMaxDepth = useGridSelector(apiRef, gridDensityHeaderGroupingMaxDepthSelector); + const headerGroupingRowHeight = useGridSelector( + apiRef, + gridDensityHeaderGroupingRowHeightSelector, + ); + const totalHeaderHeight = useGridSelector(apiRef, gridDensityTotalHeaderHeightSelector); const filterColumnLookup = useGridSelector(apiRef, gridFilterActiveItemsLookupSelector); const sortColumnLookup = useGridSelector(apiRef, gridSortColumnLookupSelector); const columnMenuState = useGridSelector(apiRef, gridColumnMenuSelector); @@ -187,7 +219,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { useGridApiEventHandler(apiRef, 'rowsScroll', handleScroll); - const getColumns = ( + const getColumnsHeader = ( params?: { renderContext: GridRenderContext | null; minFirstColumn?: number; @@ -268,20 +300,215 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ); } + return ( + + {columns} + + ); + }; + + const getColumnsHeaderGroups = (params?: { + renderContext: GridRenderContext | null; + minFirstColumn?: number; + maxLastColumn?: number; + }) => { + if (headerGroupingMaxDepth === 0) { + return null; + } + + const { + renderContext: nextRenderContext = renderContext, + minFirstColumn = minColumnIndex, + maxLastColumn = visibleColumns.length, + } = params || {}; + + if (!nextRenderContext) { + return null; + } + + const columns: JSX.Element[] = []; + + const [firstRowToRender, lastRowToRender] = getRenderableIndexes({ + firstIndex: nextRenderContext.firstRowIndex, + lastIndex: nextRenderContext.lastRowIndex, + minFirstIndex: 0, + maxLastIndex: currentPage.rows.length, + buffer: rootProps.rowBuffer, + }); + + const firstColumnToRender = getFirstColumnIndexToRenderRef.current({ + firstColumnIndex: nextRenderContext!.firstColumnIndex, + minColumnIndex: minFirstColumn, + columnBuffer: rootProps.columnBuffer, + apiRef, + firstRowToRender, + lastRowToRender, + visibleRows: currentPage.rows, + }); + + const lastColumnToRender = Math.min( + nextRenderContext.lastColumnIndex! + rootProps.columnBuffer, + maxLastColumn, + ); + + const renderedColumns = visibleColumns.slice(firstColumnToRender, lastColumnToRender); + + const headerToRender: { + leftOverflow: number; + elements: HeaderInfo[]; + }[] = []; + + for (let depth = 0; depth < headerGroupingMaxDepth; depth += 1) { + // Initialize the header line with a grouping item containing all the columns on the left of the virtualization which are in the same group as the first group to render + const initialHeader: HeaderInfo[] = []; + let leftOverflow = 0; + + let columnIndex = firstColumnToRender - 1; + const firstColumnToRenderGroup = visibleColumns[firstColumnToRender]?.groupPath?.[depth]!; + while ( + firstColumnToRenderGroup !== null && + columnIndex >= minColumnIndex && + visibleColumns[columnIndex]?.groupPath && + visibleColumns[columnIndex]?.groupPath?.[depth] === firstColumnToRenderGroup + ) { + const column = visibleColumns[columnIndex]; + + leftOverflow += column.width ?? 0; + + if (initialHeader.length === 0) { + initialHeader.push({ + width: column.width ?? 0, + fields: [column.field], + groupId: firstColumnToRenderGroup, + colIndex: columnIndex, + }); + } else { + initialHeader[0].width += column.width ?? 0; + initialHeader[0].fields.push(column.field); + initialHeader[0].colIndex = columnIndex; + } + + columnIndex -= 1; + } + + const depthInfo = renderedColumns.reduce((aggregated, column, i) => { + const lastItem: HeaderInfo | undefined = aggregated[aggregated.length - 1]; + + if (column.groupPath && column.groupPath.length > depth) { + if (lastItem && lastItem.groupId === column.groupPath[depth]) { + // Merge with the previous columns + return [ + ...aggregated.slice(0, aggregated.length - 1), + { + ...lastItem, + width: lastItem.width + (column.width ?? 0), + fields: [...lastItem.fields, column.field], + }, + ]; + } + // Create a new grouping + return [ + ...aggregated, + { + groupId: column.groupPath[depth], + width: column.width ?? 0, + fields: [column.field], + colIndex: firstColumnToRender + i, + }, + ]; + } + + // It is the first level for which their is no group + if (MERGE_EMPTY_CELLS && lastItem && lastItem.groupId === null) { + // We merge with previous column + return [ + ...aggregated.slice(0, aggregated.length - 1), + { + ...lastItem, + width: lastItem.width + (column.width ?? 0), + fields: [...lastItem.fields, column.field], + }, + ]; + } + // We create new empty cell + return [ + ...aggregated, + { + groupId: null, + width: column.width ?? 0, + fields: [column.field], + colIndex: firstColumnToRender + i, + }, + ]; + }, initialHeader); + + columnIndex = lastColumnToRender; + const lastColumnToRenderGroup = depthInfo[depthInfo.length - 1].groupId; + + while ( + lastColumnToRenderGroup !== null && + columnIndex < maxLastColumn && + visibleColumns[columnIndex]?.groupPath && + visibleColumns[columnIndex]?.groupPath?.[depth] === lastColumnToRenderGroup + ) { + const column = visibleColumns[columnIndex]; + + depthInfo[depthInfo.length - 1].width += column.width ?? 0; + depthInfo[depthInfo.length - 1].fields.push(column.field); + columnIndex += 1; + } + + headerToRender.push({ leftOverflow, elements: [...depthInfo] }); + } + + headerToRender.forEach((depthInfo, depthIndex) => { + columns.push( + + {depthInfo.elements.map(({ groupId, width, fields, colIndex }, groupIndex) => { + return ( + + ); + })} + , + ); + }); return columns; }; const rootStyle = { - minHeight: headerHeight, - maxHeight: headerHeight, + minHeight: totalHeaderHeight, + maxHeight: totalHeaderHeight, lineHeight: `${headerHeight}px`, }; return { renderContext, - getColumns, + getColumnsHeader, + getColumnsHeaderGroups, isDragging: !!dragCol, getRootProps: (other = {}) => ({ style: rootStyle, ...other }), - getInnerProps: () => ({ ref: handleInnerRef, 'aria-rowindex': 1, role: 'row' }), + getInnerProps: () => ({ + ref: handleInnerRef, + role: 'rowgroup', + }), }; }; diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsInterfaces.ts b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsInterfaces.ts index 04a7bd4b7a139..b338f1337f04f 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsInterfaces.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsInterfaces.ts @@ -1,5 +1,6 @@ import type { GridRowId } from '../../../models'; import { GridColDef, GridStateColDef } from '../../../models/colDef/gridColDef'; +import { GridColumnGroup } from '../../../models/gridColumnGrouping'; import type { GridColumnDimensionProperties } from './gridColumnsUtils'; export type GridColumnLookup = { @@ -19,6 +20,19 @@ export interface GridColumnsState { columnVisibilityModel: GridColumnVisibilityModel; } +export type GridColumnGroupLookup = { + [field: string]: Omit; +}; + +export type GridColumnGroupCollapsedModel = { + [field: string]: GridStateColDef; +}; + +export interface GridColumnsGroupingState { + lookup: GridColumnGroupLookup; + groupCollapsedModel: GridColumnGroupCollapsedModel; +} + export interface GridColumnsInternalCache { isUsingColumnVisibilityModel: boolean; } diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts index 586c099be4ef6..a91ac5b37cf56 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts @@ -128,6 +128,17 @@ export const gridFilterableColumnLookupSelector = createSelector( }, {}), ); +/** + * @category ColumnGrouping + * @ignore - do not document. + */ +export const gridColumnGroupingSelector = (state: GridStateCommunity) => state.columnGrouping; + +export const gridColumnGroupsLookupSelector = createSelector( + gridColumnGroupingSelector, + (columnGrouping) => columnGrouping.lookup, +); + /** * @category Columns * @deprecated Use `gridColumnFieldsSelector` instead. diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/index.ts b/packages/grid/x-data-grid/src/hooks/features/columns/index.ts index 20d1ef59a789b..a5ec23c808a70 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/index.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/index.ts @@ -4,5 +4,6 @@ export type { GridColumnsState, GridColumnsInitialState, GridColumnVisibilityModel, + GridColumnsGroupingState, } from './gridColumnsInterfaces'; export { getGridColDef } from './gridColumnsUtils'; diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts new file mode 100644 index 0000000000000..544d5487d7454 --- /dev/null +++ b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts @@ -0,0 +1,212 @@ +import * as React from 'react'; +import { GridApiCommunity } from '../../../models/api/gridApiCommunity'; +import { GridPipeProcessor, useGridRegisterPipeProcessor } from '../../core/pipeProcessing'; +import { DataGridProcessedProps } from '../../../models/props/DataGridProps'; +import { GridStateInitializer } from '../../utils/useGridInitializeState'; +import { + GridColumnGroupingModel, + GridColumnNode, + isLeaf, +} from '../../../models/gridColumnGrouping'; +import { gridColumnGroupsLookupSelector, gridColumnLookupSelector } from './gridColumnsSelector'; +import { GridColumnGroupLookup } from './gridColumnsInterfaces'; +import { GridColumnGroupingApi } from '../../../models/api/gridColumnGroupingApi'; +import { useGridApiMethod } from '../../utils/useGridApiMethod'; +import { isDeepEqual } from '../../../utils/utils'; +import { GridStateColDef, GridColDef } from '../../../models/colDef'; + +export function hasGroupPath( + lookupElement: GridColDef | GridStateColDef, +): lookupElement is GridStateColDef { + return (lookupElement).groupPath !== undefined; +} + +type UnwrappedGroupingModel = { [key: string]: string[] }; + +const recurrentUnwrapGroupingColumnModel = ( + columnGroupNode: GridColumnNode, + parents: any, +): UnwrappedGroupingModel => { + if (isLeaf(columnGroupNode)) { + return { [columnGroupNode.field]: parents }; + } + const rep: UnwrappedGroupingModel = {}; + const { groupId, children } = columnGroupNode; + children.forEach((child) => { + const unwrappedSubTree = recurrentUnwrapGroupingColumnModel(child, [...parents, groupId]); + Object.entries(unwrappedSubTree).forEach(([key, value]) => { + if (rep[key] !== undefined) { + throw new Error( + [ + `MUI DataGrid - column grouping: duplicated field`, + `column field ${key} occurres two times in the grouping model:`, + `- ${rep[key].join(' > ')}`, + `- ${value.join(' > ')}`, + ].join('\n'), + ); + } + rep[key] = value; + }); + }); + return rep; +}; + +export const unwrapGroupingColumnModel = ( + columnGroupingModel?: GridColumnGroupingModel, +): UnwrappedGroupingModel => { + if (!columnGroupingModel) { + return {}; + } + + const rep: UnwrappedGroupingModel = {}; + + columnGroupingModel.forEach((columnGroupNode) => { + const unwrappedSubTree = recurrentUnwrapGroupingColumnModel(columnGroupNode, []); + Object.entries(unwrappedSubTree).forEach(([key, value]) => { + if (rep[key] !== undefined) { + throw new Error( + [ + `MUI DataGrid - column grouping: duplicated field`, + `column field ${key} occurres two times in the grouping model:`, + `- ${rep[key].join(' > ')}`, + `- ${value.join(' > ')}`, + ].join('\n'), + ); + } + rep[key] = value; + }); + }); + + return rep; +}; + +const createGroupLookup = (columnGroupingModel: GridColumnNode[]): GridColumnGroupLookup => { + let groupLookup: GridColumnGroupLookup = {}; + + columnGroupingModel.forEach((node) => { + if (isLeaf(node)) { + return; + } + const { groupId, children, ...other } = node; + if (!groupId) { + throw new Error( + 'MUI-DataGrid: an element of the columnGroupingModel does not have either `field` or `groupId`', + ); + } + if (!children) { + console.warn(`MUI-DataGrid: group groupId=${groupId} has no children. `); + } + const groupParam = { ...other, groupId }; + const subTreeLookup = createGroupLookup(children); + if (subTreeLookup[groupId] !== undefined || groupLookup[groupId] !== undefined) { + throw new Error(`The groupId ${groupId} is used multiple times`); + } + groupLookup = { ...groupLookup, ...subTreeLookup, [groupId]: groupParam }; + }); + + return { ...groupLookup }; +}; +export const columnGroupsStateInitializer: GridStateInitializer< + Pick +> = (state, props) => { + const groupLookup = createGroupLookup(props.columnGroupingModel ?? []); + return { + ...state, + columnGrouping: { lookup: groupLookup, groupCollapsedModel: {} }, + }; +}; + +/** + * @requires useGridColumns (method, event) + * @requires useGridParamsApi (method) + */ +export const useGridColumnGrouping = ( + apiRef: React.MutableRefObject, + props: Pick, +) => { + /** + * API METHODS + */ + const getColumnGroupPath = React.useCallback( + (field) => { + const columnLookup = gridColumnLookupSelector(apiRef); + + return columnLookup[field]?.groupPath ?? []; + }, + [apiRef], + ); + + const getAllGroupDetails = React.useCallback(() => { + const columnGroupLookup = gridColumnGroupsLookupSelector(apiRef); + return columnGroupLookup; + }, [apiRef]); + + const getGroupDetails = React.useCallback( + (groupId) => { + const columnGroupLookup = gridColumnGroupsLookupSelector(apiRef); + + return columnGroupLookup[groupId] ?? null; + }, + [apiRef], + ); + + const columnGroupingApi: GridColumnGroupingApi = { + getColumnGroupPath, + getGroupDetails, + getAllGroupDetails, + }; + + useGridApiMethod(apiRef, columnGroupingApi, 'GridColumnGroupingApi'); + + /** + * Processors + * */ + const addHeaderGroups = React.useCallback>( + (columnsState) => { + if (!props.columnGroupingModel) { + return columnsState; + } + const unwrappedGroupingModel = unwrapGroupingColumnModel(props.columnGroupingModel); + if (Object.keys(unwrappedGroupingModel).length === 0) { + return columnsState; + } + + columnsState.all.forEach((field) => { + const newGroupPath = unwrappedGroupingModel[field] ?? []; + + const lookupElement = columnsState.lookup[field]; + if (hasGroupPath(lookupElement) && isDeepEqual(newGroupPath, lookupElement?.groupPath)) { + // Avoid modifying the pointer to allow shadow comparison in https://github.com/mui/mui-x/blob/f90afbf10a1264ee8b453d7549dd7cdd6110a4ed/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts#L446:L453 + return; + } + columnsState.lookup[field] = { + ...columnsState.lookup[field], + groupPath: unwrappedGroupingModel[field] ?? [], + }; + }); + return columnsState; + }, + [props.columnGroupingModel], + ); + + useGridRegisterPipeProcessor(apiRef, 'hydrateColumns', addHeaderGroups); + + /** + * EFFECTS + */ + // The effect do not track any value defined synchronously during the 1st render by hooks called after `useGridColumns` + // As a consequence, the state generated by the 1st run of this useEffect will always be equal to the initialization one + const isFirstRender = React.useRef(true); + React.useEffect(() => { + if (isFirstRender.current) { + isFirstRender.current = false; + return; + } + + const groupLookup = createGroupLookup(props.columnGroupingModel ?? []); + apiRef.current.setState((state) => ({ + ...state, + columnGrouping: { ...state.columnGrouping, lookup: groupLookup }, + })); + }, [apiRef, props.columnGroupingModel]); +}; diff --git a/packages/grid/x-data-grid/src/hooks/features/density/densitySelector.ts b/packages/grid/x-data-grid/src/hooks/features/density/densitySelector.ts index 6e6cf2756939b..c0fa87124448d 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/densitySelector.ts +++ b/packages/grid/x-data-grid/src/hooks/features/density/densitySelector.ts @@ -18,7 +18,23 @@ export const gridDensityHeaderHeightSelector = createSelector( (density) => density.headerHeight, ); +export const gridDensityHeaderGroupingMaxDepthSelector = createSelector( + gridDensitySelector, + (density) => density.headerGroupingMaxDepth, +); + +export const gridDensityHeaderGroupingRowHeightSelector = createSelector( + gridDensitySelector, + (density) => density.headerGroupingRowHeight, +); + export const gridDensityFactorSelector = createSelector( gridDensitySelector, (density) => density.factor, ); + +export const gridDensityTotalHeaderHeightSelector = createSelector( + gridDensitySelector, + (density) => + density.headerHeight + density.headerGroupingMaxDepth * density.headerGroupingRowHeight, +); diff --git a/packages/grid/x-data-grid/src/hooks/features/density/densityState.ts b/packages/grid/x-data-grid/src/hooks/features/density/densityState.ts index b924f6461377d..a601b24053e2f 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/densityState.ts +++ b/packages/grid/x-data-grid/src/hooks/features/density/densityState.ts @@ -4,5 +4,7 @@ export interface GridDensityState { value: GridDensity; rowHeight: number; headerHeight: number; + headerGroupingRowHeight: number; + headerGroupingMaxDepth: number; factor: number; } diff --git a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx index 6ea806b48e106..7d0351d1e3d3a 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx @@ -9,6 +9,9 @@ import { DataGridProcessedProps } from '../../../models/props/DataGridProps'; import { gridDensitySelector } from './densitySelector'; import { isDeepEqual } from '../../../utils/utils'; import { GridStateInitializer } from '../../utils/useGridInitializeState'; +import { useGridSelector } from '../../utils/useGridSelector'; +import { gridVisibleColumnDefinitionsSelector } from '../columns'; +import { unwrapGroupingColumnModel } from '../columns/useGridColumnGrouping'; export const COMPACT_DENSITY_FACTOR = 0.7; export const COMFORTABLE_DENSITY_FACTOR = 1.3; @@ -18,6 +21,8 @@ const getUpdatedDensityState = ( newDensity: GridDensity, newHeaderHeight: number, newRowHeight: number, + newMaxDepth: number, + newHeaderGroupingRowHeight: number, ): GridDensityState => { switch (newDensity) { case GridDensityTypes.Compact: @@ -25,6 +30,8 @@ const getUpdatedDensityState = ( value: newDensity, headerHeight: Math.floor(newHeaderHeight * COMPACT_DENSITY_FACTOR), rowHeight: Math.floor(newRowHeight * COMPACT_DENSITY_FACTOR), + headerGroupingRowHeight: Math.floor(newHeaderGroupingRowHeight * COMPACT_DENSITY_FACTOR), + headerGroupingMaxDepth: newMaxDepth, factor: COMPACT_DENSITY_FACTOR, }; case GridDensityTypes.Comfortable: @@ -32,6 +39,10 @@ const getUpdatedDensityState = ( value: newDensity, headerHeight: Math.floor(newHeaderHeight * COMFORTABLE_DENSITY_FACTOR), rowHeight: Math.floor(newRowHeight * COMFORTABLE_DENSITY_FACTOR), + headerGroupingRowHeight: Math.floor( + newHeaderGroupingRowHeight * COMFORTABLE_DENSITY_FACTOR, + ), + headerGroupingMaxDepth: newMaxDepth, factor: COMFORTABLE_DENSITY_FACTOR, }; default: @@ -39,30 +50,88 @@ const getUpdatedDensityState = ( value: newDensity, headerHeight: newHeaderHeight, rowHeight: newRowHeight, + headerGroupingRowHeight: newHeaderGroupingRowHeight, + headerGroupingMaxDepth: newMaxDepth, factor: 1, }; } }; export const densityStateInitializer: GridStateInitializer< - Pick -> = (state, props) => ({ - ...state, - density: getUpdatedDensityState(props.density, props.headerHeight, props.rowHeight), -}); + Pick< + DataGridProcessedProps, + 'density' | 'headerHeight' | 'rowHeight' | 'headerGroupingRowHeight' | 'columnGroupingModel' + > +> = (state, props) => { + // TODO: think about improving this initialization. Could it be done in the useColumn initializer? + // TODO: ma,age to remove ts-ignore + let maxDepth: number; + if (props.columnGroupingModel == null || Object.keys(props.columnGroupingModel).length === 0) { + maxDepth = 0; + } else { + const unwrappedGroupingColumnModel = unwrapGroupingColumnModel(props.columnGroupingModel); + + // @ts-ignore + const visibleColumns = state.columns.all.filter( + // @ts-ignore + (field) => state.columns.columnVisibilityModel[field] !== false, + ); + + if (visibleColumns.length === 0) { + maxDepth = 0; + } else { + maxDepth = Math.max( + // @ts-ignore + ...visibleColumns.map((field) => unwrappedGroupingColumnModel[field]?.length ?? 0), + ); + } + } + return { + ...state, + density: getUpdatedDensityState( + props.density, + props.headerHeight, + props.rowHeight, + maxDepth, + props.headerGroupingRowHeight, + ), + }; +}; export const useGridDensity = ( apiRef: React.MutableRefObject, - props: Pick, + props: Pick< + DataGridProcessedProps, + 'headerHeight' | 'rowHeight' | 'density' | 'headerGroupingRowHeight' + >, ): void => { + const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector); + + const maxDepth = + visibleColumns.length > 0 + ? Math.max(...visibleColumns.map((column) => column.groupPath?.length ?? 0)) + : 0; + const logger = useGridLogger(apiRef, 'useDensity'); const setDensity = React.useCallback( - (newDensity, newHeaderHeight = props.headerHeight, newRowHeight = props.rowHeight): void => { + ( + newDensity, + newHeaderHeight = props.headerHeight, + newRowHeight = props.rowHeight, + newMaxDepth = maxDepth, + newHeaderGroupingRowHeight = props.headerGroupingRowHeight, + ): void => { logger.debug(`Set grid density to ${newDensity}`); apiRef.current.setState((state) => { const currentDensityState = gridDensitySelector(state); - const newDensityState = getUpdatedDensityState(newDensity, newHeaderHeight, newRowHeight); + const newDensityState = getUpdatedDensityState( + newDensity, + newHeaderHeight, + newRowHeight, + newMaxDepth, + newHeaderGroupingRowHeight, + ); if (isDeepEqual(currentDensityState, newDensityState)) { return state; @@ -75,12 +144,25 @@ export const useGridDensity = ( }); apiRef.current.forceUpdate(); }, - [logger, apiRef, props.headerHeight, props.rowHeight], + [logger, apiRef, props.headerHeight, props.rowHeight, maxDepth, props.headerGroupingRowHeight], ); React.useEffect(() => { - apiRef.current.setDensity(props.density, props.headerHeight, props.rowHeight); - }, [apiRef, props.density, props.rowHeight, props.headerHeight]); + apiRef.current.setDensity( + props.density, + props.headerHeight, + props.rowHeight, + maxDepth, + props.headerGroupingRowHeight, + ); + }, [ + apiRef, + props.density, + props.rowHeight, + props.headerHeight, + maxDepth, + props.headerGroupingRowHeight, + ]); const densityApi: GridDensityApi = { setDensity, diff --git a/packages/grid/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts b/packages/grid/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts index b6cacda8a48b3..bd2279d751e06 100644 --- a/packages/grid/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts +++ b/packages/grid/x-data-grid/src/hooks/features/dimensions/useGridDimensions.ts @@ -16,7 +16,7 @@ import { useGridLogger } from '../../utils/useGridLogger'; import { DataGridProcessedProps } from '../../../models/props/DataGridProps'; import { GridDimensions, GridDimensionsApi } from './gridDimensionsApi'; import { gridColumnsTotalWidthSelector } from '../columns'; -import { gridDensityHeaderHeightSelector, gridDensityRowHeightSelector } from '../density'; +import { gridDensityTotalHeaderHeightSelector, gridDensityRowHeightSelector } from '../density'; import { useGridSelector } from '../../utils'; import { getVisibleRows } from '../../utils/useGridVisibleRows'; import { gridRowsMetaSelector } from '../rows/gridRowsMetaSelector'; @@ -62,7 +62,7 @@ export function useGridDimensions( const rootDimensionsRef = React.useRef(null); const fullDimensionsRef = React.useRef(null); const rowsMeta = useGridSelector(apiRef, gridRowsMetaSelector); - const headerHeight = useGridSelector(apiRef, gridDensityHeaderHeightSelector); + const totalHeaderHeight = useGridSelector(apiRef, gridDensityTotalHeaderHeightSelector); const updateGridDimensionsRef = React.useCallback(() => { const rootElement = apiRef.current.rootElementRef?.current; @@ -94,7 +94,7 @@ export function useGridDimensions( width: rootDimensionsRef.current.width, height: props.autoHeight ? rowsMeta.currentPageTotalHeight - : rootDimensionsRef.current.height - headerHeight, + : rootDimensionsRef.current.height - totalHeaderHeight, }; const { hasScrollX, hasScrollY } = hasScroll({ @@ -129,7 +129,7 @@ export function useGridDimensions( apiRef, props.scrollbarSize, props.autoHeight, - headerHeight, + totalHeaderHeight, rowsMeta.currentPageTotalHeight, ]); diff --git a/packages/grid/x-data-grid/src/hooks/features/export/useGridPrintExport.tsx b/packages/grid/x-data-grid/src/hooks/features/export/useGridPrintExport.tsx index 32032a57ce2a3..3ba78776ab55c 100644 --- a/packages/grid/x-data-grid/src/hooks/features/export/useGridPrintExport.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/export/useGridPrintExport.tsx @@ -11,7 +11,7 @@ import { gridColumnDefinitionsSelector, gridColumnVisibilityModelSelector, } from '../columns/gridColumnsSelector'; -import { gridDensityHeaderHeightSelector } from '../density/densitySelector'; +import { gridDensityTotalHeaderHeightSelector } from '../density/densitySelector'; import { gridClasses } from '../../../constants/gridClasses'; import { useGridApiMethod } from '../../utils/useGridApiMethod'; import { gridRowsMetaSelector } from '../rows/gridRowsMetaSelector'; @@ -111,7 +111,7 @@ export const useGridPrintExport = ( return; } - const headerHeight = gridDensityHeaderHeightSelector(apiRef); + const totalHeaderHeight = gridDensityTotalHeaderHeightSelector(apiRef); const rowsMeta = gridRowsMetaSelector(apiRef.current.state); const gridRootElement = apiRef.current.rootElementRef!.current; @@ -153,7 +153,7 @@ export const useGridPrintExport = ( // Expand container height to accommodate all rows gridClone.style.height = `${ rowsMeta.currentPageTotalHeight + - headerHeight + + totalHeaderHeight + gridToolbarElementHeight + gridFooterElementHeight }px`; diff --git a/packages/grid/x-data-grid/src/internals/index.ts b/packages/grid/x-data-grid/src/internals/index.ts index b8c8bc13c58cd..01081139eea30 100644 --- a/packages/grid/x-data-grid/src/internals/index.ts +++ b/packages/grid/x-data-grid/src/internals/index.ts @@ -18,6 +18,10 @@ export { } from '../hooks/features/columnMenu/useGridColumnMenu'; export { useGridColumns, columnsStateInitializer } from '../hooks/features/columns/useGridColumns'; export { useGridColumnSpanning } from '../hooks/features/columns/useGridColumnSpanning'; +export { + useGridColumnGrouping, + columnGroupsStateInitializer, +} from '../hooks/features/columns/useGridColumnGrouping'; export type { GridColumnRawLookup, GridColumnsRawState, diff --git a/packages/grid/x-data-grid/src/models/api/gridApiCommon.ts b/packages/grid/x-data-grid/src/models/api/gridApiCommon.ts index 46d0ca6c19626..aa1cbe00fc919 100644 --- a/packages/grid/x-data-grid/src/models/api/gridApiCommon.ts +++ b/packages/grid/x-data-grid/src/models/api/gridApiCommon.ts @@ -26,6 +26,7 @@ import type { GridStrategyProcessingApi } from '../../hooks/core/strategyProcess import type { GridDimensionsApi } from '../../hooks/features/dimensions'; import type { GridPaginationApi } from '../../hooks/features/pagination'; import type { GridStatePersistenceApi } from '../../hooks/features/statePersistence'; +import { GridColumnGroupingApi } from './gridColumnGroupingApi'; type GridStateApiUntyped = { [key in keyof (GridStateApi & GridStatePersistenceApi)]: any; @@ -58,4 +59,5 @@ export interface GridApiCommon GridClipboardApi, GridScrollApi, GridColumnSpanningApi, - GridStateApiUntyped {} + GridStateApiUntyped, + GridColumnGroupingApi {} diff --git a/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts b/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts new file mode 100644 index 0000000000000..31b48e589a4d2 --- /dev/null +++ b/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts @@ -0,0 +1,25 @@ +import { GridColumnGroupLookup } from '@mui/x-data-grid/hooks/features/columns/gridColumnsInterfaces'; +import { GridColumnGroup } from '../gridColumnGrouping'; + +/** + * The column grouping API interface that is available in the grid [[apiRef]]. + */ +export interface GridColumnGroupingApi { + /** + * Returns the array of groupId applied on the column `field`. + * @param {string} field The id of of the column requested. + * @returns {string[]} array of groupId. + */ + getColumnGroupPath: (field: string) => GridColumnGroup['groupId'][]; + /** + * Returns the details about a group corresponding to `groupId`. + * @param {string} groupId The id of the group requested. + * @returns {Omit} group details. + */ + getGroupDetails: (groupId: string) => Omit | null; + /** + * Returns the column group lookup. + * @returns {GridColumnGroupLookup} groupsLookup. + */ + getAllGroupDetails: () => GridColumnGroupLookup; +} diff --git a/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts b/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts index a405c913b0837..40c356d8fdbdd 100644 --- a/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts +++ b/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts @@ -16,6 +16,14 @@ export interface GridDensityApi { * @param {string} density Can be: `"compact"`, `"standard"`, `"comfortable"`. * @param {number} headerHeight The new header height. * @param {number} rowHeight The new row height. + * @param {number} maxDepth The depth of maximal depth column header grouping tree. + * @param {number} headerGroupingRowHeight The height of a header grouping line. */ - setDensity: (density: GridDensity, headerHeight?: number, rowHeight?: number) => void; + setDensity: ( + density: GridDensity, + headerHeight?: number, + rowHeight?: number, + maxDepth?: number, + headerGroupingRowHeight?: number, + ) => void; } diff --git a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts index e1843540dab2b..db5b67dcd322c 100644 --- a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts +++ b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts @@ -284,6 +284,11 @@ export type GridStateColDef = * If `true`, it means that at least one of the dimension's property of this column has been modified since the last time the column prop has changed. */ hasBeenResized?: boolean; + /** + * The array groupId containing the column from top to bottom. + * This parameters is computed from `columnGroupingModel` props + */ + groupPath?: string[]; }; /** diff --git a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts new file mode 100644 index 0000000000000..c9bd353085e69 --- /dev/null +++ b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts @@ -0,0 +1,54 @@ +import { GridColDef } from './colDef'; + +export type LeafColumn = { + field: GridColDef['field']; +}; + +export type GridColumnNode = GridColumnGroup | LeafColumn; + +export function isLeaf(node: GridColumnNode): node is LeafColumn { + return (node).field !== undefined; +} + +export type GridColumnGroupHeaderParams = { + groupId: string; + headerName: string; + description: string; + depth: number; + maxDepth: number; + fields: string[]; + colIndex: number; + isLastColumn: boolean; +}; + +export type GridColumnGroup = { + /** + * A unique string identifying the group + */ + groupId: string; + /** + * The array of groups and columns included in this group + */ + children: GridColumnNode[]; + /** + * The name to display in the group header + */ + headerName?: string; + /** + * The description displayed in the header tooltip + */ + description?: string; + /** + * If `true` allows to reorder columns outside of the group + * @default false + */ + freeReordering?: boolean; + /** + * Allows to render a component in the column group header cell. + * @param {GridColumnGroupHeaderParams} params Object containing parameters for the renderer. + * @returns {React.ReactNode} The element to be rendered. + */ + renderHeaderGroup?: (params: GridColumnGroupHeaderParams) => React.ReactNode; +}; + +export type GridColumnGroupingModel = GridColumnGroup[]; diff --git a/packages/grid/x-data-grid/src/models/gridStateCommunity.ts b/packages/grid/x-data-grid/src/models/gridStateCommunity.ts index 5880d31a6f3ea..d4bff06c21cd1 100644 --- a/packages/grid/x-data-grid/src/models/gridStateCommunity.ts +++ b/packages/grid/x-data-grid/src/models/gridStateCommunity.ts @@ -2,6 +2,7 @@ import type { GridColumnMenuState, GridColumnsInitialState, GridColumnsState, + GridColumnsGroupingState, GridDensityState, GridFilterInitialState, GridFilterState, @@ -28,6 +29,7 @@ export interface GridStateCommunity { editRows: GridEditRowsModel; pagination: GridPaginationState; columns: GridColumnsState; + columnGrouping: GridColumnsGroupingState; columnMenu: GridColumnMenuState; sorting: GridSortingState; focus: GridFocusState; diff --git a/packages/grid/x-data-grid/src/models/index.ts b/packages/grid/x-data-grid/src/models/index.ts index debf8deff6c64..49e72e4a84a12 100644 --- a/packages/grid/x-data-grid/src/models/index.ts +++ b/packages/grid/x-data-grid/src/models/index.ts @@ -22,6 +22,7 @@ export * from './logger'; export * from './muiEvent'; export * from './events'; export * from './gridSortModel'; +export * from './gridColumnGrouping'; // Do not export GridExportFormat and GridExportExtension which are override in pro package export type { diff --git a/packages/grid/x-data-grid/src/models/props/DataGridProps.ts b/packages/grid/x-data-grid/src/models/props/DataGridProps.ts index d3d3ac20cff7a..724fbf88b0dfc 100644 --- a/packages/grid/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/grid/x-data-grid/src/models/props/DataGridProps.ts @@ -30,6 +30,7 @@ import { GridInitialStateCommunity } from '../gridStateCommunity'; import { GridSlotsComponentsProps } from '../gridSlotsComponentsProps'; import { GridColumnVisibilityModel } from '../../hooks/features/columns/gridColumnsInterfaces'; import { GridCellModesModel, GridRowModesModel } from '../api/gridEditingApi'; +import { GridColumnGroupingModel } from '../gridColumnGrouping'; export interface GridExperimentalFeatures { /** @@ -329,6 +330,12 @@ export interface DataGridPropsWithDefaultValues { * @default false */ disableColumnResize: boolean; + /** + * The height of a row of grouping column headers. + * TODO: choose correctly this value + * @default 32 + */ + headerGroupingRowHeight: number; } /** @@ -779,4 +786,5 @@ export interface DataGridPropsWithoutDefaultValue void; + columnGroupingModel?: GridColumnGroupingModel; } From 0a11d17fd4b0b048784e6162b87f9fac759fe4e3 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Fri, 24 Jun 2022 11:17:30 +0200 Subject: [PATCH 04/53] update style --- .../x-data-grid/src/components/containers/GridRootStyles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts index 036cf9b587c4a..78d59198c540a 100644 --- a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts +++ b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts @@ -141,7 +141,7 @@ export const GridRootStyles = styled('div', { }, [`& .${gridClasses['columnGroupHeader--withName']} .${gridClasses.columnGroupHeaderTitleContainerContent}`]: { - borderBottom: `solid ${theme.palette.divider} 2px`, + borderBottom: `solid ${borderColor} 1px`, }, [`& .${gridClasses.withBorder} .${gridClasses.columnGroupHeaderTitleContainerContent}`]: { borderBottom: `none`, From 22782a007bb1631ab06c9544bb7a33b66fb3199a Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Sat, 2 Jul 2022 12:53:28 +0200 Subject: [PATCH 05/53] move column hydratation in a dedicated hook --- .../useDataGridPremiumComponent.tsx | 2 + .../DataGridPro/useDataGridProComponent.tsx | 2 + .../src/DataGrid/useDataGridComponent.tsx | 2 + .../features/columns/useGridColumnGrouping.ts | 35 ---------------- .../useGridColumnGroupingPreProcessors.ts | 41 +++++++++++++++++++ .../grid/x-data-grid/src/internals/index.ts | 1 + 6 files changed, 48 insertions(+), 35 deletions(-) create mode 100644 packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGroupingPreProcessors.ts diff --git a/packages/grid/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx b/packages/grid/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx index 8b7f72dacac62..690ce1d96afea 100644 --- a/packages/grid/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx +++ b/packages/grid/x-data-grid-premium/src/DataGridPremium/useDataGridPremiumComponent.tsx @@ -55,6 +55,7 @@ import { useGridColumnSpanning, useGridRowReorder, useGridRowReorderPreProcessors, + useGridColumnGroupingPreProcessors, } from '@mui/x-data-grid-pro/internals'; import { GridApiPremium } from '../models/gridApiPremium'; import { DataGridPremiumProcessedProps } from '../models/dataGridPremiumProps'; @@ -75,6 +76,7 @@ export const useDataGridPremiumComponent = ( /** * Register all pre-processors called during state initialization here. */ + useGridColumnGroupingPreProcessors(apiRef, props); useGridSelectionPreProcessors(apiRef, props); useGridRowReorderPreProcessors(apiRef, props); useGridRowGroupingPreProcessors(apiRef, props); diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx index a4a31168d98e9..5f6fd5b06ea15 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro/useDataGridProComponent.tsx @@ -42,6 +42,7 @@ import { selectionStateInitializer, useGridColumnGrouping, columnGroupsStateInitializer, + useGridColumnGroupingPreProcessors, } from '@mui/x-data-grid/internals'; import { GridApiPro } from '../models/gridApiPro'; import { DataGridProProcessedProps } from '../models/dataGridProProps'; @@ -79,6 +80,7 @@ export const useDataGridProComponent = ( /** * Register all pre-processors called during state initialization here. */ + useGridColumnGroupingPreProcessors(apiRef, props); useGridSelectionPreProcessors(apiRef, props); useGridRowReorderPreProcessors(apiRef, props); useGridTreeDataPreProcessors(apiRef, props); diff --git a/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx b/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx index d7d4d88752f64..a7d3060c30b1c 100644 --- a/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx @@ -49,6 +49,7 @@ import { useGridColumnGrouping, columnGroupsStateInitializer, } from '../hooks/features/columns/useGridColumnGrouping'; +import { useGridColumnGroupingPreProcessors } from '../hooks/features/columns/useGridColumnGroupingPreProcessors'; export const useDataGridComponent = (props: DataGridProcessedProps) => { const apiRef = useGridInitialization(undefined, props); @@ -56,6 +57,7 @@ export const useDataGridComponent = (props: DataGridProcessedProps) => { /** * Register all pre-processors called during state initialization here. */ + useGridColumnGroupingPreProcessors(apiRef, props); useGridSelectionPreProcessors(apiRef, props); useGridRowsPreProcessors(apiRef); diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts index 544d5487d7454..b2ff93d548d85 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts @@ -1,6 +1,5 @@ import * as React from 'react'; import { GridApiCommunity } from '../../../models/api/gridApiCommunity'; -import { GridPipeProcessor, useGridRegisterPipeProcessor } from '../../core/pipeProcessing'; import { DataGridProcessedProps } from '../../../models/props/DataGridProps'; import { GridStateInitializer } from '../../utils/useGridInitializeState'; import { @@ -12,7 +11,6 @@ import { gridColumnGroupsLookupSelector, gridColumnLookupSelector } from './grid import { GridColumnGroupLookup } from './gridColumnsInterfaces'; import { GridColumnGroupingApi } from '../../../models/api/gridColumnGroupingApi'; import { useGridApiMethod } from '../../utils/useGridApiMethod'; -import { isDeepEqual } from '../../../utils/utils'; import { GridStateColDef, GridColDef } from '../../../models/colDef'; export function hasGroupPath( @@ -158,39 +156,6 @@ export const useGridColumnGrouping = ( useGridApiMethod(apiRef, columnGroupingApi, 'GridColumnGroupingApi'); - /** - * Processors - * */ - const addHeaderGroups = React.useCallback>( - (columnsState) => { - if (!props.columnGroupingModel) { - return columnsState; - } - const unwrappedGroupingModel = unwrapGroupingColumnModel(props.columnGroupingModel); - if (Object.keys(unwrappedGroupingModel).length === 0) { - return columnsState; - } - - columnsState.all.forEach((field) => { - const newGroupPath = unwrappedGroupingModel[field] ?? []; - - const lookupElement = columnsState.lookup[field]; - if (hasGroupPath(lookupElement) && isDeepEqual(newGroupPath, lookupElement?.groupPath)) { - // Avoid modifying the pointer to allow shadow comparison in https://github.com/mui/mui-x/blob/f90afbf10a1264ee8b453d7549dd7cdd6110a4ed/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts#L446:L453 - return; - } - columnsState.lookup[field] = { - ...columnsState.lookup[field], - groupPath: unwrappedGroupingModel[field] ?? [], - }; - }); - return columnsState; - }, - [props.columnGroupingModel], - ); - - useGridRegisterPipeProcessor(apiRef, 'hydrateColumns', addHeaderGroups); - /** * EFFECTS */ diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGroupingPreProcessors.ts b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGroupingPreProcessors.ts new file mode 100644 index 0000000000000..88b808ec59792 --- /dev/null +++ b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGroupingPreProcessors.ts @@ -0,0 +1,41 @@ +import * as React from 'react'; +import { GridPipeProcessor, useGridRegisterPipeProcessor } from '../../core/pipeProcessing'; +import { DataGridProcessedProps } from '../../../models/props/DataGridProps'; +import { GridApiCommunity } from '../../../models/api/gridApiCommunity'; +import { isDeepEqual } from '../../../utils/utils'; +import { unwrapGroupingColumnModel, hasGroupPath } from './useGridColumnGrouping'; + +export const useGridColumnGroupingPreProcessors = ( + apiRef: React.MutableRefObject, + props: DataGridProcessedProps, +) => { + const addHeaderGroups = React.useCallback>( + (columnsState) => { + if (!props.columnGroupingModel) { + return columnsState; + } + const unwrappedGroupingModel = unwrapGroupingColumnModel(props.columnGroupingModel); + if (Object.keys(unwrappedGroupingModel).length === 0) { + return columnsState; + } + + columnsState.all.forEach((field) => { + const newGroupPath = unwrappedGroupingModel[field] ?? []; + + const lookupElement = columnsState.lookup[field]; + if (hasGroupPath(lookupElement) && isDeepEqual(newGroupPath, lookupElement?.groupPath)) { + // Avoid modifying the pointer to allow shadow comparison in https://github.com/mui/mui-x/blob/f90afbf10a1264ee8b453d7549dd7cdd6110a4ed/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsUtils.ts#L446:L453 + return; + } + columnsState.lookup[field] = { + ...columnsState.lookup[field], + groupPath: unwrappedGroupingModel[field] ?? [], + }; + }); + return columnsState; + }, + [props.columnGroupingModel], + ); + + useGridRegisterPipeProcessor(apiRef, 'hydrateColumns', addHeaderGroups); +}; diff --git a/packages/grid/x-data-grid/src/internals/index.ts b/packages/grid/x-data-grid/src/internals/index.ts index 01081139eea30..d4450f9fb209a 100644 --- a/packages/grid/x-data-grid/src/internals/index.ts +++ b/packages/grid/x-data-grid/src/internals/index.ts @@ -22,6 +22,7 @@ export { useGridColumnGrouping, columnGroupsStateInitializer, } from '../hooks/features/columns/useGridColumnGrouping'; +export { useGridColumnGroupingPreProcessors } from '../hooks/features/columns/useGridColumnGroupingPreProcessors'; export type { GridColumnRawLookup, GridColumnsRawState, From 8e42932889c7a26f35ceaec6442b8948ce17f402 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 6 Jul 2022 16:32:59 +0200 Subject: [PATCH 06/53] add some tests --- .../features/columns/useGridColumnGrouping.ts | 4 +- .../tests/columnsGrouping.DataGrid.test.tsx | 308 ++++++++++++++++++ 2 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts index b2ff93d548d85..58b450fb64df3 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts @@ -64,7 +64,7 @@ export const unwrapGroupingColumnModel = ( if (rep[key] !== undefined) { throw new Error( [ - `MUI DataGrid - column grouping: duplicated field`, + `MUI: column grouping has duplicated field.`, `column field ${key} occurres two times in the grouping model:`, `- ${rep[key].join(' > ')}`, `- ${value.join(' > ')}`, @@ -97,7 +97,7 @@ const createGroupLookup = (columnGroupingModel: GridColumnNode[]): GridColumnGro const groupParam = { ...other, groupId }; const subTreeLookup = createGroupLookup(children); if (subTreeLookup[groupId] !== undefined || groupLookup[groupId] !== undefined) { - throw new Error(`The groupId ${groupId} is used multiple times`); + throw new Error(`MUI: The groupId ${groupId} is used multiple times`); } groupLookup = { ...groupLookup, ...subTreeLookup, [groupId]: groupParam }; }); diff --git a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx new file mode 100644 index 0000000000000..95f3eedca51b1 --- /dev/null +++ b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx @@ -0,0 +1,308 @@ +import * as React from 'react'; +import { expect } from 'chai'; +// @ts-ignore Remove once the test utils are typed +import { createRenderer, ErrorBoundary, screen } from '@mui/monorepo/test/utils'; +import { + DataGrid, + DataGridProps, + GridRowModel, + GridColumns, +} from '@mui/x-data-grid'; + +const isJSDOM = /jsdom/.test(window.navigator.userAgent); + +const getDefaultProps = (nbColumns: number) => { + const columns: GridColumns = []; + const row: GridRowModel = {}; + + for (let i = 1; i <= nbColumns; i += 1) { + columns.push({ field: `col${i}` }); + row[`col${i}`] = i; + } + + return { + disableVirtualization: true, + columns, + rows: [{ id: 0, ...row }], + autoHeight: isJSDOM, + }; +}; + +type TestDataGridProps = Omit & + Partial> & { nbColumns: number }; + +describe(' - Column grouping', () => { + const { render } = createRenderer(); + + const TestDataGrid = (props: TestDataGridProps) => { + const { nbColumns, ...other } = props; + return ( +
+ +
+ ); + }; + + describe('Header grouping columns', () => { + it('should add one header row when columns have a group', () => { + render( + , + ); + expect(screen.queryAllByRole('row')).to.have.length(3); + }); + + it('should add header rows to match max depth oc column groups', () => { + render( + , + ); + expect(screen.queryAllByRole('row')).to.have.length(4); + }); + + it('should add correct aria-colspan, aria-colindex on headers', () => { + render( + , + ); + + const row1Headers = document.querySelectorAll( + '[aria-rowindex="1"] [role="columnheader"]', + ); + const row2Headers = document.querySelectorAll( + '[aria-rowindex="2"] [role="columnheader"]', + ); + + expect( + Array.from(row1Headers).map((header) => header.getAttribute('aria-colspan')), + ).to.deep.equal(['3']); + expect( + Array.from(row1Headers).map((header) => header.getAttribute('aria-colindex')), + ).to.deep.equal(['1']); + + expect( + Array.from(row2Headers).map((header) => header.getAttribute('aria-colspan')), + ).to.deep.equal(['2', '1']); + expect( + Array.from(row2Headers).map((header) => header.getAttribute('aria-colindex')), + ).to.deep.equal(['1', '3']); + }); + + it('should support non connexe groups', () => { + render( + , + ); + + const row1Headers = document.querySelectorAll( + '[aria-rowindex="1"] [role="columnheader"]', + ); + const row2Headers = document.querySelectorAll( + '[aria-rowindex="2"] [role="columnheader"]', + ); + + expect( + Array.from(row1Headers).map((header) => header.getAttribute('aria-colspan')), + ).to.deep.equal(['1', '1', '2']); + expect( + Array.from(row1Headers).map((header) => header.getAttribute('aria-colindex')), + ).to.deep.equal(['1', '2', '3']); + + expect( + Array.from(row2Headers).map((header) => header.getAttribute('aria-colspan')), + ).to.deep.equal(['1', '1', '1', '1']); + expect( + Array.from(row2Headers).map((header) => header.getAttribute('aria-colindex')), + ).to.deep.equal(['1', '2', '3', '4']); + }); + + it('should only consider visible columns non connexe groups', () => { + const { setProps } = render( + , + ); + + // 2 header groups, 1 header, 1 row + expect(screen.queryAllByRole('row')).to.have.length(4); + + // hide the column with 2 nested groups + setProps({ columnVisibilityModel: { col2: false } }); + expect(screen.queryAllByRole('row')).to.have.length(3); + + // hide the last column with a group + setProps({ columnVisibilityModel: { col1: false, col2: false } }); + expect(screen.queryAllByRole('row')).to.have.length(2); + }); + + it('should update headers when `columnGroupingModel` is modified', () => { + const { setProps } = render( + , + ); + + // 2 header groups, 1 header, 1 row + expect(screen.queryAllByRole('row')).to.have.length(4); + + // remove the top group + setProps({ columnGroupingModel: [{ groupId: 'col2', children: [{ field: 'col2' }] }] }); + expect(screen.queryAllByRole('row')).to.have.length(3); + + }); + }); + + // TODO: remove the skip. I failed to test if an error is thrown + // eslint-disable-next-line mocha/no-skipped-tests + describe.skip('error messages', () => { + const TestWithError = (props: TestDataGridProps) => ( + + + + ); + + it('should log an error if two groups have the same id', function test() { + expect(() => { + render( + , + ); + }).toErrorDev() + }); + + it('should log an error if a columns is referenced in two groups', function test() { + expect(() => { + render( + , + ); + }).toErrorDev() + }); + + it('should log an error if a group have no id', function test() { + expect(() => { + try { + render( + , + ); + } catch (error) { + console.error(error); + } + }).toErrorDev( + 'MUI-DataGrid: an element of the columnGroupingModel does not have either `field` or `groupId`', + ); + }); + + it('should log an warning if a group have no children', function test() { + expect(() => { + render( + , + ); + }).toWarnDev('MUI-DataGrid: group groupId=col12 has no children.'); + expect(() => { + render( + , + ); + }).toWarnDev('MUI-DataGrid: group groupId=col12 has no children.'); + }); + }); +}); From 9c33fe2bc3b17c9e92b66898012ef2abab6ca3a9 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Thu, 7 Jul 2022 13:58:51 +0200 Subject: [PATCH 07/53] add and fix tests --- .../columnReorder/useGridColumnReorder.tsx | 6 +- .../tests/columnReorder.DataGridPro.test.tsx | 170 ++++++++++++++++++ .../tests/columnsGrouping.DataGrid.test.tsx | 29 +-- test/utils/helperFn.ts | 7 +- 4 files changed, 184 insertions(+), 28 deletions(-) diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx index b4700de78cb85..a7d797d3b3acd 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -100,14 +100,12 @@ export const useGridColumnReorder = ( originColumnIndex.current = apiRef.current.getColumnIndex(params.field, false); const draggingColumnGroupPath = apiRef.current.getColumnGroupPath(params.field); - if (draggingColumnGroupPath.length === 0) { - forbiddenIndexes.current = {}; - return; - } + const visibleColumnIndex = apiRef.current.getColumnIndex(params.field, true); const visibleColumns = apiRef.current.getVisibleColumns(); const groupsLookup = apiRef.current.getAllGroupDetails(); + // The limitingGroupId is the id of the group from which the dragged column should ne escape let limitingGroupId: string | null = null; draggingColumnGroupPath.forEach((groupId) => { diff --git a/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx index b888dc613b376..66a4450ceffe7 100644 --- a/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx @@ -426,4 +426,174 @@ describe(' - Columns reorder', () => { expect(handleDragOver.callCount).to.equal(0); expect(handleDragEnd.callCount).to.equal(0); }); + + describe('reorder with column grouping', () => { + it('should not allow to drag column outside of its group', () => { + const rows = [{ id: 0 }]; + const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; + + const columnGroupingModel = [ + { groupId: 'col12', children: [{ field: 'col1' }, { field: 'col2' }] }, + ]; + + const Test = () => { + return ( +
+ +
+ ); + }; + + render(); + expect(getColumnHeadersTextContent()).to.deep.equal(['col12', '', 'col1', 'col2', 'col3']); + const dragCol = getColumnHeaderCell(0, 1).firstChild!; + const targetCol = getColumnHeaderCell(2, 1).firstChild!; + + fireEvent.dragStart(dragCol); + fireEvent.dragEnter(targetCol); + const dragOverEvent2 = createDragOverEvent(targetCol); + fireEvent(targetCol, dragOverEvent2); + expect(getColumnHeadersTextContent()).to.deep.equal(['col12', '', 'col1', 'col2', 'col3']); + + const dragEndEvent = createDragEndEvent(dragCol); + fireEvent(dragCol, dragEndEvent); + expect(getColumnHeadersTextContent()).to.deep.equal(['col12', '', 'col1', 'col2', 'col3']); + }); + + it('should not allow to drag column inside a group', () => { + const rows = [{ id: 0 }]; + const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; + + const columnGroupingModel = [ + { groupId: 'col12', children: [{ field: 'col1' }, { field: 'col2' }] }, + ]; + + const Test = () => { + return ( +
+ +
+ ); + }; + + render(); + expect(getColumnHeadersTextContent()).to.deep.equal(['col12', '', 'col1', 'col2', 'col3']); + const dragCol = getColumnHeaderCell(2, 1).firstChild!; + const targetCol = getColumnHeaderCell(1, 1).firstChild!; + + fireEvent.dragStart(dragCol); + fireEvent.dragEnter(targetCol); + const dragOverEvent2 = createDragOverEvent(targetCol); + fireEvent(targetCol, dragOverEvent2); + expect(getColumnHeadersTextContent()).to.deep.equal(['col12', '', 'col1', 'col2', 'col3']); + + const dragEndEvent = createDragEndEvent(dragCol); + fireEvent(dragCol, dragEndEvent); + expect(getColumnHeadersTextContent()).to.deep.equal(['col12', '', 'col1', 'col2', 'col3']); + }); + + it('should allow to drag column outside of its group if it allows freeReordering', () => { + const rows = [{ id: 0 }]; + const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; + + const columnGroupingModel = [ + { + groupId: 'col12', + children: [{ field: 'col1' }, { field: 'col2' }], + freeReordering: true, + }, + ]; + + const Test = () => { + return ( +
+ +
+ ); + }; + + render(); + expect(getColumnHeadersTextContent()).to.deep.equal(['col12', '', 'col1', 'col2', 'col3']); + const dragCol = getColumnHeaderCell(0, 1).firstChild!; + const targetCol = getColumnHeaderCell(2, 1).firstChild!; + + fireEvent.dragStart(dragCol); + fireEvent.dragEnter(targetCol); + const dragOverEvent2 = createDragOverEvent(targetCol); + fireEvent(targetCol, dragOverEvent2); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col12', + '', + 'col12', + 'col2', + 'col3', + 'col1', + ]); + + const dragEndEvent = createDragEndEvent(dragCol); + fireEvent(dragCol, dragEndEvent); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col12', + '', + 'col12', + 'col2', + 'col3', + 'col1', + ]); + }); + + it('should allow to drag column inside a group if it allows freeReordering', () => { + // TODO: I observed columns are always moved from left to right + // The reason being that is: + // - when event.clientX does not change we consider that column is moving to the right + // - fireEvent.dragStart always set event.clientX = 1 (did not managed to modify this behavior) + const rows = [{ id: 0 }]; + const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; + + const columnGroupingModel = [ + { + groupId: 'col23', + children: [{ field: 'col2' }, { field: 'col3' }], + freeReordering: true, + }, + ]; + + const Test = () => { + return ( +
+ +
+ ); + }; + + render(); + expect(getColumnHeadersTextContent()).to.deep.equal(['', 'col23', 'col1', 'col2', 'col3']); + const dragCol = getColumnHeaderCell(0, 1).firstChild!; + const targetCol = getColumnHeaderCell(1, 1).firstChild!; + + fireEvent.dragStart(dragCol); + fireEvent.dragEnter(targetCol); + const dragOverEvent2 = createDragOverEvent(targetCol); + fireEvent(targetCol, dragOverEvent2); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col23', + '', + 'col23', + 'col2', + 'col1', + 'col3', + ]); + + const dragEndEvent = createDragEndEvent(dragCol); + fireEvent(dragCol, dragEndEvent); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col23', + '', + 'col23', + 'col2', + 'col1', + 'col3', + ]); + }); + }); }); diff --git a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx index 95f3eedca51b1..0a46518588200 100644 --- a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx @@ -2,12 +2,7 @@ import * as React from 'react'; import { expect } from 'chai'; // @ts-ignore Remove once the test utils are typed import { createRenderer, ErrorBoundary, screen } from '@mui/monorepo/test/utils'; -import { - DataGrid, - DataGridProps, - GridRowModel, - GridColumns, -} from '@mui/x-data-grid'; +import { DataGrid, DataGridProps, GridRowModel, GridColumns } from '@mui/x-data-grid'; const isJSDOM = /jsdom/.test(window.navigator.userAgent); @@ -192,7 +187,6 @@ describe(' - Column grouping', () => { // remove the top group setProps({ columnGroupingModel: [{ groupId: 'col2', children: [{ field: 'col2' }] }] }); expect(screen.queryAllByRole('row')).to.have.length(3); - }); }); @@ -200,7 +194,7 @@ describe(' - Column grouping', () => { // eslint-disable-next-line mocha/no-skipped-tests describe.skip('error messages', () => { const TestWithError = (props: TestDataGridProps) => ( - + ); @@ -213,15 +207,12 @@ describe(' - Column grouping', () => { columnGroupingModel={[ { groupId: 'col12', - children: [ - { field: 'col1' }, - { groupId: 'col12', children: [{ field: 'col2' }] } - ], + children: [{ field: 'col1' }, { groupId: 'col12', children: [{ field: 'col2' }] }], }, ]} />, ); - }).toErrorDev() + }).toErrorDev(); }); it('should log an error if a columns is referenced in two groups', function test() { @@ -232,22 +223,16 @@ describe(' - Column grouping', () => { columnGroupingModel={[ { groupId: 'col12', - children: [ - { field: 'col1' }, - { field: 'col2' }, - ], + children: [{ field: 'col1' }, { field: 'col2' }], }, { groupId: 'col23', - children: [ - { field: 'col2' }, - { field: 'col3' }, - ], + children: [{ field: 'col2' }, { field: 'col3' }], }, ]} />, ); - }).toErrorDev() + }).toErrorDev(); }); it('should log an error if a group have no id', function test() { diff --git a/test/utils/helperFn.ts b/test/utils/helperFn.ts index c24e9ab00d0bd..c5b06dea84f25 100644 --- a/test/utils/helperFn.ts +++ b/test/utils/helperFn.ts @@ -64,9 +64,12 @@ export function getColumnValues(colIndex: number) { ); } -export function getColumnHeaderCell(colIndex: number): HTMLElement { +export function getColumnHeaderCell(colIndex: number, rowIndex?: number): HTMLElement { + const headerRowSelector = + rowIndex === undefined ? '' : `[role="row"][aria-rowindex="${rowIndex + 1}"] `; + const headerCellSelector = `[role="columnheader"][aria-colindex="${colIndex + 1}"]`; const columnHeader = document.querySelector( - `[role="columnheader"][aria-colindex="${colIndex + 1}"]`, + `${headerRowSelector}${headerCellSelector}`, ); if (columnHeader == null) { throw new Error(`columnheader ${colIndex} not found`); From d5f09393b4afe16aac0463756ebadc6baee0a1a4 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Thu, 7 Jul 2022 14:16:53 +0200 Subject: [PATCH 08/53] add test --- .../tests/columnReorder.DataGridPro.test.tsx | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx index 66a4450ceffe7..9d84cfe999557 100644 --- a/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx @@ -595,5 +595,139 @@ describe(' - Columns reorder', () => { 'col3', ]); }); + + it('should allow to split a group with freeReordering in another group', () => { + const rows = [{ id: 0 }]; + const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; + + const columnGroupingModel = [ + { + groupId: 'col123', + children: [ + { field: 'col1' }, + { + groupId: 'col23', + children: [{ field: 'col2' }, { field: 'col3' }], + freeReordering: true, + }, + ], + }, + ]; + + const Test = () => { + return ( +
+ +
+ ); + }; + + render(); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col123', + '', + 'col23', + 'col1', + 'col2', + 'col3', + ]); + const dragCol = getColumnHeaderCell(0, 1).firstChild!; + const targetCol = getColumnHeaderCell(1, 1).firstChild!; + + fireEvent.dragStart(dragCol); + fireEvent.dragEnter(targetCol); + const dragOverEvent2 = createDragOverEvent(targetCol); + fireEvent(targetCol, dragOverEvent2); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col123', + 'col23', + '', + 'col23', + 'col2', + 'col1', + 'col3', + ]); + + const dragEndEvent = createDragEndEvent(dragCol); + fireEvent(dragCol, dragEndEvent); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col123', + 'col23', + '', + 'col23', + 'col2', + 'col1', + 'col3', + ]); + }); + + it('should block dragging outside ot a group even at deeper level', () => { + const rows = [{ id: 0 }]; + const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; + + const columnGroupingModel = [ + { + groupId: 'col12', + children: [ + { field: 'col1' }, + { + groupId: 'col2', + children: [{ field: 'col2' }], + freeReordering: true, + }, + ], + }, + ]; + + const Test = () => { + return ( +
+ +
+ ); + }; + + render(); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col12', + '', + '', + 'col2', + '', + 'col1', + 'col2', + 'col3', + ]); + const dragCol = getColumnHeaderCell(0, 1).firstChild!; + const targetCol = getColumnHeaderCell(2, 1).firstChild!; + + fireEvent.dragStart(dragCol); + fireEvent.dragEnter(targetCol); + const dragOverEvent2 = createDragOverEvent(targetCol); + fireEvent(targetCol, dragOverEvent2); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col12', + '', + '', + 'col2', + '', + 'col1', + 'col2', + 'col3', + ]); + + const dragEndEvent = createDragEndEvent(dragCol); + fireEvent(dragCol, dragEndEvent); + expect(getColumnHeadersTextContent()).to.deep.equal([ + 'col12', + '', + '', + 'col2', + '', + 'col1', + 'col2', + 'col3', + ]); + }); }); }); From a01c4ea43891a82333f302fd20e484627669b71e Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Fri, 8 Jul 2022 14:17:51 +0200 Subject: [PATCH 09/53] use same components for column and group headers --- .../src/DataGridPremium/DataGridPremium.tsx | 1 + .../src/DataGridPro/DataGridPro.tsx | 1 + .../tests/columnReorder.DataGridPro.test.tsx | 4 +- .../x-data-grid/src/DataGrid/DataGrid.tsx | 1 + .../columnHeaders/GridColumnGroupHeader.tsx | 99 ++++++---- .../columnHeaders/GridColumnHeaderItem.tsx | 143 ++++---------- .../GridGenericColumnHeaderItem.tsx | 181 ++++++++++++++++++ .../columnHeaders/useGridColumnHeaders.tsx | 1 + .../src/models/gridColumnGrouping.ts | 6 +- 9 files changed, 288 insertions(+), 149 deletions(-) create mode 100644 packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx diff --git a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 3a8f6b6e1e342..a9a78c7cfc580 100644 --- a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -131,6 +131,7 @@ DataGridPremiumRaw.propTypes = { description: PropTypes.string, freeReordering: PropTypes.bool, groupId: PropTypes.string.isRequired, + headerAlign: PropTypes.oneOf(['center', 'left', 'right']), headerName: PropTypes.string, renderHeaderGroup: PropTypes.func, }), diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 222d00be388e8..9326b543189dd 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -128,6 +128,7 @@ DataGridProRaw.propTypes = { description: PropTypes.string, freeReordering: PropTypes.bool, groupId: PropTypes.string.isRequired, + headerAlign: PropTypes.oneOf(['center', 'left', 'right']), headerName: PropTypes.string, renderHeaderGroup: PropTypes.func, }), diff --git a/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx index 9d84cfe999557..fe18705aca198 100644 --- a/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx @@ -631,8 +631,8 @@ describe(' - Columns reorder', () => { 'col2', 'col3', ]); - const dragCol = getColumnHeaderCell(0, 1).firstChild!; - const targetCol = getColumnHeaderCell(1, 1).firstChild!; + const dragCol = getColumnHeaderCell(0, 2).firstChild!; + const targetCol = getColumnHeaderCell(1, 2).firstChild!; fireEvent.dragStart(dragCol); fireEvent.dragEnter(targetCol); diff --git a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx index 8275651415ef3..e6269f7040b6e 100644 --- a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx @@ -102,6 +102,7 @@ DataGridRaw.propTypes = { description: PropTypes.string, freeReordering: PropTypes.bool, groupId: PropTypes.string.isRequired, + headerAlign: PropTypes.oneOf(['center', 'left', 'right']), headerName: PropTypes.string, renderHeaderGroup: PropTypes.func, }), diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx index 09cfc6f95072b..0ac7fcf321d70 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx @@ -1,12 +1,14 @@ import * as React from 'react'; +import { unstable_useId as useId } from '@mui/utils'; import { unstable_composeClasses as composeClasses } from '@mui/material'; -import { GridColumnHeaderTitle } from './GridColumnHeaderTitle'; +import { GridAlignment } from '../../models/colDef/gridColDef'; import { getDataGridUtilityClass } from '../../constants/gridClasses'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; import { DataGridProcessedProps } from '../../models/props/DataGridProps'; import { gridColumnGroupsLookupSelector } from '../../hooks/features/columns/gridColumnsSelector'; import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { useGridSelector } from '../../hooks/utils/useGridSelector'; +import { GridGenericColumnHeaderItem } from './GridGenericColumnHeaderItem'; interface GridColumnGroupHeaderProps { groupId: string | null; @@ -17,34 +19,48 @@ interface GridColumnGroupHeaderProps { extendRowFullWidth: boolean; depth: number; maxDepth: number; + height: number; } -type OwnerState = GridColumnGroupHeaderProps & { +type OwnerState = { showRightBorder: boolean; - depth: number; - maxDepth: number; + isDragging: boolean; + headerAlign?: GridAlignment; classes?: DataGridProcessedProps['classes']; }; const useUtilityClasses = (ownerState: OwnerState) => { - const { groupId, classes, showRightBorder } = ownerState; + const { classes, headerAlign, isDragging, showRightBorder } = ownerState; const slots = { root: [ - 'columnGroupHeader', + 'columnHeader', + headerAlign === 'left' && 'columnHeader--alignLeft', + headerAlign === 'center' && 'columnHeader--alignCenter', + headerAlign === 'right' && 'columnHeader--alignRight', + isDragging && 'columnHeader--moving', showRightBorder && 'withBorder', - groupId ? 'columnGroupHeader--withName' : 'columnGroupHeader--withoutName', ], - titleContainer: ['columnGroupHeaderTitleContainer'], - titleContainerContent: ['columnGroupHeaderTitleContainerContent'], + draggableContainer: ['columnHeaderDraggableContainer'], + titleContainer: ['columnHeaderTitleContainer'], + titleContainerContent: ['columnHeaderTitleContainerContent'], }; return composeClasses(slots, getDataGridUtilityClass, classes); }; function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { - const { groupId, width, depth, maxDepth, fields, colIndex, isLastColumn, extendRowFullWidth } = - props; + const { + groupId, + width, + depth, + maxDepth, + fields, + height, + colIndex, + isLastColumn, + extendRowFullWidth, + } = props; const rootProps = useGridRootProps(); @@ -55,11 +71,13 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { hasScrollY: false, }; - const { headerName = groupId ?? '', description = '' } = groupId - ? columnGroupsLookup[groupId] - : {}; + const { + headerName = groupId ?? '', + description = '', + headerAlign = undefined, + } = groupId ? columnGroupsLookup[groupId] : {}; - let headerComponent: React.ReactNode = null; + let headerComponent: React.ReactNode; const render = groupId && columnGroupsLookup[groupId]?.renderHeaderGroup; if (groupId && render) { @@ -75,8 +93,6 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { }); } - const headerCellRef = React.useRef(null); - const removeLastBorderRight = isLastColumn && hasScrollX && !hasScrollY; const showRightBorder = !isLastColumn ? rootProps.showColumnRightBorder @@ -86,38 +102,39 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { ...props, classes: rootProps.classes, showRightBorder, + headerAlign, depth, + isDragging: false, }; + const label = headerName ?? groupId; + + const id = useId(); + const elementId = groupId === null ? `empty-group-cell-${id}` : groupId; const classes = useUtilityClasses(ownerState); return ( -
-
-
- {headerComponent || ( - - )} -
-
-
+ /> ); } diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx index 83cf862460b9d..2a872bc470708 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx @@ -1,23 +1,18 @@ import * as React from 'react'; import PropTypes from 'prop-types'; -import clsx from 'clsx'; import { unstable_composeClasses as composeClasses } from '@mui/material'; import { unstable_useId as useId } from '@mui/material/utils'; -import { GridColumnHeaderEventLookup } from '../../models/events'; import { GridStateColDef } from '../../models/colDef/gridColDef'; import { GridSortDirection } from '../../models/gridSortModel'; import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { GridColumnHeaderSortIcon } from './GridColumnHeaderSortIcon'; -import { GridColumnHeaderTitle } from './GridColumnHeaderTitle'; -import { - GridColumnHeaderSeparator, - GridColumnHeaderSeparatorProps, -} from './GridColumnHeaderSeparator'; +import { GridColumnHeaderSeparatorProps } from './GridColumnHeaderSeparator'; import { ColumnHeaderMenuIcon } from './ColumnHeaderMenuIcon'; import { GridColumnHeaderMenu } from '../menu/columnMenu/GridColumnHeaderMenu'; import { getDataGridUtilityClass } from '../../constants/gridClasses'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; import { DataGridProcessedProps } from '../../models/props/DataGridProps'; +import { GridGenericColumnHeaderItem } from './GridGenericColumnHeaderItem'; interface GridColumnHeaderItemProps { colIndex: number; @@ -106,48 +101,11 @@ function GridColumnHeaderItem(props: GridColumnHeaderItemProps) { [rootProps.disableColumnReorder, disableReorder, column.disableReorder], ); - let headerComponent: React.ReactNode = null; + let headerComponent: React.ReactNode; if (column.renderHeader) { headerComponent = column.renderHeader(apiRef.current.getColumnHeaderParams(column.field)); } - const publish = React.useCallback( - (eventName: keyof GridColumnHeaderEventLookup) => (event: React.SyntheticEvent) => { - // Ignore portal - // See https://github.com/mui/mui-x/issues/1721 - if (!event.currentTarget.contains(event.target as Element)) { - return; - } - apiRef.current.publishEvent( - eventName, - apiRef.current.getColumnHeaderParams(column.field), - event as any, - ); - }, - [apiRef, column.field], - ); - - const mouseEventsHandlers = { - onClick: publish('columnHeaderClick'), - onDoubleClick: publish('columnHeaderDoubleClick'), - onMouseOver: publish('columnHeaderOver'), // TODO remove as it's not used - onMouseOut: publish('columnHeaderOut'), // TODO remove as it's not used - onMouseEnter: publish('columnHeaderEnter'), // TODO remove as it's not used - onMouseLeave: publish('columnHeaderLeave'), // TODO remove as it's not used - onKeyDown: publish('columnHeaderKeyDown'), - onFocus: publish('columnHeaderFocus'), - onBlur: publish('columnHeaderBlur'), - }; - - const draggableEventHandlers = isDraggable - ? { - onDragStart: publish('columnHeaderDragStart'), - onDragEnter: publish('columnHeaderDragEnter'), - onDragOver: publish('columnHeaderDragOver'), - onDragEnd: publish('columnHeaderDragEnd'), - } - : null; - const removeLastBorderRight = isLastColumn && hasScrollX && !hasScrollY; const showRightBorder = !isLastColumn ? rootProps.showColumnRightBorder @@ -161,13 +119,6 @@ function GridColumnHeaderItem(props: GridColumnHeaderItemProps) { const classes = useUtilityClasses(ownerState); - const width = column.computedWidth; - - let ariaSort: 'ascending' | 'descending' | 'none' = 'none'; - if (sortDirection != null) { - ariaSort = sortDirection === 'asc' ? 'ascending' : 'descending'; - } - React.useEffect(() => { if (!showColumnMenuIcon) { setShowColumnMenuIcon(columnMenuOpen); @@ -188,6 +139,19 @@ function GridColumnHeaderItem(props: GridColumnHeaderItemProps) { /> ); + const columnMenu = ( + + ); + const sortingOrder: GridSortDirection[] = column.sortingOrder ?? rootProps.sortingOrder; const columnTitleIconButtons = ( @@ -228,61 +192,30 @@ function GridColumnHeaderItem(props: GridColumnHeaderItemProps) { const label = column.headerName ?? column.field; return ( -
-
-
-
- {column.renderHeader ? ( - headerComponent - ) : ( - - )} -
- {columnTitleIconButtons} -
- {columnMenuIconButton} -
- - -
+ separatorSide={separatorSide} + isDraggable={isDraggable} + headerComponent={headerComponent} + description={column.description} + elementId={column.field} + width={column.computedWidth} + columnMenuIconButton={columnMenuIconButton} + columnTitleIconButtons={columnTitleIconButtons} + headerClassName={headerClassName} + label={label} + resizable={!rootProps.disableColumnResize && !!column.resizable} + data-field={column.field} + columnMenu={columnMenu} + /> ); } diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx new file mode 100644 index 0000000000000..a0c87a96988df --- /dev/null +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx @@ -0,0 +1,181 @@ +import * as React from 'react'; +import clsx from 'clsx'; +import { useForkRef } from '@mui/material/utils'; +import { GridColumnHeaderEventLookup } from '../../models/events'; +import { GridStateColDef } from '../../models/colDef/gridColDef'; +import { GridSortDirection } from '../../models/gridSortModel'; +import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; +import { GridColumnHeaderTitle } from './GridColumnHeaderTitle'; +import { + GridColumnHeaderSeparator, + GridColumnHeaderSeparatorProps, +} from './GridColumnHeaderSeparator'; +import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; +import { GridColumnGroup } from '../../models/gridColumnGrouping'; + +interface GridGenericColumnHeaderItemProps + extends Pick { + classes: Record< + 'root' | 'draggableContainer' | 'titleContainer' | 'titleContainerContent', + string + >; + colIndex: number; + columnMenuOpen: boolean; + height: number; + isResizing: boolean; + sortDirection: GridSortDirection; + sortIndex?: number; + filterItemsCounter?: number; + hasFocus?: boolean; + tabIndex: 0 | -1; + disableReorder?: boolean; + separatorSide?: GridColumnHeaderSeparatorProps['side']; + headerComponent?: React.ReactNode; + elementId: GridStateColDef['field'] | GridColumnGroup['groupId']; + isDraggable: boolean; + width: number; + columnMenuIconButton?: React.ReactNode; + columnMenu?: React.ReactNode; + columnTitleIconButtons?: React.ReactNode; + label: string; +} + +const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnHeaderItem( + props: GridGenericColumnHeaderItemProps, + ref, +) { + const { + classes, + columnMenuOpen, + colIndex, + height, + isResizing, + sortDirection, + hasFocus, + tabIndex, + separatorSide, + isDraggable, + headerComponent, + description, + elementId, + width, + columnMenuIconButton = null, + columnMenu = null, + columnTitleIconButtons = null, + headerClassName, + label, + resizable, + ...other + } = props; + + const apiRef = useGridApiContext(); + const rootProps = useGridRootProps(); + const headerCellRef = React.useRef(null); + const [showColumnMenuIcon, setShowColumnMenuIcon] = React.useState(columnMenuOpen); + + const handleRef = useForkRef(headerCellRef, ref); + const publish = React.useCallback( + (eventName: keyof GridColumnHeaderEventLookup) => (event: React.SyntheticEvent) => { + // Ignore portal + // See https://github.com/mui/mui-x/issues/1721 + if (!event.currentTarget.contains(event.target as Element)) { + return; + } + apiRef.current.publishEvent( + eventName, + apiRef.current.getColumnHeaderParams(elementId), + event as any, + ); + }, + [apiRef, elementId], + ); + + const mouseEventsHandlers = { + onClick: publish('columnHeaderClick'), + onDoubleClick: publish('columnHeaderDoubleClick'), + onMouseOver: publish('columnHeaderOver'), // TODO remove as it's not used + onMouseOut: publish('columnHeaderOut'), // TODO remove as it's not used + onMouseEnter: publish('columnHeaderEnter'), // TODO remove as it's not used + onMouseLeave: publish('columnHeaderLeave'), // TODO remove as it's not used + onKeyDown: publish('columnHeaderKeyDown'), + onFocus: publish('columnHeaderFocus'), + onBlur: publish('columnHeaderBlur'), + }; + + const draggableEventHandlers = isDraggable + ? { + onDragStart: publish('columnHeaderDragStart'), + onDragEnter: publish('columnHeaderDragEnter'), + onDragOver: publish('columnHeaderDragOver'), + onDragEnd: publish('columnHeaderDragEnd'), + } + : null; + + let ariaSort: 'ascending' | 'descending' | 'none' = 'none'; + if (sortDirection != null) { + ariaSort = sortDirection === 'asc' ? 'ascending' : 'descending'; + } + + React.useEffect(() => { + if (!showColumnMenuIcon) { + setShowColumnMenuIcon(columnMenuOpen); + } + }, [showColumnMenuIcon, columnMenuOpen]); + + React.useLayoutEffect(() => { + const columnMenuState = apiRef.current.state.columnMenu; + if (hasFocus && !columnMenuState.open) { + const focusableElement = headerCellRef.current!.querySelector('[tabindex="0"]'); + const elementToFocus = focusableElement || headerCellRef.current; + elementToFocus?.focus(); + apiRef.current.columnHeadersContainerElementRef!.current!.scrollLeft = 0; + } + }, [apiRef, hasFocus]); + + return ( +
+
+
+
+ {headerComponent !== undefined ? ( + headerComponent + ) : ( + + )} +
+ {columnTitleIconButtons} +
+ {columnMenuIconButton} +
+ + {columnMenu} +
+ ); +}); + +export { GridGenericColumnHeaderItem }; diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index a081ad0e558f5..f05b99afcb7bc 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -485,6 +485,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { isLastColumn={colIndex === visibleColumns.length - fields.length} extendRowFullWidth={!rootProps.disableExtendRowFullWidth} maxDepth={headerToRender.length} + height={headerGroupingRowHeight} /> ); })} diff --git a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts index c9bd353085e69..6b19af4439b36 100644 --- a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts @@ -1,4 +1,4 @@ -import { GridColDef } from './colDef'; +import { GridAlignment, GridColDef } from './colDef'; export type LeafColumn = { field: GridColDef['field']; @@ -43,6 +43,10 @@ export type GridColumnGroup = { * @default false */ freeReordering?: boolean; + /** + * Header cell element alignment. + */ + headerAlign?: GridAlignment; /** * Allows to render a component in the column group header cell. * @param {GridColumnGroupHeaderParams} params Object containing parameters for the renderer. From 373b04e622742a626a1a93e014e7b0a0626ef82d Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Fri, 8 Jul 2022 15:54:02 +0200 Subject: [PATCH 10/53] fix height inconsitencies --- .../src/components/columnHeaders/GridGenericColumnHeaderItem.tsx | 1 + .../src/hooks/features/columnHeaders/useGridColumnHeaders.tsx | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx index a0c87a96988df..ae47f8db6f86c 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx @@ -137,6 +137,7 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH ref={handleRef} className={clsx(classes.root, headerClassName)} style={{ + height, width, minWidth: width, maxWidth: width, diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index f05b99afcb7bc..6d6d5e7a9303e 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -465,7 +465,6 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { columns.push( Date: Mon, 11 Jul 2022 17:28:19 +0200 Subject: [PATCH 11/53] typo feedbacks Co-authored-by: Flavien DELANGLE --- .../features/columnReorder/useGridColumnReorder.tsx | 2 +- .../hooks/features/columns/useGridColumnGrouping.ts | 2 +- .../src/hooks/features/density/useGridDensity.tsx | 2 +- .../src/models/api/gridColumnGroupingApi.ts | 12 ++++++++---- .../grid/x-data-grid/src/models/colDef/gridColDef.ts | 6 ++++-- .../x-data-grid/src/models/gridColumnGrouping.ts | 2 +- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx index a7d797d3b3acd..0ca4678c9b110 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -105,7 +105,7 @@ export const useGridColumnReorder = ( const visibleColumns = apiRef.current.getVisibleColumns(); const groupsLookup = apiRef.current.getAllGroupDetails(); - // The limitingGroupId is the id of the group from which the dragged column should ne escape + // The limitingGroupId is the id of the group from which the dragged column should not escape let limitingGroupId: string | null = null; draggingColumnGroupPath.forEach((groupId) => { diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts index 58b450fb64df3..7397a022bc4ed 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts @@ -37,7 +37,7 @@ const recurrentUnwrapGroupingColumnModel = ( throw new Error( [ `MUI DataGrid - column grouping: duplicated field`, - `column field ${key} occurres two times in the grouping model:`, + `column field ${key} occurrs two times in the grouping model:`, `- ${rep[key].join(' > ')}`, `- ${value.join(' > ')}`, ].join('\n'), diff --git a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx index 7d0351d1e3d3a..01f7483b5b1dc 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx @@ -64,7 +64,7 @@ export const densityStateInitializer: GridStateInitializer< > > = (state, props) => { // TODO: think about improving this initialization. Could it be done in the useColumn initializer? - // TODO: ma,age to remove ts-ignore + // TODO: manage to remove ts-ignore let maxDepth: number; if (props.columnGroupingModel == null || Object.keys(props.columnGroupingModel).length === 0) { maxDepth = 0; diff --git a/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts b/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts index 31b48e589a4d2..8e227a961df83 100644 --- a/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts +++ b/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts @@ -6,20 +6,24 @@ import { GridColumnGroup } from '../gridColumnGrouping'; */ export interface GridColumnGroupingApi { /** - * Returns the array of groupId applied on the column `field`. + * Returns the id of the groups leading to the requested column. + * The array is ordered by increasing depth (the last element is the direct parent of the column). + * @param {string} field The field of of the column requested. + * @returns {string[]} The id of the groups leading to the requested column. + * @param {string} field The id of of the column requested. * @returns {string[]} array of groupId. */ getColumnGroupPath: (field: string) => GridColumnGroup['groupId'][]; /** - * Returns the details about a group corresponding to `groupId`. + * Returns the details of the requested group. * @param {string} groupId The id of the group requested. - * @returns {Omit} group details. + * @returns {Omit} The group details. */ getGroupDetails: (groupId: string) => Omit | null; /** * Returns the column group lookup. - * @returns {GridColumnGroupLookup} groupsLookup. + * @returns {GridColumnGroupLookup} The column group lookup. */ getAllGroupDetails: () => GridColumnGroupLookup; } diff --git a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts index db5b67dcd322c..131e53ebbdc0d 100644 --- a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts +++ b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts @@ -285,8 +285,10 @@ export type GridStateColDef = */ hasBeenResized?: boolean; /** - * The array groupId containing the column from top to bottom. - * This parameters is computed from `columnGroupingModel` props + * The id of the groups leading to the column. + * The array is ordered by increasing depth (the last element is the direct parent of the column). + * If not defined, the column is in no group (equivalent to a path equal to `[]`) + * This parameter is computed from the `columnGroupingModel` prop. */ groupPath?: string[]; }; diff --git a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts index 6b19af4439b36..3863abad61d24 100644 --- a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts @@ -27,7 +27,7 @@ export type GridColumnGroup = { */ groupId: string; /** - * The array of groups and columns included in this group + * The groups and columns included in this group */ children: GridColumnNode[]; /** From 83144c418fcaf67574d7a3aeae05a22fa418fc7d Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Mon, 11 Jul 2022 17:11:58 +0200 Subject: [PATCH 12/53] feedbacks on doc --- .../column-groups/BreakingGroupDemo.js | 39 ++++++++----------- .../column-groups/BreakingGroupDemo.tsx | 39 ++++++++----------- .../data-grid/column-groups/column-groups.md | 4 +- 3 files changed, 34 insertions(+), 48 deletions(-) diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.js b/docs/data/data-grid/column-groups/BreakingGroupDemo.js index ebb00387cb99e..66d7a57dbc90d 100644 --- a/docs/data/data-grid/column-groups/BreakingGroupDemo.js +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.js @@ -2,7 +2,8 @@ import * as React from 'react'; import { DataGridPro } from '@mui/x-data-grid-pro'; const columns = [ - { field: 'id', headerName: 'ID', width: 90 }, + { field: 'id', headerName: 'ID', width: 100 }, + { field: 'isAdmin', type: 'boolean', headerName: 'is admin', width: 100 }, { field: 'firstName', headerName: 'First name', @@ -25,37 +26,29 @@ const columns = [ ]; const rows = [ - { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, - { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, - { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, - { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, - { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, - { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, - { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, - { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, - { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, + { id: 1, isAdmin: false, lastName: 'Snow', firstName: 'Jon', age: 35 }, + { id: 2, isAdmin: true, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, + { id: 3, isAdmin: false, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, + { id: 4, isAdmin: false, lastName: 'Stark', firstName: 'Arya', age: 16 }, + { id: 5, isAdmin: true, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, + { id: 6, isAdmin: true, lastName: 'Melisandre', firstName: null, age: 150 }, + { id: 7, isAdmin: false, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, + { id: 8, isAdmin: false, lastName: 'Frances', firstName: 'Rossini', age: 36 }, + { id: 9, isAdmin: false, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, ]; const columnGroupingModel = [ { groupId: 'internal_data', - headerName: 'Internal', + headerName: 'Internal (not freeReordering)', description: '', - children: [{ field: 'id' }], + children: [{ field: 'id' }, { field: 'isAdmin' }], }, { - groupId: 'perso', - description: 'Information about the character', - headerName: 'Character (freeReordering)', + groupId: 'naming', + headerName: 'Names (freeReordering)', freeReordering: true, - children: [ - { - groupId: 'naming', - headerName: 'Names', - children: [{ field: 'lastName' }, { field: 'firstName' }], - }, - { field: 'age' }, - ], + children: [{ field: 'lastName' }, { field: 'firstName' }], }, ]; diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx index 9f85d62d4417b..c4a1fbd76d0b8 100644 --- a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx @@ -3,7 +3,8 @@ import { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'; import { GridColumnGroupingModel } from '@mui/x-data-grid/models/gridColumnGrouping'; const columns: GridColDef[] = [ - { field: 'id', headerName: 'ID', width: 90 }, + { field: 'id', headerName: 'ID', width: 100 }, + { field: 'isAdmin', type: 'boolean', headerName: 'is admin', width: 100 }, { field: 'firstName', headerName: 'First name', @@ -26,37 +27,29 @@ const columns: GridColDef[] = [ ]; const rows = [ - { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, - { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, - { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, - { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, - { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, - { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, - { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, - { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, - { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, + { id: 1, isAdmin: false, lastName: 'Snow', firstName: 'Jon', age: 35 }, + { id: 2, isAdmin: true, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, + { id: 3, isAdmin: false, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, + { id: 4, isAdmin: false, lastName: 'Stark', firstName: 'Arya', age: 16 }, + { id: 5, isAdmin: true, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, + { id: 6, isAdmin: true, lastName: 'Melisandre', firstName: null, age: 150 }, + { id: 7, isAdmin: false, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, + { id: 8, isAdmin: false, lastName: 'Frances', firstName: 'Rossini', age: 36 }, + { id: 9, isAdmin: false, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, ]; const columnGroupingModel: GridColumnGroupingModel = [ { groupId: 'internal_data', - headerName: 'Internal', + headerName: 'Internal (not freeReordering)', description: '', - children: [{ field: 'id' }], + children: [{ field: 'id' }, { field: 'isAdmin' }], }, { - groupId: 'perso', - description: 'Information about the character', - headerName: 'Character (freeReordering)', + groupId: 'naming', + headerName: 'Names (freeReordering)', freeReordering: true, - children: [ - { - groupId: 'naming', - headerName: 'Names', - children: [{ field: 'lastName' }, { field: 'firstName' }], - }, - { field: 'age' }, - ], + children: [{ field: 'lastName' }, { field: 'firstName' }], }, ]; export default function BreakingGroupDemo() { diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index ce72217471abe..078e9b300f755 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -24,7 +24,7 @@ The children can contains two types of objects: - other column groups which allows you to have nested groups. :::warning -Since this is a tree structure, a column can be associated to only one group. +A column can only be associated with one group. ::: ```jsx @@ -88,7 +88,7 @@ This feature isn't implemented yet. It's coming. The column group should allow to switch between an extended/collapsed view which hide/show some columns -## Reordering groups 🚧 +## Reordering groups 🚧[](https://mui.com/store/items/mui-x-pro/) :::warning This feature isn't implemented yet. It's coming. From a82db7b28219f4a839c4636b1a05bedcf0937a80 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Mon, 11 Jul 2022 17:52:31 +0200 Subject: [PATCH 13/53] type documentation --- docs/pages/x/api/data-grid/grid-api.md | 4 +- .../features/columns/useGridColumnGrouping.ts | 19 +++++++--- .../src/models/api/gridDensityApi.ts | 1 + .../src/models/gridColumnGrouping.ts | 37 +++++++++++++------ scripts/x-data-grid-premium.exports.json | 4 +- scripts/x-data-grid-pro.exports.json | 4 +- scripts/x-data-grid.exports.json | 4 +- 7 files changed, 48 insertions(+), 25 deletions(-) diff --git a/docs/pages/x/api/data-grid/grid-api.md b/docs/pages/x/api/data-grid/grid-api.md index f3eff6b12b1af..f936b24adc942 100644 --- a/docs/pages/x/api/data-grid/grid-api.md +++ b/docs/pages/x/api/data-grid/grid-api.md @@ -32,7 +32,7 @@ import { GridApi } from '@mui/x-data-grid-pro'; | getCellParams | <V = any, R extends GridValidRowModel = any, F = V>(id: GridRowId, field: string) => GridCellParams<R, V, F> | Gets the [GridCellParams](/x/api/data-grid/grid-cell-params/) object that is passed as argument in events. | | getCellValue | <V extends any = any>(id: GridRowId, field: string) => V | Gets the value of a cell at the given `id` and `field`. | | getColumn | (field: string) => GridStateColDef | Returns the [GridColDef](/x/api/data-grid/grid-col-def/) for the given `field`. | -| getColumnGroupPath | (field: string) => GridColumnGroup['groupId'][] | Returns the array of groupId applied on the column `field`. | +| getColumnGroupPath | (field: string) => GridColumnGroup['groupId'][] | Returns the id of the groups leading to the requested column.
The array is ordered by increasing depth (the last element is the direct parent of the column). | | getColumnHeaderElement | (field: string) => HTMLDivElement \| null | Gets the underlying DOM element for the column header with the given `field`. | | getColumnHeaderParams | (field: string) => GridColumnHeaderParams | Gets the GridColumnHeaderParams object that is passed as argument in events. | | getColumnIndex | (field: string, useVisibleColumns?: boolean) => number | Returns the index position of a column. By default, only the visible columns are considered.
Pass `false` to `useVisibleColumns` to consider all columns. | @@ -42,7 +42,7 @@ import { GridApi } from '@mui/x-data-grid-pro'; | getDataAsExcel [](https://mui.com/store/items/material-ui-premium/) | (options?: GridExcelExportOptions) => Promise<Excel.Workbook> \| null | Returns the grid data as an exceljs workbook.
This method is used internally by `exportDataAsExcel`. | | getEditRowsModel | () => GridEditRowsModel | Gets the edit rows model of the grid. | | getExpandedDetailPanels [](https://mui.com/store/items/mui-x-pro/) | () => GridRowId[] | Returns the rows whose detail panel is open. | -| getGroupDetails | (groupId: string) => Omit<GridColumnGroup, 'children'> \| null | Returns the details about a group corresponding to `groupId`. | +| getGroupDetails | (groupId: string) => Omit<GridColumnGroup, 'children'> \| null | Returns the details of the requested group. | | getLocaleText | <T extends GridTranslationKeys>(key: T) => GridLocaleText[T] | Returns the translation for the `key`. | | getPinnedColumns [](https://mui.com/store/items/mui-x-pro/) | () => GridPinnedColumns | Returns which columns are pinned. | | getRootDimensions | () => GridDimensions \| null | Returns the dimensions of the grid | diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts index 7397a022bc4ed..bf8de34d6bd02 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts @@ -21,6 +21,7 @@ export function hasGroupPath( type UnwrappedGroupingModel = { [key: string]: string[] }; +// The is the recurrence function that help writing `unwrapGroupingColumnModel()` const recurrentUnwrapGroupingColumnModel = ( columnGroupNode: GridColumnNode, parents: any, @@ -36,7 +37,7 @@ const recurrentUnwrapGroupingColumnModel = ( if (rep[key] !== undefined) { throw new Error( [ - `MUI DataGrid - column grouping: duplicated field`, + `MUI: columnGroupingModel contains duplicated field`, `column field ${key} occurrs two times in the grouping model:`, `- ${rep[key].join(' > ')}`, `- ${value.join(' > ')}`, @@ -49,6 +50,12 @@ const recurrentUnwrapGroupingColumnModel = ( return rep; }; +/** + * This is a function that provide for each column the array of its parents. + * Parents are ordered from the root to the leaf. + * @param columnGroupingModel The model such as provided in DataGrid props + * @returns An object `{[field]: groupIds}` where `groupIds` is the parents of the column `field` + */ export const unwrapGroupingColumnModel = ( columnGroupingModel?: GridColumnGroupingModel, ): UnwrappedGroupingModel => { @@ -64,7 +71,7 @@ export const unwrapGroupingColumnModel = ( if (rep[key] !== undefined) { throw new Error( [ - `MUI: column grouping has duplicated field.`, + `MUI: columnGroupingModel has duplicated field.`, `column field ${key} occurres two times in the grouping model:`, `- ${rep[key].join(' > ')}`, `- ${value.join(' > ')}`, @@ -88,16 +95,18 @@ const createGroupLookup = (columnGroupingModel: GridColumnNode[]): GridColumnGro const { groupId, children, ...other } = node; if (!groupId) { throw new Error( - 'MUI-DataGrid: an element of the columnGroupingModel does not have either `field` or `groupId`', + 'MUI: An element of the columnGroupingModel does not have either `field` or `groupId`', ); } if (!children) { - console.warn(`MUI-DataGrid: group groupId=${groupId} has no children. `); + console.warn(`MUI: group groupId=${groupId} has no children. `); } const groupParam = { ...other, groupId }; const subTreeLookup = createGroupLookup(children); if (subTreeLookup[groupId] !== undefined || groupLookup[groupId] !== undefined) { - throw new Error(`MUI: The groupId ${groupId} is used multiple times`); + throw new Error( + `MUI: The groupId ${groupId} is used multiple times in the columnGroupingModel`, + ); } groupLookup = { ...groupLookup, ...subTreeLookup, [groupId]: groupParam }; }); diff --git a/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts b/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts index 40c356d8fdbdd..5054b547a0eab 100644 --- a/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts +++ b/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts @@ -7,6 +7,7 @@ export interface GridDensityOption { value: GridDensityTypes; } +// TODO v6: turns `setDensity` parameters in an object /** * The density API interface that is available in the grid `apiRef`. */ diff --git a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts index 3863abad61d24..2862ea97778a6 100644 --- a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts @@ -1,8 +1,8 @@ import { GridAlignment, GridColDef } from './colDef'; -export type LeafColumn = { +export interface LeafColumn { field: GridColDef['field']; -}; +} export type GridColumnNode = GridColumnGroup | LeafColumn; @@ -10,36 +10,49 @@ export function isLeaf(node: GridColumnNode): node is LeafColumn { return (node).field !== undefined; } -export type GridColumnGroupHeaderParams = { - groupId: string; - headerName: string; - description: string; +export interface GridColumnGroupHeaderParams + extends Pick { + /** + * The number parent the group have. + */ depth: number; + /** + * The maximal depth among visible columns. + */ maxDepth: number; + /** + * The column fields included in the group (including nested ones). + */ fields: string[]; + /** + * The column index (0 based). + */ colIndex: number; + /** + * Indicate if the group is the last one for the given depth. + */ isLastColumn: boolean; -}; +} export type GridColumnGroup = { /** - * A unique string identifying the group + * A unique string identifying the group. */ groupId: string; /** - * The groups and columns included in this group + * The groups and columns included in this group. */ children: GridColumnNode[]; /** - * The name to display in the group header + * The name to display in the group header. */ headerName?: string; /** - * The description displayed in the header tooltip + * The description displayed in the header tooltip. */ description?: string; /** - * If `true` allows to reorder columns outside of the group + * If `true` allows to reorder columns outside of the group. * @default false */ freeReordering?: boolean; diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index c81e84718f9e1..7ddcb69fd31b6 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -108,7 +108,7 @@ { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, { "name": "GridColumnGroup", "kind": "TypeAlias" }, - { "name": "GridColumnGroupHeaderParams", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, { "name": "gridColumnGroupsLookupSelector", "kind": "Variable" }, @@ -506,7 +506,7 @@ { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, - { "name": "LeafColumn", "kind": "TypeAlias" }, + { "name": "LeafColumn", "kind": "Interface" }, { "name": "LicenseInfo", "kind": "Class" }, { "name": "Logger", "kind": "Interface" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index fe4c1408aa063..4165d0a30332a 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -105,7 +105,7 @@ { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, { "name": "GridColumnGroup", "kind": "TypeAlias" }, - { "name": "GridColumnGroupHeaderParams", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, { "name": "gridColumnGroupsLookupSelector", "kind": "Variable" }, @@ -489,7 +489,7 @@ { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, - { "name": "LeafColumn", "kind": "TypeAlias" }, + { "name": "LeafColumn", "kind": "Interface" }, { "name": "LicenseInfo", "kind": "Class" }, { "name": "Logger", "kind": "Interface" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 56b1ed2fb4b2f..be17b55d4d042 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -100,7 +100,7 @@ { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, { "name": "GridColumnGroup", "kind": "TypeAlias" }, - { "name": "GridColumnGroupHeaderParams", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, { "name": "gridColumnGroupsLookupSelector", "kind": "Variable" }, @@ -459,7 +459,7 @@ { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, - { "name": "LeafColumn", "kind": "TypeAlias" }, + { "name": "LeafColumn", "kind": "Interface" }, { "name": "Logger", "kind": "Interface" }, { "name": "MAX_PAGE_SIZE", "kind": "Variable" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, From 8bb4b2e2ad3c815204f41efa3c0c10d7ec33f09b Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Wed, 27 Jul 2022 16:40:09 +0200 Subject: [PATCH 14/53] Apply suggestions about documentation Co-authored-by: Danail Hadjiatanasov Co-authored-by: Matheus Wichman --- .../data-grid/column-groups/column-groups.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 078e9b300f755..fbcb93e501b32 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -1,24 +1,24 @@ --- -title: Data Grid - Column groups +title: Data grid - Column groups --- -# Data Grid - Column groups +# Data grid - Column groups

Group your columns.

-Grouping columns allows you to have multiple levels of columns in your header and the ability, if needed, to 'open and close' column groups to show and hide additional columns. +Grouping columns allows you to have multiple levels of columns in your header and the ability, if needed, to toggle column groups to show and hide additional columns. ## Define column grouping -You can define the column grouping structure by providing `columnGroupingModel` prop to the data grid. +You can define the column grouping structure by providing the `columnGroupingModel` prop to the grid. This prop receives an array of column group. -A column group is defined by at least two variables: +A column group is defined by at least two attributes: -- `groupId` a string used to identify the group -- `children` an array containing the children of the group +- `groupId`: a string used to identify the group +- `children`: an array containing the children of the group -The children can contains two types of objects: +The `children` attribute can contain two types of objects: - leafs with type `{ field: string }`, which add the column with the corresponding `field` to this group. - other column groups which allows you to have nested groups. From 1fe45f4481615b35fc9e162d434555d5dc7c537a Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 27 Jul 2022 17:14:46 +0200 Subject: [PATCH 15/53] small suggestions --- .../src/components/DataGridProColumnHeaders.tsx | 16 ++++++++-------- .../src/components/DataGridColumnHeaders.tsx | 6 +++--- .../columnHeaders/useGridColumnHeaders.tsx | 8 ++++---- .../features/columns/useGridColumnGrouping.ts | 2 +- .../hooks/features/density/useGridDensity.tsx | 9 +++------ .../x-data-grid/src/models/gridColumnGrouping.ts | 8 ++++---- scripts/x-data-grid-premium.exports.json | 2 +- scripts/x-data-grid-pro.exports.json | 2 +- scripts/x-data-grid.exports.json | 2 +- 9 files changed, 26 insertions(+), 29 deletions(-) diff --git a/packages/grid/x-data-grid-pro/src/components/DataGridProColumnHeaders.tsx b/packages/grid/x-data-grid-pro/src/components/DataGridProColumnHeaders.tsx index 2006b658bb244..ac52424b5e740 100644 --- a/packages/grid/x-data-grid-pro/src/components/DataGridProColumnHeaders.tsx +++ b/packages/grid/x-data-grid-pro/src/components/DataGridProColumnHeaders.tsx @@ -126,8 +126,8 @@ export const DataGridProColumnHeaders = React.forwardRef< renderContext, getRootProps, getInnerProps, - getColumnsHeader, - getColumnsHeaderGroups, + getColumnHeaders, + getColumnGroupHeaders, } = useGridColumnHeaders({ innerRef, minColumnIndex: leftPinnedColumns.length, @@ -161,12 +161,12 @@ export const DataGridProColumnHeaders = React.forwardRef< className={classes.leftPinnedColumns} ownerState={{ side: GridPinnedPosition.left }} > - {getColumnsHeaderGroups({ + {getColumnGroupHeaders({ renderContext: leftRenderContext, minFirstColumn: leftRenderContext.firstColumnIndex, maxLastColumn: leftRenderContext.lastColumnIndex, })} - {getColumnsHeader( + {getColumnHeaders( { renderContext: leftRenderContext, minFirstColumn: leftRenderContext.firstColumnIndex, @@ -177,12 +177,12 @@ export const DataGridProColumnHeaders = React.forwardRef< )} - {getColumnsHeaderGroups({ + {getColumnGroupHeaders({ renderContext, minFirstColumn: leftPinnedColumns.length, maxLastColumn: visibleColumnFields.length - rightPinnedColumns.length, })} - {getColumnsHeader({ + {getColumnHeaders({ renderContext, minFirstColumn: leftPinnedColumns.length, maxLastColumn: visibleColumnFields.length - rightPinnedColumns.length, @@ -194,12 +194,12 @@ export const DataGridProColumnHeaders = React.forwardRef< className={classes.rightPinnedColumns} style={{ paddingRight: scrollbarSize }} > - {getColumnsHeaderGroups({ + {getColumnGroupHeaders({ renderContext: rightRenderContext, minFirstColumn: rightRenderContext.firstColumnIndex, maxLastColumn: rightRenderContext.lastColumnIndex, })} - {getColumnsHeader( + {getColumnHeaders( { renderContext: rightRenderContext, minFirstColumn: rightRenderContext.firstColumnIndex, diff --git a/packages/grid/x-data-grid/src/components/DataGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/components/DataGridColumnHeaders.tsx index 3279611e5f67a..0888cb7a3d165 100644 --- a/packages/grid/x-data-grid/src/components/DataGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/components/DataGridColumnHeaders.tsx @@ -12,7 +12,7 @@ export const DataGridColumnHeaders = React.forwardRef - {getColumnsHeaderGroups()} - {getColumnsHeader()} + {getColumnGroupHeaders()} + {getColumnHeaders()} diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index 6d6d5e7a9303e..99da35fc3cfdc 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -219,7 +219,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { useGridApiEventHandler(apiRef, 'rowsScroll', handleScroll); - const getColumnsHeader = ( + const getColumnHeaders = ( params?: { renderContext: GridRenderContext | null; minFirstColumn?: number; @@ -307,7 +307,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ); }; - const getColumnsHeaderGroups = (params?: { + const getColumnGroupHeaders = (params?: { renderContext: GridRenderContext | null; minFirstColumn?: number; maxLastColumn?: number; @@ -502,8 +502,8 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { return { renderContext, - getColumnsHeader, - getColumnsHeaderGroups, + getColumnHeaders, + getColumnGroupHeaders, isDragging: !!dragCol, getRootProps: (other = {}) => ({ style: rootStyle, ...other }), getInnerProps: () => ({ diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts index bf8de34d6bd02..1f1f30e433108 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts @@ -21,7 +21,7 @@ export function hasGroupPath( type UnwrappedGroupingModel = { [key: string]: string[] }; -// The is the recurrence function that help writing `unwrapGroupingColumnModel()` +// This is the recurrence function that help writing `unwrapGroupingColumnModel()` const recurrentUnwrapGroupingColumnModel = ( columnGroupNode: GridColumnNode, parents: any, diff --git a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx index 01f7483b5b1dc..22a7667549c6c 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx @@ -71,18 +71,15 @@ export const densityStateInitializer: GridStateInitializer< } else { const unwrappedGroupingColumnModel = unwrapGroupingColumnModel(props.columnGroupingModel); - // @ts-ignore - const visibleColumns = state.columns.all.filter( - // @ts-ignore - (field) => state.columns.columnVisibilityModel[field] !== false, + const visibleColumns = state.columns!.all!.filter( + (field) => state.columns!.columnVisibilityModel![field!] !== false, ); if (visibleColumns.length === 0) { maxDepth = 0; } else { maxDepth = Math.max( - // @ts-ignore - ...visibleColumns.map((field) => unwrappedGroupingColumnModel[field]?.length ?? 0), + ...visibleColumns.map((field) => unwrappedGroupingColumnModel[field!]?.length ?? 0), ); } } diff --git a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts index 2862ea97778a6..9d8642a2130b1 100644 --- a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts @@ -1,13 +1,13 @@ import { GridAlignment, GridColDef } from './colDef'; -export interface LeafColumn { +export interface GridLeafColumn { field: GridColDef['field']; } -export type GridColumnNode = GridColumnGroup | LeafColumn; +export type GridColumnNode = GridColumnGroup | GridLeafColumn; -export function isLeaf(node: GridColumnNode): node is LeafColumn { - return (node).field !== undefined; +export function isLeaf(node: GridColumnNode): node is GridLeafColumn { + return (node).field !== undefined; } export interface GridColumnGroupHeaderParams diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index 7ddcb69fd31b6..6d0eb33547094 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -302,6 +302,7 @@ { "name": "GridInputSelectionModel", "kind": "TypeAlias" }, { "name": "GridKeyboardArrowRight", "kind": "Variable" }, { "name": "GridKeyValue", "kind": "TypeAlias" }, + { "name": "GridLeafColumn", "kind": "Interface" }, { "name": "GridLinkOperator", "kind": "Enum" }, { "name": "GridLoadIcon", "kind": "Variable" }, { "name": "GridLoadingOverlay", "kind": "Variable" }, @@ -506,7 +507,6 @@ { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, - { "name": "LeafColumn", "kind": "Interface" }, { "name": "LicenseInfo", "kind": "Class" }, { "name": "Logger", "kind": "Interface" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 4165d0a30332a..d1e5c8b8fb2f2 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -293,6 +293,7 @@ { "name": "GridInputSelectionModel", "kind": "TypeAlias" }, { "name": "GridKeyboardArrowRight", "kind": "Variable" }, { "name": "GridKeyValue", "kind": "TypeAlias" }, + { "name": "GridLeafColumn", "kind": "Interface" }, { "name": "GridLinkOperator", "kind": "Enum" }, { "name": "GridLoadIcon", "kind": "Variable" }, { "name": "GridLoadingOverlay", "kind": "Variable" }, @@ -489,7 +490,6 @@ { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, - { "name": "LeafColumn", "kind": "Interface" }, { "name": "LicenseInfo", "kind": "Class" }, { "name": "Logger", "kind": "Interface" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index be17b55d4d042..c18e4b74d779a 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -270,6 +270,7 @@ { "name": "GridInputSelectionModel", "kind": "TypeAlias" }, { "name": "GridKeyboardArrowRight", "kind": "Variable" }, { "name": "GridKeyValue", "kind": "TypeAlias" }, + { "name": "GridLeafColumn", "kind": "Interface" }, { "name": "GridLinkOperator", "kind": "Enum" }, { "name": "GridLoadIcon", "kind": "Variable" }, { "name": "GridLoadingOverlay", "kind": "Variable" }, @@ -459,7 +460,6 @@ { "name": "itIT", "kind": "Variable" }, { "name": "jaJP", "kind": "Variable" }, { "name": "koKR", "kind": "Variable" }, - { "name": "LeafColumn", "kind": "Interface" }, { "name": "Logger", "kind": "Interface" }, { "name": "MAX_PAGE_SIZE", "kind": "Variable" }, { "name": "MuiBaseEvent", "kind": "TypeAlias" }, From 8304b84ee4ba82b9aea7c5d15a8c7770842bb0bc Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 27 Jul 2022 17:43:54 +0200 Subject: [PATCH 16/53] factorise code with one function for common part between getColumHeaders and getColumGroupHeaders --- .../columnHeaders/useGridColumnHeaders.tsx | 89 +++++++++---------- 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index 99da35fc3cfdc..9d81bdf29cbb8 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -27,6 +27,7 @@ import { useGridRootProps } from '../../utils/useGridRootProps'; import { GridRenderContext } from '../../../models/params/gridScrollParams'; import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler'; import { GridEventListener } from '../../../models/events'; +import { GridStateColDef } from '../../../models/colDef'; import { GridColumnHeaderItem } from '../../../components/columnHeaders/GridColumnHeaderItem'; import { getFirstColumnIndexToRender } from '../columns/gridColumnsUtils'; import { useGridVisibleRows } from '../../utils/useGridVisibleRows'; @@ -57,6 +58,12 @@ interface UseGridColumnHeadersProps { minColumnIndex?: number; } +interface GetHeadersParams { + renderContext: GridRenderContext | null; + minFirstColumn?: number; + maxLastColumn?: number; +} + function isUIEvent(event: any): event is React.UIEvent { return !!event.target; } @@ -219,14 +226,16 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { useGridApiEventHandler(apiRef, 'rowsScroll', handleScroll); - const getColumnHeaders = ( - params?: { - renderContext: GridRenderContext | null; - minFirstColumn?: number; - maxLastColumn?: number; - }, - other = {}, - ) => { + // Helper for computation common between getColumnHeaders and getColumnGroupHeaders + const getColumnsToRender = ( + params?: GetHeadersParams, + ): null | { + renderedColumns: GridStateColDef[]; + firstColumnToRender: number; + lastColumnToRender: number; + minFirstColumn: number; + maxLastColumn: number; + } => { const { renderContext: nextRenderContext = renderContext, minFirstColumn = minColumnIndex, @@ -237,8 +246,6 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { return null; } - const columns: JSX.Element[] = []; - const [firstRowToRender, lastRowToRender] = getRenderableIndexes({ firstIndex: nextRenderContext.firstRowIndex, lastIndex: nextRenderContext.lastRowIndex, @@ -264,6 +271,25 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { const renderedColumns = visibleColumns.slice(firstColumnToRender, lastColumnToRender); + return { + renderedColumns, + firstColumnToRender, + lastColumnToRender, + minFirstColumn, + maxLastColumn, + }; + }; + + const getColumnHeaders = (params?: GetHeadersParams, other = {}) => { + const columnsToRender = getColumnsToRender(params); + + if (columnsToRender == null) { + return null; + } + + const { renderedColumns, firstColumnToRender } = columnsToRender; + + const columns: JSX.Element[] = []; for (let i = 0; i < renderedColumns.length; i += 1) { const column = renderedColumns[i]; @@ -307,51 +333,20 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ); }; - const getColumnGroupHeaders = (params?: { - renderContext: GridRenderContext | null; - minFirstColumn?: number; - maxLastColumn?: number; - }) => { + const getColumnGroupHeaders = (params?: GetHeadersParams) => { if (headerGroupingMaxDepth === 0) { return null; } + const columnsToRender = getColumnsToRender(params); - const { - renderContext: nextRenderContext = renderContext, - minFirstColumn = minColumnIndex, - maxLastColumn = visibleColumns.length, - } = params || {}; - - if (!nextRenderContext) { + if (columnsToRender == null) { return null; } - const columns: JSX.Element[] = []; + const { renderedColumns, firstColumnToRender, lastColumnToRender, maxLastColumn } = + columnsToRender; - const [firstRowToRender, lastRowToRender] = getRenderableIndexes({ - firstIndex: nextRenderContext.firstRowIndex, - lastIndex: nextRenderContext.lastRowIndex, - minFirstIndex: 0, - maxLastIndex: currentPage.rows.length, - buffer: rootProps.rowBuffer, - }); - - const firstColumnToRender = getFirstColumnIndexToRenderRef.current({ - firstColumnIndex: nextRenderContext!.firstColumnIndex, - minColumnIndex: minFirstColumn, - columnBuffer: rootProps.columnBuffer, - apiRef, - firstRowToRender, - lastRowToRender, - visibleRows: currentPage.rows, - }); - - const lastColumnToRender = Math.min( - nextRenderContext.lastColumnIndex! + rootProps.columnBuffer, - maxLastColumn, - ); - - const renderedColumns = visibleColumns.slice(firstColumnToRender, lastColumnToRender); + const columns: JSX.Element[] = []; const headerToRender: { leftOverflow: number; From 2d0f25ae138eafa7220b64709af88c99e895cb95 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 27 Jul 2022 17:55:32 +0200 Subject: [PATCH 17/53] reduce API surface --- .../columnReorder/useGridColumnReorder.tsx | 4 ++-- .../features/columns/useGridColumnGrouping.ts | 22 +++++++------------ .../src/models/api/gridColumnGroupingApi.ts | 13 ++--------- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx index 0ca4678c9b110..ddabd93baa4f3 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -99,11 +99,11 @@ export const useGridColumnReorder = ( originColumnIndex.current = apiRef.current.getColumnIndex(params.field, false); - const draggingColumnGroupPath = apiRef.current.getColumnGroupPath(params.field); + const draggingColumnGroupPath = apiRef.current.unstable_getColumnGroupPath(params.field); const visibleColumnIndex = apiRef.current.getColumnIndex(params.field, true); const visibleColumns = apiRef.current.getVisibleColumns(); - const groupsLookup = apiRef.current.getAllGroupDetails(); + const groupsLookup = apiRef.current.unstable_getAllGroupDetails(); // The limitingGroupId is the id of the group from which the dragged column should not escape let limitingGroupId: string | null = null; diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts index 1f1f30e433108..092f097663bfd 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts @@ -134,7 +134,9 @@ export const useGridColumnGrouping = ( /** * API METHODS */ - const getColumnGroupPath = React.useCallback( + const getColumnGroupPath = React.useCallback< + GridColumnGroupingApi['unstable_getColumnGroupPath'] + >( (field) => { const columnLookup = gridColumnLookupSelector(apiRef); @@ -143,24 +145,16 @@ export const useGridColumnGrouping = ( [apiRef], ); - const getAllGroupDetails = React.useCallback(() => { + const getAllGroupDetails = React.useCallback< + GridColumnGroupingApi['unstable_getAllGroupDetails'] + >(() => { const columnGroupLookup = gridColumnGroupsLookupSelector(apiRef); return columnGroupLookup; }, [apiRef]); - const getGroupDetails = React.useCallback( - (groupId) => { - const columnGroupLookup = gridColumnGroupsLookupSelector(apiRef); - - return columnGroupLookup[groupId] ?? null; - }, - [apiRef], - ); - const columnGroupingApi: GridColumnGroupingApi = { - getColumnGroupPath, - getGroupDetails, - getAllGroupDetails, + unstable_getColumnGroupPath: getColumnGroupPath, + unstable_getAllGroupDetails: getAllGroupDetails, }; useGridApiMethod(apiRef, columnGroupingApi, 'GridColumnGroupingApi'); diff --git a/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts b/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts index 8e227a961df83..e2c4631d05c89 100644 --- a/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts +++ b/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts @@ -10,20 +10,11 @@ export interface GridColumnGroupingApi { * The array is ordered by increasing depth (the last element is the direct parent of the column). * @param {string} field The field of of the column requested. * @returns {string[]} The id of the groups leading to the requested column. - - * @param {string} field The id of of the column requested. - * @returns {string[]} array of groupId. */ - getColumnGroupPath: (field: string) => GridColumnGroup['groupId'][]; - /** - * Returns the details of the requested group. - * @param {string} groupId The id of the group requested. - * @returns {Omit} The group details. - */ - getGroupDetails: (groupId: string) => Omit | null; + unstable_getColumnGroupPath: (field: string) => GridColumnGroup['groupId'][]; /** * Returns the column group lookup. * @returns {GridColumnGroupLookup} The column group lookup. */ - getAllGroupDetails: () => GridColumnGroupLookup; + unstable_getAllGroupDetails: () => GridColumnGroupLookup; } From a750d7b227ca2f50c8a75d7acba3fb104cd860e2 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 27 Jul 2022 18:00:54 +0200 Subject: [PATCH 18/53] scripts --- docs/pages/x/api/data-grid/grid-api.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/pages/x/api/data-grid/grid-api.md b/docs/pages/x/api/data-grid/grid-api.md index f936b24adc942..707b6c4b3369f 100644 --- a/docs/pages/x/api/data-grid/grid-api.md +++ b/docs/pages/x/api/data-grid/grid-api.md @@ -25,14 +25,12 @@ import { GridApi } from '@mui/x-data-grid-pro'; | exportState | () => InitialState | Generates a serializable object containing the exportable parts of the DataGrid state.
These values can then be passed to the `initialState` prop or injected using the `restoreState` method. | | forceUpdate | () => void | Forces the grid to rerender. It's often used after a state update. | | getAllColumns | () => GridStateColDef[] | Returns an array of [GridColDef](/x/api/data-grid/grid-col-def/) containing all the column definitions. | -| getAllGroupDetails | () => GridColumnGroupLookup | Returns the column group lookup. | | getAllRowIds | () => GridRowId[] | Gets the list of row ids. | | getCellElement | (id: GridRowId, field: string) => HTMLDivElement \| null | Gets the underlying DOM element for a cell at the given `id` and `field`. | | getCellMode | (id: GridRowId, field: string) => GridCellMode | Gets the mode of a cell. | | getCellParams | <V = any, R extends GridValidRowModel = any, F = V>(id: GridRowId, field: string) => GridCellParams<R, V, F> | Gets the [GridCellParams](/x/api/data-grid/grid-cell-params/) object that is passed as argument in events. | | getCellValue | <V extends any = any>(id: GridRowId, field: string) => V | Gets the value of a cell at the given `id` and `field`. | | getColumn | (field: string) => GridStateColDef | Returns the [GridColDef](/x/api/data-grid/grid-col-def/) for the given `field`. | -| getColumnGroupPath | (field: string) => GridColumnGroup['groupId'][] | Returns the id of the groups leading to the requested column.
The array is ordered by increasing depth (the last element is the direct parent of the column). | | getColumnHeaderElement | (field: string) => HTMLDivElement \| null | Gets the underlying DOM element for the column header with the given `field`. | | getColumnHeaderParams | (field: string) => GridColumnHeaderParams | Gets the GridColumnHeaderParams object that is passed as argument in events. | | getColumnIndex | (field: string, useVisibleColumns?: boolean) => number | Returns the index position of a column. By default, only the visible columns are considered.
Pass `false` to `useVisibleColumns` to consider all columns. | @@ -42,7 +40,6 @@ import { GridApi } from '@mui/x-data-grid-pro'; | getDataAsExcel [](https://mui.com/store/items/material-ui-premium/) | (options?: GridExcelExportOptions) => Promise<Excel.Workbook> \| null | Returns the grid data as an exceljs workbook.
This method is used internally by `exportDataAsExcel`. | | getEditRowsModel | () => GridEditRowsModel | Gets the edit rows model of the grid. | | getExpandedDetailPanels [](https://mui.com/store/items/mui-x-pro/) | () => GridRowId[] | Returns the rows whose detail panel is open. | -| getGroupDetails | (groupId: string) => Omit<GridColumnGroup, 'children'> \| null | Returns the details of the requested group. | | getLocaleText | <T extends GridTranslationKeys>(key: T) => GridLocaleText[T] | Returns the translation for the `key`. | | getPinnedColumns [](https://mui.com/store/items/mui-x-pro/) | () => GridPinnedColumns | Returns which columns are pinned. | | getRootDimensions | () => GridDimensions \| null | Returns the dimensions of the grid | @@ -119,6 +116,8 @@ import { GridApi } from '@mui/x-data-grid-pro'; | toggleColumnMenu | (field: string) => void | Toggles the column menu under the `field` column. | | toggleDetailPanel [](https://mui.com/store/items/mui-x-pro/) | (id: GridRowId) => void | Expands or collapses the detail panel of a row. | | unpinColumn [](https://mui.com/store/items/mui-x-pro/) | (field: string) => void | Unpins a column. | +| unstable_getAllGroupDetails | () => GridColumnGroupLookup | Returns the column group lookup. | +| unstable_getColumnGroupPath | (field: string) => GridColumnGroup['groupId'][] | Returns the id of the groups leading to the requested column.
The array is ordered by increasing depth (the last element is the direct parent of the column). | | updateColumn | (col: GridColDef) => void | Updates the definition of a column. | | updateColumns | (cols: GridColDef[]) => void | Updates the definition of multiple columns at the same time. | | updateRows | (updates: GridRowModelUpdate[]) => void | Allows to updates, insert and delete rows in a single call. | From 9584426a8a64ce753e925062e9746ca8cd4df3f2 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Thu, 28 Jul 2022 13:22:03 +0200 Subject: [PATCH 19/53] move column grouping hooks to a special folder --- .../src/DataGrid/useDataGridComponent.tsx | 4 ++-- .../columnHeaders/GridColumnGroupHeader.tsx | 2 +- .../columnGrouping/gridColumnGroupsInterfaces.ts | 9 +++++++++ .../columnGrouping/gridColumnGroupsSelector.ts | 13 +++++++++++++ .../src/hooks/features/columnGrouping/index.ts | 4 ++++ .../useGridColumnGrouping.ts | 5 +++-- .../useGridColumnGroupingPreProcessors.ts | 0 .../features/columns/gridColumnsInterfaces.ts | 14 -------------- .../hooks/features/columns/gridColumnsSelector.ts | 10 ---------- .../src/hooks/features/columns/index.ts | 1 - .../src/hooks/features/density/useGridDensity.tsx | 2 +- .../grid/x-data-grid/src/hooks/features/index.ts | 1 + packages/grid/x-data-grid/src/internals/index.ts | 4 ++-- .../src/models/api/gridColumnGroupingApi.ts | 2 +- 14 files changed, 37 insertions(+), 34 deletions(-) create mode 100644 packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsInterfaces.ts create mode 100644 packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsSelector.ts create mode 100644 packages/grid/x-data-grid/src/hooks/features/columnGrouping/index.ts rename packages/grid/x-data-grid/src/hooks/features/{columns => columnGrouping}/useGridColumnGrouping.ts (96%) rename packages/grid/x-data-grid/src/hooks/features/{columns => columnGrouping}/useGridColumnGroupingPreProcessors.ts (100%) diff --git a/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx b/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx index a7d3060c30b1c..4f0aca47a76e5 100644 --- a/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/useDataGridComponent.tsx @@ -48,8 +48,8 @@ import { useGridColumnSpanning } from '../hooks/features/columns/useGridColumnSp import { useGridColumnGrouping, columnGroupsStateInitializer, -} from '../hooks/features/columns/useGridColumnGrouping'; -import { useGridColumnGroupingPreProcessors } from '../hooks/features/columns/useGridColumnGroupingPreProcessors'; +} from '../hooks/features/columnGrouping/useGridColumnGrouping'; +import { useGridColumnGroupingPreProcessors } from '../hooks/features/columnGrouping/useGridColumnGroupingPreProcessors'; export const useDataGridComponent = (props: DataGridProcessedProps) => { const apiRef = useGridInitialization(undefined, props); diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx index 0ac7fcf321d70..504c504f57f6d 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx @@ -5,7 +5,7 @@ import { GridAlignment } from '../../models/colDef/gridColDef'; import { getDataGridUtilityClass } from '../../constants/gridClasses'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; import { DataGridProcessedProps } from '../../models/props/DataGridProps'; -import { gridColumnGroupsLookupSelector } from '../../hooks/features/columns/gridColumnsSelector'; +import { gridColumnGroupsLookupSelector } from '../../hooks/features/columnGrouping/gridColumnGroupsSelector'; import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { useGridSelector } from '../../hooks/utils/useGridSelector'; import { GridGenericColumnHeaderItem } from './GridGenericColumnHeaderItem'; diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsInterfaces.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsInterfaces.ts new file mode 100644 index 0000000000000..f34a26ca45ec6 --- /dev/null +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsInterfaces.ts @@ -0,0 +1,9 @@ +import { GridColumnGroup } from '../../../models/gridColumnGrouping'; + +export type GridColumnGroupLookup = { + [field: string]: Omit; +}; + +export interface GridColumnsGroupingState { + lookup: GridColumnGroupLookup; +} diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsSelector.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsSelector.ts new file mode 100644 index 0000000000000..84ca7adc05b10 --- /dev/null +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsSelector.ts @@ -0,0 +1,13 @@ +import { createSelector } from '../../../utils/createSelector'; +import { GridStateCommunity } from '../../../models/gridStateCommunity'; + +/** + * @category ColumnGrouping + * @ignore - do not document. + */ +export const gridColumnGroupingSelector = (state: GridStateCommunity) => state.columnGrouping; + +export const gridColumnGroupsLookupSelector = createSelector( + gridColumnGroupingSelector, + (columnGrouping) => columnGrouping.lookup, +); \ No newline at end of file diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/index.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/index.ts new file mode 100644 index 0000000000000..3c1bf493f36b5 --- /dev/null +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/index.ts @@ -0,0 +1,4 @@ +export * from './gridColumnGroupsSelector'; +export type { + GridColumnsGroupingState, +} from './gridColumnGroupsInterfaces'; diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts similarity index 96% rename from packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts rename to packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts index 092f097663bfd..f379f0e12df23 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts @@ -7,8 +7,9 @@ import { GridColumnNode, isLeaf, } from '../../../models/gridColumnGrouping'; -import { gridColumnGroupsLookupSelector, gridColumnLookupSelector } from './gridColumnsSelector'; -import { GridColumnGroupLookup } from './gridColumnsInterfaces'; +import { gridColumnGroupsLookupSelector } from './gridColumnGroupsSelector'; +import { gridColumnLookupSelector } from '../columns/gridColumnsSelector' +import { GridColumnGroupLookup } from './gridColumnGroupsInterfaces'; import { GridColumnGroupingApi } from '../../../models/api/gridColumnGroupingApi'; import { useGridApiMethod } from '../../utils/useGridApiMethod'; import { GridStateColDef, GridColDef } from '../../../models/colDef'; diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGroupingPreProcessors.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts similarity index 100% rename from packages/grid/x-data-grid/src/hooks/features/columns/useGridColumnGroupingPreProcessors.ts rename to packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsInterfaces.ts b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsInterfaces.ts index b338f1337f04f..04a7bd4b7a139 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsInterfaces.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsInterfaces.ts @@ -1,6 +1,5 @@ import type { GridRowId } from '../../../models'; import { GridColDef, GridStateColDef } from '../../../models/colDef/gridColDef'; -import { GridColumnGroup } from '../../../models/gridColumnGrouping'; import type { GridColumnDimensionProperties } from './gridColumnsUtils'; export type GridColumnLookup = { @@ -20,19 +19,6 @@ export interface GridColumnsState { columnVisibilityModel: GridColumnVisibilityModel; } -export type GridColumnGroupLookup = { - [field: string]: Omit; -}; - -export type GridColumnGroupCollapsedModel = { - [field: string]: GridStateColDef; -}; - -export interface GridColumnsGroupingState { - lookup: GridColumnGroupLookup; - groupCollapsedModel: GridColumnGroupCollapsedModel; -} - export interface GridColumnsInternalCache { isUsingColumnVisibilityModel: boolean; } diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts index a91ac5b37cf56..c2baa80e604bf 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts @@ -128,16 +128,6 @@ export const gridFilterableColumnLookupSelector = createSelector( }, {}), ); -/** - * @category ColumnGrouping - * @ignore - do not document. - */ -export const gridColumnGroupingSelector = (state: GridStateCommunity) => state.columnGrouping; - -export const gridColumnGroupsLookupSelector = createSelector( - gridColumnGroupingSelector, - (columnGrouping) => columnGrouping.lookup, -); /** * @category Columns diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/index.ts b/packages/grid/x-data-grid/src/hooks/features/columns/index.ts index a5ec23c808a70..20d1ef59a789b 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/index.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/index.ts @@ -4,6 +4,5 @@ export type { GridColumnsState, GridColumnsInitialState, GridColumnVisibilityModel, - GridColumnsGroupingState, } from './gridColumnsInterfaces'; export { getGridColDef } from './gridColumnsUtils'; diff --git a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx index 22a7667549c6c..8c871cef91d6e 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx @@ -11,7 +11,7 @@ import { isDeepEqual } from '../../../utils/utils'; import { GridStateInitializer } from '../../utils/useGridInitializeState'; import { useGridSelector } from '../../utils/useGridSelector'; import { gridVisibleColumnDefinitionsSelector } from '../columns'; -import { unwrapGroupingColumnModel } from '../columns/useGridColumnGrouping'; +import { unwrapGroupingColumnModel } from '../columnGrouping/useGridColumnGrouping'; export const COMPACT_DENSITY_FACTOR = 0.7; export const COMFORTABLE_DENSITY_FACTOR = 1.3; diff --git a/packages/grid/x-data-grid/src/hooks/features/index.ts b/packages/grid/x-data-grid/src/hooks/features/index.ts index 701c2018f4652..c98af58ad5f24 100644 --- a/packages/grid/x-data-grid/src/hooks/features/index.ts +++ b/packages/grid/x-data-grid/src/hooks/features/index.ts @@ -1,6 +1,7 @@ // Only export the variable and types that should be publicly exposed and re-exported from `@mui/x-data-grid-pro` export * from './columnMenu'; export * from './columns'; +export * from './columnGrouping'; export * from './density'; export * from './editRows'; export * from './filter'; diff --git a/packages/grid/x-data-grid/src/internals/index.ts b/packages/grid/x-data-grid/src/internals/index.ts index d4450f9fb209a..c9fcc00542109 100644 --- a/packages/grid/x-data-grid/src/internals/index.ts +++ b/packages/grid/x-data-grid/src/internals/index.ts @@ -21,8 +21,8 @@ export { useGridColumnSpanning } from '../hooks/features/columns/useGridColumnSp export { useGridColumnGrouping, columnGroupsStateInitializer, -} from '../hooks/features/columns/useGridColumnGrouping'; -export { useGridColumnGroupingPreProcessors } from '../hooks/features/columns/useGridColumnGroupingPreProcessors'; +} from '../hooks/features/columnGrouping/useGridColumnGrouping'; +export { useGridColumnGroupingPreProcessors } from '../hooks/features/columnGrouping/useGridColumnGroupingPreProcessors'; export type { GridColumnRawLookup, GridColumnsRawState, diff --git a/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts b/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts index e2c4631d05c89..cb66d54d7b3e7 100644 --- a/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts +++ b/packages/grid/x-data-grid/src/models/api/gridColumnGroupingApi.ts @@ -1,4 +1,4 @@ -import { GridColumnGroupLookup } from '@mui/x-data-grid/hooks/features/columns/gridColumnsInterfaces'; +import { GridColumnGroupLookup } from '../../hooks/features/columnGrouping/gridColumnGroupsInterfaces'; import { GridColumnGroup } from '../gridColumnGrouping'; /** From 817fc2ea36f2aa1119b2d3e4c83ed5ae84b2c713 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Thu, 28 Jul 2022 13:51:24 +0200 Subject: [PATCH 20/53] scripts --- docs/data/data-grid/column-groups/CustomizationDemo.js | 8 +++++++- .../features/columnGrouping/gridColumnGroupsSelector.ts | 2 +- .../src/hooks/features/columnGrouping/index.ts | 4 +--- .../features/columnGrouping/useGridColumnGrouping.ts | 2 +- .../src/hooks/features/columns/gridColumnsSelector.ts | 1 - 5 files changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.js b/docs/data/data-grid/column-groups/CustomizationDemo.js index 67887ee2b2242..4da9134de124b 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.js +++ b/docs/data/data-grid/column-groups/CustomizationDemo.js @@ -63,8 +63,14 @@ const HeaderWithIcon = (props) => { }; HeaderWithIcon.propTypes = { + /** + * A unique string identifying the group. + */ groupId: PropTypes.string.isRequired, - headerName: PropTypes.string.isRequired, + /** + * The name to display in the group header. + */ + headerName: PropTypes.string, icon: PropTypes.node, }; diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsSelector.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsSelector.ts index 84ca7adc05b10..d97a7a2274b6c 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsSelector.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/gridColumnGroupsSelector.ts @@ -10,4 +10,4 @@ export const gridColumnGroupingSelector = (state: GridStateCommunity) => state.c export const gridColumnGroupsLookupSelector = createSelector( gridColumnGroupingSelector, (columnGrouping) => columnGrouping.lookup, -); \ No newline at end of file +); diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/index.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/index.ts index 3c1bf493f36b5..dbdd20cca9b13 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/index.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/index.ts @@ -1,4 +1,2 @@ export * from './gridColumnGroupsSelector'; -export type { - GridColumnsGroupingState, -} from './gridColumnGroupsInterfaces'; +export type { GridColumnsGroupingState } from './gridColumnGroupsInterfaces'; diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts index f379f0e12df23..79dc5259641a0 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts @@ -8,7 +8,7 @@ import { isLeaf, } from '../../../models/gridColumnGrouping'; import { gridColumnGroupsLookupSelector } from './gridColumnGroupsSelector'; -import { gridColumnLookupSelector } from '../columns/gridColumnsSelector' +import { gridColumnLookupSelector } from '../columns/gridColumnsSelector'; import { GridColumnGroupLookup } from './gridColumnGroupsInterfaces'; import { GridColumnGroupingApi } from '../../../models/api/gridColumnGroupingApi'; import { useGridApiMethod } from '../../utils/useGridApiMethod'; diff --git a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts index c2baa80e604bf..586c099be4ef6 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columns/gridColumnsSelector.ts @@ -128,7 +128,6 @@ export const gridFilterableColumnLookupSelector = createSelector( }, {}), ); - /** * @category Columns * @deprecated Use `gridColumnFieldsSelector` instead. From 1b60a02bffef3f3420b72d6b15190cad598f2554 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Thu, 28 Jul 2022 19:08:19 +0200 Subject: [PATCH 21/53] feedbacks --- docs/data/data-grid/column-groups/column-groups.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index fbcb93e501b32..5ff38dc12c5f2 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -6,12 +6,12 @@ title: Data grid - Column groups

Group your columns.

-Grouping columns allows you to have multiple levels of columns in your header and the ability, if needed, to toggle column groups to show and hide additional columns. +Grouping columns allows you to have multiple levels of columns in your header and to toggle column groups to show and hide additional columns. ## Define column grouping You can define the column grouping structure by providing the `columnGroupingModel` prop to the grid. -This prop receives an array of column group. +This prop receives an array of column groups. A column group is defined by at least two attributes: @@ -63,7 +63,7 @@ columnGroupingModel={[ ## Customize column group -In addition to the `groupId`, and `children` properties which are mandatory, you can add extra properties to a column group object to customize it: +In addition to the required `groupId` and `children`, you can add extra properties to a column group object to customize it: - `headerName`: the sting displayed instead of `groupId`. - `description`: a longer string displayed in a tooltip. From 81354195805e865be00dc4905b456950bcb7f870 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Fri, 29 Jul 2022 11:08:31 +0200 Subject: [PATCH 22/53] make grouping experimental --- .../data-grid/column-groups/BasicGroupingDemo.js | 7 +++---- .../data-grid/column-groups/BasicGroupingDemo.tsx | 7 +++---- .../column-groups/BasicGroupingDemo.tsx.preview | 3 +-- .../data-grid/column-groups/BreakingGroupDemo.js | 3 +-- .../data-grid/column-groups/BreakingGroupDemo.tsx | 3 +-- .../column-groups/BreakingGroupDemo.tsx.preview | 3 +-- .../data-grid/column-groups/CustomizationDemo.js | 3 +-- .../data-grid/column-groups/CustomizationDemo.tsx | 3 +-- .../column-groups/CustomizationDemo.tsx.preview | 3 +-- .../src/tests/columnReorder.DataGridPro.test.tsx | 14 +++++++------- .../columnGrouping/useGridColumnGrouping.ts | 8 +++++--- .../useGridColumnGroupingPreProcessors.ts | 4 ++-- .../x-data-grid/src/models/props/DataGridProps.ts | 12 ++++++++---- .../src/tests/columnsGrouping.DataGrid.test.tsx | 1 + 14 files changed, 36 insertions(+), 38 deletions(-) diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.js b/docs/data/data-grid/column-groups/BasicGroupingDemo.js index 5d44b45aea362..4465e4bbaf537 100644 --- a/docs/data/data-grid/column-groups/BasicGroupingDemo.js +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.js @@ -38,12 +38,12 @@ const rows = [ const columnGroupingModel = [ { - groupId: 'internal_data', + groupId: 'internal data', description: '', children: [{ field: 'id' }], }, { - groupId: 'perso', + groupId: 'character', children: [ { groupId: 'naming', @@ -58,10 +58,9 @@ export default function BasicGroupingDemo() { return (
- Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -471,7 +471,7 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -507,7 +507,7 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -561,7 +561,7 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -617,7 +617,7 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -661,7 +661,7 @@ describe(' - Columns reorder', () => { ]); }); - it('should block dragging outside ot a group even at deeper level', () => { + it('should block dragging outside of a group even at deeper level', () => { const rows = [{ id: 0 }]; const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; @@ -682,7 +682,7 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts index 79dc5259641a0..3088b488916a2 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts @@ -130,7 +130,7 @@ export const columnGroupsStateInitializer: GridStateInitializer< */ export const useGridColumnGrouping = ( apiRef: React.MutableRefObject, - props: Pick, + props: Pick, ) => { /** * API METHODS @@ -171,11 +171,13 @@ export const useGridColumnGrouping = ( isFirstRender.current = false; return; } - + if (!props.experimentalFeatures?.columnGrouping) { + return + } const groupLookup = createGroupLookup(props.columnGroupingModel ?? []); apiRef.current.setState((state) => ({ ...state, columnGrouping: { ...state.columnGrouping, lookup: groupLookup }, })); - }, [apiRef, props.columnGroupingModel]); + }, [apiRef, props.columnGroupingModel, props.experimentalFeatures?.columnGrouping]); }; diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts index 88b808ec59792..b2f8520ccdabd 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts @@ -11,7 +11,7 @@ export const useGridColumnGroupingPreProcessors = ( ) => { const addHeaderGroups = React.useCallback>( (columnsState) => { - if (!props.columnGroupingModel) { + if (!props.experimentalFeatures?.columnGrouping || !props.columnGroupingModel) { return columnsState; } const unwrappedGroupingModel = unwrapGroupingColumnModel(props.columnGroupingModel); @@ -34,7 +34,7 @@ export const useGridColumnGroupingPreProcessors = ( }); return columnsState; }, - [props.columnGroupingModel], + [props.columnGroupingModel, props.experimentalFeatures?.columnGrouping], ); useGridRegisterPipeProcessor(apiRef, 'hydrateColumns', addHeaderGroups); diff --git a/packages/grid/x-data-grid/src/models/props/DataGridProps.ts b/packages/grid/x-data-grid/src/models/props/DataGridProps.ts index ed5f6d290ad92..df4f4b3c0cb06 100644 --- a/packages/grid/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/grid/x-data-grid/src/models/props/DataGridProps.ts @@ -41,6 +41,10 @@ export interface GridExperimentalFeatures { * Enables the new API for cell editing and row editing. */ newEditingApi: boolean; + /** + * Enables the column grouping. + */ + columnGrouping: boolean; /** * Emits a warning if the cell receives focus without also syncing the focus state. * Only works if NODE_ENV=test. @@ -53,8 +57,8 @@ export interface GridExperimentalFeatures { */ export type DataGridProps = Omit< Partial & - DataGridPropsWithComplexDefaultValueBeforeProcessing & - DataGridPropsWithoutDefaultValue, + DataGridPropsWithComplexDefaultValueBeforeProcessing & + DataGridPropsWithoutDefaultValue, DataGridForcedPropsKey > & { pagination?: true; @@ -65,8 +69,8 @@ export type DataGridProps = Omit< */ export interface DataGridProcessedProps extends DataGridPropsWithDefaultValues, - DataGridPropsWithComplexDefaultValueAfterProcessing, - DataGridPropsWithoutDefaultValue {} + DataGridPropsWithComplexDefaultValueAfterProcessing, + DataGridPropsWithoutDefaultValue { } /** * The props of the `DataGrid` component after the pre-processing phase that the user should not be able to override. diff --git a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx index 0a46518588200..882f7e8f84024 100644 --- a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx @@ -20,6 +20,7 @@ const getDefaultProps = (nbColumns: number) => { columns, rows: [{ id: 0, ...row }], autoHeight: isJSDOM, + experimentalFeatures: { columnGrouping: true } }; }; From 6d3f4bad573e693b365317c894ca9eb99e5e8553 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Fri, 29 Jul 2022 14:50:00 +0200 Subject: [PATCH 23/53] doc updates --- .../column-groups/BasicGroupingDemo.js | 2 +- .../column-groups/BasicGroupingDemo.tsx | 2 +- .../column-groups/BreakingGroupDemo.js | 2 +- .../column-groups/BreakingGroupDemo.tsx | 2 +- .../column-groups/CustomizationDemo.js | 4 +- .../column-groups/CustomizationDemo.tsx | 7 +++- .../data-grid/column-groups/column-groups.md | 14 +------ .../x/api/data-grid/data-grid-premium.json | 2 +- docs/pages/x/api/data-grid/data-grid-pro.json | 2 +- docs/pages/x/api/data-grid/data-grid.json | 2 +- .../src/DataGridPremium/DataGridPremium.tsx | 1 + .../src/DataGridPro/DataGridPro.tsx | 1 + .../tests/columnReorder.DataGridPro.test.tsx | 42 ++++++++++++++++--- .../x-data-grid/src/DataGrid/DataGrid.tsx | 1 + .../columnGrouping/useGridColumnGrouping.ts | 2 +- .../src/models/props/DataGridProps.ts | 8 ++-- .../tests/columnsGrouping.DataGrid.test.tsx | 2 +- 17 files changed, 61 insertions(+), 35 deletions(-) diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.js b/docs/data/data-grid/column-groups/BasicGroupingDemo.js index 4465e4bbaf537..471234b64f680 100644 --- a/docs/data/data-grid/column-groups/BasicGroupingDemo.js +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.js @@ -56,7 +56,7 @@ const columnGroupingModel = [ export default function BasicGroupingDemo() { return ( -
+
+
+
+
( @@ -104,7 +104,7 @@ const columnGroupingModel = [ export default function CustomizationDemo() { return ( -
+
({ overflow: 'hidden', display: 'flex', @@ -58,6 +59,7 @@ const HeaderWithIconRoot = styled('div')(({ theme }) => ({ marginRight: theme.spacing(0.5), }, })); + const HeaderWithIcon = (props: HeaderWithIconProps) => { const { icon, ...params } = props; @@ -67,6 +69,7 @@ const HeaderWithIcon = (props: HeaderWithIconProps) => { ); }; + const columnGroupingModel: GridColumnGroupingModel = [ { groupId: 'internal_data', @@ -78,7 +81,7 @@ const columnGroupingModel: GridColumnGroupingModel = [ children: [{ field: 'id' }], }, { - groupId: 'perso', + groupId: 'character', description: 'Information about the character', headerName: 'Character', renderHeaderGroup: (params) => ( @@ -96,7 +99,7 @@ const columnGroupingModel: GridColumnGroupingModel = [ ]; export default function CustomizationDemo() { return ( -
+
- Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -471,7 +476,12 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -507,7 +517,12 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -561,7 +576,12 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -617,7 +637,12 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; @@ -682,7 +707,12 @@ describe(' - Columns reorder', () => { const Test = () => { return (
- +
); }; diff --git a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx index e5d85a4692f1e..843227d321845 100644 --- a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx @@ -209,6 +209,7 @@ DataGridRaw.propTypes = { * For each feature, if the flag is not explicitly set to `true`, the feature will be fully disabled and any property / method call will not have any effect. */ experimentalFeatures: PropTypes.shape({ + columnGrouping: PropTypes.bool, newEditingApi: PropTypes.bool, preventCommitWhileValidating: PropTypes.bool, warnIfFocusStateIsNotSynced: PropTypes.bool, diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts index 3088b488916a2..db159f4acb8e5 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts @@ -172,7 +172,7 @@ export const useGridColumnGrouping = ( return; } if (!props.experimentalFeatures?.columnGrouping) { - return + return; } const groupLookup = createGroupLookup(props.columnGroupingModel ?? []); apiRef.current.setState((state) => ({ diff --git a/packages/grid/x-data-grid/src/models/props/DataGridProps.ts b/packages/grid/x-data-grid/src/models/props/DataGridProps.ts index df4f4b3c0cb06..637144b5cd758 100644 --- a/packages/grid/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/grid/x-data-grid/src/models/props/DataGridProps.ts @@ -57,8 +57,8 @@ export interface GridExperimentalFeatures { */ export type DataGridProps = Omit< Partial & - DataGridPropsWithComplexDefaultValueBeforeProcessing & - DataGridPropsWithoutDefaultValue, + DataGridPropsWithComplexDefaultValueBeforeProcessing & + DataGridPropsWithoutDefaultValue, DataGridForcedPropsKey > & { pagination?: true; @@ -69,8 +69,8 @@ export type DataGridProps = Omit< */ export interface DataGridProcessedProps extends DataGridPropsWithDefaultValues, - DataGridPropsWithComplexDefaultValueAfterProcessing, - DataGridPropsWithoutDefaultValue { } + DataGridPropsWithComplexDefaultValueAfterProcessing, + DataGridPropsWithoutDefaultValue {} /** * The props of the `DataGrid` component after the pre-processing phase that the user should not be able to override. diff --git a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx index 882f7e8f84024..cd6663150f2bf 100644 --- a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx @@ -20,7 +20,7 @@ const getDefaultProps = (nbColumns: number) => { columns, rows: [{ id: 0, ...row }], autoHeight: isJSDOM, - experimentalFeatures: { columnGrouping: true } + experimentalFeatures: { columnGrouping: true }, }; }; From 93311d75e84c5065a15e23a819d58212baff6494 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Mon, 1 Aug 2022 14:58:37 +0200 Subject: [PATCH 24/53] distingush header and group header events --- .../columnHeaders/GridColumnHeaderItem.tsx | 53 +++++++++++++++++++ .../GridGenericColumnHeaderItem.tsx | 46 +++------------- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx index 2a872bc470708..65b0e010d5884 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx @@ -13,6 +13,7 @@ import { getDataGridUtilityClass } from '../../constants/gridClasses'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; import { DataGridProcessedProps } from '../../models/props/DataGridProps'; import { GridGenericColumnHeaderItem } from './GridGenericColumnHeaderItem'; +import { GridColumnHeaderEventLookup } from '../../models/events'; interface GridColumnHeaderItemProps { colIndex: number; @@ -119,6 +120,55 @@ function GridColumnHeaderItem(props: GridColumnHeaderItemProps) { const classes = useUtilityClasses(ownerState); + const publish = React.useCallback( + (eventName: keyof GridColumnHeaderEventLookup) => (event: React.SyntheticEvent) => { + // Ignore portal + // See https://github.com/mui/mui-x/issues/1721 + if (!event.currentTarget.contains(event.target as Element)) { + return; + } + apiRef.current.publishEvent( + eventName, + apiRef.current.getColumnHeaderParams(column.field), + event as any, + ); + }, + [apiRef, column.field], + ); + + const mouseEventsHandlers = React.useMemo( + () => ({ + onClick: publish('columnHeaderClick'), + onDoubleClick: publish('columnHeaderDoubleClick'), + onMouseOver: publish('columnHeaderOver'), // TODO remove as it's not used + onMouseOut: publish('columnHeaderOut'), // TODO remove as it's not used + onMouseEnter: publish('columnHeaderEnter'), // TODO remove as it's not used + onMouseLeave: publish('columnHeaderLeave'), // TODO remove as it's not used + onKeyDown: publish('columnHeaderKeyDown'), + onFocus: publish('columnHeaderFocus'), + onBlur: publish('columnHeaderBlur'), + }), + [publish], + ); + + const draggableEventHandlers = React.useMemo( + () => + isDraggable + ? { + onDragStart: publish('columnHeaderDragStart'), + onDragEnter: publish('columnHeaderDragEnter'), + onDragOver: publish('columnHeaderDragOver'), + onDragEnd: publish('columnHeaderDragEnd'), + } + : {}, + [isDraggable, publish], + ); + + const columnHeaderSeparatorProps = React.useMemo( + () => ({ onMouseDown: publish('columnSeparatorMouseDown') }), + [publish], + ); + React.useEffect(() => { if (!showColumnMenuIcon) { setShowColumnMenuIcon(columnMenuOpen); @@ -215,6 +265,9 @@ function GridColumnHeaderItem(props: GridColumnHeaderItemProps) { resizable={!rootProps.disableColumnResize && !!column.resizable} data-field={column.field} columnMenu={columnMenu} + draggableContainerProps={draggableEventHandlers} + columnHeaderSeparatorProps={columnHeaderSeparatorProps} + {...mouseEventsHandlers} /> ); } diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx index ae47f8db6f86c..13f31e69e2bf2 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import clsx from 'clsx'; import { useForkRef } from '@mui/material/utils'; -import { GridColumnHeaderEventLookup } from '../../models/events'; import { GridStateColDef } from '../../models/colDef/gridColDef'; import { GridSortDirection } from '../../models/gridSortModel'; import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; @@ -38,6 +37,8 @@ interface GridGenericColumnHeaderItemProps columnMenu?: React.ReactNode; columnTitleIconButtons?: React.ReactNode; label: string; + draggableContainerProps?: Partial>; + columnHeaderSeparatorProps?: Partial; } const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnHeaderItem( @@ -65,6 +66,8 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH headerClassName, label, resizable, + draggableContainerProps, + columnHeaderSeparatorProps, ...other } = props; @@ -74,42 +77,6 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH const [showColumnMenuIcon, setShowColumnMenuIcon] = React.useState(columnMenuOpen); const handleRef = useForkRef(headerCellRef, ref); - const publish = React.useCallback( - (eventName: keyof GridColumnHeaderEventLookup) => (event: React.SyntheticEvent) => { - // Ignore portal - // See https://github.com/mui/mui-x/issues/1721 - if (!event.currentTarget.contains(event.target as Element)) { - return; - } - apiRef.current.publishEvent( - eventName, - apiRef.current.getColumnHeaderParams(elementId), - event as any, - ); - }, - [apiRef, elementId], - ); - - const mouseEventsHandlers = { - onClick: publish('columnHeaderClick'), - onDoubleClick: publish('columnHeaderDoubleClick'), - onMouseOver: publish('columnHeaderOver'), // TODO remove as it's not used - onMouseOut: publish('columnHeaderOut'), // TODO remove as it's not used - onMouseEnter: publish('columnHeaderEnter'), // TODO remove as it's not used - onMouseLeave: publish('columnHeaderLeave'), // TODO remove as it's not used - onKeyDown: publish('columnHeaderKeyDown'), - onFocus: publish('columnHeaderFocus'), - onBlur: publish('columnHeaderBlur'), - }; - - const draggableEventHandlers = isDraggable - ? { - onDragStart: publish('columnHeaderDragStart'), - onDragEnter: publish('columnHeaderDragEnter'), - onDragOver: publish('columnHeaderDragOver'), - onDragEnd: publish('columnHeaderDragEnd'), - } - : null; let ariaSort: 'ascending' | 'descending' | 'none' = 'none'; if (sortDirection != null) { @@ -147,13 +114,12 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH aria-colindex={colIndex + 1} aria-sort={ariaSort} aria-label={headerComponent == null ? label : undefined} - {...mouseEventsHandlers} {...other} >
@@ -171,8 +137,8 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH resizable={!rootProps.disableColumnResize && !!resizable} resizing={isResizing} height={height} - onMouseDown={publish('columnSeparatorMouseDown')} side={separatorSide} + {...columnHeaderSeparatorProps} /> {columnMenu}
From fb650a5d2d5dcd47139b13b6057a1faecb3f4b2d Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Mon, 1 Aug 2022 15:37:35 +0200 Subject: [PATCH 25/53] TS fix --- .../src/hooks/features/columnReorder/useGridColumnReorder.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx index ddabd93baa4f3..597646b925100 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -134,11 +134,11 @@ export const useGridColumnReorder = ( if (limitingGroupId !== null) { // verify this indexToForbid will be linked to the limiting group. Otherwise forbid it let allowIndex = false; - if (leftIndex >= 0 && visibleColumns[leftIndex].groupPath?.includes(limitingGroupId!)) { + if (leftIndex >= 0 && visibleColumns[leftIndex].groupPath?.includes(limitingGroupId)) { allowIndex = true; } else if ( rightIndex < visibleColumns.length && - visibleColumns[rightIndex].groupPath?.includes(limitingGroupId!) + visibleColumns[rightIndex].groupPath?.includes(limitingGroupId) ) { allowIndex = true; } From db1663e98c713d3d0eb06c791fd5d6a3accd0c09 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Mon, 1 Aug 2022 15:40:31 +0200 Subject: [PATCH 26/53] use helper function for groupheaders selection --- .../columnResize/useGridColumnResize.tsx | 18 ++++++++---------- .../grid/x-data-grid-pro/src/utils/domUtils.ts | 4 ++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnResize/useGridColumnResize.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnResize/useGridColumnResize.tsx index 3dfaf9cb75366..ed2e4480bda88 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnResize/useGridColumnResize.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnResize/useGridColumnResize.tsx @@ -22,6 +22,7 @@ import { findGridCellElementsFromCol, getFieldFromHeaderElem, findHeaderElementFromField, + findGroupHeaderElementsFromField, } from '../../../utils/domUtils'; import { GridApiPro } from '../../../models/gridApiPro'; import { DataGridProProcessedProps } from '../../../models/dataGridProProps'; @@ -132,7 +133,7 @@ export const useGridColumnResize = ( const colDefRef = React.useRef(); const colElementRef = React.useRef(); - const colGroupingElementRef = React.useRef(); + const colGroupingElementRef = React.useRef(); const colCellElementsRef = React.useRef(); const theme = useTheme(); @@ -253,10 +254,9 @@ export const useGridColumnResize = ( `[data-field="${colDef.field}"]`, )!; - colGroupingElementRef.current = Array.from( - apiRef.current.columnHeadersContainerElementRef?.current!.querySelectorAll( - `[data-fields~="${colDef.field}"]`, - ) ?? [], + colGroupingElementRef.current = findGroupHeaderElementsFromField( + apiRef.current.columnHeadersContainerElementRef?.current!, + colDef.field, ); colCellElementsRef.current = findGridCellElementsFromCol( @@ -358,12 +358,10 @@ export const useGridColumnResize = ( const field = getFieldFromHeaderElem(colElementRef.current!); const colDef = apiRef.current.getColumn(field); - colGroupingElementRef.current = Array.from( - apiRef.current.columnHeadersContainerElementRef?.current!.querySelectorAll( - `[data-fields~="${colDef.field}"]`, - ) ?? [], + colGroupingElementRef.current = findGroupHeaderElementsFromField( + apiRef.current.columnHeadersContainerElementRef?.current!, + field, ); - logger.debug(`Start Resize on col ${colDef.field}`); apiRef.current.publishEvent('columnResizeStart', { field }, event); diff --git a/packages/grid/x-data-grid-pro/src/utils/domUtils.ts b/packages/grid/x-data-grid-pro/src/utils/domUtils.ts index ef33671ad9dd6..94f75daae5d59 100644 --- a/packages/grid/x-data-grid-pro/src/utils/domUtils.ts +++ b/packages/grid/x-data-grid-pro/src/utils/domUtils.ts @@ -10,6 +10,10 @@ export function findHeaderElementFromField(elem: Element, field: string): Elemen return elem.querySelector(`[data-field="${field}"]`); } +export function findGroupHeaderElementsFromField(elem: Element, field: string): Element[] { + return Array.from(elem.querySelectorAll(`[data-fields~="${field}"]`) ?? []); +} + export function findGridCellElementsFromCol(col: HTMLElement, api: GridApiPro) { const root = findParentElementFromClassName(col, 'MuiDataGrid-root'); if (!root) { From 9f88ee20b0d3149f8a7dd7f34c82c6ceb362fe28 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Mon, 1 Aug 2022 17:24:09 +0200 Subject: [PATCH 27/53] feedbacks --- .../column-groups/BasicGroupingDemo.tsx | 7 +++++-- .../column-groups/BreakingGroupDemo.tsx | 7 +++++-- .../column-groups/CustomizationDemo.js | 2 +- .../src/models/gridColumnGrouping.ts | 19 ++++--------------- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx index 6d855a9729d57..e65f9b010f6d0 100644 --- a/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx @@ -1,6 +1,9 @@ import * as React from 'react'; -import { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'; -import { GridColumnGroupingModel } from '@mui/x-data-grid/models/gridColumnGrouping'; +import { + DataGridPro, + GridColDef, + GridColumnGroupingModel, +} from '@mui/x-data-grid-pro'; const columns: GridColDef[] = [ { field: 'id', headerName: 'ID', width: 90 }, diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx index 6050422921e29..ac1ae00f09344 100644 --- a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx @@ -1,6 +1,9 @@ import * as React from 'react'; -import { DataGridPro, GridColDef } from '@mui/x-data-grid-pro'; -import { GridColumnGroupingModel } from '@mui/x-data-grid/models/gridColumnGrouping'; +import { + DataGridPro, + GridColDef, + GridColumnGroupingModel, +} from '@mui/x-data-grid-pro'; const columns: GridColDef[] = [ { field: 'id', headerName: 'ID', width: 100 }, diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.js b/docs/data/data-grid/column-groups/CustomizationDemo.js index bc97e27babe99..038fea3c8a73d 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.js +++ b/docs/data/data-grid/column-groups/CustomizationDemo.js @@ -68,7 +68,7 @@ HeaderWithIcon.propTypes = { */ groupId: PropTypes.string.isRequired, /** - * The name to display in the group header. + * The title of the column rendered in the column header cell. */ headerName: PropTypes.string, icon: PropTypes.node, diff --git a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts index 9d8642a2130b1..abe3e616f7570 100644 --- a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts @@ -1,4 +1,4 @@ -import { GridAlignment, GridColDef } from './colDef'; +import { GridColDef } from './colDef'; export interface GridLeafColumn { field: GridColDef['field']; @@ -34,7 +34,8 @@ export interface GridColumnGroupHeaderParams isLastColumn: boolean; } -export type GridColumnGroup = { +export interface GridColumnGroup + extends Pick { /** * A unique string identifying the group. */ @@ -43,29 +44,17 @@ export type GridColumnGroup = { * The groups and columns included in this group. */ children: GridColumnNode[]; - /** - * The name to display in the group header. - */ - headerName?: string; - /** - * The description displayed in the header tooltip. - */ - description?: string; /** * If `true` allows to reorder columns outside of the group. * @default false */ freeReordering?: boolean; - /** - * Header cell element alignment. - */ - headerAlign?: GridAlignment; /** * Allows to render a component in the column group header cell. * @param {GridColumnGroupHeaderParams} params Object containing parameters for the renderer. * @returns {React.ReactNode} The element to be rendered. */ renderHeaderGroup?: (params: GridColumnGroupHeaderParams) => React.ReactNode; -}; +} export type GridColumnGroupingModel = GridColumnGroup[]; From d3445a1d2b6bf514ffc5c359f06d8460c53ff859 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 11:03:43 +0200 Subject: [PATCH 28/53] avoid error verification at each depth level --- .../columnGrouping/useGridColumnGrouping.ts | 46 ++++++++++--------- 1 file changed, 25 insertions(+), 21 deletions(-) diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts index db159f4acb8e5..9c0dc55f2bedc 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts @@ -5,6 +5,7 @@ import { GridStateInitializer } from '../../utils/useGridInitializeState'; import { GridColumnGroupingModel, GridColumnNode, + GridColumnGroup, isLeaf, } from '../../../models/gridColumnGrouping'; import { gridColumnGroupsLookupSelector } from './gridColumnGroupsSelector'; @@ -20,35 +21,37 @@ export function hasGroupPath( return (lookupElement).groupPath !== undefined; } -type UnwrappedGroupingModel = { [key: string]: string[] }; +type UnwrappedGroupingModel = { [key: GridColDef['field']]: GridColumnGroup['groupId'][] }; // This is the recurrence function that help writing `unwrapGroupingColumnModel()` const recurrentUnwrapGroupingColumnModel = ( columnGroupNode: GridColumnNode, - parents: any, -): UnwrappedGroupingModel => { + parents: GridColumnGroup['groupId'][], + unwrappedGroupingModelToComplet: UnwrappedGroupingModel, +): void => { if (isLeaf(columnGroupNode)) { - return { [columnGroupNode.field]: parents }; + if (unwrappedGroupingModelToComplet[columnGroupNode.field] !== undefined) { + throw new Error( + [ + `MUI: columnGroupingModel contains duplicated field`, + `column field ${columnGroupNode.field} occurrs two times in the grouping model:`, + `- ${unwrappedGroupingModelToComplet[columnGroupNode.field].join(' > ')}`, + `- ${parents.join(' > ')}`, + ].join('\n'), + ); + } + unwrappedGroupingModelToComplet[columnGroupNode.field] = parents; + return; } - const rep: UnwrappedGroupingModel = {}; + const { groupId, children } = columnGroupNode; children.forEach((child) => { - const unwrappedSubTree = recurrentUnwrapGroupingColumnModel(child, [...parents, groupId]); - Object.entries(unwrappedSubTree).forEach(([key, value]) => { - if (rep[key] !== undefined) { - throw new Error( - [ - `MUI: columnGroupingModel contains duplicated field`, - `column field ${key} occurrs two times in the grouping model:`, - `- ${rep[key].join(' > ')}`, - `- ${value.join(' > ')}`, - ].join('\n'), - ); - } - rep[key] = value; - }); + recurrentUnwrapGroupingColumnModel( + child, + [...parents, groupId], + unwrappedGroupingModelToComplet, + ); }); - return rep; }; /** @@ -67,7 +70,8 @@ export const unwrapGroupingColumnModel = ( const rep: UnwrappedGroupingModel = {}; columnGroupingModel.forEach((columnGroupNode) => { - const unwrappedSubTree = recurrentUnwrapGroupingColumnModel(columnGroupNode, []); + const unwrappedSubTree: UnwrappedGroupingModel = {}; + recurrentUnwrapGroupingColumnModel(columnGroupNode, [], unwrappedSubTree); Object.entries(unwrappedSubTree).forEach(([key, value]) => { if (rep[key] !== undefined) { throw new Error( From d0c36e4e50d1f62721e7dec3d9cabe34042ca629 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 11:11:04 +0200 Subject: [PATCH 29/53] allows to remove and add grouping --- .../columnGrouping/useGridColumnGroupingPreProcessors.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts index b2f8520ccdabd..efda8bc2f9ad7 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGroupingPreProcessors.ts @@ -11,13 +11,10 @@ export const useGridColumnGroupingPreProcessors = ( ) => { const addHeaderGroups = React.useCallback>( (columnsState) => { - if (!props.experimentalFeatures?.columnGrouping || !props.columnGroupingModel) { + if (!props.experimentalFeatures?.columnGrouping) { return columnsState; } const unwrappedGroupingModel = unwrapGroupingColumnModel(props.columnGroupingModel); - if (Object.keys(unwrappedGroupingModel).length === 0) { - return columnsState; - } columnsState.all.forEach((field) => { const newGroupPath = unwrappedGroupingModel[field] ?? []; From 5ce33b12b04b151935fc5f0a55ec5849497b8252 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 11:12:28 +0200 Subject: [PATCH 30/53] yarn docs:api --- scripts/x-data-grid-premium.exports.json | 2 +- scripts/x-data-grid-pro.exports.json | 2 +- scripts/x-data-grid.exports.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index b96567f89d358..ed505f140cb5c 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -126,7 +126,7 @@ { "name": "GridColumnApi", "kind": "Interface" }, { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, - { "name": "GridColumnGroup", "kind": "TypeAlias" }, + { "name": "GridColumnGroup", "kind": "Interface" }, { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 513a68e839e5c..72c4fa1bb9239 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -105,7 +105,7 @@ { "name": "GridColumnApi", "kind": "Interface" }, { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, - { "name": "GridColumnGroup", "kind": "TypeAlias" }, + { "name": "GridColumnGroup", "kind": "Interface" }, { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index c0d89b9ee10c9..3f327535ec6e8 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -100,7 +100,7 @@ { "name": "GridColumnApi", "kind": "Interface" }, { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, - { "name": "GridColumnGroup", "kind": "TypeAlias" }, + { "name": "GridColumnGroup", "kind": "Interface" }, { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, From c4899e8ddf870e18cc61e1e0b9127b9da00b06b9 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 13:40:16 +0200 Subject: [PATCH 31/53] split empty cell when not from the same group --- .../columnHeaders/useGridColumnHeaders.tsx | 30 ++++++-- .../tests/columnsGrouping.DataGrid.test.tsx | 72 +++++++++++++++++++ 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index 9d81bdf29cbb8..fb0c6c30c9526 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -33,6 +33,8 @@ import { getFirstColumnIndexToRender } from '../columns/gridColumnsUtils'; import { useGridVisibleRows } from '../../utils/useGridVisibleRows'; import { getRenderableIndexes } from '../virtualization/useGridVirtualScroller'; import { GridColumnGroupHeader } from '../../../components/columnHeaders/GridColumnGroupHeader'; +import { GridColumnGroup } from '../../../models/gridColumnGrouping'; +import { isDeepEqual } from '../../../utils/utils'; // TODO: add the possibility to switch this value if needed for customization const MERGE_EMPTY_CELLS = true; @@ -46,7 +48,8 @@ const GridColumnHeaderRow = styled('div', { })); interface HeaderInfo { - groupId: string | null; + groupId: GridColumnGroup['groupId'] | null; + groupParents: GridColumnGroup['groupId'][]; width: number; fields: string[]; colIndex: number; @@ -333,6 +336,8 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ); }; + const getParents = (path: string[] = [], depth: number) => path.slice(0, depth + 1); + const getColumnGroupHeaders = (params?: GetHeadersParams) => { if (headerGroupingMaxDepth === 0) { return null; @@ -360,11 +365,21 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { let columnIndex = firstColumnToRender - 1; const firstColumnToRenderGroup = visibleColumns[firstColumnToRender]?.groupPath?.[depth]!; + + // The array of parent is used to manage empty grouping cell + // When two empty grouping cell are next to each other, we merge them if the belong to the same group. + const firstColumnToRenderGroupParents = getParents( + visibleColumns[firstColumnToRender]?.groupPath, + depth, + ); while ( firstColumnToRenderGroup !== null && columnIndex >= minColumnIndex && visibleColumns[columnIndex]?.groupPath && - visibleColumns[columnIndex]?.groupPath?.[depth] === firstColumnToRenderGroup + isDeepEqual( + getParents(visibleColumns[columnIndex]?.groupPath, depth), + firstColumnToRenderGroupParents, + ) ) { const column = visibleColumns[columnIndex]; @@ -375,6 +390,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { width: column.width ?? 0, fields: [column.field], groupId: firstColumnToRenderGroup, + groupParents: firstColumnToRenderGroupParents, colIndex: columnIndex, }); } else { @@ -406,6 +422,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ...aggregated, { groupId: column.groupPath[depth], + groupParents: getParents(column.groupPath, depth), width: column.width ?? 0, fields: [column.field], colIndex: firstColumnToRender + i, @@ -413,8 +430,12 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ]; } - // It is the first level for which their is no group - if (MERGE_EMPTY_CELLS && lastItem && lastItem.groupId === null) { + if ( + MERGE_EMPTY_CELLS && + lastItem && + lastItem.groupId === null && + isDeepEqual(getParents(column.groupPath, depth), lastItem.groupParents) + ) { // We merge with previous column return [ ...aggregated.slice(0, aggregated.length - 1), @@ -430,6 +451,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ...aggregated, { groupId: null, + groupParents: getParents(column.groupPath, depth), width: column.width ?? 0, fields: [column.field], colIndex: firstColumnToRender + i, diff --git a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx index cd6663150f2bf..084065bc4febb 100644 --- a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx @@ -189,6 +189,78 @@ describe(' - Column grouping', () => { setProps({ columnGroupingModel: [{ groupId: 'col2', children: [{ field: 'col2' }] }] }); expect(screen.queryAllByRole('row')).to.have.length(3); }); + + it('should split empty group cell if they are children of different group', () => { + render( + , + ); + + const row2Headers = document.querySelectorAll( + '[aria-rowindex="2"] [role="columnheader"]', + ); + + expect( + Array.from(row2Headers).map((header) => header.getAttribute('aria-colspan')), + ).to.deep.equal(['1', '1', '1']); + expect( + Array.from(row2Headers).map((header) => header.getAttribute('aria-colindex')), + ).to.deep.equal(['1', '2', '3']); + }); + + it('should merge empty group cell if they are children of the group', () => { + render( + , + ); + + const row2Headers = document.querySelectorAll( + '[aria-rowindex="2"] [role="columnheader"]', + ); + + expect( + Array.from(row2Headers).map((header) => header.getAttribute('aria-colspan')), + ).to.deep.equal(['2', '1']); + expect( + Array.from(row2Headers).map((header) => header.getAttribute('aria-colindex')), + ).to.deep.equal(['1', '3']); + }); }); // TODO: remove the skip. I failed to test if an error is thrown From 28dcb05ca5f490c5faab13a3e6ed978180cb2317 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 13:40:43 +0200 Subject: [PATCH 32/53] improve group style --- .../columnHeaders/GridColumnGroupHeader.tsx | 11 ++++++- .../GridGenericColumnHeaderItem.tsx | 18 ++++++----- .../components/containers/GridRootStyles.ts | 31 ++++++++----------- .../x-data-grid/src/constants/gridClasses.ts | 18 ++++++----- 4 files changed, 45 insertions(+), 33 deletions(-) diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx index 504c504f57f6d..ecbb435ef35f7 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx @@ -23,14 +23,17 @@ interface GridColumnGroupHeaderProps { } type OwnerState = { + groupId: GridColumnGroupHeaderProps['groupId']; showRightBorder: boolean; + showColumnBorder: boolean; isDragging: boolean; headerAlign?: GridAlignment; classes?: DataGridProcessedProps['classes']; }; const useUtilityClasses = (ownerState: OwnerState) => { - const { classes, headerAlign, isDragging, showRightBorder } = ownerState; + const { classes, headerAlign, isDragging, showRightBorder, showColumnBorder, groupId } = + ownerState; const slots = { root: [ @@ -40,6 +43,8 @@ const useUtilityClasses = (ownerState: OwnerState) => { headerAlign === 'right' && 'columnHeader--alignRight', isDragging && 'columnHeader--moving', showRightBorder && 'withBorder', + showColumnBorder && 'columnHeader--showColumnBorder', + groupId === null ? 'columnHeader--emptyGroup' : 'columnHeader--filledGroup', ], draggableContainer: ['columnHeaderDraggableContainer'], titleContainer: ['columnHeaderTitleContainer'], @@ -98,10 +103,13 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { ? rootProps.showColumnRightBorder : !removeLastBorderRight && !extendRowFullWidth; + const showColumnBorder = rootProps.showColumnRightBorder; + const ownerState = { ...props, classes: rootProps.classes, showRightBorder, + showColumnBorder, headerAlign, depth, isDragging: false, @@ -134,6 +142,7 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { label={label} aria-colspan={fields.length} data-fields={fields.join(' ')} + disableHeaderSeparator /> ); } diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx index 13f31e69e2bf2..54a51f5da338a 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridGenericColumnHeaderItem.tsx @@ -39,6 +39,7 @@ interface GridGenericColumnHeaderItemProps label: string; draggableContainerProps?: Partial>; columnHeaderSeparatorProps?: Partial; + disableHeaderSeparator?: boolean; } const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnHeaderItem( @@ -68,6 +69,7 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH resizable, draggableContainerProps, columnHeaderSeparatorProps, + disableHeaderSeparator, ...other } = props; @@ -133,13 +135,15 @@ const GridGenericColumnHeaderItem = React.forwardRef(function GridGenericColumnH
{columnMenuIconButton}
- + {!disableHeaderSeparator && ( + + )} {columnMenu}
); diff --git a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts index 4965bbf30364e..387488f5d53e5 100644 --- a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts +++ b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts @@ -99,13 +99,12 @@ export const GridRootStyles = styled('div', { { borderBottomColor: 'transparent', }, - [`& .${gridClasses.columnHeader}, & .${gridClasses.columnGroupHeader}, & .${gridClasses.cell}`]: - { - WebkitTapHighlightColor: 'transparent', - lineHeight: null, - padding: '0 10px', - boxSizing: 'border-box', - }, + [`& .${gridClasses.columnHeader}, & .${gridClasses.cell}`]: { + WebkitTapHighlightColor: 'transparent', + lineHeight: null, + padding: '0 10px', + boxSizing: 'border-box', + }, [`& .${gridClasses.columnHeader}:focus-within, & .${gridClasses.cell}:focus-within`]: { outline: `solid ${alpha(theme.palette.primary.main, 0.5)} 1px`, outlineWidth: 1, @@ -148,21 +147,17 @@ export const GridRootStyles = styled('div', { whiteSpace: 'nowrap', overflowX: 'hidden', }, - [`& .${gridClasses.columnHeaderTitleContainerContent}`]: { - overflow: 'hidden', - display: 'flex', - alignItems: 'center', + [`& .${gridClasses['columnHeader--filledGroup']} .${gridClasses.columnHeaderTitleContainer}`]: { + borderBottom: `solid ${borderColor} 1px`, }, - [`& .${gridClasses['columnGroupHeader--withName']} .${gridClasses.columnGroupHeaderTitleContainerContent}`]: + [`& .${gridClasses['columnHeader--filledGroup']}.${gridClasses['columnHeader--showColumnBorder']} .${gridClasses.columnHeaderTitleContainer}`]: + { + borderBottom: `none`, + }, + [`& .${gridClasses['columnHeader--filledGroup']}.${gridClasses['columnHeader--showColumnBorder']}`]: { borderBottom: `solid ${borderColor} 1px`, }, - [`& .${gridClasses.withBorder} .${gridClasses.columnGroupHeaderTitleContainerContent}`]: { - borderBottom: `none`, - }, - [`& .${gridClasses.withBorder}.${gridClasses.columnGroupHeader}`]: { - borderBottom: `solid ${borderColor} 1px`, - }, [`& .${gridClasses.sortIcon}, & .${gridClasses.filterIcon}`]: { fontSize: 'inherit', }, diff --git a/packages/grid/x-data-grid/src/constants/gridClasses.ts b/packages/grid/x-data-grid/src/constants/gridClasses.ts index 9d3bda637860e..5d723d4f9df43 100644 --- a/packages/grid/x-data-grid/src/constants/gridClasses.ts +++ b/packages/grid/x-data-grid/src/constants/gridClasses.ts @@ -146,13 +146,17 @@ export interface GridClasses { */ columnHeaderTitleContainerContent: string; /** - * Styles applied to the column group header's title excepted buttons. + * Styles applied to the column group header cell if not empty. */ - columnGroupHeaderTitleContainerContent: string; + 'columnHeader--filledGroup': string; /** - * Styles applied to the column group header cell if not empty. + * Styles applied to the empty column group header cell. + */ + 'columnHeader--emptyGroup': string; + /** + * Styles applied to the column group header cell when show column border. */ - 'columnGroupHeader--withName': string; + 'columnHeader--showColumnBorder': string; /** * Styles applied to the column headers. */ @@ -516,9 +520,9 @@ export const gridClasses = generateUtilityClasses('MuiDataGrid', [ 'columnHeaderTitle', 'columnHeaderTitleContainer', 'columnGroupHeader', - 'columnGroupHeader--withName', - 'columnHeaderTitleContainerContent', - 'columnGroupHeaderTitleContainerContent', + 'columnHeader--filledGroup', + 'columnHeader--emptyGroup', + 'columnHeader--showColumnBorder', 'columnHeaders', 'columnHeadersInner', 'columnHeadersInner--scrollable', From 956b0261fd566ff7689fff10caac49aa55e0c28a Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 13:48:18 +0200 Subject: [PATCH 33/53] scripts --- docs/pages/x/api/data-grid/data-grid-premium.json | 5 +++-- docs/pages/x/api/data-grid/data-grid-pro.json | 5 +++-- docs/pages/x/api/data-grid/data-grid.json | 5 +++-- .../api-docs/data-grid/data-grid-premium-pt.json | 15 ++++++++++----- .../api-docs/data-grid/data-grid-premium-zh.json | 15 ++++++++++----- .../api-docs/data-grid/data-grid-premium.json | 15 ++++++++++----- .../api-docs/data-grid/data-grid-pro-pt.json | 15 ++++++++++----- .../api-docs/data-grid/data-grid-pro-zh.json | 15 ++++++++++----- .../api-docs/data-grid/data-grid-pro.json | 15 ++++++++++----- .../api-docs/data-grid/data-grid-pt.json | 15 ++++++++++----- .../api-docs/data-grid/data-grid-zh.json | 15 ++++++++++----- .../api-docs/data-grid/data-grid.json | 15 ++++++++++----- 12 files changed, 99 insertions(+), 51 deletions(-) diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index 8fdc14e1cfa43..5c02853ba250c 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -289,8 +289,9 @@ "columnHeaderTitle", "columnHeaderTitleContainer", "columnHeaderTitleContainerContent", - "columnGroupHeaderTitleContainerContent", - "columnGroupHeader--withName", + "columnHeader--filledGroup", + "columnHeader--emptyGroup", + "columnHeader--showColumnBorder", "columnHeaders", "columnHeadersInner", "columnHeadersInner--scrollable", diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index 6b567a23a1fb6..a35687842bead 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -341,8 +341,9 @@ "columnHeaderTitle", "columnHeaderTitleContainer", "columnHeaderTitleContainerContent", - "columnGroupHeaderTitleContainerContent", - "columnGroupHeader--withName", + "columnHeader--filledGroup", + "columnHeader--emptyGroup", + "columnHeader--showColumnBorder", "columnHeaders", "columnHeadersInner", "columnHeadersInner--scrollable", diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 85c805daef63d..cf02c6c2b5756 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -295,8 +295,9 @@ "columnHeaderTitle", "columnHeaderTitleContainer", "columnHeaderTitleContainerContent", - "columnGroupHeaderTitleContainerContent", - "columnGroupHeader--withName", + "columnHeader--filledGroup", + "columnHeader--emptyGroup", + "columnHeader--showColumnBorder", "columnHeaders", "columnHeadersInner", "columnHeadersInner--scrollable", diff --git a/docs/translations/api-docs/data-grid/data-grid-premium-pt.json b/docs/translations/api-docs/data-grid/data-grid-premium-pt.json index 2e66529a3069c..065ea45cdfbd1 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium-pt.json @@ -311,15 +311,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-premium-zh.json b/docs/translations/api-docs/data-grid/data-grid-premium-zh.json index 2e66529a3069c..065ea45cdfbd1 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium-zh.json @@ -311,15 +311,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium.json index 2e66529a3069c..065ea45cdfbd1 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium.json @@ -311,15 +311,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json index f53f37b436fc5..5981705a7b264 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json @@ -301,15 +301,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json index f53f37b436fc5..5981705a7b264 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json @@ -301,15 +301,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro.json index f53f37b436fc5..5981705a7b264 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro.json @@ -301,15 +301,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-pt.json b/docs/translations/api-docs/data-grid/data-grid-pt.json index e4190e9c327cf..da546c7852950 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pt.json @@ -271,15 +271,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid-zh.json b/docs/translations/api-docs/data-grid/data-grid-zh.json index e4190e9c327cf..da546c7852950 100644 --- a/docs/translations/api-docs/data-grid/data-grid-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-zh.json @@ -271,15 +271,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" diff --git a/docs/translations/api-docs/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid.json index e4190e9c327cf..da546c7852950 100644 --- a/docs/translations/api-docs/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid.json @@ -271,15 +271,20 @@ "description": "Styles applied to {{nodeName}}.", "nodeName": "the column header's title excepted buttons" }, - "columnGroupHeaderTitleContainerContent": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the column group header's title excepted buttons" - }, - "columnGroupHeader--withName": { + "columnHeader--filledGroup": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the column group header cell", "conditions": "not empty" }, + "columnHeader--emptyGroup": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the empty column group header cell" + }, + "columnHeader--showColumnBorder": { + "description": "Styles applied to {{nodeName}} when {{conditions}}.", + "nodeName": "the column group header cell", + "conditions": "show column border" + }, "columnHeaders": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the column headers" From 16ffc9cd143862918721b824e182fa12577123b8 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 16:27:19 +0200 Subject: [PATCH 34/53] fix tests --- packages/grid/x-data-grid/src/constants/gridClasses.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grid/x-data-grid/src/constants/gridClasses.ts b/packages/grid/x-data-grid/src/constants/gridClasses.ts index 5d723d4f9df43..ecda4f4d810a3 100644 --- a/packages/grid/x-data-grid/src/constants/gridClasses.ts +++ b/packages/grid/x-data-grid/src/constants/gridClasses.ts @@ -519,6 +519,7 @@ export const gridClasses = generateUtilityClasses('MuiDataGrid', [ 'columnHeaderDropZone', 'columnHeaderTitle', 'columnHeaderTitleContainer', + 'columnHeaderTitleContainerContent', 'columnGroupHeader', 'columnHeader--filledGroup', 'columnHeader--emptyGroup', From 4049f002af6a83e58cbccb069df998299cc6442d Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 16:41:15 +0200 Subject: [PATCH 35/53] helper simplification --- .../columnGrouping/useGridColumnGrouping.ts | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts index 9c0dc55f2bedc..8656f22a8b9f3 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts @@ -67,27 +67,12 @@ export const unwrapGroupingColumnModel = ( return {}; } - const rep: UnwrappedGroupingModel = {}; - + const unwrappedSubTree: UnwrappedGroupingModel = {}; columnGroupingModel.forEach((columnGroupNode) => { - const unwrappedSubTree: UnwrappedGroupingModel = {}; recurrentUnwrapGroupingColumnModel(columnGroupNode, [], unwrappedSubTree); - Object.entries(unwrappedSubTree).forEach(([key, value]) => { - if (rep[key] !== undefined) { - throw new Error( - [ - `MUI: columnGroupingModel has duplicated field.`, - `column field ${key} occurres two times in the grouping model:`, - `- ${rep[key].join(' > ')}`, - `- ${value.join(' > ')}`, - ].join('\n'), - ); - } - rep[key] = value; - }); }); - return rep; + return unwrappedSubTree; }; const createGroupLookup = (columnGroupingModel: GridColumnNode[]): GridColumnGroupLookup => { From e638a90a87490b76a588921301386ffabaf202de Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 2 Aug 2022 16:42:46 +0200 Subject: [PATCH 36/53] wrapp field to avoid wrong overlapping string --- packages/grid/x-data-grid-pro/src/utils/domUtils.ts | 2 +- .../src/components/columnHeaders/GridColumnGroupHeader.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grid/x-data-grid-pro/src/utils/domUtils.ts b/packages/grid/x-data-grid-pro/src/utils/domUtils.ts index 94f75daae5d59..1958f84a405ef 100644 --- a/packages/grid/x-data-grid-pro/src/utils/domUtils.ts +++ b/packages/grid/x-data-grid-pro/src/utils/domUtils.ts @@ -11,7 +11,7 @@ export function findHeaderElementFromField(elem: Element, field: string): Elemen } export function findGroupHeaderElementsFromField(elem: Element, field: string): Element[] { - return Array.from(elem.querySelectorAll(`[data-fields~="${field}"]`) ?? []); + return Array.from(elem.querySelectorAll(`[data-fields~="|-${field}-|"]`) ?? []); } export function findGridCellElementsFromCol(col: HTMLElement, api: GridApiPro) { diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx index ecbb435ef35f7..604100a196603 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx @@ -141,7 +141,8 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { resizable={false} label={label} aria-colspan={fields.length} - data-fields={fields.join(' ')} + // The fields are wrapped between |-...-| to avoid confusion between fields "id" and "id2" when using selector data-fields~= + data-fields={`|-${fields.join('-|-')}-|`} disableHeaderSeparator /> ); From 0fc9a801c5f55d69526efb704f860bacc4f0b891 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette <45398769+alexfauquette@users.noreply.github.com> Date: Tue, 2 Aug 2022 17:34:11 +0200 Subject: [PATCH 37/53] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Andrew Cherniavskii Co-authored-by: José Rodolfo Freitas --- .../data-grid/column-groups/column-groups.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 9470a39cfb775..08638a995364b 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -8,9 +8,9 @@ title: Data grid - Column groups Grouping columns allows you to have multiple levels of columns in your header and to toggle column groups to show and hide additional columns. -## Define column grouping +## Define column groups -You can define the column grouping structure by providing the `columnGroupingModel` prop to the grid. +You can define column groups with the `columnGroupingModel` prop. This prop receives an array of column groups. A column group is defined by at least two properties: @@ -30,7 +30,7 @@ A column can only be associated with one group. ```jsx columnGroupingModel={[ { - groupId: "internal", + groupId: "internal data", children: [{ field: "id" }] }, { @@ -53,10 +53,10 @@ columnGroupingModel={[ ## Customize column group -In addition to the required `groupId` and `children`, you can add extra properties to a column group object to customize it: +In addition to the required `groupId` and `children`, you can use the following optional properties to customize a column group: -- `headerName`: the sting displayed instead of `groupId`. -- `description`: a longer string displayed in a tooltip. +- `headerName`: the string displayed as the column's name (instead of `groupId`). +- `description`: a text for the tooltip. - `renderHeaderGroup`: a function returning custom React component. {{"demo": "CustomizationDemo.js", "bg": "inline"}} @@ -64,9 +64,9 @@ In addition to the required `groupId` and `children`, you can add extra properti ## Column reordering [](https://mui.com/store/items/mui-x-pro/) By default, column groups can not be divided when reordering columns. -This default behavior can be removed on specific group by setting `freeReordering: true` in the column group object. +You can customize this behavior on specific groups by setting `freeReordering: true` in a column group object. -In the example bellow the `Character` column group can be divided, but not other column groups +In the example below, the `Names` column group can be divided, but not other column groups {{"demo": "BreakingGroupDemo.js", "disableAd": true, "bg": "inline"}} From 0d2b6f3fe831a38d44b6a688cb3a1352b47045f1 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 3 Aug 2022 14:23:27 +0200 Subject: [PATCH 38/53] fix styling --- .../x-data-grid/src/components/containers/GridRootStyles.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts index 387488f5d53e5..f22101b72fede 100644 --- a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts +++ b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts @@ -147,6 +147,11 @@ export const GridRootStyles = styled('div', { whiteSpace: 'nowrap', overflowX: 'hidden', }, + [`& .${gridClasses.columnHeaderTitleContainerContent}`]: { + overflow: 'hidden', + display: 'flex', + alignItems: 'center', + }, [`& .${gridClasses['columnHeader--filledGroup']} .${gridClasses.columnHeaderTitleContainer}`]: { borderBottom: `solid ${borderColor} 1px`, }, From d595a7230143c7d6abff9480d63d49b4f923e326 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 3 Aug 2022 14:26:03 +0200 Subject: [PATCH 39/53] add message for experimental flag --- docs/data/data-grid/column-groups/column-groups.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 08638a995364b..054a6bf40eaf3 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -8,6 +8,15 @@ title: Data grid - Column groups Grouping columns allows you to have multiple levels of columns in your header and to toggle column groups to show and hide additional columns. +:::warning +This feature is experimental, it needs to be explicitly activated using the `columnGrouping` experimental feature flag. + +```tsx + +``` + +::: + ## Define column groups You can define column groups with the `columnGroupingModel` prop. From 82011e22fb038d2803d66f1514826e097117c16a Mon Sep 17 00:00:00 2001 From: Olivier Tassinari Date: Thu, 4 Aug 2022 18:14:14 +0200 Subject: [PATCH 40/53] fix prettier style --- .../data-grid/column-groups/column-groups.md | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 054a6bf40eaf3..b7f152c0a8081 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -37,25 +37,24 @@ A column can only be associated with one group. ::: ```jsx -columnGroupingModel={[ + ``` {{"demo": "BasicGroupingDemo.js", "bg": "inline"}} From 552d6cdcbfe292fc050c6f4c29f6876048dbc813 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Fri, 5 Aug 2022 11:39:28 +0200 Subject: [PATCH 41/53] Olivier style feedbacks --- .../data-grid/column-groups/CustomizationDemo.js | 1 - .../data-grid/column-groups/CustomizationDemo.tsx | 1 - docs/data/data-grid/column-groups/column-groups.md | 13 ++++++++----- .../columnGrouping/useGridColumnGrouping.ts | 6 +++--- .../x-data-grid/src/models/colDef/gridColDef.ts | 2 +- .../x-data-grid/src/models/gridColumnGrouping.ts | 2 +- .../src/tests/columnsGrouping.DataGrid.test.tsx | 8 ++++---- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.js b/docs/data/data-grid/column-groups/CustomizationDemo.js index 038fea3c8a73d..160edbbb90235 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.js +++ b/docs/data/data-grid/column-groups/CustomizationDemo.js @@ -2,7 +2,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { styled } from '@mui/material/styles'; import { DataGridPro } from '@mui/x-data-grid-pro'; - import BuildIcon from '@mui/icons-material/Build'; import PersonIcon from '@mui/icons-material/Person'; diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.tsx b/docs/data/data-grid/column-groups/CustomizationDemo.tsx index be825e5e8ea97..632853c1bdff7 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.tsx +++ b/docs/data/data-grid/column-groups/CustomizationDemo.tsx @@ -6,7 +6,6 @@ import { GridColumnGroupHeaderParams, GridColumnGroupingModel, } from '@mui/x-data-grid-pro'; - import BuildIcon from '@mui/icons-material/Build'; import PersonIcon from '@mui/icons-material/Person'; diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index b7f152c0a8081..7bd0e8174d749 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -41,18 +41,21 @@ A column can only be associated with one group. columnGroupingModel={[ { groupId: 'internal data', - children: [{ field: 'id' }], + children: [{ field: 'id' }] }, { groupId: 'character', children: [ { groupId: 'naming', - children: [{ field: 'lastName' }, { field: 'firstName' }], + children: [ + { field: 'lastName' }, + { field: 'firstName' }, + ] }, - { field: 'age' }, - ], - }, + { field: 'age' } + ] + } ]} /> ``` diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts index 8656f22a8b9f3..eeb10241e748c 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts @@ -85,17 +85,17 @@ const createGroupLookup = (columnGroupingModel: GridColumnNode[]): GridColumnGro const { groupId, children, ...other } = node; if (!groupId) { throw new Error( - 'MUI: An element of the columnGroupingModel does not have either `field` or `groupId`', + 'MUI: An element of the columnGroupingModel does not have either `field` or `groupId`.', ); } if (!children) { - console.warn(`MUI: group groupId=${groupId} has no children. `); + console.warn(`MUI: group groupId=${groupId} has no children.`); } const groupParam = { ...other, groupId }; const subTreeLookup = createGroupLookup(children); if (subTreeLookup[groupId] !== undefined || groupLookup[groupId] !== undefined) { throw new Error( - `MUI: The groupId ${groupId} is used multiple times in the columnGroupingModel`, + `MUI: The groupId ${groupId} is used multiple times in the columnGroupingModel.`, ); } groupLookup = { ...groupLookup, ...subTreeLookup, [groupId]: groupParam }; diff --git a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts index 131e53ebbdc0d..2a44905af03e2 100644 --- a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts +++ b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts @@ -287,7 +287,7 @@ export type GridStateColDef = /** * The id of the groups leading to the column. * The array is ordered by increasing depth (the last element is the direct parent of the column). - * If not defined, the column is in no group (equivalent to a path equal to `[]`) + * If not defined, the column is in no group (equivalent to a path equal to `[]`). * This parameter is computed from the `columnGroupingModel` prop. */ groupPath?: string[]; diff --git a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts index abe3e616f7570..392350f64b0ec 100644 --- a/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/models/gridColumnGrouping.ts @@ -45,7 +45,7 @@ export interface GridColumnGroup */ children: GridColumnNode[]; /** - * If `true` allows to reorder columns outside of the group. + * If `true`, allows reordering columns outside of the group. * @default false */ freeReordering?: boolean; diff --git a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx index 084065bc4febb..9c6e896e9fb2a 100644 --- a/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx +++ b/packages/grid/x-data-grid/src/tests/columnsGrouping.DataGrid.test.tsx @@ -272,7 +272,7 @@ describe(' - Column grouping', () => { ); - it('should log an error if two groups have the same id', function test() { + it('should log an error if two groups have the same id', () => { expect(() => { render( - Column grouping', () => { }).toErrorDev(); }); - it('should log an error if a columns is referenced in two groups', function test() { + it('should log an error if a columns is referenced in two groups', () => { expect(() => { render( - Column grouping', () => { }).toErrorDev(); }); - it('should log an error if a group have no id', function test() { + it('should log an error if a group have no id', () => { expect(() => { try { render( @@ -334,7 +334,7 @@ describe(' - Column grouping', () => { ); }); - it('should log an warning if a group have no children', function test() { + it('should log a warning if a group has no children', () => { expect(() => { render( Date: Tue, 9 Aug 2022 10:09:13 +0200 Subject: [PATCH 42/53] Mathews feedback --- .../data-grid/column-groups/column-groups.md | 2 +- docs/scripts/generateProptypes.ts | 1 + .../src/DataGridPremium/DataGridPremium.tsx | 19 +------------------ .../src/DataGridPro/DataGridPro.tsx | 19 +------------------ .../x-data-grid/src/DataGrid/DataGrid.tsx | 19 +------------------ 5 files changed, 5 insertions(+), 55 deletions(-) diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 7bd0e8174d749..1b0a46dcfed50 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -74,7 +74,7 @@ In addition to the required `groupId` and `children`, you can use the following ## Column reordering [](https://mui.com/store/items/mui-x-pro/) -By default, column groups can not be divided when reordering columns. +By default, the columns that are part of a group cannot be dragged to outside their group. You can customize this behavior on specific groups by setting `freeReordering: true` in a column group object. In the example below, the `Names` column group can be divided, but not other column groups diff --git a/docs/scripts/generateProptypes.ts b/docs/scripts/generateProptypes.ts index 37661c037c0fe..01a398bacd761 100644 --- a/docs/scripts/generateProptypes.ts +++ b/docs/scripts/generateProptypes.ts @@ -34,6 +34,7 @@ async function generateProptypes(program: ttp.ts.Program, sourceFile: string) { 'groupingColDef', 'rowNode', 'localeText', + 'columnGroupingModel' ]; if (propsToNotResolve.includes(name)) { return false; diff --git a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 824e12d8a1f77..d36199f1d7760 100644 --- a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -134,24 +134,7 @@ DataGridPremiumRaw.propTypes = { * @default 3 */ columnBuffer: PropTypes.number, - columnGroupingModel: PropTypes.arrayOf( - PropTypes.shape({ - children: PropTypes.arrayOf( - PropTypes.oneOfType([ - PropTypes.object, - PropTypes.shape({ - field: PropTypes.string.isRequired, - }), - ]).isRequired, - ).isRequired, - description: PropTypes.string, - freeReordering: PropTypes.bool, - groupId: PropTypes.string.isRequired, - headerAlign: PropTypes.oneOf(['center', 'left', 'right']), - headerName: PropTypes.string, - renderHeaderGroup: PropTypes.func, - }), - ), + columnGroupingModel: PropTypes.arrayOf(PropTypes.object), /** * Set of columns of type [[GridColumns]]. */ diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 5aa328ce77092..7458187c0384f 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -115,24 +115,7 @@ DataGridProRaw.propTypes = { * @default 3 */ columnBuffer: PropTypes.number, - columnGroupingModel: PropTypes.arrayOf( - PropTypes.shape({ - children: PropTypes.arrayOf( - PropTypes.oneOfType([ - PropTypes.object, - PropTypes.shape({ - field: PropTypes.string.isRequired, - }), - ]).isRequired, - ).isRequired, - description: PropTypes.string, - freeReordering: PropTypes.bool, - groupId: PropTypes.string.isRequired, - headerAlign: PropTypes.oneOf(['center', 'left', 'right']), - headerName: PropTypes.string, - renderHeaderGroup: PropTypes.func, - }), - ), + columnGroupingModel: PropTypes.arrayOf(PropTypes.object), /** * Set of columns of type [[GridColumns]]. */ diff --git a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx index 843227d321845..cfa721d152e13 100644 --- a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx @@ -89,24 +89,7 @@ DataGridRaw.propTypes = { * @default 3 */ columnBuffer: PropTypes.number, - columnGroupingModel: PropTypes.arrayOf( - PropTypes.shape({ - children: PropTypes.arrayOf( - PropTypes.oneOfType([ - PropTypes.object, - PropTypes.shape({ - field: PropTypes.string.isRequired, - }), - ]).isRequired, - ).isRequired, - description: PropTypes.string, - freeReordering: PropTypes.bool, - groupId: PropTypes.string.isRequired, - headerAlign: PropTypes.oneOf(['center', 'left', 'right']), - headerName: PropTypes.string, - renderHeaderGroup: PropTypes.func, - }), - ), + columnGroupingModel: PropTypes.arrayOf(PropTypes.object), /** * Set of columns of type [[GridColumns]]. */ From 64b382f85956e73e7b7fca4d2ccc0eae821a006e Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 9 Aug 2022 11:30:41 +0200 Subject: [PATCH 43/53] scripts and remove useless editing --- .../data-grid/column-groups/BasicGroupingDemo.js | 3 --- .../data-grid/column-groups/BasicGroupingDemo.tsx | 3 --- .../data-grid/column-groups/BreakingGroupDemo.js | 3 --- .../data-grid/column-groups/BreakingGroupDemo.tsx | 3 --- .../data-grid/column-groups/CustomizationDemo.js | 3 --- .../data-grid/column-groups/CustomizationDemo.tsx | 3 --- docs/data/data-grid/column-groups/column-groups.md | 13 +++++-------- docs/scripts/generateProptypes.ts | 2 +- 8 files changed, 6 insertions(+), 27 deletions(-) diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.js b/docs/data/data-grid/column-groups/BasicGroupingDemo.js index 471234b64f680..eda34144574af 100644 --- a/docs/data/data-grid/column-groups/BasicGroupingDemo.js +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.js @@ -7,20 +7,17 @@ const columns = [ field: 'firstName', headerName: 'First name', width: 150, - editable: true, }, { field: 'lastName', headerName: 'Last name', width: 150, - editable: true, }, { field: 'age', headerName: 'Age', type: 'number', width: 110, - editable: true, }, ]; diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx index e65f9b010f6d0..736f474d0e769 100644 --- a/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx @@ -11,20 +11,17 @@ const columns: GridColDef[] = [ field: 'firstName', headerName: 'First name', width: 150, - editable: true, }, { field: 'lastName', headerName: 'Last name', width: 150, - editable: true, }, { field: 'age', headerName: 'Age', type: 'number', width: 110, - editable: true, }, ]; diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.js b/docs/data/data-grid/column-groups/BreakingGroupDemo.js index 32a0b6c100a6a..fa8dc8ed2f540 100644 --- a/docs/data/data-grid/column-groups/BreakingGroupDemo.js +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.js @@ -8,20 +8,17 @@ const columns = [ field: 'firstName', headerName: 'First name', width: 150, - editable: true, }, { field: 'lastName', headerName: 'Last name', width: 150, - editable: true, }, { field: 'age', headerName: 'Age', type: 'number', width: 110, - editable: true, }, ]; diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx index ac1ae00f09344..77be7f1248726 100644 --- a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx @@ -12,20 +12,17 @@ const columns: GridColDef[] = [ field: 'firstName', headerName: 'First name', width: 150, - editable: true, }, { field: 'lastName', headerName: 'Last name', width: 150, - editable: true, }, { field: 'age', headerName: 'Age', type: 'number', width: 110, - editable: true, }, ]; diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.js b/docs/data/data-grid/column-groups/CustomizationDemo.js index 160edbbb90235..8d701b7faffa1 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.js +++ b/docs/data/data-grid/column-groups/CustomizationDemo.js @@ -11,20 +11,17 @@ const columns = [ field: 'firstName', headerName: 'First name', width: 150, - editable: true, }, { field: 'lastName', headerName: 'Last name', width: 150, - editable: true, }, { field: 'age', headerName: 'Age', type: 'number', width: 110, - editable: true, }, ]; diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.tsx b/docs/data/data-grid/column-groups/CustomizationDemo.tsx index 632853c1bdff7..61f7da9be3bb1 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.tsx +++ b/docs/data/data-grid/column-groups/CustomizationDemo.tsx @@ -15,20 +15,17 @@ const columns: GridColDef[] = [ field: 'firstName', headerName: 'First name', width: 150, - editable: true, }, { field: 'lastName', headerName: 'Last name', width: 150, - editable: true, }, { field: 'age', headerName: 'Age', type: 'number', width: 110, - editable: true, }, ]; diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 1b0a46dcfed50..2ba7b45a21d78 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -41,21 +41,18 @@ A column can only be associated with one group. columnGroupingModel={[ { groupId: 'internal data', - children: [{ field: 'id' }] + children: [{ field: 'id' }], }, { groupId: 'character', children: [ { groupId: 'naming', - children: [ - { field: 'lastName' }, - { field: 'firstName' }, - ] + children: [{ field: 'lastName' }, { field: 'firstName' }], }, - { field: 'age' } - ] - } + { field: 'age' }, + ], + }, ]} /> ``` diff --git a/docs/scripts/generateProptypes.ts b/docs/scripts/generateProptypes.ts index 01a398bacd761..9a6ad47e3734b 100644 --- a/docs/scripts/generateProptypes.ts +++ b/docs/scripts/generateProptypes.ts @@ -34,7 +34,7 @@ async function generateProptypes(program: ttp.ts.Program, sourceFile: string) { 'groupingColDef', 'rowNode', 'localeText', - 'columnGroupingModel' + 'columnGroupingModel', ]; if (propsToNotResolve.includes(name)) { return false; From dac5a1d6850e188de840f7ac8b4a7d4c771780fd Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 9 Aug 2022 11:31:01 +0200 Subject: [PATCH 44/53] allows to add headerClassName to column group --- .../column-groups/CustomizationDemo.js | 17 +++++++-- .../column-groups/CustomizationDemo.tsx | 14 ++++++-- .../columnHeaders/GridColumnGroupHeader.tsx | 36 +++++++++++-------- .../src/models/gridColumnGrouping.ts | 20 ++++++++++- scripts/x-data-grid-premium.exports.json | 2 ++ scripts/x-data-grid-pro.exports.json | 2 ++ scripts/x-data-grid.exports.json | 2 ++ 7 files changed, 72 insertions(+), 21 deletions(-) diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.js b/docs/data/data-grid/column-groups/CustomizationDemo.js index 8d701b7faffa1..29b4b48586297 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.js +++ b/docs/data/data-grid/column-groups/CustomizationDemo.js @@ -1,6 +1,7 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { styled } from '@mui/material/styles'; +import Box from '@mui/material/Box'; import { DataGridPro } from '@mui/x-data-grid-pro'; import BuildIcon from '@mui/icons-material/Build'; import PersonIcon from '@mui/icons-material/Person'; @@ -62,7 +63,8 @@ HeaderWithIcon.propTypes = { /** * A unique string identifying the group. */ - groupId: PropTypes.string.isRequired, + groupId: PropTypes.oneOfType([PropTypes.oneOf([null]), PropTypes.string]) + .isRequired, /** * The title of the column rendered in the column header cell. */ @@ -91,6 +93,7 @@ const columnGroupingModel = [ { groupId: 'naming', headerName: 'Names', + headerClassName: 'my-super-theme--character-group', children: [{ field: 'lastName' }, { field: 'firstName' }], }, { field: 'age' }, @@ -100,7 +103,15 @@ const columnGroupingModel = [ export default function CustomizationDemo() { return ( -
+ -
+ ); } diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.tsx b/docs/data/data-grid/column-groups/CustomizationDemo.tsx index 61f7da9be3bb1..f23e4c740c189 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.tsx +++ b/docs/data/data-grid/column-groups/CustomizationDemo.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { styled } from '@mui/material/styles'; +import Box from '@mui/material/Box'; import { DataGridPro, GridColDef, @@ -87,6 +88,7 @@ const columnGroupingModel: GridColumnGroupingModel = [ { groupId: 'naming', headerName: 'Names', + headerClassName: 'my-super-theme--character-group', children: [{ field: 'lastName' }, { field: 'firstName' }], }, { field: 'age' }, @@ -95,7 +97,15 @@ const columnGroupingModel: GridColumnGroupingModel = [ ]; export default function CustomizationDemo() { return ( -
+ -
+ ); } diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx index 604100a196603..ed2d7cf25d8aa 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx @@ -9,6 +9,7 @@ import { gridColumnGroupsLookupSelector } from '../../hooks/features/columnGroup import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { useGridSelector } from '../../hooks/utils/useGridSelector'; import { GridGenericColumnHeaderItem } from './GridGenericColumnHeaderItem'; +import { GridColumnGroup, GridColumnGroupHeaderParams } from '../../models/gridColumnGrouping'; interface GridColumnGroupHeaderProps { groupId: string | null; @@ -76,26 +77,25 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { hasScrollY: false, }; - const { - headerName = groupId ?? '', - description = '', - headerAlign = undefined, - } = groupId ? columnGroupsLookup[groupId] : {}; + const group: Partial = groupId ? columnGroupsLookup[groupId] : {}; + + const { headerName = groupId ?? '', description = '', headerAlign = undefined } = group; let headerComponent: React.ReactNode; const render = groupId && columnGroupsLookup[groupId]?.renderHeaderGroup; + const renderParams = { + groupId, + headerName, + description, + depth, + maxDepth, + fields, + colIndex, + isLastColumn, + }; if (groupId && render) { - headerComponent = render({ - groupId, - headerName, - description, - depth, - maxDepth, - fields, - colIndex, - isLastColumn, - }); + headerComponent = render(renderParams as GridColumnGroupHeaderParams); } const removeLastBorderRight = isLastColumn && hasScrollX && !hasScrollY; @@ -121,6 +121,11 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { const elementId = groupId === null ? `empty-group-cell-${id}` : groupId; const classes = useUtilityClasses(ownerState); + const headerClassName = + typeof group.headerClassName === 'function' + ? group.headerClassName(renderParams) + : group.headerClassName; + return ( node).field !== undefined; } +/** + * A function used to process headerClassName params. + */ +export type GridColumnGroupHeaderClassFn = (params: GridColumnGroupHeaderParams) => string; + +/** + * The union type representing the [[GridColDef]] column header class type. + */ +export type GridColumnGroupHeaderClassNamePropType = string | GridColumnGroupHeaderClassFn; + export interface GridColumnGroupHeaderParams - extends Pick { + extends Pick { + /** + * A unique string identifying the group. + */ + groupId: GridColumnGroup['groupId'] | null; /** * The number parent the group have. */ @@ -55,6 +69,10 @@ export interface GridColumnGroup * @returns {React.ReactNode} The element to be rendered. */ renderHeaderGroup?: (params: GridColumnGroupHeaderParams) => React.ReactNode; + /** + * Class name that will be added in the column group header cell. + */ + headerClassName?: GridColumnGroupHeaderClassNamePropType; } export type GridColumnGroupingModel = GridColumnGroup[]; diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index ed505f140cb5c..9b3c95990204b 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -127,6 +127,8 @@ { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, { "name": "GridColumnGroup", "kind": "Interface" }, + { "name": "GridColumnGroupHeaderClassFn", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderClassNamePropType", "kind": "TypeAlias" }, { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 72c4fa1bb9239..2a67a34c7deb5 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -106,6 +106,8 @@ { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, { "name": "GridColumnGroup", "kind": "Interface" }, + { "name": "GridColumnGroupHeaderClassFn", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderClassNamePropType", "kind": "TypeAlias" }, { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index 3f327535ec6e8..f031481e1258c 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -101,6 +101,8 @@ { "name": "gridColumnDefinitionsSelector", "kind": "Variable" }, { "name": "gridColumnFieldsSelector", "kind": "Variable" }, { "name": "GridColumnGroup", "kind": "Interface" }, + { "name": "GridColumnGroupHeaderClassFn", "kind": "TypeAlias" }, + { "name": "GridColumnGroupHeaderClassNamePropType", "kind": "TypeAlias" }, { "name": "GridColumnGroupHeaderParams", "kind": "Interface" }, { "name": "GridColumnGroupingModel", "kind": "TypeAlias" }, { "name": "gridColumnGroupingSelector", "kind": "Variable" }, From 28642b3e238d29fd2fb6eb63f862a8c740aa8a01 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 10 Aug 2022 10:20:31 +0200 Subject: [PATCH 45/53] fix resize --- packages/grid/x-data-grid-pro/src/utils/domUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grid/x-data-grid-pro/src/utils/domUtils.ts b/packages/grid/x-data-grid-pro/src/utils/domUtils.ts index 1958f84a405ef..7b03c91493eac 100644 --- a/packages/grid/x-data-grid-pro/src/utils/domUtils.ts +++ b/packages/grid/x-data-grid-pro/src/utils/domUtils.ts @@ -11,7 +11,7 @@ export function findHeaderElementFromField(elem: Element, field: string): Elemen } export function findGroupHeaderElementsFromField(elem: Element, field: string): Element[] { - return Array.from(elem.querySelectorAll(`[data-fields~="|-${field}-|"]`) ?? []); + return Array.from(elem.querySelectorAll(`[data-fields*="|-${field}-|"]`) ?? []); } export function findGridCellElementsFromCol(col: HTMLElement, api: GridApiPro) { From af268e7b10b3b2921748f6b3c19ba237fe14ba6a Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Wed, 10 Aug 2022 10:26:13 +0200 Subject: [PATCH 46/53] demo naming fixes --- docs/data/data-grid/column-groups/BasicGroupingDemo.js | 6 +++--- docs/data/data-grid/column-groups/BasicGroupingDemo.tsx | 7 ++++--- docs/data/data-grid/column-groups/BreakingGroupDemo.js | 2 +- docs/data/data-grid/column-groups/BreakingGroupDemo.tsx | 3 ++- docs/data/data-grid/column-groups/CustomizationDemo.js | 4 ++-- docs/data/data-grid/column-groups/CustomizationDemo.tsx | 5 +++-- 6 files changed, 15 insertions(+), 12 deletions(-) diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.js b/docs/data/data-grid/column-groups/BasicGroupingDemo.js index eda34144574af..e9cc4d0f8046f 100644 --- a/docs/data/data-grid/column-groups/BasicGroupingDemo.js +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.js @@ -35,15 +35,15 @@ const rows = [ const columnGroupingModel = [ { - groupId: 'internal data', + groupId: 'Internal', description: '', children: [{ field: 'id' }], }, { - groupId: 'character', + groupId: 'Basic info', children: [ { - groupId: 'naming', + groupId: 'Full name', children: [{ field: 'lastName' }, { field: 'firstName' }], }, { field: 'age' }, diff --git a/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx index 736f474d0e769..39b149a79ca26 100644 --- a/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx +++ b/docs/data/data-grid/column-groups/BasicGroupingDemo.tsx @@ -39,21 +39,22 @@ const rows = [ const columnGroupingModel: GridColumnGroupingModel = [ { - groupId: 'internal data', + groupId: 'Internal', description: '', children: [{ field: 'id' }], }, { - groupId: 'character', + groupId: 'Basic info', children: [ { - groupId: 'naming', + groupId: 'Full name', children: [{ field: 'lastName' }, { field: 'firstName' }], }, { field: 'age' }, ], }, ]; + export default function BasicGroupingDemo() { return (
diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.js b/docs/data/data-grid/column-groups/BreakingGroupDemo.js index fa8dc8ed2f540..462958c566b18 100644 --- a/docs/data/data-grid/column-groups/BreakingGroupDemo.js +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.js @@ -43,7 +43,7 @@ const columnGroupingModel = [ }, { groupId: 'naming', - headerName: 'Names (freeReordering)', + headerName: 'Full name (freeReordering)', freeReordering: true, children: [{ field: 'lastName' }, { field: 'firstName' }], }, diff --git a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx index 77be7f1248726..385111a7e483d 100644 --- a/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx +++ b/docs/data/data-grid/column-groups/BreakingGroupDemo.tsx @@ -47,11 +47,12 @@ const columnGroupingModel: GridColumnGroupingModel = [ }, { groupId: 'naming', - headerName: 'Names (freeReordering)', + headerName: 'Full name (freeReordering)', freeReordering: true, children: [{ field: 'lastName' }, { field: 'firstName' }], }, ]; + export default function BreakingGroupDemo() { return (
diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.js b/docs/data/data-grid/column-groups/CustomizationDemo.js index 29b4b48586297..7402c3c0690e9 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.js +++ b/docs/data/data-grid/column-groups/CustomizationDemo.js @@ -93,7 +93,7 @@ const columnGroupingModel = [ { groupId: 'naming', headerName: 'Names', - headerClassName: 'my-super-theme--character-group', + headerClassName: 'my-super-theme--naming-group', children: [{ field: 'lastName' }, { field: 'firstName' }], }, { field: 'age' }, @@ -107,7 +107,7 @@ export default function CustomizationDemo() { sx={{ height: 400, width: '100%', - '& .my-super-theme--character-group': { + '& .my-super-theme--naming-group': { backgroundColor: 'rgba(255, 7, 0, 0.55)', }, }} diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.tsx b/docs/data/data-grid/column-groups/CustomizationDemo.tsx index f23e4c740c189..5f167502f18c0 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.tsx +++ b/docs/data/data-grid/column-groups/CustomizationDemo.tsx @@ -88,20 +88,21 @@ const columnGroupingModel: GridColumnGroupingModel = [ { groupId: 'naming', headerName: 'Names', - headerClassName: 'my-super-theme--character-group', + headerClassName: 'my-super-theme--naming-group', children: [{ field: 'lastName' }, { field: 'firstName' }], }, { field: 'age' }, ], }, ]; + export default function CustomizationDemo() { return ( Date: Wed, 10 Aug 2022 12:31:06 +0200 Subject: [PATCH 47/53] allows to move column between hidden ones --- .../columnReorder/useGridColumnReorder.tsx | 81 ++++++++++++----- .../tests/columnReorder.DataGridPro.test.tsx | 88 +++++++++++++++++++ 2 files changed, 147 insertions(+), 22 deletions(-) diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx index 597646b925100..0dd27048a8fb1 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -101,8 +101,8 @@ export const useGridColumnReorder = ( const draggingColumnGroupPath = apiRef.current.unstable_getColumnGroupPath(params.field); - const visibleColumnIndex = apiRef.current.getColumnIndex(params.field, true); - const visibleColumns = apiRef.current.getVisibleColumns(); + const columnIndex = originColumnIndex.current as number; + const allColumns = apiRef.current.getAllColumns(); const groupsLookup = apiRef.current.unstable_getAllGroupDetails(); // The limitingGroupId is the id of the group from which the dragged column should not escape @@ -111,14 +111,11 @@ export const useGridColumnReorder = ( draggingColumnGroupPath.forEach((groupId) => { if (!groupsLookup[groupId]?.freeReordering) { // Only consider group that are made of more than one column - if ( - visibleColumnIndex > 0 && - visibleColumns[visibleColumnIndex - 1].groupPath?.includes(groupId) - ) { + if (columnIndex > 0 && allColumns[columnIndex - 1].groupPath?.includes(groupId)) { limitingGroupId = groupId; } else if ( - visibleColumnIndex + 1 < visibleColumns.length && - visibleColumns[visibleColumnIndex + 1].groupPath?.includes(groupId) + columnIndex + 1 < allColumns.length && + allColumns[columnIndex + 1].groupPath?.includes(groupId) ) { limitingGroupId = groupId; } @@ -127,18 +124,18 @@ export const useGridColumnReorder = ( forbiddenIndexes.current = {}; - for (let indexToForbid = 0; indexToForbid < visibleColumns.length; indexToForbid += 1) { - const leftIndex = indexToForbid <= visibleColumnIndex ? indexToForbid - 1 : indexToForbid; - const rightIndex = indexToForbid < visibleColumnIndex ? indexToForbid : indexToForbid + 1; + for (let indexToForbid = 0; indexToForbid < allColumns.length; indexToForbid += 1) { + const leftIndex = indexToForbid <= columnIndex ? indexToForbid - 1 : indexToForbid; + const rightIndex = indexToForbid < columnIndex ? indexToForbid : indexToForbid + 1; if (limitingGroupId !== null) { // verify this indexToForbid will be linked to the limiting group. Otherwise forbid it let allowIndex = false; - if (leftIndex >= 0 && visibleColumns[leftIndex].groupPath?.includes(limitingGroupId)) { + if (leftIndex >= 0 && allColumns[leftIndex].groupPath?.includes(limitingGroupId)) { allowIndex = true; } else if ( - rightIndex < visibleColumns.length && - visibleColumns[rightIndex].groupPath?.includes(limitingGroupId) + rightIndex < allColumns.length && + allColumns[rightIndex].groupPath?.includes(limitingGroupId) ) { allowIndex = true; } @@ -148,9 +145,9 @@ export const useGridColumnReorder = ( } // Verify we are not splitting another group - if (leftIndex >= 0 && rightIndex < visibleColumns.length) { - visibleColumns[rightIndex]?.groupPath?.forEach((groupId) => { - if (visibleColumns[leftIndex].groupPath?.includes(groupId)) { + if (leftIndex >= 0 && rightIndex < allColumns.length) { + allColumns[rightIndex]?.groupPath?.forEach((groupId) => { + if (allColumns[leftIndex].groupPath?.includes(groupId)) { if (!draggingColumnGroupPath.includes(groupId)) { // moving here split the group groupId in two distincts chunks if (!groupsLookup[groupId]?.freeReordering) { @@ -200,6 +197,7 @@ export const useGridColumnReorder = ( const targetCol = apiRef.current.getColumn(params.field); const dragColIndex = apiRef.current.getColumnIndex(dragColField, false); const visibleColumns = apiRef.current.getVisibleColumns(); + const allColumns = apiRef.current.getAllColumns(); const cursorMoveDirectionX = getCursorMoveDirectionX(cursorPosition.current, coordinates); const hasMovedLeft = @@ -209,19 +207,55 @@ export const useGridColumnReorder = ( if (hasMovedLeft || hasMovedRight) { let canBeReordered: boolean; + let indexOffsetInHiddenColumns = 0; if (!targetCol.disableReorder) { canBeReordered = true; } else if (hasMovedLeft) { canBeReordered = - targetColIndex > 0 && !visibleColumns[targetColIndex - 1].disableReorder; + targetColVisibleIndex > 0 && + !visibleColumns[targetColVisibleIndex - 1].disableReorder; } else { canBeReordered = - targetColIndex < visibleColumns.length - 1 && - !visibleColumns[targetColIndex + 1].disableReorder; + targetColVisibleIndex < visibleColumns.length - 1 && + !visibleColumns[targetColVisibleIndex + 1].disableReorder; } if (forbiddenIndexes.current[targetColIndex]) { - canBeReordered = false; + let nextVisibleColumnField: string | null; + let indexWithOffset = targetColIndex + indexOffsetInHiddenColumns; + if (hasMovedLeft) { + nextVisibleColumnField = + targetColVisibleIndex > 0 ? visibleColumns[targetColVisibleIndex - 1].field : null; + while ( + indexWithOffset > 0 && + allColumns[indexWithOffset].field !== nextVisibleColumnField && + forbiddenIndexes.current[indexWithOffset] + ) { + indexOffsetInHiddenColumns -= 1; + indexWithOffset = targetColIndex + indexOffsetInHiddenColumns; + } + } else { + nextVisibleColumnField = + targetColVisibleIndex + 1 < visibleColumns.length + ? visibleColumns[targetColVisibleIndex + 1].field + : null; + while ( + indexWithOffset < allColumns.length - 1 && + allColumns[indexWithOffset].field !== nextVisibleColumnField && + forbiddenIndexes.current[indexWithOffset] + ) { + indexOffsetInHiddenColumns += 1; + indexWithOffset = targetColIndex + indexOffsetInHiddenColumns; + } + } + + if ( + forbiddenIndexes.current[indexWithOffset] || + allColumns[indexWithOffset].field === nextVisibleColumnField + ) { + // If we ended up on a visible column, or a forbidden one, we can not do the reorder + canBeReordered = false; + } } const canBeReorderedProcessed = apiRef.current.unstable_applyPipeProcessors( @@ -231,7 +265,10 @@ export const useGridColumnReorder = ( ); if (canBeReorderedProcessed) { - apiRef.current.setColumnIndex(dragColField, targetColIndex); + apiRef.current.setColumnIndex( + dragColField, + targetColIndex + indexOffsetInHiddenColumns, + ); } } diff --git a/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx b/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx index 208bf3585f24a..2559c3d944db3 100644 --- a/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx +++ b/packages/grid/x-data-grid-pro/src/tests/columnReorder.DataGridPro.test.tsx @@ -465,6 +465,94 @@ describe(' - Columns reorder', () => { expect(getColumnHeadersTextContent()).to.deep.equal(['col12', '', 'col1', 'col2', 'col3']); }); + describe('column - hidden', () => { + it('should use the correct start and end index', () => { + const rows = [{ id: 0 }]; + const columns = [ + { field: 'col1' }, + { field: 'col2' }, + { field: 'col3' }, + { field: 'col4' }, + ]; + + const columnGroupingModel = [ + { groupId: 'col23', children: [{ field: 'col2' }, { field: 'col3' }] }, + ]; + + const Test = () => { + return ( +
+ +
+ ); + }; + + render(); + expect(getColumnHeadersTextContent()).to.deep.equal(['col23', '', 'col2', 'col3', 'col4']); + const dragCol = getColumnHeaderCell(0, 1).firstChild!; + const col3 = getColumnHeaderCell(1, 1).firstChild!; + const col4 = getColumnHeaderCell(2, 1).firstChild!; + + // Do not allow to move col2 after col4 + fireEvent.dragStart(dragCol); + fireEvent.dragEnter(col3); + const dragOverEvent1 = createDragOverEvent(col3); + fireEvent(col3, dragOverEvent1); + expect(getColumnHeadersTextContent()).to.deep.equal(['col23', '', 'col3', 'col2', 'col4']); + + // Allow to move col2 after col3 + fireEvent.dragEnter(col4); + const dragOverEvent2 = createDragOverEvent(col4); + fireEvent(col4, dragOverEvent2); + expect(getColumnHeadersTextContent()).to.deep.equal(['col23', '', 'col3', 'col2', 'col4']); + }); + + it('should consider moving the column between hidden columns if it respect group constraint and visible behavior', () => { + const rows = [{ id: 0 }]; + const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; + + const columnGroupingModel = [ + { groupId: 'col23', children: [{ field: 'col2' }, { field: 'col3' }] }, + ]; + + const Test = (props: any) => { + return ( +
+ +
+ ); + }; + + const { setProps } = render(); + expect(getColumnHeadersTextContent()).to.deep.equal(['', 'col23', 'col1', 'col2']); + const dragCol = getColumnHeaderCell(0, 1).firstChild!; + const targetCol = getColumnHeaderCell(1, 1).firstChild!; + + // Move col 1 after col 3 to respect column grouping consistency even if col3 is hidden + fireEvent.dragStart(dragCol); + fireEvent.dragEnter(targetCol); + const dragOverEvent = createDragOverEvent(targetCol); + fireEvent(targetCol, dragOverEvent); + expect(getColumnHeadersTextContent()).to.deep.equal(['col23', '', 'col2', 'col1']); + + setProps({ columnVisibilityModel: {} }); + expect(getColumnHeadersTextContent()).to.deep.equal(['col23', '', 'col2', 'col3', 'col1']); + }); + }); + it('should not allow to drag column inside a group', () => { const rows = [{ id: 0 }]; const columns = [{ field: 'col1' }, { field: 'col2' }, { field: 'col3' }]; From 2bb956958650719460eec93ee9eecfed1243c82f Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Fri, 12 Aug 2022 09:22:11 +0200 Subject: [PATCH 48/53] use computed width --- .../columnHeaders/useGridColumnHeaders.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index fb0c6c30c9526..cbd3c6f0d7313 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -383,18 +383,18 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ) { const column = visibleColumns[columnIndex]; - leftOverflow += column.width ?? 0; + leftOverflow += column.computedWidth ?? 0; if (initialHeader.length === 0) { initialHeader.push({ - width: column.width ?? 0, + width: column.computedWidth ?? 0, fields: [column.field], groupId: firstColumnToRenderGroup, groupParents: firstColumnToRenderGroupParents, colIndex: columnIndex, }); } else { - initialHeader[0].width += column.width ?? 0; + initialHeader[0].width += column.computedWidth ?? 0; initialHeader[0].fields.push(column.field); initialHeader[0].colIndex = columnIndex; } @@ -412,7 +412,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ...aggregated.slice(0, aggregated.length - 1), { ...lastItem, - width: lastItem.width + (column.width ?? 0), + width: lastItem.width + (column.computedWidth ?? 0), fields: [...lastItem.fields, column.field], }, ]; @@ -423,7 +423,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { { groupId: column.groupPath[depth], groupParents: getParents(column.groupPath, depth), - width: column.width ?? 0, + width: column.computedWidth ?? 0, fields: [column.field], colIndex: firstColumnToRender + i, }, @@ -441,7 +441,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ...aggregated.slice(0, aggregated.length - 1), { ...lastItem, - width: lastItem.width + (column.width ?? 0), + width: lastItem.width + (column.computedWidth ?? 0), fields: [...lastItem.fields, column.field], }, ]; @@ -452,7 +452,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { { groupId: null, groupParents: getParents(column.groupPath, depth), - width: column.width ?? 0, + width: column.computedWidth ?? 0, fields: [column.field], colIndex: firstColumnToRender + i, }, @@ -470,7 +470,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { ) { const column = visibleColumns[columnIndex]; - depthInfo[depthInfo.length - 1].width += column.width ?? 0; + depthInfo[depthInfo.length - 1].width += column.computedWidth ?? 0; depthInfo[depthInfo.length - 1].fields.push(column.field); columnIndex += 1; } From 2c5ff80243e5ae51833d32806d1eaddff538f5d8 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Fri, 12 Aug 2022 09:36:26 +0200 Subject: [PATCH 49/53] Andrew feedbacks --- docs/data/data-grid/column-groups/column-groups.md | 2 +- .../features/columnReorder/useGridColumnReorder.tsx | 2 +- .../columnHeaders/GridColumnGroupHeader.tsx | 4 ++-- .../features/columnGrouping/useGridColumnGrouping.ts | 2 +- .../features/columnHeaders/useGridColumnHeaders.tsx | 11 +---------- .../src/hooks/features/density/useGridDensity.tsx | 6 ++++-- .../grid/x-data-grid/src/models/colDef/gridColDef.ts | 4 ++-- 7 files changed, 12 insertions(+), 19 deletions(-) diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 2ba7b45a21d78..3e68d68d354ae 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -1,5 +1,5 @@ --- -title: Data grid - Column groups +title: Data Grid - Column groups --- # Data grid - Column groups diff --git a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx index 0dd27048a8fb1..baf3674e8df61 100644 --- a/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx +++ b/packages/grid/x-data-grid-pro/src/hooks/features/columnReorder/useGridColumnReorder.tsx @@ -101,7 +101,7 @@ export const useGridColumnReorder = ( const draggingColumnGroupPath = apiRef.current.unstable_getColumnGroupPath(params.field); - const columnIndex = originColumnIndex.current as number; + const columnIndex = originColumnIndex.current; const allColumns = apiRef.current.getAllColumns(); const groupsLookup = apiRef.current.unstable_getAllGroupDetails(); diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx index ed2d7cf25d8aa..59426d4342e12 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx @@ -9,7 +9,7 @@ import { gridColumnGroupsLookupSelector } from '../../hooks/features/columnGroup import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { useGridSelector } from '../../hooks/utils/useGridSelector'; import { GridGenericColumnHeaderItem } from './GridGenericColumnHeaderItem'; -import { GridColumnGroup, GridColumnGroupHeaderParams } from '../../models/gridColumnGrouping'; +import { GridColumnGroup } from '../../models/gridColumnGrouping'; interface GridColumnGroupHeaderProps { groupId: string | null; @@ -95,7 +95,7 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { isLastColumn, }; if (groupId && render) { - headerComponent = render(renderParams as GridColumnGroupHeaderParams); + headerComponent = render(renderParams); } const removeLastBorderRight = isLastColumn && hasScrollX && !hasScrollY; diff --git a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts index eeb10241e748c..5b2e107a8309c 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts +++ b/packages/grid/x-data-grid/src/hooks/features/columnGrouping/useGridColumnGrouping.ts @@ -152,7 +152,7 @@ export const useGridColumnGrouping = ( /** * EFFECTS */ - // The effect do not track any value defined synchronously during the 1st render by hooks called after `useGridColumns` + // The effect does not track any value defined synchronously during the 1st render by hooks called after `useGridColumns` // As a consequence, the state generated by the 1st run of this useEffect will always be equal to the initialization one const isFirstRender = React.useRef(true); React.useEffect(() => { diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index cbd3c6f0d7313..05f6233d7ff82 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -27,7 +27,6 @@ import { useGridRootProps } from '../../utils/useGridRootProps'; import { GridRenderContext } from '../../../models/params/gridScrollParams'; import { useGridApiEventHandler } from '../../utils/useGridApiEventHandler'; import { GridEventListener } from '../../../models/events'; -import { GridStateColDef } from '../../../models/colDef'; import { GridColumnHeaderItem } from '../../../components/columnHeaders/GridColumnHeaderItem'; import { getFirstColumnIndexToRender } from '../columns/gridColumnsUtils'; import { useGridVisibleRows } from '../../utils/useGridVisibleRows'; @@ -230,15 +229,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { useGridApiEventHandler(apiRef, 'rowsScroll', handleScroll); // Helper for computation common between getColumnHeaders and getColumnGroupHeaders - const getColumnsToRender = ( - params?: GetHeadersParams, - ): null | { - renderedColumns: GridStateColDef[]; - firstColumnToRender: number; - lastColumnToRender: number; - minFirstColumn: number; - maxLastColumn: number; - } => { + const getColumnsToRender = (params?: GetHeadersParams) => { const { renderContext: nextRenderContext = renderContext, minFirstColumn = minColumnIndex, diff --git a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx index 8c871cef91d6e..1eb51433e6a0e 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx @@ -12,6 +12,7 @@ import { GridStateInitializer } from '../../utils/useGridInitializeState'; import { useGridSelector } from '../../utils/useGridSelector'; import { gridVisibleColumnDefinitionsSelector } from '../columns'; import { unwrapGroupingColumnModel } from '../columnGrouping/useGridColumnGrouping'; +import { GridStateCommunity } from '../../../models/gridStateCommunity'; export const COMPACT_DENSITY_FACTOR = 0.7; export const COMFORTABLE_DENSITY_FACTOR = 1.3; @@ -71,8 +72,9 @@ export const densityStateInitializer: GridStateInitializer< } else { const unwrappedGroupingColumnModel = unwrapGroupingColumnModel(props.columnGroupingModel); - const visibleColumns = state.columns!.all!.filter( - (field) => state.columns!.columnVisibilityModel![field!] !== false, + const columnsState = state.columns as GridStateCommunity['columns']; + const visibleColumns = columnsState.all.filter( + (field) => columnsState.columnVisibilityModel[field] !== false, ); if (visibleColumns.length === 0) { diff --git a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts index 2a44905af03e2..d46d1f3798757 100644 --- a/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts +++ b/packages/grid/x-data-grid/src/models/colDef/gridColDef.ts @@ -20,7 +20,7 @@ import { GridActionsCellItemProps } from '../../components/cell/GridActionsCellI import { GridEditCellProps } from '../gridEditRowModel'; import type { GridValidRowModel } from '../gridRows'; import { GridApiCommunity } from '../api/gridApiCommunity'; - +import type { GridColumnGroup } from '../gridColumnGrouping'; /** * Alignment used in position elements in Cells. */ @@ -290,7 +290,7 @@ export type GridStateColDef = * If not defined, the column is in no group (equivalent to a path equal to `[]`). * This parameter is computed from the `columnGroupingModel` prop. */ - groupPath?: string[]; + groupPath?: GridColumnGroup['groupId'][]; }; /** From 552f226b8bf3fb043ba27d144a295182d2cd6d4f Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 16 Aug 2022 10:19:14 +0200 Subject: [PATCH 50/53] feedbacks --- docs/data/data-grid/column-groups/CustomizationDemo.js | 2 +- docs/data/data-grid/column-groups/CustomizationDemo.tsx | 2 +- docs/data/data-grid/column-groups/column-groups.md | 5 +++-- .../src/components/columnHeaders/GridColumnGroupHeader.tsx | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.js b/docs/data/data-grid/column-groups/CustomizationDemo.js index 7402c3c0690e9..e0373d6f1662b 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.js +++ b/docs/data/data-grid/column-groups/CustomizationDemo.js @@ -85,7 +85,7 @@ const columnGroupingModel = [ { groupId: 'character', description: 'Information about the character', - headerName: 'Character', + headerName: 'Basic info', renderHeaderGroup: (params) => ( } /> ), diff --git a/docs/data/data-grid/column-groups/CustomizationDemo.tsx b/docs/data/data-grid/column-groups/CustomizationDemo.tsx index 5f167502f18c0..4918e926884c9 100644 --- a/docs/data/data-grid/column-groups/CustomizationDemo.tsx +++ b/docs/data/data-grid/column-groups/CustomizationDemo.tsx @@ -80,7 +80,7 @@ const columnGroupingModel: GridColumnGroupingModel = [ { groupId: 'character', description: 'Information about the character', - headerName: 'Character', + headerName: 'Basic info', renderHeaderGroup: (params) => ( } /> ), diff --git a/docs/data/data-grid/column-groups/column-groups.md b/docs/data/data-grid/column-groups/column-groups.md index 3e68d68d354ae..1221d196460bd 100644 --- a/docs/data/data-grid/column-groups/column-groups.md +++ b/docs/data/data-grid/column-groups/column-groups.md @@ -6,7 +6,7 @@ title: Data Grid - Column groups

Group your columns.

-Grouping columns allows you to have multiple levels of columns in your header and to toggle column groups to show and hide additional columns. +Grouping columns allows you to have a multi-level hierarchy of columns in your header. :::warning This feature is experimental, it needs to be explicitly activated using the `columnGrouping` experimental feature flag. @@ -65,6 +65,7 @@ In addition to the required `groupId` and `children`, you can use the following - `headerName`: the string displayed as the column's name (instead of `groupId`). - `description`: a text for the tooltip. +- `headerClassName`: a CSS class for styling customization. - `renderHeaderGroup`: a function returning custom React component. {{"demo": "CustomizationDemo.js", "bg": "inline"}} @@ -74,7 +75,7 @@ In addition to the required `groupId` and `children`, you can use the following By default, the columns that are part of a group cannot be dragged to outside their group. You can customize this behavior on specific groups by setting `freeReordering: true` in a column group object. -In the example below, the `Names` column group can be divided, but not other column groups +In the example below, the `Full name` column group can be divided, but not other column groups. {{"demo": "BreakingGroupDemo.js", "disableAd": true, "bg": "inline"}} diff --git a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx index 59426d4342e12..2e9f74064462c 100644 --- a/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx +++ b/packages/grid/x-data-grid/src/components/columnHeaders/GridColumnGroupHeader.tsx @@ -135,7 +135,7 @@ function GridColumnGroupHeader(props: GridColumnGroupHeaderProps) { isResizing={false} sortDirection={null} hasFocus={false} - tabIndex={0} + tabIndex={-1} isDraggable={false} headerComponent={headerComponent} headerClassName={headerClassName} From 7eaccb30eb81c5697ff7793a7f598fc07121458c Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 16 Aug 2022 10:43:37 +0200 Subject: [PATCH 51/53] proptypes --- packages/grid/x-data-grid/src/components/GridAutoSizer.tsx | 6 ------ .../grid/x-data-grid/src/components/panel/GridPanel.tsx | 1 - .../src/components/panel/filterPanel/GridFilterForm.tsx | 4 ---- .../src/components/panel/filterPanel/GridFilterPanel.tsx | 4 ---- 4 files changed, 15 deletions(-) diff --git a/packages/grid/x-data-grid/src/components/GridAutoSizer.tsx b/packages/grid/x-data-grid/src/components/GridAutoSizer.tsx index 1955042a67f6d..690eac36fce65 100644 --- a/packages/grid/x-data-grid/src/components/GridAutoSizer.tsx +++ b/packages/grid/x-data-grid/src/components/GridAutoSizer.tsx @@ -167,12 +167,6 @@ GridAutoSizer.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- - /** - * Function responsible for rendering children. - * @param {AutoSizerSize} size The grid's size. - * @returns {React.ReactNode} The children to render. - */ - children: PropTypes.func.isRequired, /** * Default height to use for initial render; useful for SSR. * @default null diff --git a/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx b/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx index 7c3f89dd9c0c8..07cf2a65bd779 100644 --- a/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx +++ b/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx @@ -120,7 +120,6 @@ GridPanel.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- - children: PropTypes.node, /** * Override or extend the styles applied to the component. */ diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx index 4306976d58531..9224ad96fdc2b 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx @@ -505,10 +505,6 @@ GridFilterForm.propTypes = { * @param {GridLinkOperator} operator The new logic operator. */ applyMultiFilterOperatorChanges: PropTypes.func.isRequired, - /** - * @ignore - do not document. - */ - children: PropTypes.node, /** * Props passed to the column input component. * @default {} diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterPanel.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterPanel.tsx index a309f67429408..3cfe4c0c681f6 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterPanel.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterPanel.tsx @@ -173,10 +173,6 @@ GridFilterPanel.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- - /** - * @ignore - do not document. - */ - children: PropTypes.node, /** * Changes how the options in the columns selector should be ordered. * If not specified, the order is derived from the `columns` prop. From 1f71d4279a88951fb3c9bddfcbac9a24e5c0f5b7 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 16 Aug 2022 11:27:20 +0200 Subject: [PATCH 52/53] proptypes with up to date packages --- packages/grid/x-data-grid/src/components/GridAutoSizer.tsx | 6 ++++++ .../grid/x-data-grid/src/components/panel/GridPanel.tsx | 1 + .../src/components/panel/filterPanel/GridFilterForm.tsx | 4 ++++ .../src/components/panel/filterPanel/GridFilterPanel.tsx | 4 ++++ 4 files changed, 15 insertions(+) diff --git a/packages/grid/x-data-grid/src/components/GridAutoSizer.tsx b/packages/grid/x-data-grid/src/components/GridAutoSizer.tsx index 690eac36fce65..1955042a67f6d 100644 --- a/packages/grid/x-data-grid/src/components/GridAutoSizer.tsx +++ b/packages/grid/x-data-grid/src/components/GridAutoSizer.tsx @@ -167,6 +167,12 @@ GridAutoSizer.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * Function responsible for rendering children. + * @param {AutoSizerSize} size The grid's size. + * @returns {React.ReactNode} The children to render. + */ + children: PropTypes.func.isRequired, /** * Default height to use for initial render; useful for SSR. * @default null diff --git a/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx b/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx index 07cf2a65bd779..7c3f89dd9c0c8 100644 --- a/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx +++ b/packages/grid/x-data-grid/src/components/panel/GridPanel.tsx @@ -120,6 +120,7 @@ GridPanel.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + children: PropTypes.node, /** * Override or extend the styles applied to the component. */ diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx index 9224ad96fdc2b..4306976d58531 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterForm.tsx @@ -505,6 +505,10 @@ GridFilterForm.propTypes = { * @param {GridLinkOperator} operator The new logic operator. */ applyMultiFilterOperatorChanges: PropTypes.func.isRequired, + /** + * @ignore - do not document. + */ + children: PropTypes.node, /** * Props passed to the column input component. * @default {} diff --git a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterPanel.tsx b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterPanel.tsx index 3cfe4c0c681f6..a309f67429408 100644 --- a/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterPanel.tsx +++ b/packages/grid/x-data-grid/src/components/panel/filterPanel/GridFilterPanel.tsx @@ -173,6 +173,10 @@ GridFilterPanel.propTypes = { // | These PropTypes are generated from the TypeScript type definitions | // | To update them edit the TypeScript types and run "yarn proptypes" | // ---------------------------------------------------------------------- + /** + * @ignore - do not document. + */ + children: PropTypes.node, /** * Changes how the options in the columns selector should be ordered. * If not specified, the order is derived from the `columns` prop. From e6e383e49c94426b872ec9a987ebcde79e2125b2 Mon Sep 17 00:00:00 2001 From: Alexandre Fauquette Date: Tue, 23 Aug 2022 11:35:56 +0200 Subject: [PATCH 53/53] use same heigh for column header and group header --- .../x/api/data-grid/data-grid-premium.json | 1 - docs/pages/x/api/data-grid/data-grid-pro.json | 1 - docs/pages/x/api/data-grid/data-grid.json | 1 - docs/pages/x/api/data-grid/grid-api.md | 2 +- docs/pages/x/api/data-grid/selectors.json | 6 --- .../data-grid/data-grid-premium-pt.json | 1 - .../data-grid/data-grid-premium-zh.json | 1 - .../api-docs/data-grid/data-grid-premium.json | 1 - .../api-docs/data-grid/data-grid-pro-pt.json | 1 - .../api-docs/data-grid/data-grid-pro-zh.json | 1 - .../api-docs/data-grid/data-grid-pro.json | 1 - .../api-docs/data-grid/data-grid-pt.json | 1 - .../api-docs/data-grid/data-grid-zh.json | 1 - .../api-docs/data-grid/data-grid.json | 1 - .../src/DataGridPremium/DataGridPremium.tsx | 6 --- .../src/DataGridPro/DataGridPro.tsx | 6 --- .../x-data-grid/src/DataGrid/DataGrid.tsx | 6 --- .../src/DataGrid/useDataGridProps.ts | 1 - .../components/containers/GridRootStyles.ts | 5 ++- .../columnHeaders/useGridColumnHeaders.tsx | 9 +--- .../hooks/features/density/densitySelector.ts | 8 +--- .../hooks/features/density/densityState.ts | 1 - .../hooks/features/density/useGridDensity.tsx | 45 +++---------------- .../src/models/api/gridDensityApi.ts | 2 - .../src/models/props/DataGridProps.ts | 6 --- scripts/x-data-grid-premium.exports.json | 1 - scripts/x-data-grid-pro.exports.json | 1 - scripts/x-data-grid.exports.json | 1 - 28 files changed, 14 insertions(+), 104 deletions(-) diff --git a/docs/pages/x/api/data-grid/data-grid-premium.json b/docs/pages/x/api/data-grid/data-grid-premium.json index c071339d6c32f..52d19949beedd 100644 --- a/docs/pages/x/api/data-grid/data-grid-premium.json +++ b/docs/pages/x/api/data-grid/data-grid-premium.json @@ -97,7 +97,6 @@ "getRowSpacing": { "type": { "name": "func" } }, "getTreeDataPath": { "type": { "name": "func" } }, "groupingColDef": { "type": { "name": "union", "description": "func
| object" } }, - "headerGroupingRowHeight": { "type": { "name": "number" }, "default": "32" }, "headerHeight": { "type": { "name": "number" }, "default": "56" }, "hideFooter": { "type": { "name": "bool" } }, "hideFooterPagination": { "type": { "name": "bool" } }, diff --git a/docs/pages/x/api/data-grid/data-grid-pro.json b/docs/pages/x/api/data-grid/data-grid-pro.json index f20d96080c271..38615bff95fdb 100644 --- a/docs/pages/x/api/data-grid/data-grid-pro.json +++ b/docs/pages/x/api/data-grid/data-grid-pro.json @@ -82,7 +82,6 @@ "getRowSpacing": { "type": { "name": "func" } }, "getTreeDataPath": { "type": { "name": "func" } }, "groupingColDef": { "type": { "name": "union", "description": "func
| object" } }, - "headerGroupingRowHeight": { "type": { "name": "number" }, "default": "32" }, "headerHeight": { "type": { "name": "number" }, "default": "56" }, "hideFooter": { "type": { "name": "bool" } }, "hideFooterPagination": { "type": { "name": "bool" } }, diff --git a/docs/pages/x/api/data-grid/data-grid.json b/docs/pages/x/api/data-grid/data-grid.json index 4476aa4670172..6de4912093c29 100644 --- a/docs/pages/x/api/data-grid/data-grid.json +++ b/docs/pages/x/api/data-grid/data-grid.json @@ -59,7 +59,6 @@ "getRowHeight": { "type": { "name": "func" } }, "getRowId": { "type": { "name": "func" } }, "getRowSpacing": { "type": { "name": "func" } }, - "headerGroupingRowHeight": { "type": { "name": "number" }, "default": "32" }, "headerHeight": { "type": { "name": "number" }, "default": "56" }, "hideFooter": { "type": { "name": "bool" } }, "hideFooterPagination": { "type": { "name": "bool" } }, diff --git a/docs/pages/x/api/data-grid/grid-api.md b/docs/pages/x/api/data-grid/grid-api.md index 18b4079256e48..c63564268ae43 100644 --- a/docs/pages/x/api/data-grid/grid-api.md +++ b/docs/pages/x/api/data-grid/grid-api.md @@ -86,7 +86,7 @@ import { GridApi } from '@mui/x-data-grid-pro'; | setColumnVisibility | (field: string, isVisible: boolean) => void | Changes the visibility of the column referred by `field`. | | setColumnVisibilityModel | (model: GridColumnVisibilityModel) => void | Sets the column visibility model to the one given by `model`. | | setColumnWidth | (field: string, width: number) => void | Updates the width of a column. | -| setDensity | (density: GridDensity, headerHeight?: number, rowHeight?: number, maxDepth?: number, headerGroupingRowHeight?: number) => void | Sets the density of the grid. | +| setDensity | (density: GridDensity, headerHeight?: number, rowHeight?: number, maxDepth?: number) => void | Sets the density of the grid. | | setEditCellValue | (params: GridEditCellValueParams, event?: MuiBaseEvent) => Promise<boolean> \| void | Sets the value of the edit cell.
Commonly used inside the edit cell component. | | setEditRowsModel | (model: GridEditRowsModel) => void | Set the edit rows model of the grid. | | setExpandedDetailPanels [](/x/introduction/licensing/#pro-plan) | (ids: GridRowId[]) => void | Changes which rows to expand the detail panel. | diff --git a/docs/pages/x/api/data-grid/selectors.json b/docs/pages/x/api/data-grid/selectors.json index b7ef834cf64c4..17845cffa07ca 100644 --- a/docs/pages/x/api/data-grid/selectors.json +++ b/docs/pages/x/api/data-grid/selectors.json @@ -95,12 +95,6 @@ "description": "", "supportsApiRef": true }, - { - "name": "gridDensityHeaderGroupingRowHeightSelector", - "returnType": "number", - "description": "", - "supportsApiRef": true - }, { "name": "gridDensityHeaderHeightSelector", "returnType": "number", diff --git a/docs/translations/api-docs/data-grid/data-grid-premium-pt.json b/docs/translations/api-docs/data-grid/data-grid-premium-pt.json index d5c8ec6a40a7f..2086662587c46 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium-pt.json @@ -58,7 +58,6 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/docs/translations/api-docs/data-grid/data-grid-premium-zh.json b/docs/translations/api-docs/data-grid/data-grid-premium-zh.json index d5c8ec6a40a7f..2086662587c46 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium-zh.json @@ -58,7 +58,6 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/docs/translations/api-docs/data-grid/data-grid-premium.json b/docs/translations/api-docs/data-grid/data-grid-premium.json index d5c8ec6a40a7f..2086662587c46 100644 --- a/docs/translations/api-docs/data-grid/data-grid-premium.json +++ b/docs/translations/api-docs/data-grid/data-grid-premium.json @@ -58,7 +58,6 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json index 86a04b39abff6..6e06b5e2898d5 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-pt.json @@ -52,7 +52,6 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json index 86a04b39abff6..6e06b5e2898d5 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro-zh.json @@ -52,7 +52,6 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/docs/translations/api-docs/data-grid/data-grid-pro.json b/docs/translations/api-docs/data-grid/data-grid-pro.json index 86a04b39abff6..6e06b5e2898d5 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pro.json +++ b/docs/translations/api-docs/data-grid/data-grid-pro.json @@ -52,7 +52,6 @@ "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", "getTreeDataPath": "Determines the path of a row in the tree data. For instance, a row with the path ["A", "B"] is the child of the row with the path ["A"]. Note that all paths must contain at least one element.

Signature:
function(row: R) => Array<string>
row: The row from which we want the path.
returns (Array): The path to the row.", "groupingColDef": "The grouping column used by the tree data.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/docs/translations/api-docs/data-grid/data-grid-pt.json b/docs/translations/api-docs/data-grid/data-grid-pt.json index b598b17af3982..20c31c00daabc 100644 --- a/docs/translations/api-docs/data-grid/data-grid-pt.json +++ b/docs/translations/api-docs/data-grid/data-grid-pt.json @@ -37,7 +37,6 @@ "getRowHeight": "Function that sets the row height per row.

Signature:
function(params: GridRowHeightParams) => GridRowHeightReturnValue
params: With all properties from GridRowHeightParams.
returns (GridRowHeightReturnValue): The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content.", "getRowId": "Return the id of a given GridRowModel.", "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/docs/translations/api-docs/data-grid/data-grid-zh.json b/docs/translations/api-docs/data-grid/data-grid-zh.json index b598b17af3982..20c31c00daabc 100644 --- a/docs/translations/api-docs/data-grid/data-grid-zh.json +++ b/docs/translations/api-docs/data-grid/data-grid-zh.json @@ -37,7 +37,6 @@ "getRowHeight": "Function that sets the row height per row.

Signature:
function(params: GridRowHeightParams) => GridRowHeightReturnValue
params: With all properties from GridRowHeightParams.
returns (GridRowHeightReturnValue): The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content.", "getRowId": "Return the id of a given GridRowModel.", "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/docs/translations/api-docs/data-grid/data-grid.json b/docs/translations/api-docs/data-grid/data-grid.json index b598b17af3982..20c31c00daabc 100644 --- a/docs/translations/api-docs/data-grid/data-grid.json +++ b/docs/translations/api-docs/data-grid/data-grid.json @@ -37,7 +37,6 @@ "getRowHeight": "Function that sets the row height per row.

Signature:
function(params: GridRowHeightParams) => GridRowHeightReturnValue
params: With all properties from GridRowHeightParams.
returns (GridRowHeightReturnValue): The row height value. If null or undefined then the default row height is applied. If "auto" then the row height is calculated based on the content.", "getRowId": "Return the id of a given GridRowModel.", "getRowSpacing": "Function that allows to specify the spacing between rows.

Signature:
function(params: GridRowSpacingParams) => GridRowSpacing
params: With all properties from GridRowSpacingParams.
returns (GridRowSpacing): The row spacing values.", - "headerGroupingRowHeight": "The height of a row of grouping column headers. TODO: choose correctly this value", "headerHeight": "Set the height in pixel of the column headers in the grid.", "hideFooter": "If true, the footer component is hidden.", "hideFooterPagination": "If true, the pagination component in the footer is hidden.", diff --git a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx index 562b2f10a6722..bbdfc8f442b2f 100644 --- a/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx +++ b/packages/grid/x-data-grid-premium/src/DataGridPremium/DataGridPremium.tsx @@ -391,12 +391,6 @@ DataGridPremiumRaw.propTypes = { * The grouping column used by the tree data. */ groupingColDef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - /** - * The height of a row of grouping column headers. - * TODO: choose correctly this value - * @default 32 - */ - headerGroupingRowHeight: PropTypes.number, /** * Set the height in pixel of the column headers in the grid. * @default 56 diff --git a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx index 271cc9d3a93f0..b36812c31aa73 100644 --- a/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx +++ b/packages/grid/x-data-grid-pro/src/DataGridPro/DataGridPro.tsx @@ -354,12 +354,6 @@ DataGridProRaw.propTypes = { * The grouping column used by the tree data. */ groupingColDef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]), - /** - * The height of a row of grouping column headers. - * TODO: choose correctly this value - * @default 32 - */ - headerGroupingRowHeight: PropTypes.number, /** * Set the height in pixel of the column headers in the grid. * @default 56 diff --git a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx index d9a71542b90dd..7058730b11b52 100644 --- a/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx +++ b/packages/grid/x-data-grid/src/DataGrid/DataGrid.tsx @@ -261,12 +261,6 @@ DataGridRaw.propTypes = { * @returns {GridRowSpacing} The row spacing values. */ getRowSpacing: PropTypes.func, - /** - * The height of a row of grouping column headers. - * TODO: choose correctly this value - * @default 32 - */ - headerGroupingRowHeight: PropTypes.number, /** * Set the height in pixel of the column headers in the grid. * @default 56 diff --git a/packages/grid/x-data-grid/src/DataGrid/useDataGridProps.ts b/packages/grid/x-data-grid/src/DataGrid/useDataGridProps.ts index b627310e94c18..339e3ffe630c5 100644 --- a/packages/grid/x-data-grid/src/DataGrid/useDataGridProps.ts +++ b/packages/grid/x-data-grid/src/DataGrid/useDataGridProps.ts @@ -77,7 +77,6 @@ export const DATA_GRID_PROPS_DEFAULT_VALUES: DataGridPropsWithDefaultValues = { disableColumnReorder: false, disableColumnResize: false, keepNonExistentRowsSelected: false, - headerGroupingRowHeight: 40, }; export const useDataGridProps = (inProps: DataGridProps) => { diff --git a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts index f22101b72fede..f1f9bd738b751 100644 --- a/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts +++ b/packages/grid/x-data-grid/src/components/containers/GridRootStyles.ts @@ -145,7 +145,7 @@ export const GridRootStyles = styled('div', { minWidth: 0, flex: 1, whiteSpace: 'nowrap', - overflowX: 'hidden', + overflow: 'hidden', }, [`& .${gridClasses.columnHeaderTitleContainerContent}`]: { overflow: 'hidden', @@ -154,6 +154,7 @@ export const GridRootStyles = styled('div', { }, [`& .${gridClasses['columnHeader--filledGroup']} .${gridClasses.columnHeaderTitleContainer}`]: { borderBottom: `solid ${borderColor} 1px`, + boxSizing: 'border-box', }, [`& .${gridClasses['columnHeader--filledGroup']}.${gridClasses['columnHeader--showColumnBorder']} .${gridClasses.columnHeaderTitleContainer}`]: { @@ -162,6 +163,7 @@ export const GridRootStyles = styled('div', { [`& .${gridClasses['columnHeader--filledGroup']}.${gridClasses['columnHeader--showColumnBorder']}`]: { borderBottom: `solid ${borderColor} 1px`, + boxSizing: 'border-box', }, [`& .${gridClasses.sortIcon}, & .${gridClasses.filterIcon}`]: { fontSize: 'inherit', @@ -351,6 +353,7 @@ export const GridRootStyles = styled('div', { [`& .${gridClasses.columnHeaderDraggableContainer}`]: { display: 'flex', width: '100%', + height: '100%', }, [`& .${gridClasses.rowReorderCellPlaceholder}`]: { display: 'none', diff --git a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx index 05f6233d7ff82..e08ce80f4c087 100644 --- a/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/columnHeaders/useGridColumnHeaders.tsx @@ -17,7 +17,6 @@ import { import { gridDensityHeaderHeightSelector, gridDensityHeaderGroupingMaxDepthSelector, - gridDensityHeaderGroupingRowHeightSelector, gridDensityTotalHeaderHeightSelector, } from '../density/densitySelector'; import { gridFilterActiveItemsLookupSelector } from '../filter/gridFilterSelector'; @@ -84,10 +83,6 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { const columnHeaderFocus = useGridSelector(apiRef, gridFocusColumnHeaderSelector); const headerHeight = useGridSelector(apiRef, gridDensityHeaderHeightSelector); const headerGroupingMaxDepth = useGridSelector(apiRef, gridDensityHeaderGroupingMaxDepthSelector); - const headerGroupingRowHeight = useGridSelector( - apiRef, - gridDensityHeaderGroupingRowHeightSelector, - ); const totalHeaderHeight = useGridSelector(apiRef, gridDensityTotalHeaderHeightSelector); const filterColumnLookup = useGridSelector(apiRef, gridFilterActiveItemsLookupSelector); const sortColumnLookup = useGridSelector(apiRef, gridSortColumnLookupSelector); @@ -473,7 +468,7 @@ export const useGridColumnHeaders = (props: UseGridColumnHeadersProps) => { columns.push( { isLastColumn={colIndex === visibleColumns.length - fields.length} extendRowFullWidth={!rootProps.disableExtendRowFullWidth} maxDepth={headerToRender.length} - height={headerGroupingRowHeight} + height={headerHeight} /> ); })} diff --git a/packages/grid/x-data-grid/src/hooks/features/density/densitySelector.ts b/packages/grid/x-data-grid/src/hooks/features/density/densitySelector.ts index c0fa87124448d..37e089b0aee22 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/densitySelector.ts +++ b/packages/grid/x-data-grid/src/hooks/features/density/densitySelector.ts @@ -23,11 +23,6 @@ export const gridDensityHeaderGroupingMaxDepthSelector = createSelector( (density) => density.headerGroupingMaxDepth, ); -export const gridDensityHeaderGroupingRowHeightSelector = createSelector( - gridDensitySelector, - (density) => density.headerGroupingRowHeight, -); - export const gridDensityFactorSelector = createSelector( gridDensitySelector, (density) => density.factor, @@ -35,6 +30,5 @@ export const gridDensityFactorSelector = createSelector( export const gridDensityTotalHeaderHeightSelector = createSelector( gridDensitySelector, - (density) => - density.headerHeight + density.headerGroupingMaxDepth * density.headerGroupingRowHeight, + (density) => density.headerHeight * (1 + density.headerGroupingMaxDepth), ); diff --git a/packages/grid/x-data-grid/src/hooks/features/density/densityState.ts b/packages/grid/x-data-grid/src/hooks/features/density/densityState.ts index a601b24053e2f..c79f750f471eb 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/densityState.ts +++ b/packages/grid/x-data-grid/src/hooks/features/density/densityState.ts @@ -4,7 +4,6 @@ export interface GridDensityState { value: GridDensity; rowHeight: number; headerHeight: number; - headerGroupingRowHeight: number; headerGroupingMaxDepth: number; factor: number; } diff --git a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx index 1eb51433e6a0e..556d524acfb6c 100644 --- a/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx +++ b/packages/grid/x-data-grid/src/hooks/features/density/useGridDensity.tsx @@ -23,7 +23,6 @@ const getUpdatedDensityState = ( newHeaderHeight: number, newRowHeight: number, newMaxDepth: number, - newHeaderGroupingRowHeight: number, ): GridDensityState => { switch (newDensity) { case GridDensityTypes.Compact: @@ -31,7 +30,6 @@ const getUpdatedDensityState = ( value: newDensity, headerHeight: Math.floor(newHeaderHeight * COMPACT_DENSITY_FACTOR), rowHeight: Math.floor(newRowHeight * COMPACT_DENSITY_FACTOR), - headerGroupingRowHeight: Math.floor(newHeaderGroupingRowHeight * COMPACT_DENSITY_FACTOR), headerGroupingMaxDepth: newMaxDepth, factor: COMPACT_DENSITY_FACTOR, }; @@ -40,9 +38,6 @@ const getUpdatedDensityState = ( value: newDensity, headerHeight: Math.floor(newHeaderHeight * COMFORTABLE_DENSITY_FACTOR), rowHeight: Math.floor(newRowHeight * COMFORTABLE_DENSITY_FACTOR), - headerGroupingRowHeight: Math.floor( - newHeaderGroupingRowHeight * COMFORTABLE_DENSITY_FACTOR, - ), headerGroupingMaxDepth: newMaxDepth, factor: COMFORTABLE_DENSITY_FACTOR, }; @@ -51,7 +46,6 @@ const getUpdatedDensityState = ( value: newDensity, headerHeight: newHeaderHeight, rowHeight: newRowHeight, - headerGroupingRowHeight: newHeaderGroupingRowHeight, headerGroupingMaxDepth: newMaxDepth, factor: 1, }; @@ -59,10 +53,7 @@ const getUpdatedDensityState = ( }; export const densityStateInitializer: GridStateInitializer< - Pick< - DataGridProcessedProps, - 'density' | 'headerHeight' | 'rowHeight' | 'headerGroupingRowHeight' | 'columnGroupingModel' - > + Pick > = (state, props) => { // TODO: think about improving this initialization. Could it be done in the useColumn initializer? // TODO: manage to remove ts-ignore @@ -87,22 +78,13 @@ export const densityStateInitializer: GridStateInitializer< } return { ...state, - density: getUpdatedDensityState( - props.density, - props.headerHeight, - props.rowHeight, - maxDepth, - props.headerGroupingRowHeight, - ), + density: getUpdatedDensityState(props.density, props.headerHeight, props.rowHeight, maxDepth), }; }; export const useGridDensity = ( apiRef: React.MutableRefObject, - props: Pick< - DataGridProcessedProps, - 'headerHeight' | 'rowHeight' | 'density' | 'headerGroupingRowHeight' - >, + props: Pick, ): void => { const visibleColumns = useGridSelector(apiRef, gridVisibleColumnDefinitionsSelector); @@ -119,7 +101,6 @@ export const useGridDensity = ( newHeaderHeight = props.headerHeight, newRowHeight = props.rowHeight, newMaxDepth = maxDepth, - newHeaderGroupingRowHeight = props.headerGroupingRowHeight, ): void => { logger.debug(`Set grid density to ${newDensity}`); apiRef.current.setState((state) => { @@ -129,7 +110,6 @@ export const useGridDensity = ( newHeaderHeight, newRowHeight, newMaxDepth, - newHeaderGroupingRowHeight, ); if (isDeepEqual(currentDensityState, newDensityState)) { @@ -143,25 +123,12 @@ export const useGridDensity = ( }); apiRef.current.forceUpdate(); }, - [logger, apiRef, props.headerHeight, props.rowHeight, maxDepth, props.headerGroupingRowHeight], + [logger, apiRef, props.headerHeight, props.rowHeight, maxDepth], ); React.useEffect(() => { - apiRef.current.setDensity( - props.density, - props.headerHeight, - props.rowHeight, - maxDepth, - props.headerGroupingRowHeight, - ); - }, [ - apiRef, - props.density, - props.rowHeight, - props.headerHeight, - maxDepth, - props.headerGroupingRowHeight, - ]); + apiRef.current.setDensity(props.density, props.headerHeight, props.rowHeight, maxDepth); + }, [apiRef, props.density, props.rowHeight, props.headerHeight, maxDepth]); const densityApi: GridDensityApi = { setDensity, diff --git a/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts b/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts index 5054b547a0eab..2a02f78e8b51d 100644 --- a/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts +++ b/packages/grid/x-data-grid/src/models/api/gridDensityApi.ts @@ -18,13 +18,11 @@ export interface GridDensityApi { * @param {number} headerHeight The new header height. * @param {number} rowHeight The new row height. * @param {number} maxDepth The depth of maximal depth column header grouping tree. - * @param {number} headerGroupingRowHeight The height of a header grouping line. */ setDensity: ( density: GridDensity, headerHeight?: number, rowHeight?: number, maxDepth?: number, - headerGroupingRowHeight?: number, ) => void; } diff --git a/packages/grid/x-data-grid/src/models/props/DataGridProps.ts b/packages/grid/x-data-grid/src/models/props/DataGridProps.ts index d120b843a75e8..a8549cacb212c 100644 --- a/packages/grid/x-data-grid/src/models/props/DataGridProps.ts +++ b/packages/grid/x-data-grid/src/models/props/DataGridProps.ts @@ -339,12 +339,6 @@ export interface DataGridPropsWithDefaultValues { * @default false */ disableColumnResize: boolean; - /** - * The height of a row of grouping column headers. - * TODO: choose correctly this value - * @default 32 - */ - headerGroupingRowHeight: number; } /** diff --git a/scripts/x-data-grid-premium.exports.json b/scripts/x-data-grid-premium.exports.json index c8ea97accd7af..e800c6440221a 100644 --- a/scripts/x-data-grid-premium.exports.json +++ b/scripts/x-data-grid-premium.exports.json @@ -205,7 +205,6 @@ { "name": "GridDensityApi", "kind": "Interface" }, { "name": "gridDensityFactorSelector", "kind": "Variable" }, { "name": "gridDensityHeaderGroupingMaxDepthSelector", "kind": "Variable" }, - { "name": "gridDensityHeaderGroupingRowHeightSelector", "kind": "Variable" }, { "name": "gridDensityHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityOption", "kind": "Interface" }, { "name": "gridDensityRowHeightSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid-pro.exports.json b/scripts/x-data-grid-pro.exports.json index 93afa97f294b6..d995dfb8337f9 100644 --- a/scripts/x-data-grid-pro.exports.json +++ b/scripts/x-data-grid-pro.exports.json @@ -184,7 +184,6 @@ { "name": "GridDensityApi", "kind": "Interface" }, { "name": "gridDensityFactorSelector", "kind": "Variable" }, { "name": "gridDensityHeaderGroupingMaxDepthSelector", "kind": "Variable" }, - { "name": "gridDensityHeaderGroupingRowHeightSelector", "kind": "Variable" }, { "name": "gridDensityHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityOption", "kind": "Interface" }, { "name": "gridDensityRowHeightSelector", "kind": "Variable" }, diff --git a/scripts/x-data-grid.exports.json b/scripts/x-data-grid.exports.json index e5f2f3b3c33a2..494758be7b848 100644 --- a/scripts/x-data-grid.exports.json +++ b/scripts/x-data-grid.exports.json @@ -170,7 +170,6 @@ { "name": "GridDensityApi", "kind": "Interface" }, { "name": "gridDensityFactorSelector", "kind": "Variable" }, { "name": "gridDensityHeaderGroupingMaxDepthSelector", "kind": "Variable" }, - { "name": "gridDensityHeaderGroupingRowHeightSelector", "kind": "Variable" }, { "name": "gridDensityHeaderHeightSelector", "kind": "Variable" }, { "name": "GridDensityOption", "kind": "Interface" }, { "name": "gridDensityRowHeightSelector", "kind": "Variable" },