| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847 | 
							- /* eslint-disable eqeqeq */
 
- /* eslint-disable @typescript-eslint/member-ordering */
 
- /* eslint-disable max-len */
 
- import React, { ReactNode } from 'react';
 
- import PropTypes from 'prop-types';
 
- import { get, size, isMap, each, isEqual, pick, isNull, isFunction } from 'lodash';
 
- import classnames from 'classnames';
 
- import { VariableSizeList as List } from 'react-window';
 
- import {
 
-     arrayAdd,
 
-     getRecordKey,
 
-     isExpanded,
 
-     isSelected,
 
-     isDisabled,
 
-     getRecord,
 
-     genExpandedRowKey,
 
-     getDefaultVirtualizedRowConfig,
 
-     isTreeTable
 
- } from '@douyinfe/semi-foundation/table/utils';
 
- import BodyFoundation, { BodyAdapter, FlattenData, GroupFlattenData } from '@douyinfe/semi-foundation/table/bodyFoundation';
 
- import { strings } from '@douyinfe/semi-foundation/table/constants';
 
- import Store from '@douyinfe/semi-foundation/utils/Store';
 
- import BaseComponent, { BaseProps } from '../../_base/baseComponent';
 
- import { logger } from '../utils';
 
- import ColGroup from '../ColGroup';
 
- import BaseRow from './BaseRow';
 
- import ExpandedRow from './ExpandedRow';
 
- import SectionRow from './SectionRow';
 
- import TableHeader from '../TableHeader';
 
- import ConfigContext from '../../configProvider/context';
 
- import TableContext from '../table-context';
 
- import {
 
-     ExpandedRowRender,
 
-     Virtualized,
 
-     GetVirtualizedListRef,
 
-     ColumnProps,
 
-     Size,
 
-     BodyScrollEvent,
 
-     Scroll,
 
-     Fixed,
 
-     TableComponents,
 
-     RowExpandable,
 
-     VirtualizedOnScroll,
 
-     Direction,
 
-     RowKey
 
- } from '../interface';
 
- export interface BodyProps extends BaseProps {
 
-     anyColumnFixed?: boolean;
 
-     columns?: ColumnProps[];
 
-     dataSource?: Record<string, any>[];
 
-     disabledRowKeysSet: Set<any>; // required
 
-     emptySlot?: ReactNode;
 
-     expandedRowKeys?: (string | number)[];
 
-     expandedRowRender?: ExpandedRowRender<Record<string, any>>;
 
-     fixed?: Fixed;
 
-     forwardedRef?: React.MutableRefObject<HTMLDivElement> | ((instance: any) => void);
 
-     handleBodyScroll?: (e: BodyScrollEvent) => void;
 
-     handleWheel?: (e: React.WheelEvent<HTMLDivElement>) => void;
 
-     includeHeader?: boolean;
 
-     prefixCls?: string;
 
-     scroll?: Scroll;
 
-     selectedRowKeysSet: Set<any>; // required
 
-     showHeader?: boolean;
 
-     size?: Size;
 
-     virtualized?: Virtualized;
 
-     components?: TableComponents;
 
-     store: Store;
 
-     groups?: Map<string, Record<string, any>[]>[];
 
-     rowKey?: RowKey<Record<string, any>>;
 
-     childrenRecordName?: string;
 
-     rowExpandable?: RowExpandable<Record<string, any>>;
 
-     renderExpandIcon: (record: Record<string, any>, isNested: boolean) => ReactNode | null;
 
-     headerRef?: React.MutableRefObject<HTMLDivElement> | ((instance: any) => void);
 
-     onScroll?: VirtualizedOnScroll;
 
- }
 
- export interface BodyState {
 
-     virtualizedData?: Array<FlattenData | GroupFlattenData>;
 
-     cache?: {
 
-         virtualizedScrollTop?: number;
 
-         virtualizedScrollLeft?: number;
 
-     };
 
-     cachedExpandBtnShouldInRow?: boolean;
 
-     cachedExpandRelatedProps?: any[];
 
- }
 
- export interface BodyContext {
 
-     getVirtualizedListRef: GetVirtualizedListRef;
 
- }
 
