Skip to content

Commit

Permalink
fix row pinning with column virtualization
Browse files Browse the repository at this point in the history
  • Loading branch information
cherniavskii committed Jun 17, 2022
1 parent e4a3c09 commit ff42b31
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 5 deletions.
63 changes: 63 additions & 0 deletions docs/data/data-grid/rows/RowPinningWithVirtualization.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import * as React from 'react';
import { DataGridPro } from '@mui/x-data-grid-pro';

function useData(rowLength, columnLength) {
const [data, setData] = React.useState({ columns: [], rows: [] });

React.useEffect(() => {
const rows = [];

for (let i = 0; i < rowLength; i += 1) {
const row = {
id: i,
};

for (let j = 1; j <= columnLength; j += 1) {
row[`price${j}M`] = `${i.toString()}, ${j} `;
}

rows.push(row);
}

const columns = [];

for (let j = 1; j <= columnLength; j += 1) {
columns.push({ field: `price${j}M`, headerName: `${j}M` });
}

setData({
rows,
columns,
});
}, [rowLength, columnLength]);

return data;
}

export default function RowPinningWithVirtualization() {
const data = useData(100, 1000);

console.log('data', data);

if (!data.rows.length) {
return null;
}

const [pinnedRow0, pinnedRow1, pinnedRow2, ...rows] = data.rows;

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPro
{...data}
rows={rows}
columnBuffer={2}
columnThreshold={2}
pinnedRows={{ top: [pinnedRow0, pinnedRow1], bottom: [pinnedRow2] }}
pinnedColumns={{
left: ['price1M', 'price67M'],
right: ['price31M', 'price2M'],
}}
/>
</div>
);
}
11 changes: 11 additions & 0 deletions docs/data/data-grid/rows/RowPinningWithVirtualization.preview
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<DataGridPro
{...data}
rows={rows}
columnBuffer={2}
columnThreshold={2}
pinnedRows={{ top: [pinnedRow0, pinnedRow1], bottom: [pinnedRow2] }}
pinnedColumns={{
left: ['price1M', 'price67M'],
right: ['price31M', 'price2M'],
}}
/>
73 changes: 73 additions & 0 deletions docs/data/data-grid/rows/RowPinningWithVirtualization.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import * as React from 'react';
import { DataGridPro, GridColDef, GridRowId } from '@mui/x-data-grid-pro';

export interface DataRowModel {
id: GridRowId;
[price: string]: number | string;
}

export interface GridData {
columns: GridColDef[];
rows: DataRowModel[];
}

function useData(rowLength: number, columnLength: number) {
const [data, setData] = React.useState<GridData>({ columns: [], rows: [] });

React.useEffect(() => {
const rows: DataRowModel[] = [];

for (let i = 0; i < rowLength; i += 1) {
const row: DataRowModel = {
id: i,
};

for (let j = 1; j <= columnLength; j += 1) {
row[`price${j}M`] = `${i.toString()}, ${j} `;
}

rows.push(row);
}

const columns: GridColDef[] = [];

for (let j = 1; j <= columnLength; j += 1) {
columns.push({ field: `price${j}M`, headerName: `${j}M` });
}

setData({
rows,
columns,
});
}, [rowLength, columnLength]);

return data;
}

export default function RowPinningWithVirtualization() {
const data = useData(100, 1000);

console.log('data', data);

if (!data.rows.length) {
return null;
}

const [pinnedRow0, pinnedRow1, pinnedRow2, ...rows] = data.rows;

return (
<div style={{ height: 400, width: '100%' }}>
<DataGridPro
{...data}
rows={rows}
columnBuffer={2}
columnThreshold={2}
pinnedRows={{ top: [pinnedRow0, pinnedRow1], bottom: [pinnedRow2] }}
pinnedColumns={{
left: ['price1M', 'price67M'],
right: ['price31M', 'price2M'],
}}
/>
</div>
);
}
6 changes: 5 additions & 1 deletion docs/data/data-grid/rows/rows.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,14 @@ Pinned (or frozen, locked, or sticky) rows are rows that are visible at all time

{{"demo": "RowPinning.js", "disableAd": true, "bg": "inline"}}

Interactive demo using `actions` column
Interactive demo with row pinning `actions` column:

{{"demo": "RowPinningWithActions.js", "disableAd": true, "bg": "inline", "defaultCodeOpen": false}}

With virtualization:

{{"demo": "RowPinningWithVirtualization.js", "disableAd": true, "bg": "inline", "defaultCodeOpen": false}}

## 🚧 Row spanning

