Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
167 changes: 57 additions & 110 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
HeaderRowSelectionChangeContext,
HeaderRowSelectionContext,
RowSelectionChangeContext,
useActivePosition,
useCalculatedColumns,
useColumnWidths,
useGridDimensions,
Expand Down Expand Up @@ -77,16 +78,6 @@ import {
} from './style/core';
import SummaryRow from './SummaryRow';

interface ActiveCellState extends Position {
readonly mode: 'ACTIVE';
}

interface EditCellState<R> extends Position {
readonly mode: 'EDIT';
readonly row: R;
readonly originalRow: R;
}

export type DefaultColumnOptions<R, SR> = Pick<
Column<R, SR>,
| 'renderCell'
Expand Down Expand Up @@ -365,33 +356,50 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
enableVirtualization
});

/**
* computed values
*/
const isTreeGrid = role === 'treegrid';
const topSummaryRowsCount = topSummaryRows?.length ?? 0;
const bottomSummaryRowsCount = bottomSummaryRows?.length ?? 0;
const summaryRowsCount = topSummaryRowsCount + bottomSummaryRowsCount;
const headerAndTopSummaryRowsCount = headerRowsCount + topSummaryRowsCount;
const groupedColumnHeaderRowsCount = headerRowsCount - 1;
const minRowIdx = -headerAndTopSummaryRowsCount;
const mainHeaderRowIdx = minRowIdx + groupedColumnHeaderRowsCount;
const maxRowIdx = rows.length + bottomSummaryRowsCount - 1;
const frozenShadowStyles: React.CSSProperties = {
gridColumnStart: lastFrozenColumnIndex + 2,
insetInlineStart: totalFrozenColumnWidth
};

const [activePosition, setActivePosition] = useState<ActiveCellState | EditCellState<R>>(
getInitialActivePosition
);

/**
* computed values
*/
const isTreeGrid = role === 'treegrid';
const mainHeaderRowIdx = minRowIdx + groupedColumnHeaderRowsCount;
const maxColIdx = columns.length - 1;
const headerRowsHeight = headerRowsCount * headerRowHeight;
const summaryRowsHeight = summaryRowsCount * summaryRowHeight;
const clientHeight = gridHeight - headerRowsHeight - summaryRowsHeight;
const isSelectable = selectedRows != null && onSelectedRowsChange != null;
const { leftKey, rightKey } = getLeftRightKey(direction);
const ariaRowCount = rawAriaRowCount ?? headerRowsCount + rows.length + summaryRowsCount;
const frozenShadowStyles: React.CSSProperties = {
gridColumnStart: lastFrozenColumnIndex + 2,
insetInlineStart: totalFrozenColumnWidth
};

const {
activePosition,
setActivePosition,
activePositionIsInActiveBounds,
activePositionIsInViewport,
activePositionIsRow,
activePositionIsCellInViewport,
validatePosition,
getActiveColumn,
getActiveRow
} = useActivePosition<R, SR>({
columns,
rows,
isTreeGrid,
maxColIdx,
minRowIdx,
maxRowIdx,
setDraggedOverRowIdx,
setShouldFocusPosition
});

