Skip to content

Commit 2c075f1

Browse files
authored
feat: support virtual components.body (#1069)
* feat: support virtual components.body * test: add test case * demo: restore * perf: perf context * fix: remove unused code
1 parent 5926b1c commit 2c075f1

File tree

6 files changed

+54
-17
lines changed

6 files changed

+54
-17
lines changed

src/VirtualTable/BodyGrid.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ const Grid = React.forwardRef<GridRef, GridProps>((props, ref) => {
4141
'emptyNode',
4242
'scrollX',
4343
]);
44-
const { sticky, scrollY, listItemHeight } = useContext(StaticContext);
44+
const { sticky, scrollY, listItemHeight, getComponent } = useContext(StaticContext);
4545

4646
// =========================== Ref ============================
4747
const listRef = React.useRef<ListRef>();
@@ -198,6 +198,11 @@ const Grid = React.forwardRef<GridRef, GridProps>((props, ref) => {
198198
// ========================== Render ==========================
199199
const tblPrefixCls = `${prefixCls}-tbody`;
200200

201+
// default 'div' in rc-virtual-list
202+
const wrapperComponent = getComponent(['body', 'wrapper']);
203+
const RowComponent = getComponent(['body', 'row'], 'div');
204+
const cellComponent = getComponent(['body', 'cell'], 'div');
205+
201206
let bodyContent: React.ReactNode;
202207
if (flattenData.length) {
203208
// ========================== Sticky Scroll Bar ==========================
@@ -220,6 +225,7 @@ const Grid = React.forwardRef<GridRef, GridProps>((props, ref) => {
220225
itemHeight={listItemHeight || 24}
221226
data={flattenData}
222227
itemKey={item => getRowKey(item.record)}
228+
component={wrapperComponent}
223229
scrollWidth={scrollX as number}
224230
onVirtualScroll={({ x }) => {
225231
onScroll({
@@ -236,11 +242,11 @@ const Grid = React.forwardRef<GridRef, GridProps>((props, ref) => {
236242
);
237243
} else {
238244
bodyContent = (
239-
<div className={classNames(`${prefixCls}-placeholder`)}>
240-
<Cell component="div" prefixCls={prefixCls}>
245+
<RowComponent className={classNames(`${prefixCls}-placeholder`)}>
246+
<Cell component={cellComponent} prefixCls={prefixCls}>
241247
{emptyNode}
242248
</Cell>
243-
</div>
249+
</RowComponent>
244250
);
245251
}
246252

src/VirtualTable/BodyLine.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import TableContext, { responseImmutable } from '../context/TableContext';
66
import type { FlattenData } from '../hooks/useFlattenRecords';
77
import useRowInfo from '../hooks/useRowInfo';
88
import VirtualCell from './VirtualCell';
9+
import { StaticContext } from './context';
910

1011
export interface BodyLineProps<RecordType = any> {
1112
data: FlattenData<RecordType>;
@@ -27,9 +28,13 @@ const BodyLine = React.forwardRef<HTMLDivElement, BodyLineProps>((props, ref) =>
2728
TableContext,
2829
['prefixCls', 'flattenColumns', 'fixColumn', 'componentWidth', 'scrollX'],
2930
);
31+
const { getComponent } = useContext(StaticContext, ['getComponent']);
3032

3133
const rowInfo = useRowInfo(record, rowKey, index, indent);
3234

35+
const RowComponent = getComponent(['body', 'row'], 'div');
36+
const cellComponent = getComponent(['body', 'cell'], 'div');
37+
3338
// ========================== Expand ==========================
3439
const { rowSupportExpand, expanded, rowProps, expandedRowRender, expandedRowClassName } = rowInfo;
3540

@@ -50,15 +55,15 @@ const BodyLine = React.forwardRef<HTMLDivElement, BodyLineProps>((props, ref) =>
5055
const rowCellCls = `${prefixCls}-expanded-row-cell`;
5156

5257
expandRowNode = (
53-
<div
58+
<RowComponent
5459
className={classNames(
5560
`${prefixCls}-expanded-row`,
5661
`${prefixCls}-expanded-row-level-${indent + 1}`,
5762
computedExpandedRowClassName,
5863
)}
5964
>
6065
<Cell
61-
component="div"
66+
component={cellComponent}
6267
prefixCls={prefixCls}
6368
className={classNames(rowCellCls, {
6469
[`${rowCellCls}-fixed`]: fixColumn,
@@ -67,12 +72,11 @@ const BodyLine = React.forwardRef<HTMLDivElement, BodyLineProps>((props, ref) =>
6772
>
6873
{expandContent}
6974
</Cell>
70-
</div>
75+
</RowComponent>
7176
);
7277
}
7378

7479
// ========================== Render ==========================
75-
7680
const rowStyle: React.CSSProperties = {
7781
...style,
7882
width: scrollX as number,
@@ -84,7 +88,7 @@ const BodyLine = React.forwardRef<HTMLDivElement, BodyLineProps>((props, ref) =>
8488
}
8589

8690
const rowNode = (
87-
<div
91+
<RowComponent
8892
{...rowProps}
8993
{...restProps}
9094
ref={rowSupportExpand ? null : ref}
@@ -97,6 +101,7 @@ const BodyLine = React.forwardRef<HTMLDivElement, BodyLineProps>((props, ref) =>
97101
return (
98102
<VirtualCell
99103
key={colIndex}
104+
component={cellComponent}
100105
rowInfo={rowInfo}
101106
column={column}
102107
colIndex={colIndex}
@@ -109,7 +114,7 @@ const BodyLine = React.forwardRef<HTMLDivElement, BodyLineProps>((props, ref) =>
109114
/>
110115
);
111116
})}
112-
</div>
117+
</RowComponent>
113118
);
114119

115120
if (rowSupportExpand) {

src/VirtualTable/VirtualCell.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import * as React from 'react';
44
import { getCellProps } from '../Body/BodyRow';
55
import Cell from '../Cell';
66
import type useRowInfo from '../hooks/useRowInfo';
7-
import type { ColumnType } from '../interface';
7+
import type { ColumnType, CustomizeComponent } from '../interface';
88
import { GridContext } from './context';
99

1010
export interface VirtualCellProps<RecordType> {
@@ -13,6 +13,7 @@ export interface VirtualCellProps<RecordType> {
1313
colIndex: number;
1414
indent: number;
1515
index: number;
16+
component?: CustomizeComponent;
1617
/** Used for `column.render` */
1718
renderIndex: number;
1819
record: RecordType;
@@ -42,6 +43,7 @@ function VirtualCell<RecordType = any>(props: VirtualCellProps<RecordType>) {
4243
colIndex,
4344
indent,
4445
index,
46+
component,
4547
renderIndex,
4648
record,
4749
style,
@@ -114,7 +116,7 @@ function VirtualCell<RecordType = any>(props: VirtualCellProps<RecordType>) {
114116
ellipsis={column.ellipsis}
115117
align={column.align}
116118
scope={column.rowScope}
117-
component="div"
119+
component={component}
118120
prefixCls={rowInfo.prefixCls}
119121
key={key}
120122
record={record}

src/VirtualTable/context.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
import { createContext } from '@rc-component/context';
2-
import type { TableSticky } from '../interface';
2+
import type { GetComponent, TableSticky } from '../interface';
33

44
export interface StaticContextProps {
55
scrollY: number;
66
listItemHeight: number;
77
sticky: boolean | TableSticky;
8+
getComponent: GetComponent;
89
}
910

1011
export const StaticContext = createContext<StaticContextProps>(null);

src/VirtualTable/index.tsx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import type { CompareProps } from '@rc-component/context/lib/Immutable';
22
import classNames from 'classnames';
3-
import { warning } from 'rc-util';
3+
import { useEvent, warning } from 'rc-util';
44
import * as React from 'react';
55
import { INTERNAL_HOOKS } from '../constant';
66
import { makeImmutable } from '../context/TableContext';
7-
import type { CustomizeScrollBody, Reference } from '../interface';
7+
import type { CustomizeScrollBody, GetComponent, Reference } from '../interface';
88
import Table, { DEFAULT_PREFIX, type TableProps } from '../Table';
99
import Grid from './BodyGrid';
1010
import { StaticContext } from './context';
11+
import getValue from 'rc-util/lib/utils/get';
1112

1213
const renderBody: CustomizeScrollBody<any> = (rawData, props) => {
1314
const { ref, onScroll } = props;
@@ -54,10 +55,14 @@ function VirtualTable<RecordType>(props: VirtualTableProps<RecordType>, ref: Rea
5455
}
5556
}
5657

58+
const getComponent = useEvent<GetComponent>(
59+
(path, defaultComponent) => getValue(components, path) || defaultComponent,
60+
);
61+
5762
// ========================= Context ==========================
5863
const context = React.useMemo(
59-
() => ({ sticky, scrollY, listItemHeight }),
60-
[sticky, scrollY, listItemHeight],
64+
() => ({ sticky, scrollY, listItemHeight, getComponent }),
65+
[sticky, scrollY, listItemHeight, getComponent],
6166
);
6267

6368
// ========================== Render ==========================

tests/Virtual.spec.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,18 +398,36 @@ describe('Table.Virtual', () => {
398398
});
399399

400400
it('components', async () => {
401+
const Wrapper = React.forwardRef((props, ref: React.Ref<HTMLDivElement>) => (
402+
<div {...props} ref={ref} data-mark="my-wrapper" />
403+
));
404+
401405
const { container } = getTable({
402406
components: {
403407
header: {
404408
cell: function MyTh(props: any) {
405409
return <th {...props} data-mark="my-th" />;
406410
},
407411
},
412+
body: {
413+
wrapper: Wrapper,
414+
row: (props: any) => <div {...props} data-mark="my-row" />,
415+
cell: (props: any) => <div {...props} data-mark="my-cell" />,
416+
},
408417
},
409418
});
410419

411420
await waitFakeTimer();
412421

413422
expect(container.querySelector('thead th')).toHaveAttribute('data-mark', 'my-th');
423+
expect(container.querySelector('.rc-virtual-list-holder')).toHaveAttribute(
424+
'data-mark',
425+
'my-wrapper',
426+
);
427+
expect(container.querySelector('.rc-table-row')).toHaveAttribute('data-mark', 'my-row');
428+
expect(container.querySelector('.rc-table-row .rc-table-cell')).toHaveAttribute(
429+
'data-mark',
430+
'my-cell',
431+
);
414432
});
415433
});

0 commit comments

Comments
 (0)