| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410 | 
							- /* eslint-disable no-nested-ternary */
 
- /* eslint-disable prefer-const */
 
- /* eslint-disable prefer-destructuring */
 
- /* eslint-disable no-shadow */
 
- /* eslint-disable no-param-reassign */
 
- /* eslint-disable max-len */
 
- /* eslint-disable react/no-did-update-set-state */
 
- /* eslint-disable eqeqeq */
 
- /* eslint-disable max-lines-per-function */
 
- import React, { ReactNode, createRef, isValidElement } from 'react';
 
- import PropTypes from 'prop-types';
 
- import classnames from 'classnames';
 
- import {
 
-     get,
 
-     noop,
 
-     includes,
 
-     find,
 
-     findIndex,
 
-     some,
 
-     debounce,
 
-     flattenDeep,
 
-     each,
 
-     omit,
 
-     isNull,
 
-     difference,
 
-     isFunction,
 
-     isObject
 
- } from 'lodash';
 
- import {
 
-     mergeQueries,
 
-     equalWith,
 
-     mergeColumns,
 
-     isAnyFixedRight,
 
-     assignColumnKeys,
 
-     flattenColumns,
 
-     getAllDisabledRowKeys
 
- } from '@douyinfe/semi-foundation/table/utils';
 
- import Store from '@douyinfe/semi-foundation/utils/Store';
 
- import TableFoundation, { TableAdapter, BasePageData, BaseRowKeyType, BaseHeadWidth } from '@douyinfe/semi-foundation/table/foundation';
 
- import { TableSelectionCellEvent } from '@douyinfe/semi-foundation/table/tableSelectionCellFoundation';
 
- import { strings, cssClasses, numbers } from '@douyinfe/semi-foundation/table/constants';
 
- import '@douyinfe/semi-foundation/table/table.scss';
 
- import Spin from '../spin';
 
- import BaseComponent from '../_base/baseComponent';
 
- import LocaleConsumer from '../locale/localeConsumer';
 
- import ColumnShape from './ColumnShape';
 
- import getColumns from './getColumns';
 
- import TableContext, { TableContextProps } from './table-context';
 
- import TableContextProvider from './TableContextProvider';
 
- import ColumnSelection from './ColumnSelection';
 
- import TablePagination from './TablePagination';
 
- import ColumnFilter, { OnSelectData } from './ColumnFilter';
 
- import ColumnSorter from './ColumnSorter';
 
- import ExpandedIcon from './CustomExpandIcon';
 
- import HeadTable, { HeadTableProps } from './HeadTable';
 
- import BodyTable, { BodyProps } from './Body';
 
- import { measureScrollbar, logger, cloneDeep, mergeComponents } from './utils';
 
- import {
 
-     ColumnProps,
 
-     TablePaginationProps,
 
-     BodyScrollEvent,
 
-     BodyScrollPosition,
 
-     ExpandIcon,
 
-     ColumnTitleProps,
 
-     Pagination,
 
-     RenderPagination,
 
-     TableLocale,
 
-     TableProps,
 
-     TableComponents,
 
-     RowSelectionProps,
 
-     Data
 
- } from './interface';
 
- import { ArrayElement } from '../_base/base';
 
- export type NormalTableProps<RecordType extends Record<string, any> = Data> = Omit<TableProps<RecordType>, 'resizable'>;
 
- export interface NormalTableState<RecordType extends Record<string, any> = Data> {
 
-     cachedColumns?: ColumnProps<RecordType>[];
 
-     cachedChildren?: React.ReactNode;
 
-     flattenColumns?: ColumnProps<RecordType>[];
 
-     components?: TableComponents;
 
-     queries?: ColumnProps<RecordType>[];
 
-     dataSource?: RecordType[];
 
-     flattenData?: RecordType[];
 
-     expandedRowKeys?: (string | number)[];
 
-     rowSelection?: TableStateRowSelection<RecordType>;
 
-     pagination?: Pagination;
 
-     groups?: Map<string, RecordType[]>;
 
-     allRowKeys?: (string | number)[];
 
-     disabledRowKeys?: (string | number)[];
 
-     disabledRowKeysSet?: Set<string | number>;
 
-     headWidths?: Array<Array<BaseHeadWidth>>;
 
-     bodyHasScrollBar?: boolean;
 
-     prePropRowSelection?: TableStateRowSelection<RecordType>;
 
-     tableWidth?: number;
 
-     prePagination?: Pagination;
 
- }
 
- export type TableStateRowSelection<RecordType extends Record<string, any> = Data> = (RowSelectionProps<RecordType> & { selectedRowKeysSet?: Set<(string | number)> }) | boolean;
 
- export interface RenderTableProps<RecordType> extends HeadTableProps, BodyProps {
 
-     filteredColumns: ColumnProps<RecordType>[];
 
-     useFixedHeader: boolean;
 
-     bodyRef: React.MutableRefObject<HTMLDivElement> | ((instance: any) => void);
 
-     rowSelection: TableStateRowSelection<RecordType>;
 
-     bodyHasScrollBar: boolean;
 
- }
 
- class Table<RecordType extends Record<string, any>> extends BaseComponent<NormalTableProps<RecordType>, NormalTableState<RecordType>> {
 
-     static contextType = TableContext;
 
-     static propTypes = {
 
-         className: PropTypes.string,
 
-         style: PropTypes.object,
 
-         prefixCls: PropTypes.string,
 
-         components: PropTypes.any,
 
-         bordered: PropTypes.bool,
 
-         loading: PropTypes.bool,
 
-         size: PropTypes.oneOf(strings.SIZES),
 
-         tableLayout: PropTypes.oneOf(strings.LAYOUTS),
 
-         columns: PropTypes.arrayOf(PropTypes.shape(ColumnShape)),
 
-         hideExpandedColumn: PropTypes.bool,
 
-         id: PropTypes.string,
 
-         expandIcon: PropTypes.oneOfType([PropTypes.bool, PropTypes.func, PropTypes.node]),
 
-         expandCellFixed: PropTypes.oneOf(strings.FIXED_SET),
 
-         title: PropTypes.oneOfType([PropTypes.string, PropTypes.node, PropTypes.func]),
 
-         onHeaderRow: PropTypes.func,
 
-         showHeader: PropTypes.bool,
 
-         indentSize: PropTypes.number,
 
-         rowKey: PropTypes.oneOfType([PropTypes.func, PropTypes.string, PropTypes.number]),
 
-         onRow: PropTypes.func,
 
-         onExpandedRowsChange: PropTypes.func,
 
-         onExpand: PropTypes.func,
 
-         rowExpandable: PropTypes.func,
 
-         expandedRowRender: PropTypes.func,
 
-         expandedRowKeys: PropTypes.array,
 
-         defaultExpandAllRows: PropTypes.bool,
 
-         expandAllRows: PropTypes.bool,
 
-         defaultExpandAllGroupRows: PropTypes.bool,
 
-         expandAllGroupRows: PropTypes.bool,
 
-         defaultExpandedRowKeys: PropTypes.array,
 
-         pagination: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
 
-         renderPagination: PropTypes.func,
 
-         footer: PropTypes.oneOfType([PropTypes.func, PropTypes.string, PropTypes.node]),
 
-         empty: PropTypes.node,
 
-         dataSource: PropTypes.array,
 
-         childrenRecordName: PropTypes.string, // children data property name
 
-         rowSelection: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
 
-         onChange: PropTypes.func,
 
-         scroll: PropTypes.shape({
 
-             x: PropTypes.oneOfType([PropTypes.number, PropTypes.string, PropTypes.bool]),
 
-             y: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
 
-         }),
 
-         groupBy: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]),
 
-         renderGroupSection: PropTypes.oneOfType([PropTypes.func]),
 
-         onGroupedRow: PropTypes.func,
 
-         clickGroupedRowToExpand: PropTypes.bool,
 
