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 column resize #12792

Merged
merged 3 commits into from
Apr 17, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
unstable_ownerDocument as ownerDocument,
unstable_useEventCallback as useEventCallback,
} from '@mui/utils';
import useLazyRef from '@mui/utils/useLazyRef';
import { useTheme, Direction } from '@mui/material/styles';
import {
findGridCellElementsFromCol,
Expand Down Expand Up @@ -264,6 +265,26 @@ export const columnResizeStateInitializer: GridStateInitializer = (state) => ({
...state,
columnResize: { resizingColumnField: '' },
});

function createResizeRefs() {
return {
colDef: undefined as undefined | GridStateColDef,
initialColWidth: 0,
initialTotalWidth: 0,
previousMouseClickEvent: undefined as undefined | MouseEvent,
columnHeaderElement: undefined as undefined | HTMLDivElement,
headerFilterElement: undefined as undefined | HTMLDivElement,
groupHeaderElements: [] as Element[],
cellElements: [] as Element[],
leftPinnedCellsAfter: [] as HTMLElement[],
rightPinnedCellsBefore: [] as HTMLElement[],
fillerLeft: undefined as undefined | HTMLElement,
fillerRight: undefined as undefined | HTMLElement,
leftPinnedHeadersAfter: [] as HTMLElement[],
rightPinnedHeadersBefore: [] as HTMLElement[],
};
}

/**
* @requires useGridColumns (method, event)
* TODO: improve experience for last column
Expand All @@ -282,18 +303,7 @@ export const useGridColumnResize = (
const theme = useTheme();
const logger = useGridLogger(apiRef, 'useGridColumnResize');

const colDefRef = React.useRef<GridStateColDef>();
const previousMouseClickEvent = React.useRef<MouseEvent>();
const columnHeaderElementRef = React.useRef<HTMLDivElement>();
const headerFilterElementRef = React.useRef<HTMLDivElement>();
const groupHeaderElementsRef = React.useRef<Element[]>([]);
const cellElementsRef = React.useRef<Element[]>([]);
const leftPinnedCellsAfterRef = React.useRef<HTMLElement[]>([]);
const rightPinnedCellsBeforeRef = React.useRef<HTMLElement[]>([]);
const fillerLeftRef = React.useRef<HTMLElement>();
const fillerRightRef = React.useRef<HTMLElement>();
const leftPinnedHeadersAfterRef = React.useRef<HTMLElement[]>([]);
const rightPinnedHeadersBeforeRef = React.useRef<HTMLElement[]>([]);
const refs = useLazyRef(createResizeRefs).current;

// To improve accessibility, the separator has padding on both sides.
// Clicking inside the padding area should be treated as a click in the separator.
Expand All @@ -305,27 +315,34 @@ export const useGridColumnResize = (
const touchId = React.useRef<number>();

const updateWidth = (newWidth: number) => {
logger.debug(`Updating width to ${newWidth} for col ${colDefRef.current!.field}`);
logger.debug(`Updating width to ${newWidth} for col ${refs.colDef!.field}`);

const prevWidth = columnHeaderElementRef.current!.offsetWidth;
const prevWidth = refs.columnHeaderElement!.offsetWidth;
const widthDiff = newWidth - prevWidth;
const columnWidthDiff = newWidth - refs.initialColWidth;
const newTotalWidth = refs.initialTotalWidth + columnWidthDiff;

colDefRef.current!.computedWidth = newWidth;
colDefRef.current!.width = newWidth;
colDefRef.current!.flex = 0;
apiRef.current.rootElementRef?.current?.style.setProperty(
'--DataGrid-rowWidth',
`${newTotalWidth}px`,
);

refs.colDef!.computedWidth = newWidth;
refs.colDef!.width = newWidth;
refs.colDef!.flex = 0;

columnHeaderElementRef.current!.style.width = `${newWidth}px`;
columnHeaderElementRef.current!.style.minWidth = `${newWidth}px`;
columnHeaderElementRef.current!.style.maxWidth = `${newWidth}px`;
refs.columnHeaderElement!.style.width = `${newWidth}px`;
refs.columnHeaderElement!.style.minWidth = `${newWidth}px`;
refs.columnHeaderElement!.style.maxWidth = `${newWidth}px`;

const headerFilterElement = headerFilterElementRef.current;
const headerFilterElement = refs.headerFilterElement;
if (headerFilterElement) {
headerFilterElement.style.width = `${newWidth}px`;
headerFilterElement.style.minWidth = `${newWidth}px`;
headerFilterElement.style.maxWidth = `${newWidth}px`;
}

groupHeaderElementsRef.current!.forEach((element) => {
refs.groupHeaderElements!.forEach((element) => {
const div = element as HTMLDivElement;
let finalWidth: `${number}px`;

Expand All @@ -342,7 +359,7 @@ export const useGridColumnResize = (
div.style.maxWidth = finalWidth;
});

cellElementsRef.current!.forEach((element) => {
refs.cellElements!.forEach((element) => {
const div = element as HTMLDivElement;
let finalWidth: `${number}px`;

Expand All @@ -360,27 +377,27 @@ export const useGridColumnResize = (
const pinnedPosition = apiRef.current.unstable_applyPipeProcessors(
'isColumnPinned',
false,
colDefRef.current!.field,
refs.colDef!.field,
);

if (pinnedPosition === GridPinnedColumnPosition.LEFT) {
updateProperty(fillerLeftRef.current, 'width', widthDiff);
updateProperty(refs.fillerLeft, 'width', widthDiff);

leftPinnedCellsAfterRef.current.forEach((cell) => {
refs.leftPinnedCellsAfter.forEach((cell) => {
updateProperty(cell, 'left', widthDiff);
});
leftPinnedHeadersAfterRef.current.forEach((header) => {
refs.leftPinnedHeadersAfter.forEach((header) => {
updateProperty(header, 'left', widthDiff);
});
}

if (pinnedPosition === GridPinnedColumnPosition.RIGHT) {
updateProperty(fillerRightRef.current, 'width', widthDiff);
updateProperty(refs.fillerRight, 'width', widthDiff);

rightPinnedCellsBeforeRef.current.forEach((cell) => {
refs.rightPinnedCellsBefore.forEach((cell) => {
updateProperty(cell, 'right', widthDiff);
});
rightPinnedHeadersBeforeRef.current.forEach((header) => {
refs.rightPinnedHeadersBefore.forEach((header) => {
updateProperty(header, 'right', widthDiff);
});
}
Expand All @@ -391,8 +408,8 @@ export const useGridColumnResize = (
stopListening();

// Prevent double-clicks from being interpreted as two separate clicks
if (previousMouseClickEvent.current) {
const prevEvent = previousMouseClickEvent.current;
if (refs.previousMouseClickEvent) {
const prevEvent = refs.previousMouseClickEvent;
const prevTimeStamp = prevEvent.timeStamp;
const prevClientX = prevEvent.clientX;
const prevClientY = prevEvent.clientY;
Expand All @@ -403,16 +420,14 @@ export const useGridColumnResize = (
nativeEvent.clientX === prevClientX &&
nativeEvent.clientY === prevClientY
) {
previousMouseClickEvent.current = undefined;
refs.previousMouseClickEvent = undefined;
return;
}
}

if (colDefRef.current) {
apiRef.current.setColumnWidth(colDefRef.current.field, colDefRef.current.width!);
logger.debug(
`Updating col ${colDefRef.current.field} with new width: ${colDefRef.current.width}`,
);
if (refs.colDef) {
apiRef.current.setColumnWidth(refs.colDef.field, refs.colDef.width!);
logger.debug(`Updating col ${refs.colDef.field} with new width: ${refs.colDef.width}`);
}

stopResizeEventTimeout.start(0, () => {
Expand All @@ -423,9 +438,12 @@ export const useGridColumnResize = (
const storeReferences = (colDef: GridStateColDef, separator: HTMLElement, xStart: number) => {
const root = apiRef.current.rootElementRef.current!;

colDefRef.current = colDef as GridStateColDef;
refs.initialColWidth = colDef.computedWidth;
refs.initialTotalWidth = apiRef.current.getRootDimensions().rowWidth;

columnHeaderElementRef.current = findHeaderElementFromField(
refs.colDef = colDef as GridStateColDef;

refs.columnHeaderElement = findHeaderElementFromField(
apiRef.current.columnHeadersContainerRef!.current!,
colDef.field,
);
Expand All @@ -434,51 +452,48 @@ export const useGridColumnResize = (
`.${gridClasses.headerFilterRow} [data-field="${colDef.field}"]`,
);
if (headerFilterElement) {
headerFilterElementRef.current = headerFilterElement as HTMLDivElement;
refs.headerFilterElement = headerFilterElement as HTMLDivElement;
}

groupHeaderElementsRef.current = findGroupHeaderElementsFromField(
refs.groupHeaderElements = findGroupHeaderElementsFromField(
apiRef.current.columnHeadersContainerRef?.current!,
colDef.field,
);

cellElementsRef.current = findGridCellElementsFromCol(
columnHeaderElementRef.current,
apiRef.current,
);
refs.cellElements = findGridCellElementsFromCol(refs.columnHeaderElement, apiRef.current);

fillerLeftRef.current = findGridElement(apiRef.current, 'filler--pinnedLeft');
fillerRightRef.current = findGridElement(apiRef.current, 'filler--pinnedRight');
refs.fillerLeft = findGridElement(apiRef.current, 'filler--pinnedLeft');
refs.fillerRight = findGridElement(apiRef.current, 'filler--pinnedRight');

const pinnedPosition = apiRef.current.unstable_applyPipeProcessors(
'isColumnPinned',
false,
colDefRef.current!.field,
refs.colDef!.field,
);

leftPinnedCellsAfterRef.current =
refs.leftPinnedCellsAfter =
pinnedPosition !== GridPinnedColumnPosition.LEFT
? []
: findLeftPinnedCellsAfterCol(apiRef.current, columnHeaderElementRef.current);
rightPinnedCellsBeforeRef.current =
: findLeftPinnedCellsAfterCol(apiRef.current, refs.columnHeaderElement);
refs.rightPinnedCellsBefore =
pinnedPosition !== GridPinnedColumnPosition.RIGHT
? []
: findRightPinnedCellsBeforeCol(apiRef.current, columnHeaderElementRef.current);
: findRightPinnedCellsBeforeCol(apiRef.current, refs.columnHeaderElement);

leftPinnedHeadersAfterRef.current =
refs.leftPinnedHeadersAfter =
pinnedPosition !== GridPinnedColumnPosition.LEFT
? []
: findLeftPinnedHeadersAfterCol(apiRef.current, columnHeaderElementRef.current);
rightPinnedHeadersBeforeRef.current =
: findLeftPinnedHeadersAfterCol(apiRef.current, refs.columnHeaderElement);
refs.rightPinnedHeadersBefore =
pinnedPosition !== GridPinnedColumnPosition.RIGHT
? []
: findRightPinnedHeadersBeforeCol(apiRef.current, columnHeaderElementRef.current);
: findRightPinnedHeadersBeforeCol(apiRef.current, refs.columnHeaderElement);

resizeDirection.current = getResizeDirection(separator, theme.direction);

initialOffsetToSeparator.current = computeOffsetToSeparator(
xStart,
columnHeaderElementRef.current!.getBoundingClientRect(),
refs.columnHeaderElement!.getBoundingClientRect(),
resizeDirection.current,
);
};
Expand All @@ -495,16 +510,16 @@ export const useGridColumnResize = (
let newWidth = computeNewWidth(
initialOffsetToSeparator.current!,
nativeEvent.clientX,
columnHeaderElementRef.current!.getBoundingClientRect(),
refs.columnHeaderElement!.getBoundingClientRect(),
resizeDirection.current!,
);

newWidth = clamp(newWidth, colDefRef.current!.minWidth!, colDefRef.current!.maxWidth!);
newWidth = clamp(newWidth, refs.colDef!.minWidth!, refs.colDef!.maxWidth!);
updateWidth(newWidth);

const params: GridColumnResizeParams = {
element: columnHeaderElementRef.current,
colDef: colDefRef.current!,
element: refs.columnHeaderElement,
colDef: refs.colDef!,
width: newWidth,
};
apiRef.current.publishEvent('columnResize', params, nativeEvent);
Expand Down Expand Up @@ -535,16 +550,16 @@ export const useGridColumnResize = (
let newWidth = computeNewWidth(
initialOffsetToSeparator.current!,
(finger as CursorCoordinates).x,
columnHeaderElementRef.current!.getBoundingClientRect(),
refs.columnHeaderElement!.getBoundingClientRect(),
resizeDirection.current!,
);

newWidth = clamp(newWidth, colDefRef.current!.minWidth!, colDefRef.current!.maxWidth!);
newWidth = clamp(newWidth, refs.colDef!.minWidth!, refs.colDef!.maxWidth!);
updateWidth(newWidth);

const params: GridColumnResizeParams = {
element: columnHeaderElementRef.current,
colDef: colDefRef.current!,
element: refs.columnHeaderElement,
colDef: refs.colDef!,
width: newWidth,
};
apiRef.current.publishEvent('columnResize', params, nativeEvent);
Expand Down Expand Up @@ -599,12 +614,12 @@ export const useGridColumnResize = (
setTimeout(() => {
doc.removeEventListener('click', preventClick, true);
}, 100);
if (columnHeaderElementRef.current) {
columnHeaderElementRef.current!.style.pointerEvents = 'unset';
if (refs.columnHeaderElement) {
refs.columnHeaderElement!.style.pointerEvents = 'unset';
}
}, [
apiRef,
columnHeaderElementRef,
refs.columnHeaderElement,
handleResizeMouseMove,
handleResizeMouseUp,
handleTouchMove,
Expand Down Expand Up @@ -653,7 +668,7 @@ export const useGridColumnResize = (
const doc = ownerDocument(apiRef.current.rootElementRef!.current);
doc.body.style.cursor = 'col-resize';

previousMouseClickEvent.current = event.nativeEvent;
refs.previousMouseClickEvent = event.nativeEvent;

doc.addEventListener('mousemove', handleResizeMouseMove);
doc.addEventListener('mouseup', handleResizeMouseUp);
Expand Down