Skip to content

feat: support classNames and styles #1261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
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
14 changes: 14 additions & 0 deletions docs/examples/className.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ const Demo = () => (
expandedRowClassName={(record, i) => `ex-row-${i}`}
data={data}
className="table"
title={() => <span>title</span>}
footer={() => <span>footer</span>}
/>
<h2>scroll</h2>
<Table
columns={columns}
rowClassName={(record, i) => `row-${i}`}
expandedRowRender={record => <p>extra: {record.a}</p>}
expandedRowClassName={(record, i) => `ex-row-${i}`}
data={Array(5).fill(data)}
className="table"
scroll={{ x: 'calc(700px + 50%)', y: 47 * 5 }}
title={() => <span>title</span>}
footer={() => <span>footer</span>}
/>
</div>
);
Expand Down
11 changes: 8 additions & 3 deletions src/Cell/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useContext } from '@rc-component/context';
import classNames from 'classnames';
import cls from 'classnames';
import * as React from 'react';
import TableContext from '../context/TableContext';
import devRenderTimes from '../hooks/useRenderTimes';
Expand Down Expand Up @@ -122,9 +122,12 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
} = props;

const cellPrefixCls = `${prefixCls}-cell`;
const { allColumnsFixedLeft, rowHoverable } = useContext(TableContext, [

const { allColumnsFixedLeft, rowHoverable, classNames, styles } = useContext(TableContext, [
'allColumnsFixedLeft',
'rowHoverable',
'classNames',
'styles',
]);

// ====================== Value =======================
Expand Down Expand Up @@ -212,8 +215,9 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
});

