Skip to content

Commit 65cf41c

Browse files
committed
[DataGrid] Prevent column header scroll
1 parent e66404d commit 65cf41c

File tree

5 files changed

+45
-23
lines changed

5 files changed

+45
-23
lines changed

packages/grid/x-data-grid-pro/src/tests/columnHeaders.DataGridPro.test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,26 @@ describe('<DataGridPro /> - Column Headers', () => {
3232
],
3333
};
3434

35+
it('should not scroll the column headers when a column is focused', function test() {
36+
if (isJSDOM) {
37+
this.skip(); // JSDOM version of .focus() doesn't scroll
38+
}
39+
render(
40+
<div style={{ width: 102, height: 500 }}>
41+
<DataGridPro
42+
{...baselineProps}
43+
columns={[{ field: 'brand' }, { field: 'foundationYear' }]}
44+
/>
45+
</div>,
46+
);
47+
const columnHeaders = document.querySelector('.MuiDataGrid-columnHeaders')!;
48+
expect(columnHeaders.scrollLeft).to.equal(0);
49+
const columnCell = getColumnHeaderCell(0);
50+
columnCell.focus();
51+
fireEvent.keyDown(columnCell, { key: 'End' });
52+
expect(columnHeaders.scrollLeft).to.equal(0);
53+
});
54+
3555
describe('GridColumnHeaderMenu', () => {
3656
it('should close the menu when the window is scrolled', () => {
3757
render(

packages/grid/x-data-grid/src/components/cell/GridCell.tsx

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { useGridApiContext } from '../../hooks/utils/useGridApiContext';
1818
import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
1919
import { gridFocusCellSelector } from '../../hooks/features/focus/gridFocusStateSelector';
2020
import { DataGridProcessedProps } from '../../models/props/DataGridProps';
21+
import { doesSupportPreventScroll } from '../../utils/utils';
2122

2223
export interface GridCellProps {
2324
align: GridAlignment;
@@ -45,20 +46,6 @@ export interface GridCellProps {
4546
[x: string]: any; // TODO it should not accept unspecified props
4647
}
4748

48-
// Based on https://stackoverflow.com/a/59518678
49-
let cachedSupportsPreventScroll: boolean;
50-
function doesSupportPreventScroll(): boolean {
51-
if (cachedSupportsPreventScroll === undefined) {
52-
document.createElement('div').focus({
53-
get preventScroll() {
54-
cachedSupportsPreventScroll = true;
55-
return false;
56-
},
57-
});
58-
}
59-
return cachedSupportsPreventScroll;
60-
}
61-
6249
type OwnerState = Pick<GridCellProps, 'align' | 'showRightBorder' | 'isEditable'> & {
6350
classes?: DataGridProcessedProps['classes'];
6451
};

packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaderItem.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { GridColumnHeaderMenu } from '../menu/columnMenu/GridColumnHeaderMenu';
1919
import { getDataGridUtilityClass } from '../../constants/gridClasses';
2020
import { useGridRootProps } from '../../hooks/utils/useGridRootProps';
2121
import { DataGridProcessedProps } from '../../models/props/DataGridProps';
22+
import { doesSupportPreventScroll } from '../../utils/utils';
2223

2324
interface GridColumnHeaderItemProps {
2425
colIndex: number;
@@ -201,13 +202,15 @@ function GridColumnHeaderItem(props: GridColumnHeaderItemProps) {
201202
const columnMenuState = apiRef.current.state.columnMenu;
202203
if (hasFocus && !columnMenuState.open) {
203204
const focusableElement = headerCellRef.current!.querySelector<HTMLElement>('[tabindex="0"]');
204-
if (focusableElement) {
205-
focusableElement!.focus();
206-
} else {
207-
headerCellRef.current!.focus();
205+
const elementToFocus = focusableElement || headerCellRef.current;
206+
elementToFocus?.focus({ preventScroll: true });
207+
208+
if (!doesSupportPreventScroll()) {
209+
// A ponyfill for .focus({ preventScroll: true })
210+
apiRef.current.columnHeadersContainerElementRef!.current!.scrollLeft = 0;
208211
}
209212
}
210-
});
213+
}, [apiRef, hasFocus]);
211214

212215
const headerClassName =
213216
typeof column.headerClassName === 'function'

packages/grid/x-data-grid/src/components/columnHeaders/GridColumnHeaders.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,11 @@ const GridColumnHeadersRoot = styled('div', {
4444
};
4545
});
4646

47-
interface GridColumnHeadersProps extends React.HTMLAttributes<HTMLDivElement> {
48-
innerRef?: React.Ref<HTMLDivElement>;
49-
}
47+
interface GridColumnHeadersProps extends React.HTMLAttributes<HTMLDivElement> {}
5048

5149
export const GridColumnHeaders = React.forwardRef<HTMLDivElement, GridColumnHeadersProps>(
5250
function GridColumnHeaders(props, ref) {
53-
const { innerRef, className, ...other } = props;
51+
const { className, ...other } = props;
5452
const rootProps = useGridRootProps();
5553

5654
const ownerState = { classes: rootProps.classes };

packages/grid/x-data-grid/src/utils/utils.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ export function escapeRegExp(value: string): string {
3535
export const clamp = (value: number, min: number, max: number) =>
3636
Math.max(min, Math.min(max, value));
3737

38+
// Based on https://stackoverflow.com/a/59518678
39+
let cachedSupportsPreventScroll: boolean;
40+
export function doesSupportPreventScroll(): boolean {
41+
if (cachedSupportsPreventScroll === undefined) {
42+
document.createElement('div').focus({
43+
get preventScroll() {
44+
cachedSupportsPreventScroll = true;
45+
return false;
46+
},
47+
});
48+
}
49+
return cachedSupportsPreventScroll;
50+
}
51+
3852
/**
3953
* Based on `fast-deep-equal`
4054
*

0 commit comments

Comments
 (0)