-         virtualized: PropTypes.oneOfType([PropTypes.object, PropTypes.bool]),
 
-         dropdownPrefixCls: PropTypes.string, // TODO: future api
 
-         expandRowByClick: PropTypes.bool, // TODO: future api
 
-         getVirtualizedListRef: PropTypes.func, // TODO: future api
 
-     };
 
-     static defaultProps = {
 
-         // rowExpandable: stubTrue,
 
-         tableLayout: '',
 
-         dataSource: [] as [],
 
-         prefixCls: cssClasses.PREFIX,
 
-         rowSelection: null as null,
 
-         className: '',
 
-         childrenRecordName: 'children',
 
-         size: 'default',
 
-         loading: false,
 
-         bordered: false,
 
-         expandCellFixed: false,
 
-         hideExpandedColumn: true,
 
-         showHeader: true,
 
-         indentSize: numbers.DEFAULT_INDENT_WIDTH,
 
-         onChange: noop,
 
-         pagination: true,
 
-         rowKey: 'key',
 
-         defaultExpandedRowKeys: [] as [],
 
-         defaultExpandAllRows: false,
 
-         defaultExpandAllGroupRows: false,
 
-         expandAllRows: false,
 
-         expandAllGroupRows: false,
 
-         onFilterDropdownVisibleChange: noop,
 
-         onExpand: noop,
 
-         onExpandedRowsChange: noop,
 
-         expandRowByClick: false,
 
-     };
 
-     get adapter(): TableAdapter<RecordType> {
 
-         return {
 
-             ...super.adapter,
 
-             resetScrollY: () => {
 
-                 if (this.bodyWrapRef.current) {
 
-                     this.bodyWrapRef.current.scrollTop = 0;
 
-                 }
 
-             },
 
-             setSelectedRowKeys: selectedRowKeys => {
 
-                 this.setState({ rowSelection: {
 
-                     ...this.state.rowSelection as Record<string, any>,
 
-                     selectedRowKeys: [...selectedRowKeys],
 
-                     selectedRowKeysSet: new Set(selectedRowKeys),
 
-                 } });
 
-             },
 
-             setDisabledRowKeys: disabledRowKeys => {
 
-                 this.setState({ disabledRowKeys, disabledRowKeysSet: new Set(disabledRowKeys) });
 
-             },
 
-             setCurrentPage: currentPage => {
 
-                 const { pagination } = this.state;
 
-                 if (typeof pagination === 'object') {
 
-                     this.setState({ pagination: { ...pagination, currentPage } });
 
-                 } else {
 
-                     this.setState({ pagination: { currentPage } });
 
-                 }
 
-             },
 
-             setPagination: pagination => this.setState({ pagination }),
 
-             setGroups: groups => this.setState({ groups }),
 
-             setDataSource: dataSource => this.setState({ dataSource }),
 
-             setExpandedRowKeys: expandedRowKeys => this.setState({ expandedRowKeys: [...expandedRowKeys] }),
 
-             setQuery: (query = {}) => {
 
-                 let queries = [...this.state.queries];
 
-                 queries = mergeQueries(query, queries);
 
-                 this.setState({ queries });
 
-             },
 
-             // Update queries when filtering or sorting
 
-             setQueries: (queries: ColumnProps<RecordType>[]) => this.setState({ queries }),
 
-             setFlattenData: flattenData => this.setState({ flattenData }),
 
-             setAllRowKeys: allRowKeys => this.setState({ allRowKeys }),
 
-             setHoveredRowKey: hoveredRowKey => {
 
-                 this.store.setState({ hoveredRowKey });
 
-             },
 
-             setCachedFilteredSortedDataSource: filteredSortedDataSource => {
 
-                 this.cachedFilteredSortedDataSource = filteredSortedDataSource;
 
-             },
 
-             setCachedFilteredSortedRowKeys: filteredSortedRowKeys => {
 
-                 this.cachedFilteredSortedRowKeys = filteredSortedRowKeys;
 
-                 this.cachedFilteredSortedRowKeysSet = new Set(filteredSortedRowKeys);
 
-             },
 
-             getCurrentPage: () => get(this.state, 'pagination.currentPage', 1),
 
-             getCurrentPageSize: () => get(this.state, 'pagination.pageSize', numbers.DEFAULT_PAGE_SIZE),
 
-             getCachedFilteredSortedDataSource: () => this.cachedFilteredSortedDataSource,
 
-             getCachedFilteredSortedRowKeys: () => this.cachedFilteredSortedRowKeys,
 
-             getCachedFilteredSortedRowKeysSet: () => this.cachedFilteredSortedRowKeysSet,
 
-             notifyFilterDropdownVisibleChange: (visible, dataIndex) =>
 
-                 this._invokeColumnFn(dataIndex, 'onFilterDropdownVisibleChange', visible),
 
-             notifyChange: (...args) => this.props.onChange(...args),
 
-             notifyExpand: (...args) => this.props.onExpand(...args),
 
-             notifyExpandedRowsChange: (...args) => this.props.onExpandedRowsChange(...args),
 
-             notifySelect: (...args) => this._invokeRowSelection('onSelect', ...args),
 
-             notifySelectAll: (...args) => this._invokeRowSelection('onSelectAll', ...args),
 
-             notifySelectInvert: (...args) => this._invokeRowSelection('onSelectInvert', ...args),
 
-             notifySelectionChange: (...args) => this._invokeRowSelection('onChange', ...args),
 
-             isAnyColumnFixed: (columns: ColumnProps<RecordType>[]) =>
 
-                 some(this.getColumns(columns || this.props.columns, this.props.children), column => Boolean(column.fixed)),
 
-             useFixedHeader: () => {
 
-                 const { scroll } = this.props;
 
-                 if (get(scroll, 'y')) {
 
-                     return true;
 
-                 }
 
-                 return false;
 
-             },
 
-             setHeadWidths: (headWidths: Array<BaseHeadWidth>, index = 0) => {
 
-                 if (!equalWith(this.state.headWidths[index], headWidths)) {
 
-                     // The map call depends on the last state
 
-                     this.setState(state => {
 
-                         const newHeadWidths: Array<Array<BaseHeadWidth>> = [...state.headWidths];
 
-                         newHeadWidths[index] = [...headWidths];
 
-                         return { headWidths: newHeadWidths };
 
-                     });
 
-                 }
 
-             },
 
-             getHeadWidths: (index = 0) => {
 
-                 if (this.state.headWidths.length && typeof index === 'number') {
 
-                     const configs = this.state.headWidths[index] || [];
 
-                     return configs.map(item => item.width);
 
-                 }
 
-                 return [];
 
-             },
 
-             // This method is called by row rendering function
 
-             getCellWidths: (flattenedColumns: ColumnProps<RecordType>[], flattenedWidths: BaseHeadWidth[] = null, ignoreScrollBarKey = false): number[] => {
 
-                 if (Array.isArray(flattenedColumns) && flattenedColumns.length) {
 
-                     flattenedWidths =
 
-                         flattenedWidths == null && this.state.headWidths.length ?
 
-                             flattenDeep(this.state.headWidths) :
 
-                             [];
 
-                     if (
 
-                         Array.isArray(flattenedWidths) &&
 
-                         flattenedWidths.length
 
-                     ) {
 
-                         return flattenedColumns.reduce((result, column) => {
 
-                             const found =
 
-                                 column.key === strings.DEFAULT_KEY_COLUMN_SCROLLBAR && ignoreScrollBarKey ?
 
-                                     null :
 
-                                     find(
 
-                                         flattenedWidths,
 
-                                         item => item && item.key != null && item.key === column.key
 
-                                     );
 
-                             if (found) {
 
-                                 result.push(found.width);
 
-                             }
 
-                             return result;
 
-                         }, [] as number[]);
 
-                     }
 
-                 }
 
-                 return [];
 
-             },
 
-             mergedRowExpandable: record => {
 
-                 const { expandedRowRender, childrenRecordName, rowExpandable } = this.props;
 
-                 const children = get(record, childrenRecordName);
 
-                 const hasExpandedRowRender = typeof expandedRowRender === 'function';
 
-                 const hasRowExpandable = typeof rowExpandable === 'function';
 
-                 const hasChildren = Array.isArray(children) && children.length;
 
-                 const strictExpandableResult = hasRowExpandable && rowExpandable(record);
 
-                 const looseExpandableResult = !hasRowExpandable || strictExpandableResult;
 
-                 return (
 
-                     ((hasExpandedRowRender || hasChildren) && looseExpandableResult) ||
 
-                     (!(hasExpandedRowRender || hasChildren) && strictExpandableResult)
 
-                 );
 
-             },
 
-             isAnyColumnUseFullRender: (columns: ColumnProps<RecordType>[]) =>
 
-                 some(columns, column => Boolean(column.useFullRender)),
 
-             getNormalizeColumns: () => this.normalizeColumns,
 
-             getHandleColumns: () => this.handleColumns,
 
-             getMergePagination: () => this.mergePagination,
 
-             setBodyHasScrollbar: bodyHasScrollBar => {
 
-                 if (bodyHasScrollBar !== this.state.bodyHasScrollBar) {
 
-                     this.setState({ bodyHasScrollBar });
 
-                 }
 
-             }
 
-         };
 
-     }
 