- class Body extends BaseComponent<BodyProps, BodyState> {
 
-     static contextType = TableContext;
 
-     static propTypes = {
 
-         anyColumnFixed: PropTypes.bool,
 
-         childrenRecordName: PropTypes.string,
 
-         columns: PropTypes.array,
 
-         components: PropTypes.object,
 
-         dataSource: PropTypes.array,
 
-         disabledRowKeysSet: PropTypes.instanceOf(Set).isRequired,
 
-         emptySlot: PropTypes.node,
 
-         expandRowByClick: PropTypes.bool,
 
-         expandedRowKeys: PropTypes.array,
 
-         expandedRowRender: PropTypes.func,
 
-         fixed: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
 
-         forwardedRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
 
-         groups: PropTypes.instanceOf(Map),
 
-         handleBodyScroll: PropTypes.func,
 
-         handleWheel: PropTypes.func,
 
-         headerRef: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
 
-         includeHeader: PropTypes.bool,
 
-         onScroll: PropTypes.func,
 
-         prefixCls: PropTypes.string,
 
-         renderExpandIcon: PropTypes.func,
 
-         rowExpandable: PropTypes.func,
 
-         rowKey: PropTypes.oneOfType([PropTypes.string, PropTypes.bool, PropTypes.func]),
 
-         scroll: PropTypes.object,
 
-         selectedRowKeysSet: PropTypes.instanceOf(Set).isRequired,
 
-         showHeader: PropTypes.bool,
 
-         size: PropTypes.string,
 
-         store: PropTypes.object,
 
-         virtualized: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
 
-     };
 
-     ref: React.MutableRefObject<any>;
 
-     listRef: React.MutableRefObject<any>;
 
-     observer: ResizeObserver;
 
-     foundation: BodyFoundation;
 
-     constructor(props: BodyProps, context: BodyContext) {
 
-         super(props);
 
-         this.ref = React.createRef();
 
-         this.state = {
 
-             virtualizedData: [],
 
-             cache: {
 
-                 virtualizedScrollTop: null,
 
-                 virtualizedScrollLeft: null,
 
-             },
 
-             cachedExpandBtnShouldInRow: null,
 
-             cachedExpandRelatedProps: [],
 
-         };
 
-         this.listRef = React.createRef();
 
-         const { getVirtualizedListRef } = context;
 
-         if (getVirtualizedListRef) {
 
-             if (props.virtualized) {
 
-                 getVirtualizedListRef(this.listRef);
 
-             } else {
 
-                 console.warn('getVirtualizedListRef only works with virtualized. ' +
 
-                     'See https://semi.design/zh-CN/show/table for more information.');
 
-             }
 
-         }
 
-         this.foundation = new BodyFoundation(this.adapter);
 
-         this.observer = null;
 
-     }
 
-     get adapter(): BodyAdapter<BodyProps, BodyState> {
 
-         return {
 
-             ...super.adapter,
 
-             setVirtualizedData: (virtualizedData, cb) => this.setState({ virtualizedData }, cb),
 
-             setCachedExpandBtnShouldInRow: cachedExpandBtnShouldInRow => this.setState({ cachedExpandBtnShouldInRow }),
 
-             setCachedExpandRelatedProps: cachedExpandRelatedProps => this.setState({ cachedExpandRelatedProps }),
 
-             observeBodyResize: (bodyWrapDOM: HTMLDivElement) => {
 
-                 const { setBodyHasScrollbar } = this.context;
 
-                 // Callback when the size of the body dom content changes, notifying Table.jsx whether the bodyHasScrollBar exists
 
-                 const resizeCallback = () => {
 
-                     const update = () => {
 
-                         const { offsetWidth, clientWidth } = bodyWrapDOM;
 
-                         const bodyHasScrollBar = clientWidth < offsetWidth;
 
-                         setBodyHasScrollbar(bodyHasScrollBar);
 
-                     };
 
-                     const requestAnimationFrame = window.requestAnimationFrame || window.setTimeout;
 
-                     requestAnimationFrame(update);
 
-                 };
 
-                 // Monitor body dom resize
 
-                 if (bodyWrapDOM) {
 
-                     if (get(window, 'ResizeObserver')) {
 
-                         if (this.observer) {
 
-                             this.observer.unobserve(bodyWrapDOM);
 
-                             this.observer = null;
 
-                         }
 
-                         this.observer = new ResizeObserver(resizeCallback);
 
-                         this.observer.observe(bodyWrapDOM);
 
-                     } else {
 
-                         logger.warn(
 
-                             'The current browser does not support ResizeObserver,' +
 
-                             'and the table may be misaligned after plugging and unplugging the mouse and keyboard.' +
 
-                             'You can try to refresh it.'
 
-                         );
 
-                     }
 
-                 }
 
-             },
 
-             unobserveBodyResize: () => {
 
-                 const bodyWrapDOM = this.ref.current;
 
-                 if (this.observer) {
 
-                     this.observer.unobserve(bodyWrapDOM);
 
-                     this.observer = null;
 
-                 }
 
-             }
 
-         };
 
-     }
 
-     componentDidUpdate(prevProps: BodyProps, prevState: BodyState) {
 
-         const { virtualized, dataSource, expandedRowKeys, columns, scroll  } = this.props;
 
-         if (virtualized) {
 
-             if (
 
-                 prevProps.dataSource !== dataSource ||
 
-                 prevProps.expandedRowKeys !== expandedRowKeys ||
 
-                 prevProps.columns !== columns
 
-             ) {
 
-                 this.foundation.initVirtualizedData();
 
-             }
 
-         }
 
-         const expandRelatedProps = strings.EXPAND_RELATED_PROPS;
 
-         const newExpandRelatedProps = expandRelatedProps.map(key => get(this.props, key, undefined));
 
-         if (!isEqual(newExpandRelatedProps, prevState.cachedExpandRelatedProps)) {
 
-             this.foundation.initExpandBtnShouldInRow(newExpandRelatedProps);
 
-         }
 
-         const scrollY = get(scroll, 'y');
 
-         const bodyWrapDOM = this.ref.current;
 
-         if (scrollY && scrollY !== get(prevProps, 'scroll.y')) {
 
-             this.foundation.observeBodyResize(bodyWrapDOM);
 
-         }
 
-     }
 
-     forwardRef = (node: HTMLDivElement) => {
 
-         const { forwardedRef } = this.props;
 
-         this.ref.current = node;
 
-         this.foundation.observeBodyResize(node);
 
-         if (typeof forwardedRef === 'function') {
 
-             forwardedRef(node);
 
-         } else if (forwardedRef && typeof forwardedRef === 'object') {
 
-             forwardedRef.current = node;
 
-         }
 
-     };
 
-     itemSize = (index: number) => {
 
-         const { virtualized, size: tableSize } = this.props;
 
-         const { virtualizedData } = this.state;
 
-         const virtualizedItem = get(virtualizedData, index);
 
-         const defaultConfig = getDefaultVirtualizedRowConfig(tableSize, virtualizedItem.sectionRow);
 
-         const itemSize = get(virtualized, 'itemSize', defaultConfig.height);
 
-         let realSize = itemSize;
 
-         if (typeof itemSize === 'function') {
 
-             realSize = itemSize(index, {
 
-                 expandedRow: get(virtualizedItem, 'expandedRow', false),
 
-                 sectionRow: get(virtualizedItem, 'sectionRow', false),
 
-             });
 
-         }
 
-         if (realSize < defaultConfig.minHeight) {
 
-             logger.warn(`The computed real \`itemSize\` cannot be less than ${defaultConfig.minHeight}`);
 
-         }
 
-         return realSize;
 
-     };
 
-     itemKey = (index: number, data: Array<FlattenData | GroupFlattenData>) => get(data, [index, 'key'], index);
 
-     handleRowClick = (rowKey: RowKey<any>, e: React.MouseEvent, expand: boolean) => {
 
-         const { handleRowExpanded } = this.context;
 
-         handleRowExpanded(!expand, rowKey, e);
 
-     };
 
-     handleVirtualizedScroll = (props = {}) => {
 
-         const onScroll = get(this.props.virtualized, 'onScroll');
 
-         if (typeof onScroll === 'function') {
 
-             onScroll(props);
 
-         }
 
-     };
 
-     /**
 
-      * @param {MouseEvent<HTMLDivElement>} e
 
-      */
 
-     handleVirtualizedBodyScroll = (e: BodyScrollEvent) => {
 
-         const { handleBodyScroll } = this.props;
 
-         const newScrollLeft = get(e, 'nativeEvent.target.scrollLeft');
 
-         const newScrollTop = get(e, 'nativeEvent.target.scrollTop');
 
-         if (newScrollTop === this.state.cache.virtualizedScrollTop) {
 
-             this.handleVirtualizedScroll({ horizontalScrolling: true });
 
-         }
 
-         this.state.cache.virtualizedScrollLeft = newScrollLeft;
 
-         this.state.cache.virtualizedScrollTop = newScrollTop;
 
-         if (typeof handleBodyScroll === 'function') {
 
-             handleBodyScroll(e);
 
-         }
 
-     };
 
-     getVirtualizedRowWidth = () => {
 
-         const { getCellWidths } = this.context;
 
-         const { columns } = this.props;
 
-         const cellWidths = getCellWidths(columns);
 
-         const rowWidth = arrayAdd(cellWidths, 0, size(columns));
 
-         return rowWidth;
 
-     };
 
-     renderVirtualizedRow = (options: { index?: number; style?: React.CSSProperties; isScrolling?: boolean }) => {
 
-         const { index, style } = options;
 
-         const { virtualizedData, cachedExpandBtnShouldInRow } = this.state;
 
-         const { flattenedColumns } = this.context;
 
-         const virtualizedItem: any = get(virtualizedData, [index], {});
 
-         // eslint-disable-next-line @typescript-eslint/no-unused-vars
 
-         const { key, parentKeys, expandedRow, sectionRow, ...rest } = virtualizedItem;
 
-         const rowWidth = this.getVirtualizedRowWidth();
 
-         const expandBtnShouldInRow = cachedExpandBtnShouldInRow;
 
-         const props = {
 
-             ...this.props,
 
-             style: {
 
-                 ...style,
 
-                 width: rowWidth,
 
-             },
 
-             ...rest,
 
-             columns: flattenedColumns,
 
-             index,
 
-             expandBtnShouldInRow,
 
-         };
 
-         // eslint-disable-next-line no-nested-ternary
 
-         return sectionRow ?
 
-             this.renderSectionRow(props) :
 
-             expandedRow ?
 
-                 this.renderExpandedRow(props) :
 
-                 this.renderBaseRow(props);
 
-     };
 
-     // virtualized List innerElementType
 
-     renderTbody = React.forwardRef<HTMLDivElement, any>((props: any = {}, ref: React.MutableRefObject<HTMLDivElement> | ((instance: HTMLDivElement) => void)) => (
 
-         <div
 
-             {...props}
 
-             onScroll={(...args) => {
 
-                 if (props.onScroll) {
 
-                     props.onScroll(...args);
 
-                 }
 
-             }}
 
-             // eslint-disable-next-line react/no-this-in-sfc,react/destructuring-assignment
 
-             className={classnames(props.className, `${this.props.prefixCls}-tbody`)}
 
-             style={{ ...props.style }}
 
-             ref={ref}
 
-         />
 
-     ));
 
-     // virtualized List outerElementType
 
-     renderOuter = React.forwardRef<HTMLDivElement, any>((props: any, ref: React.MutableRefObject<HTMLDivElement> | ((instance: HTMLDivElement) => void)) => {
 
-         const { children, ...rest } = props;
 
-         // eslint-disable-next-line react/no-this-in-sfc
 
-         const { handleWheel, prefixCls, emptySlot, dataSource } = this.props;
 
-         // eslint-disable-next-line react/no-this-in-sfc
 
-         const tableWidth = this.getVirtualizedRowWidth();
 
-         const tableCls = classnames(`${prefixCls}`, `${prefixCls}-fixed`);
 
-         return (
 
-             <div
 
-                 {...rest}
 
-                 ref={ref}
 
-                 onWheel={(...args) => {
 
-                     if (handleWheel) {
 
-                         handleWheel(...args);
 
-                     }
 
-                     if (rest.onWheel) {
 
-                         rest.onWheel(...args);
 
-                     }
 
-                 }}
 
-                 onScroll={(...args) => {
 
-                     // eslint-disable-next-line react/no-this-in-sfc
 
-                     this.handleVirtualizedBodyScroll(...args);
 
-                     if (rest.onScroll) {
 
-                         rest.onScroll(...args);
 
-                     }
 
-                 }}
 
-             >
 
-                 <div style={{ width: tableWidth }} className={tableCls}>
 
-                     {size(dataSource) === 0 ? emptySlot : children}
 
-                 </div>
 
-             </div>
 
-         );
 
-     });
 
-     onItemsRendered = (props: { overscanStartIndex: number; overscanStopIndex: number; visibleStartIndex: number; visibleStopIndex: number }) => {
 
-         if (this.state.cache.virtualizedScrollLeft && this.ref.current) {
 
-             this.ref.current.scrollLeft = this.state.cache.virtualizedScrollLeft;
 
-         }
 
-     };
 
-     renderVirtualizedBody = (direction?: Direction) => {
 
-         const { scroll, prefixCls, virtualized, anyColumnFixed, columns } = this.props;
 
-         const { virtualizedData } = this.state;
 
-         const { getCellWidths } = this.context;
 
-         const cellWidths = getCellWidths(columns);
 
-         if (!size(cellWidths)) {
 
-             return null;
 
-         }
 
-         const rawY = get(scroll, 'y');
 
-         const yIsNumber = typeof rawY === 'number';
 
-         const y = yIsNumber ? rawY : 600;
 
-         if (!yIsNumber) {
 
-             logger.warn('You have to specific "scroll.y" which must be a number for table virtualization!');
 
-         }
 
-         const listStyle = {
 
-             width: '100%',
 
-             height: y,
 
-             overflowX: 'auto',
 
-             overflowY: 'auto',
 
-         } as const;
 
-         const wrapCls = classnames(`${prefixCls}-body`);
 
-         return (
 
-             <List<Array<FlattenData | GroupFlattenData>>
 
-                 {...virtualized}
 
-                 initialScrollOffset={this.state.cache.virtualizedScrollTop}
 
-                 onScroll={this.handleVirtualizedScroll}
 
-                 onItemsRendered={this.onItemsRendered}
 
-                 ref={this.listRef}
 
-                 className={wrapCls}
 
-                 outerRef={this.forwardRef}
 
-                 height={listStyle.height}
 
-                 width={listStyle.width}
 
-                 itemData={virtualizedData}
 
-                 itemSize={this.itemSize}
 
-                 itemCount={virtualizedData.length}
 
-                 itemKey={this.itemKey}
 
-                 innerElementType={this.renderTbody}
 
-                 outerElementType={this.renderOuter}
 
-                 style={{ ...listStyle, direction }}
 
-                 direction={direction}
 
-             >
 
-                 {this.renderVirtualizedRow}
 
-             </List>
 
-         );
 
-     };
 
-     /**
 
-      * render group title
 
-      * @param {*} props
 
-      */
 
-     renderSectionRow = (props: RenderSectionRowProps = { groupKey: undefined }) => {
 
-         const { dataSource, rowKey, group, groupKey, index } = props;
 
-         const sectionRowPickKeys = Object.keys(SectionRow.propTypes);
 
-         const sectionRowProps: any = pick(props, sectionRowPickKeys);
 
-         const { handleRowExpanded } = this.context;
 
-         return (
 
-             <SectionRow
 
-                 {...sectionRowProps}
 
-                 record={{
 
-                     groupKey,
 
-                     records: [...group].map(recordKey => getRecord(dataSource, recordKey, rowKey)),
 
-                 }}
 
-                 index={index}
 
-                 onExpand={handleRowExpanded}
 
-                 data={dataSource}
 
-                 key={groupKey || index}
 
-             />
 
-         );
 
-     };
 
-     renderExpandedRow = (props: RenderExpandedRowProps = { renderExpandIcon: () => null }) => {
 
-         const {
 
-             style,
 
-             components,
 
-             renderExpandIcon,
 
-             expandedRowRender,
 
-             record,
 
-             columns,
 
-             expanded,
 
-             index,
 
-             rowKey,
 
-             virtualized,
 
-         } = props;
 
-         let key = getRecordKey(record, rowKey);
 
-         if (key == null) {
 
-             key = index;
 
-         }
 
-         const { flattenedColumns, getCellWidths } = this.context;
 
-         const cellWidths = getCellWidths(flattenedColumns);
 
-         return (
 
-             <ExpandedRow
 
-                 style={style}
 
-                 components={components}
 
-                 renderExpandIcon={renderExpandIcon}
 
-                 expandedRowRender={expandedRowRender}
 
-                 record={record}
 
-                 columns={columns}
 
-                 expanded={expanded}
 
-                 index={index}
 
-                 virtualized={virtualized}
 
-                 key={genExpandedRowKey(key)}
 
-                 cellWidths={cellWidths}
 
-             />
 
-         );
 
-     };
 
-     /**
 
-      * render base row
 
-      * @param {*} props
 
-      * @returns
 
-      */
 
-     renderBaseRow(props: any = {}) {
 
-         const {
 
-             rowKey,
 
-             columns,
 
-             expandedRowKeys,
 
-             rowExpandable,
 
-             record,
 
-             index,
 
-             level,
 
-             expandBtnShouldInRow, // effect the display of the indent span
 
-             selectedRowKeysSet,
 
-             disabledRowKeysSet,
 
-             expandRowByClick,
 
-         } = props;
 
-         const baseRowPickKeys = Object.keys(BaseRow.propTypes);
 
-         const baseRowProps: Record<string, any> = pick(props, baseRowPickKeys);
 
-         let key = getRecordKey(record, rowKey);
 
-         if (key == null) {
 
-             key = index;
 
-         }
 
-         const expanded = isExpanded(expandedRowKeys, key);
 
-         const expandable = rowExpandable && rowExpandable(record);
 
-         const expandableProps: {
 
-             level?: number;
 
-             expanded?: boolean;
 
-             expandableRow?: boolean;
 
-             onRowClick?: (...args: any[]) => void;
 
-         } = {
 
-             level: undefined,
 
-             expanded,
 
-         };
 
-         if (expandable || expandBtnShouldInRow) {
 
-             expandableProps.level = level;
 
-             expandableProps.expandableRow = expandable;
 
-             if (expandRowByClick) {
 
-                 expandableProps.onRowClick = this.handleRowClick;
 
-             }
 
-         }
 
-         const selectionProps = {
 
-             selected: isSelected(selectedRowKeysSet, key),
 
-             disabled: isDisabled(disabledRowKeysSet, key),
 
-         };
 
-         const { getCellWidths } = this.context;
 
-         const cellWidths = getCellWidths(columns, null, true);
 
-         return (
 
-             <BaseRow
 
-                 {...baseRowProps}
 
-                 {...expandableProps}
 
-                 {...selectionProps}
 
-                 key={key}
 
-                 rowKey={key}
 
-                 cellWidths={cellWidths}
 
-             />
 
-         );
 
-     }
 
-     /**
 
-      * render grouped rows
 
-      * @returns {ReactNode[]} renderedRows
 
-      */
 
-     renderGroupedRows = () => {
 
-         const { groups, dataSource: data, rowKey, expandedRowKeys } = this.props;
 
-         const { flattenedColumns } = this.context;
 
-         const groupsInData = new Map();
 
-         const renderedRows: ReactNode[] = [];
 
-         if (groups != null && Array.isArray(data) && data.length) {
 
-             data.forEach(record => {
 
-                 const recordKey = getRecordKey(record, rowKey);
 
-                 groups.forEach((group: Map<string, Record<string, any>[]>, key: number) => {
 
-                     if (group.has(recordKey)) {
 
-                         if (!groupsInData.has(key)) {
 
-                             groupsInData.set(key, new Set([]));
 
-                         }
 
-                         groupsInData.get(key).add(recordKey);
 
-                         return false;
 
-                     }
 
-                     return undefined;
 
-                 });
 
-             });
 
-         }
 
-         let index = -1;
 
-         groupsInData.forEach((group, groupKey) => {
 
-             // Calculate the expanded state of the group
 
-             const expanded = isExpanded(expandedRowKeys, groupKey);
 
-             // Render the title of the group
 
-             renderedRows.push(
 
-                 this.renderSectionRow({
 
-                     ...this.props,
 
-                     columns: flattenedColumns,
 
-                     index: ++index,
 
-                     group,
 
-                     groupKey,
 
-                     expanded,
 
-                 })
 
-             );
 
-             // Render the grouped content when the group is expanded
 
-             if (expanded) {
 
-                 const dataInGroup: any[] = [];
 
-                 group.forEach((recordKey: string) => {
 
-                     const record = getRecord(data, recordKey, rowKey);
 
-                     if (record != null) {
 
-                         dataInGroup.push(record);
 
-                     }
 
-                 });
 
-                 /**
 
-                  * Render the contents of the group row
 
-                  */
 
-                 renderedRows.push(this.renderBodyRows(dataInGroup));
 
-             }
 
-         });
 
-         return renderedRows;
 
-     };
 
-     renderBodyRows(data: Record<string, any>[] = [], level = 0, renderedRows: ReactNode[] = []) {
 
-         const {
 
-             rowKey,
 
-             expandedRowRender,
 
-             expandedRowKeys,
 
-             childrenRecordName,
 
-             rowExpandable,
 
-         } = this.props;
 
-         const hasExpandedRowRender = typeof expandedRowRender === 'function';
 
-         const expandBtnShouldInRow = this.state.cachedExpandBtnShouldInRow;
 
-         const { flattenedColumns } = this.context;
 
-         each(data, (record, index) => {
 
-             let key = getRecordKey(record, rowKey);
 
-             if (key == null) {
 
-                 key = index;
 
-             }
 
-             const recordChildren = get(record, childrenRecordName);
 
-             const recordHasChildren = Boolean(Array.isArray(recordChildren) && recordChildren.length);
 
-             renderedRows.push(
 
-                 this.renderBaseRow({
 
-                     ...this.props,
 
-                     columns: flattenedColumns,
 
-                     expandBtnShouldInRow,
 
-                     record,
 
-                     key,
 
-                     level,
 
-                     index,
 
-                 })
 
-             );
 
-             // render expand row
 
-             const expanded = isExpanded(expandedRowKeys, key);
 
-             if (hasExpandedRowRender && rowExpandable && rowExpandable(record) && expanded) {
 
-                 const currentExpandRow = this.renderExpandedRow({
 
-                     ...this.props,
 
-                     columns: flattenedColumns,
 
-                     level,
 
-                     index,
 
-                     record,
 
-                     expanded,
 
-                 });
 
-                 /**
 
-                   * If expandedRowRender returns falsy, this expanded row will not be rendered
 
-                   * Render an empty div before v1.19.7
 
-                   */
 
-                 if (!isNull(currentExpandRow)) {
 
-                     renderedRows.push(currentExpandRow);
 
-                 }
 
-             }
 
-             // render tree data
 
-             if (recordHasChildren && expanded) {
 
-                 const nestedRows = this.renderBodyRows(recordChildren, level + 1);
 
-                 renderedRows.push(...nestedRows);
 
-             }
 
-         });
 
-         return renderedRows;
 
-     }
 
-     renderBody = (direction?: Direction) => {
 
-         const {
 
-             scroll,
 
-             prefixCls,
 
-             columns,
 
-             components,
 
-             fixed,
 
-             handleWheel,
 
-             headerRef,
 
-             handleBodyScroll,
 
-             anyColumnFixed,
 
-             showHeader,
 
-             emptySlot,
 
-             includeHeader,
 
-             dataSource,
 
-             onScroll,
 
-             groups,
 
-             expandedRowRender,
 
-         } = this.props;
 
-         const x = get(scroll, 'x');
 
-         const y = get(scroll, 'y');
 
-         const bodyStyle: {
 
-             maxHeight?: string | number;
 
-             overflow?: string;
 
-             WebkitTransform?: string;
 
-         } = {};
 
-         const tableStyle: {
 
-             width?: string | number;
 
-         } = {};
 
-         const Table = get(components, 'body.outer', 'table');
 
-         const BodyWrapper = get(components, 'body.wrapper') || 'tbody';
 
-         if (y) {
 
-             bodyStyle.maxHeight = y;
 
-         }
 
-         if (x) {
 
-             tableStyle.width = x;
 
-         }
 
-         if (anyColumnFixed && size(dataSource)) {
 
-             // Auto is better than scroll. For example, when there is only scrollY, the scroll axis is not displayed horizontally.
 
-             bodyStyle.overflow = 'auto';
 
-             // Fix weird webkit render bug
 
-             bodyStyle.WebkitTransform = 'translate3d (0, 0, 0)';
 
-         }
 
-         const colgroup = <ColGroup components={get(components, 'body')} columns={columns} prefixCls={prefixCls} />;
 
-         // const tableBody = this.renderBody();
 
-         const wrapCls = `${prefixCls}-body`;
 
-         const baseTable = (
 
-             <div
 
-                 key="bodyTable"
 
-                 className={wrapCls}
 
-                 style={bodyStyle}
 
-                 ref={this.forwardRef}
 
-                 onWheel={handleWheel}
 
-                 onScroll={handleBodyScroll}
 
-             >
 
-                 <Table
 
-                     role={ isMap(groups) || isFunction(expandedRowRender) || isTreeTable({ dataSource }) ? 'treegrid' : 'grid'}
 
-                     aria-rowcount={dataSource && dataSource.length}
 
-                     aria-colcount={columns && columns.length}
 
-                     style={tableStyle}
 
-                     className={classnames(prefixCls, {
 
-                         [`${prefixCls}-fixed`]: anyColumnFixed,
 
-                     })}
 
-                 >
 
-                     {colgroup}
 
-                     {includeHeader && showHeader ? (
 
-                         <TableHeader {...this.props} ref={headerRef} components={components} columns={columns} />
 
-                     ) : null}
 
-                     <BodyWrapper className={`${prefixCls}-tbody`} onScroll={onScroll}>
 
-                         {isMap(groups) ? this.renderGroupedRows() : this.renderBodyRows(dataSource)}
 
-                     </BodyWrapper>
 
-                 </Table>
 
-                 {emptySlot}
 
-             </div>
 
-         );
 
-         if (fixed && columns.length) {
 
-             return (
 
-                 <div key="bodyTable" className={`${prefixCls}-body-outer`}>
 
-                     {baseTable}
 
-                 </div>
 
-             );
 
-         }
 
-         return baseTable;
 
-     };
 
-     render() {
 
-         const { virtualized } = this.props;
 
-         return (
 
-             <ConfigContext.Consumer>
 
-                 {({ direction }: { direction?: Direction }) => (virtualized ? this.renderVirtualizedBody(direction) : this.renderBody(direction))}
 
-             </ConfigContext.Consumer>
 
-         );
 
-     }
 
- }
 
- export default React.forwardRef<HTMLDivElement, Omit<BodyProps, 'forwardedRef'>>(function TableBody(props, ref) {
 
-     return <Body {...props} forwardedRef={ref} />;
 
- });
 
- export interface RenderExpandedRowProps {
 
-     style?: React.CSSProperties;
 
-     components?: TableComponents;
 
-     renderExpandIcon: (record?: Record<string, any>, isNested?: boolean) => ReactNode | null;
 
-     expandedRowRender?: ExpandedRowRender<Record<string, any>>;
 
-     record?: Record<string, any>;
 
-     columns?: ColumnProps[];
 
-     expanded?: boolean;
 
-     index?: number;
 
-     rowKey?: RowKey<Record<string, any>>;
 
-     virtualized?: Virtualized;
 
-     level?: number;
 
- }
 
- export interface RenderSectionRowProps {
 
-     dataSource?: Record<string, any>[];
 
-     columns?: ColumnProps[];
 
-     rowKey?: RowKey<Record<string, any>>;
 
-     group?: any;
 
-     groupKey: string | number;
 
-     index?: number;
 
-     expanded?: boolean;
 
- }
 
 
  |