:::warning
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ const useUtilityClasses = (ownerState: OwnerState) => {
],
topPinnedRows: ['pinnedRows', topPinnedRowsCount > 0 && 'pinnedRows--top'],
bottomPinnedRows: ['pinnedRows', bottomPinnedRowsCount > 0 && 'pinnedRows--bottom'],
pinnedRowsRenderZone: ['pinnedRowsRenderZone'],
detailPanels: ['detailPanels'],
detailPanel: ['detailPanel'],
};
Expand Down Expand Up @@ -168,10 +169,10 @@ const VirtualScrollerPinnedRows = styled('div', {
overridesResolver: (props, styles) => [
{ [`&.${gridClasses['pinnedRows--top']}`]: styles['pinnedRows--top'] },
{ [`&.${gridClasses['pinnedRows--bottom']}`]: styles['pinnedRows--bottom'] },
styles.pinnedColumns,
styles.pinnedRows,
],
})<{ ownerState: { position: 'top' | 'bottom' } }>(({ theme, ownerState }) => ({
display: 'flex',
display: 'flow-root', // TODO: Find another solution?
position: 'sticky',
// should be above the detail panel
zIndex: 3,
Expand All @@ -187,6 +188,10 @@ const VirtualScrollerPinnedRows = styled('div', {
}),
}));

const VirtualScrollerPinnedRowsRenderZone = styled('div')({
position: 'absolute',
});

interface DataGridProVirtualScrollerProps extends React.HTMLAttributes<HTMLDivElement> {
disableVirtualization?: boolean;
}
Expand Down Expand Up @@ -383,7 +388,9 @@ const DataGridProVirtualScroller = React.forwardRef<
})}
</VirtualScrollerPinnedColumns>
)}
<div>{topPinnedRows}</div>
<VirtualScrollerPinnedRowsRenderZone className={classes.pinnedRowsRenderZone}>
{topPinnedRows}
</VirtualScrollerPinnedRowsRenderZone>
{rightRenderContext && (
<VirtualScrollerPinnedColumns
className={classes.rightPinnedColumns}
Expand Down Expand Up @@ -467,7 +474,9 @@ const DataGridProVirtualScroller = React.forwardRef<
})}
</VirtualScrollerPinnedColumns>
)}
<div>{bottomPinnedRows}</div>
<VirtualScrollerPinnedRowsRenderZone className={classes.pinnedRowsRenderZone}>
{bottomPinnedRows}
</VirtualScrollerPinnedRowsRenderZone>
{rightRenderContext && (
<VirtualScrollerPinnedColumns
className={classes.rightPinnedColumns}
Expand Down
5 changes: 5 additions & 0 deletions packages/grid/x-data-grid/src/constants/gridClasses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,10 @@ export interface GridClasses {
* Styles applied to the bottom pinned rows container.
*/
'pinnedRows--bottom': string;
/**
* @ignore - do not document
*/
pinnedRowsRenderZone: string;
}

export type GridClassKey = keyof GridClasses;
Expand Down Expand Up @@ -551,4 +555,5 @@ export const gridClasses = generateUtilityClasses<GridClassKey>('MuiDataGrid', [
'pinnedRows',
'pinnedRows--top',
'pinnedRows--bottom',
'pinnedRowsRenderZone',
]);
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { GridRowId, GridRowModel } from '../../../models/gridRows';
import { getFirstNonSpannedColumnToRender } from '../columns/gridColumnsUtils';
import { gridRowsLookupSelector } from '../rows/gridRowsSelector';
import { getRowIdFromRowModel } from '../rows/gridRowsUtils';
import { gridClasses } from '../../../constants/gridClasses';

// Uses binary search to avoid looping through all possible positions
export function binarySearch(
Expand Down Expand Up @@ -251,6 +252,15 @@ export const useGridVirtualScroller = (props: UseGridVirtualScrollerProps) => {
const left = gridColumnPositionsSelector(apiRef)[firstColumnToRender]; // Call directly the selector because it might be outdated when this method is called
renderZoneRef.current!.style.transform = `translate3d(${left}px, ${top}px, 0px)`;

// update pinned rows render zones
apiRef.current
.rootElementRef!.current!.querySelectorAll<HTMLElement>(
`.${gridClasses.pinnedRowsRenderZone}`,
)
.forEach((element) => {
element.style.transform = `translate3d(${left}px, 0px, 0px)`;
});

if (typeof onRenderZonePositioning === 'function') {
onRenderZonePositioning({ top, left });
}
Expand Down

0 comments on commit ff42b31

Please sign in to comment.