-     bodyWrapRef: React.MutableRefObject<HTMLDivElement>;
 
-     rootWrapRef: React.MutableRefObject<HTMLDivElement>;
 
-     wrapRef: React.MutableRefObject<HTMLDivElement>;
 
-     headerWrapRef: React.MutableRefObject<HTMLDivElement>;
 
-     debouncedWindowResize: () => void;
 
-     cachedFilteredSortedDataSource: RecordType[];
 
-     cachedFilteredSortedRowKeys: BaseRowKeyType[];
 
-     cachedFilteredSortedRowKeysSet: Set<string | number>;
 
-     store: Store;
 
-     lastScrollTop!: number;
 
-     lastScrollLeft!: number;
 
-     scrollPosition!: BodyScrollPosition;
 
-     position!: BodyScrollPosition;
 
-     foundation: TableFoundation<RecordType>;
 
-     context: TableContextProps;
 
-     constructor(props: NormalTableProps<RecordType>, context: TableContextProps) {
 
-         super(props);
 
-         this.foundation = new TableFoundation<RecordType>(this.adapter);
 
-         // columns cannot be deepClone, otherwise the comparison will be false
 
-         const columns = this.getColumns(props.columns, props.children);
 
-         const cachedflattenColumns = flattenColumns(columns);
 
-         this.state = {
 
-             /**
 
-              * Cached props
 
-              */
 
-             cachedColumns: columns, // update cachedColumns after columns or children change
 
-             cachedChildren: props.children,
 
-             flattenColumns: cachedflattenColumns,
 
-             components: mergeComponents(props.components, props.virtualized), // cached components
 
-             /**
 
-              * State calculated based on prop
 
-              */
 
-             queries: cloneDeep(cachedflattenColumns), // flatten columns, update when sorting or filtering
 
-             dataSource: [], // data after paging
 
-             flattenData: [],
 
-             expandedRowKeys: [...(props.expandedRowKeys || []), ...(props.defaultExpandedRowKeys || [])], // cached expandedRowKeys
 
-             rowSelection: props.rowSelection ? isObject(props.rowSelection) ? { ...props.rowSelection } : {} : null,
 
-             pagination:
 
-                 props.pagination && typeof props.pagination === 'object' ?
 
-                     { ...props.pagination } :
 
-                     props.pagination || false,
 
-             /**
 
-              * Internal state
 
-              */
 
-             groups: null,
 
-             allRowKeys: [], // row keys after paging
 
-             disabledRowKeys: [], // disabled row keys after paging
 
-             disabledRowKeysSet: new Set(),
 
-             headWidths: [], // header cell width
 
-             bodyHasScrollBar: false,
 
-             prePropRowSelection: undefined,
 
-             prePagination: undefined
 
-         };
 
-         this.rootWrapRef = createRef();
 
-         this.wrapRef = createRef(); // table's outside wrap
 
-         this.bodyWrapRef = createRef();
 
-         this.headerWrapRef = createRef();
 
-         this.store = new Store({
 
-             hoveredRowKey: null,
 
-         });
 
-         this.setScrollPosition('left');
 
-         this.debouncedWindowResize = debounce(this.handleWindowResize, 150);
 
-         this.cachedFilteredSortedDataSource = [];
 
-         this.cachedFilteredSortedRowKeys = [];
 
-         this.cachedFilteredSortedRowKeysSet = new Set();
 
-     }
 
-     static getDerivedStateFromProps(props: NormalTableProps, state: NormalTableState) {
 
-         const willUpdateStates: Partial<NormalTableState> = {};
 
-         const { rowSelection, dataSource, childrenRecordName, rowKey, pagination } = props;
 
-         props.columns && props.children && logger.warn('columns should not given by object and children at the same time');
 
-         if (props.columns && props.columns !== state.cachedColumns) {
 
-             const newFlattenColumns = flattenColumns(props.columns);
 
-             willUpdateStates.flattenColumns = newFlattenColumns;
 
-             willUpdateStates.queries = mergeColumns(state.queries, newFlattenColumns, null, false);
 
-             willUpdateStates.cachedColumns = props.columns;
 
-             willUpdateStates.cachedChildren = null;
 
-         } else if (props.children && props.children !== state.cachedChildren) {
 
-             const newNestedColumns = getColumns(props.children);
 
-             const newFlattenColumns = flattenColumns(newNestedColumns);
 
-             const columns = mergeColumns(state.queries, newFlattenColumns, null, false);
 
-             willUpdateStates.flattenColumns = newFlattenColumns;
 
-             willUpdateStates.queries = [...columns];
 
-             willUpdateStates.cachedColumns = [...newNestedColumns];
 
-             willUpdateStates.cachedChildren = props.children;
 
-         }
 
-         // Update controlled selection column
 
-         if (rowSelection !== state.prePropRowSelection) {
 
-             let newSelectionStates: TableStateRowSelection = {};
 
-             if (isObject(state.rowSelection)) {
 
-                 newSelectionStates = { ...newSelectionStates, ...state.rowSelection };
 
-             }
 
-             if (isObject(rowSelection)) {
 
-                 newSelectionStates = { ...newSelectionStates, ...rowSelection };
 
-             }
 
-             const selectedRowKeys = get(rowSelection, 'selectedRowKeys');
 
-             const getCheckboxProps = get(rowSelection, 'getCheckboxProps');
 
-             if (selectedRowKeys && Array.isArray(selectedRowKeys)) {
 
-                 newSelectionStates.selectedRowKeysSet = new Set(selectedRowKeys);
 
-             }
 
-             // The return value of getCheckboxProps affects the disabled rows
 
-             if (isFunction(getCheckboxProps)) {
 
-                 const disabledRowKeys = getAllDisabledRowKeys({ dataSource, getCheckboxProps, childrenRecordName, rowKey });
 
-                 willUpdateStates.disabledRowKeys = disabledRowKeys;
 
-                 willUpdateStates.disabledRowKeysSet = new Set(disabledRowKeys);
 
-             }
 
-             willUpdateStates.rowSelection = newSelectionStates;
 
-             willUpdateStates.prePropRowSelection = rowSelection;
 
-         }
 
-         if (pagination !== state.prePagination) {
 
-             let newPagination: Pagination = {};
 
-             if (isObject(state.pagination)) {
 
-                 newPagination = { ...newPagination, ...state.pagination };
 
-             }
 
-             if (isObject(pagination)) {
 
-                 newPagination = { ...newPagination, ...pagination };
 
-             }
 
-             willUpdateStates.pagination = newPagination;
 
-             willUpdateStates.prePagination = pagination;
 
-         }
 
-         return willUpdateStates;
 
-     }
 
