Skip to content

Commit 06dcb66

Browse files
authored
feat: Support EXPAND_COLUMN (#704)
* feat: support EXPAND_COLUMN * feat: showExpandColumn * test: tet case * test: more check * test: patch hover test case
1 parent a0b2cd0 commit 06dcb66

File tree

7 files changed

+163
-52
lines changed

7 files changed

+163
-52
lines changed

src/Table.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import FixedHolder from './FixedHolder';
7676
import type { SummaryProps } from './Footer/Summary';
7777
import Summary from './Footer/Summary';
7878
import StickyContext from './context/StickyContext';
79+
import { EXPAND_COLUMN } from './constant';
7980

8081
// Used for conditions cache
8182
const EMPTY_DATA = [];
@@ -106,7 +107,8 @@ const MemoTableContent = React.memo<MemoTableContentProps>(
106107
},
107108
);
108109

109-
export interface TableProps<RecordType = unknown> extends LegacyExpandableProps<RecordType> {
110+
export interface TableProps<RecordType = unknown>
111+
extends Omit<LegacyExpandableProps<RecordType>, 'showExpandColumn'> {
110112
prefixCls?: string;
111113
className?: string;
112114
style?: React.CSSProperties;
@@ -849,6 +851,8 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
849851
);
850852
}
851853

854+
Table.EXPAND_COLUMN = EXPAND_COLUMN;
855+
852856
Table.Column = Column;
853857

854858
Table.ColumnGroup = ColumnGroup;

src/constant.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const EXPAND_COLUMN = {} as const;

src/hooks/useColumns.tsx

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import type {
1212
ColumnGroupType,
1313
} from '../interface';
1414
import { INTERNAL_COL_DEFINE } from '../utils/legacyUtil';
15+
import { EXPAND_COLUMN } from '../constant';
1516

