Skip to content

Commit

Permalink
Add onSelectedCellChange event (#3328)
Browse files Browse the repository at this point in the history
* feat: add `onCellSelected` event

* test: add `onCellSelected` event

* doc: add `onCellSelected` event

* refactor: define `row` & `column` with minimum scope

Co-Authored-By: Aman Mahajan <[email protected]>

Co-Authored-By: Aman Mahajan <[email protected]>

* test: fix wrong MouseKey

Co-authored-by: Aman Mahajan <[email protected]>

* test: combine the tests for `onCellSelected` to one

Co-Authored-By: Aman Mahajan <[email protected]>

* refactor: rename from `onCellSelected` to `onSelectedCellChange`

Co-Authored-By: Aman Mahajan <[email protected]>

* doc: simplify document

Co-Authored-By: Aman Mahajan <[email protected]>

* doc: improve English expressions

Co-Authored-By: Aman Mahajan <[email protected]>

* refactor: avoid unnecessary assignment to variable

* feat: remove `idx` argument from `onSelectedCellChange`

You can easily get `idx` from `column`. (column.idx)

Co-Authored-By: Aman Mahajan <[email protected]>

* test: remove `idx` argument from `onSelectedCellChange`

* test: use spy to test called time of `onSelectedCellChange`

Co-Authored-By: Aman Mahajan <[email protected]>

* doc: remove no longer supported argument `args.idx`

Co-authored-by: Aman Mahajan <[email protected]>

* test: avoid using function for `onSelectedCellChange` test

Co-authored-by: Aman Mahajan <[email protected]>

* Update test/events.test.tsx

---------

Co-authored-by: Aman Mahajan <[email protected]>
Co-authored-by: Aman Mahajan <[email protected]>
  • Loading branch information
3 people authored Sep 13, 2023
1 parent 72db386 commit b44343a
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 4 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,16 @@ A number defining the height of summary rows.

###### `onCellKeyDown?: Maybe<(args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) => void>`

###### `onSelectedCellChange?: Maybe<(args: CellSelectArgs<R, SR>) => void>;`

Triggered when the selected cell is changed.

Arguments:

- `args.rowIdx`: `number` - row index
- `args.row`: `R` - row object of the currently selected cell
- `args.column`: `CalculatedColumn<TRow, TSummaryRow>` - column object of the currently selected cell

###### `onScroll?: Maybe<(event: React.UIEvent<HTMLDivElement>) => void>`

###### `onColumnResize?: Maybe<(idx: number, width: number) => void>`
Expand Down
18 changes: 16 additions & 2 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import type {
CellKeyDownArgs,
CellMouseEvent,
CellNavigationMode,
CellSelectArgs,
Column,
ColumnOrColumnGroup,
CopyEvent,
Expand Down Expand Up @@ -166,6 +167,8 @@ export interface DataGridProps<R, SR = unknown, K extends Key = Key> extends Sha
/** Function called whenever a cell is right clicked */
onCellContextMenu?: Maybe<(args: CellClickArgs<R, SR>, event: CellMouseEvent) => void>;
onCellKeyDown?: Maybe<(args: CellKeyDownArgs<R, SR>, event: CellKeyboardEvent) => void>;
/** Function called whenever cell selection is changed */
onSelectedCellChange?: Maybe<(args: CellSelectArgs<R, SR>) => void>;
/** Called when the grid is scrolled */
onScroll?: Maybe<(event: React.UIEvent<HTMLDivElement>) => void>;
/** Called when a column is resized */
Expand Down Expand Up @@ -221,6 +224,7 @@ function DataGrid<R, SR, K extends Key>(
onCellDoubleClick,
onCellContextMenu,
onCellKeyDown,
onSelectedCellChange,
onScroll,
onColumnResize,
onFill,
Expand Down Expand Up @@ -688,16 +692,26 @@ function DataGrid<R, SR, K extends Key>(
if (!isCellWithinSelectionBounds(position)) return;
commitEditorChanges();

const row = rows[position.rowIdx];
const samePosition = isSamePosition(selectedPosition, position);

if (enableEditor && isCellEditable(position)) {
const row = rows[position.rowIdx];
setSelectedPosition({ ...position, mode: 'EDIT', row, originalRow: row });
} else if (isSamePosition(selectedPosition, position)) {
} else if (samePosition) {
// Avoid re-renders if the selected cell state is the same
scrollIntoView(getCellToScroll(gridRef.current!));
} else {
shouldFocusCellRef.current = true;
setSelectedPosition({ ...position, mode: 'SELECT' });
}

if (onSelectedCellChange && !samePosition) {
onSelectedCellChange({
rowIdx: position.rowIdx,
row,
column: columns[position.idx]
});
}
}

function getNextPosition(key: string, ctrlKey: boolean, shiftKey: boolean): Position {
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,6 @@ export type {
CellMouseEvent,
CellClickArgs,
CellKeyDownArgs,
CellKeyboardEvent
CellKeyboardEvent,
CellSelectArgs
} from './types';
6 changes: 6 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ export type CellKeyDownArgs<TRow, TSummaryRow = unknown> =
| SelectCellKeyDownArgs<TRow, TSummaryRow>
| EditCellKeyDownArgs<TRow, TSummaryRow>;

export interface CellSelectArgs<TRow, TSummaryRow = unknown> {
rowIdx: number;
row: TRow;
column: CalculatedColumn<TRow, TSummaryRow>;
}

export interface BaseRenderRowProps<TRow, TSummaryRow = unknown>
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'style' | 'children'>,
Pick<
Expand Down
55 changes: 54 additions & 1 deletion test/events.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,64 @@ describe('Events', () => {
await userEvent.pointer({ target: getCellsAtRowIndex(0)[1], keys: '[MouseRight]' });
expect(getCellsAtRowIndex(0)[1]).toHaveAttribute('aria-selected', 'true');
});

it('should call onSelectedCellChange when cell selection is changed', async () => {
const onSelectedCellChange = vi.fn();

render(<EventTest onSelectedCellChange={onSelectedCellChange} />);

expect(onSelectedCellChange).not.toHaveBeenCalled();

// Selected by click
await userEvent.click(getCellsAtRowIndex(0)[1]);
expect(onSelectedCellChange).toHaveBeenCalledWith({
column: expect.objectContaining(columns[1]),
row: rows[0],
rowIdx: 0
});
expect(onSelectedCellChange).toHaveBeenCalledTimes(1);

// Selected by double click
await userEvent.dblClick(getCellsAtRowIndex(0)[0]);
expect(onSelectedCellChange).toHaveBeenCalledWith({
column: expect.objectContaining(columns[0]),
row: rows[0],
rowIdx: 0
});
expect(onSelectedCellChange).toHaveBeenCalledTimes(2);

// Selected by right-click
await userEvent.pointer({ target: getCellsAtRowIndex(1)[0], keys: '[MouseRight]' });
expect(onSelectedCellChange).toHaveBeenCalledWith({
column: expect.objectContaining(columns[0]),
row: rows[1],
rowIdx: 1
});
expect(onSelectedCellChange).toHaveBeenCalledTimes(3);

// Selected by ←↑→↓ keys
await userEvent.keyboard('{ArrowUp}');
expect(onSelectedCellChange).toHaveBeenCalledWith({
column: expect.objectContaining(columns[0]),
row: rows[0],
rowIdx: 0
});
expect(onSelectedCellChange).toHaveBeenCalledTimes(4);

// Selected by tab key
await userEvent.keyboard('{Tab}');
expect(onSelectedCellChange).toHaveBeenCalledWith({
column: expect.objectContaining(columns[1]),
row: rows[0],
rowIdx: 0
});
expect(onSelectedCellChange).toHaveBeenCalledTimes(5);
});
});

type EventProps = Pick<
DataGridProps<Row>,
'onCellClick' | 'onCellDoubleClick' | 'onCellContextMenu'
'onCellClick' | 'onCellDoubleClick' | 'onCellContextMenu' | 'onSelectedCellChange'
>;

function EventTest(props: EventProps) {
Expand Down

0 comments on commit b44343a

Please sign in to comment.