Skip to content

Commit

Permalink
[DataGrid] Set default overlay height in flex parent layout (#15535)
Browse files Browse the repository at this point in the history
  • Loading branch information
cherniavskii authored Nov 21, 2024
1 parent 6589a44 commit 88877c1
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ function CustomNoRowsOverlay() {
);
}

export default function AutoHeightOverlay() {
export default function GridOverlayHeight() {
return (
<Box sx={{ width: '100%' }}>
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'column' }}>
<DataGrid
autoHeight
columns={[{ field: 'ID' }, { field: 'First name' }, { field: 'Last name' }]}
rows={[]}
slots={{ noRowsOverlay: CustomNoRowsOverlay }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,10 @@ function CustomNoRowsOverlay() {
);
}

export default function AutoHeightOverlay() {
export default function GridOverlayHeight() {
return (
<Box sx={{ width: '100%' }}>
<Box sx={{ width: '100%', display: 'flex', flexDirection: 'column' }}>
<DataGrid
autoHeight
columns={[{ field: 'ID' }, { field: 'First name' }, { field: 'Last name' }]}
rows={[]}
slots={{ noRowsOverlay: CustomNoRowsOverlay }}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
<DataGrid
autoHeight
columns={[{ field: 'ID' }, { field: 'First name' }, { field: 'Last name' }]}
rows={[]}
slots={{ noRowsOverlay: CustomNoRowsOverlay }}
Expand Down
22 changes: 11 additions & 11 deletions docs/data/data-grid/layout/layout.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ You can predefine dimensions for the parent of the Data Grid.

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

## Overlay height

When data grid has no content, overlays (such as
["Loading"](/x/react-data-grid/overlays/#loading-overlay) or
["No rows"](/x/react-data-grid/overlays/#no-rows-overlay))
take the height of two rows by default.

To customize the overlay height, use the `--DataGrid-overlayHeight` CSS variable.

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

## Auto height

:::error
Expand All @@ -52,17 +63,6 @@ This means that the Data Grid's height will be determined by the number of rows,

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

### Overlay height

When `autoHeight` is enabled, grid overlays (such as
["Loading"](/x/react-data-grid/overlays/#loading-overlay) or
["No rows"](/x/react-data-grid/overlays/#no-rows-overlay))
take the height of two rows by default.

To customize the overlay height, use the `--DataGrid-overlayHeight` CSS variable.

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

## API

- [DataGrid](/x/api/data-grid/data-grid/)
Expand Down
20 changes: 10 additions & 10 deletions packages/x-data-grid/src/components/base/GridOverlays.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,12 @@ import PropTypes from 'prop-types';
import { styled } from '@mui/system';
import composeClasses from '@mui/utils/composeClasses';
import clsx from 'clsx';
import { minimalContentHeight } from '../../hooks/features/rows/gridRowsUtils';
import { useGridSelector } from '../../hooks/utils/useGridSelector';
import { gridDimensionsSelector } from '../../hooks/features/dimensions';
import { GridOverlayType } from '../../hooks/features/overlays/useGridOverlays';
import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
import { useGridVisibleRows } from '../../hooks/utils/useGridVisibleRows';
import { getMinimalContentHeight } from '../../hooks/features/rows/gridRowsUtils';
import { DataGridProcessedProps } from '../../models/props/DataGridProps';
import { getDataGridUtilityClass } from '../../constants/gridClasses';
import { GridLoadingOverlayVariant } from '../GridLoadingOverlay';
Expand All @@ -29,7 +28,7 @@ const GridOverlayWrapperRoot = styled('div', {
loadingOverlayVariant !== 'skeleton'
? {
position: 'sticky', // To stay in place while scrolling
top: 'var(--DataGrid-headersTotalHeight)',
top: 'var(--DataGrid-headersTotalHeight)', // TODO: take pinned rows into account
left: 0,
width: 0, // To stay above the content instead of shifting it down
height: 0, // To stay above the content instead of shifting it down
Expand Down Expand Up @@ -64,17 +63,18 @@ const useUtilityClasses = (ownerState: OwnerState) => {
function GridOverlayWrapper(props: React.PropsWithChildren<GridOverlaysProps>) {
const apiRef = useGridApiContext();
const rootProps = useGridRootProps();
const currentPage = useGridVisibleRows(apiRef, rootProps);
const dimensions = useGridSelector(apiRef, gridDimensionsSelector);

let height: React.CSSProperties['height'] =
let height: React.CSSProperties['height'] = Math.max(
dimensions.viewportOuterSize.height -
dimensions.topContainerHeight -
dimensions.bottomContainerHeight -
(dimensions.hasScrollX ? dimensions.scrollbarSize : 0);
dimensions.topContainerHeight -
dimensions.bottomContainerHeight -
(dimensions.hasScrollX ? dimensions.scrollbarSize : 0),
0,
);

if ((rootProps.autoHeight && currentPage.rows.length === 0) || height === 0) {
height = getMinimalContentHeight(apiRef);
if (height === 0) {
height = minimalContentHeight;
}

const classes = useUtilityClasses({ ...props, classes: rootProps.classes });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import {
GridRowsPartialUpdateAction,
} from './gridRowsInterfaces';
import { gridPinnedRowsSelector } from './gridRowsSelector';
import { gridDimensionsSelector } from '../dimensions/gridDimensionsSelectors';

export const GRID_ROOT_GROUP_ID: GridRowId = `auto-generated-group-node-root`;
export const GRID_ID_AUTOGENERATED = Symbol('mui.id_autogenerated');
Expand Down Expand Up @@ -401,10 +400,7 @@ export function calculatePinnedRowsHeight(apiRef: React.MutableRefObject<GridApi
};
}

export function getMinimalContentHeight(apiRef: React.MutableRefObject<GridApiCommunity>) {
const dimensions = gridDimensionsSelector(apiRef.current.state);
return `var(--DataGrid-overlayHeight, ${2 * dimensions.rowHeight}px)`;
}
export const minimalContentHeight = 'var(--DataGrid-overlayHeight, calc(var(--height) * 2))';

export function computeRowsUpdates(
apiRef: React.MutableRefObject<GridApiCommunity>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ import type {
import { selectedIdsLookupSelector } from '../rowSelection/gridRowSelectionSelector';
import { gridRowsMetaSelector } from '../rows/gridRowsMetaSelector';
import { getFirstNonSpannedColumnToRender } from '../columns/gridColumnsUtils';
import { getMinimalContentHeight } from '../rows/gridRowsUtils';
import { GridRowProps } from '../../../components/GridRow';
import { GridInfiniteLoaderPrivateApi } from '../../../models/api/gridInfiniteLoaderApi';
import {
Expand All @@ -47,6 +46,7 @@ import {
import { EMPTY_RENDER_CONTEXT } from './useGridVirtualization';
import { gridRowSpanningHiddenCellsOriginMapSelector } from '../rows/gridRowSpanningSelectors';
import { gridListColumnSelector } from '../listView/gridListViewSelectors';
import { minimalContentHeight } from '../rows/gridRowsUtils';

const MINIMUM_COLUMN_WIDTH = 50;

Expand Down Expand Up @@ -538,19 +538,12 @@ export const useGridVirtualScroller = () => {
flexShrink: 0,
};

if (rootProps.autoHeight && currentPage.rows.length === 0) {
size.flexBasis = getMinimalContentHeight(apiRef); // Give room to show the overlay when there no rows.
if (size.flexBasis === 0) {
size.flexBasis = minimalContentHeight; // Give room to show the overlay when there no rows.
}

return size;
}, [
apiRef,
columnsTotalWidth,
contentHeight,
needsHorizontalScrollbar,
rootProps.autoHeight,
currentPage.rows.length,
]);
}, [columnsTotalWidth, contentHeight, needsHorizontalScrollbar]);

React.useEffect(() => {
apiRef.current.publishEvent('virtualScrollerContentSizeChange');
Expand Down
168 changes: 168 additions & 0 deletions test/regressions/data-grid/DataGridOverlays.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/* eslint-disable react/prop-types */
import * as React from 'react';
import { DataGrid } from '@mui/x-data-grid';

function FlexParent({ children, style }) {
return <div style={{ display: 'flex', flexDirection: 'column', ...style }}>{children}</div>;
}

function FlexParentNoRowsOverlay() {
return (
<div>
FlexParentNoRowsOverlay
<FlexParent>
<DataGrid columns={[{ field: 'id' }]} />
</FlexParent>
</div>
);
}

function FlexParentMinHeightNoRowsOverlay() {
return (
<div>
FlexParentMinHeightNoRowsOverlay
<FlexParent style={{ minHeight: 300 }}>
<DataGrid columns={[{ field: 'id' }]} />
</FlexParent>
</div>
);
}

function FlexParentMaxHeightNoRowsOverlay() {
return (
<div>
FlexParentMaxHeightNoRowsOverlay
<FlexParent style={{ maxHeight: 200 }}>
<DataGrid columns={[{ field: 'id' }]} />
</FlexParent>
</div>
);
}

function AutoHeightNoRowsOverlay() {
return (
<div>
AutoHeightNoRowsOverlay
<div style={{ width: '100%' }}>
<DataGrid columns={[{ field: 'id' }]} autoHeight />
</div>
</div>
);
}

function AutoHeightLoadingOverlay() {
return (
<div>
AutoHeightLoadingOverlay
<div style={{ width: '100%' }}>
<DataGrid columns={[{ field: 'id' }]} rows={[{ id: 1 }]} loading autoHeight />
</div>
</div>
);
}

function PredefinedSizeNoRowsLoadingOverlay() {
return (
<div>
PredefinedSizeNoRowsLoadingOverlay
<div style={{ width: '100%', height: 300 }}>
<DataGrid columns={[{ field: 'id' }]} loading />
</div>
</div>
);
}

function FlexParentSkeletonOverlay() {
return (
<div>
FlexParentSkeletonOverlay
<FlexParent>
<DataGrid
columns={[{ field: 'id' }]}
slotProps={{ loadingOverlay: { variant: 'skeleton', noRowsVariant: 'skeleton' } }}
loading
/>
</FlexParent>
</div>
);
}

function FlexParentMinHeightSkeletonOverlay() {
return (
<div>
FlexParentMinHeightSkeletonOverlay
<FlexParent style={{ minHeight: 300 }}>
<DataGrid
columns={[{ field: 'id' }]}
slotProps={{ loadingOverlay: { variant: 'skeleton', noRowsVariant: 'skeleton' } }}
loading
/>
</FlexParent>
</div>
);
}

function FlexParentMaxHeightSkeletonOverlay() {
return (
<div>
FlexParentMaxHeightSkeletonOverlay
<FlexParent style={{ maxHeight: 200 }}>
<DataGrid
columns={[{ field: 'id' }]}
slotProps={{ loadingOverlay: { variant: 'skeleton', noRowsVariant: 'skeleton' } }}
loading
/>
</FlexParent>
</div>
);
}

function AutoHeightSkeletonOverlay() {
return (
<div>
AutoHeightSkeletonOverlay
<div style={{ width: '100%' }}>
<DataGrid
columns={[{ field: 'id' }]}
autoHeight
slotProps={{ loadingOverlay: { variant: 'skeleton', noRowsVariant: 'skeleton' } }}
loading
/>
</div>
</div>
);
}

function PredefinedSizeSkeletonOverlay() {
return (
<div>
PredefinedSizeSkeletonOverlay
<div style={{ width: '100%', height: 300 }}>
<DataGrid
columns={[{ field: 'id' }]}
loading
slotProps={{ loadingOverlay: { variant: 'skeleton', noRowsVariant: 'skeleton' } }}
/>
</div>
</div>
);
}

export default function DataGridFlexParentOverlay() {
return (
<div style={{ width: '100%' }}>
<FlexParentNoRowsOverlay />
<FlexParentMinHeightNoRowsOverlay />
<FlexParentMaxHeightNoRowsOverlay />
<AutoHeightNoRowsOverlay />
<AutoHeightLoadingOverlay />
<PredefinedSizeNoRowsLoadingOverlay />

<FlexParentSkeletonOverlay />
<FlexParentMinHeightSkeletonOverlay />
<FlexParentMaxHeightSkeletonOverlay />
<AutoHeightSkeletonOverlay />
<PredefinedSizeSkeletonOverlay />
</div>
);
}

0 comments on commit 88877c1

Please sign in to comment.