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
55 changes: 55 additions & 0 deletions src/table/__tests__/table.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { fireEvent, render } from '@testing-library/react';
import { Table as AntdTable } from 'antd';
import '@testing-library/jest-dom/extend-expect';

import Table from '../index';
Expand All @@ -21,6 +22,18 @@ const dataSource = [
];

describe('test Table', () => {
test('should preserve antd Table static members', () => {
expect(Table.defaultProps).toBe(AntdTable.defaultProps);
expect(Table.SELECTION_COLUMN).toBe(AntdTable.SELECTION_COLUMN);
expect(Table.EXPAND_COLUMN).toBe(AntdTable.EXPAND_COLUMN);
expect(Table.SELECTION_ALL).toBe(AntdTable.SELECTION_ALL);
expect(Table.SELECTION_INVERT).toBe(AntdTable.SELECTION_INVERT);
expect(Table.SELECTION_NONE).toBe(AntdTable.SELECTION_NONE);
expect(Table.Column).toBe(AntdTable.Column);
expect(Table.ColumnGroup).toBe(AntdTable.ColumnGroup);
expect(Table.Summary).toBe(AntdTable.Summary);
});

test('should support tooltip column attribute', async () => {
jest.useFakeTimers();
const { container } = render(
Expand All @@ -38,4 +51,46 @@ describe('test Table', () => {
container.parentElement?.querySelector('.ant-tooltip:not(.ant-tooltip-hidden)')
).toBeInTheDocument();
});

test('should support declarative Table.Column', () => {
const { getByText } = render(
<Table rowKey="id" dataSource={dataSource}>
<Table.Column title="Name" dataIndex="name" />
<Table.Column title="Address" dataIndex="address" />
</Table>
);

expect(getByText('Name')).toBeInTheDocument();
expect(getByText('ZhangSan')).toBeInTheDocument();
});

test('should preserve function column title', () => {
const title = jest.fn(() => 'Dynamic Name');
const { getByText } = render(
<Table rowKey="id" columns={[{ dataIndex: 'name', title }]} dataSource={dataSource} />
);

expect(title).toHaveBeenCalled();
expect(getByText('Dynamic Name')).toBeInTheDocument();
});

test('should support tooltip in nested columns', () => {
const columns = [
{
title: 'Information',
children: [
{
dataIndex: 'name',
title: 'Name',
tooltip: 'This is Name!',
},
],
},
];
const { container } = render(
<Table rowKey="id" columns={columns} dataSource={dataSource} />
);

expect(container.querySelectorAll('.dtc-table__tooltip')).toHaveLength(1);
});
});
23 changes: 23 additions & 0 deletions src/table/demos/declarative.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import { Table } from 'dt-react-component';

interface DataType {
id: number;
name: string;
age: number;
address: string;
}

const dataSource: DataType[] = [
{ id: 1, name: 'ZhangSan', age: 17, address: 'New York No. 1 Lake Park' },
{ id: 2, name: 'LiSi', age: 20, address: 'Bei Jing No. 1 Lake Park' },
{ id: 3, name: 'WangWu', age: 23, address: 'Zhe Jiang No. 1 Lake Park' },
];

export default () => (
<Table<DataType> rowKey="id" dataSource={dataSource} pagination={false}>
<Table.Column<DataType> title="Name" dataIndex="name" />
<Table.Column<DataType> title="Age" dataIndex="age" />
<Table.Column<DataType> title="Address" dataIndex="address" />
</Table>
);
37 changes: 37 additions & 0 deletions src/table/demos/dynamicTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';
import { Table } from 'dt-react-component';

import type { ColumnsType } from '..';

interface DataType {
id: number;
name: string;
age: number;
}

const columns: ColumnsType<DataType> = [
{
title: 'Name',
dataIndex: 'name',
},
{
title: ({ sortColumns }) => {
const sortOrder = sortColumns?.find(({ column }) => column.dataIndex === 'age')?.order;
const sortText = sortOrder === 'ascend' ? 'ascending' : 'descending';
return sortOrder ? `Age (${sortText})` : 'Age';
},
dataIndex: 'age',
sorter: (previous, next) => previous.age - next.age,
tooltip: 'Click the sorter to see the title update',
},
];

const dataSource: DataType[] = [
{ id: 1, name: 'ZhangSan', age: 23 },
{ id: 2, name: 'LiSi', age: 17 },
{ id: 3, name: 'WangWu', age: 20 },
];

export default () => (
<Table<DataType> rowKey="id" columns={columns} dataSource={dataSource} pagination={false} />
);
65 changes: 65 additions & 0 deletions src/table/demos/group.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from 'react';
import { Table } from 'dt-react-component';

import type { ColumnsType } from '..';

interface DataType {
id: number;
name: string;
age: number;
city: string;
address: string;
}

const columns: ColumnsType<DataType> = [
{
title: 'Basic Information',
tooltip: 'Personal information',
children: [
{
title: 'Name',
dataIndex: 'name',
tooltip: 'User name',
},
{
title: 'Age',
dataIndex: 'age',
},
],
},
{
title: 'Contact Address',
children: [
{
title: 'City',
dataIndex: 'city',
},
{
title: 'Address',
dataIndex: 'address',
tooltip: 'Detailed contact address',
},
],
},
];

const dataSource: DataType[] = [
{
id: 1,
name: 'ZhangSan',
age: 17,
city: 'New York',
address: 'No. 1 Lake Park',
},
{
id: 2,
name: 'LiSi',
age: 20,
city: 'Beijing',
address: 'No. 1 Lake Park',
},
];

export default () => (
<Table<DataType> rowKey="id" columns={columns} dataSource={dataSource} pagination={false} />
);
8 changes: 7 additions & 1 deletion src/table/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ demo:

## 示例

<code src="./demos/basic.tsx" description="为标题头添加tooltip">基础使用</code>
<code src="./demos/basic.tsx" title="基础使用" description="为标题头添加 tooltip"></code>

<code src="./demos/declarative.tsx" title="声明式列" description="兼容 antd 的 Table.Column JSX 写法"></code>

<code src="./demos/dynamicTitle.tsx" title="动态表头" description="函数式 title 可根据排序状态动态更新,并与 tooltip 一起使用"></code>

<code src="./demos/group.tsx" title="分组表头" description="分组列及其子列均可配置 tooltip"></code>

## API

Expand Down
69 changes: 50 additions & 19 deletions src/table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import React, { forwardRef, useMemo } from 'react';
import { QuestionOutlined } from '@dtinsight/react-icons';
import { Table as InternalTable, Tooltip } from 'antd';
import type { LabelTooltipType, WrapperTooltipProps } from 'antd/lib/form/FormItemLabel';
import type { ColumnType as PrimitiveColumnType, TableProps } from 'antd/lib/table';
import type {
ColumnGroupType as PrimitiveColumnGroupType,
ColumnsType as PrimitiveColumnsType,
ColumnType as PrimitiveColumnType,
TableProps,
} from 'antd/lib/table';
import classNames from 'classnames';

import './index.scss';
Expand All @@ -21,12 +26,19 @@ export interface ColumnType<R = any> extends PrimitiveColumnType<R> {
tooltip?: LabelTooltipType;
}

export interface ITableProps<R = any> extends TableProps<R> {
columns?: ColumnType<R>[];
export interface ColumnGroupType<R = any> extends Omit<PrimitiveColumnGroupType<R>, 'children'> {
tooltip?: LabelTooltipType;
children: ColumnsType<R>;
}

export type ColumnsType<R = any> = (ColumnGroupType<R> | ColumnType<R>)[];

export interface ITableProps<R = any> extends Omit<TableProps<R>, 'columns'> {
columns?: ColumnsType<R>;
}

export type RefTable = <R extends object = any>(
props: React.PropsWithChildren<TableProps<R>> & { ref?: React.Ref<HTMLDivElement | unknown> }
props: React.PropsWithChildren<ITableProps<R>> & { ref?: React.Ref<HTMLDivElement> }
) => React.ReactElement;

function toTooltipProps(tooltip: LabelTooltipType): WrapperTooltipProps | null {
Expand All @@ -43,10 +55,11 @@ function toTooltipProps(tooltip: LabelTooltipType): WrapperTooltipProps | null {
};
}

function convertColumns(columns?: ColumnType[]): PrimitiveColumnType<any>[] {
if (!columns?.length) return [];
function convertColumns<R>(columns?: ColumnsType<R>): PrimitiveColumnsType<R> | undefined {
if (!columns) return undefined;

return columns.map((col) => {
const { tooltip, title } = col;
const { tooltip, title, ...restColumn } = col;

const tooltipProps = toTooltipProps(tooltip);
let tooltipNode: React.ReactNode | null = null;
Expand All @@ -61,24 +74,40 @@ function convertColumns(columns?: ColumnType[]): PrimitiveColumnType<any>[] {
);
}

const titleNode = (
<>
{title}
{tooltipNode}
</>
const convertedTitle = tooltipNode ? (
typeof title === 'function' ? (
(...args: Parameters<typeof title>) => (
<>
{title(...args)}
{tooltipNode}
</>
)
) : (
<>
{title}
{tooltipNode}
</>
)
) : (
title
);

if ('children' in col) {
return {
...restColumn,
title: convertedTitle,
children: convertColumns(col.children) || [],
} as PrimitiveColumnGroupType<R>;
}

return {
...col,
title: titleNode,
};
...restColumn,
title: convertedTitle,
} as PrimitiveColumnType<R>;
});
}

function Table<R extends Record<any, any> = any>(
props: ITableProps<R>,
ref: React.Ref<HTMLDivElement>
) {
function Table<R extends object = any>(props: ITableProps<R>, ref: React.Ref<HTMLDivElement>) {
const { columns, className, ...reset } = props;
const cols = useMemo(() => convertColumns(columns), [columns]);

Expand All @@ -93,6 +122,7 @@ function Table<R extends Record<any, any> = any>(
}

const ForwardTable = forwardRef(Table) as unknown as RefTable & {
defaultProps?: Partial<ITableProps<any>>;
SELECTION_COLUMN: typeof SELECTION_COLUMN;
EXPAND_COLUMN: typeof EXPAND_COLUMN;
SELECTION_ALL: typeof SELECTION_ALL;
Expand All @@ -104,6 +134,7 @@ const ForwardTable = forwardRef(Table) as unknown as RefTable & {
Summary: typeof InternalTable.Summary;
};

ForwardTable.defaultProps = InternalTable.defaultProps as Partial<ITableProps<any>>;
ForwardTable.SELECTION_COLUMN = SELECTION_COLUMN;
ForwardTable.EXPAND_COLUMN = EXPAND_COLUMN;
ForwardTable.SELECTION_ALL = SELECTION_ALL;
Expand Down
Loading