Skip to content

Commit

Permalink
[DataGrid] New virtualization implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
m4theushw committed Oct 12, 2021
1 parent 4db8ce3 commit 43b31b9
Show file tree
Hide file tree
Showing 40 changed files with 834 additions and 1,251 deletions.
5 changes: 0 additions & 5 deletions docs/pages/api-docs/data-grid/data-grid-pro.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ You can use the [slots API](/components/data-grid/components/#overriding-compone
| <span class="prop-name">columnSeparator--resizable</span> | <span class="prop-name">.MuiDataGrid-columnSeparator--resizable</span> | Styles applied to the column header separator if the column is resizable. |
| <span class="prop-name">columnSeparator--resizing</span> | <span class="prop-name">.MuiDataGrid-columnSeparator--resizing</span> | Styles applied to the column header separator if the column is being resized. |
| <span class="prop-name">columnSeparator</span> | <span class="prop-name">.MuiDataGrid-columnSeparator</span> | Styles applied to the column header separator element. |
| <span class="prop-name">dataContainer</span> | <span class="prop-name">.MuiDataGrid-dataContainer</span> | Styles applied to the data container element. |
| <span class="prop-name">editBooleanCell</span> | <span class="prop-name">.MuiDataGrid-editBooleanCell</span> | Styles applied to root of the boolean edit component. |
| <span class="prop-name">editInputCell</span> | <span class="prop-name">.MuiDataGrid-editInputCell</span> | Styles applied to the root of the input component. |
| <span class="prop-name">filterIcon</span> | <span class="prop-name">.MuiDataGrid-filterIcon</span> | Styles applied to the filter icon element. |
Expand All @@ -198,7 +197,6 @@ You can use the [slots API](/components/data-grid/components/#overriding-compone
| <span class="prop-name">menuIconButton</span> | <span class="prop-name">.MuiDataGrid-menuIconButton</span> | Styles applied to the menu icon button element. |
| <span class="prop-name">menuOpen</span> | <span class="prop-name">.MuiDataGrid-menuOpen</span> | Styles applied to the menu icon element if the menu is open. |
| <span class="prop-name">overlay</span> | <span class="prop-name">.MuiDataGrid-overlay</span> | Styles applied to the overlay element. |
| <span class="prop-name">renderingZone</span> | <span class="prop-name">.MuiDataGrid-renderingZone</span> | Styles applied to the rendering zone element. |
| <span class="prop-name">root</span> | <span class="prop-name">.MuiDataGrid-root</span> | Styles applied to the root element. |
| <span class="prop-name">row--editable</span> | <span class="prop-name">.MuiDataGrid-row--editable</span> | Styles applied to the row element if the row is editable. |
| <span class="prop-name">row--editing</span> | <span class="prop-name">.MuiDataGrid-row--editing</span> | Styles applied to the row element if the row is in edit mode. |
Expand All @@ -210,9 +208,6 @@ You can use the [slots API](/components/data-grid/components/#overriding-compone
| <span class="prop-name">selectedRowCount</span> | <span class="prop-name">.MuiDataGrid-selectedRowCount</span> | Styles applied to the footer selected row count element. |
| <span class="prop-name">sortIcon</span> | <span class="prop-name">.MuiDataGrid-sortIcon</span> | Styles applied to the sort icon element. |
| <span class="prop-name">toolbarContainer</span> | <span class="prop-name">.MuiDataGrid-toolbarContainer</span> | Styles applied to the toolbar container element. |
| <span class="prop-name">viewport</span> | <span class="prop-name">.MuiDataGrid-viewport</span> | Styles applied to the viewport element. |
| <span class="prop-name">window</span> | <span class="prop-name">.MuiDataGrid-window</span> | Styles applied to the window element. |
| <span class="prop-name">windowContainer</span> | <span class="prop-name">.MuiDataGrid-windowContainer</span> | Styles applied to the window container element. |
| <span class="prop-name">withBorder</span> | <span class="prop-name">.MuiDataGrid-withBorder</span> | Styles applied to both the cell and the column header if `showColumnRightBorder={true}`. |

You can override the style of the component thanks to one of these customization points:
Expand Down
5 changes: 0 additions & 5 deletions docs/pages/api-docs/data-grid/data-grid.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,6 @@ You can use the [slots API](/components/data-grid/components/#overriding-compone
| <span class="prop-name">columnSeparator--resizable</span> | <span class="prop-name">.MuiDataGrid-columnSeparator--resizable</span> | Styles applied to the column header separator if the column is resizable. |
| <span class="prop-name">columnSeparator--resizing</span> | <span class="prop-name">.MuiDataGrid-columnSeparator--resizing</span> | Styles applied to the column header separator if the column is being resized. |
| <span class="prop-name">columnSeparator</span> | <span class="prop-name">.MuiDataGrid-columnSeparator</span> | Styles applied to the column header separator element. |
| <span class="prop-name">dataContainer</span> | <span class="prop-name">.MuiDataGrid-dataContainer</span> | Styles applied to the data container element. |
| <span class="prop-name">editBooleanCell</span> | <span class="prop-name">.MuiDataGrid-editBooleanCell</span> | Styles applied to root of the boolean edit component. |
| <span class="prop-name">editInputCell</span> | <span class="prop-name">.MuiDataGrid-editInputCell</span> | Styles applied to the root of the input component. |
| <span class="prop-name">filterIcon</span> | <span class="prop-name">.MuiDataGrid-filterIcon</span> | Styles applied to the filter icon element. |
Expand All @@ -186,7 +185,6 @@ You can use the [slots API](/components/data-grid/components/#overriding-compone
| <span class="prop-name">menuIconButton</span> | <span class="prop-name">.MuiDataGrid-menuIconButton</span> | Styles applied to the menu icon button element. |
| <span class="prop-name">menuOpen</span> | <span class="prop-name">.MuiDataGrid-menuOpen</span> | Styles applied to the menu icon element if the menu is open. |
| <span class="prop-name">overlay</span> | <span class="prop-name">.MuiDataGrid-overlay</span> | Styles applied to the overlay element. |
| <span class="prop-name">renderingZone</span> | <span class="prop-name">.MuiDataGrid-renderingZone</span> | Styles applied to the rendering zone element. |
| <span class="prop-name">root</span> | <span class="prop-name">.MuiDataGrid-root</span> | Styles applied to the root element. |
| <span class="prop-name">row--editable</span> | <span class="prop-name">.MuiDataGrid-row--editable</span> | Styles applied to the row element if the row is editable. |
| <span class="prop-name">row--editing</span> | <span class="prop-name">.MuiDataGrid-row--editing</span> | Styles applied to the row element if the row is in edit mode. |
Expand All @@ -198,9 +196,6 @@ You can use the [slots API](/components/data-grid/components/#overriding-compone
| <span class="prop-name">selectedRowCount</span> | <span class="prop-name">.MuiDataGrid-selectedRowCount</span> | Styles applied to the footer selected row count element. |
| <span class="prop-name">sortIcon</span> | <span class="prop-name">.MuiDataGrid-sortIcon</span> | Styles applied to the sort icon element. |
| <span class="prop-name">toolbarContainer</span> | <span class="prop-name">.MuiDataGrid-toolbarContainer</span> | Styles applied to the toolbar container element. |
| <span class="prop-name">viewport</span> | <span class="prop-name">.MuiDataGrid-viewport</span> | Styles applied to the viewport element. |
| <span class="prop-name">window</span> | <span class="prop-name">.MuiDataGrid-window</span> | Styles applied to the window element. |
| <span class="prop-name">windowContainer</span> | <span class="prop-name">.MuiDataGrid-windowContainer</span> | Styles applied to the window container element. |
| <span class="prop-name">withBorder</span> | <span class="prop-name">.MuiDataGrid-withBorder</span> | Styles applied to both the cell and the column header if `showColumnRightBorder={true}`. |

You can override the style of the component thanks to one of these customization points:
Expand Down
1 change: 1 addition & 0 deletions docs/scripts/generateProptypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ async function generateProptypes(program: ttp.ts.Program, sourceFile: string) {
'renderedColumns',
'scrollBarState',
'renderState',
'visibleColumns',
'cellFocus',
'cellTabIndex',
];
Expand Down
59 changes: 0 additions & 59 deletions packages/grid/_modules_/grid/components/GridRenderingZone.tsx

This file was deleted.

92 changes: 54 additions & 38 deletions packages/grid/_modules_/grid/components/GridRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,32 @@ import { composeClasses } from '../utils/material-ui-utils';
import { getDataGridUtilityClass, gridClasses } from '../gridClasses';
import { useGridRootProps } from '../hooks/utils/useGridRootProps';
import { GridComponentProps } from '../GridComponentProps';
import { GridStateColDef } from '../models/colDef/gridColDef';
import { GridCellIdentifier } from '../hooks/features/focus/gridFocusState';
import { GridScrollBarState } from '../models/gridContainerProps';
import { GridStateColDef } from '../models/colDef/gridColDef';
import { GridEmptyCell } from './cell/GridEmptyCell';
import { GridRenderingState } from '../hooks/features/virtualization/renderingState';
import { gridColumnsMetaSelector } from '../hooks/features/columns/gridColumnsSelector';
import { useGridSelector } from '../hooks/features/core/useGridSelector';

export interface GridRowProps {
id: GridRowId;
rowId: GridRowId;
selected: boolean;
index: number;
rowHeight: number;
containerWidth: number;
row: GridRowData;
renderState: GridRenderingState;
firstColumnToRender: number;
lastColumnToRender: number;
visibleColumns: GridStateColDef[];
renderedColumns: GridStateColDef[];
children: React.ReactNode;
cellFocus: GridCellIdentifier | null;
cellTabIndex: GridCellIdentifier | null;
editRowsModel: GridEditRowsModel;
editRowsState: GridEditRowsModel;
scrollBarState: GridScrollBarState;
onClick?: React.MouseEventHandler<HTMLDivElement>;
onDoubleClick?: React.MouseEventHandler<HTMLDivElement>;
}

type OwnerState = GridRowProps & {
type OwnerState = Pick<GridRowProps, 'selected'> & {
editable: boolean;
editing: boolean;
classes?: GridComponentProps['classes'];
Expand All @@ -51,33 +52,47 @@ const useUtilityClasses = (ownerState: OwnerState) => {
return composeClasses(slots, getDataGridUtilityClass, classes);
};

function GridRow(props: GridRowProps) {
const EmptyCell = ({ width, height }) => {
if (!width || !height) {
return null;
}

const style = { width, height };

return <div className="MuiDataGrid-cell" style={style} />; // TODO change to .MuiDataGrid-emptyCell or .MuiDataGrid-rowFiller
};

function GridRow(props: React.HTMLAttributes<HTMLDivElement> & GridRowProps) {
const {
selected,
id,
rowId,
row,
index,
style: styleProp,
rowHeight,
className,
visibleColumns,
renderedColumns,
containerWidth,
firstColumnToRender,
children,
lastColumnToRender,
cellFocus,
cellTabIndex,
editRowsModel,
editRowsState,
scrollBarState, // to be removed
renderState, // to be removed
onClick,
onDoubleClick,
...other
} = props;
const ariaRowIndex = index + 2; // 1 for the header row and 1 as it's 1 based
const ariaRowIndex = index + 2; // 1 for the header row and 1 as it's 1-based
const apiRef = useGridApiContext();
const rootProps = useGridRootProps();
const columnsMeta = useGridSelector(apiRef, gridColumnsMetaSelector);

const ownerState = {
...props,
selected,
classes: rootProps.classes,
editing: apiRef.current.getRowMode(id) === GridRowModes.Edit,
editing: apiRef.current.getRowMode(rowId) === GridRowModes.Edit,
editable: rootProps.editMode === GridEditModes.Row,
};

Expand All @@ -96,42 +111,43 @@ function GridRow(props: GridRowProps) {
}

// The row might have been deleted
if (!apiRef.current.getRow(id)) {
if (!apiRef.current.getRow(rowId)) {
return;
}

apiRef.current.publishEvent(eventName, apiRef.current.getRowParams(id), event);
apiRef.current.publishEvent(eventName, apiRef.current.getRowParams(rowId), event);

if (propHandler) {
propHandler(event);
}
},
[apiRef, id],
[apiRef, rowId],
);

const style = {
maxHeight: rowHeight,
minHeight: rowHeight,
...styleProp,
};

const rowClassName =
typeof rootProps.getRowClassName === 'function' &&
rootProps.getRowClassName(apiRef.current.getRowParams(id));
rootProps.getRowClassName(apiRef.current.getRowParams(rowId));

const cells: JSX.Element[] = [];

for (let i = 0; i < renderedColumns.length; i += 1) {
const column = renderedColumns[i];
const indexRelativeToAllColumns = firstColumnToRender + i;

const isLastColumn = indexRelativeToAllColumns === renderedColumns.length - 1;
const isLastColumn = indexRelativeToAllColumns === visibleColumns.length - 1;
const removeLastBorderRight =
isLastColumn && scrollBarState.hasScrollX && !scrollBarState.hasScrollY;
const showRightBorder = !isLastColumn
? rootProps.showCellRightBorder
: !removeLastBorderRight && rootProps.disableExtendRowFullWidth;

const cellParams = apiRef.current.getCellParams(id, column.field);
const cellParams = apiRef.current.getCellParams(rowId, column.field);

const classNames: string[] = [];

Expand All @@ -145,7 +161,7 @@ function GridRow(props: GridRowProps) {
);
}

const editCellState = editRowsModel[id] && editRowsModel[id][column.field];
const editCellState = editRowsState[rowId] ? editRowsState[rowId][column.field] : null;
let content: React.ReactNode = null;

if (editCellState == null && column.renderCell) {
Expand All @@ -168,23 +184,24 @@ function GridRow(props: GridRowProps) {
classNames.push(rootProps.getCellClassName(cellParams));
}

const hasFocus = cellFocus !== null && cellFocus.id === id && cellFocus.field === column.field;
const hasFocus =
cellFocus !== null && cellFocus.id === rowId && cellFocus.field === column.field;

const tabIndex =
cellTabIndex !== null &&
cellTabIndex.id === id &&
cellTabIndex.id === rowId &&
cellTabIndex.field === column.field &&
cellParams.cellMode === 'view'
? 0
: -1;

cells.push(
<rootProps.components.Cell
key={column.field} // This is wrong. The key should be the index so the cells can be recycled.
key={i}
value={cellParams.value}
field={column.field}
width={column.computedWidth}
rowId={id}
rowId={rowId}
height={rowHeight}
showRightBorder={showRightBorder}
formattedValue={cellParams.formattedValue}
Expand All @@ -202,23 +219,23 @@ function GridRow(props: GridRowProps) {
);
}

const emptyCellWidth = containerWidth - columnsMeta.totalWidth;

return (
<div
key={id}
data-id={id}
data-id={rowId}
data-rowindex={index}
role="row"
className={clsx(rowClassName, classes.root)}
className={clsx(rowClassName, classes.root, className)}
aria-rowindex={ariaRowIndex}
aria-selected={selected}
style={style}
onClick={publish(GridEvents.rowClick, onClick)}
onDoubleClick={publish(GridEvents.rowDoubleClick, onDoubleClick)}
{...other}
>
<GridEmptyCell width={renderState.renderContext!.leftEmptyWidth} height={rowHeight} />
{cells}
<GridEmptyCell width={renderState.renderContext!.rightEmptyWidth} height={rowHeight} />
{emptyCellWidth > 0 && <EmptyCell width={emptyCellWidth} height={rowHeight} />}
</div>
);
}
Expand All @@ -230,19 +247,18 @@ GridRow.propTypes = {
// ----------------------------------------------------------------------
cellFocus: PropTypes.object,
cellTabIndex: PropTypes.object,
children: PropTypes.node,
editRowsModel: PropTypes.object.isRequired,
containerWidth: PropTypes.number.isRequired,
editRowsState: PropTypes.object.isRequired,
firstColumnToRender: PropTypes.number.isRequired,
id: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
index: PropTypes.number.isRequired,
onClick: PropTypes.func,
onDoubleClick: PropTypes.func,
lastColumnToRender: PropTypes.number.isRequired,
renderedColumns: PropTypes.arrayOf(PropTypes.object).isRequired,
renderState: PropTypes.object.isRequired,
row: PropTypes.object.isRequired,
rowHeight: PropTypes.number.isRequired,
rowId: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
scrollBarState: PropTypes.object.isRequired,
selected: PropTypes.bool.isRequired,
visibleColumns: PropTypes.arrayOf(PropTypes.object).isRequired,
} as any;

export { GridRow };
7 changes: 5 additions & 2 deletions packages/grid/_modules_/grid/components/GridScrollArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { getDataGridUtilityClass } from '../gridClasses';
import { composeClasses } from '../utils/material-ui-utils';
import { useGridRootProps } from '../hooks/utils/useGridRootProps';
import { GridComponentProps } from '../GridComponentProps';
import { gridDensityHeaderHeightSelector } from '../hooks/features/density/densitySelector';
import { useGridSelector } from '../hooks/features/core/useGridSelector';

const CLIFF = 1;
const SLOP = 1.5;
Expand All @@ -24,7 +26,7 @@ const useUtilityClasses = (ownerState: OwnerState) => {
const { scrollDirection, classes } = ownerState;

const slots = {
root: ['scrollArea', `scrollArea__${scrollDirection}`],
root: ['scrollArea', `scrollArea--${scrollDirection}`],
};

return composeClasses(slots, getDataGridUtilityClass, classes);
Expand All @@ -36,6 +38,7 @@ function GridScrollAreaRaw(props: ScrollAreaProps) {
const apiRef = useGridApiContext();
const timeout = React.useRef<any>();
const [dragging, setDragging] = React.useState<boolean>(false);
const height = useGridSelector(apiRef, gridDensityHeaderHeightSelector);
const scrollPosition = React.useRef<GridScrollParams>({
left: 0,
top: 0,
Expand Down Expand Up @@ -90,7 +93,7 @@ function GridScrollAreaRaw(props: ScrollAreaProps) {
useGridApiEventHandler(apiRef, GridEvents.columnHeaderDragEnd, toggleDragging);

return dragging ? (
<div ref={rootRef} className={classes.root} onDragOver={handleDragOver} />
<div ref={rootRef} className={classes.root} onDragOver={handleDragOver} style={{ height }} />
) : null;
}

Expand Down
Loading

0 comments on commit 43b31b9

Please sign in to comment.