// >>>>> ClassName
const mergedClassName = classNames(
const mergedClassName = cls(
cellPrefixCls,
classNames?.item,
className,
{
// Fixed
Expand Down Expand Up @@ -249,6 +253,7 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
...fixedStyle,
...alignStyle,
...additionalProps.style,
...styles?.item,
};

// >>>>> Children Node
Expand Down
3 changes: 3 additions & 0 deletions src/FixedHolder/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ function useColumnWidth(colWidths: readonly number[], columCount: number) {

export interface FixedHeaderProps<RecordType> extends HeaderProps<RecordType> {
className: string;
style?: React.CSSProperties;
noData: boolean;
maxContentScroll: boolean;
colWidths: readonly number[];
Expand All @@ -46,6 +47,7 @@ const FixedHolder = React.forwardRef<HTMLDivElement, FixedHeaderProps<any>>((pro

const {
className,
style,
noData,
columns,
flattenColumns,
Expand Down Expand Up @@ -159,6 +161,7 @@ const FixedHolder = React.forwardRef<HTMLDivElement, FixedHeaderProps<any>>((pro
style={{
overflow: 'hidden',
...(isSticky ? { top: stickyTopOffset, bottom: stickyBottomOffset } : {}),
...style,
}}
ref={setScrollRef}
className={classNames(className, {
Expand Down
5 changes: 3 additions & 2 deletions src/Panel/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import * as React from 'react';
export interface TitleProps {
className: string;
children: React.ReactNode;
style: React.CSSProperties;
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

样式属性应该是可选的

TitleProps 接口中,新增的 style 属性被定义为必须项,这可能会导致现有使用 Panel 组件的地方出现兼容性问题。建议将其修改为可选属性。

-  style: React.CSSProperties;
+  style?: React.CSSProperties;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
style: React.CSSProperties;
style?: React.CSSProperties;

}

function Panel({ className, children }: TitleProps) {
return <div className={className}>{children}</div>;
function Panel({ className, style, children }: TitleProps) {
return <div className={className} style={style}>{children}</div>;
}

export default Panel;
27 changes: 19 additions & 8 deletions src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
*/

import type { CompareProps } from '@rc-component/context/lib/Immutable';
import classNames from 'classnames';
import cls from 'classnames';
import ResizeObserver from '@rc-component/resize-observer';
import isVisible from '@rc-component/util/lib/Dom/isVisible';
import { getTargetScrollBarSize } from '@rc-component/util/lib/getScrollBarSize';
Expand Down Expand Up @@ -85,11 +85,14 @@ const EMPTY_DATA = [];
// Used for customize scroll
const EMPTY_SCROLL_TARGET = {};

export type SemanticName = 'section'| 'header' | 'title' | 'footer' | 'body' | 'content' | 'item';
export interface TableProps<RecordType = any>
extends Omit<LegacyExpandableProps<RecordType>, 'showExpandColumn'> {
prefixCls?: string;
className?: string;
style?: React.CSSProperties;
classNames?: Partial<Record<SemanticName, string>>;
styles?: Partial<Record<SemanticName, React.CSSProperties>>;
children?: React.ReactNode;
data?: readonly RecordType[];
columns?: ColumnsType<RecordType>;
Expand Down Expand Up @@ -190,6 +193,8 @@ function Table<RecordType extends DefaultRecordType>(
className,
rowClassName,
style,
classNames,
styles,
data,
rowKey,
scroll,
Expand Down Expand Up @@ -655,10 +660,11 @@ function Table<RecordType extends DefaultRecordType>(
style={{
...scrollXStyle,
...scrollYStyle,
...styles?.body,
}}
onScroll={onBodyScroll}
ref={scrollBodyRef}
className={classNames(`${prefixCls}-body`)}
className={cls(`${prefixCls}-body`, classNames?.body)}
>
<TableComponent
style={{
Expand Down Expand Up @@ -698,7 +704,8 @@ function Table<RecordType extends DefaultRecordType>(
<FixedHolder
{...fixedHolderProps}
stickyTopOffset={offsetHeader}
className={`${prefixCls}-header`}
className={cls(`${prefixCls}-header`, classNames?.header)}
style={styles?.header}
ref={scrollHeaderRef}
>
{renderFixedHeaderTable}
Expand Down Expand Up @@ -739,8 +746,9 @@ function Table<RecordType extends DefaultRecordType>(
style={{
...scrollXStyle,
...scrollYStyle,
...styles?.content,
}}
className={classNames(`${prefixCls}-content`)}
className={cls(`${prefixCls}-content`, classNames?.content)}
onScroll={onInternalScroll}
ref={scrollBodyRef}
>
Expand Down Expand Up @@ -773,7 +781,7 @@ function Table<RecordType extends DefaultRecordType>(

let fullTable = (
<div
className={classNames(prefixCls, className, {
className={cls(prefixCls, className, {
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-fix-start-shadow`]: horizonScroll,
[`${prefixCls}-fix-end-shadow`]: horizonScroll,
Expand All @@ -792,11 +800,11 @@ function Table<RecordType extends DefaultRecordType>(
ref={fullTableRef}
{...dataProps}
>
{title && <Panel className={`${prefixCls}-title`}>{title(mergedData)}</Panel>}
<div ref={scrollBodyContainerRef} className={`${prefixCls}-container`}>
{title && <Panel className={cls(`${prefixCls}-title`, classNames?.title)} style={styles?.title}>{title(mergedData)}</Panel>}
<div ref={scrollBodyContainerRef} className={cls(`${prefixCls}-container`, classNames?.section)} style={styles?.section}>
{groupTableNode}
</div>
{footer && <Panel className={`${prefixCls}-footer`}>{footer(mergedData)}</Panel>}
{footer && <Panel className={cls(`${prefixCls}-footer`, classNames?.footer)} style={styles?.footer}>{footer(mergedData)}</Panel>}
</div>
);

Expand All @@ -812,6 +820,9 @@ function Table<RecordType extends DefaultRecordType>(
scrollX: mergedScrollX,
scrollInfo,

classNames,
styles,

// Table
prefixCls,
getComponent,
Expand Down
3 changes: 3 additions & 0 deletions src/context/TableContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
TriggerEventHandler,
} from '../interface';
import type { FixedInfo } from '../utils/fixUtil';
import { SemanticName } from '../Table';

const { makeImmutable, responseImmutable, useImmutableMark } = createImmutable();
export { makeImmutable, responseImmutable, useImmutableMark };
Expand All @@ -23,6 +24,8 @@ export type ScrollInfoType = [scrollLeft: number, scrollRange: number];
export interface TableContextProps<RecordType = any> {
// Scroll
scrollX: number | string | true;
classNames?: Partial<Record<SemanticName, string>>;
styles?: Partial<Record<SemanticName, React.CSSProperties>>;

// Table
prefixCls: string;
Expand Down
112 changes: 112 additions & 0 deletions tests/semantic.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { render, fireEvent } from '@testing-library/react';
import React from 'react';
import Table, { TableProps } from '../src';
describe('support classNames and styles', () => {
const columns: TableProps['columns'] = [
{
title: 'title1',
dataIndex: 'a',
className: 'a',
key: 'a',
width: 100,
},
{
title: 'title2',
dataIndex: 'b',
className: 'b',
key: 'b',
width: 100,
},
{
title: 'title3',
dataIndex: 'c',
className: 'c',
key: 'c',
width: 200,
},
{
title: 'Operations',
dataIndex: '',
className: 'd',
key: 'd',
render() {
return <a href="#">Operations</a>;
},
},
];

const data = [
{ a: '123', key: '1' },
{ a: 'cdd', b: 'edd', key: '2' },
{ a: '1333', c: 'eee', d: 2, key: '3' },
];
const commonTableProps = {
columns: columns,
rowClassName: (record, i) => `row-${i}`,
expandedRowRender: (record) => <p>extra: {record.a}</p>,
expandedRowClassName: (record, i) => `ex-row-${i}`,
className: "table",
title: () => <span>title</span>,
footer: () => <span>footer</span>,
};
it('should support className and style', () => {
const testClassNames = {
section: 'test-section',
header: 'test-header',
title: 'test-title',
body: 'test-body',
footer: 'test-footer',
content: 'test-content',
item: 'test-item',
}
const testStyles = {
section: { background: 'red' },
header: { background: 'blue' },
title: { background: 'green' },
body: { background: 'yellow' },
footer: { background: 'pink' },
content: { background: 'purple' },
item: { background: 'orange' },
}
const { container } = render(
<Table
{...commonTableProps}
classNames={testClassNames}
styles={testStyles}
data={data}
/>
)
const section = container.querySelector('.rc-table-container');
const title = container.querySelector('.rc-table-title');
const footer = container.querySelector('.rc-table-footer');
const content = container.querySelector('.rc-table-content');
const item = container.querySelector('.rc-table-cell');
expect(section).toHaveClass(testClassNames.section);
expect(section).toHaveStyle(testStyles.section);
expect(title).toHaveClass(testClassNames.title);
expect(title).toHaveStyle(testStyles.title);
expect(footer).toHaveClass(testClassNames.footer);
expect(footer).toHaveStyle(testStyles.footer);
expect(content).toHaveClass(testClassNames.content);
expect(content).toHaveStyle(testStyles.content);
expect(item).toHaveClass(testClassNames.item);
expect(item).toHaveStyle(testStyles.item);

const { container: scrollContainer } = render(
<Table
{...commonTableProps}
classNames={testClassNames}
styles={testStyles}
data={data}
scroll={{ y: 200 }}
/>
)
const header = scrollContainer.querySelector('.rc-table-header');
const body = scrollContainer.querySelector('.rc-table-body');
expect(header).toHaveClass(testClassNames.header);
expect(header).toHaveStyle(testStyles.header);
expect(body).toHaveClass(testClassNames.body);
expect(body).toHaveStyle(testStyles.body);
})
})