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] Refactor keyboard/click event management #3275

Merged
merged 19 commits into from
Dec 14, 2021

Conversation

alexfauquette
Copy link
Member

@alexfauquette alexfauquette commented Nov 24, 2021

Fix #3265 and fix #3272

This is a first step to handle all the keyboard events in their feature hook #3265 (comment)

@alexfauquette alexfauquette changed the title Demo [DataGrid] refacto Keyboeard/Click event management Nov 24, 2021
@alexfauquette alexfauquette changed the title [DataGrid] refacto Keyboeard/Click event management [DataGrid] Refacto Keyboeard/Click event management Nov 24, 2021
@alexfauquette alexfauquette self-assigned this Nov 24, 2021
@alexfauquette alexfauquette marked this pull request as ready for review November 26, 2021 13:59
@alexfauquette
Copy link
Member Author

The handleCellKeyDown can not be completely merged with handleCellNavigationKeyDown because of the early return

if ((event.target as any).nodeType === 1 && !isGridCellRoot(event.target as Element)) {
        return;
}

this condition prevents from applying keyboard shortcuts if the focus is not on a cell component (for example a select input)

To apply keyboard events inside cells (for example when the focus is on a button) the event cellNavigationKeyDown is dispatched. This one triggers handleCellNavigationKeyDown which does not check if the event.target is a Cell component.

So the solution still needs improvement, but at least it solves the two issues

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Nov 27, 2021
@github-actions
Copy link

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Nov 29, 2021
Copy link
Member

@flaviendelangle flaviendelangle left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid breaking changes, we should still fire columnHeaderNavigationKeydown even if we do not use it internally.

@@ -103,7 +103,7 @@ const GridHeaderCheckbox = React.forwardRef<HTMLInputElement, GridColumnHeaderPa
event.stopPropagation();
}
if (isNavigationKey(event.key) && !event.shiftKey) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we fire the columnHeaderKeyDown on any key, not just navigation one ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove this handler and let columnHeaderKeyDown to propagate freely?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did not noticed, but we are already firing columnHeaderKeyDown on any key except Space (because of the stop event propagation)

The stop eventPropagation is here to avoid a preventDefault which would disable the validation of the input with Space key.

I'm putting back the columnHeaderNavigationKeyDown and add a TODO such as it should be remove in v6

For the stopPropagation, I see two options:

  • keep the stopPropagation and fire columnHeaderKeyDown
  • remove the stopPropagation, and call the handleChange the the key pressed is a Space

Copy link
Member

@m4theushw m4theushw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a draft PR to explain the proposed solution in #3265 (comment)

Is it still in draft? I don't know how rigorous should I review it.

image

@@ -24,6 +24,10 @@ export function isGridHeaderCellRoot(elem: Element | null): boolean {
return elem != null && elem.classList.contains(gridClasses.columnHeader);
}

export function isGridHeaderSelectAllCheckBox(elem: Element | null): boolean {
return elem != null && elem.ariaLabel === 'Select All Rows checkbox';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It could have been translated.

GridEventListener<GridEvents.columnHeaderNavigationKeyDown>
>(
(params, event) => {
event.preventDefault();
if (
!isGridHeaderCellRoot(event.target as HTMLElement) &&
!isGridHeaderSelectAllCheckBox(event.target as HTMLElement)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking params.field is safer.

@@ -103,7 +103,7 @@ const GridHeaderCheckbox = React.forwardRef<HTMLInputElement, GridColumnHeaderPa
event.stopPropagation();
}
if (isNavigationKey(event.key) && !event.shiftKey) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we remove this handler and let columnHeaderKeyDown to propagate freely?

@github-actions
Copy link

github-actions bot commented Dec 1, 2021

This pull request has conflicts, please resolve those before we can evaluate the pull request.

@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 1, 2021
@github-actions github-actions bot removed the PR: out-of-date The pull request has merge conflicts and can't be merged label Dec 2, 2021
Copy link
Member

@m4theushw m4theushw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to add some test cases to cover the fixed issues.

Copy link
Member

@m4theushw m4theushw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We miss a test for #3275 (comment) in selection.DataGridPro.test.tsx.

it('should select one row at a time on Shift + Space', () => {
render(<TestDataGridSelection />);
getCell(0, 0).focus();
fireEvent.keyDown(document.activeElement || document.body, { key: ' ', shiftKey: true });
Copy link
Member

@m4theushw m4theushw Dec 7, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why document.activeElement || document.body? Was it to snooze the ESLint rule "Don't use document.activeElement as a target for keyboard events."? 😁 You can fix it properly by passing the cell element as bellow:

https://github.com/mui-org/material-ui-x/blob/1d82bea672afc1ece26739a47b2de7ae298de9bc/packages/grid/x-data-grid-pro/src/tests/clipboard.DataGridPro.test.tsx#L91-L93

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really, it is to follow the documentation :)

This will also test that the element in question can even receive keyboard events

https://testing-library.com/docs/guide-events#keydown

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The element is passed to improve readability: mui/material-ui#20945

This will also test that the element in question can even receive keyboard events

This check is embedded into the custom fireEvent we use. See https://github.com/mui-org/material-ui/blob/69b7e4d911e8ff99d17a74330496ae69e7cc0ade/test/utils/createRenderer.tsx#L622

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've done the modifications, but I'm not really convinced that it improves readability

The core team has element which are all meaning full, leading to testing code such as

fireEvent.keyDown(button, ...);
fireEvent.keyDown(firstTab, ...);

We are navigating between cells so most of the components with focus are cells which only differ by there coordinates which is translated by

fireEvent.keyDown(cell01, ...);
fireEvent.keyDown(cell23, ...);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take as example the following test case:

expect(getActiveCell()).to.equal('8-1');
fireEvent.keyDown(document.activeElement!, { key: 'ArrowDown' });
fireEvent.keyDown(document.activeElement!, { key: 'ArrowRight' });
fireEvent.keyDown(document.activeElement!, { key: 'ArrowLeft' });
fireEvent.keyDown(document.activeElement!, { key: 'ArrowUp' });

Can you easily spot where the focus is after the last keyDown? 😛

@alexfauquette
Copy link
Member Author

@m4theushw I added a commit to prevent keyboard "Shift+Space" from starting editing the cell, which is a pain when selecting rows in an editable DataGrid

@m4theushw m4theushw changed the title [DataGrid] Refacto Keyboeard/Click event management [DataGrid] Refactor keyboard/click event management Dec 10, 2021
@m4theushw m4theushw added the component: data grid This is the name of the generic UI component, not the React module! label Dec 10, 2021
Copy link
Member

@m4theushw m4theushw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job.

!isGridHeaderCellRoot(event.target as HTMLElement) &&
!isGridHeaderSelectAllCheckBox(event.target as HTMLElement)
) {
if (!params.field) {
return;
}
const dimensions = apiRef.current.getRootDimensions();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This modification

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: data grid This is the name of the generic UI component, not the React module!
Projects
None yet
3 participants