-     componentDidMount() {
 
-         super.componentDidMount();
 
-         if (this.adapter.isAnyColumnFixed() || (this.props.showHeader && this.adapter.useFixedHeader())) {
 
-             this.handleWindowResize();
 
-             window.addEventListener('resize', this.debouncedWindowResize);
 
-         }
 
-     }
 
-     // TODO: Extract the setState operation to the adapter or getDerivedStateFromProps function
 
-     componentDidUpdate(prevProps: NormalTableProps<RecordType>, prevState: NormalTableState<RecordType>) {
 
-         const {
 
-             dataSource,
 
-             expandedRowKeys,
 
-             expandAllRows,
 
-             expandAllGroupRows,
 
-             virtualized,
 
-             components,
 
-             pagination: propsPagination
 
-         } = this.props;
 
-         const {
 
-             pagination: statePagination,
 
-             queries: stateQueries,
 
-             cachedColumns: stateCachedColumns,
 
-             cachedChildren: stateCachedChildren,
 
-             groups: stateGroups,
 
-         } = this.state;
 
-         /**
 
-          * State related to paging
 
-          *
 
-          * @param dataSource
 
-          * @param groups
 
-          * @param pagination
 
-          * @param disabledRowKeys
 
-          * @param allRowKeys
 
-          * @param queries
 
-          */
 
-         const states: Partial<NormalTableState<RecordType>> = {};
 
-         this._warnIfNoKey();
 
-         /**
 
-          * The state that needs to be updated after props changes
 
-          */
 
-         // Update controlled expand column
 
-         if (Array.isArray(expandedRowKeys) && expandedRowKeys !== prevProps.expandedRowKeys) {
 
-             this.setState({ expandedRowKeys });
 
-         }
 
-         // Update components
 
-         if (components !== prevProps.components || virtualized !== prevProps.virtualized) {
 
-             this.setState({ components: mergeComponents(components, virtualized) });
 
-         }
 
-         // Update the default expanded column
 
-         if (
 
-             expandAllRows !== prevProps.expandAllRows ||
 
-             expandAllGroupRows !== prevProps.expandAllGroupRows
 
-         ) {
 
-             this.foundation.initExpandedRowKeys({ groups: stateGroups });
 
-         }
 
-         /**
 
-          * After dataSource is updated || (cachedColumns || cachedChildren updated)
 
-          * 1. Cache filtered sorted data and a collection of data rows, stored in this
 
-          * 2. Update pager and group, stored in state
 
-          */
 
-         if (dataSource !== prevProps.dataSource || stateCachedColumns !== prevState.cachedColumns || stateCachedChildren !== prevState.cachedChildren) {
 
-             // TODO: foundation.getFilteredSortedDataSource has side effects and will be modified to the dataSource reference
 
-             // Temporarily use _dataSource=[...dataSource] for processing
 
-             const _dataSource = [...dataSource];
 
-             const filteredSortedDataSource = this.foundation.getFilteredSortedDataSource(_dataSource, stateQueries);
 
-             this.foundation.setCachedFilteredSortedDataSource(filteredSortedDataSource);
 
-             states.dataSource = filteredSortedDataSource;
 
-             if (this.props.groupBy) {
 
-                 states.groups = null;
 
-             }
 
-         }
 
-         // when dataSource has change, should reset currentPage
 
-         if (dataSource !== prevProps.dataSource) {
 
-             states.pagination = isObject(statePagination) ? {
 
-                 ...statePagination,
 
-                 currentPage: isObject(propsPagination) && propsPagination.currentPage ? propsPagination.currentPage : 1,
 
-             } : statePagination;
 
-         }
 
-         if (Object.keys(states).length) {
 
-             const {
 
-                 // eslint-disable-next-line @typescript-eslint/no-shadow
 
-                 pagination: mergedStatePagination = null,
 
-                 queries: stateQueries = null,
 
-                 dataSource: stateDataSource = null,
 
-             } = states;
 
-             const handledProps: Partial<NormalTableState<RecordType>> = this.foundation.getCurrentPageData(stateDataSource, mergedStatePagination as TablePaginationProps, stateQueries);
 
-             // After the pager is updated, reset allRowKeys of the current page
 
-             this.adapter.setAllRowKeys(handledProps.allRowKeys);
 
-             this.adapter.setDisabledRowKeys(handledProps.disabledRowKeys);
 
-             if ('dataSource' in states) {
 
-                 if (this.props.defaultExpandAllRows && handledProps.groups && handledProps.groups.size ||
 
-                     this.props.expandAllRows ||
 
-                     this.props.expandAllGroupRows
 
-                 ) {
 
-                     this.foundation.initExpandedRowKeys(handledProps);
 
-                 }
 
-             }
 
-             // Centrally update paging related state
 
-             const statesKeys: any[] = Object.keys(states);
 
-             for (const k of statesKeys) {
 
-                 this.setState({ [k]: handledProps[k] });
 
-             }
 
-         }
 
-         if (this.adapter.isAnyColumnFixed() || (this.props.showHeader && this.adapter.useFixedHeader())) {
 
-             if (!this.debouncedWindowResize) {
 
-                 window.addEventListener('resize', this.debouncedWindowResize);
 
-             }
 
-         }
 
-     }
 
-     componentWillUnmount() {
 
-         super.componentWillUnmount();
 
-         if (this.debouncedWindowResize) {
 
-             window.removeEventListener('resize', this.debouncedWindowResize);
 
-             (this.debouncedWindowResize as any).cancel();
 
-             this.debouncedWindowResize = null;
 
-         }
 
-     }
 
-     // TODO: notify when data don't have key
 
-     _warnIfNoKey = () => {
 
-         if (
 
-             (this.props.rowSelection || this.props.expandedRowRender) &&
 
-             some(this.props.dataSource, record => this.foundation.getRecordKey(record) == null)
 
-         ) {
 
-             logger.error(
 
-                 'You must specify a key for each element in the dataSource or use "rowKey" to specify an attribute name as the primary key!'
 
-             );
 
-         }
 
-     };
 
-     _invokeRowSelection = (funcName: string, ...args: any[]) => {
 
-         const func = get(this.state, ['rowSelection', funcName]);
 
-         if (typeof func === 'function') {
 
-             func(...args);
 
-         }
 
-     };
 
-     _invokeColumnFn = (key: string, funcName: string, ...args: any[]) => {
 
-         if (key && funcName) {
 
-             const column = this.foundation.getQuery(key);
 
-             const func = get(column, funcName, null);
 
-             if (typeof func === 'function') {
 
-                 func(...args);
 
-             }
 
-         }
 
-     };
 
-     _cacheHeaderRef = (node: HTMLDivElement) => {
 
-         this.headerWrapRef.current = node;
 
-     };
 
-     getCurrentPageData = () => {
 
-         const pageData = this.foundation.getCurrentPageData();
 
-         const retObj = ['dataSource', 'groups'].reduce((result, key) => {
 
-             if (pageData[key]) {
 
-                 result[key] = pageData[key];
 
-             }
 
-             return result;
 
-         }, {});
 
-         return cloneDeep(retObj);
 
-     };
 
-     getColumns = (columns: ColumnProps<RecordType>[], children: ReactNode) => (!Array.isArray(columns) || !columns || !columns.length ? getColumns(children) : columns);
 
-     // @ts-ignore
 
-     getCellWidths = (...args: any[]) => this.foundation.getCellWidths(...args);
 
-     // @ts-ignore
 
-     setHeadWidths = (...args: any[]) => this.foundation.setHeadWidths(...args);
 
-     // @ts-ignore
 
-     getHeadWidths = (...args: any[]) => this.foundation.getHeadWidths(...args);
 
-     // @ts-ignore
 
