Skip to content

Commit d891771

Browse files
committed
feat: Table add prop "colHoverable"
1 parent 489e40f commit d891771

File tree

9 files changed

+121
-27
lines changed

9 files changed

+121
-27
lines changed

src/Body/BodyRow.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,8 @@ function BodyRow<RecordType extends { children?: readonly RecordType[] }>(
165165
prefixCls={prefixCls}
166166
key={key}
167167
record={record}
168-
index={index}
168+
colIndex={colIndex}
169+
rowIndex={index}
169170
renderIndex={renderIndex}
170171
dataIndex={dataIndex}
171172
render={render}

src/Cell/index.tsx

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,9 @@ export interface CellProps<RecordType extends DefaultRecordType> {
2020
prefixCls?: string;
2121
className?: string;
2222
record?: RecordType;
23+
colIndex?: number;
2324
/** `column` index is the real show rowIndex */
24-
index?: number;
25+
rowIndex?: number;
2526
/** the index of the record. For the render(value, record, renderIndex) */
2627
renderIndex?: number;
2728
dataIndex?: DataIndex<RecordType>;
@@ -95,8 +96,10 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
9596
renderIndex,
9697
shouldCellUpdate,
9798

99+
colIndex,
100+
98101
// Row
99-
index,
102+
rowIndex,
100103
rowType,
101104

102105
// Span
@@ -118,10 +121,9 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
118121
} = props;
119122

120123
const cellPrefixCls = `${prefixCls}-cell`;
121-
const { supportSticky, allColumnsFixedLeft, rowHoverable } = useContext(TableContext, [
124+
const { supportSticky, allColumnsFixedLeft } = useContext(TableContext, [
122125
'supportSticky',
123126
'allColumnsFixedLeft',
124-
'rowHoverable',
125127
]);
126128

127129
// ====================== Value =======================
@@ -153,19 +155,26 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
153155
const mergedRowSpan = legacyCellProps?.rowSpan ?? additionalProps.rowSpan ?? rowSpan ?? 1;
154156

155157
// ====================== Hover =======================
156-
const [hovering, onHover] = useHoverState(index, mergedRowSpan);
158+
const [rowHovering, colHovering, onRowHover, onColHover] = useHoverState(
159+
rowIndex,
160+
mergedRowSpan,
161+
colIndex,
162+
mergedColSpan,
163+
);
157164

158165
const onMouseEnter: React.MouseEventHandler<HTMLTableCellElement> = useEvent(event => {
159166
if (record) {
160-
onHover(index, index + mergedRowSpan - 1);
167+
onRowHover(rowIndex, rowIndex + mergedRowSpan - 1);
168+
onColHover(colIndex, colIndex + mergedColSpan - 1);
161169
}
162170

163171
additionalProps?.onMouseEnter?.(event);
164172
});
165173

166174
const onMouseLeave: React.MouseEventHandler<HTMLTableCellElement> = useEvent(event => {
167175
if (record) {
168-
onHover(-1, -1);
176+
onRowHover(-1, -1);
177+
onColHover(-1, -1);
169178
}
170179

171180
additionalProps?.onMouseLeave?.(event);
@@ -200,7 +209,8 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
200209
[`${cellPrefixCls}-ellipsis`]: ellipsis,
201210
[`${cellPrefixCls}-with-append`]: appendNode,
202211
[`${cellPrefixCls}-fix-sticky`]: (isFixLeft || isFixRight) && isSticky && supportSticky,
203-
[`${cellPrefixCls}-row-hover`]: !legacyCellProps && hovering,
212+
[`${cellPrefixCls}-row-hover`]: !legacyCellProps && rowHovering,
213+
[`${cellPrefixCls}-col-hover`]: !legacyCellProps && colHovering,
204214
},
205215
additionalProps.className,
206216
legacyCellProps?.className,
@@ -247,8 +257,8 @@ function Cell<RecordType>(props: CellProps<RecordType>) {
247257
title={title}
248258
scope={scope}
249259
// Hover
250-
onMouseEnter={rowHoverable ? onMouseEnter : undefined}
251-
onMouseLeave={rowHoverable ? onMouseLeave : undefined}
260+
onMouseEnter={onMouseEnter}
261+
onMouseLeave={onMouseLeave}
252262
//Span
253263
colSpan={mergedColSpan !== 1 ? mergedColSpan : null}
254264
rowSpan={mergedRowSpan !== 1 ? mergedRowSpan : null}

src/Cell/useHoverState.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ function inHoverRange(cellStartRow: number, cellRowSpan: number, startRow: numbe
1111
export default function useHoverState(
1212
rowIndex: number,
1313
rowSpan: number,
14-
): [hovering: boolean, onHover: OnHover] {
14+
colIndex: number,
15+
colSpan: number,
16+
): [hovering: boolean, colHovering: boolean, onRowHover: OnHover, onColHover: OnHover] {
1517
return useContext(TableContext, ctx => {
16-
const hovering = inHoverRange(rowIndex, rowSpan || 1, ctx.hoverStartRow, ctx.hoverEndRow);
18+
const rowHovering =
19+
ctx.rowHoverable && inHoverRange(rowIndex, rowSpan || 1, ctx.hoverStartRow, ctx.hoverEndRow);
20+
const colHovering =
21+
ctx.colHoverable && inHoverRange(colIndex, colSpan || 1, ctx.hoverStartCol, ctx.hoverEndCol);
1722

18-
return [hovering, ctx.onHover];
23+
return [rowHovering, colHovering, ctx.onRowHover, ctx.onColHover];
1924
});
2025
}

src/Footer/Cell.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default function SummaryCell({
3939
return (
4040
<Cell
4141
className={className}
42-
index={index}
42+
rowIndex={index}
4343
component="td"
4444
prefixCls={prefixCls}
4545
record={null}

src/Table.tsx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ export interface TableProps<RecordType = any>
122122

123123
sticky?: boolean | TableSticky;
124124

125+
colHoverable?: boolean;
125126
rowHoverable?: boolean;
126127

127128
// Events
@@ -221,6 +222,7 @@ function Table<RecordType extends DefaultRecordType>(
221222
getContainerWidth,
222223

223224
sticky,
225+
colHoverable = false,
224226
rowHoverable = true,
225227
} = props;
226228

@@ -274,7 +276,7 @@ function Table<RecordType extends DefaultRecordType>(
274276
const customizeScrollBody = getComponent(['body']) as CustomizeScrollBody<RecordType>;
275277

276278
// ====================== Hover =======================
277-
const [startRow, endRow, onHover] = useHover();
279+
const [startRow, endRow, startCol, endCol, onRowHover, onColHover] = useHover();
278280

279281
// ====================== Expand ======================
280282
const [
@@ -835,17 +837,22 @@ function Table<RecordType extends DefaultRecordType>(
835837
flattenColumns,
836838
onColumnResize,
837839

840+
hoverStartCol: startCol,
841+
hoverEndCol: endCol,
842+
onColHover,
843+
838844
// Row
839845
hoverStartRow: startRow,
840846
hoverEndRow: endRow,
841-
onHover,
847+
onRowHover,
842848
rowExpandable: expandableConfig.rowExpandable,
843849
onRow,
844850

845851
getRowKey,
846852
expandedKeys: mergedExpandedKeys,
847853
childrenColumnName: mergedChildrenColumnName,
848854

855+
colHoverable,
849856
rowHoverable,
850857
}),
851858
[
@@ -884,17 +891,22 @@ function Table<RecordType extends DefaultRecordType>(
884891
flattenColumns,
885892
onColumnResize,
886893

894+
startCol,
895+
endCol,
896+
onColHover,
897+
887898
// Row
888899
startRow,
889900
endRow,
890-
onHover,
901+
onRowHover,
891902
expandableConfig.rowExpandable,
892903
onRow,
893904

894905
getRowKey,
895906
mergedExpandedKeys,
896907
mergedChildrenColumnName,
897908

909+
colHoverable,
898910
rowHoverable,
899911
],
900912
);

src/VirtualTable/VirtualCell.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ function VirtualCell<RecordType = any>(props: VirtualCellProps<RecordType>) {
120120
prefixCls={rowInfo.prefixCls}
121121
key={key}
122122
record={record}
123-
index={index}
123+
rowIndex={index}
124+
colIndex={colIndex}
124125
renderIndex={renderIndex}
125126
dataIndex={dataIndex}
126127
render={mergedRender}

src/context/TableContext.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,16 +57,21 @@ export interface TableContextProps<RecordType = any> {
5757
flattenColumns: readonly ColumnType<RecordType>[];
5858
onColumnResize: (columnKey: React.Key, width: number) => void;
5959

60+
hoverStartCol: number;
61+
hoverEndCol: number;
62+
onColHover: (start: number, end: number) => void;
63+
6064
// Row
6165
hoverStartRow: number;
6266
hoverEndRow: number;
63-
onHover: (start: number, end: number) => void;
67+
onRowHover: (start: number, end: number) => void;
6468
rowExpandable: (record: RecordType) => boolean;
6569

6670
expandedKeys: Set<React.Key>;
6771
getRowKey: GetRowKey<RecordType>;
6872
childrenColumnName: string;
6973

74+
colHoverable?: boolean;
7075
rowHoverable?: boolean;
7176
}
7277

src/hooks/useHover.ts

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,28 @@ import * as React from 'react';
22

33
export type OnHover = (start: number, end: number) => void;
44

5-
export default function useHover(): [startRow: number, endRow: number, onHover: OnHover] {
5+
export default function useHover(): [
6+
startRow: number,
7+
endRow: number,
8+
startCol: number,
9+
endCol: number,
10+
onRowHover: OnHover,
11+
onColHover: OnHover,
12+
] {
613
const [startRow, setStartRow] = React.useState(-1);
714
const [endRow, setEndRow] = React.useState(-1);
15+
const [startCol, setStartCol] = React.useState(-1);
16+
const [endCol, setEndCol] = React.useState(-1);
817

9-
const onHover = React.useCallback<OnHover>((start, end) => {
18+
const onRowHover = React.useCallback<OnHover>((start, end) => {
1019
setStartRow(start);
1120
setEndRow(end);
1221
}, []);
1322

14-
return [startRow, endRow, onHover];
23+
const onColHover = React.useCallback<OnHover>((start, end) => {
24+
setStartCol(start);
25+
setEndCol(end);
26+
}, []);
27+
28+
return [startRow, endRow, startCol, endCol, onRowHover, onColHover];
1529
}

tests/Hover.spec.tsx

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ describe('Table.Hover', () => {
1313
const createTable = (props?: TableProps) => {
1414
const columns = [{ title: 'Name', dataIndex: 'name', key: 'name' }];
1515

16-
return <Table columns={columns} data={data} {...props} />;
16+
return <Table columns={columns} data={data} colHoverable {...props} />;
1717
};
1818

1919
it('basic', () => {
2020
const wrapper = mount(createTable());
2121
wrapper.find('tbody td').first().simulate('mouseEnter');
2222
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeTruthy();
23+
expect(wrapper.exists('.rc-table-cell-col-hover')).toBeTruthy();
2324

2425
wrapper.find('tbody td').first().simulate('mouseLeave');
2526
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy();
27+
expect(wrapper.exists('.rc-table-cell-col-hover')).toBeFalsy();
2628
});
2729

2830
it('works on shouldCellUpdate', () => {
@@ -34,9 +36,11 @@ describe('Table.Hover', () => {
3436

3537
wrapper.find('tbody td').first().simulate('mouseEnter');
3638
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeTruthy();
39+
expect(wrapper.exists('.rc-table-cell-col-hover')).toBeTruthy();
3740

3841
wrapper.find('tbody td').first().simulate('mouseLeave');
3942
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy();
43+
expect(wrapper.exists('.rc-table-cell-col-hover')).toBeFalsy();
4044
});
4145

4246
it('warning if use `render` for rowSpan', () => {
@@ -151,7 +155,7 @@ describe('Table.Hover', () => {
151155
renderTimes = 0;
152156
wrapper.find('tbody td').at(0).simulate('mouseEnter');
153157
expect(wrapper.find('td.rc-table-cell-row-hover')).toHaveLength(1);
154-
expect(renderTimes).toBe(1);
158+
expect(renderTimes).toBe(2);
155159

156160
// Hover 0-1
157161
renderTimes = 0;
@@ -163,7 +167,7 @@ describe('Table.Hover', () => {
163167
renderTimes = 0;
164168
wrapper.find('tbody td').at(1).simulate('mouseLeave');
165169
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy();
166-
expect(renderTimes).toBe(1);
170+
expect(renderTimes).toBe(2);
167171
});
168172

169173
it('perf mode to save render times', () => {
@@ -204,7 +208,7 @@ describe('Table.Hover', () => {
204208
});
205209
});
206210

207-
it('perf', () => {
211+
it('perf row', () => {
208212
const renderTimes: Record<string, any> = {};
209213

210214
const TD = (props: any) => {
@@ -217,6 +221,7 @@ describe('Table.Hover', () => {
217221

218222
const wrapper = mount(
219223
createTable({
224+
colHoverable: false,
220225
components: {
221226
body: {
222227
cell: TD,
@@ -229,11 +234,52 @@ describe('Table.Hover', () => {
229234

230235
wrapper.find('tbody td').first().simulate('mouseEnter');
231236
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeTruthy();
237+
expect(wrapper.exists('.rc-table-cell-col-hover')).toBeFalsy();
232238

233239
wrapper.find('tbody td').first().simulate('mouseLeave');
234240
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy();
241+
expect(wrapper.exists('.rc-table-cell-col-hover')).toBeFalsy();
235242

236243
expect(firstMountTimes).toEqual(renderTimes.Jack);
237244
expect(renderTimes.Lucy).toBeGreaterThan(renderTimes.Jack);
238245
});
246+
247+
it('perf col', () => {
248+
const renderTimes: Record<string, any> = {};
249+
250+
const TD = (props: any) => {
251+
const children = toArray(props.children);
252+
const first = children[0] as unknown as string;
253+
254+
renderTimes[first] = (renderTimes[first] || 0) + 1;
255+
return <td {...props} />;
256+
};
257+
258+
const columns = [
259+
{ title: 'index', dataIndex: 'key', key: 'key' },
260+
{ title: 'Name', dataIndex: 'name', key: 'name' },
261+
];
262+
263+
const wrapper = mount(
264+
createTable({
265+
columns,
266+
rowHoverable: false,
267+
components: {
268+
body: {
269+
cell: TD,
270+
},
271+
},
272+
}),
273+
);
274+
275+
wrapper.find('tbody td').at(1).simulate('mouseEnter');
276+
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy();
277+
expect(wrapper.exists('.rc-table-cell-col-hover')).toBeTruthy();
278+
279+
wrapper.find('tbody td').at(1).simulate('mouseLeave');
280+
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy();
281+
expect(wrapper.exists('.rc-table-cell-col-hover')).toBeFalsy();
282+
283+
expect(renderTimes.Lucy).toEqual(renderTimes.Jack);
284+
});
239285
});

0 commit comments

Comments
 (0)