Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
aa82e54
Add column.colSpan prop
Apr 13, 2021
8e3c000
Change colSpan signature
Apr 13, 2021
ec27a71
Handle keyboard navigation
Apr 14, 2021
5895ccd
Add comments
Apr 14, 2021
ac6fe76
Update example
Apr 14, 2021
12a68f8
Handle frozen columns
Apr 14, 2021
3b6bd13
Handle header and summary rows
Apr 14, 2021
9dd16f1
Update example
Apr 14, 2021
7eed169
Update viewport columns to handle colspan
Apr 16, 2021
c08734f
Add ColumnSpanning example
Apr 20, 2021
6535db7
Cleanup cell selection logic
Apr 20, 2021
ace6346
Update src/utils/index.ts
amanmahajan7 Apr 20, 2021
8c5dc3e
Update src/utils/index.ts
amanmahajan7 Apr 20, 2021
0e69e0c
Remove unused import
Apr 20, 2021
535b6a0
Check integer and non negative values
Apr 20, 2021
f918583
Move to cell selection logic to DataGrid
Apr 20, 2021
54e4f53
Update src/utils/index.ts
amanmahajan7 Apr 20, 2021
13d28f1
Tweak colors
Apr 20, 2021
30fe74d
Fix eslint warning
Apr 20, 2021
96416e2
Split into two useMemos, fix startIdx
Apr 20, 2021
9b8b5bd
Check header and summary rows
Apr 20, 2021
4a1461c
Fix next position logic
Apr 20, 2021
24a4ba9
Make sure cell is within bounds
Apr 20, 2021
aa7cd4a
Loop through columns once
Apr 20, 2021
fc6ed3d
Do not close flighting editor on enter/escape
Apr 20, 2021
f5b337e
Revert "Do not close flighting editor on enter/escape"
Apr 20, 2021
6b705a1
Merge branch 'canary' into am-col-span
amanmahajan7 Apr 20, 2021
8f9b78c
Add cellSpan tests
Apr 20, 2021
0f74223
Remove colSpan number type
Apr 21, 2021
b8e1216
Optimize colSpan check
Apr 21, 2021
890ca22
Test navigation
Apr 21, 2021
1170703
Fix types
Apr 21, 2021
6800dac
Check filter row
Apr 21, 2021
d069d11
Fix types
Apr 21, 2021
cbc3143
Update src/hooks/useCalculatedColumns.ts
amanmahajan7 Apr 21, 2021
7b1941b
Update src/hooks/useViewportColumns.ts
amanmahajan7 Apr 21, 2021
0ee74d9
Update src/hooks/useViewportColumns.ts
amanmahajan7 Apr 21, 2021
232af07
Update src/types.ts
amanmahajan7 Apr 21, 2021
ade49d2
Update src/hooks/useViewportColumns.ts
amanmahajan7 Apr 21, 2021
39fb41c
Update src/hooks/useViewportColumns.ts
amanmahajan7 Apr 21, 2021
f3f3312
Update src/hooks/useViewportColumns.ts
amanmahajan7 Apr 21, 2021
35bcd3e
Quit loop when first startIdx is found
Apr 21, 2021
65dbfca
Re-export ColSpanArgs
Apr 21, 2021
88a8b7a
Use lastFrozenColumnIndex to validate colSpan
Apr 21, 2021
6513d21
Update src/hooks/useViewportColumns.ts
amanmahajan7 Apr 21, 2021
832d268
Update src/utils/index.ts
amanmahajan7 Apr 21, 2021
6780ecf
Update test/column/colSpan.test.ts
amanmahajan7 Apr 21, 2021
4dc2f85
Update test/column/colSpan.test.ts
amanmahajan7 Apr 21, 2021
af36ec3
Add getCellsAtRowIndex util
Apr 21, 2021
7cf7009
Move nextPosition calculation logic to getNextSelectedCellPosition
Apr 21, 2021
b69af47
column.colSpan can't be a number
Apr 21, 2021
860a25b
Eslint
Apr 21, 2021
ea5e00e
Typecheck
Apr 21, 2021
5422f44
Reuse colIdx, add posIdx
Apr 21, 2021
2a49cf5
Move posIdx outside
Apr 21, 2021
c1922ec
Add failing tests
Apr 21, 2021
c5d8421
Fix cell navigation
Apr 21, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const cellDragHandleClassname = `rdg-cell-drag-handle ${cellDragHandle}`;
function Cell<R, SR>({
className,
column,
colSpan,
isCellSelected,
isCopied,
isDraggedOver,
Expand Down Expand Up @@ -105,9 +106,10 @@ function Cell<R, SR>({
role="gridcell"
aria-colindex={column.idx + 1} // aria-colindex is 1-based
aria-selected={isCellSelected}
aria-colspan={colSpan}
ref={ref}
className={className}
style={getCellStyle(column)}
style={getCellStyle(column, colSpan)}
onClick={handleClick}
onDoubleClick={handleDoubleClick}
onContextMenu={handleContextMenu}
Expand Down
44 changes: 38 additions & 6 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type { RefAttributes } from 'react';
import clsx from 'clsx';

import { rootClassname, viewportDraggingClassname, focusSinkClassname } from './style';
import { useGridDimensions, useViewportColumns, useViewportRows, useLatestFunc } from './hooks';
import { useGridDimensions, useCalculatedColumns, useViewportColumns, useViewportRows, useLatestFunc } from './hooks';
import HeaderRow from './HeaderRow';
import FilterRow from './FilterRow';
import Row from './Row';
Expand Down Expand Up @@ -258,7 +258,18 @@ function DataGrid<R, SR>({
const clientHeight = gridHeight - totalHeaderHeight - summaryRowsCount * summaryRowHeight;
const isSelectable = selectedRows !== undefined && onSelectedRowsChange !== undefined;

const { columns, viewportColumns, layoutCssVars, columnMetrics, totalColumnWidth, lastFrozenColumnIndex, totalFrozenColumnWidth, groupBy } = useViewportColumns({
const {
columns,
colSpanColumns,
colOverscanStartIdx,
colOverscanEndIdx,
layoutCssVars,
columnMetrics,
totalColumnWidth,
lastFrozenColumnIndex,
totalFrozenColumnWidth,
groupBy
} = useCalculatedColumns({
rawColumns,
columnWidths,
scrollLeft,
Expand All @@ -279,6 +290,20 @@ function DataGrid<R, SR>({
enableVirtualization
});

const viewportColumns = useViewportColumns({
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to split into two hooks as we need to calculate colspan for all the rows in the viewport. This is needed to ensure a column that spans a column in the viewport is also visible

columns,
colSpanColumns,
colOverscanStartIdx,
colOverscanEndIdx,
lastFrozenColumnIndex,
rowOverscanStartIdx,
rowOverscanEndIdx,
rows,
summaryRows,
enableFilterRow,
isGroupRow
});

const hasGroups = groupBy.length > 0 && typeof rowGrouper === 'function';
const minColIdx = hasGroups ? -1 : 0;

Expand Down Expand Up @@ -778,12 +803,16 @@ function DataGrid<R, SR>({
event.preventDefault();

const ctrlKey = isCtrlKeyHeldDown(event);
let nextPosition = getNextPosition(key, ctrlKey, shiftKey);
nextPosition = getNextSelectedCellPosition({
const nextPosition = getNextSelectedCellPosition({
columns,
rowsCount: rows.length,
colSpanColumns,
rows,
lastFrozenColumnIndex,
cellNavigationMode: mode,
nextPosition
currentPosition: selectedPosition,
nextPosition: getNextPosition(key, ctrlKey, shiftKey),
isCellWithinBounds,
isGroupRow
});

selectCell(nextPosition);
Expand Down Expand Up @@ -887,6 +916,7 @@ function DataGrid<R, SR>({
copiedCellIdx={copiedCell !== null && copiedCell.row === row ? columns.findIndex(c => c.key === copiedCell.columnKey) : undefined}
draggedOverCellIdx={getDraggedOverCellIdx(rowIdx)}
setDraggedOverRowIdx={isDragging ? setDraggedOverRowIdx : undefined}
lastFrozenColumnIndex={lastFrozenColumnIndex}
selectedCellProps={getSelectedCellProps(rowIdx)}
onRowChange={handleFormatterRowChangeWrapper}
selectCell={selectCellWrapper}
Expand Down Expand Up @@ -941,6 +971,7 @@ function DataGrid<R, SR>({
sortColumn={sortColumn}
sortDirection={sortDirection}
onSort={onSort}
lastFrozenColumnIndex={lastFrozenColumnIndex}
/>
{enableFilterRow && (
<FilterRow<R, SR>
Expand Down Expand Up @@ -968,6 +999,7 @@ function DataGrid<R, SR>({
row={row}
bottom={summaryRowHeight * (summaryRows.length - 1 - rowIdx)}
viewportColumns={viewportColumns}
lastFrozenColumnIndex={lastFrozenColumnIndex}
/>
))}
</>
Expand Down
4 changes: 3 additions & 1 deletion src/EditCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ type SharedCellRendererProps<R, SR> = Pick<CellRendererProps<R, SR>,
| 'rowIdx'
| 'row'
| 'column'
| 'colSpan'
>;

interface EditCellProps<R, SR> extends SharedCellRendererProps<R, SR>, Omit<React.HTMLAttributes<HTMLDivElement>, 'style' | 'children'> {
Expand All @@ -25,6 +26,7 @@ interface EditCellProps<R, SR> extends SharedCellRendererProps<R, SR>, Omit<Reac
export default function EditCell<R, SR>({
className,
column,
colSpan,
row,
rowIdx,
editorProps,
Expand Down Expand Up @@ -73,7 +75,7 @@ export default function EditCell<R, SR>({
aria-selected
ref={cellRef}
className={className}
style={getCellStyle(column)}
style={getCellStyle(column, colSpan)}
{...props}
>
{getCellContent()}
Expand Down
4 changes: 3 additions & 1 deletion src/HeaderCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ type SharedHeaderRowProps<R, SR> = Pick<HeaderRowProps<R, SR>,

export interface HeaderCellProps<R, SR> extends SharedHeaderRowProps<R, SR> {
column: CalculatedColumn<R, SR>;
colSpan?: number;
onResize: (column: CalculatedColumn<R, SR>, width: number) => void;
onAllRowsSelectionChange: (checked: boolean) => void;
}

export default function HeaderCell<R, SR>({
column,
colSpan,
onResize,
allRowsSelected,
onAllRowsSelectionChange,
Expand Down Expand Up @@ -128,7 +130,7 @@ export default function HeaderCell<R, SR>({
aria-colindex={column.idx + 1}
aria-sort={sortColumn === column.key ? getAriaSort(sortDirection) : undefined}
className={className}
style={getCellStyle(column)}
style={getCellStyle(column, colSpan)}
onPointerDown={column.resizable ? onPointerDown : undefined}
>
{getCell()}
Expand Down
44 changes: 28 additions & 16 deletions src/HeaderRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useCallback, memo } from 'react';

import HeaderCell from './HeaderCell';
import type { CalculatedColumn } from './types';
import { assertIsValidKeyGetter } from './utils';
import { assertIsValidKeyGetter, getColSpan } from './utils';
import type { DataGridProps } from './DataGrid';
import { headerRowClassname } from './style';

Expand All @@ -19,6 +19,7 @@ export interface HeaderRowProps<R, SR> extends SharedDataGridProps<R, SR> {
columns: readonly CalculatedColumn<R, SR>[];
allRowsSelected: boolean;
onColumnResize: (column: CalculatedColumn<R, SR>, width: number) => void;
lastFrozenColumnIndex: number;
}

function HeaderRow<R, SR>({
Expand All @@ -30,7 +31,8 @@ function HeaderRow<R, SR>({
onColumnResize,
sortColumn,
sortDirection,
onSort
onSort,
lastFrozenColumnIndex
}: HeaderRowProps<R, SR>) {
const handleAllRowsSelectionChange = useCallback((checked: boolean) => {
if (!onSelectedRowsChange) return;
Expand All @@ -41,26 +43,36 @@ function HeaderRow<R, SR>({
onSelectedRowsChange(newSelectedRows);
}, [onSelectedRowsChange, rows, rowKeyGetter]);

const cells = [];
for (let index = 0; index < columns.length; index++) {
const column = columns[index];
const colSpan = getColSpan(column, lastFrozenColumnIndex, { type: 'HEADER' });
if (colSpan !== undefined) {
index += colSpan - 1;
}

cells.push(
<HeaderCell<R, SR>
key={column.key}
column={column}
colSpan={colSpan}
onResize={onColumnResize}
allRowsSelected={allRowsSelected}
onAllRowsSelectionChange={handleAllRowsSelectionChange}
onSort={onSort}
sortColumn={sortColumn}
sortDirection={sortDirection}
/>
);
}

return (
<div
role="row"
aria-rowindex={1} // aria-rowindex is 1 based
className={headerRowClassname}
>
{columns.map(column => {
return (
<HeaderCell<R, SR>
key={column.key}
column={column}
onResize={onColumnResize}
allRowsSelected={allRowsSelected}
onAllRowsSelectionChange={handleAllRowsSelectionChange}
onSort={onSort}
sortColumn={sortColumn}
sortDirection={sortDirection}
/>
);
})}
{cells}
</div>
);
}
Expand Down
84 changes: 49 additions & 35 deletions src/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { RefAttributes } from 'react';
import clsx from 'clsx';

import { groupRowSelectedClassname, rowClassname, rowSelectedClassname } from './style';
import { getColSpan } from './utils';
import Cell from './Cell';
import EditCell from './EditCell';
import type { RowRendererProps, SelectedCellProps } from './types';
Expand All @@ -14,6 +15,7 @@ function Row<R, SR = unknown>({
isRowSelected,
copiedCellIdx,
draggedOverCellIdx,
lastFrozenColumnIndex,
row,
viewportColumns,
selectedCellProps,
Expand Down Expand Up @@ -44,6 +46,52 @@ function Row<R, SR = unknown>({
className
);

const cells = [];
for (let index = 0; index < viewportColumns.length; index++) {
const column = viewportColumns[index];
const colSpan = getColSpan(column, lastFrozenColumnIndex, { type: 'ROW', row });
if (colSpan !== undefined) {
index += colSpan - 1;
}

const isCellSelected = selectedCellProps?.idx === column.idx;
if (selectedCellProps?.mode === 'EDIT' && isCellSelected) {
cells.push(
<EditCell<R, SR>
key={column.key}
rowIdx={rowIdx}
column={column}
colSpan={colSpan}
row={row}
onKeyDown={selectedCellProps.onKeyDown}
editorProps={selectedCellProps.editorProps}
/>
);
continue;
}

cells.push(
<CellRenderer
key={column.key}
rowIdx={rowIdx}
column={column}
colSpan={colSpan}
row={row}
isCopied={copiedCellIdx === column.idx}
isDraggedOver={draggedOverCellIdx === column.idx}
isCellSelected={isCellSelected}
isRowSelected={isRowSelected}
dragHandleProps={isCellSelected ? (selectedCellProps as SelectedCellProps).dragHandleProps : undefined}
onFocus={isCellSelected ? (selectedCellProps as SelectedCellProps).onFocus : undefined}
onKeyDown={isCellSelected ? selectedCellProps!.onKeyDown : undefined}
onRowClick={onRowClick}
onRowChange={onRowChange}
selectCell={selectCell}
selectRow={selectRow}
/>
);
}

return (
<div
role="row"
Expand All @@ -55,41 +103,7 @@ function Row<R, SR = unknown>({
style={{ top }}
{...props}
>
{viewportColumns.map(column => {
const isCellSelected = selectedCellProps?.idx === column.idx;
if (selectedCellProps?.mode === 'EDIT' && isCellSelected) {
return (
<EditCell<R, SR>
key={column.key}
rowIdx={rowIdx}
column={column}
row={row}
onKeyDown={selectedCellProps.onKeyDown}
editorProps={selectedCellProps.editorProps}
/>
);
}

return (
<CellRenderer
key={column.key}
rowIdx={rowIdx}
column={column}
row={row}
isCopied={copiedCellIdx === column.idx}
isDraggedOver={draggedOverCellIdx === column.idx}
isCellSelected={isCellSelected}
isRowSelected={isRowSelected}
dragHandleProps={isCellSelected ? (selectedCellProps as SelectedCellProps).dragHandleProps : undefined}
onFocus={isCellSelected ? (selectedCellProps as SelectedCellProps).onFocus : undefined}
onKeyDown={isCellSelected ? selectedCellProps!.onKeyDown : undefined}
onRowClick={onRowClick}
onRowChange={onRowChange}
selectCell={selectCell}
selectRow={selectRow}
/>
);
})}
{cells}
</div>
);
}
Expand Down
5 changes: 3 additions & 2 deletions src/SummaryCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import { memo } from 'react';
import { getCellStyle, getCellClassname } from './utils';
import type { CellRendererProps } from './types';

type SharedCellRendererProps<R, SR> = Pick<CellRendererProps<R, SR>, 'column'>;
type SharedCellRendererProps<R, SR> = Pick<CellRendererProps<R, SR>, 'column' | 'colSpan'>;

interface SummaryCellProps<R, SR> extends SharedCellRendererProps<R, SR> {
row: SR;
}

function SummaryCell<R, SR>({
column,
colSpan,
row
}: SummaryCellProps<R, SR>) {
const { summaryFormatter: SummaryFormatter, summaryCellClass } = column;
Expand All @@ -23,7 +24,7 @@ function SummaryCell<R, SR>({
role="gridcell"
aria-colindex={column.idx + 1}
className={className}
style={getCellStyle(column)}
style={getCellStyle(column, colSpan)}
>
{SummaryFormatter && <SummaryFormatter column={column} row={row} />}
</div>
Expand Down
Loading