-     mergedRowExpandable = (...args: any[]) => this.foundation.mergedRowExpandable(...args);
 
-     // @ts-ignore
 
-     setBodyHasScrollbar = (...args: any[]) => this.foundation.setBodyHasScrollbar(...args);
 
-     handleWheel = (event: React.WheelEvent<HTMLDivElement>) => {
 
-         const { scroll = {} } = this.props;
 
-         if (window.navigator.userAgent.match(/Trident\/7\./) && scroll.y) {
 
-             event.preventDefault();
 
-             const wd = event.deltaY;
 
-             const { target } = event;
 
-             // const { bodyTable, fixedColumnsBodyLeft, fixedColumnsBodyRight } = this;
 
-             const bodyTable = this.bodyWrapRef.current;
 
-             let scrollTop = 0;
 
-             if (this.lastScrollTop) {
 
-                 scrollTop = this.lastScrollTop + wd;
 
-             } else {
 
-                 scrollTop = wd;
 
-             }
 
-             if (bodyTable && target !== bodyTable) {
 
-                 bodyTable.scrollTop = scrollTop;
 
-             }
 
-         }
 
-     };
 
-     handleBodyScrollLeft = (e: BodyScrollEvent) => {
 
-         if (e.currentTarget !== e.target) {
 
-             return;
 
-         }
 
-         const { target } = e;
 
-         // const { headTable, bodyTable } = this;
 
-         const headTable = this.headerWrapRef.current;
 
-         const bodyTable = this.bodyWrapRef.current;
 
-         if (target.scrollLeft !== this.lastScrollLeft) {
 
-             if (target === bodyTable && headTable) {
 
-                 headTable.scrollLeft = target.scrollLeft;
 
-             } else if (target === headTable && bodyTable) {
 
-                 bodyTable.scrollLeft = target.scrollLeft;
 
-             }
 
-             this.setScrollPositionClassName();
 
-         }
 
-         // Remember last scrollLeft for scroll direction detecting.
 
-         this.lastScrollLeft = target.scrollLeft;
 
-     };
 
-     handleWindowResize = () => {
 
-         this.syncTableWidth();
 
-         this.setScrollPositionClassName();
 
-     };
 
-     handleBodyScrollTop = (e: BodyScrollEvent) => {
 
-         const { target } = e;
 
-         if (e.currentTarget !== target) {
 
-             return;
 
-         }
 
-         const { scroll = {} } = this.props;
 
-         // const { headTable, bodyTable, fixedColumnsBodyLeft, fixedColumnsBodyRight } = this;
 
-         const headTable = this.headerWrapRef.current;
 
-         const bodyTable = this.bodyWrapRef.current;
 
-         if (target.scrollTop !== this.lastScrollTop && scroll.y && target !== headTable) {
 
-             const { scrollTop } = target;
 
-             if (bodyTable && target !== bodyTable) {
 
-                 bodyTable.scrollTop = scrollTop;
 
-             }
 
-         }
 
-         // Remember last scrollTop for scroll direction detecting.
 
-         this.lastScrollTop = target.scrollTop;
 
-     };
 
-     handleBodyScroll = (e: BodyScrollEvent) => {
 
-         this.handleBodyScrollLeft(e);
 
-         this.handleBodyScrollTop(e);
 
-     };
 
-     setScrollPosition = (position: BodyScrollPosition) => {
 
-         const { prefixCls } = this.props;
 
-         const positionAll = [
 
-             `${prefixCls}-scroll-position-both`,
 
-             `${prefixCls}-scroll-position-middle`,
 
-             `${prefixCls}-scroll-position-left`,
 
-             `${prefixCls}-scroll-position-right`,
 
-         ];
 
-         this.scrollPosition = position;
 
-         const tableNode = this.wrapRef.current;
 
-         if (tableNode && tableNode.nodeType) {
 
-             if (position === 'both') {
 
-                 const acceptPosition = [`${prefixCls}-scroll-position-left`, `${prefixCls}-scroll-position-right`];
 
-                 tableNode.classList.remove(...difference(positionAll, acceptPosition));
 
-                 tableNode.classList.add(...acceptPosition);
 
-             } else {
 
-                 const acceptPosition = [`${prefixCls}-scroll-position-${position}`];
 
-                 tableNode.classList.remove(...difference(positionAll, acceptPosition));
 
-                 tableNode.classList.add(...acceptPosition);
 
-             }
 
-         }
 
-     };
 
-     setScrollPositionClassName = () => {
 
-         const node = this.bodyWrapRef.current;
 
-         if (node && node.children && node.children.length) {
 
-             const scrollToLeft = node.scrollLeft === 0;
 
-             const scrollToRight =
 
-                 node.scrollLeft + 1 >=
 
-                 node.children[0].getBoundingClientRect().width - node.getBoundingClientRect().width;
 
-             if (scrollToLeft && scrollToRight) {
 
-                 this.setScrollPosition('both');
 
-             } else if (scrollToLeft) {
 
-                 this.setScrollPosition('left');
 
-             } else if (scrollToRight) {
 
-                 this.setScrollPosition('right');
 
-             } else if (this.scrollPosition !== 'middle') {
 
-                 this.setScrollPosition('middle');
 
-             }
 
-         }
 
-     };
 
-     syncTableWidth = () => {
 
-         if (this.rootWrapRef && this.rootWrapRef.current) {
 
-             this.setState({ tableWidth: this.rootWrapRef.current.getBoundingClientRect().width });
 
-         }
 
-     };
 
-     renderSelection = (record = {} as any, inHeader = false): React.ReactNode => {
 
-         const { rowSelection, disabledRowKeysSet } = this.state;
 
-         if (rowSelection && typeof rowSelection === 'object') {
 
-             const { selectedRowKeys = [], selectedRowKeysSet = new Set(), getCheckboxProps, disabled } = rowSelection;
 
-             if (inHeader) {
 
-                 const columnKey = get(rowSelection, 'key', strings.DEFAULT_KEY_COLUMN_SELECTION);
 
-                 const allRowKeys = this.cachedFilteredSortedRowKeys;
 
-                 const allRowKeysSet = this.cachedFilteredSortedRowKeysSet;
 
-                 const allIsSelected = this.foundation.allIsSelected(selectedRowKeysSet, disabledRowKeysSet, allRowKeys);
 
-                 const hasRowSelected = this.foundation.hasRowSelected(selectedRowKeys, allRowKeysSet);
 
-                 return (
 
-                     <ColumnSelection
 
-                         aria-label={`${allIsSelected ? 'Deselect' : 'Select'} all rows`}
 
-                         disabled={disabled}
 
-                         key={columnKey}
 
-                         selected={allIsSelected}
 
-                         indeterminate={hasRowSelected && !allIsSelected}
 
-                         onChange={(status, e) => {
 
-                             this.toggleSelectAllRow(status, e);
 
-                         }}
 
-                     />
 
-                 );
 
-             } else {
 
-                 const key = this.foundation.getRecordKey(record);
 
-                 const selected = selectedRowKeysSet.has(key);
 
-                 const checkboxPropsFn = () => (typeof getCheckboxProps === 'function' ? getCheckboxProps(record) : {});
 
-                 return (
 
-                     <ColumnSelection
 
-                         aria-label={`${selected ? 'Deselect' : 'Select'} this row`}
 
-                         getCheckboxProps={checkboxPropsFn}
 
-                         selected={selected}
 
-                         onChange={(status, e) => this.toggleSelectRow(status, key, e)}
 
-                     />
 
-                 );
 
-             }
 
-         }
 
-         return null;
 
-     };
 
-     renderRowSelectionCallback = (text: string, record: RecordType = {} as RecordType) => this.renderSelection(record);
 
-     renderTitleSelectionCallback = () => this.renderSelection(null, true);
 
