Skip to content

Commit

Permalink
[DataGridPro] Fix column pinning layout (#14966)
Browse files Browse the repository at this point in the history
  • Loading branch information
cherniavskii authored Oct 23, 2024
1 parent 341220a commit 66c7b5a
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,10 @@ describe('<DataGridPro /> - Detail panel', () => {
await microtasks();

const virtualScrollerContent = $('.MuiDataGrid-virtualScrollerContent')!;
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
expect(virtualScrollerContent).toHaveComputedStyle({
height: `${rowHeight + detailPanelHeight}px`,
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });

const detailPanels = $$('.MuiDataGrid-detailPanel');
expect(detailPanels[0]).toHaveComputedStyle({
Expand Down Expand Up @@ -128,11 +128,9 @@ describe('<DataGridPro /> - Detail panel', () => {
});

await waitFor(() => {
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: `${rowHeight + 100}px`,
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: `${rowHeight + 100}px` });
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });

const detailPanels = $$('.MuiDataGrid-detailPanel');
expect(detailPanels[0]).toHaveComputedStyle({
Expand All @@ -142,11 +140,9 @@ describe('<DataGridPro /> - Detail panel', () => {
fireEvent.click(screen.getByRole('button', { name: 'Increase' }));

await waitFor(() => {
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: `${rowHeight + 200}px`,
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: `${rowHeight + 200}px` });
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });

expect(detailPanels[0]).toHaveComputedStyle({
height: `200px`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ export const GridRootStyles = styled('div', {
},

[`& .${c.filler}`]: {
flex: 1,
flex: '1 0 auto',
},
[`& .${c['filler--borderBottom']}`]: {
borderBottom: '1px solid var(--DataGrid-rowBorderColor)',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@ import clsx from 'clsx';
import { styled } from '@mui/system';
import composeClasses from '@mui/utils/composeClasses';
import { gridClasses, getDataGridUtilityClass } from '../../constants/gridClasses';
import { gridDimensionsSelector } from '../../hooks/features/dimensions/gridDimensionsSelectors';
import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
import { useGridSelector } from '../../hooks/utils/useGridSelector';

const useUtilityClasses = () => {
const slots = {
Expand All @@ -23,25 +20,10 @@ const Element = styled('div')({
export function GridBottomContainer(props: React.PropsWithChildren) {
const classes = useUtilityClasses();

const apiRef = useGridApiContext();
const { viewportOuterSize, minimumSize, hasScrollX, scrollbarSize } = useGridSelector(
apiRef,
gridDimensionsSelector,
);
const scrollHeight = hasScrollX ? scrollbarSize : 0;
const offset = Math.max(
viewportOuterSize.height -
minimumSize.height -
// Subtract scroll height twice to account for GridVirtualScrollerFiller and horizontal scrollbar
2 * scrollHeight,
0,
);

return (
<Element
{...props}
className={clsx(classes.root, gridClasses['container--bottom'])}
style={{ transform: `translateY(${offset}px)` }}
role="presentation"
/>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ const Scroller = styled('div', {
flexGrow: 1,
overflow: 'scroll',
scrollbarWidth: 'none' /* Firefox */,
display: 'flex',
flexDirection: 'column',
'&::-webkit-scrollbar': {
display: 'none' /* Safari and Chrome */,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,8 @@ export const useGridVirtualScroller = () => {
const contentSize = React.useMemo(() => {
const size: React.CSSProperties = {
width: needsHorizontalScrollbar ? columnsTotalWidth : 'auto',
height: contentHeight,
flexBasis: contentHeight,
flexShrink: 0,
};

if (rootProps.autoHeight && currentPage.rows.length === 0) {
Expand Down
62 changes: 28 additions & 34 deletions packages/x-data-grid/src/tests/rows.DataGrid.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -645,11 +645,9 @@ describe('<DataGrid /> - Rows', () => {
);
const expectedHeight = baselineProps.rows.length * (contentHeight + border);
await waitFor(() => {
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: `${expectedHeight}px`,
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: `${expectedHeight}px` });
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
});

it('should use the default row height to calculate the content size when the row has not been measured yet', async () => {
Expand All @@ -674,11 +672,9 @@ describe('<DataGrid /> - Rows', () => {
border + // Measured rows also include the border
(baselineProps.rows.length - 1) * defaultRowHeight;
await waitFor(() => {
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: `${expectedHeight}px`,
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: `${expectedHeight}px` });
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
});

it('should use the value from getEstimatedRowHeight to estimate the content size', async () => {
Expand All @@ -703,11 +699,9 @@ describe('<DataGrid /> - Rows', () => {
const expectedHeight =
firstRowHeight + (baselineProps.rows.length - 1) * estimatedRowHeight;
await waitFor(() => {
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: `${expectedHeight}px`,
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: `${expectedHeight}px` });
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
});

it('should recalculate the content size when the rows prop changes', async () => {
Expand All @@ -723,18 +717,14 @@ describe('<DataGrid /> - Rows', () => {
'.MuiDataGrid-virtualScrollerContent',
);
await waitFor(() => {
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: '101px',
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: '101px' });
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
setProps({ rows: [{ clientId: 'c1', expanded: true }] });
await waitFor(() => {
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: '201px',
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: '201px' });
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
});

it('should set minHeight to "auto" in all rows with dynamic row height', () => {
Expand Down Expand Up @@ -813,11 +803,11 @@ describe('<DataGrid /> - Rows', () => {
'.MuiDataGrid-virtualScrollerContent',
)!;
await waitFor(() => {
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
expect(virtualScrollerContent).toHaveComputedStyle({
height: `${Math.floor(expectedHeight)}px`,
});
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
});

it('should position correctly the render zone when the 2nd page has less rows than the 1st page', async function test() {
Expand Down Expand Up @@ -968,7 +958,11 @@ describe('<DataGrid /> - Rows', () => {
});
});

it('should consider the spacing when computing the content size', () => {
it('should consider the spacing when computing the content size', function test() {
if (isJSDOM) {
// Need layouting
this.skip();
}
const spacingTop = 5;
const spacingBottom = 10;
const rowHeight = 50;
Expand All @@ -981,13 +975,15 @@ describe('<DataGrid /> - Rows', () => {
);
const virtualScrollerContent = document.querySelector('.MuiDataGrid-virtualScrollerContent');
const expectedHeight = rows.length * (rowHeight + spacingTop + spacingBottom);
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: `${expectedHeight}px`,
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: `${expectedHeight}px` });
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
});

it('should update the content size when getRowSpacing is removed', () => {
it('should update the content size when getRowSpacing is removed', function test() {
if (isJSDOM) {
// Need layouting
this.skip();
}
const spacingTop = 5;
const spacingBottom = 10;
const rowHeight = 50;
Expand All @@ -1000,15 +996,13 @@ describe('<DataGrid /> - Rows', () => {
);
const virtualScrollerContent = document.querySelector('.MuiDataGrid-virtualScrollerContent');
const expectedHeight = rows.length * (rowHeight + spacingTop + spacingBottom);
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
height: `${expectedHeight}px`,
});
expect(virtualScrollerContent).toHaveComputedStyle({ height: `${expectedHeight}px` });
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
setProps({ getRowSpacing: null });
expect(virtualScrollerContent).toHaveInlineStyle({
width: 'auto',
expect(virtualScrollerContent).toHaveComputedStyle({
height: `${rows.length * rowHeight}px`,
});
expect(virtualScrollerContent).toHaveInlineStyle({ width: 'auto' });
});

it('should set the row margin to the value returned by getRowSpacing if rowSpacingType is not defined', () => {
Expand Down
62 changes: 62 additions & 0 deletions test/regressions/data-grid/DataGridPinnedColumns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import * as React from 'react';
import DeleteIcon from '@mui/icons-material/Delete';
import EditIcon from '@mui/icons-material/Edit';
import { DataGridPro, GridActionsCellItem } from '@mui/x-data-grid-pro';
import {
randomCreatedDate,
randomTraderName,
randomEmail,
randomUpdatedDate,
} from '@mui/x-data-grid-generator';

const columns = [
{ field: 'name', headerName: 'Name', width: 160, editable: true },
{ field: 'email', headerName: 'Email', width: 200, editable: true },
{ field: 'age', headerName: 'Age', type: 'number', editable: true },
{
field: 'dateCreated',
headerName: 'Date Created',
type: 'date',
width: 180,
editable: true,
},
{
field: 'lastLogin',
headerName: 'Last Login',
type: 'dateTime',
width: 220,
editable: true,
},
{
field: 'actions',
type: 'actions',
width: 100,
getActions: () => [
<GridActionsCellItem icon={<EditIcon />} label="Edit" />,
<GridActionsCellItem icon={<DeleteIcon />} label="Delete" />,
],
},
];

const rows = [
{
id: 1,
name: randomTraderName(),
email: randomEmail(),
age: 25,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
];

export default function BasicColumnPinning() {
return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPro
rows={rows}
columns={columns}
initialState={{ pinnedColumns: { left: ['name'], right: ['actions'] } }}
/>
</div>
);
}

0 comments on commit 66c7b5a

Please sign in to comment.