diff --git a/README.md b/README.md index b4e6ca591..80966f048 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ Then open `http://localhost:8000`. | expandable.defaultExpandedRowKeys | String[] | [] | initial expanded rows keys | | expandable.expandedRowKeys | String[] | | current expanded rows keys | | expandable.expandedRowRender | Function(recode, index, indent, expanded):ReactNode | | Content render to expanded row | +| expandable.forceRender | Boolean | false | Force render expanded row content before expansion | | expandable.expandedRowClassName | `string` \| `(recode, index, indent) => string` | | get expanded row's className | | expandable.expandRowByClick | boolean | | Support expand by click row | | expandable.expandIconColumnIndex | Number | 0 | The index of expandIcon which column will be inserted when expandIconAsCell is false | diff --git a/README.zh-CN.md b/README.zh-CN.md index e9a9f762e..e5153e782 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -82,6 +82,7 @@ npm start | expandable.defaultExpandedRowKeys | String[] | [] | 初始扩展行键 | | expandable.expandedRowKeys | String[] | | 当前扩展行键 | | expandable.expandedRowRender | Function(recode, index, indent, expanded):ReactNode | | 内容渲染到扩展行 | +| expandable.forceRender | Boolean | false | 在展开前强制渲染展开行内容 | | expandable.expandedRowClassName | `string` \| `(recode, index, indent) => string` | | 获取扩展行的 className | | expandable.expandRowByClick | boolean | | 支持点击行展开 | | expandable.expandIconColumnIndex | Number | 0 | ExpandIconAsCell 为 false 时将插入哪一列的 ExpandIcon 索引 | diff --git a/src/Body/BodyRow.tsx b/src/Body/BodyRow.tsx index aae9f4c7b..13435f0ab 100644 --- a/src/Body/BodyRow.tsx +++ b/src/Body/BodyRow.tsx @@ -146,6 +146,7 @@ const BodyRow = ( flattenColumns, expandedRowClassName, expandedRowRender, + forceRender, rowProps, // Misc @@ -153,7 +154,7 @@ const BodyRow = ( rowSupportExpand, } = rowInfo; - // Force render expand row if expanded before + // Keep the expanded row mounted after it has been expanded const expandedRef = React.useRef(false); expandedRef.current ||= expanded; @@ -224,7 +225,7 @@ const BodyRow = ( // ======================== Expand Row ========================= let expandRowNode: React.ReactElement; - if (rowSupportExpand && (expandedRef.current || expanded)) { + if (rowSupportExpand && (forceRender || expandedRef.current || expanded)) { const expandContent = expandedRowRender(record, index, indent + 1, expanded); expandRowNode = ( diff --git a/src/Table.tsx b/src/Table.tsx index 26f9cf3f4..18cc0169b 100644 --- a/src/Table.tsx +++ b/src/Table.tsx @@ -910,6 +910,7 @@ const Table = ( expandableType, expandRowByClick: expandableConfig.expandRowByClick, expandedRowRender: expandableConfig.expandedRowRender, + forceRender: expandableConfig.forceRender, expandedRowOffset: expandableConfig.expandedRowOffset, onTriggerExpand, expandIconColumnIndex: expandableConfig.expandIconColumnIndex, @@ -967,6 +968,7 @@ const Table = ( expandableType, expandableConfig.expandRowByClick, expandableConfig.expandedRowRender, + expandableConfig.forceRender, expandableConfig.expandedRowOffset, onTriggerExpand, expandableConfig.expandIconColumnIndex, diff --git a/src/VirtualTable/BodyLine.tsx b/src/VirtualTable/BodyLine.tsx index 21562f69b..ca2cf8e34 100644 --- a/src/VirtualTable/BodyLine.tsx +++ b/src/VirtualTable/BodyLine.tsx @@ -43,12 +43,19 @@ const BodyLine = React.forwardRef((props, ref) => const cellComponent = getComponent(['body', 'cell'], 'div'); // ========================== Expand ========================== - const { rowSupportExpand, expanded, rowProps, expandedRowRender, expandedRowClassName } = rowInfo; + const { + rowSupportExpand, + expanded, + rowProps, + expandedRowRender, + expandedRowClassName, + forceRender, + } = rowInfo; const expandedClsName = computedExpandedClassName(expandedRowClassName, record, index, indent); let expandRowNode: React.ReactElement; - if (rowSupportExpand && expanded) { + if (rowSupportExpand && (forceRender || expanded)) { const expandContent = expandedRowRender(record, index, indent + 1, expanded); let additionalProps: React.TdHTMLAttributes = {}; @@ -69,6 +76,7 @@ const BodyLine = React.forwardRef((props, ref) => `${prefixCls}-expanded-row-level-${indent + 1}`, expandedClsName, )} + style={{ display: expanded ? undefined : 'none' }} > { expandableType: ExpandableType; expandRowByClick: boolean; expandedRowRender: ExpandedRowRender; + forceRender: boolean; expandIcon: RenderExpandIcon; onTriggerExpand: TriggerEventHandler; expandIconColumnIndex: number; diff --git a/src/hooks/useRowInfo.tsx b/src/hooks/useRowInfo.tsx index 724aafe5a..cdba4059e 100644 --- a/src/hooks/useRowInfo.tsx +++ b/src/hooks/useRowInfo.tsx @@ -23,6 +23,7 @@ export default function useRowInfo( | 'indentSize' | 'expandIcon' | 'expandedRowRender' + | 'forceRender' | 'expandIconColumnIndex' | 'expandedKeys' | 'childrenColumnName' @@ -49,6 +50,7 @@ export default function useRowInfo( 'indentSize', 'expandIcon', 'expandedRowRender', + 'forceRender', 'expandIconColumnIndex', 'expandedKeys', 'childrenColumnName', diff --git a/src/interface.ts b/src/interface.ts index d5a8aee03..bea4a689e 100644 --- a/src/interface.ts +++ b/src/interface.ts @@ -90,10 +90,7 @@ export type Direction = 'ltr' | 'rtl'; export type SpecialString = T | (string & NonNullable); export type DataIndex = - | DeepNamePath - | SpecialString - | number - | (SpecialString | number)[]; + DeepNamePath | SpecialString | number | (SpecialString | number)[]; export type CellEllipsisType = { showTitle?: boolean } | boolean; @@ -139,8 +136,7 @@ export interface ColumnType extends ColumnSharedType { } export type ColumnsType = readonly ( - | ColumnGroupType - | ColumnType + ColumnGroupType | ColumnType )[]; export type GetRowKey = (record: RecordType, index?: number) => Key; @@ -257,6 +253,7 @@ export interface ExpandableConfig { expandedRowKeys?: readonly Key[]; defaultExpandedRowKeys?: readonly Key[]; expandedRowRender?: ExpandedRowRender; + forceRender?: boolean; columnTitle?: React.ReactNode; expandRowByClick?: boolean; expandIcon?: RenderExpandIcon; diff --git a/tests/ExpandRow.spec.jsx b/tests/ExpandRow.spec.jsx index d15eaa15b..5bafa15ac 100644 --- a/tests/ExpandRow.spec.jsx +++ b/tests/ExpandRow.spec.jsx @@ -39,6 +39,37 @@ describe('Table.Expand', () => { expect(rowRender).toHaveBeenLastCalledWith(sampleData[0], 0, 1, false); }); + it('force renders expanded rows before expansion', () => { + const rowRender = vi.fn(record =>
{record.name} expanded row
); + const { container } = render( + createTable({ + expandable: { + expandedRowRender: rowRender, + forceRender: true, + }, + }), + ); + + const expandedRows = container.querySelectorAll('.rc-table-expanded-row'); + + expect(rowRender).toHaveBeenCalledTimes(2); + expect(rowRender).toHaveBeenNthCalledWith(1, sampleData[0], 0, 1, false); + expect(rowRender).toHaveBeenNthCalledWith(2, sampleData[1], 1, 1, false); + expect(expandedRows).toHaveLength(2); + expect(expandedRows[0]).toHaveStyle({ display: 'none' }); + expect(expandedRows[1]).toHaveStyle({ display: 'none' }); + + fireEvent.click(container.querySelector('.rc-table-row-expand-icon')); + + expect(expandedRows[0]).not.toHaveStyle({ display: 'none' }); + expect(expandedRows[1]).toHaveStyle({ display: 'none' }); + + fireEvent.click(container.querySelector('.rc-table-row-expand-icon')); + + expect(expandedRows[0]).toHaveStyle({ display: 'none' }); + expect(expandedRows[1]).toHaveStyle({ display: 'none' }); + }); + it('renders tree row correctly', () => { const data = [ { diff --git a/tests/Virtual.spec.tsx b/tests/Virtual.spec.tsx index 8eb49c165..e0f2f4016 100644 --- a/tests/Virtual.spec.tsx +++ b/tests/Virtual.spec.tsx @@ -180,6 +180,37 @@ describe('Table.Virtual', () => { }); }); + it('force renders expanded rows before expansion', () => { + const expandedRowRender = vi.fn((record: { name: string }) => record.name); + const { container } = getTable({ + data: [{ name: 'name0', age: 0, address: 'address0' }], + expandable: { + expandedRowRender, + forceRender: true, + }, + }); + + expect(expandedRowRender).toHaveBeenCalledWith( + { name: 'name0', age: 0, address: 'address0' }, + 0, + 1, + false, + ); + expect(container.querySelector('.rc-table-expanded-row')).toHaveStyle({ display: 'none' }); + + fireEvent.click(container.querySelector('.rc-table-row-expand-icon')!); + + expect(container.querySelector('.rc-table-expanded-row')).not.toHaveStyle({ + display: 'none', + }); + + fireEvent.click(container.querySelector('.rc-table-row-expand-icon')!); + + expect(container.querySelector('.rc-table-expanded-row')).toHaveStyle({ + display: 'none', + }); + }); + it('applies expanded row class to tree rows', () => { const { container } = getTable({ data: [