-     normalizeSelectionColumn = (props: { rowSelection?: TableStateRowSelection<RecordType>; prefixCls?: string } = {}) => {
 
-         const { rowSelection, prefixCls } = props;
 
-         let column: ColumnProps = {};
 
-         if (rowSelection) {
 
-             const needOmitSelectionKey = ['selectedRowKeys', 'selectedRowKeysSet'];
 
-             column = { key: strings.DEFAULT_KEY_COLUMN_SELECTION };
 
-             if (isObject(rowSelection)) {
 
-                 column = { ...column, ...omit(rowSelection, needOmitSelectionKey) };
 
-             }
 
-             column.className = classnames(column.className, `${prefixCls}-column-selection`);
 
-             column.title = this.renderTitleSelectionCallback;
 
-             column.render = this.renderRowSelectionCallback;
 
-         }
 
-         return column;
 
-     };
 
-     // If there is a scroll bar, manually construct a column and insert it into the header
 
-     normalizeScrollbarColumn = (props: { scrollbarWidth?: number } = {}): { key: 'column-scrollbar'; width: number; fixed: 'right' } => {
 
-         const { scrollbarWidth = 0 } = props;
 
-         return {
 
-             key: strings.DEFAULT_KEY_COLUMN_SCROLLBAR as 'column-scrollbar',
 
-             width: scrollbarWidth,
 
-             fixed: 'right',
 
-         };
 
-     };
 
-     /**
 
-      * render expand icon
 
-      * @param {Object} record
 
-      * @param {Boolean} isNested
 
-      * @param {String} groupKey
 
-      * @returns {ReactNode}
 
-      */
 
-     renderExpandIcon = (record = {}, isNested = false, groupKey: string | number = null) => {
 
-         const { expandedRowKeys } = this.state;
 
-         const { expandIcon } = this.props;
 
-         const key =
 
-             typeof groupKey === 'string' || typeof groupKey === 'number' ?
 
-                 groupKey :
 
-                 this.foundation.getRecordKey(record as RecordType);
 
-         return (
 
-             <ExpandedIcon
 
-                 key={key}
 
-                 componentType={isNested ? 'tree' : 'expand'}
 
-                 expanded={includes(expandedRowKeys, key)}
 
-                 expandIcon={expandIcon}
 
-                 onClick={(expanded, e) => this.handleRowExpanded(expanded, key, e)}
 
-             />
 
-         );
 
-     };
 
-     // @ts-ignore
 
-     handleRowExpanded = (...args: any[]) => this.foundation.handleRowExpanded(...args);
 
-     normalizeExpandColumn = (props: { prefixCls?: string; expandCellFixed?: ArrayElement<typeof strings.FIXED_SET>; expandIcon?: ExpandIcon } = {}) => {
 
-         let column: ColumnProps = null;
 
-         const { prefixCls, expandCellFixed, expandIcon } = props;
 
-         column = { fixed: expandCellFixed, key: strings.DEFAULT_KEY_COLUMN_EXPAND };
 
-         column.className = classnames(column.className, `${prefixCls}-column-expand`);
 
-         column.render =
 
-             expandIcon !== false ?
 
-                 (text = '', record, index) =>
 
-                     (this.adapter.mergedRowExpandable(record) ? this.renderExpandIcon(record) : null) :
 
-                 () => null;
 
-         return column;
 
-     };
 
-     /**
 
-       * Add sorting, filtering, and rendering functions to columns, and add column event handling
 
-       * Title support function, passing parameters as {filter: node, sorter: node, selection: node}
 
-       * @param {*} column
 
-       */
 
-     addFnsInColumn = (column: ColumnProps = {}) => {
 
-         if (column && (column.sorter || column.filters || column.useFullRender)) {
 
-             const { dataIndex, title: rawTitle, useFullRender } = column;
 
-             const curQuery = this.foundation.getQuery(dataIndex);
 
-             const titleMap: ColumnTitleProps = {};
 
-             const titleArr = [];
 
-             // useFullRender adds select buttons to each column
 
-             if (useFullRender) {
 
-                 titleMap.selection = this.renderSelection(null, true);
 
-             }
 
-             const stateSortOrder = get(curQuery, 'sortOrder');
 
-             const defaultSortOrder = get(curQuery, 'defaultSortOrder', false);
 
-             const sortOrder = this.foundation.isSortOrderValid(stateSortOrder) ? stateSortOrder : defaultSortOrder;
 
-             if (typeof column.sorter === 'function' || column.sorter === true) {
 
-                 const sorter = (
 
-                     <ColumnSorter
 
-                         key={strings.DEFAULT_KEY_COLUMN_SORTER}
 
-                         sortOrder={sortOrder}
 
-                         onClick={e => this.foundation.handleSort(column, e)}
 
-                     />
 
-                 );
 
-                 useFullRender && (titleMap.sorter = sorter);
 
-                 titleArr.push(sorter);
 
-             }
 
-             const stateFilteredValue = get(curQuery, 'filteredValue');
 
-             const defaultFilteredValue = get(curQuery, 'defaultFilteredValue');
 
-             const filteredValue = stateFilteredValue ? stateFilteredValue : defaultFilteredValue;
 
-             if ((Array.isArray(column.filters) && column.filters.length) || isValidElement(column.filterDropdown)) {
 
-                 const filter = (
 
-                     <ColumnFilter
 
-                         key={strings.DEFAULT_KEY_COLUMN_FILTER}
 
-                         {...curQuery}
 
-                         filteredValue={filteredValue}
 
-                         onFilterDropdownVisibleChange={(visible: boolean) => this.foundation.toggleShowFilter(dataIndex, visible)}
 
-                         onSelect={(data: OnSelectData) => this.foundation.handleFilterSelect(dataIndex, data)}
 
-                     />
 
-                 );
 
-                 useFullRender && (titleMap.filter = filter);
 
-                 titleArr.push(filter);
 
-             }
 
-             const newTitle =
 
-                 typeof rawTitle === 'function' ?
 
-                     () => rawTitle(titleMap) :
 
-                     titleArr.unshift(
 
-                         <React.Fragment key={strings.DEFAULT_KEY_COLUMN_TITLE}>{rawTitle}</React.Fragment>
 
-                     ) && titleArr;
 
-             column = { ...column, title: newTitle };
 
-         }
 
-         return column;
 
-     };
 
-     toggleSelectRow = (selected: boolean, realKey: string | number, e: TableSelectionCellEvent) => {
 
-         this.foundation.handleSelectRow(realKey, selected, e);
 
-     };
 
-     toggleSelectAllRow = (status: boolean, e: TableSelectionCellEvent) => {
 
-         this.foundation.handleSelectAllRow(status, e);
 
-     };
 
-     /**
 
-      * render pagination
 
-      * @param {object} pagination
 
-      * @param {object} propRenderPagination
 
-      */
 
-     renderPagination = (pagination: TablePaginationProps, propRenderPagination: RenderPagination) => {
 
-         if (!pagination) {
 
-             return null;
 
-         }
 
-         // use memoized pagination
 
-         const mergedPagination = this.foundation.memoizedPagination(pagination);
 
-         return (
 
-             <LocaleConsumer componentName="Table">
 
-                 {(locale: TableLocale) => {
 
-                     const info = this.foundation.formatPaginationInfo(mergedPagination, locale.pageText);
 
-                     return <TablePagination info={info} pagination={mergedPagination} renderPagination={propRenderPagination} />;
 
-                 }}
 
-             </LocaleConsumer>
 
-         );
 
-     };
 
-     renderTitle = (props: { title?: ReactNode | ((dataSource?: RecordType[]) => ReactNode); prefixCls?: string; dataSource?: any[] } = {}) => {
 
-         let { title } = props;
 
-         const { prefixCls, dataSource } = props;
 
-         if (typeof title === 'function') {
 
-             title = title(dataSource);
 
-         }
 
-         return isValidElement(title) || typeof title === 'string' ? (
 
-             <div className={`${prefixCls}-title`} x-semi-prop="title">{title}</div>
 
-         ) : null;
 
-     };
 
