From efc361e8df21803f9fd777520a655fa115accd97 Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Thu, 13 May 2021 12:12:41 -0500 Subject: [PATCH] Use context for selection (#2338) * Use context for selection * Use context for group selection * Move context provider a level up * Cleanup context usage * Use a single 'useRowSelection' hook * Format * Fix group selection * Cleanup import * Update src/hooks/useRowSelection.ts Co-authored-by: Nicolas Stepien <567105+nstepien@users.noreply.github.com> * Cleanup useRowSelection: remove extra functions * Do not destructure props * Update src/hooks/useRowSelection.ts Co-authored-by: Nicolas Stepien <567105+nstepien@users.noreply.github.com> Co-authored-by: Nicolas Stepien <567105+nstepien@users.noreply.github.com> --- src/Cell.tsx | 8 ---- src/Columns.tsx | 68 +++++++++++++++++++------------ src/DataGrid.tsx | 9 ++-- src/GroupCell.tsx | 18 +------- src/GroupRow.tsx | 79 ++++++++++++++++++------------------ src/Row.tsx | 40 ++++++++---------- src/hooks/index.ts | 1 + src/hooks/useRowSelection.ts | 22 ++++++++++ src/index.ts | 1 + src/types.ts | 8 +--- 10 files changed, 130 insertions(+), 124 deletions(-) create mode 100644 src/hooks/useRowSelection.ts diff --git a/src/Cell.tsx b/src/Cell.tsx index b273ee407d..0d7bd4f546 100644 --- a/src/Cell.tsx +++ b/src/Cell.tsx @@ -48,7 +48,6 @@ function Cell( isCellSelected, isCopied, isDraggedOver, - isRowSelected, row, rowIdx, dragHandleProps, @@ -58,7 +57,6 @@ function Cell( onContextMenu, onRowChange, selectCell, - selectRow, ...props }: CellRendererProps, ref: React.Ref @@ -98,10 +96,6 @@ function Cell( onRowChange(rowIdx, newRow); } - function onRowSelectionChange(checked: boolean, isShiftClick: boolean) { - selectRow({ rowIdx, checked, isShiftClick }); - } - return (
( rowIdx={rowIdx} row={row} isCellSelected={isCellSelected} - isRowSelected={isRowSelected} - onRowSelectionChange={onRowSelectionChange} onRowChange={handleRowChange} /> {dragHandleProps &&
} diff --git a/src/Columns.tsx b/src/Columns.tsx index 68e49dc952..8592ceee8f 100644 --- a/src/Columns.tsx +++ b/src/Columns.tsx @@ -1,9 +1,46 @@ import { SelectCellFormatter } from './formatters'; -import type { Column } from './types'; -import { stopPropagation } from './utils/domUtils'; +import { useRowSelection } from './hooks'; +import type { Column, FormatterProps, GroupFormatterProps } from './types'; +import { stopPropagation } from './utils'; export const SELECT_COLUMN_KEY = 'select-row'; +function SelectFormatter(props: FormatterProps) { + const [isRowSelected, onRowSelectionChange] = useRowSelection(); + + return ( + { + onRowSelectionChange({ rowIdx: props.rowIdx, checked, isShiftClick }); + }} + /> + ); +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function SelectGroupFormatter(props: GroupFormatterProps) { + const [isRowSelected, onRowSelectionChange] = useRowSelection(); + + return ( + { + onRowSelectionChange({ checked, isShiftClick: false, rowIdx: props.rowIdx }); + }} + // Stop propagation to prevent row selection + onClick={stopPropagation} + /> + ); +} + // eslint-disable-next-line @typescript-eslint/no-explicit-any export const SelectColumn: Column = { key: SELECT_COLUMN_KEY, @@ -22,29 +59,6 @@ export const SelectColumn: Column = { /> ); }, - formatter(props) { - return ( - - ); - }, - groupFormatter(props) { - return ( - - ); - } + formatter: SelectFormatter, + groupFormatter: SelectGroupFormatter }; diff --git a/src/DataGrid.tsx b/src/DataGrid.tsx index 6301d6db66..f75c57e6c9 100644 --- a/src/DataGrid.tsx +++ b/src/DataGrid.tsx @@ -15,7 +15,8 @@ import { useCalculatedColumns, useViewportColumns, useViewportRows, - useLatestFunc + useLatestFunc, + RowSelectionChangeProvider } from './hooks'; import HeaderRow from './HeaderRow'; import FilterRow from './FilterRow'; @@ -965,7 +966,6 @@ function DataGrid( onFocus={selectedPosition.rowIdx === rowIdx ? handleFocus : undefined} onKeyDown={selectedPosition.rowIdx === rowIdx ? handleKeyDown : undefined} selectCell={selectCellWrapper} - selectRow={selectRowWrapper} toggleGroup={toggleGroupWrapper} /> ); @@ -1004,7 +1004,6 @@ function DataGrid( selectedCellProps={getSelectedCellProps(rowIdx)} onRowChange={handleFormatterRowChangeWrapper} selectCell={selectCellWrapper} - selectRow={selectRowWrapper} /> ); } @@ -1098,7 +1097,9 @@ function DataGrid( onFocus={onGridFocus} />
- {getViewportRows()} + + {getViewportRows()} + {summaryRows?.map((row, rowIdx) => ( aria-rowindex={headerRowsCount + rowsCount + rowIdx + 1} diff --git a/src/GroupCell.tsx b/src/GroupCell.tsx index 141fc7d80e..8d86273818 100644 --- a/src/GroupCell.tsx +++ b/src/GroupCell.tsx @@ -6,14 +6,7 @@ import type { GroupRowRendererProps } from './GroupRow'; type SharedGroupRowRendererProps = Pick< GroupRowRendererProps, - | 'id' - | 'rowIdx' - | 'groupKey' - | 'childRows' - | 'isExpanded' - | 'isRowSelected' - | 'selectRow' - | 'toggleGroup' + 'id' | 'rowIdx' | 'groupKey' | 'childRows' | 'isExpanded' | 'toggleGroup' >; interface GroupCellProps extends SharedGroupRowRendererProps { @@ -29,20 +22,14 @@ function GroupCell({ childRows, isExpanded, isCellSelected, - isRowSelected, column, groupColumnIndex, - selectRow, toggleGroup: toggleGroupWrapper }: GroupCellProps) { function toggleGroup() { toggleGroupWrapper(id); } - function onRowSelectionChange(checked: boolean) { - selectRow({ rowIdx, checked, isShiftClick: false }); - } - // Only make the cell clickable if the group level matches const isLevelMatching = column.rowGroup && groupColumnIndex === column.idx; @@ -60,13 +47,12 @@ function GroupCell({ > {(!column.rowGroup || groupColumnIndex === column.idx) && column.groupFormatter && ( )} diff --git a/src/GroupRow.tsx b/src/GroupRow.tsx index 51c2bfad36..87419cf6b9 100644 --- a/src/GroupRow.tsx +++ b/src/GroupRow.tsx @@ -5,7 +5,8 @@ import clsx from 'clsx'; import { groupRowClassname, groupRowSelectedClassname, rowClassname } from './style'; import { SELECT_COLUMN_KEY } from './Columns'; import GroupCell from './GroupCell'; -import type { CalculatedColumn, Position, SelectRowEvent, Omit } from './types'; +import type { CalculatedColumn, Position, Omit } from './types'; +import { RowSelectionProvider } from './hooks'; export interface GroupRowRendererProps extends Omit, 'style' | 'children'> { @@ -21,7 +22,6 @@ export interface GroupRowRendererProps isExpanded: boolean; isRowSelected: boolean; selectCell: (position: Position, enableEditor?: boolean) => void; - selectRow: (selectRowEvent: SelectRowEvent) => void; toggleGroup: (expandedGroupId: unknown) => void; } @@ -38,7 +38,6 @@ function GroupedRow({ selectedCellIdx, isRowSelected, selectCell, - selectRow, toggleGroup, ...props }: GroupRowRendererProps) { @@ -50,44 +49,44 @@ function GroupedRow({ } return ( -
+
- {viewportColumns.map((column) => ( - - key={column.key} - id={id} - rowIdx={rowIdx} - groupKey={groupKey} - childRows={childRows} - isExpanded={isExpanded} - isRowSelected={isRowSelected} - isCellSelected={selectedCellIdx === column.idx} - column={column} - groupColumnIndex={idx} - selectRow={selectRow} - toggleGroup={toggleGroup} - /> - ))} -
+ {...props} + > + {viewportColumns.map((column) => ( + + key={column.key} + id={id} + rowIdx={rowIdx} + groupKey={groupKey} + childRows={childRows} + isExpanded={isExpanded} + isCellSelected={selectedCellIdx === column.idx} + column={column} + groupColumnIndex={idx} + toggleGroup={toggleGroup} + /> + ))} +
+ ); } diff --git a/src/Row.tsx b/src/Row.tsx index 98b4e622e1..595d7bafc4 100644 --- a/src/Row.tsx +++ b/src/Row.tsx @@ -7,6 +7,7 @@ import { getColSpan } from './utils'; import Cell from './Cell'; import EditCell from './EditCell'; import type { RowRendererProps, SelectedCellProps } from './types'; +import { RowSelectionProvider } from './hooks'; function Row( { @@ -28,9 +29,6 @@ function Row( height, onRowChange, selectCell, - selectRow, - 'aria-rowindex': ariaRowIndex, - 'aria-selected': ariaSelected, ...props }: RowRendererProps, ref: React.Ref @@ -84,7 +82,6 @@ function Row( isCopied={copiedCellIdx === column.idx} isDraggedOver={draggedOverCellIdx === column.idx} isCellSelected={isCellSelected} - isRowSelected={isRowSelected} dragHandleProps={ isCellSelected ? (selectedCellProps as SelectedCellProps).dragHandleProps : undefined } @@ -93,29 +90,28 @@ function Row( onRowClick={onRowClick} onRowChange={onRowChange} selectCell={selectCell} - selectRow={selectRow} /> ); } return ( -
- {cells} -
+ +
+ {cells} +
+
); } diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 75be89ed47..3cd35d019b 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -5,3 +5,4 @@ export * from './useViewportColumns'; export * from './useViewportRows'; export * from './useFocusRef'; export * from './useLatestFunc'; +export * from './useRowSelection'; diff --git a/src/hooks/useRowSelection.ts b/src/hooks/useRowSelection.ts new file mode 100644 index 0000000000..a97759c255 --- /dev/null +++ b/src/hooks/useRowSelection.ts @@ -0,0 +1,22 @@ +import { createContext, useContext } from 'react'; +import type { SelectRowEvent } from '../types'; + +const RowSelectionContext = createContext(undefined); + +export const RowSelectionProvider = RowSelectionContext.Provider; + +const RowSelectionChangeContext = + createContext<((selectRowEvent: SelectRowEvent) => void) | undefined>(undefined); + +export const RowSelectionChangeProvider = RowSelectionChangeContext.Provider; + +export function useRowSelection(): [boolean, (selectRowEvent: SelectRowEvent) => void] { + const rowSelectionContext = useContext(RowSelectionContext); + const rowSelectionChangeContext = useContext(RowSelectionChangeContext); + + if (rowSelectionContext === undefined || rowSelectionChangeContext === undefined) { + throw new Error('useRowSelection must be used within DataGrid cells'); + } + + return [rowSelectionContext, rowSelectionChangeContext]; +} diff --git a/src/index.ts b/src/index.ts index c50ccc1e66..7ccf4c9298 100644 --- a/src/index.ts +++ b/src/index.ts @@ -6,6 +6,7 @@ export * from './Columns'; export * from './formatters'; export { default as TextEditor } from './editors/TextEditor'; export { default as SortableHeaderCell } from './headerCells/SortableHeaderCell'; +export { useRowSelection } from './hooks'; export type { Column, CalculatedColumn, diff --git a/src/types.ts b/src/types.ts index 794b0b5a9a..1d05de65d2 100644 --- a/src/types.ts +++ b/src/types.ts @@ -81,8 +81,6 @@ export interface FormatterProps { column: CalculatedColumn; row: TRow; isCellSelected: boolean; - isRowSelected: boolean; - onRowSelectionChange: (checked: boolean, isShiftClick: boolean) => void; onRowChange: (row: Readonly) => void; } @@ -92,13 +90,12 @@ export interface SummaryFormatterProps { } export interface GroupFormatterProps { + rowIdx: number; groupKey: unknown; column: CalculatedColumn; childRows: readonly TRow[]; isExpanded: boolean; isCellSelected: boolean; - isRowSelected: boolean; - onRowSelectionChange: (checked: boolean) => void; toggleGroup: () => void; } @@ -151,12 +148,10 @@ export interface CellRendererProps isCopied: boolean; isDraggedOver: boolean; isCellSelected: boolean; - isRowSelected: boolean; dragHandleProps?: Pick, 'onMouseDown' | 'onDoubleClick'>; onRowChange: (rowIdx: number, newRow: TRow) => void; onRowClick?: (rowIdx: number, row: TRow, column: CalculatedColumn) => void; selectCell: (position: Position, enableEditor?: boolean) => void; - selectRow: (selectRowEvent: SelectRowEvent) => void; } export interface RowRendererProps @@ -177,7 +172,6 @@ export interface RowRendererProps rowClass?: (row: TRow) => string | undefined; setDraggedOverRowIdx?: (overRowIdx: number) => void; selectCell: (position: Position, enableEditor?: boolean) => void; - selectRow: (selectRowEvent: SelectRowEvent) => void; } export interface FilterRendererProps {