From e423296432a5be555d2771d5c1007b940ef951f1 Mon Sep 17 00:00:00 2001 From: Matheus Wichman Date: Tue, 15 Nov 2022 20:32:10 -0300 Subject: [PATCH] [DataGrid] Remove unnecessary keyboard navigation events --- .../tree-data/TreeDataCustomGroupingColumn.js | 16 +- .../TreeDataCustomGroupingColumn.tsx | 16 +- .../tree-data/TreeDataLazyLoading.js | 10 - .../tree-data/TreeDataLazyLoading.tsx | 10 - .../migration-data-grid-v5.md | 2 + .../components/GridGroupingCriteriaCell.tsx | 2 + .../components/GridTreeDataGroupingCell.tsx | 11 - .../GridCellCheckboxRenderer.tsx | 20 +- .../columnSelection/GridHeaderCheckbox.tsx | 7 +- .../useGridKeyboardNavigation.ts | 264 +++++++++--------- .../src/models/events/gridEventLookup.ts | 18 -- 11 files changed, 143 insertions(+), 233 deletions(-) diff --git a/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.js b/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.js index 47b58ba7b871..e0d7fde69652 100644 --- a/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.js +++ b/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.js @@ -25,15 +25,6 @@ function CustomGridTreeDataGroupingCell(props) { const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; - const handleKeyDown = (event) => { - if (event.key === ' ') { - event.stopPropagation(); - } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent('cellNavigationKeyDown', props, event); - } - }; - const handleClick = (event) => { if (rowNode.type !== 'group') { return; @@ -48,12 +39,7 @@ function CustomGridTreeDataGroupingCell(props) {
{filteredDescendantCount > 0 ? ( - ) : ( diff --git a/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.tsx b/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.tsx index 409eaeeca3ce..1615251e3538 100644 --- a/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.tsx +++ b/docs/data/data-grid/tree-data/TreeDataCustomGroupingColumn.tsx @@ -29,15 +29,6 @@ function CustomGridTreeDataGroupingCell(props: GridRenderCellParams) { ); const filteredDescendantCount = filteredDescendantCountLookup[rowNode.id] ?? 0; - const handleKeyDown: ButtonProps['onKeyDown'] = (event) => { - if (event.key === ' ') { - event.stopPropagation(); - } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent('cellNavigationKeyDown', props, event); - } - }; - const handleClick: ButtonProps['onClick'] = (event) => { if (rowNode.type !== 'group') { return; @@ -52,12 +43,7 @@ function CustomGridTreeDataGroupingCell(props: GridRenderCellParams) {
{filteredDescendantCount > 0 ? ( - ) : ( diff --git a/docs/data/data-grid/tree-data/TreeDataLazyLoading.js b/docs/data/data-grid/tree-data/TreeDataLazyLoading.js index 90bdc302198e..17e4ce12aad0 100644 --- a/docs/data/data-grid/tree-data/TreeDataLazyLoading.js +++ b/docs/data/data-grid/tree-data/TreeDataLazyLoading.js @@ -173,15 +173,6 @@ function GroupingCellWithLazyLoading(props) { ? rootProps.components.TreeDataCollapseIcon : rootProps.components.TreeDataExpandIcon; - const handleKeyDown = (event) => { - if (event.key === ' ') { - event.stopPropagation(); - } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent('cellNavigationKeyDown', props, event); - } - }; - const handleClick = (event) => { apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); apiRef.current.setCellFocus(id, field); @@ -195,7 +186,6 @@ function GroupingCellWithLazyLoading(props) { { - if (event.key === ' ') { - event.stopPropagation(); - } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent('cellNavigationKeyDown', props, event); - } - }; - const handleClick: IconButtonProps['onClick'] = (event) => { apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); apiRef.current.setCellFocus(id, field); @@ -215,7 +206,6 @@ function GroupingCellWithLazyLoading(props: GroupingCellWithLazyLoadingProps) { ) => { if (event.key === ' ') { + // We call event.stopPropagation to avoid unfolding the row and also scrolling to bottom + // TODO: Remove and add a check inside useGridKeyboardNavigation event.stopPropagation(); } apiRef.current.publishEvent('cellKeyDown', props, event); diff --git a/packages/grid/x-data-grid-pro/src/components/GridTreeDataGroupingCell.tsx b/packages/grid/x-data-grid-pro/src/components/GridTreeDataGroupingCell.tsx index cb9691b9a476..dee9c4687ef7 100644 --- a/packages/grid/x-data-grid-pro/src/components/GridTreeDataGroupingCell.tsx +++ b/packages/grid/x-data-grid-pro/src/components/GridTreeDataGroupingCell.tsx @@ -10,7 +10,6 @@ import { GridRenderCellParams, GridGroupNode, } from '@mui/x-data-grid'; -import { isNavigationKey } from '@mui/x-data-grid/internals'; import { useGridRootProps } from '../hooks/utils/useGridRootProps'; import { useGridApiContext } from '../hooks/utils/useGridApiContext'; import { DataGridProProcessedProps } from '../models/dataGridProProps'; @@ -55,15 +54,6 @@ function GridTreeDataGroupingCell(props: GridTreeDataGroupingCellProps) { ? rootProps.components.TreeDataCollapseIcon : rootProps.components.TreeDataExpandIcon; - const handleKeyDown = (event: React.KeyboardEvent) => { - if (event.key === ' ') { - event.stopPropagation(); - } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent('cellNavigationKeyDown', props, event); - } - }; - const handleClick = (event: React.MouseEvent) => { apiRef.current.setRowChildrenExpansion(id, !rowNode.childrenExpanded); apiRef.current.setCellFocus(id, field); @@ -77,7 +67,6 @@ function GridTreeDataGroupingCell(props: GridTreeDataGroupingCellProps) { ) => { - if (isSpaceKey(event.key)) { - event.stopPropagation(); - } - if (isNavigationKey(event.key) && !event.shiftKey) { - apiRef.current.publishEvent('cellNavigationKeyDown', props, event); - } - }, - [apiRef, props], - ); + const handleKeyDown = React.useCallback((event: React.KeyboardEvent) => { + if (isSpaceKey(event.key)) { + // We call event.stopPropagation to avoid selecting the row and also scrolling to bottom + // TODO: Remove and add a check inside useGridKeyboardNavigation + event.stopPropagation(); + } + }, []); if (rowNode.type === 'footer' || rowNode.type === 'pinnedRow') { return null; diff --git a/packages/grid/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx b/packages/grid/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx index a5ba4733bfb0..dfdfe5963749 100644 --- a/packages/grid/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx +++ b/packages/grid/x-data-grid/src/components/columnSelection/GridHeaderCheckbox.tsx @@ -5,7 +5,6 @@ import { useGridSelector } from '../../hooks/utils/useGridSelector'; import { gridTabIndexColumnHeaderSelector } from '../../hooks/features/focus/gridFocusStateSelector'; import { gridRowSelectionStateSelector } from '../../hooks/features/rowSelection/gridRowSelectionSelector'; import { GridColumnHeaderParams } from '../../models/params/gridColumnHeaderParams'; -import { isNavigationKey } from '../../utils/keyboardUtils'; import { useGridApiContext } from '../../hooks/utils/useGridApiContext'; import { getDataGridUtilityClass } from '../../constants/gridClasses'; import { useGridRootProps } from '../../hooks/utils/useGridRootProps'; @@ -113,12 +112,8 @@ const GridHeaderCheckbox = React.forwardRef { diff --git a/packages/grid/x-data-grid/src/hooks/features/keyboardNavigation/useGridKeyboardNavigation.ts b/packages/grid/x-data-grid/src/hooks/features/keyboardNavigation/useGridKeyboardNavigation.ts index 6e5c55199626..540e141d1149 100644 --- a/packages/grid/x-data-grid/src/hooks/features/keyboardNavigation/useGridKeyboardNavigation.ts +++ b/packages/grid/x-data-grid/src/hooks/features/keyboardNavigation/useGridKeyboardNavigation.ts @@ -107,138 +107,6 @@ export const useGridKeyboardNavigation = ( [currentPageRows], ); - const handleCellNavigationKeyDown = React.useCallback>( - (params, event) => { - const dimensions = apiRef.current.getRootDimensions(); - if (currentPageRows.length === 0 || !dimensions) { - return; - } - - const viewportPageSize = apiRef.current.getViewportPageSize(); - - const colIndexBefore = (params as GridCellParams).field - ? apiRef.current.getColumnIndex((params as GridCellParams).field) - : 0; - const rowIndexBefore = currentPageRows.findIndex((row) => row.id === params.id); - const firstRowIndexInPage = 0; - const lastRowIndexInPage = currentPageRows.length - 1; - const firstColIndex = 0; - const lastColIndex = gridVisibleColumnDefinitionsSelector(apiRef).length - 1; - let shouldPreventDefault = true; - - switch (event.key) { - case 'ArrowDown': - case 'Enter': { - // TODO v6: Remove Enter case because `cellNavigationKeyDown` is not fired by the new editing API - // "Enter" is only triggered by the row / cell editing feature - if (rowIndexBefore < lastRowIndexInPage) { - goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore + 1)); - } - break; - } - - case 'ArrowUp': { - if (rowIndexBefore > firstRowIndexInPage) { - goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore - 1)); - } else { - goToHeader(colIndexBefore, event); - } - break; - } - - case 'ArrowRight': { - if (colIndexBefore < lastColIndex) { - goToCell(colIndexBefore + 1, getRowIdFromIndex(rowIndexBefore), 'right'); - } - break; - } - - case 'ArrowLeft': { - if (colIndexBefore > firstColIndex) { - goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore)); - } - break; - } - - case 'Tab': { - // "Tab" is only triggered by the row / cell editing feature - if (event.shiftKey && colIndexBefore > firstColIndex) { - goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore), 'left'); - } else if (!event.shiftKey && colIndexBefore < lastColIndex) { - goToCell(colIndexBefore + 1, getRowIdFromIndex(rowIndexBefore), 'right'); - } - break; - } - - case ' ': { - const field = (params as GridCellParams).field; - if (field === GRID_DETAIL_PANEL_TOGGLE_FIELD) { - break; - } - const colDef = (params as GridCellParams).colDef; - if (colDef && colDef.type === 'treeDataGroup') { - break; - } - if (!event.shiftKey && rowIndexBefore < lastRowIndexInPage) { - goToCell( - colIndexBefore, - getRowIdFromIndex(Math.min(rowIndexBefore + viewportPageSize, lastRowIndexInPage)), - ); - } - break; - } - - case 'PageDown': { - if (rowIndexBefore < lastRowIndexInPage) { - goToCell( - colIndexBefore, - getRowIdFromIndex(Math.min(rowIndexBefore + viewportPageSize, lastRowIndexInPage)), - ); - } - break; - } - - case 'PageUp': { - // Go to the first row before going to header - const nextRowIndex = Math.max(rowIndexBefore - viewportPageSize, firstRowIndexInPage); - if (nextRowIndex !== rowIndexBefore && nextRowIndex >= firstRowIndexInPage) { - goToCell(colIndexBefore, getRowIdFromIndex(nextRowIndex)); - } else { - goToHeader(colIndexBefore, event); - } - break; - } - - case 'Home': { - if (event.ctrlKey || event.metaKey || event.shiftKey) { - goToCell(firstColIndex, getRowIdFromIndex(firstRowIndexInPage)); - } else { - goToCell(firstColIndex, getRowIdFromIndex(rowIndexBefore)); - } - break; - } - - case 'End': { - if (event.ctrlKey || event.metaKey || event.shiftKey) { - goToCell(lastColIndex, getRowIdFromIndex(lastRowIndexInPage)); - } else { - goToCell(lastColIndex, getRowIdFromIndex(rowIndexBefore)); - } - break; - } - - default: { - shouldPreventDefault = false; - } - } - - if (shouldPreventDefault) { - event.preventDefault(); - } - }, - [apiRef, currentPageRows, goToCell, goToHeader, getRowIdFromIndex], - ); - const handleColumnHeaderKeyDown = React.useCallback>( (params, event) => { const headerTitleNode = event.currentTarget.querySelector( @@ -459,14 +327,138 @@ export const useGridKeyboardNavigation = ( // Get the most recent params because the cell mode may have changed by another listener const cellParams = apiRef.current.getCellParams(params.id, params.field); - if (cellParams.cellMode !== GridCellModes.Edit && isNavigationKey(event.key)) { - apiRef.current.publishEvent('cellNavigationKeyDown', cellParams, event); + if (cellParams.cellMode === GridCellModes.Edit || !isNavigationKey(event.key)) { + return; + } + + const dimensions = apiRef.current.getRootDimensions(); + if (currentPageRows.length === 0 || !dimensions) { + return; + } + + const viewportPageSize = apiRef.current.getViewportPageSize(); + + const colIndexBefore = (params as GridCellParams).field + ? apiRef.current.getColumnIndex((params as GridCellParams).field) + : 0; + const rowIndexBefore = currentPageRows.findIndex((row) => row.id === params.id); + const firstRowIndexInPage = 0; + const lastRowIndexInPage = currentPageRows.length - 1; + const firstColIndex = 0; + const lastColIndex = gridVisibleColumnDefinitionsSelector(apiRef).length - 1; + let shouldPreventDefault = true; + + switch (event.key) { + case 'ArrowDown': { + // "Enter" is only triggered by the row / cell editing feature + if (rowIndexBefore < lastRowIndexInPage) { + goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore + 1)); + } + break; + } + + case 'ArrowUp': { + if (rowIndexBefore > firstRowIndexInPage) { + goToCell(colIndexBefore, getRowIdFromIndex(rowIndexBefore - 1)); + } else { + goToHeader(colIndexBefore, event); + } + break; + } + + case 'ArrowRight': { + if (colIndexBefore < lastColIndex) { + goToCell(colIndexBefore + 1, getRowIdFromIndex(rowIndexBefore), 'right'); + } + break; + } + + case 'ArrowLeft': { + if (colIndexBefore > firstColIndex) { + goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore)); + } + break; + } + + case 'Tab': { + // "Tab" is only triggered by the row / cell editing feature + if (event.shiftKey && colIndexBefore > firstColIndex) { + goToCell(colIndexBefore - 1, getRowIdFromIndex(rowIndexBefore), 'left'); + } else if (!event.shiftKey && colIndexBefore < lastColIndex) { + goToCell(colIndexBefore + 1, getRowIdFromIndex(rowIndexBefore), 'right'); + } + break; + } + + case ' ': { + const field = (params as GridCellParams).field; + if (field === GRID_DETAIL_PANEL_TOGGLE_FIELD) { + break; + } + const colDef = (params as GridCellParams).colDef; + if (colDef && colDef.type === 'treeDataGroup') { + break; + } + if (!event.shiftKey && rowIndexBefore < lastRowIndexInPage) { + goToCell( + colIndexBefore, + getRowIdFromIndex(Math.min(rowIndexBefore + viewportPageSize, lastRowIndexInPage)), + ); + } + break; + } + + case 'PageDown': { + if (rowIndexBefore < lastRowIndexInPage) { + goToCell( + colIndexBefore, + getRowIdFromIndex(Math.min(rowIndexBefore + viewportPageSize, lastRowIndexInPage)), + ); + } + break; + } + + case 'PageUp': { + // Go to the first row before going to header + const nextRowIndex = Math.max(rowIndexBefore - viewportPageSize, firstRowIndexInPage); + if (nextRowIndex !== rowIndexBefore && nextRowIndex >= firstRowIndexInPage) { + goToCell(colIndexBefore, getRowIdFromIndex(nextRowIndex)); + } else { + goToHeader(colIndexBefore, event); + } + break; + } + + case 'Home': { + if (event.ctrlKey || event.metaKey || event.shiftKey) { + goToCell(firstColIndex, getRowIdFromIndex(firstRowIndexInPage)); + } else { + goToCell(firstColIndex, getRowIdFromIndex(rowIndexBefore)); + } + break; + } + + case 'End': { + if (event.ctrlKey || event.metaKey || event.shiftKey) { + goToCell(lastColIndex, getRowIdFromIndex(lastRowIndexInPage)); + } else { + goToCell(lastColIndex, getRowIdFromIndex(rowIndexBefore)); + } + break; + } + + default: { + shouldPreventDefault = false; + } + } + + if (shouldPreventDefault) { + event.preventDefault(); } }, - [apiRef], + [apiRef, currentPageRows, getRowIdFromIndex, goToCell, goToHeader], ); - useGridApiEventHandler(apiRef, 'cellNavigationKeyDown', handleCellNavigationKeyDown); useGridApiEventHandler(apiRef, 'columnHeaderKeyDown', handleColumnHeaderKeyDown); useGridApiEventHandler(apiRef, 'columnGroupHeaderKeyDown', handleColumnGroupHeaderKeyDown); useGridApiEventHandler(apiRef, 'cellKeyDown', handleCellKeyDown); diff --git a/packages/grid/x-data-grid/src/models/events/gridEventLookup.ts b/packages/grid/x-data-grid/src/models/events/gridEventLookup.ts index a2711c4956c1..957e86387fcc 100644 --- a/packages/grid/x-data-grid/src/models/events/gridEventLookup.ts +++ b/packages/grid/x-data-grid/src/models/events/gridEventLookup.ts @@ -460,24 +460,6 @@ export interface GridEventLookup */ cellFocusOut: { params: GridCellParams; event: MuiBaseEvent }; - // Navigation - /** - * Fired when a [navigation key](/x/react-data-grid/accessibility#keyboard-navigation) is pressed in a cell. - * @ignore - do not document. - */ - cellNavigationKeyDown: { - params: GridCellParams | GridRowParams; - event: React.KeyboardEvent; - }; - /** - * Fired when a [navigation key](/x/react-data-grid/accessibility#keyboard-navigation) is pressed in a column header. - * @ignore - do not document. - */ - columnHeaderNavigationKeyDown: { - params: GridColumnHeaderParams; - event: React.KeyboardEvent; - }; - // Scroll /** * Fired during the scroll of the grid viewport.