Skip to content
Closed
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ interface Renderers<TRow, TSummaryRow> {
renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>;
renderRow?: Maybe<(key: Key, props: RenderRowProps<TRow, TSummaryRow>) => ReactNode>;
renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>;
renderCell?: Maybe<(key: Key, props: CellRendererProps<TRow, TSummaryRow>) => ReactNode>;
noRowsFallback?: Maybe<ReactNode>;
}
```
Expand Down
52 changes: 33 additions & 19 deletions src/Cell.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { memo } from 'react';
import { forwardRef, memo, type RefAttributes } from 'react';
import { css } from '@linaria/core';

import { useRovingTabIndex } from './hooks';
Expand All @@ -25,31 +25,36 @@ const cellDraggedOver = css`

const cellDraggedOverClassname = `rdg-cell-dragged-over ${cellDraggedOver}`;

function Cell<R, SR>({
column,
colSpan,
isCellSelected,
isCopied,
isDraggedOver,
row,
rowIdx,
onClick,
onDoubleClick,
onContextMenu,
onRowChange,
selectCell,
...props
}: CellRendererProps<R, SR>) {
function Cell<R, SR>(
{
column,
colSpan,
isCellSelected,
isCopied,
isDraggedOver,
row,
rowIdx,
className,
onClick,
onDoubleClick,
onContextMenu,
onRowChange,
selectCell,
...props
}: CellRendererProps<R, SR>,
ref: React.Ref<HTMLDivElement>
) {
const { tabIndex, childTabIndex, onFocus } = useRovingTabIndex(isCellSelected);

const { cellClass } = column;
const className = getCellClassname(
className = getCellClassname(
column,
{
[cellCopiedClassname]: isCopied,
[cellDraggedOverClassname]: isDraggedOver
},
typeof cellClass === 'function' ? cellClass(row) : cellClass
typeof cellClass === 'function' ? cellClass(row) : cellClass,
className
);
const isEditable = isCellEditableUtil(column, row);

Expand Down Expand Up @@ -95,6 +100,7 @@ function Cell<R, SR>({
aria-colspan={colSpan}
aria-selected={isCellSelected}
aria-readonly={!isEditable || undefined}
ref={ref}
tabIndex={tabIndex}
className={className}
style={getCellStyle(column, colSpan)}
Expand All @@ -116,4 +122,12 @@ function Cell<R, SR>({
);
}

export default memo(Cell) as <R, SR>(props: CellRendererProps<R, SR>) => React.JSX.Element;
const CellComponent = memo(forwardRef(Cell)) as <R, SR>(
props: CellRendererProps<R, SR> & RefAttributes<HTMLDivElement>
) => JSX.Element;

export default CellComponent;

export function defaultRenderCell<R, SR>(key: React.Key, props: CellRendererProps<R, SR>) {
return <CellComponent key={key} {...props} />;
}
7 changes: 5 additions & 2 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import type {
SelectRowEvent,
SortColumn
} from './types';
import { defaultRenderCell } from './Cell';
import { renderCheckbox as defaultRenderCheckbox } from './cellRenderers';
import {
DataGridDefaultRenderersProvider,
Expand Down Expand Up @@ -273,6 +274,7 @@ function DataGrid<R, SR, K extends Key>(
const headerRowHeight = rawHeaderRowHeight ?? (typeof rowHeight === 'number' ? rowHeight : 35);
const summaryRowHeight = rawSummaryRowHeight ?? (typeof rowHeight === 'number' ? rowHeight : 35);
const renderRow = renderers?.renderRow ?? defaultRenderers?.renderRow ?? defaultRenderRow;
const renderCell = renderers?.renderCell ?? defaultRenderers?.renderCell ?? defaultRenderCell;
const renderSortStatus =
renderers?.renderSortStatus ?? defaultRenderers?.renderSortStatus ?? defaultRenderSortStatus;
const renderCheckbox =
Expand Down Expand Up @@ -364,9 +366,10 @@ function DataGrid<R, SR, K extends Key>(
const defaultGridComponents = useMemo(
() => ({
renderCheckbox,
renderSortStatus
renderSortStatus,
renderCell
}),
[renderCheckbox, renderSortStatus]
[renderCheckbox, renderSortStatus, renderCell]
);

const headerSelectionValue = useMemo((): HeaderRowSelectionContextValue => {
Expand Down
33 changes: 17 additions & 16 deletions src/Row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import clsx from 'clsx';
import { RowSelectionProvider, useLatestFunc, type RowSelectionContextValue } from './hooks';
import { getColSpan, getRowStyle } from './utils';
import type { CalculatedColumn, RenderRowProps } from './types';
import Cell from './Cell';
import { useDefaultRenderers } from './DataGridDefaultRenderersProvider';
import { rowClassname, rowSelectedClassname } from './style/row';

function Row<R, SR>(
Expand Down Expand Up @@ -33,6 +33,8 @@ function Row<R, SR>(
}: RenderRowProps<R, SR>,
ref: React.Ref<HTMLDivElement>
) {
const renderCell = useDefaultRenderers<R, SR>()!.renderCell!;

const handleRowChange = useLatestFunc((column: CalculatedColumn<R, SR>, newRow: R) => {
onRowChange(column, rowIdx, newRow);
});
Expand Down Expand Up @@ -68,21 +70,20 @@ function Row<R, SR>(
cells.push(selectedCellEditor);
} else {
cells.push(
<Cell
key={column.key}
column={column}
colSpan={colSpan}
row={row}
rowIdx={rowIdx}
isCopied={copiedCellIdx === idx}
isDraggedOver={draggedOverCellIdx === idx}
isCellSelected={isCellSelected}
onClick={onCellClick}
onDoubleClick={onCellDoubleClick}
onContextMenu={onCellContextMenu}
onRowChange={handleRowChange}
selectCell={selectCell}
/>
renderCell(column.key, {
column,
colSpan,
row,
rowIdx,
isCopied: copiedCellIdx === idx,
isDraggedOver: draggedOverCellIdx === idx,
isCellSelected,
onClick: onCellClick,
onDoubleClick: onCellDoubleClick,
onContextMenu: onCellContextMenu,
onRowChange: handleRowChange,
selectCell
})
);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { default, type DataGridProps, type DataGridHandle } from './DataGrid';
export { default as TreeDataGrid, type TreeDataGridProps } from './TreeDataGrid';
export { DataGridDefaultRenderersProvider } from './DataGridDefaultRenderersProvider';
export { default as Row } from './Row';
export { default as Cell } from './Cell';
export * from './Columns';
export * from './cellRenderers';
export { default as textEditor } from './editors/textEditor';
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ export interface Renderers<TRow, TSummaryRow> {
renderCheckbox?: Maybe<(props: RenderCheckboxProps) => ReactNode>;
renderRow?: Maybe<(key: Key, props: RenderRowProps<TRow, TSummaryRow>) => ReactNode>;
renderSortStatus?: Maybe<(props: RenderSortStatusProps) => ReactNode>;
renderCell?: Maybe<(key: Key, props: CellRendererProps<TRow, TSummaryRow>) => ReactNode>;
noRowsFallback?: Maybe<ReactNode>;
}

Expand Down
52 changes: 49 additions & 3 deletions test/browser/renderers.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,19 @@ import DataGrid, {
renderSortIcon,
SelectColumn
} from '../../src';
import type { Column, DataGridProps, RenderSortStatusProps, SortColumn } from '../../src';
import { getHeaderCells, getRows, setup } from './utils';
import type {
CellRendererProps,
Column,
DataGridProps,
RenderSortStatusProps,
SortColumn
} from '../../src';
import { getCells, getHeaderCells, getRows, setup } from './utils';

interface Row {
id: number;
col1?: string;
col2?: string;
}

const noRows: readonly Row[] = [];
Expand All @@ -30,6 +38,22 @@ const columns: readonly Column<Row>[] = [
}
];

function globalCellRenderer(key: React.Key, props: CellRendererProps<Row, unknown>) {
return (
<div key={key} role="gridcell">
{props.row[props.column.key as keyof Row]}
</div>
);
}

function localCellRenderer(key: React.Key) {
return (
<div key={key} role="gridcell">
local
</div>
);
}

function NoRowsFallback() {
return <div>Local no rows fallback</div>;
}
Expand Down Expand Up @@ -76,7 +100,8 @@ function setupProvider<R, SR, K extends React.Key>(props: DataGridProps<R, SR, K
value={{
noRowsFallback: <GlobalNoRowsFallback />,
renderCheckbox: globalRenderCheckbox,
renderSortStatus: globalSortStatus
renderSortStatus: globalSortStatus,
renderCell: globalCellRenderer
}}
>
<TestGrid {...props} />
Expand Down Expand Up @@ -180,3 +205,24 @@ test('sortPriority defined using both providers and renderers', async () => {

expect(screen.queryByTestId('global-sort-priority')).not.toBeInTheDocument();
});

test('renderCell defined using provider', () => {
setupProvider({ columns, rows: [{ id: 1, col1: 'col 1 value', col2: 'col 2 value' }] });

const [, cell1, cell2] = getCells();
expect(cell1).toHaveTextContent('col 1 value');
expect(cell2).toHaveTextContent('col 2 value');
});

test('renderCell defined using both providers and renderers', () => {
setupProvider({
columns,
rows: [{ id: 1, col1: 'col 1 value', col2: 'col 2 value' }],
renderers: { renderCell: localCellRenderer }
});

const [selectCell, cell1, cell2] = getCells();
expect(selectCell).toHaveTextContent('local');
expect(cell1).toHaveTextContent('local');
expect(cell2).toHaveTextContent('local');
});