1617
export function convertChildrenToColumns<RecordType>(
1718
children: React.ReactNode,
@@ -144,11 +145,41 @@ function useColumns<RecordType>(
144145
[columns, children],
145146
);
146147

147-
// Add expand column
148+
// ========================== Expand ==========================
148149
const withExpandColumns = React.useMemo<ColumnsType<RecordType>>(() => {
149150
if (expandable) {
150-
const expandColIndex = expandIconColumnIndex || 0;
151-
const prevColumn = baseColumns[expandColIndex];
151+
let cloneColumns = baseColumns.slice();
152+
153+
// >>> Warning if use `expandIconColumnIndex`
154+
if (process.env.NODE_ENV !== 'production' && expandIconColumnIndex >= 0) {
155+
warning(
156+
false,
157+
'`expandIconColumnIndex` is deprecated. Please use `Table.EXPAND_COLUMN` in `columns` instead.',
158+
);
159+
}
160+
161+
// >>> Insert expand column if not exist
162+
if (!cloneColumns.includes(EXPAND_COLUMN)) {
163+
const expandColIndex = expandIconColumnIndex || 0;
164+
if (expandColIndex >= 0) {
165+
cloneColumns.splice(expandColIndex, 0, EXPAND_COLUMN);
166+
}
167+
}
168+
169+
// >>> Deduplicate additional expand column
170+
if (
171+
process.env.NODE_ENV !== 'production' &&
172+
cloneColumns.filter(c => c === EXPAND_COLUMN).length > 1
173+
) {
174+
warning(false, 'There exist more than one `EXPAND_COLUMN` in `columns`.');
175+
}
176+
const expandColumnIndex = cloneColumns.indexOf(EXPAND_COLUMN);
177+
cloneColumns = cloneColumns.filter(
178+
(column, index) => column !== EXPAND_COLUMN || index === expandColumnIndex,
179+
);
180+
181+
// >>> Check if expand column need to fixed
182+
const prevColumn = baseColumns[expandColumnIndex];
152183

153184
let fixedColumn: FixedType | null;
154185
if ((fixed === 'left' || fixed) && !expandIconColumnIndex) {
@@ -159,6 +190,7 @@ function useColumns<RecordType>(
159190
fixedColumn = prevColumn ? prevColumn.fixed : null;
160191
}
161192

193+
// >>> Create expandable column
162194
const expandColumn = {
163195
[INTERNAL_COL_DEFINE]: {
164196
className: `${prefixCls}-expand-icon-col`,
@@ -187,16 +219,12 @@ function useColumns<RecordType>(
187219
},
188220
};
189221

190-
// Insert expand column in the target position
191-
const cloneColumns = baseColumns.slice();
192-
if (expandColIndex >= 0) {
193-
cloneColumns.splice(expandColIndex, 0, expandColumn);
194-
}
195-
return cloneColumns;
222+
return cloneColumns.map(col => (col === EXPAND_COLUMN ? expandColumn : col));
196223
}
197224
return baseColumns;
198225
}, [expandable, baseColumns, getRowKey, expandedKeys, expandIcon, direction]);
199226

227+
// ========================= Transform ========================
200228
const mergedColumns = React.useMemo(() => {
201229
let finalColumns = withExpandColumns;
202230
if (transformColumns) {
@@ -214,6 +242,7 @@ function useColumns<RecordType>(
214242
return finalColumns;
215243
}, [transformColumns, withExpandColumns, direction]);
216244

245+
// ========================== Flatten =========================
217246
const flattenColumns = React.useMemo(() => {
218247
if (direction === 'rtl') {
219248
return revertForRtl(flatColumns(mergedColumns));

src/interface.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,9 @@ export interface ExpandableConfig<RecordType> {
206206
onExpandedRowsChange?: (expandedKeys: readonly Key[]) => void;
207207
defaultExpandAllRows?: boolean;
208208
indentSize?: number;
209+
/** @deprecated Please use `EXPAND_COLUMN` in `columns` directly */
209210
expandIconColumnIndex?: number;
211+
showExpandColumn?: boolean;
210212
expandedRowClassName?: RowClassName<RecordType>;
211213
childrenColumnName?: string;
212214
rowExpandable?: (record: RecordType) => boolean;

src/utils/legacyUtil.ts

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,32 +9,40 @@ export function getExpandableProps<RecordType>(
99
},
1010
): ExpandableConfig<RecordType> {
1111
const { expandable, ...legacyExpandableConfig } = props;
12+
let config: ExpandableConfig<RecordType>;
1213

1314
if ('expandable' in props) {
14-
return {
15+
config = {
1516
...legacyExpandableConfig,
1617
...expandable,
1718
};
19+
} else {
20+
if (
21+
process.env.NODE_ENV !== 'production' &&
22+
[
23+
'indentSize',
24+
'expandedRowKeys',
25+
'defaultExpandedRowKeys',
26+
'defaultExpandAllRows',
27+
'expandedRowRender',
28+
'expandRowByClick',
29+
'expandIcon',
30+
'onExpand',
31+
'onExpandedRowsChange',
32+
'expandedRowClassName',
33+
'expandIconColumnIndex',
34+
'showExpandColumn',
35+
].some(prop => prop in props)
36+
) {
37+
warning(false, 'expanded related props have been moved into `expandable`.');
38+
}
39+
40+
config = legacyExpandableConfig;
1841
}
1942

20-
if (
21-
process.env.NODE_ENV !== 'production' &&
22-
[
23-
'indentSize',
24-
'expandedRowKeys',
25-
'defaultExpandedRowKeys',
26-
'defaultExpandAllRows',
27-
'expandedRowRender',
28-
'expandRowByClick',
29-
'expandIcon',
30-
'onExpand',
31-
'onExpandedRowsChange',
32-
'expandedRowClassName',
33-
'expandIconColumnIndex',
34-
].some(prop => prop in props)
35-
) {
36-
warning(false, 'expanded related props have been moved into `expandable`.');
43+
if (config.showExpandColumn === false) {
44+
config.expandIconColumnIndex = -1;
3745
}
3846

39-
return legacyExpandableConfig;
47+
return config;
4048
}

tests/ExpandRow.spec.js

Lines changed: 87 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -200,31 +200,95 @@ describe('Table.Expand', () => {
200200
expect(wrapper2.find('.rc-table-has-fix-right').length).toBe(0);
201201
});
202202

203-
it('renders expand icon to the specify column', () => {
204-
const wrapper = mount(
205-
createTable({
206-
expandable: {
207-
expandedRowRender,
208-
expandIconColumnIndex: 1,
209-
},
210-
}),
211-
);
212-
expect(
213-
wrapper.find('tbody tr td').at(1).hasClass('rc-table-row-expand-icon-cell'),
214-
).toBeTruthy();
203+
describe('config expand column index', () => {
204+
it('renders expand icon to the specify column', () => {
205+
resetWarned();
206+
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
207+
208+
const wrapper = mount(
209+
createTable({
210+
expandable: {
211+
expandedRowRender,
212+
expandIconColumnIndex: 1,
213+
},
214+
}),
215+
);
216+
expect(
217+
wrapper.find('tbody tr td').at(1).hasClass('rc-table-row-expand-icon-cell'),
218+
).toBeTruthy();
219+
220+
expect(errorSpy).toHaveBeenCalledWith(
221+
'Warning: `expandIconColumnIndex` is deprecated. Please use `Table.EXPAND_COLUMN` in `columns` instead.',
222+
);
223+
errorSpy.mockRestore();
224+
});
225+
226+
it('order with EXPAND_COLUMN', () => {
227+
const wrapper = mount(
228+
createTable({
229+
columns: [...sampleColumns, Table.EXPAND_COLUMN],
230+
expandable: {
231+
expandedRowRender,
232+
},
233+
}),
234+
);
235+
236+
expect(
237+
wrapper.find('tbody tr td').at(2).hasClass('rc-table-row-expand-icon-cell'),
238+
).toBeTruthy();
239+
});
240+
241+
it('de-duplicate of EXPAND_COLUMN', () => {
242+
resetWarned();
243+
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
244+
245+
const wrapper = mount(
246+
createTable({
247+
columns: [Table.EXPAND_COLUMN, ...sampleColumns, Table.EXPAND_COLUMN],
248+
expandable: {
249+
expandedRowRender,
250+
},
251+
}),
252+
);
253+
254+
expect(
255+
wrapper.find('tbody tr td').at(0).hasClass('rc-table-row-expand-icon-cell'),
256+
).toBeTruthy();
257+
expect(wrapper.find('tbody tr').first().find('td')).toHaveLength(3);
258+
259+
expect(errorSpy).toHaveBeenCalledWith(
260+
'Warning: There exist more than one `EXPAND_COLUMN` in `columns`.',
261+
);
262+
263+
errorSpy.mockRestore();
264+
});
215265
});
216266

217-
// https://github.com/ant-design/ant-design/issues/24129
218-
it('should not render expand icon column when expandIconColumnIndex is negative', () => {
219-
const wrapper = mount(
220-
createTable({
221-
expandable: {
222-
expandedRowRender,
223-
expandIconColumnIndex: -1,
224-
},
225-
}),
226-
);
227-
expect(wrapper.find('.rc-table-row-expand-icon-cell').length).toBe(0);
267+
describe('hide expandColumn', () => {
268+
// https://github.com/ant-design/ant-design/issues/24129
269+
it('should not render expand icon column when expandIconColumnIndex is negative', () => {
270+
const wrapper = mount(
271+
createTable({
272+
expandable: {
273+
expandedRowRender,
274+
expandIconColumnIndex: -1,
275+
},
276+
}),
277+
);
278+
expect(wrapper.find('.rc-table-row-expand-icon-cell').length).toBe(0);
279+
});
280+
281+
it('showExpandColumn = false', () => {
282+
const wrapper = mount(
283+
createTable({
284+
expandable: {
285+
expandedRowRender,
286+
showExpandColumn: false,
287+
},
288+
}),
289+
);
290+
expect(wrapper.find('.rc-table-row-expand-icon-cell').length).toBe(0);
291+
});
228292
});
229293

230294
it('renders a custom icon', () => {

tests/Table.spec.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -938,6 +938,9 @@ describe('Table.Basic', () => {
938938
const wrapper = mount(createTable());
939939
wrapper.find('tbody td').first().simulate('mouseEnter');
940940
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeTruthy();
941+
942+
wrapper.find('tbody td').first().simulate('mouseLeave');
943+
expect(wrapper.exists('.rc-table-cell-row-hover')).toBeFalsy();
941944
});
942945

943946
it('skip when config should cell update', () => {

0 commit comments

Comments
 (0)