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

[DataGrid] Fix resizing right pinned column (@KenanYusuf) #16193

Merged
merged 2 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
75 changes: 74 additions & 1 deletion packages/x-data-grid-pro/src/tests/columns.DataGridPro.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
GridAutosizeOptions,
} from '@mui/x-data-grid-pro';
import { useGridPrivateApiContext } from '@mui/x-data-grid-pro/internals';
import { getColumnHeaderCell, getCell, microtasks } from 'test/utils/helperFn';
import { getColumnHeaderCell, getCell, microtasks, getRow } from 'test/utils/helperFn';

const isJSDOM = /jsdom/.test(window.navigator.userAgent);

Expand Down Expand Up @@ -228,6 +228,79 @@ describe('<DataGridPro /> - Columns', () => {
expect(bottomPinnedRowCell?.getBoundingClientRect().width).to.equal(150);
});

// https://github.com/mui/mui-x/issues/12852
it('should work with right pinned column', () => {
render(
<Test
columns={[
{ field: 'id', width: 100 },
{ field: 'brand', width: 100 },
]}
initialState={{ pinnedColumns: { right: ['brand'] } }}
/>,
);

const pinnedHeaderCell = getColumnHeaderCell(1);
const pinnedCell = getCell(1, 1);
const pinnedSeparator = pinnedHeaderCell.querySelector(
`.${gridClasses['columnSeparator--resizable']}`,
)!;
const pinnedRightPosition = pinnedHeaderCell.getBoundingClientRect().right;

// resize right pinned column to the right
fireEvent.mouseDown(pinnedSeparator, { clientX: 100 });
fireEvent.mouseMove(pinnedSeparator, { clientX: 150, buttons: 1 });

// check that the right pinned column has shrunk and is in the same position
expect(pinnedHeaderCell.getBoundingClientRect().width).to.equal(50);
expect(pinnedCell.getBoundingClientRect().width).to.equal(50);
expect(pinnedHeaderCell.getBoundingClientRect().right).to.equal(pinnedRightPosition);

// release the mouse and check that the right pinned column is still in the same position
fireEvent.mouseUp(pinnedSeparator);
expect(pinnedHeaderCell.getBoundingClientRect().width).to.equal(50);
expect(pinnedCell.getBoundingClientRect().width).to.equal(50);
expect(pinnedHeaderCell.getBoundingClientRect().right).to.equal(pinnedRightPosition);

// resize the right pinned column to the left
fireEvent.mouseDown(pinnedSeparator, { clientX: 150 });
fireEvent.mouseMove(pinnedSeparator, { clientX: 50, buttons: 1 });

// check that the right pinned column has grown and is in the same position
expect(pinnedHeaderCell.getBoundingClientRect().width).to.equal(150);
expect(pinnedCell.getBoundingClientRect().width).to.equal(150);
expect(pinnedHeaderCell.getBoundingClientRect().right).to.equal(pinnedRightPosition);

// release the mouse and check that the right pinned column is still in the same position
fireEvent.mouseUp(pinnedSeparator);
expect(pinnedHeaderCell.getBoundingClientRect().width).to.equal(150);
expect(pinnedCell.getBoundingClientRect().width).to.equal(150);
expect(pinnedHeaderCell.getBoundingClientRect().right).to.equal(pinnedRightPosition);
});

// https://github.com/mui/mui-x/issues/13548
it('should fill remaining horizontal space in a row with an empty cell', () => {
render(<Test columns={[{ field: 'id', width: 100 }]} />);

const row = getRow(0);
const rowWidth = row.getBoundingClientRect().width;
const headerCell = getColumnHeaderCell(0);
const separator = headerCell.querySelector(`.${gridClasses['columnSeparator--resizable']}`)!;
const emptyCell = row.querySelector(`.${gridClasses.cellEmpty}`)!;

// check that empty cell takes up the remaining width in a row
expect(emptyCell.getBoundingClientRect().width).to.equal(rowWidth - 100);

// check that empty cell takes up the remaining width when the column is resized
fireEvent.mouseDown(separator, { clientX: 100 });
fireEvent.mouseMove(separator, { clientX: 50, buttons: 1 });
expect(emptyCell.getBoundingClientRect().width).to.equal(rowWidth - 50);

// release the mouse and check that the empty cell still takes up the remaining width
fireEvent.mouseUp(separator);
expect(emptyCell.getBoundingClientRect().width).to.equal(rowWidth - 50);
});

