From 502ee11212dcba07ae7fc3a4760fbf0f939984c6 Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Tue, 1 Oct 2019 22:05:17 -0500 Subject: [PATCH 01/34] Re-implement row selection --- examples/scripts/example16-row-select.js | 25 +- .../src/editors/index.ts | 2 +- packages/react-data-grid/src/Canvas.tsx | 15 +- packages/react-data-grid/src/Grid.tsx | 6 +- .../react-data-grid/src/ReactDataGrid.tsx | 292 +++++------------- packages/react-data-grid/src/RowUtils.ts | 27 -- packages/react-data-grid/src/Viewport.tsx | 2 - .../src/common/editors/CheckboxEditor.tsx | 29 -- .../editors/__tests__/CheckboxEditor.spec.tsx | 35 --- .../src/common/editors/index.ts | 1 - packages/react-data-grid/src/common/types.ts | 11 - .../src/formatters/SelectAll.tsx | 19 -- .../src/formatters/SelectCellFormatter.tsx | 24 ++ .../react-data-grid/src/formatters/index.ts | 1 - 14 files changed, 111 insertions(+), 378 deletions(-) delete mode 100644 packages/react-data-grid/src/common/editors/CheckboxEditor.tsx delete mode 100644 packages/react-data-grid/src/common/editors/__tests__/CheckboxEditor.spec.tsx delete mode 100644 packages/react-data-grid/src/formatters/SelectAll.tsx create mode 100644 packages/react-data-grid/src/formatters/SelectCellFormatter.tsx diff --git a/examples/scripts/example16-row-select.js b/examples/scripts/example16-row-select.js index 66a8005808..e40917fa3b 100644 --- a/examples/scripts/example16-row-select.js +++ b/examples/scripts/example16-row-select.js @@ -29,27 +29,21 @@ class Example extends React.Component { count: i * 1000 }); } - this.state = { rows, selectedIndexes: [] }; + this.state = { + rows, + selectedRows: new Set() + }; } rowGetter = (i) => { return this.state.rows[i]; }; - onRowsSelected = (rows) => { - this.setState({ selectedIndexes: this.state.selectedIndexes.concat(rows.map(r => r.rowIdx)) }); - }; - - onRowsDeselected = (rows) => { - const rowIndexes = rows.map(r => r.rowIdx); - this.setState({ selectedIndexes: this.state.selectedIndexes.filter(i => rowIndexes.indexOf(i) === -1) }); - }; - render() { - const rowText = this.state.selectedIndexes.length === 1 ? 'row' : 'rows'; + const rowText = this.state.selectedRows.size === 1 ? 'row' : 'rows'; return (
- {this.state.selectedIndexes.length} {rowText} selected + {this.state.selectedRows.size} {rowText} selected { + this.setState({ selectedRows }); } }} /> diff --git a/packages/react-data-grid-addons/src/editors/index.ts b/packages/react-data-grid-addons/src/editors/index.ts index 3449aa41a6..5c9d1b5a4b 100644 --- a/packages/react-data-grid-addons/src/editors/index.ts +++ b/packages/react-data-grid-addons/src/editors/index.ts @@ -1,2 +1,2 @@ -export { SimpleTextEditor, CheckboxEditor } from 'react-data-grid'; +export { SimpleTextEditor } from 'react-data-grid'; export { default as DropDownEditor } from './DropDownEditor'; diff --git a/packages/react-data-grid/src/Canvas.tsx b/packages/react-data-grid/src/Canvas.tsx index 37db96053a..4f677b5e92 100644 --- a/packages/react-data-grid/src/Canvas.tsx +++ b/packages/react-data-grid/src/Canvas.tsx @@ -5,7 +5,6 @@ import Row from './Row'; import RowsContainerDefault from './RowsContainer'; import RowGroup from './RowGroup'; import { InteractionMasks } from './masks'; -import * as rowUtils from './RowUtils'; import { getColumnScrollPosition, isPositionStickySupported } from './utils'; import { EventTypes } from './common/enums'; import { CalculatedColumn, Position, ScrollPosition, SubRowDetails, RowRenderer, RowRendererProps, RowData } from './common/types'; @@ -22,7 +21,6 @@ type SharedViewportProps = Pick, | 'rowHeight' | 'scrollToRowIndex' | 'contextMenu' -| 'rowSelection' | 'getSubRowDetails' | 'rowGroupRenderer' | 'enableCellSelect' @@ -147,19 +145,8 @@ export default class Canvas extends React.PureComponent> { } isRowSelected(idx: number, row: R) { - // Use selectedRows if set if (this.props.selectedRows) { - const selectedRow = this.props.selectedRows.find(r => { - const rowKeyValue = rowUtils.get(row, this.props.rowKey); - return r[this.props.rowKey] === rowKeyValue; - }); - return !!(selectedRow && selectedRow.isSelected); - } - - // Else use new rowSelection props - if (this.props.rowSelection) { - const { keys, indexes, isSelectedKey } = this.props.rowSelection as { [key: string]: unknown }; - return rowUtils.isRowSelected(keys as { rowKey?: string; values?: string[] } | null, indexes as number[] | null, isSelectedKey as string | null, row, idx); + return this.props.selectedRows.has(row[this.props.rowKey]); } return false; diff --git a/packages/react-data-grid/src/Grid.tsx b/packages/react-data-grid/src/Grid.tsx index 6a429e6513..4da910aa67 100644 --- a/packages/react-data-grid/src/Grid.tsx +++ b/packages/react-data-grid/src/Grid.tsx @@ -3,7 +3,7 @@ import { isValidElementType } from 'react-is'; import Header, { HeaderHandle, HeaderProps } from './Header'; import Viewport, { ScrollState } from './Viewport'; -import { HeaderRowData, CellMetaData, RowSelection, InteractionMasksMetaData, SelectedRow, ColumnMetrics } from './common/types'; +import { HeaderRowData, CellMetaData, InteractionMasksMetaData, ColumnMetrics } from './common/types'; import { DEFINE_SORT } from './common/enums'; import { ReactDataGridProps } from './ReactDataGrid'; import { EventBus } from './masks'; @@ -42,8 +42,7 @@ type SharedDataGridProps = Pick, export interface GridProps extends SharedDataGridProps { headerRows: [HeaderRowData, HeaderRowData | undefined]; cellMetaData: CellMetaData; - selectedRows?: SelectedRow[]; - rowSelection?: RowSelection; + selectedRows?: ReadonlySet; rowOffsetHeight: number; eventBus: EventBus; interactionMasksMetaData: InteractionMasksMetaData; @@ -107,7 +106,6 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p minHeight={props.minHeight} scrollToRowIndex={props.scrollToRowIndex} contextMenu={props.contextMenu} - rowSelection={props.rowSelection} getSubRowDetails={props.getSubRowDetails} rowGroupRenderer={props.rowGroupRenderer} enableCellSelect={props.enableCellSelect} diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index edb09237b4..f1e8c92af7 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -10,10 +10,8 @@ import React, { import Grid from './Grid'; import ToolbarContainer, { ToolbarProps } from './ToolbarContainer'; -import CheckboxEditor, { CheckboxEditorProps } from './common/editors/CheckboxEditor'; -import { SelectAll } from './formatters'; -import * as rowUtils from './RowUtils'; -import KeyCodes from './KeyCodes'; +import SelectCellFormatter from './formatters/SelectCellFormatter'; +// import KeyCodes from './KeyCodes'; import { getColumnMetrics } from './ColumnMetrics'; import { ScrollState } from './Viewport'; import { RowsContainerProps } from './RowsContainer'; @@ -35,13 +33,11 @@ import { Position, RowExpandToggleEvent, RowGetter, - RowSelection, - RowSelectionParams, SelectedRange, SubRowDetails, SubRowOptions, - SelectedRow, - RowRendererProps + RowRendererProps, + FormatterProps } from './common/types'; export interface ReactDataGridProps { @@ -53,8 +49,6 @@ export interface ReactDataGridProps { headerRowHeight?: number; /** The height of the header filter row in pixels */ headerFiltersHeight?: number; - /** Deprecated: Legacy prop to turn on row selection. Use rowSelection props instead*/ - enableRowSelect?: boolean | string; /** Component used to render toolbar above the grid */ toolbar?: React.ReactElement> | React.ComponentType>; cellRangeSelection?: { @@ -64,8 +58,6 @@ export interface ReactDataGridProps { }; /** Minimum column width in pixels */ minColumnWidth?: number; - /** Component to render the UI in the header row for selecting all rows */ - selectAllRenderer?: React.ComponentType>; /** Function called whenever row is clicked */ onRowClick?(rowIdx: number, rowData: R, column: CalculatedColumn): void; /** Function called whenever row is double clicked */ @@ -80,18 +72,21 @@ export interface ReactDataGridProps { onGridKeyDown?(event: React.KeyboardEvent): void; onRowSelect?(rowData: R[]): void; rowSelection?: { - enableShiftSelect?: boolean; - /** Function called whenever rows are selected */ - onRowsSelected?(args: RowSelectionParams[]): void; - /** Function called whenever rows are deselected */ - onRowsDeselected?(args: RowSelectionParams[]): void; /** toggle whether to show a checkbox in first column to select rows */ showCheckbox?: boolean; - /** Method by which rows should be selected */ - selectBy: RowSelection; + enableShiftSelect?: boolean; + + /** Selected rows Set(); */ + selectedRows: Set; + + /** Function called whenever row selection is changed */ + onSelectedRowsChanged: (selectedRows: Set) => void; + + /** Custom checkbox formatter */ + // TODO: fix types + cellRenderer?: React.ReactElement; + headerCellRenderer?: React.ReactElement; }; - /** Custom checkbox formatter */ - rowActionsCell?: React.ComponentType>; /** * Callback called whenever row data is updated * When editing is enabled, this callback will be called for the following scenarios @@ -183,11 +178,6 @@ export interface ReactDataGridHandle { selectCell(position: Position, openEditor?: boolean): void; handleToggleFilter(): void; openCellEditor(rowIdx: number, colIdx: number): void; - getSelectedRows(): SelectedRow[] | undefined; -} - -function isRowSelected(keys: unknown, indexes: unknown, isSelectedKey: unknown, rowData: R, rowIdx: number) { - return rowUtils.isRowSelected(keys as { rowKey?: string; values?: string[] } | null, indexes as number[] | null, isSelectedKey as string | null, rowData, rowIdx); } /** @@ -205,10 +195,8 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ minHeight = 350, minWidth: width, enableCellSelect = false, - enableRowSelect = false, enableCellAutoFocus = true, cellNavigationMode = CellNavigationMode.NONE, - selectAllRenderer = SelectAll, editorPortalTarget = document.body, columns, rowsCount, @@ -219,9 +207,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ onClearFilters, ...props }: ReactDataGridProps, ref: React.Ref>) { - const [selectedRows, setSelectedRows] = useState[]>([]); const [canFilter, setCanFilter] = useState(false); - const [lastRowIdxUiSelected, setLastRowIdxUiSelected] = useState(-1); const [sortColumn, setSortColumn] = useState(props.sortColumn); const [sortDirection, setSortDirection] = useState(props.sortDirection); const [columnWidths, setColumnWidths] = useState(() => new Map()); @@ -229,184 +215,72 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ const [_keysDown] = useState(() => new Set()); const [gridWidth, setGridWidth] = useState(0); const gridRef = useRef(null); - const selectAllCheckboxRef = useRef(null); const viewportWidth = (width || gridWidth) - 2; // 2 for border width; - const gridColumns = useMemo>(() => { - function isSingleKeyDown(keyCode: number) { - return _keysDown.has(keyCode) && _keysDown.size === 1; - } - - function getSelectedRow(rows: SelectedRow[], key: unknown) { - return rows.find(r => r[rowKey] === key); - } - - function canUseNewRowSelection() { - return rowSelection && rowSelection.selectBy; - } - - // return false if not a shift select so can be handled as normal row selection - function handleShiftSelect(rowIdx: number) { - if (rowSelection && lastRowIdxUiSelected > -1 && isSingleKeyDown(KeyCodes.Shift)) { - const { keys, indexes, isSelectedKey } = rowSelection.selectBy as { [key: string]: unknown }; - const isPreviouslySelected = isRowSelected(keys, indexes, isSelectedKey, rowGetter(rowIdx), rowIdx); - - if (isPreviouslySelected) return false; - - let handled = false; - - if (rowIdx > lastRowIdxUiSelected) { - const rowsSelected = []; - - for (let i = lastRowIdxUiSelected + 1; i <= rowIdx; i++) { - rowsSelected.push({ rowIdx: i, row: rowGetter(i) }); - } - - if (typeof rowSelection.onRowsSelected === 'function') { - rowSelection.onRowsSelected(rowsSelected); - } - - handled = true; - } else if (rowIdx < lastRowIdxUiSelected) { - const rowsSelected = []; - - for (let i = rowIdx; i <= lastRowIdxUiSelected - 1; i++) { - rowsSelected.push({ rowIdx: i, row: rowGetter(i) }); - } - - if (typeof rowSelection.onRowsSelected === 'function') { - rowSelection.onRowsSelected(rowsSelected); - } - - handled = true; - } - - if (handled) { - setLastRowIdxUiSelected(rowIdx); - } - - return handled; - } - - return false; - } - - function handleNewRowSelect(rowIdx: number, rowData: R) { - const { current } = selectAllCheckboxRef; - if (current && current.checked === true) { - current.checked = false; - } - - if (rowSelection) { - const { keys, indexes, isSelectedKey } = rowSelection.selectBy as { [key: string]: unknown }; - const isPreviouslySelected = isRowSelected(keys, indexes, isSelectedKey, rowData, rowIdx); - - setLastRowIdxUiSelected(isPreviouslySelected ? -1 : rowIdx); - const cb = isPreviouslySelected ? rowSelection.onRowsDeselected : rowSelection.onRowsSelected; - if (typeof cb === 'function') { - cb([{ rowIdx, row: rowData }]); - } - } - } - - // columnKey not used here as this function will select the whole row, - // but needed to match the function signature in the CheckboxEditor - function handleRowSelect(rowIdx: number, columnKey: keyof R, rowData: R, event: React.ChangeEvent) { - event.stopPropagation(); - - if (canUseNewRowSelection()) { - if (rowSelection && rowSelection.enableShiftSelect === true) { - if (!handleShiftSelect(rowIdx)) { - handleNewRowSelect(rowIdx, rowData); - } - } else { - handleNewRowSelect(rowIdx, rowData); - } - } else { // Fallback to old onRowSelect handler - const newSelectedRows = enableRowSelect === 'single' ? [] : [...selectedRows]; - const selectedRow = getSelectedRow(newSelectedRows, rowData[rowKey]); - if (selectedRow) { - selectedRow.isSelected = !selectedRow.isSelected; - } else { - (rowData as SelectedRow).isSelected = true; - newSelectedRows.push(rowData as SelectedRow); - } - setSelectedRows(newSelectedRows); - if (onRowSelect) { - onRowSelect(newSelectedRows.filter(r => r.isSelected === true)); - } + const gridColumns = useMemo(() => { + // TODO: handle row selection without checkbox, i.e using row click + if (!rowSelection || !rowSelection.showCheckbox) return columns; + + // function isShiftKeyPressed() { + // return _keysDown.has(KeyCodes.Shift) && _keysDown.size === 1; + // } + + const { selectedRows, onSelectedRowsChanged /*, enableShiftSelect*/ } = rowSelection; + // let lastSelectedRowIdx: number | undefined; + + function handleSelectionChange(rowIdx: number, row: R, value: boolean) { + const newSelectedRows = new Set(selectedRows); + const ids = [row[rowKey]]; + + // TODO: handle shift select + // if (enableShiftSelect) { + // if (typeof lastSelectedRowIdx === 'number' && ) { + // } else if (isShiftKeyPressed) { + // lastSelectedRowIdx = rowIdx; + // ids.push(row[rowKey]); + // } else { } + // } else { + // ids.push(row[rowKey]); + // } + + if (value) { + ids.forEach(id => newSelectedRows.add(id)); + } else { + ids.forEach(id => newSelectedRows.delete(id)); } + onSelectedRowsChanged(newSelectedRows); } - function handleCheckboxChange(e: React.ChangeEvent) { - const allRowsSelected = e.currentTarget.checked; - if (rowSelection && canUseNewRowSelection()) { - const { keys, indexes, isSelectedKey } = rowSelection.selectBy as { [key: string]: unknown }; - - if (allRowsSelected && typeof rowSelection.onRowsSelected === 'function') { - const selectedRows = []; - for (let i = 0; i < rowsCount; i++) { - const rowData = rowGetter(i); - if (!isRowSelected(keys, indexes, isSelectedKey, rowData, i)) { - selectedRows.push({ rowIdx: i, row: rowData }); - } - } - - if (selectedRows.length > 0) { - rowSelection.onRowsSelected(selectedRows); - } - } else if (!allRowsSelected && typeof rowSelection.onRowsDeselected === 'function') { - const deselectedRows = []; - for (let i = 0; i < rowsCount; i++) { - const rowData = rowGetter(i); - if (isRowSelected(keys, indexes, isSelectedKey, rowData, i)) { - deselectedRows.push({ rowIdx: i, row: rowData }); - } - } - - if (deselectedRows.length > 0) { - rowSelection.onRowsDeselected(deselectedRows); - } - } - } else { - const selectedRows: SelectedRow[] = []; + function handleAllSelectionChange(value: boolean) { + const newSelectedRows = new Set(); + if (value) { for (let i = 0; i < rowsCount; i++) { - const row = { ...rowGetter(i), isSelected: allRowsSelected }; - selectedRows.push(row); - } - setSelectedRows(selectedRows); - if (typeof onRowSelect === 'function') { - onRowSelect(selectedRows.filter(r => r.isSelected === true)); + newSelectedRows.add(rowGetter(i)[rowKey]); } } + onSelectedRowsChanged(newSelectedRows); } - if (props.rowActionsCell || (enableRowSelect && !rowSelection) || (rowSelection && rowSelection.showCheckbox !== false)) { - const SelectAllComponent = selectAllRenderer; - const headerRenderer = enableRowSelect === 'single' - ? undefined - : ; - const Formatter = (props.rowActionsCell ? props.rowActionsCell : CheckboxEditor) as unknown as React.ComponentClass<{ rowSelection: unknown }>; - const selectColumn = { - key: 'select-row', - name: '', - formatter: , - onCellChange: handleRowSelect, - filterable: false, - headerRenderer, - width: 60, - frozen: true, - getRowMetaData: (rowData: R) => rowData, - cellClass: props.rowActionsCell ? 'rdg-row-actions-cell' : '' - } as unknown as Column; - - return Array.isArray(columns) - ? [selectColumn, ...columns] - : columns.unshift(selectColumn); - } - - return columns; - }, [_keysDown, columns, enableRowSelect, lastRowIdxUiSelected, onRowSelect, props.rowActionsCell, rowGetter, rowKey, rowSelection, rowsCount, selectAllRenderer, selectedRows]); + // TODO: fix type + const selectColumn = { + key: 'select-row', + name: '', + formatter: (p: FormatterProps) => ( + handleSelectionChange(p.rowIdx, p.row, value)} + /> + ), + filterable: false, + headerRenderer: handleAllSelectionChange(value)} />, + width: 60, + frozen: true + } as Column; + + return Array.isArray(columns) + ? [selectColumn, ...columns] + : columns.unshift(selectColumn); + }, [columns, rowGetter, rowKey, rowSelection, rowsCount]); const columnMetrics = useMemo(() => { if (viewportWidth <= 0) return null; @@ -575,18 +449,6 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ ]; } - function getRowSelectionProps() { - return rowSelection && rowSelection.selectBy; - } - - function getSelectedRows(): SelectedRow[] | undefined { - if (rowSelection) { - return; - } - - return selectedRows.filter(r => r.isSelected === true); - } - function openCellEditor(rowIdx: number, idx: number) { selectCell({ rowIdx, idx }, true); } @@ -599,8 +461,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ scrollToColumn, selectCell, handleToggleFilter, - openCellEditor, - getSelectedRows + openCellEditor })); const cellMetaData: CellMetaData = { @@ -662,8 +523,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ rowRenderer={props.rowRenderer} rowGroupRenderer={props.rowGroupRenderer} cellMetaData={cellMetaData} - selectedRows={getSelectedRows()} - rowSelection={getRowSelectionProps()} + selectedRows={rowSelection && rowSelection.selectedRows} rowOffsetHeight={rowOffsetHeight} sortColumn={sortColumn} sortDirection={sortDirection} @@ -715,10 +575,6 @@ export default class ReactDataGrid extends React.Component[] | undefined { - return this.gridRef.current!.getSelectedRows(); - } - render() { return ( (row: R, property: keyof R) { return row[property]; } - -interface Keys { - rowKey?: string; - values?: string[]; -} - -export function isRowSelected( - keys?: Keys | null, - indexes?: number[] | null, - isSelectedKey?: string | null, - rowData?: R, - rowIdx?: number -): boolean { - if (Array.isArray(indexes) && typeof rowIdx === 'number') { - return indexes.includes(rowIdx); - } - - if (rowData && keys && keys.rowKey && Array.isArray(keys.values)) { - return keys.values.includes(rowData[keys.rowKey as K] as unknown as string); - } - - if (rowData && typeof isSelectedKey === 'string') { - return !!rowData[isSelectedKey as K]; - } - - return false; -} diff --git a/packages/react-data-grid/src/Viewport.tsx b/packages/react-data-grid/src/Viewport.tsx index 38730d9acb..86edaa4c44 100644 --- a/packages/react-data-grid/src/Viewport.tsx +++ b/packages/react-data-grid/src/Viewport.tsx @@ -25,7 +25,6 @@ type SharedGridProps = Pick, | 'minHeight' | 'scrollToRowIndex' | 'contextMenu' -| 'rowSelection' | 'getSubRowDetails' | 'rowGroupRenderer' | 'enableCellSelect' @@ -150,7 +149,6 @@ export default function Viewport({ onScroll={onScroll} scrollToRowIndex={props.scrollToRowIndex} contextMenu={props.contextMenu} - rowSelection={props.rowSelection} getSubRowDetails={props.getSubRowDetails} rowGroupRenderer={props.rowGroupRenderer} isScrolling={isScrolling} diff --git a/packages/react-data-grid/src/common/editors/CheckboxEditor.tsx b/packages/react-data-grid/src/common/editors/CheckboxEditor.tsx deleted file mode 100644 index ac9201874e..0000000000 --- a/packages/react-data-grid/src/common/editors/CheckboxEditor.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { CalculatedColumn } from '../types'; - -export interface CheckboxEditorProps { - value?: boolean; - rowIdx: number; - column: CalculatedColumn; - dependentValues: unknown; -} - -export default function CheckboxEditor({ value, rowIdx, column, dependentValues }: CheckboxEditorProps) { - function handleChange(event: React.ChangeEvent) { - if (column.onCellChange) { - column.onCellChange(rowIdx, column.key, dependentValues, event); - } - } - - return ( - - ); -} diff --git a/packages/react-data-grid/src/common/editors/__tests__/CheckboxEditor.spec.tsx b/packages/react-data-grid/src/common/editors/__tests__/CheckboxEditor.spec.tsx deleted file mode 100644 index db6287e682..0000000000 --- a/packages/react-data-grid/src/common/editors/__tests__/CheckboxEditor.spec.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import CheckboxEditor from '../CheckboxEditor'; -import { CalculatedColumn } from '../../types'; - -describe('CheckboxEditor', () => { - function setup(value = true) { - const testColumn: CalculatedColumn<{ columnKey?: string }> = { - idx: 0, - name: 'columnKey', - key: 'columnKey', - width: 100, - left: 0 - }; - - return mount( - - ); - } - - it('should be selected if value prop is true', () => { - const wrapper = setup(); - expect(wrapper.find('input').prop('checked')).toBe(true); - }); - - it('should not be selected if value prop is false', () => { - const wrapper = setup(false); - expect(wrapper.find('input').prop('checked')).toBe(false); - }); -}); diff --git a/packages/react-data-grid/src/common/editors/index.ts b/packages/react-data-grid/src/common/editors/index.ts index e82f1eeb5d..d58276ced9 100644 --- a/packages/react-data-grid/src/common/editors/index.ts +++ b/packages/react-data-grid/src/common/editors/index.ts @@ -1,2 +1 @@ -export { default as CheckboxEditor } from './CheckboxEditor'; export { default as SimpleTextEditor } from './SimpleTextEditor'; diff --git a/packages/react-data-grid/src/common/types.ts b/packages/react-data-grid/src/common/types.ts index e2b4ef619a..0cae7284b6 100644 --- a/packages/react-data-grid/src/common/types.ts +++ b/packages/react-data-grid/src/common/types.ts @@ -5,8 +5,6 @@ import { HeaderRowType, UpdateActions } from './enums'; export type Omit = Pick>; -export type SelectedRow = TRow & { isSelected: boolean }; - interface ColumnValue { /** The name of the column. By default it will be displayed in the header cell */ name: string; @@ -43,8 +41,6 @@ interface ColumnValue>; - // TODO: these props are only used by checkbox editor and we should remove them - onCellChange?(rowIdx: number, key: keyof TRow, dependentValues: TDependentValue, event: React.SyntheticEvent): void; getRowMetaData?(rowData: TRow, column: CalculatedColumn): TDependentValue; } @@ -277,8 +273,6 @@ export interface RowGroupMetaData { getRowRenderer?(props: unknown, rowIdx: number): React.ReactElement; } -export type RowSelection = { indexes?: number[] } | { isSelectedKey?: string } | { keys?: { values: unknown[]; rowKey: string } }; - export interface HeaderRowData { rowType: HeaderRowType; height: number; @@ -329,8 +323,3 @@ export interface CheckCellIsEditableEvent extends Position { row: TRow; column: CalculatedColumn; } - -export interface RowSelectionParams { - rowIdx: number; - row: TRow; -} diff --git a/packages/react-data-grid/src/formatters/SelectAll.tsx b/packages/react-data-grid/src/formatters/SelectAll.tsx deleted file mode 100644 index d593fd11e1..0000000000 --- a/packages/react-data-grid/src/formatters/SelectAll.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React, { forwardRef } from 'react'; - -export interface SelectAllProps { - onChange(event: React.ChangeEvent): void; -} - -export const SelectAll = forwardRef(function SelectAll({ onChange }, ref) { - return ( - - ); -}); diff --git a/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx b/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx new file mode 100644 index 0000000000..cf1bd54412 --- /dev/null +++ b/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +interface SelectCellFormatterProps { + value: boolean; + onChange(value: boolean): void; +} + +export default function SelectCellFormatter({ value, onChange }: SelectCellFormatterProps) { + function handleChange(e: React.ChangeEvent) { + onChange(e.target.checked); + } + + return ( + + ); +} diff --git a/packages/react-data-grid/src/formatters/index.ts b/packages/react-data-grid/src/formatters/index.ts index 722e796eef..43bce134d3 100644 --- a/packages/react-data-grid/src/formatters/index.ts +++ b/packages/react-data-grid/src/formatters/index.ts @@ -1,2 +1 @@ export * from './SimpleCellFormatter'; -export * from './SelectAll'; From 97c78fa6bccbdd17afea0ca34a0a1e30bebfce46 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 12:05:14 +0100 Subject: [PATCH 02/34] Re-enable jsx-curly-brace-presence --- .eslintrc.js | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index ef200d9401..e87dc2a438 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -357,7 +357,7 @@ const rules = { 'react/jsx-no-undef': 0, 'react/jsx-no-useless-fragment': 0, 'react/jsx-one-expression-per-line': 0, - 'react/jsx-curly-brace-presence': 0, + 'react/jsx-curly-brace-presence': 1, 'react/jsx-fragments': 1, 'react/jsx-pascal-case': 1, 'react/jsx-props-no-multi-spaces': 1, diff --git a/package.json b/package.json index 73bb0ba451..2fc6543a70 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.14.0", "eslint": "^6.5.1", - "eslint-plugin-react": "^7.15.0", + "eslint-plugin-react": "^7.15.1", "eslint-plugin-react-hooks": "^2.1.1", "eslint-plugin-sonarjs": "^0.4.0", "faker": "^4.1.0", From f5f9e86f0ae00962e2b04056664a42bbbc384eda Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 12:20:39 +0100 Subject: [PATCH 03/34] onSelectedRowsChanged -> onSelectedRowsChange --- examples/scripts/example16-row-select.js | 2 +- packages/react-data-grid/src/ReactDataGrid.tsx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/scripts/example16-row-select.js b/examples/scripts/example16-row-select.js index e40917fa3b..89d8c793f7 100644 --- a/examples/scripts/example16-row-select.js +++ b/examples/scripts/example16-row-select.js @@ -54,7 +54,7 @@ class Example extends React.Component { showCheckbox: true, enableShiftSelect: true, selectedRows: this.state.selectedRows, - onSelectedRowsChanged: (selectedRows) => { + onSelectedRowsChange: (selectedRows) => { this.setState({ selectedRows }); } }} diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index f1e8c92af7..80fa8d22af 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -80,7 +80,7 @@ export interface ReactDataGridProps { selectedRows: Set; /** Function called whenever row selection is changed */ - onSelectedRowsChanged: (selectedRows: Set) => void; + onSelectedRowsChange: (selectedRows: Set) => void; /** Custom checkbox formatter */ // TODO: fix types @@ -225,7 +225,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ // return _keysDown.has(KeyCodes.Shift) && _keysDown.size === 1; // } - const { selectedRows, onSelectedRowsChanged /*, enableShiftSelect*/ } = rowSelection; + const { selectedRows, onSelectedRowsChange /*, enableShiftSelect*/ } = rowSelection; // let lastSelectedRowIdx: number | undefined; function handleSelectionChange(rowIdx: number, row: R, value: boolean) { @@ -248,7 +248,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ } else { ids.forEach(id => newSelectedRows.delete(id)); } - onSelectedRowsChanged(newSelectedRows); + onSelectedRowsChange(newSelectedRows); } function handleAllSelectionChange(value: boolean) { @@ -258,7 +258,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ newSelectedRows.add(rowGetter(i)[rowKey]); } } - onSelectedRowsChanged(newSelectedRows); + onSelectedRowsChange(newSelectedRows); } // TODO: fix type From c7bf8fec5edb850bdbf584c2823324c2feb5a819 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 12:39:22 +0100 Subject: [PATCH 04/34] Small cleanup in Canvas.tsx --- packages/react-data-grid/src/Canvas.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/react-data-grid/src/Canvas.tsx b/packages/react-data-grid/src/Canvas.tsx index 4f677b5e92..82e47e5038 100644 --- a/packages/react-data-grid/src/Canvas.tsx +++ b/packages/react-data-grid/src/Canvas.tsx @@ -144,12 +144,8 @@ export default class Canvas extends React.PureComponent> { return scrollVariation > 0 ? rowHeight - scrollVariation : 0; } - isRowSelected(idx: number, row: R) { - if (this.props.selectedRows) { - return this.props.selectedRows.has(row[this.props.rowKey]); - } - - return false; + isRowSelected(row: R): boolean { + return this.props.selectedRows !== undefined && this.props.selectedRows.has(row[this.props.rowKey]); } setScrollLeft(scrollLeft: number) { @@ -273,7 +269,7 @@ export default class Canvas extends React.PureComponent> { row, height: rowHeight, columns, - isSelected: this.isRowSelected(rowIdx, row), + isSelected: this.isRowSelected(row), cellMetaData, subRowDetails, colVisibleStartIdx, From f50d526c5be5be9137ea24290726c0c192050b06 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 13:06:13 +0100 Subject: [PATCH 05/34] small tweaks --- packages/react-data-grid/src/ReactDataGrid.tsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index 80fa8d22af..ede7d5016c 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -261,20 +261,20 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ onSelectedRowsChange(newSelectedRows); } - // TODO: fix type - const selectColumn = { + // TODO: remove type assertion + const selectColumn: Column = { key: 'select-row', name: '', + width: 60, + filterable: false, + frozen: true, + headerRenderer: , formatter: (p: FormatterProps) => ( handleSelectionChange(p.rowIdx, p.row, value)} + onChange={value => handleSelectionChange(p.rowIdx, p.row, value)} /> - ), - filterable: false, - headerRenderer: handleAllSelectionChange(value)} />, - width: 60, - frozen: true + ) } as Column; return Array.isArray(columns) From 70c9718a76462065f2c113b15ed57320435d4374 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 13:23:26 +0100 Subject: [PATCH 06/34] Delete RowUtils tests --- .../src/__tests__/RowUtils.spec.ts | 47 ------------------- .../src/formatters/SelectCellFormatter.tsx | 2 +- 2 files changed, 1 insertion(+), 48 deletions(-) delete mode 100644 packages/react-data-grid/src/__tests__/RowUtils.spec.ts diff --git a/packages/react-data-grid/src/__tests__/RowUtils.spec.ts b/packages/react-data-grid/src/__tests__/RowUtils.spec.ts deleted file mode 100644 index 6e9b202c1f..0000000000 --- a/packages/react-data-grid/src/__tests__/RowUtils.spec.ts +++ /dev/null @@ -1,47 +0,0 @@ -import * as RowUtils from '../RowUtils'; - -describe('RowUtils Tests', () => { - describe('isRowSelected', () => { - describe('using index', () => { - it('should return true', () => { - const result = RowUtils.isRowSelected(null, [0, 2, 4], null, {}, 2); - expect(result).toBe(true); - }); - - it('should return false', () => { - const result = RowUtils.isRowSelected(null, [0, 2, 4], null, {}, 1); - expect(result).toBe(false); - }); - }); - - describe('using keys', () => { - it('should return true', () => { - const keyProps = { rowKey: 'name', values: ['tim', 'willim', 'deigo'] }; - const rowData = { id: 1, name: 'tim' }; - const result = RowUtils.isRowSelected(keyProps, null, null, rowData, 0); - expect(result).toBe(true); - }); - - it('should return false', () => { - const keyProps = { rowKey: 'name', values: ['tim', 'willim', 'deigo'] }; - const rowData = { id: 1, name: 'john' }; - const result = RowUtils.isRowSelected(keyProps, null, null, rowData, 0); - expect(result).toBe(false); - }); - }); - - describe('using `isSelectedKey`', () => { - it('should return true', () => { - const rowData = { id: 1, name: 'tim', isSelected: true }; - const result = RowUtils.isRowSelected(null, null, 'isSelected', rowData, 0); - expect(result).toBe(true); - }); - - it('should return false', () => { - const rowData = { id: 1, name: 'tim', isSelected: false }; - const result = RowUtils.isRowSelected(null, null, 'isSelected', rowData, 0); - expect(result).toBe(false); - }); - }); - }); -}); diff --git a/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx b/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx index cf1bd54412..84530716ab 100644 --- a/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx +++ b/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx @@ -16,7 +16,7 @@ export default function SelectCellFormatter({ value, onChange }: SelectCellForma type="checkbox" className="react-grid-checkbox" onChange={handleChange} - checked={value === true} + checked={value} /> From 7aad3064b98b0c89c35ba2e619ce096942eb7065 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 13:42:17 +0100 Subject: [PATCH 07/34] Fix Canvas tests --- .../src/__tests__/Canvas.spec.tsx | 46 +++++-------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/packages/react-data-grid/src/__tests__/Canvas.spec.tsx b/packages/react-data-grid/src/__tests__/Canvas.spec.tsx index 74d2f35abe..8315b85c01 100644 --- a/packages/react-data-grid/src/__tests__/Canvas.spec.tsx +++ b/packages/react-data-grid/src/__tests__/Canvas.spec.tsx @@ -96,43 +96,21 @@ describe('Canvas Tests', () => { }); describe('Row Selection', () => { - const COLUMNS = [{ key: 'id', name: 'ID', idx: 0, width: 100, left: 100 }]; + fit('renders row selected', () => { + const rowGetter = () => ({ id: 1 }); - describe('selectBy index', () => { - it('renders row selected', () => { - const rowGetter = () => ({ id: 1 }); - - const props = { rowOverscanStartIdx: 0, rowOverscanEndIdx: 1, COLUMNS, rowGetter, rowsCount: 1, rowSelection: { indexes: [0] } }; - const wrapper = renderComponent(props); - - const rows = getRows(wrapper); - expect(rows[0].props.isSelected).toBe(true); - }); - }); - - describe('selectBy keys', () => { - it('renders row selected', () => { - const rowGetter = () => { return { id: 1 }; }; - - const props = { rowOverscanStartIdx: 0, rowOverscanEndIdx: 1, COLUMNS, rowGetter, rowsCount: 1, rowSelection: { keys: { rowKey: 'id', values: [1] } } }; - const wrapper = renderComponent(props); - - const rows = getRows(wrapper); - expect(rows[0].props.isSelected).toBe(true); + const wrapper = renderComponent({ + rowOverscanStartIdx: 0, + rowOverscanEndIdx: 1, + columns: [{ key: 'id', name: 'ID', idx: 0, width: 100, left: 100 }], + rowGetter, + rowsCount: 1, + rowKey: 'id', + selectedRows: new Set([1]) }); - }); - - - describe('selectBy `isSelectedKey`', () => { - it('renders row selected', () => { - const rowGetter = (i: number) => i === 0 ? { id: 1, isSelected: true } : {}; - - const props = { rowOverscanStartIdx: 0, rowOverscanEndIdx: 1, COLUMNS, rowGetter, rowsCount: 1, rowSelection: { isSelectedKey: 'isSelected' } }; - const wrapper = renderComponent(props); + const rows = getRows(wrapper); - const rows = getRows(wrapper); - expect(rows[0].props.isSelected).toBe(true); - }); + expect(rows[0].props.isSelected).toBe(true); }); }); From a15cab44ccb160b820f2f304eb1b3cf623c225bf Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 16:39:33 +0100 Subject: [PATCH 08/34] Get shift selection almost working --- .../react-data-grid/src/ReactDataGrid.tsx | 49 +++++++++---------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index ede7d5016c..7874a57206 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -11,7 +11,7 @@ import React, { import Grid from './Grid'; import ToolbarContainer, { ToolbarProps } from './ToolbarContainer'; import SelectCellFormatter from './formatters/SelectCellFormatter'; -// import KeyCodes from './KeyCodes'; +import KeyCodes from './KeyCodes'; import { getColumnMetrics } from './ColumnMetrics'; import { ScrollState } from './Viewport'; import { RowsContainerProps } from './RowsContainer'; @@ -70,7 +70,6 @@ export interface ReactDataGridProps { onGridKeyUp?(event: React.KeyboardEvent): void; /** Function called whenever keyboard key is pressed down */ onGridKeyDown?(event: React.KeyboardEvent): void; - onRowSelect?(rowData: R[]): void; rowSelection?: { /** toggle whether to show a checkbox in first column to select rows */ showCheckbox?: boolean; @@ -173,7 +172,7 @@ export interface ReactDataGridProps { enableIsScrolling?: boolean; } -export interface ReactDataGridHandle { +export interface ReactDataGridHandle { scrollToColumn(colIdx: number): void; selectCell(position: Position, openEditor?: boolean): void; handleToggleFilter(): void; @@ -203,11 +202,11 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ rowGetter, rowSelection, cellRangeSelection, - onRowSelect, onClearFilters, ...props -}: ReactDataGridProps, ref: React.Ref>) { +}: ReactDataGridProps, ref: React.Ref) { const [canFilter, setCanFilter] = useState(false); + const [lastSelectedRowIdx, setLastSelectedRowIdx] = useState(-1); const [sortColumn, setSortColumn] = useState(props.sortColumn); const [sortDirection, setSortDirection] = useState(props.sortDirection); const [columnWidths, setColumnWidths] = useState(() => new Map()); @@ -221,32 +220,27 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ // TODO: handle row selection without checkbox, i.e using row click if (!rowSelection || !rowSelection.showCheckbox) return columns; - // function isShiftKeyPressed() { - // return _keysDown.has(KeyCodes.Shift) && _keysDown.size === 1; - // } + function isShiftKeyPressed() { + return _keysDown.has(KeyCodes.Shift) && _keysDown.size === 1; + } - const { selectedRows, onSelectedRowsChange /*, enableShiftSelect*/ } = rowSelection; - // let lastSelectedRowIdx: number | undefined; + const { selectedRows, onSelectedRowsChange, enableShiftSelect } = rowSelection; function handleSelectionChange(rowIdx: number, row: R, value: boolean) { const newSelectedRows = new Set(selectedRows); - const ids = [row[rowKey]]; - - // TODO: handle shift select - // if (enableShiftSelect) { - // if (typeof lastSelectedRowIdx === 'number' && ) { - // } else if (isShiftKeyPressed) { - // lastSelectedRowIdx = rowIdx; - // ids.push(row[rowKey]); - // } else { } - // } else { - // ids.push(row[rowKey]); - // } if (value) { - ids.forEach(id => newSelectedRows.add(id)); + newSelectedRows.add(row[rowKey]); + setLastSelectedRowIdx(rowIdx); + if (enableShiftSelect && lastSelectedRowIdx !== -1 && lastSelectedRowIdx !== rowIdx && isShiftKeyPressed()) { + const step = Math.sign(rowIdx - lastSelectedRowIdx); + for (let i = lastSelectedRowIdx + step; i !== rowIdx; i += step) { + newSelectedRows.add(rowGetter(i)[rowKey]); + } + } } else { - ids.forEach(id => newSelectedRows.delete(id)); + newSelectedRows.delete(row[rowKey]); + setLastSelectedRowIdx(-1); } onSelectedRowsChange(newSelectedRows); } @@ -258,6 +252,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ newSelectedRows.add(rowGetter(i)[rowKey]); } } + setLastSelectedRowIdx(-1); onSelectedRowsChange(newSelectedRows); } @@ -280,7 +275,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ return Array.isArray(columns) ? [selectColumn, ...columns] : columns.unshift(selectColumn); - }, [columns, rowGetter, rowKey, rowSelection, rowsCount]); + }, [_keysDown, columns, lastSelectedRowIdx, rowGetter, rowKey, rowSelection, rowsCount]); const columnMetrics = useMemo(() => { if (viewportWidth <= 0) return null; @@ -556,8 +551,8 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ }); // This is a temporary class to expose instance methods as ForwardRef does work well with generics -export default class ReactDataGrid extends React.Component> implements ReactDataGridHandle { - private readonly gridRef = React.createRef>(); +export default class ReactDataGrid extends React.Component> implements ReactDataGridHandle { + private readonly gridRef = React.createRef(); selectCell(position: Position, openEditor?: boolean | undefined): void { this.gridRef.current!.selectCell(position, openEditor); From f5da8d4d1c48a549cb50f538be3d5166a21146b0 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 19:05:23 +0100 Subject: [PATCH 09/34] Simplify a few exports --- packages/react-data-grid/src/RowGroup.tsx | 4 +--- packages/react-data-grid/src/masks/CellMask.tsx | 4 +--- packages/react-data-grid/src/masks/CopyMask.tsx | 4 +--- packages/react-data-grid/src/masks/SelectionMask.tsx | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/react-data-grid/src/RowGroup.tsx b/packages/react-data-grid/src/RowGroup.tsx index ac72b14ffb..299ccf6e0f 100644 --- a/packages/react-data-grid/src/RowGroup.tsx +++ b/packages/react-data-grid/src/RowGroup.tsx @@ -31,7 +31,7 @@ interface Props { renderBaseRow(p: RowRendererProps): React.ReactElement; } -const RowGroup = forwardRef>(function RowGroup(props, ref) { +export default forwardRef>(function RowGroup(props, ref) { function onRowExpandToggle(expand?: boolean) { const { onRowExpandToggle } = props.cellMetaData; if (onRowExpandToggle) { @@ -59,8 +59,6 @@ const RowGroup = forwardRef>(function RowGroup(props, ); }); -export default RowGroup; - interface DefaultBaseProps extends Props { onRowExpandClick(): void; onRowExpandToggle(expand?: boolean): void; diff --git a/packages/react-data-grid/src/masks/CellMask.tsx b/packages/react-data-grid/src/masks/CellMask.tsx index 0afc9faa31..a97e423d45 100644 --- a/packages/react-data-grid/src/masks/CellMask.tsx +++ b/packages/react-data-grid/src/masks/CellMask.tsx @@ -4,7 +4,7 @@ import { Dimension } from '../common/types'; export type CellMaskProps = React.HTMLAttributes & Dimension; -const CellMask = forwardRef(function CellMask({ width, height, top, left, zIndex, className, ...props }, ref) { +export default forwardRef(function CellMask({ width, height, top, left, zIndex, className, ...props }, ref) { return (
(function CellMask({ w /> ); }); - -export default CellMask; diff --git a/packages/react-data-grid/src/masks/CopyMask.tsx b/packages/react-data-grid/src/masks/CopyMask.tsx index baaf5308c4..1d0f5ff997 100644 --- a/packages/react-data-grid/src/masks/CopyMask.tsx +++ b/packages/react-data-grid/src/masks/CopyMask.tsx @@ -1,7 +1,7 @@ import React, { forwardRef } from 'react'; import CellMask, { CellMaskProps } from './CellMask'; -const CopyMask = forwardRef(function CopyMask(props, ref) { +export default forwardRef(function CopyMask(props, ref) { return ( (function CopyMask(pro /> ); }); - -export default CopyMask; diff --git a/packages/react-data-grid/src/masks/SelectionMask.tsx b/packages/react-data-grid/src/masks/SelectionMask.tsx index 138f112adb..fceb43049a 100644 --- a/packages/react-data-grid/src/masks/SelectionMask.tsx +++ b/packages/react-data-grid/src/masks/SelectionMask.tsx @@ -1,7 +1,7 @@ import React, { forwardRef } from 'react'; import CellMask, { CellMaskProps } from './CellMask'; -const SelectionMask = forwardRef(function SelectionMask(props, ref) { +export default forwardRef(function SelectionMask(props, ref) { return ( (function Selecti /> ); }); - -export default SelectionMask; From 2afa28f477731d8c18392b4ebbb4ef503a09f01b Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 19:28:37 +0100 Subject: [PATCH 10/34] Focus CellMask when clicking on a cell --- packages/react-data-grid/src/ReactDataGrid.tsx | 4 ++-- packages/react-data-grid/src/masks/InteractionMasks.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index 7874a57206..ae3cc13368 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -360,7 +360,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ } } - function handlerCellClick({ rowIdx, idx }: Position) { + function handleCellClick({ rowIdx, idx }: Position) { const { onRowClick } = props; selectCell({ rowIdx, idx }); @@ -461,7 +461,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ const cellMetaData: CellMetaData = { rowKey, - onCellClick: handlerCellClick, + onCellClick: handleCellClick, onCellContextMenu: handleCellContextMenu, onCellDoubleClick: handleCellDoubleClick, onCellExpand: props.onCellExpand, diff --git a/packages/react-data-grid/src/masks/InteractionMasks.tsx b/packages/react-data-grid/src/masks/InteractionMasks.tsx index dc6e3ff150..f5114e93e4 100644 --- a/packages/react-data-grid/src/masks/InteractionMasks.tsx +++ b/packages/react-data-grid/src/masks/InteractionMasks.tsx @@ -458,18 +458,18 @@ export default class InteractionMasks extends React.Component { if (this.selectionMask.current && !this.isFocused()) { this.selectionMask.current.focus(); } - } + }; selectFirstCell(): void { this.selectCell({ rowIdx: 0, idx: 0 }); } selectCell = (cell: Position, openEditor?: boolean): void => { - const callback = openEditor ? this.openEditor : undefined; + const callback = openEditor ? this.openEditor : this.focus; // Close the editor to commit any pending changes if (this.state.isEditorEnabled) { this.closeEditor(); From e238aacc5c1b5e4c519578af374ae6ddc58a9787 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 19:43:44 +0100 Subject: [PATCH 11/34] Working shift selection --- .../react-data-grid/src/ReactDataGrid.tsx | 20 ++++--------------- .../src/formatters/SelectCellFormatter.tsx | 4 ++-- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index ae3cc13368..a4a18c35af 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -11,7 +11,6 @@ import React, { import Grid from './Grid'; import ToolbarContainer, { ToolbarProps } from './ToolbarContainer'; import SelectCellFormatter from './formatters/SelectCellFormatter'; -import KeyCodes from './KeyCodes'; import { getColumnMetrics } from './ColumnMetrics'; import { ScrollState } from './Viewport'; import { RowsContainerProps } from './RowsContainer'; @@ -211,7 +210,6 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ const [sortDirection, setSortDirection] = useState(props.sortDirection); const [columnWidths, setColumnWidths] = useState(() => new Map()); const [eventBus] = useState(() => new EventBus()); - const [_keysDown] = useState(() => new Set()); const [gridWidth, setGridWidth] = useState(0); const gridRef = useRef(null); const viewportWidth = (width || gridWidth) - 2; // 2 for border width; @@ -220,19 +218,15 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ // TODO: handle row selection without checkbox, i.e using row click if (!rowSelection || !rowSelection.showCheckbox) return columns; - function isShiftKeyPressed() { - return _keysDown.has(KeyCodes.Shift) && _keysDown.size === 1; - } - const { selectedRows, onSelectedRowsChange, enableShiftSelect } = rowSelection; - function handleSelectionChange(rowIdx: number, row: R, value: boolean) { + function handleSelectionChange(rowIdx: number, row: R, value: boolean, isShiftClick: boolean) { const newSelectedRows = new Set(selectedRows); if (value) { newSelectedRows.add(row[rowKey]); setLastSelectedRowIdx(rowIdx); - if (enableShiftSelect && lastSelectedRowIdx !== -1 && lastSelectedRowIdx !== rowIdx && isShiftKeyPressed()) { + if (enableShiftSelect && isShiftClick && lastSelectedRowIdx !== -1 && lastSelectedRowIdx !== rowIdx) { const step = Math.sign(rowIdx - lastSelectedRowIdx); for (let i = lastSelectedRowIdx + step; i !== rowIdx; i += step) { newSelectedRows.add(rowGetter(i)[rowKey]); @@ -267,7 +261,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ formatter: (p: FormatterProps) => ( handleSelectionChange(p.rowIdx, p.row, value)} + onChange={(value, isShiftClick) => handleSelectionChange(p.rowIdx, p.row, value, isShiftClick)} /> ) } as Column; @@ -275,7 +269,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ return Array.isArray(columns) ? [selectColumn, ...columns] : columns.unshift(selectColumn); - }, [_keysDown, columns, lastSelectedRowIdx, rowGetter, rowKey, rowSelection, rowsCount]); + }, [columns, lastSelectedRowIdx, rowGetter, rowKey, rowSelection, rowsCount]); const columnMetrics = useMemo(() => { if (viewportWidth <= 0) return null; @@ -341,9 +335,6 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ } function handleViewportKeyDown(e: React.KeyboardEvent) { - // Track which keys are currently down for shift clicking etc - _keysDown.add(e.keyCode); - const { onGridKeyDown } = props; if (onGridKeyDown) { onGridKeyDown(e); @@ -351,9 +342,6 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ } function handleViewportKeyUp(e: React.KeyboardEvent) { - // Track which keys are currently down for shift clicking etc - _keysDown.delete(e.keyCode); - const { onGridKeyUp } = props; if (onGridKeyUp) { onGridKeyUp(e); diff --git a/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx b/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx index 84530716ab..01c96f37a4 100644 --- a/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx +++ b/packages/react-data-grid/src/formatters/SelectCellFormatter.tsx @@ -2,12 +2,12 @@ import React from 'react'; interface SelectCellFormatterProps { value: boolean; - onChange(value: boolean): void; + onChange(value: boolean, isShiftClick: boolean): void; } export default function SelectCellFormatter({ value, onChange }: SelectCellFormatterProps) { function handleChange(e: React.ChangeEvent) { - onChange(e.target.checked); + onChange(e.target.checked, (e.nativeEvent as MouseEvent).shiftKey); } return ( From 90034bb2795a7d7f1b4046f0dd92c907e95ebef9 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 2 Oct 2019 20:00:28 +0100 Subject: [PATCH 12/34] use a ref for lastSelectedRowIdx --- packages/react-data-grid/src/ReactDataGrid.tsx | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index a4a18c35af..c29b9c2459 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -205,12 +205,12 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ ...props }: ReactDataGridProps, ref: React.Ref) { const [canFilter, setCanFilter] = useState(false); - const [lastSelectedRowIdx, setLastSelectedRowIdx] = useState(-1); const [sortColumn, setSortColumn] = useState(props.sortColumn); const [sortDirection, setSortDirection] = useState(props.sortDirection); const [columnWidths, setColumnWidths] = useState(() => new Map()); const [eventBus] = useState(() => new EventBus()); const [gridWidth, setGridWidth] = useState(0); + const lastSelectedRowIdx = useRef(-1); const gridRef = useRef(null); const viewportWidth = (width || gridWidth) - 2; // 2 for border width; @@ -225,16 +225,17 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ if (value) { newSelectedRows.add(row[rowKey]); - setLastSelectedRowIdx(rowIdx); - if (enableShiftSelect && isShiftClick && lastSelectedRowIdx !== -1 && lastSelectedRowIdx !== rowIdx) { - const step = Math.sign(rowIdx - lastSelectedRowIdx); - for (let i = lastSelectedRowIdx + step; i !== rowIdx; i += step) { + const previousRowIdx = lastSelectedRowIdx.current; + lastSelectedRowIdx.current = rowIdx; + if (enableShiftSelect && isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx) { + const step = Math.sign(rowIdx - previousRowIdx); + for (let i = previousRowIdx + step; i !== rowIdx; i += step) { newSelectedRows.add(rowGetter(i)[rowKey]); } } } else { newSelectedRows.delete(row[rowKey]); - setLastSelectedRowIdx(-1); + lastSelectedRowIdx.current = -1; } onSelectedRowsChange(newSelectedRows); } @@ -246,7 +247,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ newSelectedRows.add(rowGetter(i)[rowKey]); } } - setLastSelectedRowIdx(-1); + lastSelectedRowIdx.current = -1; onSelectedRowsChange(newSelectedRows); } From a41b1c8b41f21d208cce6d80db00ad76e96656df Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Wed, 2 Oct 2019 18:17:57 -0500 Subject: [PATCH 13/34] Add class methods to avoid recomputation --- examples/scripts/example16-row-select.js | 12 +-- .../react-data-grid/src/ReactDataGrid.tsx | 73 ++++++++++++------- packages/react-data-grid/src/common/types.ts | 3 +- 3 files changed, 54 insertions(+), 34 deletions(-) diff --git a/examples/scripts/example16-row-select.js b/examples/scripts/example16-row-select.js index 89d8c793f7..a7691140b6 100644 --- a/examples/scripts/example16-row-select.js +++ b/examples/scripts/example16-row-select.js @@ -50,14 +50,10 @@ class Example extends React.Component { rowGetter={this.rowGetter} rowsCount={this.state.rows.length} minHeight={500} - rowSelection={{ - showCheckbox: true, - enableShiftSelect: true, - selectedRows: this.state.selectedRows, - onSelectedRowsChange: (selectedRows) => { - this.setState({ selectedRows }); - } - }} + showCheckboxColumn + enableShiftSelect + selectedRows={this.state.selectedRows} + onSelectedRowsChange={selectedRows => this.setState({ selectedRows })} />
); diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index c29b9c2459..008fd0fc4a 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -36,7 +36,8 @@ import { SubRowDetails, SubRowOptions, RowRendererProps, - FormatterProps + FormatterProps, + Omit } from './common/types'; export interface ReactDataGridProps { @@ -69,22 +70,15 @@ export interface ReactDataGridProps { onGridKeyUp?(event: React.KeyboardEvent): void; /** Function called whenever keyboard key is pressed down */ onGridKeyDown?(event: React.KeyboardEvent): void; - rowSelection?: { - /** toggle whether to show a checkbox in first column to select rows */ - showCheckbox?: boolean; - enableShiftSelect?: boolean; - /** Selected rows Set(); */ - selectedRows: Set; + showCheckboxColumn?: boolean; - /** Function called whenever row selection is changed */ - onSelectedRowsChange: (selectedRows: Set) => void; + enableShiftSelect?: boolean; - /** Custom checkbox formatter */ - // TODO: fix types - cellRenderer?: React.ReactElement; - headerCellRenderer?: React.ReactElement; - }; + selectedRows?: Set; + + /** Function called whenever row selection is changed */ + onSelectedRowsChange?: (selectedRows: Set) => void; /** * Callback called whenever row data is updated * When editing is enabled, this callback will be called for the following scenarios @@ -171,6 +165,11 @@ export interface ReactDataGridProps { enableIsScrolling?: boolean; } +interface ReactDataGridPropsBase extends Omit, 'selectedRows' | 'onSelectedRowsChange'> { + getSelectedRows(): Set; + onSelectedRowsChange: (selectedRows: Set) => void; +} + export interface ReactDataGridHandle { scrollToColumn(colIdx: number): void; selectCell(position: Position, openEditor?: boolean): void; @@ -199,11 +198,14 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ columns, rowsCount, rowGetter, - rowSelection, cellRangeSelection, onClearFilters, + showCheckboxColumn, + enableShiftSelect, + getSelectedRows, + onSelectedRowsChange, ...props -}: ReactDataGridProps, ref: React.Ref) { +}: ReactDataGridPropsBase, ref: React.Ref) { const [canFilter, setCanFilter] = useState(false); const [sortColumn, setSortColumn] = useState(props.sortColumn); const [sortDirection, setSortDirection] = useState(props.sortDirection); @@ -216,12 +218,10 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ const gridColumns = useMemo(() => { // TODO: handle row selection without checkbox, i.e using row click - if (!rowSelection || !rowSelection.showCheckbox) return columns; - - const { selectedRows, onSelectedRowsChange, enableShiftSelect } = rowSelection; + if (!showCheckboxColumn) return columns; function handleSelectionChange(rowIdx: number, row: R, value: boolean, isShiftClick: boolean) { - const newSelectedRows = new Set(selectedRows); + const newSelectedRows = new Set(getSelectedRows()); if (value) { newSelectedRows.add(row[rowKey]); @@ -258,10 +258,15 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ width: 60, filterable: false, frozen: true, - headerRenderer: , + headerRenderer: () => ( + + ), formatter: (p: FormatterProps) => ( handleSelectionChange(p.rowIdx, p.row, value, isShiftClick)} /> ) @@ -270,7 +275,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ return Array.isArray(columns) ? [selectColumn, ...columns] : columns.unshift(selectColumn); - }, [columns, lastSelectedRowIdx, rowGetter, rowKey, rowSelection, rowsCount]); + }, [columns, enableShiftSelect, getSelectedRows, onSelectedRowsChange, rowGetter, rowKey, rowsCount, showCheckboxColumn]); const columnMetrics = useMemo(() => { if (viewportWidth <= 0) return null; @@ -507,7 +512,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ rowRenderer={props.rowRenderer} rowGroupRenderer={props.rowGroupRenderer} cellMetaData={cellMetaData} - selectedRows={rowSelection && rowSelection.selectedRows} + selectedRows={getSelectedRows()} rowOffsetHeight={rowOffsetHeight} sortColumn={sortColumn} sortDirection={sortDirection} @@ -559,11 +564,29 @@ export default class ReactDataGrid extends React.Component => { + return this.props.selectedRows || new Set(); + }; + + private onSelectedRowsChange = (selectedRows: Set): void => { + if (!this.props.onSelectedRowsChange) return; + this.props.onSelectedRowsChange(selectedRows); + }; + + private rowGetter = (rowIdx: number): R => { + return this.props.rowGetter(rowIdx); + }; + render() { + const { onSelectedRowsChange, rowGetter, ...props } = this.props; + return ( } ref={this.gridRef} - {...this.props as unknown as ReactDataGridProps<{}>} + rowGetter={this.rowGetter} + getSelectedRows={this.getSelectedRows as () => Set} + onSelectedRowsChange={this.onSelectedRowsChange} /> ); } diff --git a/packages/react-data-grid/src/common/types.ts b/packages/react-data-grid/src/common/types.ts index 0cae7284b6..f1633ab5ce 100644 --- a/packages/react-data-grid/src/common/types.ts +++ b/packages/react-data-grid/src/common/types.ts @@ -37,7 +37,8 @@ interface ColumnValue>; /** Header renderer for each header cell */ - headerRenderer?: React.ReactElement | React.ComponentType>; + // TODO: finalize API + headerRenderer?: React.ReactElement | React.ComponentType> | (() => React.ReactElement); /** Component to be used to filter the data of the column */ filterRenderer?: React.ComponentType>; From 18d3334a2291ab8bca72e2661e8019d6f51cdc00 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 13:38:21 +0100 Subject: [PATCH 14/34] Do it the react way --- examples/scripts/example16-row-select.js | 5 +- packages/react-data-grid/src/Canvas.tsx | 20 ++- packages/react-data-grid/src/Cell.tsx | 3 + .../react-data-grid/src/Cell/CellContent.tsx | 14 +- .../react-data-grid/src/Cell/CellValue.tsx | 16 +- packages/react-data-grid/src/Columns.tsx | 28 ++++ packages/react-data-grid/src/Grid.tsx | 12 +- packages/react-data-grid/src/Header.tsx | 8 +- packages/react-data-grid/src/HeaderCell.tsx | 7 +- packages/react-data-grid/src/HeaderRow.tsx | 11 +- .../react-data-grid/src/ReactDataGrid.tsx | 152 ++++++------------ packages/react-data-grid/src/Row.tsx | 13 +- packages/react-data-grid/src/Viewport.tsx | 6 +- .../cells/headerCells/SortableHeaderCell.tsx | 13 +- packages/react-data-grid/src/common/types.ts | 13 +- .../src/common/utils/RowComparer.ts | 2 +- packages/react-data-grid/src/index.ts | 1 + 17 files changed, 186 insertions(+), 138 deletions(-) create mode 100644 packages/react-data-grid/src/Columns.tsx diff --git a/examples/scripts/example16-row-select.js b/examples/scripts/example16-row-select.js index a7691140b6..9bbf07d9c9 100644 --- a/examples/scripts/example16-row-select.js +++ b/examples/scripts/example16-row-select.js @@ -1,5 +1,5 @@ import React from 'react'; -import ReactDataGrid from 'react-data-grid'; +import ReactDataGrid, { SelectColumn } from 'react-data-grid'; import exampleWrapper from '../components/exampleWrapper'; @@ -7,6 +7,7 @@ class Example extends React.Component { constructor(props) { super(props); this._columns = [ + SelectColumn, { key: 'id', name: 'ID' @@ -50,8 +51,6 @@ class Example extends React.Component { rowGetter={this.rowGetter} rowsCount={this.state.rows.length} minHeight={500} - showCheckboxColumn - enableShiftSelect selectedRows={this.state.selectedRows} onSelectedRowsChange={selectedRows => this.setState({ selectedRows })} /> diff --git a/packages/react-data-grid/src/Canvas.tsx b/packages/react-data-grid/src/Canvas.tsx index 82e47e5038..78f3853174 100644 --- a/packages/react-data-grid/src/Canvas.tsx +++ b/packages/react-data-grid/src/Canvas.tsx @@ -12,10 +12,12 @@ import { ViewportProps } from './Viewport'; import { HorizontalRangeToRender, VerticalRangeToRender } from './utils/viewportUtils'; type SharedViewportProps = Pick, -'rowKey' +| 'rowKey' | 'rowGetter' | 'rowsCount' | 'selectedRows' +| 'onRowSelectionChange' +| 'onAllRowsSelectionChange' | 'rowRenderer' | 'cellMetaData' | 'rowHeight' @@ -43,14 +45,14 @@ export interface CanvasProps extends SharedViewportProps, SharedViewportSt onScroll(position: ScrollPosition): void; } -type RendererProps = Pick, 'columns' | 'cellMetaData' | 'colVisibleStartIdx' | 'colVisibleEndIdx' | 'colOverscanEndIdx' | 'colOverscanStartIdx' | 'lastFrozenColumnIndex' | 'isScrolling'> & { +type RendererProps = Pick, 'columns' | 'cellMetaData' | 'colVisibleStartIdx' | 'colVisibleEndIdx' | 'colOverscanEndIdx' | 'colOverscanStartIdx' | 'lastFrozenColumnIndex' | 'isScrolling' | 'onRowSelectionChange' | 'onAllRowsSelectionChange'> & { ref(row: (RowRenderer & React.Component>) | null): void; key: number; idx: number; row: R; subRowDetails?: SubRowDetails; height: number; - isSelected: boolean; + isRowSelected: boolean; scrollLeft: number; }; @@ -250,7 +252,7 @@ export default class Canvas extends React.PureComponent> { } render() { - const { rowOverscanStartIdx, rowOverscanEndIdx, cellMetaData, columns, colOverscanStartIdx, colOverscanEndIdx, colVisibleStartIdx, colVisibleEndIdx, lastFrozenColumnIndex, rowHeight, rowsCount, width, height, rowGetter, contextMenu } = this.props; + const { rowOverscanStartIdx, rowOverscanEndIdx, cellMetaData, columns, colOverscanStartIdx, colOverscanEndIdx, colVisibleStartIdx, colVisibleEndIdx, lastFrozenColumnIndex, rowHeight, rowsCount, width, height, rowGetter, contextMenu, isScrolling, scrollLeft, onRowSelectionChange, onAllRowsSelectionChange } = this.props; const RowsContainer = this.props.RowsContainer || RowsContainerDefault; const rows = this.getRows(rowOverscanStartIdx, rowOverscanEndIdx) @@ -269,7 +271,9 @@ export default class Canvas extends React.PureComponent> { row, height: rowHeight, columns, - isSelected: this.isRowSelected(row), + isRowSelected: this.isRowSelected(row), + onRowSelectionChange, + onAllRowsSelectionChange, cellMetaData, subRowDetails, colVisibleStartIdx, @@ -277,8 +281,8 @@ export default class Canvas extends React.PureComponent> { colOverscanStartIdx, colOverscanEndIdx, lastFrozenColumnIndex, - isScrolling: this.props.isScrolling, - scrollLeft: this.props.scrollLeft + isScrolling, + scrollLeft }); }); @@ -316,7 +320,7 @@ export default class Canvas extends React.PureComponent> { onHitTopBoundary={this.onHitTopCanvas} onHitLeftBoundary={this.handleHitColummBoundary} onHitRightBoundary={this.handleHitColummBoundary} - scrollLeft={this.props.scrollLeft} + scrollLeft={scrollLeft} scrollTop={this.props.scrollTop} getRowHeight={this.getRowHeight} getRowTop={this.getRowTop} diff --git a/packages/react-data-grid/src/Cell.tsx b/packages/react-data-grid/src/Cell.tsx index 09fdf41b2c..69b02e2949 100644 --- a/packages/react-data-grid/src/Cell.tsx +++ b/packages/react-data-grid/src/Cell.tsx @@ -186,6 +186,9 @@ export default class Cell extends React.Component> implements Ce onDeleteSubRow={cellMetaData.onDeleteSubRow} cellControls={cellControls} isScrolling={isScrolling} + isRowSelected={this.props.isRowSelected} + onRowSelectionChange={this.props.onRowSelectionChange} + onAllRowsSelectionChange={this.props.onAllRowsSelectionChange} /> ); const events = this.getEvents(); diff --git a/packages/react-data-grid/src/Cell/CellContent.tsx b/packages/react-data-grid/src/Cell/CellContent.tsx index 232dd50dba..9a7304d7c7 100644 --- a/packages/react-data-grid/src/Cell/CellContent.tsx +++ b/packages/react-data-grid/src/Cell/CellContent.tsx @@ -7,7 +7,7 @@ import { CellProps } from '../Cell'; import CellValue from './CellValue'; export type CellContentProps = Pick, -'idx' +| 'idx' | 'rowIdx' | 'rowData' | 'column' @@ -17,11 +17,13 @@ export type CellContentProps = Pick, | 'tooltip' | 'height' | 'cellControls' +| 'isRowSelected' +| 'onRowSelectionChange' +| 'onAllRowsSelectionChange' > & Pick, 'onDeleteSubRow' >; - export default function CellContent({ idx, rowIdx, @@ -33,7 +35,10 @@ export default function CellContent({ height, onDeleteSubRow, cellControls, - isScrolling + isScrolling, + isRowSelected, + onRowSelectionChange, + onAllRowsSelectionChange }: CellContentProps) { const isExpandCell = expandableOptions ? expandableOptions.field === column.key : false; const treeDepth = expandableOptions ? expandableOptions.treeDepth : 0; @@ -74,6 +79,9 @@ export default function CellContent({ column={column} value={value} isScrolling={isScrolling} + isRowSelected={isRowSelected} + onRowSelectionChange={onRowSelectionChange} + onAllRowsSelectionChange={onAllRowsSelectionChange} />
{cellControls} diff --git a/packages/react-data-grid/src/Cell/CellValue.tsx b/packages/react-data-grid/src/Cell/CellValue.tsx index edd91d3eec..9701214c7e 100644 --- a/packages/react-data-grid/src/Cell/CellValue.tsx +++ b/packages/react-data-grid/src/Cell/CellValue.tsx @@ -5,14 +5,17 @@ import { SimpleCellFormatter } from '../formatters'; import { CellContentProps } from './CellContent'; type CellValueProps = Pick, -'rowIdx' +| 'rowIdx' | 'rowData' | 'column' | 'value' | 'isScrolling' +| 'isRowSelected' +| 'onRowSelectionChange' +| 'onAllRowsSelectionChange' >; -export default function CellValue({ rowIdx, rowData, column, value, isScrolling }: CellValueProps) { +export default function CellValue({ rowIdx, rowData, column, value, isScrolling, isRowSelected, onRowSelectionChange, onAllRowsSelectionChange }: CellValueProps) { function getFormatterDependencies(row: R) { // convention based method to get corresponding Id or Name of any Name or Id property const { getRowMetaData } = column; @@ -26,11 +29,15 @@ export default function CellValue({ rowIdx, rowData, column, value, isScrolli function getFormatterProps() { return { - value, + /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ + value: value as any, column, rowIdx, isScrolling, row: rowData, + isRowSelected, + onRowSelectionChange, + onAllRowsSelectionChange, dependentValues: getFormatterDependencies(rowData) }; } @@ -42,8 +49,7 @@ export default function CellValue({ rowIdx, rowData, column, value, isScrolli } if (isValidElementType(formatter)) { - /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - return React.createElement(formatter, { ...getFormatterProps(), value: value as any }); //FIXME: fix value type + return React.createElement(formatter, getFormatterProps()); //FIXME: fix value type } return ; diff --git a/packages/react-data-grid/src/Columns.tsx b/packages/react-data-grid/src/Columns.tsx new file mode 100644 index 0000000000..c33caa0887 --- /dev/null +++ b/packages/react-data-grid/src/Columns.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import SelectCellFormatter from './formatters/SelectCellFormatter'; +import { + Column, + FormatterProps, + HeaderRowProps +} from './common/types'; + +// TODO: fix type +export const SelectColumn: Column = { + key: 'select-row', + name: '', + width: 60, + filterable: false, + frozen: true, + headerRenderer: (props: HeaderRowProps) => ( + + ), + formatter: (props: FormatterProps) => ( + props.onRowSelectionChange(props.rowIdx, props.row, value, isShiftClick)} + /> + ) +}; diff --git a/packages/react-data-grid/src/Grid.tsx b/packages/react-data-grid/src/Grid.tsx index 4da910aa67..6f65b0d095 100644 --- a/packages/react-data-grid/src/Grid.tsx +++ b/packages/react-data-grid/src/Grid.tsx @@ -9,7 +9,7 @@ import { ReactDataGridProps } from './ReactDataGrid'; import { EventBus } from './masks'; type SharedDataGridProps = Pick, -'draggableHeaderCell' +| 'draggableHeaderCell' | 'getValidFilterValues' | 'rowGetter' | 'rowsCount' @@ -26,7 +26,7 @@ type SharedDataGridProps = Pick, | 'overscanColumnCount' | 'enableIsScrolling' > & Required, -'rowKey' +| 'rowKey' | 'enableCellSelect' | 'rowHeight' | 'minHeight' @@ -50,6 +50,9 @@ export interface GridProps extends SharedDataGridProps { onViewportKeydown(e: React.KeyboardEvent): void; onViewportKeyup(e: React.KeyboardEvent): void; onColumnResize(idx: number, width: number): void; + allRowsSelected: boolean; + onRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean): void; + onAllRowsSelectionChange(checked: boolean): void; viewportWidth: number; } @@ -83,6 +86,9 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p draggableHeaderCell: props.draggableHeaderCell, onSort: props.onSort, onHeaderDrop: props.onHeaderDrop, + allRowsSelected: props.allRowsSelected, + onRowSelectionChange: props.onRowSelectionChange, + onAllRowsSelectionChange: props.onAllRowsSelectionChange, getValidFilterValues: props.getValidFilterValues, cellMetaData: props.cellMetaData }) @@ -118,6 +124,8 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p overscanRowCount={props.overscanRowCount} overscanColumnCount={props.overscanColumnCount} enableIsScrolling={props.enableIsScrolling} + onRowSelectionChange={props.onRowSelectionChange} + onAllRowsSelectionChange={props.onAllRowsSelectionChange} onViewportKeydown={props.onViewportKeydown} onViewportKeyup={props.onViewportKeyup} viewportWidth={viewportWidth} diff --git a/packages/react-data-grid/src/Header.tsx b/packages/react-data-grid/src/Header.tsx index 0678522be8..b10a7f89c7 100644 --- a/packages/react-data-grid/src/Header.tsx +++ b/packages/react-data-grid/src/Header.tsx @@ -8,13 +8,16 @@ import { CalculatedColumn, HeaderRowData } from './common/types'; import { GridProps } from './Grid'; type SharedGridProps = Pick, -'columnMetrics' +| 'columnMetrics' | 'onColumnResize' | 'headerRows' | 'rowOffsetHeight' | 'sortColumn' | 'sortDirection' | 'draggableHeaderCell' +| 'allRowsSelected' +| 'onRowSelectionChange' +| 'onAllRowsSelectionChange' | 'onSort' | 'onHeaderDrop' | 'getValidFilterValues' @@ -78,6 +81,9 @@ export default forwardRef(function Header(props: HeaderProps, ref: React.R filterable={row.filterable} onFilterChange={row.onFilterChange} onHeaderDrop={props.onHeaderDrop} + allRowsSelected={props.allRowsSelected} + onRowSelectionChange={props.onRowSelectionChange} + onAllRowsSelectionChange={props.onAllRowsSelectionChange} sortColumn={props.sortColumn} sortDirection={props.sortDirection} onSort={props.onSort} diff --git a/packages/react-data-grid/src/HeaderCell.tsx b/packages/react-data-grid/src/HeaderCell.tsx index 8e223bb827..7ff673d96b 100644 --- a/packages/react-data-grid/src/HeaderCell.tsx +++ b/packages/react-data-grid/src/HeaderCell.tsx @@ -18,6 +18,9 @@ interface Props { onResize(column: CalculatedColumn, width: number): void; onResizeEnd(): void; onHeaderDrop?(): void; + allRowsSelected: boolean; + onRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean): void; + onAllRowsSelectionChange(checked: boolean): void; draggableHeaderCell?: React.ComponentType<{ column: CalculatedColumn; onHeaderDrop(): void }>; className?: string; } @@ -103,7 +106,7 @@ export default class HeaderCell extends React.Component> { } getCell() { - const { height, column, rowType } = this.props; + const { height, column, rowType, allRowsSelected, onRowSelectionChange, onAllRowsSelectionChange } = this.props; const renderer = this.props.renderer || SimpleCellRenderer; if (isElement(renderer)) { // if it is a string, it's an HTML element, and column is not a valid property, so only pass height @@ -112,7 +115,7 @@ export default class HeaderCell extends React.Component> { } return React.cloneElement(renderer, { column, height }); } - return React.createElement(renderer, { column, rowType }); + return React.createElement(renderer, { column, rowType, allRowsSelected, onRowSelectionChange, onAllRowsSelectionChange }); } setScrollLeft(scrollLeft: number) { diff --git a/packages/react-data-grid/src/HeaderRow.tsx b/packages/react-data-grid/src/HeaderRow.tsx index f2b94c6522..710fb80d78 100644 --- a/packages/react-data-grid/src/HeaderRow.tsx +++ b/packages/react-data-grid/src/HeaderRow.tsx @@ -9,8 +9,11 @@ import { CalculatedColumn, AddFilterEvent } from './common/types'; import { HeaderProps } from './Header'; type SharedHeaderProps = Pick, -'draggableHeaderCell' +| 'draggableHeaderCell' | 'onHeaderDrop' +| 'allRowsSelected' +| 'onRowSelectionChange' +| 'onAllRowsSelectionChange' | 'sortColumn' | 'sortDirection' | 'onSort' @@ -66,6 +69,9 @@ export default class HeaderRow extends React.PureComponent> onSort={this.props.onSort} sortDirection={sortDirection} sortDescendingFirst={sortDescendingFirst} + allRowsSelected={this.props.allRowsSelected} + onRowSelectionChange={this.props.onRowSelectionChange} + onAllRowsSelectionChange={this.props.onAllRowsSelectionChange} /> ); } @@ -105,6 +111,9 @@ export default class HeaderRow extends React.PureComponent> onResize={this.props.onColumnResize} onResizeEnd={this.props.onColumnResizeEnd} onHeaderDrop={this.props.onHeaderDrop} + allRowsSelected={this.props.allRowsSelected} + onRowSelectionChange={this.props.onRowSelectionChange} + onAllRowsSelectionChange={this.props.onAllRowsSelectionChange} draggableHeaderCell={this.props.draggableHeaderCell} /> ); diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index 008fd0fc4a..373244be5a 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -10,7 +10,6 @@ import React, { import Grid from './Grid'; import ToolbarContainer, { ToolbarProps } from './ToolbarContainer'; -import SelectCellFormatter from './formatters/SelectCellFormatter'; import { getColumnMetrics } from './ColumnMetrics'; import { ScrollState } from './Viewport'; import { RowsContainerProps } from './RowsContainer'; @@ -23,7 +22,6 @@ import { CellCopyPasteEvent, CellMetaData, CheckCellIsEditableEvent, - Column, ColumnList, CommitEvent, GridRowsUpdatedEvent, @@ -35,9 +33,7 @@ import { SelectedRange, SubRowDetails, SubRowOptions, - RowRendererProps, - FormatterProps, - Omit + RowRendererProps } from './common/types'; export interface ReactDataGridProps { @@ -71,14 +67,10 @@ export interface ReactDataGridProps { /** Function called whenever keyboard key is pressed down */ onGridKeyDown?(event: React.KeyboardEvent): void; - showCheckboxColumn?: boolean; - - enableShiftSelect?: boolean; - selectedRows?: Set; - /** Function called whenever row selection is changed */ - onSelectedRowsChange?: (selectedRows: Set) => void; + onSelectedRowsChange?(selectedRows: Set): void; + /** * Callback called whenever row data is updated * When editing is enabled, this callback will be called for the following scenarios @@ -165,11 +157,6 @@ export interface ReactDataGridProps { enableIsScrolling?: boolean; } -interface ReactDataGridPropsBase extends Omit, 'selectedRows' | 'onSelectedRowsChange'> { - getSelectedRows(): Set; - onSelectedRowsChange: (selectedRows: Set) => void; -} - export interface ReactDataGridHandle { scrollToColumn(colIdx: number): void; selectCell(position: Position, openEditor?: boolean): void; @@ -200,12 +187,10 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ rowGetter, cellRangeSelection, onClearFilters, - showCheckboxColumn, - enableShiftSelect, - getSelectedRows, + selectedRows, onSelectedRowsChange, ...props -}: ReactDataGridPropsBase, ref: React.Ref) { +}: ReactDataGridProps, ref: React.Ref) { const [canFilter, setCanFilter] = useState(false); const [sortColumn, setSortColumn] = useState(props.sortColumn); const [sortDirection, setSortDirection] = useState(props.sortDirection); @@ -216,77 +201,16 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ const gridRef = useRef(null); const viewportWidth = (width || gridWidth) - 2; // 2 for border width; - const gridColumns = useMemo(() => { - // TODO: handle row selection without checkbox, i.e using row click - if (!showCheckboxColumn) return columns; - - function handleSelectionChange(rowIdx: number, row: R, value: boolean, isShiftClick: boolean) { - const newSelectedRows = new Set(getSelectedRows()); - - if (value) { - newSelectedRows.add(row[rowKey]); - const previousRowIdx = lastSelectedRowIdx.current; - lastSelectedRowIdx.current = rowIdx; - if (enableShiftSelect && isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx) { - const step = Math.sign(rowIdx - previousRowIdx); - for (let i = previousRowIdx + step; i !== rowIdx; i += step) { - newSelectedRows.add(rowGetter(i)[rowKey]); - } - } - } else { - newSelectedRows.delete(row[rowKey]); - lastSelectedRowIdx.current = -1; - } - onSelectedRowsChange(newSelectedRows); - } - - function handleAllSelectionChange(value: boolean) { - const newSelectedRows = new Set(); - if (value) { - for (let i = 0; i < rowsCount; i++) { - newSelectedRows.add(rowGetter(i)[rowKey]); - } - } - lastSelectedRowIdx.current = -1; - onSelectedRowsChange(newSelectedRows); - } - - // TODO: remove type assertion - const selectColumn: Column = { - key: 'select-row', - name: '', - width: 60, - filterable: false, - frozen: true, - headerRenderer: () => ( - - ), - formatter: (p: FormatterProps) => ( - handleSelectionChange(p.rowIdx, p.row, value, isShiftClick)} - /> - ) - } as Column; - - return Array.isArray(columns) - ? [selectColumn, ...columns] - : columns.unshift(selectColumn); - }, [columns, enableShiftSelect, getSelectedRows, onSelectedRowsChange, rowGetter, rowKey, rowsCount, showCheckboxColumn]); - const columnMetrics = useMemo(() => { if (viewportWidth <= 0) return null; return getColumnMetrics({ - columns: gridColumns, + columns, minColumnWidth, viewportWidth, columnWidths }); - }, [columnWidths, gridColumns, minColumnWidth, viewportWidth]); + }, [columnWidths, columns, minColumnWidth, viewportWidth]); useLayoutEffect(() => { // Do not calculate the width if minWidth is provided @@ -425,6 +349,43 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ } } + function handleRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean) { + const newSelectedRows = new Set(selectedRows); + + if (checked) { + newSelectedRows.add(row[rowKey]); + const previousRowIdx = lastSelectedRowIdx.current; + lastSelectedRowIdx.current = rowIdx; + if (isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx) { + const step = Math.sign(rowIdx - previousRowIdx); + for (let i = previousRowIdx + step; i !== rowIdx; i += step) { + newSelectedRows.add(rowGetter(i)[rowKey]); + } + } + } else { + newSelectedRows.delete(row[rowKey]); + lastSelectedRowIdx.current = -1; + } + + if (onSelectedRowsChange) { + onSelectedRowsChange(newSelectedRows); + } + } + + function handleAllRowsSelectionChange(checked: boolean) { + const newSelectedRows = new Set(); + if (checked) { + for (let i = 0; i < rowsCount; i++) { + newSelectedRows.add(rowGetter(i)[rowKey]); + } + } + lastSelectedRowIdx.current = -1; + + if (onSelectedRowsChange) { + onSelectedRowsChange(newSelectedRows); + } + } + function getHeaderRows(): [HeaderRowData, HeaderRowData | undefined] { const { headerRowHeight, onAddFilter } = props; return [ @@ -512,7 +473,10 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ rowRenderer={props.rowRenderer} rowGroupRenderer={props.rowGroupRenderer} cellMetaData={cellMetaData} - selectedRows={getSelectedRows()} + selectedRows={selectedRows} + allRowsSelected={selectedRows !== undefined && selectedRows.size === rowsCount} + onRowSelectionChange={handleRowSelectionChange} + onAllRowsSelectionChange={handleAllRowsSelectionChange} rowOffsetHeight={rowOffsetHeight} sortColumn={sortColumn} sortDirection={sortDirection} @@ -564,29 +528,11 @@ export default class ReactDataGrid extends React.Component => { - return this.props.selectedRows || new Set(); - }; - - private onSelectedRowsChange = (selectedRows: Set): void => { - if (!this.props.onSelectedRowsChange) return; - this.props.onSelectedRowsChange(selectedRows); - }; - - private rowGetter = (rowIdx: number): R => { - return this.props.rowGetter(rowIdx); - }; - render() { - const { onSelectedRowsChange, rowGetter, ...props } = this.props; - return ( } + {...this.props as unknown as ReactDataGridProps<{}>} ref={this.gridRef} - rowGetter={this.rowGetter} - getSelectedRows={this.getSelectedRows as () => Set} - onSelectedRowsChange={this.onSelectedRowsChange} /> ); } diff --git a/packages/react-data-grid/src/Row.tsx b/packages/react-data-grid/src/Row.tsx index cfe30f128f..740ede31cf 100644 --- a/packages/react-data-grid/src/Row.tsx +++ b/packages/react-data-grid/src/Row.tsx @@ -44,7 +44,7 @@ export default class Row extends React.Component> impleme getCell(column: CalculatedColumn) { const Renderer = this.props.cellRenderer!; - const { idx, cellMetaData, isScrolling, row, lastFrozenColumnIndex, scrollLeft } = this.props; + const { idx, cellMetaData, isScrolling, row, lastFrozenColumnIndex, scrollLeft, isRowSelected, onRowSelectionChange, onAllRowsSelectionChange } = this.props; const { key } = column; const cellProps: CellRendererProps & { ref: (cell: CellRenderer | null) => void } = { @@ -59,7 +59,10 @@ export default class Row extends React.Component> impleme expandableOptions: this.getExpandableOptions(key), isScrolling, scrollLeft: isFrozen(column) && !isPositionStickySupported() ? scrollLeft : undefined, - lastFrozenColumnIndex + lastFrozenColumnIndex, + isRowSelected, + onRowSelectionChange, + onAllRowsSelectionChange }; return ; // FIXME: fix key type @@ -83,9 +86,9 @@ export default class Row extends React.Component> impleme } getCellValue(key: keyof R) { - const { isSelected, row } = this.props; + const { isRowSelected, row } = this.props; if (key === 'select-row') { - return isSelected; + return isRowSelected; } return rowUtils.get(row, key); @@ -119,7 +122,7 @@ export default class Row extends React.Component> impleme const className = classNames( 'react-grid-Row', `react-grid-Row--${this.props.idx % 2 === 0 ? 'even' : 'odd'}`, - { 'row-selected': this.props.isSelected }, + { 'row-selected': this.props.isRowSelected }, this.props.extraClasses, { 'rdg-scrolling': this.props.isScrolling } ); diff --git a/packages/react-data-grid/src/Viewport.tsx b/packages/react-data-grid/src/Viewport.tsx index 86edaa4c44..ccadf5fd1e 100644 --- a/packages/react-data-grid/src/Viewport.tsx +++ b/packages/react-data-grid/src/Viewport.tsx @@ -13,7 +13,7 @@ export interface ScrollState { } type SharedGridProps = Pick, -'rowKey' +| 'rowKey' | 'rowHeight' | 'rowRenderer' | 'rowGetter' @@ -37,6 +37,8 @@ type SharedGridProps = Pick, | 'overscanRowCount' | 'overscanColumnCount' | 'enableIsScrolling' +| 'onRowSelectionChange' +| 'onAllRowsSelectionChange' | 'onViewportKeydown' | 'onViewportKeyup' >; @@ -140,6 +142,8 @@ export default function Viewport({ rowGetter={props.rowGetter} rowsCount={rowsCount} selectedRows={props.selectedRows} + onRowSelectionChange={props.onRowSelectionChange} + onAllRowsSelectionChange={props.onAllRowsSelectionChange} rowRenderer={props.rowRenderer} scrollTop={scrollTop} scrollLeft={scrollLeft} diff --git a/packages/react-data-grid/src/common/cells/headerCells/SortableHeaderCell.tsx b/packages/react-data-grid/src/common/cells/headerCells/SortableHeaderCell.tsx index 17b9977780..8ac6a9e6e1 100644 --- a/packages/react-data-grid/src/common/cells/headerCells/SortableHeaderCell.tsx +++ b/packages/react-data-grid/src/common/cells/headerCells/SortableHeaderCell.tsx @@ -15,10 +15,13 @@ export interface Props { onSort(columnKey: keyof R, direction: DEFINE_SORT): void; sortDirection: DEFINE_SORT; sortDescendingFirst: boolean; + allRowsSelected: boolean; + onRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean): void; + onAllRowsSelectionChange(checked: boolean): void; } export default function SortableHeaderCell(props: Props) { - const { column, rowType, onSort, sortDirection, sortDescendingFirst } = props; + const { column, rowType, onSort, sortDirection, sortDescendingFirst, allRowsSelected, onRowSelectionChange, onAllRowsSelectionChange } = props; function onClick() { let direction; switch (sortDirection) { @@ -40,7 +43,13 @@ export default function SortableHeaderCell(props: Props) { ? column.name : isElement(headerRenderer) ? React.cloneElement(headerRenderer, { column }) - : React.createElement(headerRenderer, { column, rowType }); + : React.createElement(headerRenderer, { + column, + rowType, + allRowsSelected, + onRowSelectionChange, + onAllRowsSelectionChange + }); return (
diff --git a/packages/react-data-grid/src/common/types.ts b/packages/react-data-grid/src/common/types.ts index f1633ab5ce..9cca186fd4 100644 --- a/packages/react-data-grid/src/common/types.ts +++ b/packages/react-data-grid/src/common/types.ts @@ -127,6 +127,9 @@ export interface FormatterProps { value: TValue; column: CalculatedColumn; row: TRow; + isRowSelected: boolean; + onRowSelectionChange(rowIdx: number, row: TRow, checked: boolean, isShiftClick: boolean): void; + onAllRowsSelectionChange(checked: boolean): void; isScrolling?: boolean; dependentValues?: TDependentValue; } @@ -146,6 +149,9 @@ export interface EditorProps { export interface HeaderRowProps { column: CalculatedColumn; rowType: HeaderRowType; + allRowsSelected: boolean; + onRowSelectionChange(rowIdx: number, row: TRow, checked: boolean, isShiftClick: boolean): void; + onAllRowsSelectionChange(checked: boolean): void; } export interface CellRendererProps { @@ -160,6 +166,9 @@ export interface CellRendererProps { scrollLeft?: number; expandableOptions?: ExpandableOptions; lastFrozenColumnIndex: number; + isRowSelected: boolean; + onRowSelectionChange(rowIdx: number, row: TRow, checked: boolean, isShiftClick: boolean): void; + onAllRowsSelectionChange(checked: boolean): void; } export interface RowRendererProps { @@ -168,7 +177,6 @@ export interface RowRendererProps { row: TRow; cellRenderer?: React.ComponentType>; cellMetaData: CellMetaData; - isSelected?: boolean; idx: number; extraClasses?: string; subRowDetails?: SubRowDetails; @@ -177,6 +185,9 @@ export interface RowRendererProps { isScrolling?: boolean; scrollLeft: number; lastFrozenColumnIndex: number; + isRowSelected: boolean; + onRowSelectionChange(rowIdx: number, row: TRow, checked: boolean, isShiftClick: boolean): void; + onAllRowsSelectionChange(checked: boolean): void; } export interface FilterRendererProps { diff --git a/packages/react-data-grid/src/common/utils/RowComparer.ts b/packages/react-data-grid/src/common/utils/RowComparer.ts index e1e6a20423..567aa1ee29 100644 --- a/packages/react-data-grid/src/common/utils/RowComparer.ts +++ b/packages/react-data-grid/src/common/utils/RowComparer.ts @@ -5,7 +5,7 @@ export default function shouldRowUpdate(nextProps: RowRendererProps, curre || nextProps.row !== currentProps.row || currentProps.colOverscanStartIdx !== nextProps.colOverscanStartIdx || currentProps.colOverscanEndIdx !== nextProps.colOverscanEndIdx - || currentProps.isSelected !== nextProps.isSelected + || currentProps.isRowSelected !== nextProps.isRowSelected || currentProps.isScrolling !== nextProps.isScrolling || nextProps.height !== currentProps.height || currentProps.extraClasses !== nextProps.extraClasses; diff --git a/packages/react-data-grid/src/index.ts b/packages/react-data-grid/src/index.ts index b7a122e925..9631dc24c1 100644 --- a/packages/react-data-grid/src/index.ts +++ b/packages/react-data-grid/src/index.ts @@ -5,6 +5,7 @@ export { default as Row } from './Row'; export { default as HeaderCell } from './HeaderCell'; import * as _utils from './common/utils'; import * as _helpers from './helpers'; +export * from './Columns'; export * from './formatters'; export * from './common/editors'; export * from './common/enums'; From 68bd0d899a36e8f7c81b4a776b1400ba35ed8425 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 13:56:23 +0100 Subject: [PATCH 15/34] Simplify 1 type --- packages/react-data-grid/src/Grid.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-data-grid/src/Grid.tsx b/packages/react-data-grid/src/Grid.tsx index 6f65b0d095..85e4de6e06 100644 --- a/packages/react-data-grid/src/Grid.tsx +++ b/packages/react-data-grid/src/Grid.tsx @@ -25,6 +25,7 @@ type SharedDataGridProps = Pick, | 'overscanRowCount' | 'overscanColumnCount' | 'enableIsScrolling' +| 'selectedRows' > & Required, | 'rowKey' | 'enableCellSelect' @@ -42,7 +43,6 @@ type SharedDataGridProps = Pick, export interface GridProps extends SharedDataGridProps { headerRows: [HeaderRowData, HeaderRowData | undefined]; cellMetaData: CellMetaData; - selectedRows?: ReadonlySet; rowOffsetHeight: number; eventBus: EventBus; interactionMasksMetaData: InteractionMasksMetaData; From a6bac014f6a82057d322557630715eccbb8f2e12 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 14:31:19 +0100 Subject: [PATCH 16/34] Fix selection --- packages/react-data-grid/src/Canvas.tsx | 36 +++++++++++++--- packages/react-data-grid/src/Cell.tsx | 1 - .../react-data-grid/src/Cell/CellContent.tsx | 5 +-- .../react-data-grid/src/Cell/CellValue.tsx | 4 +- packages/react-data-grid/src/Grid.tsx | 12 +++--- packages/react-data-grid/src/Header.tsx | 22 ++++++++-- packages/react-data-grid/src/HeaderCell.tsx | 5 +-- packages/react-data-grid/src/HeaderRow.tsx | 5 +-- .../react-data-grid/src/ReactDataGrid.tsx | 41 +------------------ packages/react-data-grid/src/Row.tsx | 5 +-- packages/react-data-grid/src/Viewport.tsx | 6 +-- .../cells/headerCells/SortableHeaderCell.tsx | 4 +- packages/react-data-grid/src/common/types.ts | 4 -- 13 files changed, 65 insertions(+), 85 deletions(-) diff --git a/packages/react-data-grid/src/Canvas.tsx b/packages/react-data-grid/src/Canvas.tsx index 78f3853174..878a6b1273 100644 --- a/packages/react-data-grid/src/Canvas.tsx +++ b/packages/react-data-grid/src/Canvas.tsx @@ -16,8 +16,7 @@ type SharedViewportProps = Pick, | 'rowGetter' | 'rowsCount' | 'selectedRows' -| 'onRowSelectionChange' -| 'onAllRowsSelectionChange' +| 'onSelectedRowsChange' | 'rowRenderer' | 'cellMetaData' | 'rowHeight' @@ -45,7 +44,7 @@ export interface CanvasProps extends SharedViewportProps, SharedViewportSt onScroll(position: ScrollPosition): void; } -type RendererProps = Pick, 'columns' | 'cellMetaData' | 'colVisibleStartIdx' | 'colVisibleEndIdx' | 'colOverscanEndIdx' | 'colOverscanStartIdx' | 'lastFrozenColumnIndex' | 'isScrolling' | 'onRowSelectionChange' | 'onAllRowsSelectionChange'> & { +type RendererProps = Pick, 'columns' | 'cellMetaData' | 'colVisibleStartIdx' | 'colVisibleEndIdx' | 'colOverscanEndIdx' | 'colOverscanStartIdx' | 'lastFrozenColumnIndex' | 'isScrolling'> & { ref(row: (RowRenderer & React.Component>) | null): void; key: number; idx: number; @@ -53,6 +52,7 @@ type RendererProps = Pick, 'columns' | 'cellMetaData' | 'colVi subRowDetails?: SubRowDetails; height: number; isRowSelected: boolean; + onRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean): void; scrollLeft: number; }; @@ -62,6 +62,7 @@ export default class Canvas extends React.PureComponent> { private readonly canvas = React.createRef(); private readonly interactionMasks = React.createRef>(); private readonly rows = new Map & React.Component>>(); + private lastSelectedRowIdx = -1; private unsubscribeScrollToColumn?(): void; componentDidMount() { @@ -150,6 +151,30 @@ export default class Canvas extends React.PureComponent> { return this.props.selectedRows !== undefined && this.props.selectedRows.has(row[this.props.rowKey]); } + handleRowSelectionChange = (rowIdx: number, row: R, checked: boolean, isShiftClick: boolean) => { + const { rowKey } = this.props; + const newSelectedRows = new Set(this.props.selectedRows); + + if (checked) { + newSelectedRows.add(row[rowKey]); + const previousRowIdx = this.lastSelectedRowIdx; + this.lastSelectedRowIdx = rowIdx; + if (isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx) { + const step = Math.sign(rowIdx - previousRowIdx); + for (let i = previousRowIdx + step; i !== rowIdx; i += step) { + newSelectedRows.add(this.props.rowGetter(i)[rowKey]); + } + } + } else { + newSelectedRows.delete(row[rowKey]); + this.lastSelectedRowIdx = -1; + } + + if (this.props.onSelectedRowsChange) { + this.props.onSelectedRowsChange(newSelectedRows); + } + }; + setScrollLeft(scrollLeft: number) { if (isPositionStickySupported()) return; const { current } = this.interactionMasks; @@ -252,7 +277,7 @@ export default class Canvas extends React.PureComponent> { } render() { - const { rowOverscanStartIdx, rowOverscanEndIdx, cellMetaData, columns, colOverscanStartIdx, colOverscanEndIdx, colVisibleStartIdx, colVisibleEndIdx, lastFrozenColumnIndex, rowHeight, rowsCount, width, height, rowGetter, contextMenu, isScrolling, scrollLeft, onRowSelectionChange, onAllRowsSelectionChange } = this.props; + const { rowOverscanStartIdx, rowOverscanEndIdx, cellMetaData, columns, colOverscanStartIdx, colOverscanEndIdx, colVisibleStartIdx, colVisibleEndIdx, lastFrozenColumnIndex, rowHeight, rowsCount, width, height, rowGetter, contextMenu, isScrolling, scrollLeft } = this.props; const RowsContainer = this.props.RowsContainer || RowsContainerDefault; const rows = this.getRows(rowOverscanStartIdx, rowOverscanEndIdx) @@ -272,8 +297,7 @@ export default class Canvas extends React.PureComponent> { height: rowHeight, columns, isRowSelected: this.isRowSelected(row), - onRowSelectionChange, - onAllRowsSelectionChange, + onRowSelectionChange: this.handleRowSelectionChange, cellMetaData, subRowDetails, colVisibleStartIdx, diff --git a/packages/react-data-grid/src/Cell.tsx b/packages/react-data-grid/src/Cell.tsx index 69b02e2949..dd45ea79bb 100644 --- a/packages/react-data-grid/src/Cell.tsx +++ b/packages/react-data-grid/src/Cell.tsx @@ -188,7 +188,6 @@ export default class Cell extends React.Component> implements Ce isScrolling={isScrolling} isRowSelected={this.props.isRowSelected} onRowSelectionChange={this.props.onRowSelectionChange} - onAllRowsSelectionChange={this.props.onAllRowsSelectionChange} /> ); const events = this.getEvents(); diff --git a/packages/react-data-grid/src/Cell/CellContent.tsx b/packages/react-data-grid/src/Cell/CellContent.tsx index 9a7304d7c7..d0be3418a8 100644 --- a/packages/react-data-grid/src/Cell/CellContent.tsx +++ b/packages/react-data-grid/src/Cell/CellContent.tsx @@ -19,7 +19,6 @@ export type CellContentProps = Pick, | 'cellControls' | 'isRowSelected' | 'onRowSelectionChange' -| 'onAllRowsSelectionChange' > & Pick, 'onDeleteSubRow' >; @@ -37,8 +36,7 @@ export default function CellContent({ cellControls, isScrolling, isRowSelected, - onRowSelectionChange, - onAllRowsSelectionChange + onRowSelectionChange }: CellContentProps) { const isExpandCell = expandableOptions ? expandableOptions.field === column.key : false; const treeDepth = expandableOptions ? expandableOptions.treeDepth : 0; @@ -81,7 +79,6 @@ export default function CellContent({ isScrolling={isScrolling} isRowSelected={isRowSelected} onRowSelectionChange={onRowSelectionChange} - onAllRowsSelectionChange={onAllRowsSelectionChange} /> {cellControls} diff --git a/packages/react-data-grid/src/Cell/CellValue.tsx b/packages/react-data-grid/src/Cell/CellValue.tsx index 9701214c7e..e5fa2e6b4a 100644 --- a/packages/react-data-grid/src/Cell/CellValue.tsx +++ b/packages/react-data-grid/src/Cell/CellValue.tsx @@ -12,10 +12,9 @@ type CellValueProps = Pick, | 'isScrolling' | 'isRowSelected' | 'onRowSelectionChange' -| 'onAllRowsSelectionChange' >; -export default function CellValue({ rowIdx, rowData, column, value, isScrolling, isRowSelected, onRowSelectionChange, onAllRowsSelectionChange }: CellValueProps) { +export default function CellValue({ rowIdx, rowData, column, value, isScrolling, isRowSelected, onRowSelectionChange }: CellValueProps) { function getFormatterDependencies(row: R) { // convention based method to get corresponding Id or Name of any Name or Id property const { getRowMetaData } = column; @@ -37,7 +36,6 @@ export default function CellValue({ rowIdx, rowData, column, value, isScrolli row: rowData, isRowSelected, onRowSelectionChange, - onAllRowsSelectionChange, dependentValues: getFormatterDependencies(rowData) }; } diff --git a/packages/react-data-grid/src/Grid.tsx b/packages/react-data-grid/src/Grid.tsx index 85e4de6e06..3b5a38390a 100644 --- a/packages/react-data-grid/src/Grid.tsx +++ b/packages/react-data-grid/src/Grid.tsx @@ -26,6 +26,7 @@ type SharedDataGridProps = Pick, | 'overscanColumnCount' | 'enableIsScrolling' | 'selectedRows' +| 'onSelectedRowsChange' > & Required, | 'rowKey' | 'enableCellSelect' @@ -51,8 +52,6 @@ export interface GridProps extends SharedDataGridProps { onViewportKeyup(e: React.KeyboardEvent): void; onColumnResize(idx: number, width: number): void; allRowsSelected: boolean; - onRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean): void; - onAllRowsSelectionChange(checked: boolean): void; viewportWidth: number; } @@ -77,6 +76,9 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p { React.createElement(Header as React.FunctionComponent, { ref: header, + rowKey: props.rowKey, + rowsCount: props.rowsCount, + rowGetter: props.rowGetter, columnMetrics: props.columnMetrics, onColumnResize: props.onColumnResize, headerRows, @@ -87,8 +89,7 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p onSort: props.onSort, onHeaderDrop: props.onHeaderDrop, allRowsSelected: props.allRowsSelected, - onRowSelectionChange: props.onRowSelectionChange, - onAllRowsSelectionChange: props.onAllRowsSelectionChange, + onSelectedRowsChange: props.onSelectedRowsChange, getValidFilterValues: props.getValidFilterValues, cellMetaData: props.cellMetaData }) @@ -105,6 +106,7 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p rowGetter={props.rowGetter} rowsCount={props.rowsCount} selectedRows={props.selectedRows} + onSelectedRowsChange={props.onSelectedRowsChange} columnMetrics={props.columnMetrics} onScroll={onScroll} cellMetaData={props.cellMetaData} @@ -124,8 +126,6 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p overscanRowCount={props.overscanRowCount} overscanColumnCount={props.overscanColumnCount} enableIsScrolling={props.enableIsScrolling} - onRowSelectionChange={props.onRowSelectionChange} - onAllRowsSelectionChange={props.onAllRowsSelectionChange} onViewportKeydown={props.onViewportKeydown} onViewportKeyup={props.onViewportKeyup} viewportWidth={viewportWidth} diff --git a/packages/react-data-grid/src/Header.tsx b/packages/react-data-grid/src/Header.tsx index b10a7f89c7..f017b516ca 100644 --- a/packages/react-data-grid/src/Header.tsx +++ b/packages/react-data-grid/src/Header.tsx @@ -8,6 +8,9 @@ import { CalculatedColumn, HeaderRowData } from './common/types'; import { GridProps } from './Grid'; type SharedGridProps = Pick, +| 'rowKey' +| 'rowsCount' +| 'rowGetter' | 'columnMetrics' | 'onColumnResize' | 'headerRows' @@ -16,8 +19,7 @@ type SharedGridProps = Pick, | 'sortDirection' | 'draggableHeaderCell' | 'allRowsSelected' -| 'onRowSelectionChange' -| 'onAllRowsSelectionChange' +| 'onSelectedRowsChange' | 'onSort' | 'onHeaderDrop' | 'getValidFilterValues' @@ -67,6 +69,19 @@ export default forwardRef(function Header(props: HeaderProps, ref: React.R setResizing(null); } + function handleAllRowsSelectionChange(checked: boolean) { + const newSelectedRows = new Set(); + if (checked) { + for (let i = 0; i < props.rowsCount; i++) { + newSelectedRows.add(props.rowGetter(i)[props.rowKey]); + } + } + + if (props.onSelectedRowsChange) { + props.onSelectedRowsChange(newSelectedRows); + } + } + function getHeaderRow(row: HeaderRowData, ref: React.RefObject>) { return ( @@ -82,8 +97,7 @@ export default forwardRef(function Header(props: HeaderProps, ref: React.R onFilterChange={row.onFilterChange} onHeaderDrop={props.onHeaderDrop} allRowsSelected={props.allRowsSelected} - onRowSelectionChange={props.onRowSelectionChange} - onAllRowsSelectionChange={props.onAllRowsSelectionChange} + onAllRowsSelectionChange={handleAllRowsSelectionChange} sortColumn={props.sortColumn} sortDirection={props.sortDirection} onSort={props.onSort} diff --git a/packages/react-data-grid/src/HeaderCell.tsx b/packages/react-data-grid/src/HeaderCell.tsx index 7ff673d96b..86fab4ae36 100644 --- a/packages/react-data-grid/src/HeaderCell.tsx +++ b/packages/react-data-grid/src/HeaderCell.tsx @@ -19,7 +19,6 @@ interface Props { onResizeEnd(): void; onHeaderDrop?(): void; allRowsSelected: boolean; - onRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean): void; onAllRowsSelectionChange(checked: boolean): void; draggableHeaderCell?: React.ComponentType<{ column: CalculatedColumn; onHeaderDrop(): void }>; className?: string; @@ -106,7 +105,7 @@ export default class HeaderCell extends React.Component> { } getCell() { - const { height, column, rowType, allRowsSelected, onRowSelectionChange, onAllRowsSelectionChange } = this.props; + const { height, column, rowType, allRowsSelected, onAllRowsSelectionChange } = this.props; const renderer = this.props.renderer || SimpleCellRenderer; if (isElement(renderer)) { // if it is a string, it's an HTML element, and column is not a valid property, so only pass height @@ -115,7 +114,7 @@ export default class HeaderCell extends React.Component> { } return React.cloneElement(renderer, { column, height }); } - return React.createElement(renderer, { column, rowType, allRowsSelected, onRowSelectionChange, onAllRowsSelectionChange }); + return React.createElement(renderer, { column, rowType, allRowsSelected, onAllRowsSelectionChange }); } setScrollLeft(scrollLeft: number) { diff --git a/packages/react-data-grid/src/HeaderRow.tsx b/packages/react-data-grid/src/HeaderRow.tsx index 710fb80d78..2ca879c6ef 100644 --- a/packages/react-data-grid/src/HeaderRow.tsx +++ b/packages/react-data-grid/src/HeaderRow.tsx @@ -12,8 +12,6 @@ type SharedHeaderProps = Pick, | 'draggableHeaderCell' | 'onHeaderDrop' | 'allRowsSelected' -| 'onRowSelectionChange' -| 'onAllRowsSelectionChange' | 'sortColumn' | 'sortDirection' | 'onSort' @@ -25,6 +23,7 @@ export interface HeaderRowProps extends SharedHeaderProps { columns: CalculatedColumn[]; onColumnResize(column: CalculatedColumn, width: number): void; onColumnResizeEnd(): void; + onAllRowsSelectionChange(checked: boolean): void; filterable?: boolean; onFilterChange?(args: AddFilterEvent): void; rowType: HeaderRowType; @@ -70,7 +69,6 @@ export default class HeaderRow extends React.PureComponent> sortDirection={sortDirection} sortDescendingFirst={sortDescendingFirst} allRowsSelected={this.props.allRowsSelected} - onRowSelectionChange={this.props.onRowSelectionChange} onAllRowsSelectionChange={this.props.onAllRowsSelectionChange} /> ); @@ -112,7 +110,6 @@ export default class HeaderRow extends React.PureComponent> onResizeEnd={this.props.onColumnResizeEnd} onHeaderDrop={this.props.onHeaderDrop} allRowsSelected={this.props.allRowsSelected} - onRowSelectionChange={this.props.onRowSelectionChange} onAllRowsSelectionChange={this.props.onAllRowsSelectionChange} draggableHeaderCell={this.props.draggableHeaderCell} /> diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index 373244be5a..4e3f0b54d1 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -197,7 +197,6 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ const [columnWidths, setColumnWidths] = useState(() => new Map()); const [eventBus] = useState(() => new EventBus()); const [gridWidth, setGridWidth] = useState(0); - const lastSelectedRowIdx = useRef(-1); const gridRef = useRef(null); const viewportWidth = (width || gridWidth) - 2; // 2 for border width; @@ -349,43 +348,6 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ } } - function handleRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean) { - const newSelectedRows = new Set(selectedRows); - - if (checked) { - newSelectedRows.add(row[rowKey]); - const previousRowIdx = lastSelectedRowIdx.current; - lastSelectedRowIdx.current = rowIdx; - if (isShiftClick && previousRowIdx !== -1 && previousRowIdx !== rowIdx) { - const step = Math.sign(rowIdx - previousRowIdx); - for (let i = previousRowIdx + step; i !== rowIdx; i += step) { - newSelectedRows.add(rowGetter(i)[rowKey]); - } - } - } else { - newSelectedRows.delete(row[rowKey]); - lastSelectedRowIdx.current = -1; - } - - if (onSelectedRowsChange) { - onSelectedRowsChange(newSelectedRows); - } - } - - function handleAllRowsSelectionChange(checked: boolean) { - const newSelectedRows = new Set(); - if (checked) { - for (let i = 0; i < rowsCount; i++) { - newSelectedRows.add(rowGetter(i)[rowKey]); - } - } - lastSelectedRowIdx.current = -1; - - if (onSelectedRowsChange) { - onSelectedRowsChange(newSelectedRows); - } - } - function getHeaderRows(): [HeaderRowData, HeaderRowData | undefined] { const { headerRowHeight, onAddFilter } = props; return [ @@ -475,8 +437,7 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ cellMetaData={cellMetaData} selectedRows={selectedRows} allRowsSelected={selectedRows !== undefined && selectedRows.size === rowsCount} - onRowSelectionChange={handleRowSelectionChange} - onAllRowsSelectionChange={handleAllRowsSelectionChange} + onSelectedRowsChange={onSelectedRowsChange} rowOffsetHeight={rowOffsetHeight} sortColumn={sortColumn} sortDirection={sortDirection} diff --git a/packages/react-data-grid/src/Row.tsx b/packages/react-data-grid/src/Row.tsx index 740ede31cf..9c47af086b 100644 --- a/packages/react-data-grid/src/Row.tsx +++ b/packages/react-data-grid/src/Row.tsx @@ -44,7 +44,7 @@ export default class Row extends React.Component> impleme getCell(column: CalculatedColumn) { const Renderer = this.props.cellRenderer!; - const { idx, cellMetaData, isScrolling, row, lastFrozenColumnIndex, scrollLeft, isRowSelected, onRowSelectionChange, onAllRowsSelectionChange } = this.props; + const { idx, cellMetaData, isScrolling, row, lastFrozenColumnIndex, scrollLeft, isRowSelected, onRowSelectionChange } = this.props; const { key } = column; const cellProps: CellRendererProps & { ref: (cell: CellRenderer | null) => void } = { @@ -61,8 +61,7 @@ export default class Row extends React.Component> impleme scrollLeft: isFrozen(column) && !isPositionStickySupported() ? scrollLeft : undefined, lastFrozenColumnIndex, isRowSelected, - onRowSelectionChange, - onAllRowsSelectionChange + onRowSelectionChange }; return ; // FIXME: fix key type diff --git a/packages/react-data-grid/src/Viewport.tsx b/packages/react-data-grid/src/Viewport.tsx index ccadf5fd1e..57cb6e2a56 100644 --- a/packages/react-data-grid/src/Viewport.tsx +++ b/packages/react-data-grid/src/Viewport.tsx @@ -19,6 +19,7 @@ type SharedGridProps = Pick, | 'rowGetter' | 'rowsCount' | 'selectedRows' +| 'onSelectedRowsChange' | 'columnMetrics' | 'cellMetaData' | 'rowOffsetHeight' @@ -37,8 +38,6 @@ type SharedGridProps = Pick, | 'overscanRowCount' | 'overscanColumnCount' | 'enableIsScrolling' -| 'onRowSelectionChange' -| 'onAllRowsSelectionChange' | 'onViewportKeydown' | 'onViewportKeyup' >; @@ -142,8 +141,7 @@ export default function Viewport({ rowGetter={props.rowGetter} rowsCount={rowsCount} selectedRows={props.selectedRows} - onRowSelectionChange={props.onRowSelectionChange} - onAllRowsSelectionChange={props.onAllRowsSelectionChange} + onSelectedRowsChange={props.onSelectedRowsChange} rowRenderer={props.rowRenderer} scrollTop={scrollTop} scrollLeft={scrollLeft} diff --git a/packages/react-data-grid/src/common/cells/headerCells/SortableHeaderCell.tsx b/packages/react-data-grid/src/common/cells/headerCells/SortableHeaderCell.tsx index 8ac6a9e6e1..269c30330e 100644 --- a/packages/react-data-grid/src/common/cells/headerCells/SortableHeaderCell.tsx +++ b/packages/react-data-grid/src/common/cells/headerCells/SortableHeaderCell.tsx @@ -16,12 +16,11 @@ export interface Props { sortDirection: DEFINE_SORT; sortDescendingFirst: boolean; allRowsSelected: boolean; - onRowSelectionChange(rowIdx: number, row: R, checked: boolean, isShiftClick: boolean): void; onAllRowsSelectionChange(checked: boolean): void; } export default function SortableHeaderCell(props: Props) { - const { column, rowType, onSort, sortDirection, sortDescendingFirst, allRowsSelected, onRowSelectionChange, onAllRowsSelectionChange } = props; + const { column, rowType, onSort, sortDirection, sortDescendingFirst, allRowsSelected, onAllRowsSelectionChange } = props; function onClick() { let direction; switch (sortDirection) { @@ -47,7 +46,6 @@ export default function SortableHeaderCell(props: Props) { column, rowType, allRowsSelected, - onRowSelectionChange, onAllRowsSelectionChange }); diff --git a/packages/react-data-grid/src/common/types.ts b/packages/react-data-grid/src/common/types.ts index 9cca186fd4..2aa262ba97 100644 --- a/packages/react-data-grid/src/common/types.ts +++ b/packages/react-data-grid/src/common/types.ts @@ -129,7 +129,6 @@ export interface FormatterProps { row: TRow; isRowSelected: boolean; onRowSelectionChange(rowIdx: number, row: TRow, checked: boolean, isShiftClick: boolean): void; - onAllRowsSelectionChange(checked: boolean): void; isScrolling?: boolean; dependentValues?: TDependentValue; } @@ -150,7 +149,6 @@ export interface HeaderRowProps { column: CalculatedColumn; rowType: HeaderRowType; allRowsSelected: boolean; - onRowSelectionChange(rowIdx: number, row: TRow, checked: boolean, isShiftClick: boolean): void; onAllRowsSelectionChange(checked: boolean): void; } @@ -168,7 +166,6 @@ export interface CellRendererProps { lastFrozenColumnIndex: number; isRowSelected: boolean; onRowSelectionChange(rowIdx: number, row: TRow, checked: boolean, isShiftClick: boolean): void; - onAllRowsSelectionChange(checked: boolean): void; } export interface RowRendererProps { @@ -187,7 +184,6 @@ export interface RowRendererProps { lastFrozenColumnIndex: number; isRowSelected: boolean; onRowSelectionChange(rowIdx: number, row: TRow, checked: boolean, isShiftClick: boolean): void; - onAllRowsSelectionChange(checked: boolean): void; } export interface FilterRendererProps { From e62c354091986775f1ef14ed7fec4fc4bae9ef97 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 15:58:06 +0100 Subject: [PATCH 17/34] tweaks --- packages/react-data-grid/src/Cell/CellValue.tsx | 4 ++-- packages/react-data-grid/src/Header.tsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-data-grid/src/Cell/CellValue.tsx b/packages/react-data-grid/src/Cell/CellValue.tsx index e5fa2e6b4a..38dffdf846 100644 --- a/packages/react-data-grid/src/Cell/CellValue.tsx +++ b/packages/react-data-grid/src/Cell/CellValue.tsx @@ -29,7 +29,7 @@ export default function CellValue({ rowIdx, rowData, column, value, isScrolli function getFormatterProps() { return { /* eslint-disable-next-line @typescript-eslint/no-explicit-any */ - value: value as any, + value: value as any, //FIXME: fix value type column, rowIdx, isScrolling, @@ -47,7 +47,7 @@ export default function CellValue({ rowIdx, rowData, column, value, isScrolli } if (isValidElementType(formatter)) { - return React.createElement(formatter, getFormatterProps()); //FIXME: fix value type + return React.createElement(formatter, getFormatterProps()); } return ; diff --git a/packages/react-data-grid/src/Header.tsx b/packages/react-data-grid/src/Header.tsx index f017b516ca..857c8fbb64 100644 --- a/packages/react-data-grid/src/Header.tsx +++ b/packages/react-data-grid/src/Header.tsx @@ -70,6 +70,8 @@ export default forwardRef(function Header(props: HeaderProps, ref: React.R } function handleAllRowsSelectionChange(checked: boolean) { + if (!props.onSelectedRowsChange) return; + const newSelectedRows = new Set(); if (checked) { for (let i = 0; i < props.rowsCount; i++) { @@ -77,9 +79,7 @@ export default forwardRef(function Header(props: HeaderProps, ref: React.R } } - if (props.onSelectedRowsChange) { - props.onSelectedRowsChange(newSelectedRows); - } + props.onSelectedRowsChange(newSelectedRows); } function getHeaderRow(row: HeaderRowData, ref: React.RefObject>) { From 1242b30fa4e7924dd5462d15ac36944fb079695e Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 15:58:24 +0100 Subject: [PATCH 18/34] Remove references to `enableRowSelect` --- examples/scripts/example13-all-features.js | 1 - examples/scripts/example16-row-select.js | 1 - examples/scripts/example21-cell-selection-events.js | 1 - packages/react-data-grid-addons/src/__tests__/Grid.spec.js | 4 +--- 4 files changed, 1 insertion(+), 6 deletions(-) diff --git a/examples/scripts/example13-all-features.js b/examples/scripts/example13-all-features.js index 5f9d1195e8..eeafd9a2ec 100644 --- a/examples/scripts/example13-all-features.js +++ b/examples/scripts/example13-all-features.js @@ -203,7 +203,6 @@ class Example extends React.Component { rowsCount={this.getSize()} onGridRowsUpdated={this.handleGridRowsUpdated} toolbar={} - enableRowSelect rowHeight={50} minHeight={600} /> diff --git a/examples/scripts/example16-row-select.js b/examples/scripts/example16-row-select.js index 9bbf07d9c9..f7ef9113cf 100644 --- a/examples/scripts/example16-row-select.js +++ b/examples/scripts/example16-row-select.js @@ -80,7 +80,6 @@ const exampleDescription = (

Allows a continuous range of rows to be selected by holding the shift key when clicking the row selection checkbox.

-

Note: These props supercede the existing enableRowSelect and onRowUpdated props which will be removed in a later release.

); diff --git a/examples/scripts/example21-cell-selection-events.js b/examples/scripts/example21-cell-selection-events.js index fc49cefbca..1ef4639e36 100644 --- a/examples/scripts/example21-cell-selection-events.js +++ b/examples/scripts/example21-cell-selection-events.js @@ -55,7 +55,6 @@ class Example extends React.Component { columns={this._columns} rowGetter={this.rowGetter} rowsCount={this._rows.length} - enableRowSelect="multi" minHeight={500} onRowSelect={this.onRowSelect} enableCellSelect diff --git a/packages/react-data-grid-addons/src/__tests__/Grid.spec.js b/packages/react-data-grid-addons/src/__tests__/Grid.spec.js index 1b6f73f980..032da6d686 100644 --- a/packages/react-data-grid-addons/src/__tests__/Grid.spec.js +++ b/packages/react-data-grid-addons/src/__tests__/Grid.spec.js @@ -169,7 +169,7 @@ describe('Grid', () => { let selectRowCol; beforeEach(() => { - ({ wrapper, columns } = setup({ enableRowSelect: true })); + ({ wrapper, columns } = setup()); selectRowCol = getBaseGrid(wrapper).props().columnMetrics.columns[0]; }); @@ -228,7 +228,6 @@ describe('Grid', () => { const rows = [{ id: '1' }, { id: '2' }]; const columns = [{ name: 'Id', key: 'id' }]; const { wrapper } = setup({ - enableRowSelect: true, rowsCount: rows.length, rowGetter(i) { return rows[i]; }, columns, @@ -261,7 +260,6 @@ describe('Grid', () => { const rows = [{ id: '1' }, { id: '2' }]; const columns = [{ name: 'Id', key: 'id' }]; const { wrapper } = setup({ - enableRowSelect: true, rowsCount: rows.length, rowGetter(i) { return rows[i]; }, columns, From b303f93f9eb349ef7930ba7b51a40bb770fe9d65 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 16:06:12 +0100 Subject: [PATCH 19/34] More cleanup --- examples/scripts/example16-row-select.js | 22 +------------ examples/scripts/example17-grid-events.js | 6 ---- .../example21-cell-selection-events.js | 5 --- examples/scripts/example23-row-reordering.js | 22 +------------ .../src/__tests__/Grid.spec.js | 32 +++---------------- .../src/__tests__/Grid.spec.js | 1 - 6 files changed, 7 insertions(+), 81 deletions(-) diff --git a/examples/scripts/example16-row-select.js b/examples/scripts/example16-row-select.js index f7ef9113cf..bd624f2d95 100644 --- a/examples/scripts/example16-row-select.js +++ b/examples/scripts/example16-row-select.js @@ -60,27 +60,7 @@ class Example extends React.Component { } const exampleDescription = ( -
-

Row selection is enabled via the rowSelection prop (object). The following keys control behaviour:

-

selectBy

-

- This allows rows to be selected programatically. The options are:
- indexes - to select rows by index.
- keys - to select rows by specified key and values.
- isSelectedKey - to select rows by specified key (based on value being truthy or falsy). -

-

onRowsSelected/onRowsDeselected

-

- When rows are selected or de-selected, onRowsSelected or onRowsDeselected functions will be called (set as props) with an array of .
- This allows for single or multiple selection to be implemented as desired, by either appending to or replacing the list of selected items. -

-

showCheckbox

-

Allows the row selection checkbox to be hidden (shown by default). Useful for selecting rows programatically and controlling selection via theonRowClick event.

-

enableShiftSelect

-

- Allows a continuous range of rows to be selected by holding the shift key when clicking the row selection checkbox. -

-
+
); export default exampleWrapper({ diff --git a/examples/scripts/example17-grid-events.js b/examples/scripts/example17-grid-events.js index df00931cac..dc96e9b338 100644 --- a/examples/scripts/example17-grid-events.js +++ b/examples/scripts/example17-grid-events.js @@ -69,12 +69,6 @@ class Example extends React.Component { rowGetter={this.rowGetter} rowsCount={this.state.rows.length} minHeight={500} - rowSelection={{ - showCheckbox: false, - selectBy: { - isSelectedKey: 'isSelected' - } - }} onRowClick={this.onRowClick} onGridKeyDown={this.onKeyDown} /> diff --git a/examples/scripts/example21-cell-selection-events.js b/examples/scripts/example21-cell-selection-events.js index 1ef4639e36..b22edcaf6d 100644 --- a/examples/scripts/example21-cell-selection-events.js +++ b/examples/scripts/example21-cell-selection-events.js @@ -31,10 +31,6 @@ class Example extends React.Component { return this._rows[index]; }; - onRowSelect = (rows) => { - this.setState({ selectedRows: rows }); - }; - onCellSelected = ({ rowIdx, idx }) => { this.grid.openCellEditor(rowIdx, idx); }; @@ -56,7 +52,6 @@ class Example extends React.Component { rowGetter={this.rowGetter} rowsCount={this._rows.length} minHeight={500} - onRowSelect={this.onRowSelect} enableCellSelect onCellSelected={this.onCellSelected} onCellDeSelected={this.onCellDeSelected} diff --git a/examples/scripts/example23-row-reordering.js b/examples/scripts/example23-row-reordering.js index fe189e385c..3267dc08f5 100644 --- a/examples/scripts/example23-row-reordering.js +++ b/examples/scripts/example23-row-reordering.js @@ -5,7 +5,7 @@ import { Draggable, Data } from 'react-data-grid-addons'; import exampleWrapper from '../components/exampleWrapper'; -const { Container: DraggableContainer, RowActionsCell, DropTargetRowContainer } = Draggable; +const { Container: DraggableContainer, DropTargetRowContainer } = Draggable; const { Selectors } = Data; const RowRenderer = DropTargetRowContainer(Row); @@ -83,35 +83,15 @@ class Example extends React.Component { this.setState({ rows: undraggedRows }); }; - onRowsSelected = (rows) => { - this.setState({ selectedIds: this.state.selectedIds.concat(rows.map(r => r.row[this.props.rowKey])) }); - }; - - onRowsDeselected = (rows) => { - const rowIds = rows.map(r => r.row[this.props.rowKey]); - this.setState({ selectedIds: this.state.selectedIds.filter(i => rowIds.indexOf(i) === -1) }); - }; - render() { return ( } - rowSelection={{ - showCheckbox: true, - enableShiftSelect: true, - onRowsSelected: this.onRowsSelected, - onRowsDeselected: this.onRowsDeselected, - selectBy: { - keys: { rowKey: this.props.rowKey, values: this.state.selectedIds } - } - }} /> ); diff --git a/packages/react-data-grid-addons/src/__tests__/Grid.spec.js b/packages/react-data-grid-addons/src/__tests__/Grid.spec.js index 032da6d686..1af4d3520d 100644 --- a/packages/react-data-grid-addons/src/__tests__/Grid.spec.js +++ b/packages/react-data-grid-addons/src/__tests__/Grid.spec.js @@ -193,17 +193,7 @@ describe('Grid', () => { wrapper = setup({ rowsCount: rows.length, rowGetter(i) { return rows[i]; }, - columns, - rowSelection: { - enableShiftSelect: true, - selectBy: { isSelectedKey: 'isSelected' }, - onRowsSelected(selectedRows) { - _selectedRows = selectedRows; - }, - onRowsDeselected(deselectedRows) { - _deselectedRows = deselectedRows; - } - } + columns }).wrapper; selectRowCol = getBaseGrid(wrapper).props().columnMetrics.columns[0]; }); @@ -224,19 +214,13 @@ describe('Grid', () => { describe('checking header checkbox', () => { it('should call rowSelection.onRowsSelected with all rows', () => { - let _selectedRows = []; + const _selectedRows = []; const rows = [{ id: '1' }, { id: '2' }]; const columns = [{ name: 'Id', key: 'id' }]; const { wrapper } = setup({ rowsCount: rows.length, rowGetter(i) { return rows[i]; }, - columns, - rowSelection: { - selectBy: { indexes: [] }, - onRowsSelected(selectedRows) { - _selectedRows = selectedRows; - } - } + columns }); const selectRowCol = getBaseGrid(wrapper).props().columnMetrics.columns[0]; @@ -256,19 +240,13 @@ describe('Grid', () => { describe('un-checking header checkbox', () => { it('then unchecking should call rowSelection.onRowsDeselected with all rows', () => { - let _deselectedRows = []; + const _deselectedRows = []; const rows = [{ id: '1' }, { id: '2' }]; const columns = [{ name: 'Id', key: 'id' }]; const { wrapper } = setup({ rowsCount: rows.length, rowGetter(i) { return rows[i]; }, - columns, - rowSelection: { - selectBy: { indexes: [0, 1] }, - onRowsDeselected(deselectedRows) { - _deselectedRows = deselectedRows; - } - } + columns }); const selectRowCol = getBaseGrid(wrapper).props().columnMetrics.columns[0]; diff --git a/packages/react-data-grid/src/__tests__/Grid.spec.js b/packages/react-data-grid/src/__tests__/Grid.spec.js index cf189452a2..05a58e3c8c 100644 --- a/packages/react-data-grid/src/__tests__/Grid.spec.js +++ b/packages/react-data-grid/src/__tests__/Grid.spec.js @@ -64,7 +64,6 @@ describe('Rendering Grid component', () => { rowRenderer: jest.fn(), emptyRowsView: jest.fn(), selectedRows: jest.fn(), - rowSelection: { isSelectedKey: 'selectedKey' }, rowsCount: 14, sortColumn: 'sortColumn', sortDirection: 'ASC', From 3df47103a6089d73d5f0260f44d33ffe74111596 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 16:36:00 +0100 Subject: [PATCH 20/34] fix some tests --- .../react-data-grid/src/__tests__/Canvas.spec.tsx | 4 ++-- packages/react-data-grid/src/__tests__/Cell.spec.tsx | 6 ++++++ .../react-data-grid/src/__tests__/Header.spec.tsx | 12 ++++++++++++ .../src/__tests__/HeaderCell.spec.tsx | 9 ++++++++- .../react-data-grid/src/__tests__/HeaderRow.spec.tsx | 4 ++++ packages/react-data-grid/src/__tests__/Row.spec.tsx | 4 +++- .../__tests__/SortableHeaderCell.spec.tsx | 2 ++ .../src/common/utils/__tests__/RowComparer.spec.ts | 2 ++ 8 files changed, 39 insertions(+), 4 deletions(-) diff --git a/packages/react-data-grid/src/__tests__/Canvas.spec.tsx b/packages/react-data-grid/src/__tests__/Canvas.spec.tsx index 8315b85c01..532f9f1ba3 100644 --- a/packages/react-data-grid/src/__tests__/Canvas.spec.tsx +++ b/packages/react-data-grid/src/__tests__/Canvas.spec.tsx @@ -96,7 +96,7 @@ describe('Canvas Tests', () => { }); describe('Row Selection', () => { - fit('renders row selected', () => { + it('renders row selected', () => { const rowGetter = () => ({ id: 1 }); const wrapper = renderComponent({ @@ -110,7 +110,7 @@ describe('Canvas Tests', () => { }); const rows = getRows(wrapper); - expect(rows[0].props.isSelected).toBe(true); + expect(rows[0].props.isRowSelected).toBe(true); }); }); diff --git a/packages/react-data-grid/src/__tests__/Cell.spec.tsx b/packages/react-data-grid/src/__tests__/Cell.spec.tsx index 32f096838e..215293816c 100644 --- a/packages/react-data-grid/src/__tests__/Cell.spec.tsx +++ b/packages/react-data-grid/src/__tests__/Cell.spec.tsx @@ -45,6 +45,8 @@ const testProps: CellProps = { rowData: { id: 1, description: 'Wicklow' }, height: 40, isScrolling: false, + isRowSelected: false, + onRowSelectionChange() {}, scrollLeft: 0, lastFrozenColumnIndex: -1 }; @@ -93,6 +95,8 @@ describe('Cell Tests', () => { rowData: helpers.rowGetter(11), expandableOptions, isScrolling: false, + isRowSelected: false, + onRowSelectionChange() {}, scrollLeft: 0, lastFrozenColumnIndex: -1 }; @@ -126,6 +130,8 @@ describe('Cell Tests', () => { rowData: helpers.rowGetter(11), expandableOptions, isScrolling: false, + isRowSelected: false, + onRowSelectionChange() {}, scrollLeft: 0, lastFrozenColumnIndex: -1, ...propsOverride diff --git a/packages/react-data-grid/src/__tests__/Header.spec.tsx b/packages/react-data-grid/src/__tests__/Header.spec.tsx index 69585b5b4f..fcb3d6cd58 100644 --- a/packages/react-data-grid/src/__tests__/Header.spec.tsx +++ b/packages/react-data-grid/src/__tests__/Header.spec.tsx @@ -12,6 +12,10 @@ const SCROLL_BAR_SIZE = 17; describe('Header Unit Tests', () => { function getProps(): HeaderProps { return { + rowKey: 'id', + rowsCount: 1, + rowGetter() { return {}; }, + allRowsSelected: false, columnMetrics: { columns: helpers.columns, minColumnWidth: 80, @@ -63,6 +67,10 @@ describe('Header Unit Tests', () => { return shallow(React.createElement(Header as React.FunctionComponent>, props)); } const testRequiredProps: HeaderProps = { + rowKey: 'id', + rowsCount: 1, + rowGetter() { return {}; }, + allRowsSelected: false, columnMetrics: { columns: helpers.columns, minColumnWidth: 81, @@ -84,6 +92,10 @@ describe('Header Unit Tests', () => { rowOffsetHeight: 30 }; const testAllProps: HeaderProps = { + rowKey: 'id', + rowsCount: 1, + rowGetter() { return {}; }, + allRowsSelected: false, columnMetrics: { columns: helpers.columns, minColumnWidth: 80, diff --git a/packages/react-data-grid/src/__tests__/HeaderCell.spec.tsx b/packages/react-data-grid/src/__tests__/HeaderCell.spec.tsx index 4ec03b9ac3..ace155e7dd 100644 --- a/packages/react-data-grid/src/__tests__/HeaderCell.spec.tsx +++ b/packages/react-data-grid/src/__tests__/HeaderCell.spec.tsx @@ -30,6 +30,8 @@ describe('Header Cell Tests', () => { name: 'bla', onHeaderDrop() { }, draggableHeaderCell: DraggableHeaderCell, + allRowsSelected: false, + onAllRowsSelectionChange() {}, ...overrideProps }; const wrapper = mount>(); @@ -64,7 +66,12 @@ describe('Header Cell Tests', () => { it('pass the column as property to cell renderer if it is a function', () => { const rendererFunction = jest.fn(() =>
Custom
); const { props } = setup({ renderer: rendererFunction }); - expect(rendererFunction).toHaveBeenCalledWith({ column: props.column, rowType: HeaderRowType.HEADER }, {}); + expect(rendererFunction).toHaveBeenCalledWith({ + column: props.column, + rowType: HeaderRowType.HEADER, + allRowsSelected: false, + onAllRowsSelectionChange: expect.any(Function) + }, {}); }); it('should not pass the column as property to cell renderer if it is a jsx object', () => { diff --git a/packages/react-data-grid/src/__tests__/HeaderRow.spec.tsx b/packages/react-data-grid/src/__tests__/HeaderRow.spec.tsx index 0a48bd62ef..6a3911faf6 100644 --- a/packages/react-data-grid/src/__tests__/HeaderRow.spec.tsx +++ b/packages/react-data-grid/src/__tests__/HeaderRow.spec.tsx @@ -17,6 +17,8 @@ describe('Header Row Unit Tests', () => { onSort: jest.fn(), sortDirection: DEFINE_SORT.NONE, height: 35, + allRowsSelected: false, + onAllRowsSelectionChange() {}, onFilterChange() { }, onHeaderDrop() { }, draggableHeaderCell: () =>
@@ -132,6 +134,8 @@ describe('Header Row Unit Tests', () => { columns: helpers.columns, onSort: jest.fn(), rowType: HeaderRowType.HEADER, + allRowsSelected: false, + onAllRowsSelectionChange() {}, onColumnResize: jest.fn(), onColumnResizeEnd: jest.fn(), onFilterChange() { }, diff --git a/packages/react-data-grid/src/__tests__/Row.spec.tsx b/packages/react-data-grid/src/__tests__/Row.spec.tsx index 22279d6d8e..6ef1c25142 100644 --- a/packages/react-data-grid/src/__tests__/Row.spec.tsx +++ b/packages/react-data-grid/src/__tests__/Row.spec.tsx @@ -48,7 +48,9 @@ describe('Row', () => { colOverscanEndIdx: 20, isScrolling: true, scrollLeft: 0, - lastFrozenColumnIndex: -1 + lastFrozenColumnIndex: -1, + isRowSelected: false, + onRowSelectionChange() {} }; it('passes classname property', () => { diff --git a/packages/react-data-grid/src/common/cells/headerCells/__tests__/SortableHeaderCell.spec.tsx b/packages/react-data-grid/src/common/cells/headerCells/__tests__/SortableHeaderCell.spec.tsx index b1cc1b6f58..c1379fdddb 100644 --- a/packages/react-data-grid/src/common/cells/headerCells/__tests__/SortableHeaderCell.spec.tsx +++ b/packages/react-data-grid/src/common/cells/headerCells/__tests__/SortableHeaderCell.spec.tsx @@ -21,6 +21,8 @@ describe('', () => { onSort: jest.fn(), sortDirection: DEFINE_SORT.NONE, sortDescendingFirst: false, + allRowsSelected: false, + onAllRowsSelectionChange() {}, ...overrideProps }; const wrapper = shallow(); diff --git a/packages/react-data-grid/src/common/utils/__tests__/RowComparer.spec.ts b/packages/react-data-grid/src/common/utils/__tests__/RowComparer.spec.ts index db4156e0cd..dcd1914980 100644 --- a/packages/react-data-grid/src/common/utils/__tests__/RowComparer.spec.ts +++ b/packages/react-data-grid/src/common/utils/__tests__/RowComparer.spec.ts @@ -18,6 +18,8 @@ const defaultProps: RowRendererProps = { height: 60, columns, row: {}, + isRowSelected: false, + onRowSelectionChange() {}, colOverscanStartIdx: 0, colOverscanEndIdx: 1, isScrolling: false, From edb4fa7d60888b0e2da4a610727627b06d55c884 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 16:50:13 +0100 Subject: [PATCH 21/34] fix tests --- .../src/__tests__/Grid.spec.js | 106 +----------------- .../masks/__tests__/InteractionMasks.spec.tsx | 6 +- 2 files changed, 4 insertions(+), 108 deletions(-) diff --git a/packages/react-data-grid-addons/src/__tests__/Grid.spec.js b/packages/react-data-grid-addons/src/__tests__/Grid.spec.js index 1af4d3520d..a93ffae803 100644 --- a/packages/react-data-grid-addons/src/__tests__/Grid.spec.js +++ b/packages/react-data-grid-addons/src/__tests__/Grid.spec.js @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom'; import { mount } from 'enzyme'; import TestUtils from 'react-dom/test-utils'; -import Grid, { CheckboxEditor } from 'react-data-grid'; +import Grid from 'react-data-grid'; describe('Grid', () => { const setup = (extraProps) => { @@ -163,110 +163,6 @@ describe('Grid', () => { }); }); - describe('When row selection enabled', () => { - let wrapper; - let columns; - let selectRowCol; - - beforeEach(() => { - ({ wrapper, columns } = setup()); - selectRowCol = getBaseGrid(wrapper).props().columnMetrics.columns[0]; - }); - - it('should render an additional Select Row column', () => { - expect(getBaseGrid(wrapper).props().columnMetrics.columns.length).toEqual(columns.length + 1); - expect(TestUtils.isElementOfType(selectRowCol.formatter, CheckboxEditor)).toBe(true); - }); - }); - - describe('When selection enabled and using rowSelection props', () => { - let selectRowCol; - let rows; - let _selectedRows; - let _deselectedRows; - let wrapper; - - beforeEach(() => { - _deselectedRows = []; - rows = [{ id: '1', isSelected: true }, { id: '2', isSelected: false }, { id: '3', isSelected: false }, { id: '4', isSelected: false }]; - const columns = [{ name: 'Id', key: 'id' }]; - wrapper = setup({ - rowsCount: rows.length, - rowGetter(i) { return rows[i]; }, - columns - }).wrapper; - selectRowCol = getBaseGrid(wrapper).props().columnMetrics.columns[0]; - }); - - it('should call rowSelection.onRowsSelected when row selected', () => { - selectRowCol.onCellChange(1, '', rows[1], buildFakeEvent()); - expect(_selectedRows.length).toBe(1); - expect(_selectedRows[0].rowIdx).toBe(1); - expect(_selectedRows[0].row).toBe(rows[1]); - }); - - it('should call rowSelection.onRowsDeselected when row de-selected', () => { - selectRowCol.onCellChange(0, '', rows[0], buildFakeEvent()); - expect(_deselectedRows.length).toBe(1); - expect(_deselectedRows[0].rowIdx).toBe(0); - expect(_deselectedRows[0].row).toBe(rows[0]); - }); - - describe('checking header checkbox', () => { - it('should call rowSelection.onRowsSelected with all rows', () => { - const _selectedRows = []; - const rows = [{ id: '1' }, { id: '2' }]; - const columns = [{ name: 'Id', key: 'id' }]; - const { wrapper } = setup({ - rowsCount: rows.length, - rowGetter(i) { return rows[i]; }, - columns - }); - - const selectRowCol = getBaseGrid(wrapper).props().columnMetrics.columns[0]; - - // header checkbox - const checkboxWrapper = document.createElement('div'); - checkboxWrapper.innerHTML = ''; - const checkbox = checkboxWrapper.querySelector('input'); - const fakeEvent = buildFakeEvent({ currentTarget: checkbox }); - const SelectAll = selectRowCol.headerRenderer; - const selectAllWrapper = mount(SelectAll); - selectAllWrapper.props().onChange(fakeEvent); - - expect(_selectedRows.length).toBe(2); - }); - }); - - describe('un-checking header checkbox', () => { - it('then unchecking should call rowSelection.onRowsDeselected with all rows', () => { - const _deselectedRows = []; - const rows = [{ id: '1' }, { id: '2' }]; - const columns = [{ name: 'Id', key: 'id' }]; - const { wrapper } = setup({ - rowsCount: rows.length, - rowGetter(i) { return rows[i]; }, - columns - }); - - const selectRowCol = getBaseGrid(wrapper).props().columnMetrics.columns[0]; - - // header checkbox - const checkboxWrapper = document.createElement('div'); - checkboxWrapper.innerHTML = ''; - const checkbox = checkboxWrapper.querySelector('input'); - const SelectAll = selectRowCol.headerRenderer; - const selectAllWrapper = mount(SelectAll); - - checkbox.checked = false; - const fakeEvent = buildFakeEvent({ currentTarget: checkbox }); - selectAllWrapper.props().onChange(fakeEvent); - - expect(_deselectedRows.length).toBe(2); - }); - }); - }); - describe('Table width', () => { describe('providing table width as prop', () => { it('should set the width of the table', () => { diff --git a/packages/react-data-grid/src/masks/__tests__/InteractionMasks.spec.tsx b/packages/react-data-grid/src/masks/__tests__/InteractionMasks.spec.tsx index ddf6a02f08..b10f495992 100644 --- a/packages/react-data-grid/src/masks/__tests__/InteractionMasks.spec.tsx +++ b/packages/react-data-grid/src/masks/__tests__/InteractionMasks.spec.tsx @@ -213,11 +213,11 @@ describe('', () => { it('should give focus to InteractionMasks once a selection has ended', () => { // We have to use mount, rather than shallow, so that InteractionMasks has a ref to it's node, used for focusing - const { props } = setup(undefined, undefined, true); + const { wrapper, props } = setup(undefined, undefined, true); props.eventBus.dispatch(EventTypes.SELECT_START, { idx: 2, rowIdx: 2 }); - jest.spyOn(InteractionMasks.prototype, 'focus').mockImplementation(() => { }); + jest.spyOn(wrapper.instance(), 'focus').mockImplementation(() => { }); props.eventBus.dispatch(EventTypes.SELECT_END); - expect(InteractionMasks.prototype.focus).toHaveBeenCalled(); + expect(wrapper.instance().focus).toHaveBeenCalled(); }); }); }); From 94389855ec7f9a885edf0b2892351f3987a3a9e5 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 16:54:39 +0100 Subject: [PATCH 22/34] Remove @testing-library/react/cleanup-after-each --- jest.config.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/jest.config.js b/jest.config.js index 1c36ede9b7..4c6cf01ddb 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,9 +28,6 @@ module.exports = { setupFiles: [ '/test/setupTests.js' ], - setupFilesAfterEnv: [ - '@testing-library/react/cleanup-after-each' - ], testMatch: [ '/packages/*/src/**/*.spec.(js|ts|tsx)', '/examples/**/*.spec.(js|ts|tsx)', From c79be1f7f2a66a305b1b04d81a7115a8e56c7da1 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 17:16:36 +0100 Subject: [PATCH 23/34] Fix some examples --- examples/scripts/example13-all-features.js | 14 +++++++-- examples/scripts/example16-row-select.js | 6 +++- examples/scripts/example17-grid-events.js | 34 +++++++++++++--------- packages/react-data-grid/src/Canvas.tsx | 6 ++-- 4 files changed, 41 insertions(+), 19 deletions(-) diff --git a/examples/scripts/example13-all-features.js b/examples/scripts/example13-all-features.js index eeafd9a2ec..db28829d13 100644 --- a/examples/scripts/example13-all-features.js +++ b/examples/scripts/example13-all-features.js @@ -1,5 +1,5 @@ import React from 'react'; -import ReactDataGrid from 'react-data-grid'; +import ReactDataGrid, { SelectColumn } from 'react-data-grid'; import { Editors, Toolbar, Formatters } from 'react-data-grid-addons'; import update from 'immutability-helper'; import faker from 'faker'; @@ -17,6 +17,7 @@ class Example extends React.Component { constructor(props, context) { super(props, context); this._columns = [ + SelectColumn, { key: 'id', name: 'ID', @@ -115,7 +116,10 @@ class Example extends React.Component { } ]; - this.state = { rows: this.createRows(2000) }; + this.state = { + rows: this.createRows(2000), + selectedRows: new Set() + }; } createRows = (numberOfRows) => { @@ -193,6 +197,10 @@ class Example extends React.Component { return this.state.rows.length; }; + onSelectedRowsChange = (selectedRows) => { + this.setState({ selectedRows }); + }; + render() { return ( } rowHeight={50} minHeight={600} + selectedRows={this.state.selectedRows} + onSelectedRowsChange={this.onSelectedRowsChange} /> ); } diff --git a/examples/scripts/example16-row-select.js b/examples/scripts/example16-row-select.js index bd624f2d95..45e214d2e2 100644 --- a/examples/scripts/example16-row-select.js +++ b/examples/scripts/example16-row-select.js @@ -40,6 +40,10 @@ class Example extends React.Component { return this.state.rows[i]; }; + onSelectedRowsChange = (selectedRows) => { + this.setState({ selectedRows }); + }; + render() { const rowText = this.state.selectedRows.size === 1 ? 'row' : 'rows'; return ( @@ -52,7 +56,7 @@ class Example extends React.Component { rowsCount={this.state.rows.length} minHeight={500} selectedRows={this.state.selectedRows} - onSelectedRowsChange={selectedRows => this.setState({ selectedRows })} + onSelectedRowsChange={this.onSelectedRowsChange} />
); diff --git a/examples/scripts/example17-grid-events.js b/examples/scripts/example17-grid-events.js index dc96e9b338..240d0d2814 100644 --- a/examples/scripts/example17-grid-events.js +++ b/examples/scripts/example17-grid-events.js @@ -21,7 +21,10 @@ class Example extends React.Component { } ]; - this.state = { rows: this.createRows(1000) }; + this.state = { + rows: this.createRows(), + selectedRows: new Set() + }; } createRows = () => { @@ -30,8 +33,7 @@ class Example extends React.Component { rows.push({ id: i, title: `Title ${i}`, - count: i * 1000, - isSelected: false + count: i * 1000 }); } @@ -43,24 +45,28 @@ class Example extends React.Component { }; onRowClick = (rowIdx, row) => { - const rows = this.state.rows.slice(); - rows[rowIdx] = { ...row, isSelected: !row.isSelected }; - this.setState({ rows }); + const newSelectedRows = new Set(this.state.selectedRows); + if (newSelectedRows.has(row.id)) { + newSelectedRows.delete(row.id); + } else { + newSelectedRows.add(row.id); + } + this.onSelectedRowsChange(newSelectedRows); }; onKeyDown = (e) => { if (e.ctrlKey && e.keyCode === 65) { e.preventDefault(); - - const rows = []; - this.state.rows.forEach((r) => { - rows.push({ ...r, isSelected: true }); - }); - - this.setState({ rows }); + const newSelectedRows = new Set(this.state.selectedRows); + this.state.rows.forEach(row => newSelectedRows.add(row.id)); + this.onSelectedRowsChange(newSelectedRows); } }; + onSelectedRowsChange = (selectedRows) => { + this.setState({ selectedRows }); + }; + render() { return ( ); } diff --git a/packages/react-data-grid/src/Canvas.tsx b/packages/react-data-grid/src/Canvas.tsx index 712ef532a0..0af00a83aa 100644 --- a/packages/react-data-grid/src/Canvas.tsx +++ b/packages/react-data-grid/src/Canvas.tsx @@ -152,6 +152,8 @@ export default class Canvas extends React.PureComponent> { } handleRowSelectionChange = (rowIdx: number, row: R, checked: boolean, isShiftClick: boolean) => { + if (!this.props.onSelectedRowsChange) return; + const { rowKey } = this.props; const newSelectedRows = new Set(this.props.selectedRows); @@ -170,9 +172,7 @@ export default class Canvas extends React.PureComponent> { this.lastSelectedRowIdx = -1; } - if (this.props.onSelectedRowsChange) { - this.props.onSelectedRowsChange(newSelectedRows); - } + this.props.onSelectedRowsChange(newSelectedRows); }; setScrollLeft(scrollLeft: number) { From 604cb90dc603bc58913ff9ce64241af4df757d51 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 17:32:09 +0100 Subject: [PATCH 24/34] Fix another example --- examples/scripts/example23-row-reordering.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/examples/scripts/example23-row-reordering.js b/examples/scripts/example23-row-reordering.js index 3267dc08f5..30744773a7 100644 --- a/examples/scripts/example23-row-reordering.js +++ b/examples/scripts/example23-row-reordering.js @@ -1,6 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; -import ReactDataGrid, { Row } from 'react-data-grid'; +import ReactDataGrid, { Row, SelectColumn } from 'react-data-grid'; import { Draggable, Data } from 'react-data-grid-addons'; import exampleWrapper from '../components/exampleWrapper'; @@ -19,6 +19,7 @@ class Example extends React.Component { constructor(props, context) { super(props, context); this._columns = [ + SelectColumn, { key: 'id', name: 'ID' @@ -37,7 +38,10 @@ class Example extends React.Component { } ]; - this.state = { rows: this.createRows(1000), selectedIds: [1, 2] }; + this.state = { + rows: this.createRows(1000), + selectedRows: new Set([1, 2]) + }; } getRandomDate = (start, end) => { @@ -83,6 +87,10 @@ class Example extends React.Component { this.setState({ rows: undraggedRows }); }; + onSelectedRowsChange = (selectedRows) => { + this.setState({ selectedRows }); + }; + render() { return ( @@ -92,6 +100,8 @@ class Example extends React.Component { rowsCount={this.state.rows.length} minHeight={500} rowRenderer={} + selectedRows={this.state.selectedRows} + onSelectedRowsChange={this.onSelectedRowsChange} /> ); From 2a0d7fd09b58130814ae401798c18e5395822f54 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 3 Oct 2019 17:53:35 +0100 Subject: [PATCH 25/34] optimize all-features example --- examples/scripts/example13-all-features.js | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/examples/scripts/example13-all-features.js b/examples/scripts/example13-all-features.js index db28829d13..b511f49d70 100644 --- a/examples/scripts/example13-all-features.js +++ b/examples/scripts/example13-all-features.js @@ -16,7 +16,7 @@ const titles = ['Dr.', 'Mr.', 'Mrs.', 'Miss', 'Ms.']; class Example extends React.Component { constructor(props, context) { super(props, context); - this._columns = [ + this.columns = [ SelectColumn, { key: 'id', @@ -39,8 +39,8 @@ class Example extends React.Component { width: 200, resizable: true, events: { - onDoubleClick() { - console.log('The user double clicked on title column'); + onClick: (ev, { idx, rowIdx }) => { + this.grid.openCellEditor(rowIdx, idx); } } }, @@ -149,17 +149,6 @@ class Example extends React.Component { }; }; - getColumns = () => { - const clonedColumns = this._columns.slice(); - clonedColumns[2].events = { - onClick: (ev, { idx, rowIdx }) => { - this.grid.openCellEditor(rowIdx, idx); - } - }; - - return clonedColumns; - }; - handleGridRowsUpdated = ({ fromRow, toRow, updated }) => { const rows = this.state.rows.slice(); @@ -206,7 +195,7 @@ class Example extends React.Component { this.grid = node} enableCellSelect - columns={this.getColumns()} + columns={this.columns} rowGetter={this.getRowAt} rowsCount={this.getSize()} onGridRowsUpdated={this.handleGridRowsUpdated} From 785f0d7983713530509bc7e3d026ca327f6026de Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Thu, 3 Oct 2019 12:52:22 -0500 Subject: [PATCH 26/34] Cleanup viewport events --- packages/react-data-grid/src/Grid.tsx | 4 ++-- packages/react-data-grid/src/ReactDataGrid.tsx | 18 ++---------------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/packages/react-data-grid/src/Grid.tsx b/packages/react-data-grid/src/Grid.tsx index 3b5a38390a..2ec0a3065d 100644 --- a/packages/react-data-grid/src/Grid.tsx +++ b/packages/react-data-grid/src/Grid.tsx @@ -48,8 +48,8 @@ export interface GridProps extends SharedDataGridProps { eventBus: EventBus; interactionMasksMetaData: InteractionMasksMetaData; onSort(columnKey: keyof R, sortDirection: DEFINE_SORT): void; - onViewportKeydown(e: React.KeyboardEvent): void; - onViewportKeyup(e: React.KeyboardEvent): void; + onViewportKeydown?(e: React.KeyboardEvent): void; + onViewportKeyup?(e: React.KeyboardEvent): void; onColumnResize(idx: number, width: number): void; allRowsSelected: boolean; viewportWidth: number; diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index 4e3f0b54d1..7abb88501f 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -263,20 +263,6 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ eventBus.dispatch(EventTypes.DRAG_ENTER, overRowIdx); } - function handleViewportKeyDown(e: React.KeyboardEvent) { - const { onGridKeyDown } = props; - if (onGridKeyDown) { - onGridKeyDown(e); - } - } - - function handleViewportKeyUp(e: React.KeyboardEvent) { - const { onGridKeyUp } = props; - if (onGridKeyUp) { - onGridKeyUp(e); - } - } - function handleCellClick({ rowIdx, idx }: Position) { const { onRowClick } = props; selectCell({ rowIdx, idx }); @@ -443,8 +429,8 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ sortDirection={sortDirection} onSort={handleSort} minHeight={minHeight} - onViewportKeydown={handleViewportKeyDown} - onViewportKeyup={handleViewportKeyUp} + onViewportKeydown={props.onGridKeyDown} + onViewportKeyup={props.onGridKeyUp} onColumnResize={handleColumnResize} scrollToRowIndex={props.scrollToRowIndex} contextMenu={props.contextMenu} From 9f6762d3652012a661ce3cfefd8c4298ffb34734 Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Thu, 3 Oct 2019 13:30:53 -0500 Subject: [PATCH 27/34] Cleanup props, remove PureComponent --- packages/react-data-grid/src/Grid.tsx | 25 ++++++++++++------- packages/react-data-grid/src/Header.tsx | 5 ++-- packages/react-data-grid/src/HeaderRow.tsx | 2 +- .../react-data-grid/src/ReactDataGrid.tsx | 1 - 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/packages/react-data-grid/src/Grid.tsx b/packages/react-data-grid/src/Grid.tsx index 2ec0a3065d..49e78a427d 100644 --- a/packages/react-data-grid/src/Grid.tsx +++ b/packages/react-data-grid/src/Grid.tsx @@ -51,11 +51,18 @@ export interface GridProps extends SharedDataGridProps { onViewportKeydown?(e: React.KeyboardEvent): void; onViewportKeyup?(e: React.KeyboardEvent): void; onColumnResize(idx: number, width: number): void; - allRowsSelected: boolean; viewportWidth: number; } -export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...props }: GridProps) { +export default function Grid({ + rowKey, + rowsCount, + emptyRowsView, + headerRows, + viewportWidth, + selectedRows, + ...props +}: GridProps) { const header = useRef(null); const scrollLeft = useRef(0); @@ -75,9 +82,9 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p
{ React.createElement(Header as React.FunctionComponent, { + rowKey, + rowsCount, ref: header, - rowKey: props.rowKey, - rowsCount: props.rowsCount, rowGetter: props.rowGetter, columnMetrics: props.columnMetrics, onColumnResize: props.onColumnResize, @@ -88,24 +95,24 @@ export default function Grid({ emptyRowsView, headerRows, viewportWidth, ...p draggableHeaderCell: props.draggableHeaderCell, onSort: props.onSort, onHeaderDrop: props.onHeaderDrop, - allRowsSelected: props.allRowsSelected, + allRowsSelected: selectedRows !== undefined && selectedRows.size === rowsCount, onSelectedRowsChange: props.onSelectedRowsChange, getValidFilterValues: props.getValidFilterValues, cellMetaData: props.cellMetaData }) } - {props.rowsCount === 0 && isValidElementType(emptyRowsView) ? ( + {rowsCount === 0 && isValidElementType(emptyRowsView) ? (
{createElement(emptyRowsView)}
) : ( - rowKey={props.rowKey} + rowKey={rowKey} rowHeight={props.rowHeight} rowRenderer={props.rowRenderer} rowGetter={props.rowGetter} - rowsCount={props.rowsCount} - selectedRows={props.selectedRows} + rowsCount={rowsCount} + selectedRows={selectedRows} onSelectedRowsChange={props.onSelectedRowsChange} columnMetrics={props.columnMetrics} onScroll={onScroll} diff --git a/packages/react-data-grid/src/Header.tsx b/packages/react-data-grid/src/Header.tsx index 857c8fbb64..d241d6000a 100644 --- a/packages/react-data-grid/src/Header.tsx +++ b/packages/react-data-grid/src/Header.tsx @@ -18,7 +18,6 @@ type SharedGridProps = Pick, | 'sortColumn' | 'sortDirection' | 'draggableHeaderCell' -| 'allRowsSelected' | 'onSelectedRowsChange' | 'onSort' | 'onHeaderDrop' @@ -26,7 +25,9 @@ type SharedGridProps = Pick, | 'cellMetaData' >; -export type HeaderProps = SharedGridProps; +export type HeaderProps = SharedGridProps & { + allRowsSelected: boolean; +}; export interface HeaderHandle { setScrollLeft(scrollLeft: number): void; diff --git a/packages/react-data-grid/src/HeaderRow.tsx b/packages/react-data-grid/src/HeaderRow.tsx index 2ca879c6ef..61773e4cc3 100644 --- a/packages/react-data-grid/src/HeaderRow.tsx +++ b/packages/react-data-grid/src/HeaderRow.tsx @@ -29,7 +29,7 @@ export interface HeaderRowProps extends SharedHeaderProps { rowType: HeaderRowType; } -export default class HeaderRow extends React.PureComponent> { +export default class HeaderRow extends React.Component> { static displayName = 'HeaderRow'; private readonly headerRow = React.createRef(); diff --git a/packages/react-data-grid/src/ReactDataGrid.tsx b/packages/react-data-grid/src/ReactDataGrid.tsx index 7abb88501f..c544d3b7ae 100644 --- a/packages/react-data-grid/src/ReactDataGrid.tsx +++ b/packages/react-data-grid/src/ReactDataGrid.tsx @@ -422,7 +422,6 @@ const ReactDataGridBase = forwardRef(function ReactDataGrid({ rowGroupRenderer={props.rowGroupRenderer} cellMetaData={cellMetaData} selectedRows={selectedRows} - allRowsSelected={selectedRows !== undefined && selectedRows.size === rowsCount} onSelectedRowsChange={onSelectedRowsChange} rowOffsetHeight={rowOffsetHeight} sortColumn={sortColumn} From ba576e87ad63e14340ec87abc250fadb25996243 Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Thu, 3 Oct 2019 14:26:44 -0500 Subject: [PATCH 28/34] Fix draggable header example --- .../scripts/example24-draggable-header.js | 30 +++++-------------- packages/react-data-grid/src/Header.tsx | 4 +-- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/examples/scripts/example24-draggable-header.js b/examples/scripts/example24-draggable-header.js index f6f33db548..c431835aff 100644 --- a/examples/scripts/example24-draggable-header.js +++ b/examples/scripts/example24-draggable-header.js @@ -25,29 +25,13 @@ class Example extends React.Component { }; onHeaderDrop = (source, target) => { - const stateCopy = { ...this.state }; - const columnSourceIndex = this.state.columns.findIndex( - i => i.key === source - ); - const columnTargetIndex = this.state.columns.findIndex( - i => i.key === target - ); - - stateCopy.columns.splice( - columnTargetIndex, - 0, - stateCopy.columns.splice(columnSourceIndex, 1)[0] - ); - - const emptyColumns = { ...this.state, columns: [] }; - this.setState( - emptyColumns - ); - - const reorderedColumns = { ...this.state, columns: stateCopy.columns }; - this.setState( - reorderedColumns - ); + const columns = [...this.state.columns]; + const columnSourceIndex = columns.findIndex(i => i.key === source); + const columnTargetIndex = columns.findIndex(i => i.key === target); + const temp = { ...columns[columnSourceIndex] }; + columns[columnSourceIndex] = { ...columns[columnTargetIndex] }; + columns[columnTargetIndex] = temp; + this.setState({ columns }); }; state = { diff --git a/packages/react-data-grid/src/Header.tsx b/packages/react-data-grid/src/Header.tsx index d241d6000a..ce71401199 100644 --- a/packages/react-data-grid/src/Header.tsx +++ b/packages/react-data-grid/src/Header.tsx @@ -25,9 +25,9 @@ type SharedGridProps = Pick, | 'cellMetaData' >; -export type HeaderProps = SharedGridProps & { +export interface HeaderProps extends SharedGridProps { allRowsSelected: boolean; -}; +} export interface HeaderHandle { setScrollLeft(scrollLeft: number): void; From b92761a61af9e6f11ab6dc586d7f4526eea303cc Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Thu, 3 Oct 2019 15:41:37 -0500 Subject: [PATCH 29/34] Commit reordering fixes (not working) --- examples/scripts/example23-row-reordering.js | 27 +++++++++----- .../src/draggable/DragDropContainer.js | 2 +- .../src/draggable/DropTargetRowContainer.js | 2 +- .../src/draggable/RowActionsCell.js | 37 +++++-------------- .../src/draggable/RowDragLayer.js | 22 ++--------- 5 files changed, 33 insertions(+), 57 deletions(-) diff --git a/examples/scripts/example23-row-reordering.js b/examples/scripts/example23-row-reordering.js index 30744773a7..fa01e0c723 100644 --- a/examples/scripts/example23-row-reordering.js +++ b/examples/scripts/example23-row-reordering.js @@ -5,7 +5,7 @@ import { Draggable, Data } from 'react-data-grid-addons'; import exampleWrapper from '../components/exampleWrapper'; -const { Container: DraggableContainer, DropTargetRowContainer } = Draggable; +const { Container: DraggableContainer, RowActionsCell, DropTargetRowContainer } = Draggable; const { Selectors } = Data; const RowRenderer = DropTargetRowContainer(Row); @@ -19,7 +19,16 @@ class Example extends React.Component { constructor(props, context) { super(props, context); this._columns = [ - SelectColumn, + { + ...SelectColumn, + formatter(props) { + return ( + + {SelectColumn.formatter(props)} + + ); + } + }, { key: 'id', name: 'ID' @@ -68,19 +77,19 @@ class Example extends React.Component { return this.state.rows[i]; }; - isDraggedRowSelected = (selectedRows, rowDragSource) => { - if (selectedRows && selectedRows.length > 0) { + isDraggedRowSelected = (rowDragSource) => { + if (this.state.selectedRows && this.state.selectedRows.size > 0) { const key = this.props.rowKey; - return selectedRows.filter(r => r[key] === rowDragSource.data[key]).length > 0; + return this.state.selectedRows.has(rowDragSource.data[key]); } return false; }; reorderRows = (e) => { - const selectedRows = Selectors.getSelectedRowsByKey({ rowKey: this.props.rowKey, selectedKeys: this.state.selectedIds, rows: this.state.rows }); - const draggedRows = this.isDraggedRowSelected(selectedRows, e.rowSource) ? selectedRows : [e.rowSource.data]; - const undraggedRows = this.state.rows.filter(function(r) { - return draggedRows.indexOf(r) === -1; + // TODO: fix reordering logic + const draggedRows = this.isDraggedRowSelected(e.rowSource) ? [...this.state.selectedRows] : [e.rowSource.data]; + const undraggedRows = this.state.rows.filter((r) => { + return draggedRows.includes(r[this.props.rowKey]); }); const args = [e.rowTarget.idx, 0].concat(draggedRows); Array.prototype.splice.apply(undraggedRows, args); diff --git a/packages/react-data-grid-addons/src/draggable/DragDropContainer.js b/packages/react-data-grid-addons/src/draggable/DragDropContainer.js index 4818d176f9..f6212f028f 100644 --- a/packages/react-data-grid-addons/src/draggable/DragDropContainer.js +++ b/packages/react-data-grid-addons/src/draggable/DragDropContainer.js @@ -39,7 +39,7 @@ class DraggableContainer extends Component {
{grid} diff --git a/packages/react-data-grid-addons/src/draggable/DropTargetRowContainer.js b/packages/react-data-grid-addons/src/draggable/DropTargetRowContainer.js index f8e2d0d182..414e24f92a 100644 --- a/packages/react-data-grid-addons/src/draggable/DropTargetRowContainer.js +++ b/packages/react-data-grid-addons/src/draggable/DropTargetRowContainer.js @@ -37,7 +37,7 @@ const target = { // Obtain the dragged item component.moveRow(); const rowSource = monitor.getItem(); - const rowTarget = { idx: props.idx, data: props.row }; + const rowTarget = { idx: props.idx, data: props.row, isRowSelected: props.isRowSelected }; props.onRowDrop({ rowSource, rowTarget }); } }; diff --git a/packages/react-data-grid-addons/src/draggable/RowActionsCell.js b/packages/react-data-grid-addons/src/draggable/RowActionsCell.js index be4868f570..12d13ea29f 100644 --- a/packages/react-data-grid-addons/src/draggable/RowActionsCell.js +++ b/packages/react-data-grid-addons/src/draggable/RowActionsCell.js @@ -1,7 +1,6 @@ import React from 'react'; import PropTypes from 'prop-types'; import { DragSource } from 'react-dnd'; -import { CheckboxEditor } from 'react-data-grid'; class RowActionsCell extends React.Component { static propTypes = { @@ -11,44 +10,26 @@ class RowActionsCell extends React.Component { isDragging: PropTypes.bool.isRequired, isRowHovered: PropTypes.bool, column: PropTypes.object, - dependentValues: PropTypes.object, - value: PropTypes.bool, - rowSelection: PropTypes.object.isRequired + dependentValues: PropTypes.object }; static defaultProps = { rowIdx: 0 }; - renderRowIndex() { - return ( -
- { this.props.rowIdx + 1 } -
- ); - } - render() { - const { connectDragSource, rowSelection } = this.props; - const rowHandleStyle = rowSelection != null ? { position: 'absolute', marginTop: '5px' } : {}; - const isSelected = this.props.value; - const editorClass = isSelected ? 'rdg-actions-checkbox selected' : 'rdg-actions-checkbox'; + const { connectDragSource } = this.props; + const rowHandleStyle = { position: 'absolute', marginTop: '5px' }; + const editorClass = this.props.isRowSelected ? 'rdg-actions-checkbox selected' : 'rdg-actions-checkbox'; return connectDragSource(
- {!isSelected ? this.renderRowIndex() : null} - {rowSelection != null && ( -
- -
- )} -
); +
+ {this.props.children} +
+
+ ); } } diff --git a/packages/react-data-grid-addons/src/draggable/RowDragLayer.js b/packages/react-data-grid-addons/src/draggable/RowDragLayer.js index 4daff42c4b..16e4b4706c 100644 --- a/packages/react-data-grid-addons/src/draggable/RowDragLayer.js +++ b/packages/react-data-grid-addons/src/draggable/RowDragLayer.js @@ -2,8 +2,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { DragLayer } from 'react-dnd'; -import * as Selectors from '../data/Selectors'; - const layerStyles = { cursor: '-webkit-grabbing', position: 'fixed', @@ -40,28 +38,16 @@ class CustomDragLayer extends Component { y: PropTypes.number.isRequired }), isDragging: PropTypes.bool.isRequired, - rowSelection: PropTypes.object, + selectedRows: PropTypes.object, rows: PropTypes.array.isRequired, columns: PropTypes.array.isRequired }; - isDraggedRowSelected(selectedRows) { - const { item, rowSelection } = this.props; - if (selectedRows && selectedRows.length > 0) { - const key = rowSelection.selectBy.keys.rowKey; - return selectedRows.filter(r => r[key] === item.data[key]).length > 0; - } - return false; - } - getDraggedRows() { let draggedRows; - const { rowSelection } = this.props; - if (rowSelection && rowSelection.selectBy.keys) { - const { rows } = this.props; - const { rowKey, values } = rowSelection.selectBy.keys; - const selectedRows = Selectors.getSelectedRowsByKey({ rowKey, selectedKeys: values, rows }); - draggedRows = this.isDraggedRowSelected(selectedRows) ? selectedRows : [this.props.rows[this.props.item.idx]]; + const { selectedRows } = this.props; + if (selectedRows && selectedRows.size > 0) { + draggedRows = [...selectedRows]; } else { draggedRows = [this.props.rows[this.props.item.idx]]; } From 3519c4345a24b87baad4eb670aa157966e212592 Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Fri, 4 Oct 2019 12:40:20 -0500 Subject: [PATCH 30/34] Remove row-reordering components --- examples/scripts/example23-row-reordering.js | 125 ------------------ .../src/draggable/DropTargetRowContainer.js | 54 -------- .../src/draggable/RowActionsCell.js | 53 -------- .../src/draggable/index.ts | 2 - 4 files changed, 234 deletions(-) delete mode 100644 examples/scripts/example23-row-reordering.js delete mode 100644 packages/react-data-grid-addons/src/draggable/DropTargetRowContainer.js delete mode 100644 packages/react-data-grid-addons/src/draggable/RowActionsCell.js diff --git a/examples/scripts/example23-row-reordering.js b/examples/scripts/example23-row-reordering.js deleted file mode 100644 index fa01e0c723..0000000000 --- a/examples/scripts/example23-row-reordering.js +++ /dev/null @@ -1,125 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import ReactDataGrid, { Row, SelectColumn } from 'react-data-grid'; -import { Draggable, Data } from 'react-data-grid-addons'; - -import exampleWrapper from '../components/exampleWrapper'; - -const { Container: DraggableContainer, RowActionsCell, DropTargetRowContainer } = Draggable; -const { Selectors } = Data; -const RowRenderer = DropTargetRowContainer(Row); - -class Example extends React.Component { - static propTypes = { - rowKey: PropTypes.string.isRequired - }; - - static defaultProps = { rowKey: 'id' }; - - constructor(props, context) { - super(props, context); - this._columns = [ - { - ...SelectColumn, - formatter(props) { - return ( - - {SelectColumn.formatter(props)} - - ); - } - }, - { - key: 'id', - name: 'ID' - }, - { - key: 'task', - name: 'Title' - }, - { - key: 'priority', - name: 'Priority' - }, - { - key: 'issueType', - name: 'Issue Type' - } - ]; - - this.state = { - rows: this.createRows(1000), - selectedRows: new Set([1, 2]) - }; - } - - getRandomDate = (start, end) => { - return new Date(start.getTime() + Math.random() * (end.getTime() - start.getTime())).toLocaleDateString(); - }; - - createRows = (numberOfRows) => { - const rows = []; - for (let i = 1; i < numberOfRows; i++) { - rows.push({ - id: i, - task: `Task ${i}`, - complete: Math.min(100, Math.round(Math.random() * 110)), - priority: ['Critical', 'High', 'Medium', 'Low'][Math.floor((Math.random() * 3) + 1)], - issueType: ['Bug', 'Improvement', 'Epic', 'Story'][Math.floor((Math.random() * 3) + 1)], - startDate: this.getRandomDate(new Date(2015, 3, 1), new Date()), - completeDate: this.getRandomDate(new Date(), new Date(2016, 0, 1)) - }); - } - return rows; - }; - - rowGetter = (i) => { - return this.state.rows[i]; - }; - - isDraggedRowSelected = (rowDragSource) => { - if (this.state.selectedRows && this.state.selectedRows.size > 0) { - const key = this.props.rowKey; - return this.state.selectedRows.has(rowDragSource.data[key]); - } - return false; - }; - - reorderRows = (e) => { - // TODO: fix reordering logic - const draggedRows = this.isDraggedRowSelected(e.rowSource) ? [...this.state.selectedRows] : [e.rowSource.data]; - const undraggedRows = this.state.rows.filter((r) => { - return draggedRows.includes(r[this.props.rowKey]); - }); - const args = [e.rowTarget.idx, 0].concat(draggedRows); - Array.prototype.splice.apply(undraggedRows, args); - this.setState({ rows: undraggedRows }); - }; - - onSelectedRowsChange = (selectedRows) => { - this.setState({ selectedRows }); - }; - - render() { - return ( - - } - selectedRows={this.state.selectedRows} - onSelectedRowsChange={this.onSelectedRowsChange} - /> - - ); - } -} - -export default exampleWrapper({ - WrappedComponent: Example, - exampleName: 'Row Reordering', - exampleDescription: 'This examples demonstrates how single or multiple rows can be dragged to a different positions using components from Draggable React Addons', - examplePath: './scripts/example23-row-reordering.js' -}); diff --git a/packages/react-data-grid-addons/src/draggable/DropTargetRowContainer.js b/packages/react-data-grid-addons/src/draggable/DropTargetRowContainer.js deleted file mode 100644 index 414e24f92a..0000000000 --- a/packages/react-data-grid-addons/src/draggable/DropTargetRowContainer.js +++ /dev/null @@ -1,54 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { DropTarget } from 'react-dnd'; -import { rowComparer } from 'react-data-grid'; - -const rowDropTarget = (Row) => class extends React.Component { - shouldComponentUpdate(nextProps) { - return rowComparer(nextProps, this.props); - } - - moveRow() { - ReactDOM.findDOMNode(this).classList.add('slideUp'); - } - - render() { - const { connectDropTarget, isOver, canDrop } = this.props; - const overlayTop = this.props.idx * this.props.height; - return connectDropTarget( -
- this.row = node} {...this.props} /> - {isOver && canDrop && ( -
- )} -
- ); - } -}; - -const target = { - drop(props, monitor, component) { - // Obtain the dragged item - component.moveRow(); - const rowSource = monitor.getItem(); - const rowTarget = { idx: props.idx, data: props.row, isRowSelected: props.isRowSelected }; - props.onRowDrop({ rowSource, rowTarget }); - } -}; - -function collect(connect, monitor) { - return { - connectDropTarget: connect.dropTarget(), - isOver: monitor.isOver(), - canDrop: monitor.canDrop(), - draggedRow: monitor.getItem() - }; -} - -export default (Row) => DropTarget('Row', target, collect, { arePropsEqual: (nextProps, currentProps) => !rowComparer(nextProps, currentProps) })(rowDropTarget(Row)); diff --git a/packages/react-data-grid-addons/src/draggable/RowActionsCell.js b/packages/react-data-grid-addons/src/draggable/RowActionsCell.js deleted file mode 100644 index 12d13ea29f..0000000000 --- a/packages/react-data-grid-addons/src/draggable/RowActionsCell.js +++ /dev/null @@ -1,53 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; -import { DragSource } from 'react-dnd'; - -class RowActionsCell extends React.Component { - static propTypes = { - rowIdx: PropTypes.number.isRequired, - connectDragSource: PropTypes.func.isRequired, - connectDragPreview: PropTypes.func.isRequired, - isDragging: PropTypes.bool.isRequired, - isRowHovered: PropTypes.bool, - column: PropTypes.object, - dependentValues: PropTypes.object - }; - - static defaultProps = { - rowIdx: 0 - }; - - render() { - const { connectDragSource } = this.props; - const rowHandleStyle = { position: 'absolute', marginTop: '5px' }; - const editorClass = this.props.isRowSelected ? 'rdg-actions-checkbox selected' : 'rdg-actions-checkbox'; - - return connectDragSource( -
-
-
- {this.props.children} -
-
- ); - } -} - -function collect(connect, monitor) { - return { - connectDragSource: connect.dragSource(), - isDragging: monitor.isDragging(), - connectDragPreview: connect.dragPreview() - }; -} - -const rowIndexSource = { - beginDrag(props) { - return { idx: props.rowIdx, data: props.dependentValues }; - }, - endDrag(props) { - return { idx: props.rowIdx, data: props.dependentValues }; - } -}; - -export default DragSource('Row', rowIndexSource, collect)(RowActionsCell); diff --git a/packages/react-data-grid-addons/src/draggable/index.ts b/packages/react-data-grid-addons/src/draggable/index.ts index a35d91116c..52ad22ad43 100644 --- a/packages/react-data-grid-addons/src/draggable/index.ts +++ b/packages/react-data-grid-addons/src/draggable/index.ts @@ -1,4 +1,2 @@ export { default as Container } from './DragDropContainer'; export { default as DraggableHeaderCell } from './DraggableHeaderCell'; -export { default as RowActionsCell } from './RowActionsCell'; -export { default as DropTargetRowContainer } from './DropTargetRowContainer'; From 5ce39f9dffe83be3c8aca2386ceab7966e91211e Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Fri, 4 Oct 2019 12:41:51 -0500 Subject: [PATCH 31/34] Fix eslint errors --- .../react-data-grid-addons/src/__tests__/Grid.spec.js | 9 --------- packages/react-data-grid/src/Columns.tsx | 1 + 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/react-data-grid-addons/src/__tests__/Grid.spec.js b/packages/react-data-grid-addons/src/__tests__/Grid.spec.js index a93ffae803..8d35e7f61c 100644 --- a/packages/react-data-grid-addons/src/__tests__/Grid.spec.js +++ b/packages/react-data-grid-addons/src/__tests__/Grid.spec.js @@ -1,7 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { mount } from 'enzyme'; -import TestUtils from 'react-dom/test-utils'; import Grid from 'react-data-grid'; @@ -47,14 +46,6 @@ describe('Grid', () => { return wrapper.find('Grid'); }; - const buildFakeEvent = (addedData) => { - return { - preventDefault() {}, - stopPropagation() {}, - ...addedData - }; - }; - it('should create a new instance of Grid', () => { const { wrapper } = setup(); expect(wrapper.instance()).toBeDefined(); diff --git a/packages/react-data-grid/src/Columns.tsx b/packages/react-data-grid/src/Columns.tsx index c33caa0887..c52090cd2a 100644 --- a/packages/react-data-grid/src/Columns.tsx +++ b/packages/react-data-grid/src/Columns.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import React from 'react'; import SelectCellFormatter from './formatters/SelectCellFormatter'; import { From ce14794fc08a95d519d45e33f55864fbd9f4592f Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Fri, 4 Oct 2019 12:43:59 -0500 Subject: [PATCH 32/34] Remove re-ordering refrences --- examples/components/ExampleList.js | 1 - examples/components/Examples.js | 2 -- 2 files changed, 3 deletions(-) diff --git a/examples/components/ExampleList.js b/examples/components/ExampleList.js index 839abb9ba8..0d00165390 100644 --- a/examples/components/ExampleList.js +++ b/examples/components/ExampleList.js @@ -29,7 +29,6 @@ export default class ExampleList extends React.Component {
  • Grouping Example
  • Custom Filters Example
  • Immutable Data Grouping Example
  • -
  • Row Reordering Example
  • Draggable Header Example
  • Tree View Example
  • Tree View No Add Delete Example
  • diff --git a/examples/components/Examples.js b/examples/components/Examples.js index b041c8b8cf..bba6ace05c 100644 --- a/examples/components/Examples.js +++ b/examples/components/Examples.js @@ -28,7 +28,6 @@ import CellSelectionEvents from '../scripts/example21-cell-selection-events'; import Grouping from '../scripts/example21-grouping'; import CustomFilters from '../scripts/example22-custom-filters'; import ImmutableDataGrouping from '../scripts/example23-immutable-data-grouping'; -import RowOrdering from '../scripts/example23-row-reordering'; import DraggableHeader from '../scripts/example24-draggable-header'; import TreeView from '../scripts/example25-tree-view'; import TreeViewNoAddDelete from '../scripts/example26-tree-view-no-add-delete'; @@ -78,7 +77,6 @@ export default function Examples({ match }) { - From 2e1a989bd83d83313cb9f9f3f4a5765ac58aef15 Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Fri, 4 Oct 2019 13:02:40 -0500 Subject: [PATCH 33/34] Remove tests for the deleted file --- .../__tests__/DropTargetRowContainer.spec.js | 69 ------------------- 1 file changed, 69 deletions(-) delete mode 100644 packages/react-data-grid-addons/src/draggable/__tests__/DropTargetRowContainer.spec.js diff --git a/packages/react-data-grid-addons/src/draggable/__tests__/DropTargetRowContainer.spec.js b/packages/react-data-grid-addons/src/draggable/__tests__/DropTargetRowContainer.spec.js deleted file mode 100644 index f99755fd4d..0000000000 --- a/packages/react-data-grid-addons/src/draggable/__tests__/DropTargetRowContainer.spec.js +++ /dev/null @@ -1,69 +0,0 @@ -import React, { Component } from 'react'; -import { mount } from 'enzyme'; -import TestBackend from 'react-dnd-test-backend'; -import { DragDropContext } from 'react-dnd'; - -import dropTargetRowContainer from '../DropTargetRowContainer'; -import { DragTestSource } from './TestDragSources'; -import { _helpers } from 'react-data-grid'; -const { test: { GridPropHelpers } } = _helpers; - -class fakeRow extends Component { - render() { - return fake row; - } -} - -/** - * Wraps a component into a DragDropContext that uses the TestBackend. - */ -function wrapInTestContext(DecoratedComponent) { - return DragDropContext(TestBackend)(class extends React.Component { - render() { - return ; - } - }); -} - -describe('', () => { - let ComponentUnderTest; - let wrapper; - let backend; - let registry; - let manager; - const props = { - onRowDrop: jest.fn(), - idx: 1, - row: { id: 5, country: 'England' }, - columns: GridPropHelpers.columns, - cellMetaData: GridPropHelpers.cellMetaData - }; - - beforeEach(() => { - ComponentUnderTest = wrapInTestContext(dropTargetRowContainer(fakeRow)); - wrapper = mount(); - manager = wrapper.instance().getManager(); - backend = manager.getBackend(); - registry = manager.getRegistry(); - }); - - it('renders the injected row', () => { - expect(wrapper.find(fakeRow).length).toEqual(1); - }); - - it('should call onRowDrop with correct parameters when source is dropped', () => { - const rowTargetKey = Object.keys(registry.handlers).filter(k => registry.handlers[k].monitor && registry.handlers[k].monitor.targetId)[0]; - const rowTargetId = registry.handlers[rowTargetKey].monitor.targetId; - const draggedRowItem = { idx: 3, data: { id: 11, country: 'Ireland', county: 'Wicklow' } }; - const sourceId = registry.addSource('Row', new DragTestSource(draggedRowItem)); - backend.simulateBeginDrag([sourceId]); - backend.simulateHover([rowTargetId]); - backend.simulateDrop(); - expect(props.onRowDrop).toHaveBeenCalled(); - expect(props.onRowDrop.mock.calls.length).toEqual(1); - const { rowSource, rowTarget } = props.onRowDrop.mock.calls[0][0]; - expect(rowSource).toEqual(draggedRowItem); - expect(rowTarget.idx).toEqual(1); - expect(rowTarget.data).toEqual(props.row); - }); -}); From 390434bc10b462e0252bebdba88d8de522b6b7d5 Mon Sep 17 00:00:00 2001 From: Aman Mahajan Date: Fri, 4 Oct 2019 13:28:07 -0500 Subject: [PATCH 34/34] Fix types --- packages/react-data-grid/src/common/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-data-grid/src/common/types.ts b/packages/react-data-grid/src/common/types.ts index 38299dced9..69242bca32 100644 --- a/packages/react-data-grid/src/common/types.ts +++ b/packages/react-data-grid/src/common/types.ts @@ -38,7 +38,7 @@ interface ColumnValue>; /** Header renderer for each header cell */ // TODO: finalize API - headerRenderer?: React.ReactElement | React.ComponentType> | (() => React.ReactElement); + headerRenderer?: React.ReactElement | React.ComponentType>; /** Component to be used to filter the data of the column */ filterRenderer?: React.ComponentType>;