diff --git a/docs/src/pages/components/data-grid/rendering/AntDesignGrid.js b/docs/src/pages/components/data-grid/rendering/AntDesignGrid.js new file mode 100644 index 0000000000000..74d7225697705 --- /dev/null +++ b/docs/src/pages/components/data-grid/rendering/AntDesignGrid.js @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { DataGrid } from '@material-ui/data-grid'; +import { useDemoData } from '@material-ui/x-grid-data-generator'; + +export default function AntDesignGrid() { + const { data } = useDemoData({ + dataSet: 'Commodity', + rowLength: 1000, + maxColumns: 6, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/rendering/AntDesignGrid.tsx b/docs/src/pages/components/data-grid/rendering/AntDesignGrid.tsx new file mode 100644 index 0000000000000..3fcd144a11100 --- /dev/null +++ b/docs/src/pages/components/data-grid/rendering/AntDesignGrid.tsx @@ -0,0 +1,130 @@ +import * as React from 'react'; +import { DataGrid, ComponentProps } from '@material-ui/data-grid'; +import { useDemoData } from '@material-ui/x-grid-data-generator'; +import { createStyles, Theme, makeStyles } from '@material-ui/core/styles'; +import Pagination from '@material-ui/lab/Pagination'; +import PaginationItem from '@material-ui/lab/PaginationItem'; + +function customCheckbox(theme) { + return { + '& .MuiCheckbox-root svg': { + width: 16, + height: 16, + backgroundColor: 'transparent', + border: `1px solid ${theme.palette.type === 'light' ? '#d9d9d9' : 'rgb(67, 67, 67)'}`, + borderRadius: 2, + }, + '& .MuiCheckbox-root svg path': { + display: 'none', + }, + '& .MuiCheckbox-root.Mui-checked:not(.MuiCheckbox-indeterminate) svg': { + backgroundColor: '#1890ff', + borderColor: '#1890ff', + }, + '& .MuiCheckbox-root.Mui-checked .MuiIconButton-label:after': { + position: 'absolute', + display: 'table', + border: '2px solid #fff', + borderTop: 0, + borderLeft: 0, + transform: 'rotate(45deg) translate(-50%,-50%)', + opacity: 1, + transition: 'all .2s cubic-bezier(.12,.4,.29,1.46) .1s', + content: '""', + top: '50%', + left: '39%', + width: 5.71428571, + height: 9.14285714, + }, + '& .MuiCheckbox-root.MuiCheckbox-indeterminate .MuiIconButton-label:after': { + width: 8, + height: 8, + backgroundColor: '#1890ff', + transform: 'none', + top: '39%', + border: 0, + }, + } +} + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: { + border: 0, + color: theme.palette.type === 'light' ? 'rgba(0,0,0,.85)' : 'rgba(255,255,255,0.85)', + fontFamily: [ + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + 'Roboto', + '"Helvetica Neue"', + 'Arial', + 'sans-serif', + '"Apple Color Emoji"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + ].join(','), + WebkitFontSmoothing: 'auto', + letterSpacing: 'normal', + '& .MuiDataGrid-columnsContainer': { + backgroundColor: theme.palette.type === 'light' ? '#fafafa' : '#1d1d1d', + }, + '& .MuiDataGrid-iconSeparator': { + display: 'none', + }, + '& .MuiDataGrid-colCell, .MuiDataGrid-cell': { + borderRight: `1px solid ${theme.palette.type === 'light' ? '#f0f0f0' : '#303030'}`, + }, + '& .MuiDataGrid-columnsContainer, .MuiDataGrid-cell': { + borderBottom: `1px solid ${theme.palette.type === 'light' ? '#f0f0f0' : '#303030'}`, + }, + '& .MuiDataGrid-cell': { + color: theme.palette.type === 'light' ? 'rgba(0,0,0,.85)' : 'rgba(255,255,255,0.65)', + }, + '& .MuiPaginationItem-root': { + borderRadius: 0, + }, + ...customCheckbox(theme), + }, + }), +); + +function CustomPagination(props: ComponentProps) { + const { paginationProps } = props; + + return ( + } + onChange={(event, value) => paginationProps.setPage(value)} + /> + ); +} + +export default function AntDesignGrid() { + const { data } = useDemoData({ + dataSet: 'Commodity', + rowLength: 10, + maxColumns: 10, + }); + const classes = useStyles(); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/rendering/CustomEmptyOverlayGrid.js b/docs/src/pages/components/data-grid/rendering/CustomEmptyOverlayGrid.js new file mode 100644 index 0000000000000..f0f6f19785299 --- /dev/null +++ b/docs/src/pages/components/data-grid/rendering/CustomEmptyOverlayGrid.js @@ -0,0 +1,101 @@ +import * as React from 'react'; +import { GridOverlay, DataGrid } from '@material-ui/data-grid'; +import { useDemoData } from '@material-ui/x-grid-data-generator'; +import { createStyles, makeStyles } from '@material-ui//core/styles'; + +const useStyles = makeStyles((theme) => ({ + root: { + '& .MuiDataGrid-overlayContent': { + flexDirection: 'column', + alignItems: 'center', + }, + '& .ant-empty-img-1': { + fill: theme.palette.type === 'light' ? '#aeb8c2' : '#262626', + }, + '& .ant-empty-img-2': { + fill: theme.palette.type === 'light' ? '#f5f5f7' : '#595959', + }, + '& .ant-empty-img-3': { + fill: theme.palette.type === 'light' ? '#dce0e6' : '#434343', + }, + '& .ant-empty-img-4': { + fill: theme.palette.type === 'light' ? '#fff' : '#1c1c1c', + }, + '& .ant-empty-img-5': { + fillOpacity: theme.palette.type === 'light' ? '0.8' : '0.08', + fill: theme.palette.type === 'light' ? '#f5f5f5' : '#fff', + }, + }, + label: { + marginTop: theme.spacing(1), + }, +})); + +function CustomNoRowsOverlay() { + const classes = useStyles(); + + return ( + + + + + + + + + + + + + + + + +
No Rows
+
+ ); +} + +export default function CustomEmptyOverlayGrid() { + const { data } = useDemoData({ + dataSet: 'Commodity', + rowLength: 100, + maxColumns: 6, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/rendering/CustomEmptyOverlayGrid.tsx b/docs/src/pages/components/data-grid/rendering/CustomEmptyOverlayGrid.tsx new file mode 100644 index 0000000000000..72084914a1bad --- /dev/null +++ b/docs/src/pages/components/data-grid/rendering/CustomEmptyOverlayGrid.tsx @@ -0,0 +1,103 @@ +import * as React from 'react'; +import { GridOverlay, DataGrid } from '@material-ui/data-grid'; +import { useDemoData } from '@material-ui/x-grid-data-generator'; +import { createStyles, Theme, makeStyles } from '@material-ui//core/styles'; + +const useStyles = makeStyles((theme: Theme) => + createStyles({ + root: { + '& .MuiDataGrid-overlayContent': { + flexDirection: 'column', + alignItems: 'center', + }, + '& .ant-empty-img-1': { + fill: theme.palette.type === 'light' ? '#aeb8c2' : '#262626', + }, + '& .ant-empty-img-2': { + fill: theme.palette.type === 'light' ? '#f5f5f7' : '#595959', + }, + '& .ant-empty-img-3': { + fill: theme.palette.type === 'light' ? '#dce0e6' : '#434343', + }, + '& .ant-empty-img-4': { + fill: theme.palette.type === 'light' ? '#fff' : '#1c1c1c', + }, + '& .ant-empty-img-5': { + fillOpacity: theme.palette.type === 'light' ? '0.8' : '0.08', + fill: theme.palette.type === 'light' ? '#f5f5f5' : '#fff', + }, + }, + label: { + marginTop: theme.spacing(1), + }, + }), +); + +function CustomNoRowsOverlay() { + const classes = useStyles(); + + return ( + + + + + + + + + + + + + + + + +
No Rows
+
+ ); +} + +export default function CustomEmptyOverlayGrid() { + const { data } = useDemoData({ + dataSet: 'Commodity', + rowLength: 100, + maxColumns: 6, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/rendering/CustomLoadingOverlayGrid.js b/docs/src/pages/components/data-grid/rendering/CustomLoadingOverlayGrid.js new file mode 100644 index 0000000000000..ed00919d66b68 --- /dev/null +++ b/docs/src/pages/components/data-grid/rendering/CustomLoadingOverlayGrid.js @@ -0,0 +1,34 @@ +import * as React from 'react'; +import { GridOverlay, DataGrid } from '@material-ui/data-grid'; +import LinearProgress from '@material-ui/core/LinearProgress'; +import { useDemoData } from '@material-ui/x-grid-data-generator'; + +function CustomLoadingOverlay() { + return ( + +
+ +
+
+ ); +} + +export default function CustomLoadingOverlayGrid() { + const { data } = useDemoData({ + dataSet: 'Commodity', + rowLength: 100, + maxColumns: 6, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/rendering/CustomLoadingOverlayGrid.tsx b/docs/src/pages/components/data-grid/rendering/CustomLoadingOverlayGrid.tsx new file mode 100644 index 0000000000000..ed00919d66b68 --- /dev/null +++ b/docs/src/pages/components/data-grid/rendering/CustomLoadingOverlayGrid.tsx @@ -0,0 +1,34 @@ +import * as React from 'react'; +import { GridOverlay, DataGrid } from '@material-ui/data-grid'; +import LinearProgress from '@material-ui/core/LinearProgress'; +import { useDemoData } from '@material-ui/x-grid-data-generator'; + +function CustomLoadingOverlay() { + return ( + +
+ +
+
+ ); +} + +export default function CustomLoadingOverlayGrid() { + const { data } = useDemoData({ + dataSet: 'Commodity', + rowLength: 100, + maxColumns: 6, + }); + + return ( +
+ +
+ ); +} diff --git a/docs/src/pages/components/data-grid/rendering/CustomPaginationGrid.tsx b/docs/src/pages/components/data-grid/rendering/CustomPaginationGrid.tsx index 714f377385571..bb88afba291ba 100644 --- a/docs/src/pages/components/data-grid/rendering/CustomPaginationGrid.tsx +++ b/docs/src/pages/components/data-grid/rendering/CustomPaginationGrid.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import { makeStyles } from '@material-ui/core/styles'; -import { DataGrid } from '@material-ui/data-grid'; +import { DataGrid, ComponentProps } from '@material-ui/data-grid'; import { useDemoData } from '@material-ui/x-grid-data-generator'; import Pagination from '@material-ui/lab/Pagination'; @@ -10,15 +10,7 @@ const useStyles = makeStyles({ }, }); -interface CustomPaginationProps { - paginationProps: { - page: number; - pageCount: number; - setPage: (newPage: number) => void; - }; -} - -function CustomPagination(props: CustomPaginationProps) { +function CustomPagination(props: ComponentProps) { const { paginationProps } = props; const classes = useStyles(); diff --git a/docs/src/pages/components/data-grid/rendering/rendering.md b/docs/src/pages/components/data-grid/rendering/rendering.md index 4d3861314a978..ac9e84e0043f4 100644 --- a/docs/src/pages/components/data-grid/rendering/rendering.md +++ b/docs/src/pages/components/data-grid/rendering/rendering.md @@ -222,7 +222,7 @@ By default, 2 columns are rendered outside of the viewport. You can change this You can disable column virtualization by setting the column buffer to a higher number than the number of rendered columns, e.g. with `columnBuffer={columns.length}` or `columnBuffer={Number.MAX_SAFE_INTEGER}`. -## Components +## Components prop As part of the customization API, the grid allows you to replace and override the following components: @@ -232,12 +232,28 @@ As part of the customization API, the grid allows you to replace and override th - `footer`: The component rendered below the viewport. - `pagination`: The component rendered for the pagination feature. +### Loading overlay + +By default, the loading overlay displays a circular progress. +This demo replaces it with a linear progress. + +{{"demo": "pages/components/data-grid/rendering/CustomLoadingOverlayGrid.js"}} + +### No rows overlay + +In the following demo, an illustaration is added on top of the default "No Rows" message. + +{{"demo": "pages/components/data-grid/rendering/CustomEmptyOverlayGrid.js"}} + ### Pagination -By default, pagination uses the [TablePagination](/components/pagination/#table-pagination) component that is optimized for handling tabular data. This demo replaces it with the [Pagination](/components/pagination/) component. +By default, pagination uses the [TablePagination](/components/pagination/#table-pagination) component that is optimized for handling tabular data. +This demo replaces it with the [Pagination](/components/pagination/) component. {{"demo": "pages/components/data-grid/rendering/CustomPaginationGrid.js"}} ## Customization example -The following grid leverages the Ant Design specification. +The following grid leverages the CSS customization API to match the Ant Design specification. + +{{"demo": "pages/components/data-grid/rendering/AntDesignGrid.js"}} diff --git a/packages/grid/x-grid-modules/src/components/styled-wrappers/GridRootStyles.ts b/packages/grid/x-grid-modules/src/components/styled-wrappers/GridRootStyles.ts index b128abcf1d90b..c3cfde8e1fa10 100644 --- a/packages/grid/x-grid-modules/src/components/styled-wrappers/GridRootStyles.ts +++ b/packages/grid/x-grid-modules/src/components/styled-wrappers/GridRootStyles.ts @@ -14,6 +14,8 @@ export const useStyles = makeStyles( position: 'relative', border: `1px solid ${borderColor}`, borderRadius: theme.shape.borderRadius, + color: theme.palette.text.primary, + ...theme.typography.body2, outline: 'none', display: 'flex', flexDirection: 'column', @@ -32,10 +34,14 @@ export const useStyles = makeStyles( top: 0, left: 0, right: 0, - bottom: 15, + bottom: 0, alignSelf: 'center', alignItems: 'center', zIndex: 10, + backgroundColor: fade( + theme.palette.background.default, + theme.palette.action.disabledOpacity, + ), }, '& .MuiDataGrid-overlayContent': { flex: 1, @@ -60,7 +66,6 @@ export const useStyles = makeStyles( }, '& .MuiDataGrid-colCell, & .MuiDataGrid-cell': { WebkitTapHighlightColor: 'transparent', - ...theme.typography.body2, lineHeight: null, padding: theme.spacing(0, 2), }, @@ -94,7 +99,6 @@ export const useStyles = makeStyles( textOverflow: 'ellipsis', overflow: 'hidden', whiteSpace: 'nowrap', - color: theme.palette.text.primary, fontWeight: theme.typography.fontWeightMedium, }, '& .MuiDataGrid-columnSeparator': { @@ -190,14 +194,14 @@ export const useStyles = makeStyles( '& .MuiDataGrid-footer': { display: 'flex', justifyContent: 'space-between', + alignItems: 'center', + minHeight: 52, // Match TablePagination min height }, '& .MuiDataGrid-rowCount, & .MuiDataGrid-selectedRowCount': { alignItems: 'center', - ...theme.typography.body2, display: 'none', paddingLeft: theme.spacing(2), [theme.breakpoints.up('md')]: { - minHeight: 52, // Match TablePagination min height display: 'flex', }, }, diff --git a/packages/grid/x-grid-modules/src/hooks/features/useComponents.tsx b/packages/grid/x-grid-modules/src/hooks/features/useComponents.tsx index 62266c85a97e5..e7fea02d6714f 100644 --- a/packages/grid/x-grid-modules/src/hooks/features/useComponents.tsx +++ b/packages/grid/x-grid-modules/src/hooks/features/useComponents.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { PaginationProps } from './usePagination'; import { - ComponentParams, + ComponentProps, ApiRef, GridComponentOverridesProp, GridOptions, @@ -22,7 +22,7 @@ export const useComponents = ( apiRef: ApiRef, gridRootRef: RootContainerRef, ) => { - const componentParams: ComponentParams = React.useMemo( + const componentProps: ComponentProps = React.useMemo( () => ({ paginationProps, rows, @@ -37,51 +37,51 @@ export const useComponents = ( const headerComponent = React.useMemo( () => componentOverrides?.header - ? React.createElement(componentOverrides.header, componentParams) + ? React.createElement(componentOverrides.header, componentProps) : null, - [componentOverrides, componentParams], + [componentOverrides, componentProps], ); const footerComponent = React.useMemo( () => componentOverrides?.footer - ? React.createElement(componentOverrides.footer, componentParams) + ? React.createElement(componentOverrides.footer, componentProps) : null, - [componentOverrides, componentParams], + [componentOverrides, componentProps], ); const loadingComponent = React.useMemo( () => componentOverrides?.loadingOverlay ? ( - React.createElement(componentOverrides.loadingOverlay, componentParams) + React.createElement(componentOverrides.loadingOverlay, componentProps) ) : ( ), - [componentOverrides, componentParams], + [componentOverrides, componentProps], ); const noRowsComponent = React.useMemo( () => componentOverrides?.noRowsOverlay ? ( - React.createElement(componentOverrides.noRowsOverlay, componentParams) + React.createElement(componentOverrides.noRowsOverlay, componentProps) ) : ( ), - [componentOverrides, componentParams], + [componentOverrides, componentProps], ); const paginationComponent = React.useMemo( () => componentOverrides?.pagination - ? React.createElement(componentOverrides.pagination, componentParams) + ? React.createElement(componentOverrides.pagination, componentProps) : null, - [componentOverrides, componentParams], + [componentOverrides, componentProps], ); const renderError = React.useCallback( (props) => { const ErrorOverlay = componentOverrides?.errorOverlay || ErrorMessage; - return ; + return ; }, - [componentOverrides?.errorOverlay, componentParams], + [componentOverrides?.errorOverlay, componentProps], ); return { diff --git a/packages/grid/x-grid-modules/src/models/gridComponentOverridesProp.tsx b/packages/grid/x-grid-modules/src/models/gridComponentOverridesProp.tsx index 0736500406ca1..fb482e5e96ba3 100644 --- a/packages/grid/x-grid-modules/src/models/gridComponentOverridesProp.tsx +++ b/packages/grid/x-grid-modules/src/models/gridComponentOverridesProp.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { ComponentParams } from './params'; +import { ComponentProps } from './params'; /** * Grid components React prop interface containing all the overridable components. @@ -8,25 +8,25 @@ export interface GridComponentOverridesProp { /** * Pagination component rendered in the grid footer by default. */ - pagination?: React.ElementType; + pagination?: React.ElementType; /** * Loading overlay component rendered when the grid is in a loading state. */ - loadingOverlay?: React.ElementType; + loadingOverlay?: React.ElementType; /** * No rows overlay component rendered when the grid has no rows. */ - noRowsOverlay?: React.ElementType; + noRowsOverlay?: React.ElementType; /** * Footer component rendered at the bottom of the grid viewport. */ - footer?: React.ElementType; + footer?: React.ElementType; /** * Header component rendered above the grid column header bar. */ - header?: React.ElementType; + header?: React.ElementType; /** * Error overlay component rendered above the grid when an error is caught. */ - errorOverlay?: React.ElementType; + errorOverlay?: React.ElementType; } diff --git a/packages/grid/x-grid-modules/src/models/params/componentParams.ts b/packages/grid/x-grid-modules/src/models/params/componentParams.ts index e57a9a8ce69a8..daa7cfe2c753d 100644 --- a/packages/grid/x-grid-modules/src/models/params/componentParams.ts +++ b/packages/grid/x-grid-modules/src/models/params/componentParams.ts @@ -8,7 +8,7 @@ import { ApiRef } from '../api'; /** * Object passed as React prop in the component override. */ -export interface ComponentParams { +export interface ComponentProps { /** * The object containing all pagination details in [[PaginationProps]]. */ diff --git a/packages/storybook/src/documentation/pages/components.stories.mdx b/packages/storybook/src/documentation/pages/components.stories.mdx deleted file mode 100644 index 2a743ce4ee9f5..0000000000000 --- a/packages/storybook/src/documentation/pages/components.stories.mdx +++ /dev/null @@ -1,30 +0,0 @@ -import { XGrid } from '@material-ui/x-grid'; -import LoadingOverrideDemo from './demos/customization/loadingOverride.demo'; - - - -# Components - -As part of our customization API, XGrid allows to replace and override the following components. - -- `pagination` - the native pagination component as mentioned in the pagination page [here]() -- `loadingOverlay` - rendered when the `loading` react prop is set to `true` -- `noRowsOverlay` - rendered when the `rows` react prop is empty or `[]` -- `header` - Rendered above the column header bar -- `footer` - Rendered below the viewport - -To achieve this, you need to override the desired property of the `components` react prop. - -```tsx - -``` - -Below is an example on how you can replace the loading overlay. - - - -- TODO add more components? diff --git a/packages/storybook/src/documentation/pages/demos/customization/loadingOverride.demo.tsx b/packages/storybook/src/documentation/pages/demos/customization/loadingOverride.demo.tsx deleted file mode 100644 index 28c5b31e6eac9..0000000000000 --- a/packages/storybook/src/documentation/pages/demos/customization/loadingOverride.demo.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Columns, GridOverlay, RowsProp, XGrid } from '@material-ui/x-grid'; -import LinearProgress from '@material-ui/core/LinearProgress'; -import * as React from 'react'; -import { randomCreatedDate, randomUpdatedDate } from '@material-ui/x-grid-data-generator'; - -function LoadingComponent() { - return ( - -
- -
-
- ); -} - -export default function LoadingOverrideDemo() { - const columns: Columns = [ - { field: 'id', hide: true }, - { field: 'name', type: 'string' }, - { field: 'age', type: 'number' }, - { field: 'dateCreated', type: 'date', width: 180 }, - { field: 'lastLogin', type: 'dateTime', width: 180 }, - ]; - const rows: RowsProp = [ - { - id: 1, - name: 'Damien', - age: 25, - dateCreated: randomCreatedDate(), - lastLogin: randomUpdatedDate(), - }, - { - id: 2, - name: 'Nicolas', - age: 36, - dateCreated: randomCreatedDate(), - lastLogin: randomUpdatedDate(), - }, - { - id: 3, - name: 'Kate', - age: 19, - dateCreated: randomCreatedDate(), - lastLogin: randomUpdatedDate(), - }, - ]; - return ( - - ); -}