-     renderEmpty = (props: { prefixCls?: string; empty?: ReactNode; dataSource?: RecordType[] } = {}) => {
 
-         const { prefixCls, empty, dataSource } = props;
 
-         const wrapCls = `${prefixCls}-placeholder`;
 
-         const isEmpty = this.foundation.isEmpty(dataSource);
 
-         if (!isEmpty) {
 
-             return null;
 
-         }
 
-         return (
 
-             <LocaleConsumer componentName="Table" key={'emptyText'}>
 
-                 {(locale: TableLocale, localeCode: string) => (
 
-                     <div className={wrapCls}>
 
-                         <div className={`${prefixCls}-empty`} x-semi-prop="empty">
 
-                             {empty || locale.emptyText}
 
-                         </div>
 
-                     </div>
 
-                 )}
 
-             </LocaleConsumer>
 
-         );
 
-     };
 
-     renderFooter = (props: { footer?: ReactNode | ((dataSource?: RecordType[]) => ReactNode); prefixCls?: string; dataSource?: RecordType[] } = {}) => {
 
-         let { footer } = props;
 
-         const { prefixCls, dataSource } = props;
 
-         if (typeof footer === 'function') {
 
-             footer = footer(dataSource);
 
-         }
 
-         return isValidElement(footer) || typeof footer === 'string' ? (
 
-             <div className={`${prefixCls}-footer`} key="footer" x-semi-prop="footer">
 
-                 {footer}
 
-             </div>
 
-         ) : null;
 
-     };
 
-     renderMainTable = (props: any) => {
 
-         const useFixedHeader = this.adapter.useFixedHeader();
 
-         const emptySlot = this.renderEmpty(props);
 
-         const table = [
 
-             this.renderTable({
 
-                 ...props,
 
-                 fixed: false,
 
-                 useFixedHeader,
 
-                 headerRef: this._cacheHeaderRef,
 
-                 bodyRef: this.bodyWrapRef,
 
-                 includeHeader: !useFixedHeader,
 
-             }),
 
-             emptySlot,
 
-             this.renderFooter(props),
 
-         ];
 
-         return table;
 
-     };
 
-     renderTable = (props: RenderTableProps<RecordType>) => {
 
-         const {
 
-             columns,
 
-             filteredColumns,
 
-             fixed,
 
-             useFixedHeader,
 
-             scroll,
 
-             prefixCls,
 
-             anyColumnFixed,
 
-             includeHeader,
 
-             showHeader,
 
-             components,
 
-             headerRef,
 
-             bodyRef,
 
-             onHeaderRow,
 
-             rowSelection,
 
-             dataSource,
 
-             bodyHasScrollBar,
 
-             disabledRowKeysSet,
 
-         } = props;
 
-         const selectedRowKeysSet = get(rowSelection, 'selectedRowKeysSet', new Set());
 
-         const headTable =
 
-             fixed || useFixedHeader ? (
 
-                 <HeadTable
 
-                     key="head"
 
-                     anyColumnFixed={anyColumnFixed}
 
-                     ref={headerRef}
 
-                     columns={filteredColumns}
 
-                     prefixCls={prefixCls}
 
-                     fixed={fixed}
 
-                     handleBodyScroll={this.handleBodyScrollLeft}
 
-                     components={components}
 
-                     scroll={scroll}
 
-                     showHeader={showHeader}
 
-                     selectedRowKeysSet={selectedRowKeysSet}
 
-                     onHeaderRow={onHeaderRow}
 
-                     dataSource={dataSource}
 
-                     bodyHasScrollBar={bodyHasScrollBar}
 
-                 />
 
-             ) : null;
 
-         const bodyTable = (
 
-             <BodyTable
 
-                 {...omit(props, ['rowSelection', 'headWidths']) as any}
 
-                 key="body"
 
-                 ref={bodyRef}
 
-                 columns={filteredColumns}
 
-                 fixed={fixed}
 
-                 prefixCls={prefixCls}
 
-                 handleWheel={this.handleWheel}
 
-                 handleBodyScroll={this.handleBodyScroll}
 
-                 anyColumnFixed={anyColumnFixed}
 
-                 includeHeader={includeHeader}
 
-                 showHeader={showHeader}
 
-                 scroll={scroll}
 
-                 components={components}
 
-                 store={this.store}
 
-                 selectedRowKeysSet={selectedRowKeysSet}
 
-                 disabledRowKeysSet={disabledRowKeysSet}
 
-             />
 
-         );
 
-         return [headTable, bodyTable];
 
-     };
 
-     /**
 
-      * When columns change, call this function to get the latest withFnsColumns
 
-      * In addition to changes in columns, these props changes must be recalculated
 
-      *  - hideExpandedColumn
 
-      *  -rowSelection changes from trusy to falsy or rowSelection.hidden changes
 
-      *  -isAnyFixedRight(columns) || get(scroll,'y') changes
 
-      *
 
-      * columns变化时,调用此函数获取最新的withFnsColumns
 
-      * 除了 columns 变化,这些 props 变化也要重新计算
 
-      *  - hideExpandedColumn
 
-      *  - rowSelection 从 trusy 变为 falsy 或 rowSelection.hidden 发生变化
 
-      *  - isAnyFixedRight(columns) || get(scroll, 'y') 发生变化
 
-      *
 
-      * @param {Array} queries
 
-      * @param {Array} cachedColumns
 
-      * @returns columns after adding extended functions
 
-      */
 
-     handleColumns = (queries: ColumnProps<RecordType>[], cachedColumns: ColumnProps<RecordType>[]) => {
 
-         const { hideExpandedColumn, scroll, prefixCls, expandCellFixed, expandIcon, rowSelection } = this.props;
 
-         const childrenColumnName = 'children';
 
-         let columns: ColumnProps<RecordType>[] = cloneDeep(cachedColumns);
 
-         // eslint-disable-next-line @typescript-eslint/no-shadow
 
-         const addFns = (columns: ColumnProps<RecordType>[] = []) => {
 
-             if (Array.isArray(columns) && columns.length) {
 
-                 each(columns, (column, index, originColumns) => {
 
-                     const newColumn = this.addFnsInColumn(column);
 
-                     const children = column[childrenColumnName];
 
-                     if (Array.isArray(children) && children.length) {
 
-                         const newChildren = [...children];
 
-                         addFns(newChildren);
 
-                         newColumn[childrenColumnName] = newChildren;
 
-                     }
 
-                     originColumns[index] = newColumn;
 
-                 });
 
-             }
 
-         };
 
-         addFns(columns);
 
-         // hideExpandedColumn=false render expand column separately
 
-         if (!hideExpandedColumn) {
 
-             const column = this.normalizeExpandColumn({ prefixCls, expandCellFixed, expandIcon });
 
-             const destIndex = findIndex(columns, item => item.key === strings.DEFAULT_KEY_COLUMN_EXPAND);
 
-             if (column) {
 
-                 if (destIndex > -1) {
 
-                     columns[destIndex] = { ...column, ...columns[destIndex] };
 
-                 } else if (column.fixed === 'right') {
 
-                     columns = [...columns, column];
 
-                 } else {
 
-                     columns = [column, ...columns];
 
-                 }
 
-             }
 
-         }
 
-         // selection column
 
-         if (rowSelection && !get(rowSelection, 'hidden')) {
 
-             const destIndex = findIndex(columns, item => item.key === strings.DEFAULT_KEY_COLUMN_SELECTION);
 
-             const column = this.normalizeSelectionColumn({ rowSelection, prefixCls });
 
-             if (destIndex > -1) {
 
-                 columns[destIndex] = { ...column, ...columns[destIndex] };
 
-             } else if (column.fixed === 'right') {
 
-                 columns = [...columns, column];
 
-             } else {
 
-                 columns = [column, ...columns];
 
-             }
 
-         }
 
-         assignColumnKeys(columns);
 
-         return columns;
 
-     };
 
