Skip to content
Merged
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
4 changes: 1 addition & 3 deletions src/Cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@ function Cell<R, SR>({
const { cellClass } = column;
className = getCellClassname(
column,
{
[cellDraggedOverClassname]: isDraggedOver
},
isDraggedOver && cellDraggedOverClassname,
typeof cellClass === 'function' ? cellClass(row) : cellClass,
className
);
Expand Down
8 changes: 1 addition & 7 deletions src/DataGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1170,13 +1170,7 @@ export function DataGrid<R, SR = unknown, K extends Key = Key>(props: DataGridPr
// Scrollable containers without tabIndex are keyboard focusable in Chrome only if there is no focusable element inside
// whereas they are always focusable in Firefox. We need to set tabIndex to have a consistent behavior across browsers.
tabIndex={-1}
className={classnames(
rootClassname,
{
[viewportDraggingClassname]: isDragging
},
className
)}
className={classnames(rootClassname, isDragging && viewportDraggingClassname, className)}
style={{
...style,
// set scrollPadding to correctly scroll to non-sticky cells/rows
Expand Down
16 changes: 9 additions & 7 deletions src/HeaderCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,15 @@ export default function HeaderCell<R, SR>({
sortDirection && !priority ? (sortDirection === 'ASC' ? 'ascending' : 'descending') : undefined;
const { sortable, resizable, draggable } = column;

const className = getCellClassname(column, column.headerCellClass, {
[cellSortableClassname]: sortable,
[cellResizableClassname]: resizable,
[cellDraggableClassname]: draggable,
[cellDraggingClassname]: isDragging,
[cellOverClassname]: isOver
});
const className = getCellClassname(
column,
column.headerCellClass,
sortable && cellSortableClassname,
resizable && cellResizableClassname,
draggable && cellDraggableClassname,
isDragging && cellDraggingClassname,
isOver && cellOverClassname
);

function onSort(ctrlClick: boolean) {
if (onSortColumnsChange == null) return;
Expand Down
6 changes: 1 addition & 5 deletions src/cellRenderers/renderValue.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import type { RenderCellProps } from '../types';

export function renderValue<R, SR>(props: RenderCellProps<R, SR>) {
try {
return props.row[props.column.key as keyof R] as React.ReactNode;
} catch {
return null;
}
return props.row?.[props.column.key as keyof R] as React.ReactNode;
}
24 changes: 5 additions & 19 deletions src/utils/styleUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,37 +38,23 @@ export function getCellStyle<R, SR>(
};
}

type ClassValue = Maybe<string> | Record<string, boolean> | false;
type ClassValue = Maybe<string | false>;

export function classnames(...args: readonly ClassValue[]) {
let classname = '';

for (const arg of args) {
if (arg) {
if (typeof arg === 'string') {
classname += ` ${arg}`;
} else if (typeof arg === 'object') {
for (const key in arg) {
if (arg[key]) {
classname += ` ${key}`;
}
}
}
if (typeof arg === 'string') {
classname += ` ${arg}`;
}
}

return classname.trimStart();
return classname.slice(1);
}

export function getCellClassname<R, SR>(
column: CalculatedColumn<R, SR>,
...extraClasses: readonly ClassValue[]
): string {
return classnames(
cellClassname,
{
[cellFrozenClassname]: column.frozen
},
...extraClasses
);
return classnames(cellClassname, column.frozen && cellFrozenClassname, ...extraClasses);
}
6 changes: 3 additions & 3 deletions test/browser/column/grouping.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { page, userEvent } from 'vitest/browser';

import type { ColumnOrColumnGroup } from '../../../src';
import { safeTab, setup, tabIntoGrid, testCount, validateCellPosition } from '../utils';
import { safeTab, setup, testCount, validateCellPosition } from '../utils';

const grid = page.getGrid();
const headerRows = grid.getHeaderRow();
Expand Down Expand Up @@ -252,12 +252,12 @@ test('grouping', async () => {
});

test('keyboard navigation', async () => {
await setup({ columns, rows: [{}] }, true);
await setup({ columns, rows: [{}] });

// no initial active position
await expect.element(grid.getActiveCell()).not.toBeInTheDocument();

await tabIntoGrid();
await safeTab();
await validateCellPosition(0, 3);

// arrow navigation
Expand Down
14 changes: 7 additions & 7 deletions test/browser/direction.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { page, userEvent } from 'vitest/browser';

import type { Column } from '../../src';
import { setup, tabIntoGrid } from './utils';
import { safeTab, setup } from './utils';

const grid = page.getGrid();
const activeCell = grid.getActiveCell();
Expand All @@ -25,27 +25,27 @@ const columns: readonly Column<Row>[] = [
const rows: readonly Row[] = [];

test('should use left to right direction by default', async () => {
await setup({ rows, columns }, true);
await setup({ rows, columns });
await expect.element(grid).toHaveAttribute('dir', 'ltr');
await tabIntoGrid();
await safeTab();
await expect.element(activeCell).toHaveTextContent('ID');
await userEvent.keyboard('{ArrowRight}');
await expect.element(activeCell).toHaveTextContent('Name');
});

test('should use left to right direction if direction prop is set to ltr', async () => {
await setup({ rows, columns, direction: 'ltr' }, true);
await setup({ rows, columns, direction: 'ltr' });
await expect.element(grid).toHaveAttribute('dir', 'ltr');
await tabIntoGrid();
await safeTab();
await expect.element(activeCell).toHaveTextContent('ID');
await userEvent.keyboard('{ArrowRight}');
await expect.element(activeCell).toHaveTextContent('Name');
});

test('should use right to left direction if direction prop is set to rtl', async () => {
await setup({ rows, columns, direction: 'rtl' }, true);
await setup({ rows, columns, direction: 'rtl' });
await expect.element(grid).toHaveAttribute('dir', 'rtl');
await tabIntoGrid();
await safeTab();
await expect.element(activeCell).toHaveTextContent('ID');
await userEvent.keyboard('{ArrowLeft}');
await expect.element(activeCell).toHaveTextContent('Name');
Expand Down
13 changes: 9 additions & 4 deletions test/browser/dragFill.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,14 @@ test('should allow drag up using mouse', async () => {

test('should focus the cell when drag handle is clicked', async () => {
await setup();
await userEvent.click(getCellsAtRowIndex(0).nth(0));
await userEvent.click(document.body);
await expect.element(document.body).toHaveFocus();
const cell = getCellsAtRowIndex(0).nth(0);

await userEvent.click(cell);
await expect.element(cell).toHaveFocus();

cell.element().blur();
await expect.element(cell).not.toHaveFocus();

await userEvent.click(dragHandle);
await expect.element(getCellsAtRowIndex(0).nth(0)).toHaveFocus();
await expect.element(cell).toHaveFocus();
});
35 changes: 16 additions & 19 deletions test/browser/events.test.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { page, userEvent } from 'vitest/browser';

import { DataGrid } from '../../src';
import type { Column, DataGridProps } from '../../src';
import type { Column } from '../../src';
import { safeTab } from './utils';

interface Row {
Expand Down Expand Up @@ -55,7 +55,9 @@ const rows: readonly Row[] = [
describe('Events', () => {
it('should not select cell if onCellMouseDown prevents grid default', async () => {
await page.render(
<EventTest
<DataGrid
columns={columns}
rows={rows}
onCellMouseDown={(args, event) => {
if (args.column.key === 'col1') {
event.preventGridDefault();
Expand All @@ -71,7 +73,9 @@ describe('Events', () => {

it('should be able to open editor editor on single click using onCellClick', async () => {
await page.render(
<EventTest
<DataGrid
columns={columns}
rows={rows}
onCellClick={(args, event) => {
if (args.column.key === 'col2') {
event.preventGridDefault();
Expand All @@ -88,7 +92,9 @@ describe('Events', () => {

it('should not open editor editor on double click if onCellDoubleClick prevents default', async () => {
await page.render(
<EventTest
<DataGrid
columns={columns}
rows={rows}
onCellDoubleClick={(args, event) => {
if (args.column.key === 'col1') {
event.preventGridDefault();
Expand All @@ -104,7 +110,9 @@ describe('Events', () => {

it('should call onCellContextMenu when cell is right clicked', async () => {
const onCellContextMenu = vi.fn();
await page.render(<EventTest onCellContextMenu={onCellContextMenu} />);
await page.render(
<DataGrid columns={columns} rows={rows} onCellContextMenu={onCellContextMenu} />
);
expect(onCellContextMenu).not.toHaveBeenCalled();
await userEvent.click(page.getCell({ name: '1' }), { button: 'right' });
expect(onCellContextMenu).toHaveBeenCalledExactlyOnceWith(
Expand All @@ -122,7 +130,9 @@ describe('Events', () => {
it('should call onActivePositionChange when cell selection is changed', async () => {
const onActivePositionChange = vi.fn();

await page.render(<EventTest onActivePositionChange={onActivePositionChange} />);
await page.render(
<DataGrid columns={columns} rows={rows} onActivePositionChange={onActivePositionChange} />
);

expect(onActivePositionChange).not.toHaveBeenCalled();

Expand Down Expand Up @@ -181,16 +191,3 @@ describe('Events', () => {
expect(onActivePositionChange).toHaveBeenCalledTimes(6);
});
});

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

function EventTest(props: EventProps) {
return <DataGrid columns={columns} rows={rows} {...props} />;
}
Loading
Loading