diff --git a/components/table/Table.tsx b/components/table/Table.tsx index a4a0204537..f409d30c5c 100644 --- a/components/table/Table.tsx +++ b/components/table/Table.tsx @@ -29,6 +29,7 @@ import { } from './interface'; import useSelection, { SELECTION_ALL, + SELECTION_COLUMN, SELECTION_INVERT, SELECTION_NONE, } from './hooks/useSelection'; @@ -375,7 +376,6 @@ function InternalTable( expandType, childrenColumnName, locale: tableLocale, - expandIconColumnIndex: mergedExpandable.expandIconColumnIndex, getPopupContainer, }); @@ -524,6 +524,8 @@ type InternalTableType = typeof ForwardTable; interface TableInterface extends InternalTableType { defaultProps?: Partial>; + SELECTION_COLUMN: typeof SELECTION_COLUMN; + EXPAND_COLUMN: typeof RcTable.EXPAND_COLUMN; SELECTION_ALL: 'SELECT_ALL'; SELECTION_INVERT: 'SELECT_INVERT'; SELECTION_NONE: 'SELECT_NONE'; @@ -538,6 +540,8 @@ Table.defaultProps = { rowKey: 'key', }; +Table.SELECTION_COLUMN = SELECTION_COLUMN; +Table.EXPAND_COLUMN = RcTable.EXPAND_COLUMN; Table.SELECTION_ALL = SELECTION_ALL; Table.SELECTION_INVERT = SELECTION_INVERT; Table.SELECTION_NONE = SELECTION_NONE; diff --git a/components/table/__tests__/Table.order.test.js b/components/table/__tests__/Table.order.test.js new file mode 100644 index 0000000000..e9356170fc --- /dev/null +++ b/components/table/__tests__/Table.order.test.js @@ -0,0 +1,76 @@ +import React from 'react'; +import { mount } from 'enzyme'; +import Table from '..'; +import { resetWarned } from '../../_util/devWarning'; + +describe('Table.order', () => { + window.requestAnimationFrame = callback => window.setTimeout(callback, 16); + window.cancelAnimationFrame = window.clearTimeout; + + const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); + + afterEach(() => { + errorSpy.mockReset(); + }); + + afterAll(() => { + errorSpy.mockRestore(); + }); + + const columns = [ + { + title: 'Name', + dataIndex: 'name', + }, + ]; + + const data = [ + { key: 0, name: 'Jack' }, + { key: 1, name: 'Lucy' }, + { key: 2, name: 'Tom' }, + { key: 3, name: 'Jerry' }, + ]; + + function createTable(props = {}) { + return ; + } + + it('warning if duplicated SELECTION_COLUMN', () => { + resetWarned(); + mount( + createTable({ + columns: [Table.SELECTION_COLUMN, Table.SELECTION_COLUMN], + rowSelection: {}, + expandable: { + expandedRowRender: () => null, + }, + }), + ); + + expect(errorSpy).toHaveBeenCalledWith( + 'Warning: [antd: Table] Multiple `SELECTION_COLUMN` exist in `columns`.', + ); + }); + + it('auto fixed', () => { + const wrapper = mount( + createTable({ + columns: [ + { + dataIndex: 'name', + fixed: true, + }, + Table.SELECTION_COLUMN, + { + dataIndex: 'key', + }, + ], + rowSelection: {}, + }), + ); + + expect(wrapper.find('tr').last().find('td')).toHaveLength(3); + expect(wrapper.find('tr').last().find('td.ant-table-cell-fix-left')).toHaveLength(2); + wrapper.unmount(); + }); +}); diff --git a/components/table/__tests__/__snapshots__/demo.test.js.snap b/components/table/__tests__/__snapshots__/demo.test.js.snap index 1232f46c03..5a33e70d63 100644 --- a/components/table/__tests__/__snapshots__/demo.test.js.snap +++ b/components/table/__tests__/__snapshots__/demo.test.js.snap @@ -12196,6 +12196,370 @@ exports[`renders ./components/table/demo/nested-table.md correctly 1`] = ` `; +exports[`renders ./components/table/demo/order-column.md correctly 1`] = ` +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Name + + + Age + +
+ +
+
+ Address +
+ John Brown + + + 32 + + + + New York No. 1 Lake Park +
+ Jim Green + + + 42 + + + + London No. 1 Lake Park +
+ Not Expandable + + + 29 + + + + Jiangsu No. 1 Lake Park +
+ Joe Black + + + 32 + + + + Sidney No. 1 Lake Park +
+ + + + + + + +`; + exports[`renders ./components/table/demo/pagination.md correctly 1`] = `
diff --git a/components/table/demo/order-column.md b/components/table/demo/order-column.md new file mode 100644 index 0000000000..40aefdccb7 --- /dev/null +++ b/components/table/demo/order-column.md @@ -0,0 +1,70 @@ +--- +order: 14.1 +version: 4.18.0 +title: + en-US: Order Specific Column + zh-CN: 特殊列排序 +--- + +## zh-CN + +你可以通过 `Table.EXPAND_COLUMN` 和 `Table.SELECT_COLUMN` 来控制选择和展开列的顺序。 + +## en-US + +You can control the order of the expand and select columns by using `Table.EXPAND_COLUMN` and `Table.SELECT_COLUMN`. + +```jsx +import { Table } from 'antd'; + +const columns = [ + { title: 'Name', dataIndex: 'name', key: 'name' }, + Table.EXPAND_COLUMN, + { title: 'Age', dataIndex: 'age', key: 'age' }, + Table.SELECTION_COLUMN, + { title: 'Address', dataIndex: 'address', key: 'address' }, +]; + +const data = [ + { + key: 1, + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + description: 'My name is John Brown, I am 32 years old, living in New York No. 1 Lake Park.', + }, + { + key: 2, + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + description: 'My name is Jim Green, I am 42 years old, living in London No. 1 Lake Park.', + }, + { + key: 3, + name: 'Not Expandable', + age: 29, + address: 'Jiangsu No. 1 Lake Park', + description: 'This not expandable', + }, + { + key: 4, + name: 'Joe Black', + age: 32, + address: 'Sidney No. 1 Lake Park', + description: 'My name is Joe Black, I am 32 years old, living in Sidney No. 1 Lake Park.', + }, +]; + +ReactDOM.render( +

{record.description}

, + }} + dataSource={data} + />, + mountNode, +); +``` diff --git a/components/table/hooks/useSelection.tsx b/components/table/hooks/useSelection.tsx index 92144902d7..aa0898447d 100644 --- a/components/table/hooks/useSelection.tsx +++ b/components/table/hooks/useSelection.tsx @@ -17,6 +17,7 @@ import { TableRowSelection, Key, ColumnsType, + ColumnType, GetRowKey, TableLocale, SelectionItem, @@ -26,14 +27,12 @@ import { } from '../interface'; // TODO: warning if use ajax!!! + +export const SELECTION_COLUMN = {} as const; export const SELECTION_ALL = 'SELECT_ALL' as const; export const SELECTION_INVERT = 'SELECT_INVERT' as const; export const SELECTION_NONE = 'SELECT_NONE' as const; -function getFixedType(column: ColumnsType[number]): FixedType | undefined { - return column && column.fixed; -} - interface UseSelectionConfig { prefixCls: string; pageData: RecordType[]; @@ -42,7 +41,6 @@ interface UseSelectionConfig { getRecordByKey: (key: Key) => RecordType; expandType: ExpandType; childrenColumnName: string; - expandIconColumnIndex?: number; locale: TableLocale; getPopupContainer?: GetPopupContainer; } @@ -105,7 +103,6 @@ export default function useSelection( expandType, childrenColumnName, locale: tableLocale, - expandIconColumnIndex, getPopupContainer, } = config; @@ -347,11 +344,21 @@ export default function useSelection( // ======================= Columns ======================== const transformColumns = useCallback( (columns: ColumnsType): ColumnsType => { + // >>>>>>>>>>> Skip if not exists `rowSelection` if (!rowSelection) { - return columns; + if (process.env.NODE_ENV !== 'production') { + devWarning( + !columns.includes(SELECTION_COLUMN), + 'Table', + '`rowSelection` is not config but `SELECTION_COLUMN` exists in the `columns`.', + ); + } + + return columns.filter(col => col !== SELECTION_COLUMN); } - // Support selection + // >>>>>>>>>>> Support selection + let cloneColumns = [...columns]; const keySet = new Set(derivedSelectedKeySet); // Record key only need check with enabled @@ -619,8 +626,62 @@ export default function useSelection( return node; }; - // Columns + // Insert selection column if not exist + if (!cloneColumns.includes(SELECTION_COLUMN)) { + // Always after expand icon + if ( + cloneColumns.findIndex( + (col: any) => col[INTERNAL_COL_DEFINE]?.columnType === 'EXPAND_COLUMN', + ) === 0 + ) { + const [expandColumn, ...restColumns] = cloneColumns; + cloneColumns = [expandColumn, SELECTION_COLUMN, ...restColumns]; + } else { + // Normal insert at first column + cloneColumns = [SELECTION_COLUMN, ...cloneColumns]; + } + } + + // Deduplicate selection column + const selectionColumnIndex = cloneColumns.indexOf(SELECTION_COLUMN); + if ( + process.env.NODE_ENV !== 'production' && + cloneColumns.filter(col => col === SELECTION_COLUMN).length > 1 + ) { + devWarning(false, 'Table', 'Multiple `SELECTION_COLUMN` exist in `columns`.'); + } + cloneColumns = cloneColumns.filter( + (column, index) => column !== SELECTION_COLUMN || index === selectionColumnIndex, + ); + + // Fixed column logic + const prevCol: ColumnType & Record = + cloneColumns[selectionColumnIndex - 1]; + const nextCol: ColumnType & Record = + cloneColumns[selectionColumnIndex + 1]; + + let mergedFixed: FixedType | undefined = fixed; + + if (mergedFixed === undefined) { + if (nextCol?.fixed !== undefined) { + mergedFixed = nextCol.fixed; + } else if (prevCol?.fixed !== undefined) { + mergedFixed = prevCol.fixed; + } + } + + if ( + mergedFixed && + prevCol && + prevCol[INTERNAL_COL_DEFINE]?.columnType === 'EXPAND_COLUMN' && + prevCol.fixed === undefined + ) { + prevCol.fixed = mergedFixed; + } + + // Replace with real selection column const selectionColumn = { + fixed: mergedFixed, width: selectionColWidth, className: `${prefixCls}-selection-column`, title: rowSelection.columnTitle || title, @@ -630,15 +691,7 @@ export default function useSelection( }, }; - if (expandType === 'row' && columns.length && !expandIconColumnIndex) { - const [expandColumn, ...restColumns] = columns; - const selectionFixed = fixed || getFixedType(restColumns[0]); - if (selectionFixed) { - expandColumn.fixed = selectionFixed; - } - return [expandColumn, { ...selectionColumn, fixed: selectionFixed }, ...restColumns]; - } - return [{ ...selectionColumn, fixed: fixed || getFixedType(columns[0]) }, ...columns]; + return cloneColumns.map(col => (col === SELECTION_COLUMN ? selectionColumn : col)); }, [ getRowKey, diff --git a/components/table/index.en-US.md b/components/table/index.en-US.md index 40bb98d5f4..d3c599feeb 100644 --- a/components/table/index.en-US.md +++ b/components/table/index.en-US.md @@ -178,18 +178,14 @@ Properties for expandable. | expandedRowKeys | Current expanded row keys | string\[] | - | | | expandedRowRender | Expanded container render for each row | function(record, index, indent, expanded): ReactNode | - | | | expandIcon | Customize row expand Icon. Ref [example](https://codesandbox.io/s/fervent-bird-nuzpr) | function(props): ReactNode | - | | -| expandIconColumnIndex | Customize expand icon column index. Not render when `-1` | number | - | | | expandRowByClick | Whether to expand row by clicking anywhere in the whole row | boolean | false | | | fixed | Whether the expansion icon is fixed. Optional true `left` `right` | boolean \| string | false | 4.16.0 | | indentSize | Indent size in pixels of tree data | number | 15 | | | rowExpandable | Enable row can be expandable | (record) => boolean | - | | +| showExpandColumn | Show expand column | boolean | true | 4.18.0 | | onExpand | Callback executed when the row expand icon is clicked | function(expanded, record) | - | | | onExpandedRowsChange | Callback executed when the expanded rows change | function(expandedRows) | - | | -- `fixed` - - When set to true or `left` and `expandIconColumnIndex` is not set or is 0, enable fixed - - When set to true or `right` and `expandIconColumnIndex` is set to the number of table columns, enable fixed - ### rowSelection Properties for row selection. diff --git a/components/table/index.zh-CN.md b/components/table/index.zh-CN.md index 90953a0ef2..755a367757 100644 --- a/components/table/index.zh-CN.md +++ b/components/table/index.zh-CN.md @@ -185,18 +185,14 @@ const columns = [ | expandedRowKeys | 展开的行,控制属性 | string\[] | - | | | expandedRowRender | 额外的展开行 | function(record, index, indent, expanded): ReactNode | - | | | expandIcon | 自定义展开图标,参考[示例](https://codesandbox.io/s/fervent-bird-nuzpr) | function(props): ReactNode | - | | -| expandIconColumnIndex | 自定义展开按钮的列顺序,`-1` 时不展示 | number | - | | | expandRowByClick | 通过点击行来展开子行 | boolean | false | | | fixed | 控制展开图标是否固定,可选 true `left` `right` | boolean \| string | false | 4.16.0 | | indentSize | 展示树形数据时,每层缩进的宽度,以 px 为单位 | number | 15 | | | rowExpandable | 设置是否允许行展开 | (record) => boolean | - | | +| showExpandColumn | 设置是否展示行展开列 | boolean | true | 4.18.0 | | onExpand | 点击展开图标时触发 | function(expanded, record) | - | | | onExpandedRowsChange | 展开的行变化时触发 | function(expandedRows) | - | | -- `fixed` - - 当设置为 true 或 `left` 且 `expandIconColumnIndex` 未设置或为 0 时,开启固定 - - 当设置为 true 或 `right` 且 `expandIconColumnIndex` 设置为表格列数时,开启固定 - ### rowSelection 选择功能的配置。 diff --git a/components/table/interface.tsx b/components/table/interface.tsx index 5a47df62d8..a88f85a426 100644 --- a/components/table/interface.tsx +++ b/components/table/interface.tsx @@ -4,6 +4,7 @@ import { ColumnType as RcColumnType, RenderedCell as RcRenderedCell, ExpandableConfig, + FixedType, } from 'rc-table/lib/interface'; import { TooltipProps } from '../tooltip'; import { CheckboxProps } from '../checkbox'; @@ -159,7 +160,7 @@ export interface TableRowSelection { onSelectNone?: () => void; selections?: INTERNAL_SELECTION_ITEM[] | boolean; hideSelectAll?: boolean; - fixed?: boolean; + fixed?: FixedType; columnWidth?: string | number; columnTitle?: string | React.ReactNode; checkStrictly?: boolean; diff --git a/package.json b/package.json index 779faf8ba4..9fb6a2504b 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "rc-slider": "~9.7.4", "rc-steps": "~4.1.0", "rc-switch": "~3.2.0", - "rc-table": "~7.19.0", + "rc-table": "~7.20.0", "rc-tabs": "~11.10.0", "rc-textarea": "~0.3.0", "rc-tooltip": "~5.1.1",