-     /**
 
-      * Convert children to columns object
 
-      * @param {Array} columns
 
-      * @param {ReactNode} children
 
-      * @returns {Array}
 
-      */
 
-     normalizeColumns = (columns: ColumnProps<RecordType>[], children: ReactNode) => {
 
-         const normalColumns = cloneDeep(this.getColumns(columns, children));
 
-         return normalColumns;
 
-     };
 
-     /**
 
-      * Combine pagination and table paging processing functions
 
-      */
 
-     mergePagination = (pagination: TablePaginationProps) => {
 
-         const newPagination = { onChange: this.foundation.setPage, ...pagination };
 
-         return newPagination;
 
-     };
 
-     render() {
 
-         let {
 
-             scroll,
 
-             prefixCls,
 
-             className,
 
-             style: wrapStyle = {},
 
-             bordered,
 
-             id,
 
-             pagination: propPagination,
 
-             virtualized,
 
-             size,
 
-             renderPagination: propRenderPagination,
 
-             getVirtualizedListRef,
 
-             loading,
 
-             hideExpandedColumn,
 
-             rowSelection: propRowSelection,
 
-             ...rest
 
-         } = this.props;
 
-         let {
 
-             rowSelection,
 
-             expandedRowKeys,
 
-             headWidths,
 
-             tableWidth,
 
-             pagination,
 
-             dataSource,
 
-             queries,
 
-             cachedColumns,
 
-             bodyHasScrollBar,
 
-         } = this.state;
 
-         wrapStyle = { ...wrapStyle };
 
-         let columns: ColumnProps<RecordType>[];
 
-         /**
 
-           * As state.queries will change, the columns should be refreshed as a whole at this time
 
-           * The scene of changes in queries
 
-           * 1. Filter
 
-           * 2. Pagination
 
-           *
 
-           * useFullRender needs to be passed to the user selection ReactNode, so columns need to be recalculated every time the selectedRowKeys changes
 
-           * TODO: In the future, the selection passed to the user can be changed to the function type, allowing the user to execute the function to obtain the real-time status of the selection title
 
-           *
 
-           * 由于state.queries会发生变化,此时columns应该整体刷新
 
-           * queries变化的场景
 
-           *  1. 筛选
 
-           *  2. 分页
 
-           * useFullRender需要传给用户selection ReactNode,因此需要每次selectedRowKeys变化时重新计算columns
 
-           * TODO: 未来可以将传给用户的selection改为函数类型,让用户执行函数获取selection title的实时状态
 
-           */
 
-         if (!this.adapter.isAnyColumnUseFullRender(queries)) {
 
-             const rowSelectionUpdate: boolean = propRowSelection && !get(propRowSelection, 'hidden');
 
-             columns = this.foundation.memoizedWithFnsColumns(
 
-                 queries,
 
-                 cachedColumns,
 
-                 rowSelectionUpdate,
 
-                 hideExpandedColumn,
 
-                 // Update the columns after the body scrollbar changes to ensure that the head and body are aligned
 
-                 bodyHasScrollBar
 
-             );
 
-         } else {
 
-             columns = this.handleColumns(queries, cachedColumns);
 
-         }
 
-         const filteredColumns: ColumnProps<RecordType>[] = this.foundation.memoizedFilterColumns(columns);
 
-         const flattenFnsColumns: ColumnProps<RecordType>[] = this.foundation.memoizedFlattenFnsColumns(columns);
 
-         const anyColumnFixed = this.adapter.isAnyColumnFixed(columns);
 
-         /**
 
-          * - If it is the first page break, you need to calculate the current page
 
-          * - If it is manual paging, call foundation to modify the state
 
-          *
 
-          * TODO: After merging issue 1007, you can place it in the constructor to complete
 
-          * The reason is that #1007 exposes the parameters required by getCurrentPageData in the constructor
 
-          */
 
-         if (isNull(dataSource)) {
 
-             const pageData: BasePageData<RecordType> = this.foundation.getCurrentPageData(this.props.dataSource);
 
-             dataSource = pageData.dataSource;
 
-             pagination = pageData.pagination;
 
-         }
 
-         const props = {
 
-             ...rest,
 
-             ...this.state,
 
-             // props not in rest
 
-             virtualized,
 
-             scroll,
 
-             prefixCls,
 
-             size,
 
-             hideExpandedColumn,
 
-             // renamed state
 
-             columns,
 
-             // calculated value
 
-             anyColumnFixed,
 
-             rowExpandable: this.mergedRowExpandable,
 
-             pagination,
 
-             dataSource,
 
-             rowSelection,
 
-             expandedRowKeys,
 
-             renderExpandIcon: this.renderExpandIcon,
 
-             filteredColumns,
 
-         };
 
-         const x = get(scroll, 'x');
 
-         const y = get(scroll, 'y');
 
-         if (virtualized) {
 
-             if (typeof wrapStyle.width !== 'number') {
 
-                 wrapStyle.width = x;
 
-             }
 
-         }
 
-         const wrapCls = classnames({
 
-             [`${prefixCls}-${strings.SIZE_SMALL}`]: size === strings.SIZE_SMALL,
 
-             [`${prefixCls}-${strings.SIZE_MIDDLE}`]: size === strings.SIZE_MIDDLE,
 
-             [`${prefixCls}-virtualized`]: Boolean(virtualized),
 
-             [`${prefixCls}-bordered`]: bordered,
 
-             [`${prefixCls}-fixed-header`]: Boolean(y),
 
-             [`${prefixCls}-scroll-position-left`]: ['both', 'left'].includes(this.position),
 
-             [`${prefixCls}-scroll-position-right`]: ['both', 'right'].includes(this.position),
 
-         });
 
-         // pagination
 
-         const tablePagination = pagination && propPagination ? this.renderPagination(pagination as TablePaginationProps, propRenderPagination) : null;
 
-         const paginationPosition = get(propPagination, 'position', 'bottom');
 
-         const tableContextValue: TableContextProps = {
 
-             ...this.context,
 
-             headWidths,
 
-             tableWidth,
 
-             anyColumnFixed,
 
-             flattenedColumns: flattenFnsColumns,
 
-             renderExpandIcon: this.renderExpandIcon,
 
-             renderSelection: this.renderSelection,
 
-             setHeadWidths: this.setHeadWidths,
 
-             getHeadWidths: this.getHeadWidths,
 
-             getCellWidths: this.getCellWidths,
 
-             handleRowExpanded: this.handleRowExpanded,
 
-             getVirtualizedListRef,
 
-             setBodyHasScrollbar: this.setBodyHasScrollbar,
 
-         };
 
-         return (
 
-             <div
 
-                 ref={this.rootWrapRef}
 
-                 className={classnames(className, `${prefixCls}-wrapper`)}
 
-                 data-column-fixed={anyColumnFixed}
 
-                 style={wrapStyle}
 
-                 id={id}
 
-             >
 
-                 <TableContextProvider {...tableContextValue}>
 
-                     <Spin spinning={loading} size="large">
 
-                         <div ref={this.wrapRef} className={wrapCls}>
 
-                             <React.Fragment key={'pagination-top'}>
 
-                                 {['top', 'both'].includes(paginationPosition) ? tablePagination : null}
 
-                             </React.Fragment>
 
-                             {this.renderTitle({ title: (props as any).title, dataSource: props.dataSource, prefixCls: props.prefixCls })}
 
-                             <div className={`${prefixCls}-container`}>{this.renderMainTable({ ...props })}</div>
 
-                             <React.Fragment key={'pagination-bottom'}>
 
-                                 {['bottom', 'both'].includes(paginationPosition) ? tablePagination : null}
 
-                             </React.Fragment>
 
-                         </div>
 
-                     </Spin>
 
-                 </TableContextProvider>
 
-             </div>
 
-         );
 
-     }
 
- }
 
- export default Table;
 
 
  |