const defaultGridComponents = useMemo(
() => ({
Expand Down Expand Up @@ -441,14 +449,6 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
enableVirtualization
});

const maxColIdx = columns.length - 1;
const {
isPositionInActiveBounds: activePositionIsInActiveBounds,
isPositionInViewport: activePositionIsInViewport,
isRowInActiveBounds: activePositionIsRow,
isCellInViewport: activePositionIsCellInViewport
} = validatePosition(activePosition);

const {
viewportColumns,
iterateOverViewportColumnsForRow,
Expand Down Expand Up @@ -656,29 +656,32 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr

function commitEditorChanges() {
if (activePosition.mode !== 'EDIT') return;
updateRow(columns[activePosition.idx], activePosition.rowIdx, activePosition.row);
updateRow(getActiveColumn(), activePosition.rowIdx, activePosition.row);
}

function handleCellCopy(event: CellClipboardEvent) {
if (!activePositionIsCellInViewport) return;
const { idx, rowIdx } = activePosition;
onCellCopy?.({ row: rows[rowIdx], column: columns[idx] }, event);
onCellCopy?.({ row: getActiveRow(), column: getActiveColumn() }, event);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

WDYT about getActiveRow()/getActiveColumn()? Worth it?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Not sure. Should we return variables instead activeRow, activeColumn?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We'd have to check if they're undefined in many places

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Could also add queryActive*() 🤔

}

function handleCellPaste(event: CellClipboardEvent) {
if (!onCellPaste || !onRowsChange || !isCellEditable(activePosition)) {
if (
typeof onCellPaste !== 'function' ||
typeof onRowsChange !== 'function' ||
!isCellEditable(activePosition)
) {
return;
}

const { idx, rowIdx } = activePosition;
const column = columns[idx];
const updatedRow = onCellPaste({ row: rows[rowIdx], column }, event);
updateRow(column, rowIdx, updatedRow);
const column = getActiveColumn();
const row = getActiveRow();
const updatedRow = onCellPaste({ row, column }, event);
updateRow(column, activePosition.rowIdx, updatedRow);
}

function handleCellInput(event: KeyboardEvent<HTMLDivElement>) {
if (!activePositionIsCellInViewport) return;
const row = rows[activePosition.rowIdx];
const row = getActiveRow();
const { key, shiftKey } = event;

// Select the row on Shift + Space
Expand Down Expand Up @@ -764,9 +767,9 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
function updateRows(startRowIdx: number, endRowIdx: number) {
if (onRowsChange == null) return;

const { rowIdx, idx } = activePosition;
const column = columns[idx];
const sourceRow = rows[rowIdx];
const { idx } = activePosition;
const column = getActiveColumn();
const sourceRow = getActiveRow();
const updatedRows = [...rows];
const indexes: number[] = [];
for (let i = startRowIdx; i < endRowIdx; i++) {
Expand All @@ -784,50 +787,6 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
}
}

/**
* utils
*/
function getInitialActivePosition(): ActiveCellState {
return { idx: -1, rowIdx: minRowIdx - 1, mode: 'ACTIVE' };
}

/**
* Returns whether the given position represents a valid cell or row position in the grid.
* Active bounds: any valid position in the grid
* Viewport: any valid position in the grid outside of header rows and summary rows
* Row selection is only allowed in TreeDataGrid
*/
function validatePosition({ idx, rowIdx }: Position) {
// check column position
const isColumnPositionAllColumns = isTreeGrid && idx === -1;
const isColumnPositionInActiveBounds = idx >= 0 && idx <= maxColIdx;

// check row position
const isRowPositionInActiveBounds = rowIdx >= minRowIdx && rowIdx <= maxRowIdx;
const isRowPositionInViewport = rowIdx >= 0 && rowIdx < rows.length;

// row status
const isRowInActiveBounds = isColumnPositionAllColumns && isRowPositionInActiveBounds;
const isRowInViewport = isColumnPositionAllColumns && isRowPositionInViewport;

// cell status
const isCellInActiveBounds = isColumnPositionInActiveBounds && isRowPositionInActiveBounds;
const isCellInViewport = isColumnPositionInActiveBounds && isRowPositionInViewport;

// position status
const isPositionInActiveBounds = isRowInActiveBounds || isCellInActiveBounds;
const isPositionInViewport = isRowInViewport || isCellInViewport;

return {
isPositionInActiveBounds,
isPositionInViewport,
isRowInActiveBounds,
isRowInViewport,
isCellInActiveBounds,
isCellInViewport
};
}

function isCellEditable(position: Position): boolean {
return (
validatePosition(position).isCellInViewport &&
Expand Down Expand Up @@ -977,19 +936,19 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
}

function getDragHandle() {
if (onFill == null || activePosition.mode === 'EDIT' || !activePositionIsCellInViewport) {
if (onFill == null || activePosition.mode !== 'ACTIVE' || !activePositionIsCellInViewport) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've changed the mode check in case we ever add a third mode

return;
}

const { idx, rowIdx } = activePosition;
const column = columns[idx];
const { rowIdx } = activePosition;
const column = getActiveColumn();
if (column.renderEditCell == null || column.editable === false) {
return;
}

const isLastRow = rowIdx === maxRowIdx;
const columnWidth = getColumnWidth(column);
const colSpan = column.colSpan?.({ type: 'ROW', row: rows[rowIdx] }) ?? 1;
const colSpan = column.colSpan?.({ type: 'ROW', row: getActiveRow() }) ?? 1;
const { insetInlineStart, ...style } = getCellStyle(column, colSpan);
const marginEnd = 'calc(var(--rdg-drag-handle-size) * -0.5 + 1px)';
const isLastColumn = column.idx + colSpan - 1 === maxColIdx;
Expand Down Expand Up @@ -1023,22 +982,21 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
if (
!activePositionIsCellInViewport ||
activePosition.rowIdx !== rowIdx ||
activePosition.mode === 'ACTIVE'
activePosition.mode !== 'EDIT'
) {
return;
}

const { idx, row } = activePosition;
const column = columns[idx];
const { row } = activePosition;
const column = getActiveColumn();
const colSpan = getColSpan(column, lastFrozenColumnIndex, { type: 'ROW', row });
const closeOnExternalRowChange = column.editorOptions?.closeOnExternalRowChange ?? true;

const closeEditor = (shouldFocus: boolean) => {
function closeEditor(shouldFocus: boolean) {
setShouldFocusPosition(shouldFocus);
setActivePosition(({ idx, rowIdx }) => ({ idx, rowIdx, mode: 'ACTIVE' }));
};
}

const onRowChange = (row: R, commitChanges: boolean, shouldFocus: boolean) => {
function onRowChange(row: R, commitChanges: boolean, shouldFocus: boolean) {
if (commitChanges) {
// Prevents two issues when editor is closed by clicking on a different cell
//
Expand All @@ -1051,11 +1009,6 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
} else {
setActivePosition((position) => ({ ...position, row }));
}
};

if (closeOnExternalRowChange && rows[activePosition.rowIdx] !== activePosition.originalRow) {
// Discard changes if rows are updated from outside
closeEditor(false);
}

return (
Expand Down Expand Up @@ -1135,12 +1088,6 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
.toArray();
}

// Reset the positions if the current values are no longer valid. This can happen if a column or row is removed
if (activePosition.idx > maxColIdx || activePosition.rowIdx > maxRowIdx) {
setActivePosition(getInitialActivePosition());
setDraggedOverRowIdx(undefined);
}

// Keep the state and prop in sync
if (isColumnWidthsControlled && columnWidthsInternal !== columnWidthsRaw) {
setColumnWidthsInternal(columnWidthsRaw);
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './useActivePosition';
export * from './useCalculatedColumns';
export * from './useColumnWidths';
export * from './useGridDimensions';
Expand Down
Loading