Skip to content

Commit 336edac

Browse files
authored
feat: Adds ability to define a scope (#859)
* add scope prop for columns * add scope test and example update README.md add colgroup example combine two scope examples * add row scope * update README.md * setting scope for columns automatically * pass thComponent as a prop * pass thComponent as a prop * fix: add tdCellComponent to props
1 parent 2c6f53d commit 336edac

File tree

16 files changed

+487
-20
lines changed

16 files changed

+487
-20
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ React.render(<Table columns={columns} data={data} />, mountNode);
129129
| fixed | String \| Boolean | | this column will be fixed when table scroll horizontally: true or 'left' or 'right' |
130130
| align | String | | specify how cell content is aligned |
131131
| ellipsis | Boolean | | specify whether cell content be ellipsized |
132+
| rowScope | 'row' \| 'rowgroup' | | Set scope attribute for all cells in this column |
132133
| onCell | Function(record, index) | | Set custom props per each cell. |
133134
| onHeaderCell | Function(record) | | Set custom props per each header cell. |
134135
| render | Function(value, row, index) | | The render function of cell, has three params: the text of this cell, the record of this row, the index of this row, it's return an object:{ children: value, props: { colSpan: 1, rowSpan:1 } } ==> 'children' is the text of this cell, props is some setting of this cell, eg: 'colspan' set td colspan, 'rowspan' set td rowspan |

assets/index.less

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@
166166

167167
// ================= Header =================
168168
thead {
169-
td,
170169
th {
171170
text-align: center;
172171
background: @table-head-background-color;
@@ -200,10 +199,13 @@
200199
// ================== Body ==================
201200
tbody {
202201
tr {
203-
td,
204-
th {
202+
td {
205203
background: #fff;
206204
}
205+
206+
th {
207+
background: @table-head-background-color;
208+
}
207209
}
208210
}
209211

docs/demo/scopeCol.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## scopeCol
2+
3+
<code src="../examples/scopeCol.tsx">

docs/demo/scopeRow.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## scopeRow
2+
3+
<code src="../examples/scopeRow.tsx">

docs/examples/scopeCol.tsx

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import type { ColumnsType } from '@/interface';
2+
import Table from 'rc-table';
3+
import '../../assets/index.less';
4+
5+
interface FirstTableRecordType {
6+
lastName?: string;
7+
firstName?: string;
8+
city?: string;
9+
key?: string;
10+
}
11+
12+
const firstTableColumns: ColumnsType<FirstTableRecordType> = [
13+
{ title: 'Last Name', dataIndex: 'lastName', key: 'lastName' },
14+
{ title: 'First Name', dataIndex: 'firstName', key: 'firstName' },
15+
{ title: 'City', dataIndex: 'city', key: 'city' },
16+
];
17+
18+
const firstTableData: FirstTableRecordType[] = [
19+
{ lastName: 'Phoenix', firstName: 'Imary', city: 'Henry', key: '1' },
20+
{ lastName: 'Zeki', firstName: 'Rome', city: 'Min', key: '2' },
21+
{ lastName: 'Apirka', firstName: 'Kelly', city: 'Brynn', key: '3' },
22+
];
23+
24+
interface SecondTableRecordType {
25+
productType?: string;
26+
producedMars?: string;
27+
soldMars?: string;
28+
producedVenus?: string;
29+
soldVenus?: string;
30+
key?: string;
31+
}
32+
33+
const secondTableColumns: ColumnsType<SecondTableRecordType> = [
34+
{
35+
title: '',
36+
dataIndex: 'productType',
37+
key: 'productType',
38+
rowSpan: 2,
39+
rowScope: 'row',
40+
},
41+
{
42+
title: 'Mars',
43+
dataIndex: 'mars',
44+
key: 'mars',
45+
children: [
46+
{ title: 'Produced', dataIndex: 'producedMars', key: 'producedMars' },
47+
{ title: 'Sold', dataIndex: 'soldMars', key: 'soldMars' },
48+
],
49+
},
50+
{
51+
title: 'Venus',
52+
dataIndex: 'venus',
53+
key: 'venus',
54+
children: [
55+
{ title: 'Produced', dataIndex: 'producedVenus', key: 'producedVenus' },
56+
{ title: 'Sold', dataIndex: 'soldVenus', key: 'soldVenus' },
57+
],
58+
},
59+
];
60+
61+
const secondTableData: SecondTableRecordType[] = [
62+
{
63+
productType: 'Teddy Bears',
64+
producedMars: '50,000',
65+
soldMars: '30,000',
66+
producedVenus: '100,000',
67+
soldVenus: '80,000',
68+
key: '1',
69+
},
70+
{
71+
productType: 'Board Games',
72+
producedMars: '10,000',
73+
soldMars: '5,000',
74+
producedVenus: '12,000',
75+
soldVenus: '9,000',
76+
key: '2',
77+
},
78+
];
79+
80+
const Demo = () => (
81+
<div>
82+
<h2>Scope col</h2>
83+
<Table<FirstTableRecordType> columns={firstTableColumns} data={firstTableData} />
84+
<br />
85+
<h2>Scope colgroup</h2>
86+
<Table<SecondTableRecordType> columns={secondTableColumns} data={secondTableData} />
87+
</div>
88+
);
89+
90+
export default Demo;

docs/examples/scopeRow.tsx

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import type { ColumnsType } from '@/interface';
2+
import Table from 'rc-table';
3+
import '../../assets/index.less';
4+
5+
interface FirstTableRecordType {
6+
time?: string;
7+
monday?: string;
8+
tuesday?: string;
9+
wednesday?: string;
10+
thursday?: string;
11+
friday?: string;
12+
key?: string;
13+
}
14+
15+
const firstTableColumns: ColumnsType<FirstTableRecordType> = [
16+
{ title: '', dataIndex: 'time', key: 'time', rowScope: 'row' },
17+
{ title: 'Monday', dataIndex: 'monday', key: 'monday' },
18+
{ title: 'Tuesday', dataIndex: 'tuesday', key: 'tuesday' },
19+
{ title: 'Wednesday', dataIndex: 'wednesday', key: 'wednesday' },
20+
{ title: 'Thursday', dataIndex: 'thursday', key: 'thursday' },
21+
{ title: 'Friday', dataIndex: 'friday', key: 'friday' },
22+
];
23+
24+
const firstTableData: FirstTableRecordType[] = [
25+
{
26+
time: '09:00 - 11:00',
27+
monday: 'Closed',
28+
tuesday: 'Open',
29+
wednesday: 'Open',
30+
thursday: 'Closed',
31+
friday: 'Closed',
32+
key: '1',
33+
},
34+
{
35+
time: '11:00 - 13:00',
36+
monday: 'Open',
37+
tuesday: 'Open',
38+
wednesday: 'Closed',
39+
thursday: 'Closed',
40+
friday: 'Closed',
41+
key: '2',
42+
},
43+
{
44+
time: '13:00 - 15:00',
45+
monday: 'Open',
46+
tuesday: 'Open',
47+
wednesday: 'Open',
48+
thursday: 'Closed',
49+
friday: 'Closed',
50+
key: '3',
51+
},
52+
{
53+
time: '15:00 - 17:00',
54+
monday: 'Closed',
55+
tuesday: 'Closed',
56+
wednesday: 'Closed',
57+
thursday: 'Open',
58+
friday: 'Open',
59+
key: '4',
60+
},
61+
];
62+
63+
interface SecondTableRecordType {
64+
posterName?: string;
65+
color?: string;
66+
sizesAvailable1?: string;
67+
sizesAvailable2?: string;
68+
sizesAvailable3?: string;
69+
key?: string;
70+
}
71+
72+
const secondTableColumns: ColumnsType<SecondTableRecordType> = [
73+
{
74+
title: 'Poster name',
75+
dataIndex: 'posterName',
76+
key: 'posterName',
77+
rowScope: 'rowgroup',
78+
onCell: (_, index) => {
79+
const props: React.TdHTMLAttributes<HTMLTableCellElement> = {};
80+
81+
if (index === 0) {
82+
props.rowSpan = 3;
83+
}
84+
85+
if (index === 3) {
86+
props.rowSpan = 2;
87+
}
88+
89+
if (index === 1 || index === 2 || index === 4) {
90+
props.rowSpan = 0;
91+
}
92+
93+
return props;
94+
},
95+
},
96+
{
97+
title: 'Color',
98+
dataIndex: 'color',
99+
key: 'color',
100+
rowScope: 'row',
101+
},
102+
{
103+
title: 'Sizes available',
104+
dataIndex: 'sizesAvailable1',
105+
colSpan: 3,
106+
key: 'sizesAvailable1',
107+
},
108+
{
109+
dataIndex: 'sizesAvailable2',
110+
colSpan: 0,
111+
},
112+
{
113+
dataIndex: 'sizesAvailable3',
114+
colSpan: 0,
115+
},
116+
];
117+
118+
const secondTableData: SecondTableRecordType[] = [
119+
{
120+
posterName: 'Zodiac',
121+
color: 'Full color',
122+
sizesAvailable1: 'A2',
123+
sizesAvailable2: 'A3',
124+
sizesAvailable3: 'A4',
125+
key: '1',
126+
},
127+
{
128+
posterName: 'Zodiac',
129+
color: 'Black and white',
130+
sizesAvailable1: 'A1',
131+
sizesAvailable2: 'A2',
132+
sizesAvailable3: 'A3',
133+
key: '2',
134+
},
135+
{
136+
posterName: 'Zodiac',
137+
color: 'Sepia',
138+
sizesAvailable1: 'A3',
139+
sizesAvailable2: 'A4',
140+
sizesAvailable3: 'A5',
141+
key: '3',
142+
},
143+
{
144+
posterName: 'Angels',
145+
color: 'Black and white',
146+
sizesAvailable1: 'A1',
147+
sizesAvailable2: 'A3',
148+
sizesAvailable3: 'A4',
149+
key: '4',
150+
},
151+
{
152+
posterName: 'Angels',
153+
color: 'Sepia',
154+
sizesAvailable1: 'A2',
155+
sizesAvailable2: 'A3',
156+
sizesAvailable3: 'A5',
157+
key: '5',
158+
},
159+
];
160+
161+
const Demo = () => (
162+
<div>
163+
<h2>Scope row</h2>
164+
<Table<FirstTableRecordType> columns={firstTableColumns} data={firstTableData} />
165+
<br />
166+
<h2>Scope rowgroup</h2>
167+
<Table<SecondTableRecordType> columns={secondTableColumns} data={secondTableData} />
168+
</div>
169+
);
170+
171+
export default Demo;

src/Body/BodyRow.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export interface BodyRowProps<RecordType> {
2424
expandedKeys: Set<Key>;
2525
rowComponent: CustomizeComponent;
2626
cellComponent: CustomizeComponent;
27+
scopeCellComponent: CustomizeComponent;
2728
onRow: GetComponentProps<RecordType>;
2829
rowExpandable: (record: RecordType) => boolean;
2930
indent?: number;
@@ -48,6 +49,7 @@ function BodyRow<RecordType extends { children?: readonly RecordType[] }>(
4849
indent = 0,
4950
rowComponent: RowComponent,
5051
cellComponent,
52+
scopeCellComponent,
5153
childrenColumnName,
5254
} = props;
5355
const { prefixCls, fixedInfoList } = useContextSelector(TableContext, [
@@ -174,7 +176,8 @@ function BodyRow<RecordType extends { children?: readonly RecordType[] }>(
174176
className={columnClassName}
175177
ellipsis={column.ellipsis}
176178
align={column.align}
177-
component={cellComponent}
179+
scope={column.rowScope}
180+
component={column.rowScope ? scopeCellComponent : cellComponent}
178181
prefixCls={prefixCls}
179182
key={key}
180183
record={record}

src/Body/index.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ function Body<RecordType>({
6363
const WrapperComponent = getComponent(['body', 'wrapper'], 'tbody');
6464
const trComponent = getComponent(['body', 'row'], 'tr');
6565
const tdComponent = getComponent(['body', 'cell'], 'td');
66+
const thComponent = getComponent(['body', 'cell'], 'th');
6667

6768
let rows: React.ReactNode;
6869
if (data.length) {
@@ -81,6 +82,7 @@ function Body<RecordType>({
8182
renderIndex={renderIndex}
8283
rowComponent={trComponent}
8384
cellComponent={tdComponent}
85+
scopeCellComponent={thComponent}
8486
expandedKeys={expandedKeys}
8587
onRow={onRow}
8688
getRowKey={getRowKey}

src/Cell/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import type {
1818
DataIndex,
1919
DefaultRecordType,
2020
RenderedCell,
21+
ScopeType,
2122
} from '../interface';
2223
import { getPathValue, validateValue } from '../utils/valueUtil';
2324

@@ -56,6 +57,7 @@ interface InternalCellProps<RecordType extends DefaultRecordType>
5657
children?: React.ReactNode;
5758
colSpan?: number;
5859
rowSpan?: number;
60+
scope?: ScopeType;
5961
ellipsis?: CellEllipsisType;
6062
align?: AlignType;
6163

@@ -119,6 +121,7 @@ function Cell<RecordType extends DefaultRecordType>(
119121
component: Component = 'td',
120122
colSpan,
121123
rowSpan, // This is already merged on WrapperCell
124+
scope,
122125
fixLeft,
123126
fixRight,
124127
firstFixLeft,
@@ -276,6 +279,7 @@ function Cell<RecordType extends DefaultRecordType>(
276279
...additionalProps,
277280
colSpan: mergedColSpan !== 1 ? mergedColSpan : null,
278281
rowSpan: mergedRowSpan !== 1 ? mergedRowSpan : null,
282+
scope,
279283
className: classNames(
280284
cellPrefixCls,
281285
className,

src/Header/Header.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ function Header<RecordType>({
104104
const WrapperComponent = getComponent(['header', 'wrapper'], 'thead');
105105
const trComponent = getComponent(['header', 'row'], 'tr');
106106
const thComponent = getComponent(['header', 'cell'], 'th');
107+
const tdComponent = getComponent(['header', 'cell'], 'td');
107108

108109
return (
109110
<WrapperComponent className={`${prefixCls}-thead`}>
@@ -116,6 +117,7 @@ function Header<RecordType>({
116117
stickyOffsets={stickyOffsets}
117118
rowComponent={trComponent}
118119
cellComponent={thComponent}
120+
tdCellComponent={tdComponent}
119121
onHeaderRow={onHeaderRow}
120122
index={rowIndex}
121123
/>

0 commit comments

Comments
 (0)