-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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 input element in custom header #3624
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Regarding the solution, it would be simple if we could check if the event is coming from a custom rendered header. If it does, then we don't need to care about the keyboard event handling. One way is to wrap headerComponent
below in a div. Then, we know clearly that the event came from the custom component.
event.preventDefault(); | ||
const isNativeFocusOnHeader = event.currentTarget === event.target; | ||
if (isNavigationKey(event.key) && isNativeFocusOnHeader) { | ||
event.preventDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It tooks me time to understand what append
In the PR #3275 that was only refact for column header key down, I missed the following condition
if (!isGridHeaderCellRoot(event.target as HTMLElement)) {
return;
}
Before the introduction of the bug, the rule was the next one: If the focus is not on the root component, the columnHeaderKeyDown
event has no effect. One exception is for that checkbox selection which has the focus set in the checkbox input.
I think this PR is a "regression" fix and I will open an issue to discuss how events from custom render should be managed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that isGridHeaderCellRoot
only checks if event.target
is the column header. If the target is a child of the header (e.g. the sort icon) it evaluates to false. This creates a regression because if I click the sort icon and I press Arrow Down it will scroll the page instead of going to the cell below.
I think this PR is a "regression" fix and I will open an issue to discuss how events from custom render should be managed.
Does this mean that you won't be fixing the column header with a custom component? If yes, could you update the title and description so #3599 doesn't get closed once this one is merged?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, isGridHeaderCellRoot
is a hard condition, but that is what we used before the regression occurs.
You can test the codesandbox from the issue with different versions of DataGrid:
https://codesandbox.io/s/renderheadergrid-material-demo-forked-suwsf?file=/index.tsx
- v5.2.0:
- TextField works perfectly
- keyboard navigation is blocked if the focus is on the sort button
- v5.2.1:
- TextField broken
- keyboard navigation is working if the focus is on the sort button
The modification between v5.2.0 and v5.2.1 is not intentional. So I propose to correct the regression I introduced in v5.2.1 to solve the issue.
With the modification added in the commit the Arrow Down keep same behavior as v5.2.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not to also return here? We only handle the navigation keys.
event.preventDefault(); | |
event.preventDefault(); | |
return; |
keyboard navigation is working if the focus is on the sort button
I'm not sure about this statement. In https://deploy-preview-3624--material-ui-x.netlify.app/components/data-grid/demo/, if I click the sort icon, then press Page Down, it moves the page down.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could put an early return as follow
if (isNavigationKey(event.key)) {
event.preventDefault();
} else{
return;
}
The page moves down, but not the grid. That's the behavior before the regression. Here is a comparison of key board before/after the regression and the preview of this commit.
From left to righ:
- before regression: https://deploy-preview-3302--material-ui-x.netlify.app/components/data-grid/demo/
- after regresion: https://deploy-preview-3275--material-ui-x.netlify.app/components/data-grid/demo/
- this PR: https://deploy-preview-3624--material-ui-x.netlify.app/components/data-grid/demo/
When focus on sort
When focus on column header
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could put an early return as follow
The problem is isGridHeaderCellRoot
only checking if the event was fired by the root.
Let's review what happened here:
- Before 5.2.1: clicking in any child of the column header and ArrowDown would scroll the page (nobody complained but I think it's not good)
- 5.2.1: Unintentionally fixed the bug above
- This PR reverts the fix
I see this as inserting a regression because 5.2.1 is already released. Could you take a look in #3692? I think it already fixed part of the problem here. The solution was to only call event.preventDefault
for navigation keys. #3599 was kinda fixed for free by #3692. However, pressing a navigation key inside the input won't work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I had a look at #3692 It is equivalent to add
if(isNavigationKey(event.key)) {
event.preventDefault()
}
That was my first idea but I stopped doing it because it does not allow you to use keyboard navigation in a custom input, event more problematic, it does not allow you to use space key. The worst I imagine is putting a select input in the header. In such a case, the keyboard navigation will be completely down, because it requires keyboard arrows.
My conclusion is that only the developer knows if the focusable element added requires or not the event.preventDefault
to prevent the page to scroll. But how to adapt the interface to let them choose, I don't know
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about then wrapping the custom component in a div so we know from where the event is coming from and ignore it? I proposed this in #3624 (review). I don't see a simpler and future-proof alternative. The other way, I think, would be to add a specific attribute to each of the icons and the title to allows us to detect if the event came from them or from a custom component.
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
These are the results for the performance tests:
|
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
89139e8
to
bdc8bcf
Compare
event.preventDefault(); | ||
const isNativeFocusOnHeader = event.currentTarget === event.target; | ||
if (isNavigationKey(event.key) && isNativeFocusOnHeader) { | ||
event.preventDefault(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not to also return here? We only handle the navigation keys.
event.preventDefault(); | |
event.preventDefault(); | |
return; |
keyboard navigation is working if the focus is on the sort button
I'm not sure about this statement. In https://deploy-preview-3624--material-ui-x.netlify.app/components/data-grid/demo/, if I click the sort icon, then press Page Down, it moves the page down.
if (!params.field) { | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To improve readability.
if (!params.field) { | |
return; | |
} | |
if (!params.field) { | |
return; | |
} | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition is useless I added it to apply this PR comment but I miss understood it 😅 #3275 (comment)
event.preventDefault(); | ||
if ( | ||
!isGridHeaderCellRoot(event.target as HTMLElement) && | ||
!(params.field === GRID_CHECKBOX_SELECTION_COL_DEF.field && isNavigationKey(event.key)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why to also check if it's a navigation key? We only event.preventDefault
on the navigation keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there is no reason
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
👋 The migration PR has been merged. Please follow these steps to make sure that the contents are all updated. (Sorry for the inconvenience)
If you are struggle with the steps above, feel free to tag @siriwatknp |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
To verify if the event comes from the custom title I added a class It's only used to make a query selector, but I let it accessible for developers |
packages/grid/x-data-grid/src/internals/hooks/features/keyboard/useGridKeyboardNavigation.ts
Outdated
Show resolved
Hide resolved
packages/grid/x-data-grid/src/internals/hooks/features/keyboard/useGridKeyboardNavigation.ts
Outdated
Show resolved
Hide resolved
packages/grid/x-data-grid/src/internals/components/columnHeaders/GridColumnHeaderItem.tsx
Outdated
Show resolved
Hide resolved
d6d3564
to
8345824
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
packages/grid/x-data-grid/src/internals/hooks/features/keyboard/useGridKeyboardNavigation.ts
Outdated
Show resolved
Hide resolved
packages/grid/x-data-grid/src/internals/hooks/features/keyboard/useGridKeyboardNavigation.ts
Outdated
Show resolved
Hide resolved
I'm adding a test to ensure that clicking on the sort button does not lock the focus |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
// This does not work with navigation keys. | ||
// For now, the workaround for developers is to stop the propagation | ||
// But adding input is discouraged, action column or edit mode are better options | ||
expect(fireEvent.keyDown(input, { key: 'a' })).to.equal(true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if we should have this test. An input inside a cell in view mode is not encouraged because in this mode cells are supposed to be read-only. If you fire a ArrowDown
event the assertion will fail correctly because any keydown event should move the focus to the next cell. However, in edit mode, the assertion (once changed to ArrowDown
) is correct. I would move this test to the cell editing suite and render the input inside a cell in edit mode.
mui-x/packages/grid/x-data-grid/src/hooks/features/keyboard/useGridKeyboard.ts
Lines 60 to 63 in 62bb727
const isEditMode = cellParams.cellMode === GridCellModes.Edit; | |
if (isEditMode) { | |
return; | |
} |
This can be done in another PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I will open another PR for this one 👍
Co-authored-by: Matheus Wichman <matheushw@outlook.com>
Fix #3599
The previous test was not catching the error, because it was checking that
event.defaultPrented=false
. But theonKeyDown
is first run by the input, and then by the header. Such that theevent.preventdefault()
is applied after we observe it.I tried the
fireEvent.change
but this does not trigger thekeyDown
event. Then I'm adding the library@testing-library/user-event
to useuserEvent.type
which imitates the input writing.Now the two tests break when we set a
preventDefault
at the wrong place