| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859 | /* 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, { TableContextProps } 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;    flattenedColumns: ColumnProps[];    getCellWidths: (flattenedColumns: ColumnProps[]) => number[];}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;    cellWidths: number[];    flattenedColumns: ColumnProps[];    context: TableContextProps;    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, flattenedColumns, getCellWidths } = 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.flattenedColumns = flattenedColumns;        this.cellWidths = getCellWidths(flattenedColumns);        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<HTMLElement>, 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: virtualizedData?.length ? y : 0,            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;        // we use memoized cellWidths to avoid re-render expanded row (fix #686)        if (flattenedColumns !== this.flattenedColumns) {            this.flattenedColumns = flattenedColumns;            this.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={this.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;}
 |