Skip to content
Open
68 changes: 36 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ Control column widths using the [`width`](#width-maybenumber--string), [`minWidt

### Custom Renderers

Replace default components with custom implementations using the [`renderers`](#renderers-mayberenderersr-sr) prop. Columns can also have custom renderers using the [`renderCell`](#rendercell-maybeprops-rendercellpropstrow-tsummaryrow--reactnode), [`renderHeaderCell`](#renderheadercell-maybeprops-renderheadercellpropstrow-tsummaryrow--reactnode), [`renderSummaryCell`](#rendersummarycell-maybeprops-rendersummarycellpropstsummaryrow-trow--reactnode), [`renderGroupCell`](#rendergroupcell-maybeprops-rendergroupcellpropstrow-tsummaryrow--reactnode), and [`renderEditCell`](#rendereditcell-maybeprops-rendereditcellpropstrow-tsummaryrow--reactnode) properties.
Replace default components with custom implementations using the [`renderers`](#renderers-mayberenderersr-sr) prop. Columns can also have custom renderers using the [`renderCell`](#rendercell-maybeprops-rendercellcontentpropstrow-tsummaryrow--reactnode), [`renderHeaderCell`](#renderheadercell-maybeprops-renderheadercellcontentpropstrow-tsummaryrow--reactnode), [`renderSummaryCell`](#rendersummarycell-maybeprops-rendersummarycellcontentpropstsummaryrow-trow--reactnode), [`renderGroupCell`](#rendergroupcell-maybeprops-rendergroupcellcontentpropstrow-tsummaryrow--reactnode), and [`renderEditCell`](#rendereditcell-maybeprops-rendereditcellcontentpropstrow-tsummaryrow--reactnode) properties.

## API Reference

Expand Down Expand Up @@ -862,6 +862,8 @@ function rowGrouper(rows: readonly Row[], columnKey: string): Record<string, rea
}
```

:warning: **Performance:** Define this function outside your component or memoize it with `useCallback` to prevent unnecessary re-renders.

###### `expandedGroupIds: ReadonlySet<unknown>`

**Required.** A set of group IDs that are currently expanded. Group IDs are generated by `groupIdGetter`.
Expand Down Expand Up @@ -891,6 +893,8 @@ function MyGrid() {

Function to generate unique IDs for group rows. If not provided, a default implementation is used that concatenates parent and group keys with `__`.

:warning: **Performance:** Define this function outside your component or memoize it with `useCallback` to prevent unnecessary re-renders.

###### `rowHeight?: Maybe<number | ((args: RowHeightArgs<R>) => number)>`

**Note:** Unlike `DataGrid`, the `rowHeight` function receives [`RowHeightArgs<R>`](#rowheightargstrow) which includes a `type` property to distinguish between regular rows and group rows:
Expand Down Expand Up @@ -920,11 +924,11 @@ The default cell component. Can be wrapped via the `renderers.renderCell` prop.

##### Props

[`CellRendererProps<TRow, TSummaryRow>`](#cellrendererpropstrow-tsummaryrow)
[`RenderCellProps<TRow, TSummaryRow>`](#rendercellpropstrow-tsummaryrow)

#### `<SelectCellFormatter />`
#### `<SelectCheckbox />`

A formatter component for rendering row selection checkboxes.
A component for rendering row selection checkboxes.

##### Props

Expand Down Expand Up @@ -1011,7 +1015,7 @@ Hook for managing row selection state. Used within custom cell renderers to impl
**Example:**

```tsx
function CustomSelectCell({ row }: RenderCellProps<Row>) {
function CustomSelectCell({ row }: RenderCellContentProps<Row>) {
const { isRowSelectionDisabled, isRowSelected, onRowSelectionChange } = useRowSelection();

return (
Expand All @@ -1033,7 +1037,7 @@ function CustomSelectCell({ row }: RenderCellProps<Row>) {

### Render Functions

#### `renderHeaderCell<R, SR>(props: RenderHeaderCellProps<R, SR>)`
#### `renderHeaderCell<R, SR>(props: RenderHeaderCellContentProps<R, SR>)`

The default header cell renderer. Renders sortable columns with sort indicators.

Expand All @@ -1052,7 +1056,7 @@ const columns: readonly Column<Row>[] = [
];
```

#### `renderTextEditor<TRow, TSummaryRow>(props: RenderEditCellProps<TRow, TSummaryRow>)`
#### `renderTextEditor<TRow, TSummaryRow>(props: RenderEditCellContentProps<TRow, TSummaryRow>)`

A basic text editor provided for convenience.

Expand Down Expand Up @@ -1112,13 +1116,13 @@ import { DataGrid, renderCheckbox } from 'react-data-grid';
/>;
```

#### `renderToggleGroup<R, SR>(props: RenderGroupCellProps<R, SR>)`
#### `renderToggleGroup<R, SR>(props: RenderGroupCellContentProps<R, SR>)`

The default group cell renderer used by the columns used for grouping (`groupBy` prop). This renders the expand/collapse toggle.

##### Props

[`RenderGroupCellProps<TRow, TSummaryRow>`](#rendergroupcellpropstrow-tsummaryrow)
[`RenderGroupCellContentProps<TRow, TSummaryRow>`](#rendergroupcellcontentpropstrow-tsummaryrow)

**Example:**

Expand All @@ -1134,7 +1138,7 @@ const columns: readonly Column<Row>[] = [
];
```

#### `renderValue<R, SR>(props: RenderCellProps<R, SR>)`
#### `renderValue<R, SR>(props: RenderCellContentProps<R, SR>)`

The default cell renderer that renders the value of `row[column.key]`.

Expand Down Expand Up @@ -1340,23 +1344,23 @@ Class name(s) for the header cell.

Class name(s) for summary cells. Can be a string or a function that returns a class name based on the summary row.

##### `renderCell?: Maybe<(props: RenderCellProps<TRow, TSummaryRow>) => ReactNode>`
##### `renderCell?: Maybe<(props: RenderCellContentProps<TRow, TSummaryRow>) => ReactNode>`

Render function to render the content of cells.

##### `renderHeaderCell?: Maybe<(props: RenderHeaderCellProps<TRow, TSummaryRow>) => ReactNode>`
##### `renderHeaderCell?: Maybe<(props: RenderHeaderCellContentProps<TRow, TSummaryRow>) => ReactNode>`

Render function to render the content of the header cell.

##### `renderSummaryCell?: Maybe<(props: RenderSummaryCellProps<TSummaryRow, TRow>) => ReactNode>`
##### `renderSummaryCell?: Maybe<(props: RenderSummaryCellContentProps<TSummaryRow, TRow>) => ReactNode>`

Render function to render the content of summary cells

##### `renderGroupCell?: Maybe<(props: RenderGroupCellProps<TRow, TSummaryRow>) => ReactNode>`
##### `renderGroupCell?: Maybe<(props: RenderGroupCellContentProps<TRow, TSummaryRow>) => ReactNode>`

Render function to render the content of group cells when using `TreeDataGrid`.

##### `renderEditCell?: Maybe<(props: RenderEditCellProps<TRow, TSummaryRow>) => ReactNode>`
##### `renderEditCell?: Maybe<(props: RenderEditCellContentProps<TRow, TSummaryRow>) => ReactNode>`

Render function to render the content of edit cells. When set, the column is automatically set to be editable

Expand Down Expand Up @@ -1526,12 +1530,12 @@ function getRowHeight(args: RowHeightArgs<Row>): number {
<TreeDataGrid rowHeight={getRowHeight} ... />
```

#### `RenderCellProps<TRow, TSummaryRow>`
#### `RenderCellContentProps<TRow, TSummaryRow>`

Props passed to custom cell renderers.

```tsx
interface RenderCellProps<TRow, TSummaryRow = unknown> {
interface RenderCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
rowIdx: number;
Expand All @@ -1544,9 +1548,9 @@ interface RenderCellProps<TRow, TSummaryRow = unknown> {
**Example:**

```tsx
import type { RenderCellProps } from 'react-data-grid';
import type { RenderCellContentProps } from 'react-data-grid';

function renderCell({ row, column, onRowChange }: RenderCellProps<MyRow>) {
function renderCell({ row, column, onRowChange }: RenderCellContentProps<MyRow>) {
return (
<div>
{row[column.key]}
Expand All @@ -1556,25 +1560,25 @@ function renderCell({ row, column, onRowChange }: RenderCellProps<MyRow>) {
}
```

#### `RenderHeaderCellProps<TRow, TSummaryRow>`
#### `RenderHeaderCellContentProps<TRow, TSummaryRow>`

Props passed to custom header cell renderers.

```tsx
interface RenderHeaderCellProps<TRow, TSummaryRow = unknown> {
interface RenderHeaderCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
sortDirection: SortDirection | undefined;
priority: number | undefined;
tabIndex: number;
}
```

#### `RenderEditCellProps<TRow, TSummaryRow>`
#### `RenderEditCellContentProps<TRow, TSummaryRow>`

Props passed to custom edit cell renderers (editors).

```tsx
interface RenderEditCellProps<TRow, TSummaryRow = unknown> {
interface RenderEditCellContentProps<TRow, TSummaryRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TRow;
rowIdx: number;
Expand All @@ -1586,9 +1590,9 @@ interface RenderEditCellProps<TRow, TSummaryRow = unknown> {
**Example:**

```tsx
import type { RenderEditCellProps } from 'react-data-grid';
import type { RenderEditCellContentProps } from 'react-data-grid';

function CustomEditor({ row, column, onRowChange, onClose }: RenderEditCellProps<MyRow>) {
function renderEditor({ row, column, onRowChange, onClose }: RenderEditCellContentProps<MyRow>) {
return (
<input
autoFocus
Expand All @@ -1600,24 +1604,24 @@ function CustomEditor({ row, column, onRowChange, onClose }: RenderEditCellProps
}
```

#### `RenderSummaryCellProps<TSummaryRow, TRow>`
#### `RenderSummaryCellContentProps<TSummaryRow, TRow>`

Props passed to summary cell renderers.

```tsx
interface RenderSummaryCellProps<TSummaryRow, TRow = unknown> {
interface RenderSummaryCellContentProps<TSummaryRow, TRow = unknown> {
column: CalculatedColumn<TRow, TSummaryRow>;
row: TSummaryRow;
tabIndex: number;
}
```

#### `RenderGroupCellProps<TRow, TSummaryRow>`
#### `RenderGroupCellContentProps<TRow, TSummaryRow>`

Props passed to group cell renderers when using `TreeDataGrid`.

```tsx
interface RenderGroupCellProps<TRow, TSummaryRow = unknown> {
interface RenderGroupCellContentProps<TRow, TSummaryRow = unknown> {
groupKey: unknown;
column: CalculatedColumn<TRow, TSummaryRow>;
row: GroupRow<TRow>;
Expand All @@ -1642,15 +1646,15 @@ interface RenderRowProps<TRow, TSummaryRow = unknown> {
isRowSelected: boolean;
gridRowStart: number;
draggedOverCellIdx: number | undefined;
activeCellEditor: ReactElement<RenderEditCellProps<TRow>> | undefined;
activeCellEditor: ReactElement<EditCellProps<TRow, TSummaryRow>> | undefined;
onRowChange: (column: CalculatedColumn<TRow, TSummaryRow>, rowIdx: number, newRow: TRow) => void;
rowClass: Maybe<(row: TRow, rowIdx: number) => Maybe<string>>;
isTreeGrid: boolean;
// ... and event handlers
}
```

#### `CellRendererProps<TRow, TSummaryRow>`
#### `RenderCellProps<TRow, TSummaryRow>`

Props passed to the cell renderer when using `renderers.renderCell`.

Expand All @@ -1662,7 +1666,7 @@ Custom renderer configuration for the grid.

```tsx
interface Renderers<TRow, TSummaryRow> {
renderCell?: Maybe<(key: Key, props: CellRendererProps<TRow, TSummaryRow>) => ReactNode>;
renderCell?: Maybe<(key: Key, props: RenderCellProps<TRow, TSummaryRow>) => ReactNode>;
renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>;
renderRow?: Maybe<(key: Key, props: RenderRowProps<TRow, TSummaryRow>) => ReactNode>;
renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>;
Expand Down
12 changes: 6 additions & 6 deletions src/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { css } from 'ecij';

import { useRovingTabIndex } from './hooks';
import { createCellEvent, getCellClassname, getCellStyle, isCellEditableUtil } from './utils';
import type { CellMouseEventHandler, CellRendererProps } from './types';
import type { CellMouseEventHandler, RenderCellProps } from './types';

const cellDraggedOver = css`
@layer rdg.Cell {
Expand Down Expand Up @@ -33,7 +33,7 @@ function Cell<R, SR>({
setActivePosition,
style,
...props
}: CellRendererProps<R, SR>) {
}: RenderCellProps<R, SR>) {
const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex(isCellActive);

const { cellClass } = column;
Expand Down Expand Up @@ -126,10 +126,10 @@ function Cell<R, SR>({
);
}

const CellComponent = memo(Cell) as <R, SR>(props: CellRendererProps<R, SR>) => React.JSX.Element;
const MemoCell = memo(Cell) as <R, SR>(props: RenderCellProps<R, SR>) => React.JSX.Element;

export default CellComponent;
export { MemoCell as Cell };

export function defaultRenderCell<R, SR>(key: React.Key, props: CellRendererProps<R, SR>) {
return <CellComponent key={key} {...props} />;
export function defaultRenderCell<R, SR>(key: React.Key, props: RenderCellProps<R, SR>) {
return <MemoCell key={key} {...props} />;
}
27 changes: 16 additions & 11 deletions src/Columns.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import { useHeaderRowSelection, useRowSelection } from './hooks';
import type { Column, RenderCellProps, RenderGroupCellProps, RenderHeaderCellProps } from './types';
import { SelectCellFormatter } from './cellRenderers';
import type {
Column,
RenderCellContentProps,
RenderGroupCellContentProps,
RenderHeaderCellContentProps
} from './types';
import { SelectCheckbox } from './cellRenderers';

export const SELECT_COLUMN_KEY = 'rdg-select-column';

function HeaderRenderer({ tabIndex }: RenderHeaderCellProps<unknown>) {
function SelectAllCell({ tabIndex }: RenderHeaderCellContentProps<unknown>) {
const { isIndeterminate, isRowSelected, onRowSelectionChange } = useHeaderRowSelection();

return (
<SelectCellFormatter
<SelectCheckbox
aria-label="Select All"
tabIndex={tabIndex}
indeterminate={isIndeterminate}
Expand All @@ -20,11 +25,11 @@ function HeaderRenderer({ tabIndex }: RenderHeaderCellProps<unknown>) {
);
}

function SelectFormatter({ row, tabIndex }: RenderCellProps<unknown>) {
function RowSelectCell({ row, tabIndex }: RenderCellContentProps<unknown>) {
const { isRowSelectionDisabled, isRowSelected, onRowSelectionChange } = useRowSelection();

return (
<SelectCellFormatter
<SelectCheckbox
aria-label="Select"
tabIndex={tabIndex}
disabled={isRowSelectionDisabled}
Expand All @@ -36,11 +41,11 @@ function SelectFormatter({ row, tabIndex }: RenderCellProps<unknown>) {
);
}

function SelectGroupFormatter({ row, tabIndex }: RenderGroupCellProps<unknown>) {
function GroupSelectCell({ row, tabIndex }: RenderGroupCellContentProps<unknown>) {
const { isRowSelected, onRowSelectionChange } = useRowSelection();

return (
<SelectCellFormatter
<SelectCheckbox
aria-label="Select Group"
tabIndex={tabIndex}
value={isRowSelected}
Expand All @@ -62,12 +67,12 @@ export const SelectColumn: Column<any, any> = {
sortable: false,
frozen: true,
renderHeaderCell(props) {
return <HeaderRenderer {...props} />;
return <SelectAllCell {...props} />;
},
renderCell(props) {
return <SelectFormatter {...props} />;
return <RowSelectCell {...props} />;
},
renderGroupCell(props) {
return <SelectGroupFormatter {...props} />;
return <GroupSelectCell {...props} />;
}
};
11 changes: 6 additions & 5 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -483,15 +483,15 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
*/
const handleColumnResizeLatest = useLatestFunc(handleColumnResize);
const handleColumnResizeEndLatest = useLatestFunc(handleColumnResizeEnd);
const onColumnsReorderLastest = useLatestFunc(onColumnsReorder);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"Lastest" 🙈

const onColumnsReorderLatest = useLatestFunc(onColumnsReorder);
const onSortColumnsChangeLatest = useLatestFunc(onSortColumnsChange);
const onCellMouseDownLatest = useLatestFunc(onCellMouseDown);
const onCellClickLatest = useLatestFunc(onCellClick);
const onCellDoubleClickLatest = useLatestFunc(onCellDoubleClick);
const onCellContextMenuLatest = useLatestFunc(onCellContextMenu);
const selectHeaderRowLatest = useLatestFunc(selectHeaderRow);
const selectRowLatest = useLatestFunc(selectRow);
const handleFormatterRowChangeLatest = useLatestFunc(updateRow);
const updateRowLatest = useLatestFunc(updateRow);
const setPositionLatest = useLatestFunc(setPosition);
const selectHeaderCellLatest = useLatestFunc(selectHeaderCell);

Expand Down Expand Up @@ -990,7 +990,8 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
const isLastRow = rowIdx === maxRowIdx;
const columnWidth = getColumnWidth(column);
const colSpan = column.colSpan?.({ type: 'ROW', row: rows[rowIdx] }) ?? 1;
const { insetInlineStart, ...style } = getCellStyle(column, colSpan);
const style = getCellStyle(column, colSpan);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

-1 object

const { insetInlineStart } = style;
const marginEnd = 'calc(var(--rdg-drag-handle-size) * -0.5 + 1px)';
const isLastColumn = column.idx + colSpan - 1 === maxColIdx;
const dragHandleStyle: React.CSSProperties = {
Expand Down Expand Up @@ -1126,7 +1127,7 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
gridRowStart,
activeCellIdx: isActiveRow ? activeIdx : undefined,
draggedOverCellIdx: getDraggedOverCellIdx(rowIdx),
onRowChange: handleFormatterRowChangeLatest,
onRowChange: updateRowLatest,
setActivePosition: setPositionLatest,
activeCellEditor: getCellEditor(rowIdx),
isTreeGrid
Expand Down Expand Up @@ -1218,7 +1219,7 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
iterateOverViewportColumnsForRow={iterateOverViewportColumnsForRow}
onColumnResize={handleColumnResizeLatest}
onColumnResizeEnd={handleColumnResizeEndLatest}
onColumnsReorder={onColumnsReorderLastest}
onColumnsReorder={onColumnsReorderLatest}
sortColumns={sortColumns}
onSortColumnsChange={onSortColumnsChangeLatest}
activeCellIdx={
Expand Down
Loading