Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGridPro] Fix column pinning layout #15073

Merged
merged 3 commits into from
Oct 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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>
);
}