describe('flex resizing', () => {
before(function beforeHook() {
if (isJSDOM) {
Expand Down
29 changes: 1 addition & 28 deletions packages/x-data-grid/src/components/GridRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,28 +69,6 @@ export interface GridRowProps extends React.HTMLAttributes<HTMLDivElement> {
[x: `data-${string}`]: string;
}

function EmptyCell({ width }: { width: number }) {
if (!width) {
return null;
}

return (
<div
role="presentation"
className={clsx(gridClasses.cell, gridClasses.cellEmpty)}
style={{ '--width': `${width}px` } as React.CSSProperties}
/>
);
}

EmptyCell.propTypes = {
// ----------------------------- Warning --------------------------------
// | These PropTypes are generated from the TypeScript type definitions |
// | To update them edit the TypeScript types and run "pnpm proptypes" |
// ----------------------------------------------------------------------
width: PropTypes.number.isRequired,
} as any;

const GridRow = forwardRef<HTMLDivElement, GridRowProps>(function GridRow(props, refProp) {
const {
selected,
Expand Down Expand Up @@ -464,10 +442,6 @@ const GridRow = forwardRef<HTMLDivElement, GridRowProps>(function GridRow(props,
}
: null;

const expandedWidth =
dimensions.viewportOuterSize.width - dimensions.columnsTotalWidth - scrollbarWidth;
const emptyCellWidth = Math.max(0, expandedWidth);

return (
<div
data-id={rowId}
Expand All @@ -487,8 +461,7 @@ const GridRow = forwardRef<HTMLDivElement, GridRowProps>(function GridRow(props,
style={{ width: offsetLeft }}
/>
{cells}
{emptyCellWidth > 0 && <EmptyCell width={emptyCellWidth} />}
{rightCells.length > 0 && <div role="presentation" className={gridClasses.filler} />}
<div role="presentation" className={clsx(gridClasses.cell, gridClasses.cellEmpty)} />
{rightCells}
{scrollbarWidth !== 0 && <ScrollbarFiller pinnedRight={pinnedColumns.right.length > 0} />}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,7 @@ export const GridRootStyles = styled('div', {
lineHeight: 'inherit',
},
[`& .${c.cellEmpty}`]: {
flex: 1,
padding: 0,
height: 'unset',
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,14 @@ export const useGridColumnResize = (
const prevWidth = refs.columnHeaderElement!.offsetWidth;
const widthDiff = newWidth - prevWidth;
const columnWidthDiff = newWidth - refs.initialColWidth;
const newTotalWidth = refs.initialTotalWidth + columnWidthDiff;

apiRef.current.rootElementRef?.current?.style.setProperty(
'--DataGrid-rowWidth',
`${newTotalWidth}px`,
);
if (columnWidthDiff > 0) {
const newTotalWidth = refs.initialTotalWidth + columnWidthDiff;
apiRef.current.rootElementRef?.current?.style.setProperty(
'--DataGrid-rowWidth',
`${newTotalWidth}px`,
);
}

refs.colDef!.computedWidth = newWidth;
refs.colDef!.width = newWidth;
Expand Down
4 changes: 3 additions & 1 deletion packages/x-data-grid/src/tests/rows.DataGrid.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
GridRenderCellParams,
useGridApiRef,
GridApi,
gridClasses,
} from '@mui/x-data-grid';
import { getBasicGridData } from '@mui/x-data-grid-generator';
import {
Expand All @@ -32,6 +33,7 @@ import {
getActiveCell,
getCell,
microtasks,
$$,
} from 'test/utils/helperFn';
import { fireUserEvent } from 'test/utils/fireUserEvent';
import Dialog from '@mui/material/Dialog';
Expand Down Expand Up @@ -756,7 +758,7 @@ describe('<DataGrid /> - Rows', () => {
width={100}
/>,
);
expect(document.querySelectorAll('.MuiDataGrid-cell')).to.have.length(2);
expect($$(`.${gridClasses.cell}:not(.${gridClasses.cellEmpty})`)).to.have.length(2);
});

it('should measure rows while scrolling', async () => {
Expand Down
26 changes: 26 additions & 0 deletions test/regressions/data-grid/DataGridBordered.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as React from 'react';
import { DataGridPro } from '@mui/x-data-grid-pro';
import { randomTraderName, randomEmail } from '@mui/x-data-grid-generator';

const columns = [
{ field: 'name', headerName: 'Name', width: 160 },
{ field: 'email', headerName: 'Email', width: 200 },
{ field: 'age', headerName: 'Age', type: 'number' },
];

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

export default function DataGridBordered() {
return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPro rows={rows} columns={columns} showCellVerticalBorder showColumnVerticalBorder />
</div>
);
}
32 changes: 32 additions & 0 deletions test/regressions/data-grid/DataGridPinnedColumnsBordered.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import { DataGridPro } from '@mui/x-data-grid-pro';
import { randomTraderName, randomEmail } from '@mui/x-data-grid-generator';

const columns = [
{ field: 'name', headerName: 'Name', width: 160 },
{ field: 'email', headerName: 'Email', width: 200 },
{ field: 'age', headerName: 'Age', type: 'number' },
];

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

export default function DataGridPinnedColumnsBordered() {
return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPro
rows={rows}
columns={columns}
initialState={{ pinnedColumns: { left: ['name'], right: ['age'] } }}
showCellVerticalBorder
showColumnVerticalBorder
/>
</div>
);
}
134 changes: 134 additions & 0 deletions test/regressions/data-grid/DataGridPinnedColumnsScrollbars.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
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(),
},
{
id: 2,
name: randomTraderName(),
email: randomEmail(),
age: 32,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
{
id: 3,
name: randomTraderName(),
email: randomEmail(),
age: 45,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
{
id: 4,
name: randomTraderName(),
email: randomEmail(),
age: 28,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
{
id: 5,
name: randomTraderName(),
email: randomEmail(),
age: 39,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
{
id: 6,
name: randomTraderName(),
email: randomEmail(),
age: 52,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
{
id: 7,
name: randomTraderName(),
email: randomEmail(),
age: 33,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
{
id: 8,
name: randomTraderName(),
email: randomEmail(),
age: 41,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
{
id: 9,
name: randomTraderName(),
email: randomEmail(),
age: 36,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
{
id: 10,
name: randomTraderName(),
email: randomEmail(),
age: 29,
dateCreated: randomCreatedDate(),
lastLogin: randomUpdatedDate(),
},
];

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