diff --git a/docs/examples/virtual.tsx b/docs/examples/virtual.tsx
index a161d549e..8e3380ca1 100644
--- a/docs/examples/virtual.tsx
+++ b/docs/examples/virtual.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import '../../assets/index.less';
-import type { ColumnsType } from '../../src/interface';
import { VirtualTable } from '../../src';
+import type { ColumnsType } from '../../src/interface';
interface RecordType {
a: string;
@@ -12,152 +12,154 @@ interface RecordType {
}
const columns: ColumnsType = [
- { title: 'title1', dataIndex: 'a', key: 'a', width: 100, fixed: 'left' },
- { title: 'title2', dataIndex: 'b', key: 'b', width: 100, fixed: 'left', ellipsis: true },
- {
- title: 'title3',
- dataIndex: 'c',
- key: 'c',
- onCell: (_, index) => {
- if (index % 4 === 0) {
- return {
- rowSpan: 3,
- };
- }
+ { title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
+ { title: 'title1', dataIndex: 'a', key: 'a', width: 800 },
+ { title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
+ // { title: 'title2', dataIndex: 'b', key: 'b', width: 100, fixed: 'left', ellipsis: true },
+ // {
+ // title: 'title3',
+ // dataIndex: 'c',
+ // key: 'c',
+ // onCell: (_, index) => {
+ // if (index % 4 === 0) {
+ // return {
+ // rowSpan: 3,
+ // };
+ // }
- if (index % 4 === 3) {
- return {
- rowSpan: 1,
- colSpan: 3,
- };
- }
+ // if (index % 4 === 3) {
+ // return {
+ // rowSpan: 1,
+ // colSpan: 3,
+ // };
+ // }
- return {
- rowSpan: 0,
- };
- },
- },
- {
- title: 'title4',
- key: 'd',
- children: [
- // Children columns
- {
- title: 'title4-1',
- dataIndex: 'b',
- onCell: (_, index) => {
- if (index % 4 === 0) {
- return {
- colSpan: 3,
- };
- }
+ // return {
+ // rowSpan: 0,
+ // };
+ // },
+ // },
+ // {
+ // title: 'title4',
+ // key: 'd',
+ // children: [
+ // // Children columns
+ // {
+ // title: 'title4-1',
+ // dataIndex: 'b',
+ // onCell: (_, index) => {
+ // if (index % 4 === 0) {
+ // return {
+ // colSpan: 3,
+ // };
+ // }
- if (index % 4 === 3) {
- return {
- colSpan: 0,
- };
- }
- },
- },
- {
- title: 'title4-2',
- dataIndex: 'b',
- onCell: (_, index) => {
- if (index % 4 === 0 || index % 4 === 3) {
- return {
- colSpan: 0,
- };
- }
- },
- },
- ],
- },
- {
- title: 'title6',
- dataIndex: 'b',
- key: 'f',
- onCell: (_, index) => {
- if (index % 4 === 0) {
- return {
- rowSpan: 0,
- colSpan: 0,
- };
- }
+ // if (index % 4 === 3) {
+ // return {
+ // colSpan: 0,
+ // };
+ // }
+ // },
+ // },
+ // {
+ // title: 'title4-2',
+ // dataIndex: 'b',
+ // onCell: (_, index) => {
+ // if (index % 4 === 0 || index % 4 === 3) {
+ // return {
+ // colSpan: 0,
+ // };
+ // }
+ // },
+ // },
+ // ],
+ // },
+ // {
+ // title: 'title6',
+ // dataIndex: 'b',
+ // key: 'f',
+ // onCell: (_, index) => {
+ // if (index % 4 === 0) {
+ // return {
+ // rowSpan: 0,
+ // colSpan: 0,
+ // };
+ // }
- if (index % 4 === 1) {
- return {
- rowSpan: 3,
- };
- }
+ // if (index % 4 === 1) {
+ // return {
+ // rowSpan: 3,
+ // };
+ // }
- return {
- rowSpan: 0,
- };
- },
- },
- {
- title: (
-
- title7
-
-
-
- Hello world!
-
- ),
- dataIndex: 'bk',
- key: 'g',
- },
- {
- title: 'title8',
- dataIndex: 'b',
- onCell: (_, index) => {
- if (index % 2 === 0) {
- return {
- rowSpan: 2,
- colSpan: 2,
- };
- }
+ // return {
+ // rowSpan: 0,
+ // };
+ // },
+ // },
+ // {
+ // title: (
+ //
+ // title7
+ //
+ //
+ //
+ // Hello world!
+ //
+ // ),
+ // dataIndex: 'bk',
+ // key: 'g',
+ // },
+ // {
+ // title: 'title8',
+ // dataIndex: 'b',
+ // onCell: (_, index) => {
+ // if (index % 2 === 0) {
+ // return {
+ // rowSpan: 2,
+ // colSpan: 2,
+ // };
+ // }
- return {
- rowSpan: 0,
- };
- },
- },
- {
- title: 'title9 i',
- dataIndex: 'b',
- key: 'i',
- onCell: () => ({
- colSpan: 0,
- }),
- },
- { title: 'title10', dataIndex: 'b', key: 'j' },
- {
- title: 'title11',
- dataIndex: 'b',
- key: 'k',
- width: 50,
- fixed: 'right',
- onCell: (_, index) => {
- return {
- rowSpan: index % 2 === 0 ? 2 : 0,
- // colSpan: 2,
- };
- },
- },
- {
- title: 'title12',
- dataIndex: 'b',
- key: 'l',
- width: 100,
- fixed: 'right',
- onCell: () => {
- return {
- // colSpan: 0,
- };
- },
- },
+ // return {
+ // rowSpan: 0,
+ // };
+ // },
+ // },
+ // {
+ // title: 'title9 i',
+ // dataIndex: 'b',
+ // key: 'i',
+ // onCell: () => ({
+ // colSpan: 0,
+ // }),
+ // },
+ // { title: 'title10', dataIndex: 'b', key: 'j' },
+ // {
+ // title: 'title11',
+ // dataIndex: 'b',
+ // key: 'k',
+ // width: 50,
+ // fixed: 'right',
+ // onCell: (_, index) => {
+ // return {
+ // rowSpan: index % 2 === 0 ? 2 : 0,
+ // // colSpan: 2,
+ // };
+ // },
+ // },
+ // {
+ // title: 'title12',
+ // dataIndex: 'b',
+ // key: 'l',
+ // width: 100,
+ // fixed: 'right',
+ // onCell: () => {
+ // return {
+ // // colSpan: 0,
+ // };
+ // },
+ // },
];
export function cleanOnCell(cols: any = []) {
diff --git a/src/FixedHolder/index.tsx b/src/FixedHolder/index.tsx
index 7d60c7ea0..b7e48ce7f 100644
--- a/src/FixedHolder/index.tsx
+++ b/src/FixedHolder/index.tsx
@@ -96,7 +96,7 @@ const FixedHolder = React.forwardRef>(
// Check if all flattenColumns has width
const allFlattenColumnsWithWidth = React.useMemo(
- () => flattenColumns.every(column => column.width >= 0),
+ () => flattenColumns.every(column => column.width),
[flattenColumns],
);
diff --git a/src/Table.tsx b/src/Table.tsx
index 74f64ed9b..ab0b3a451 100644
--- a/src/Table.tsx
+++ b/src/Table.tsx
@@ -264,9 +264,10 @@ function Table(tableProps: TableProps(tableProps: TableProps ({
@@ -308,7 +310,7 @@ function Table(tableProps: TableProps pureColWidths, [pureColWidths.join('_')]);
const stickyOffsets = useStickyOffsets(colWidths, flattenColumns.length, direction);
const fixHeader = scroll && validateValue(scroll.y);
- const horizonScroll = (scroll && validateValue(scroll.x)) || Boolean(expandableConfig.fixed);
+ const horizonScroll = (scroll && validateValue(mergedScrollX)) || Boolean(expandableConfig.fixed);
const fixColumn = horizonScroll && flattenColumns.some(({ fixed }) => fixed);
// Sticky
@@ -345,7 +347,7 @@ function Table(tableProps: TableProps(tableProps: TableProps ellipsis)) {
return 'fixed';
@@ -615,7 +617,7 @@ function Table(tableProps: TableProps(tableProps: TableProps ({
+ // Scroll
+ scrollX: mergedScrollX,
+
// Table
prefixCls,
getComponent,
@@ -775,6 +780,9 @@ function Table(tableProps: TableProps {
data: RecordType[];
@@ -29,6 +29,7 @@ const Grid = React.forwardRef((props, ref) => {
prefixCls,
childrenColumnName,
emptyNode,
+ scrollX,
} = useContext(TableContext, [
'flattenColumns',
'onColumnResize',
@@ -37,8 +38,9 @@ const Grid = React.forwardRef((props, ref) => {
'expandedKeys',
'childrenColumnName',
'emptyNode',
+ 'scrollX',
]);
- const { scrollY, scrollX, listItemHeight } = useContext(StaticContext);
+ const { scrollY, listItemHeight } = useContext(StaticContext);
// =========================== Ref ============================
const listRef = React.useRef();
@@ -201,7 +203,7 @@ const Grid = React.forwardRef((props, ref) => {
itemHeight={listItemHeight || 24}
data={flattenData}
itemKey={item => getRowKey(item.record)}
- scrollWidth={scrollX}
+ scrollWidth={scrollX as number}
onVirtualScroll={({ x }) => {
onScroll({
scrollLeft: x,
diff --git a/src/VirtualTable/BodyLine.tsx b/src/VirtualTable/BodyLine.tsx
index 5d793059c..7655294df 100644
--- a/src/VirtualTable/BodyLine.tsx
+++ b/src/VirtualTable/BodyLine.tsx
@@ -1,12 +1,11 @@
import { useContext } from '@rc-component/context';
import classNames from 'classnames';
import * as React from 'react';
+import Cell from '../Cell';
import TableContext, { responseImmutable } from '../context/TableContext';
import type { FlattenData } from '../hooks/useFlattenRecords';
-import { StaticContext } from './context';
-import VirtualCell from './VirtualCell';
import useRowInfo from '../hooks/useRowInfo';
-import Cell from '../Cell';
+import VirtualCell from './VirtualCell';
export interface BodyLineProps {
data: FlattenData;
@@ -24,13 +23,10 @@ const BodyLine = React.forwardRef((props, ref) =>
const { data, index, className, rowKey, style, extra, getHeight, ...restProps } = props;
const { record, indent } = data;
- const { flattenColumns, prefixCls, fixColumn, componentWidth } = useContext(TableContext, [
- 'prefixCls',
- 'flattenColumns',
- 'fixColumn',
- 'componentWidth',
- ]);
- const { scrollX } = useContext(StaticContext, ['scrollX']);
+ const { scrollX, flattenColumns, prefixCls, fixColumn, componentWidth } = useContext(
+ TableContext,
+ ['prefixCls', 'flattenColumns', 'fixColumn', 'componentWidth', 'scrollX'],
+ );
const rowInfo = useRowInfo(record, rowKey, index, indent);
@@ -79,7 +75,7 @@ const BodyLine = React.forwardRef((props, ref) =>
const rowStyle: React.CSSProperties = {
...style,
- width: scrollX,
+ width: scrollX as number,
};
if (extra) {
diff --git a/src/VirtualTable/context.ts b/src/VirtualTable/context.ts
index d22fd0a98..5e6786737 100644
--- a/src/VirtualTable/context.ts
+++ b/src/VirtualTable/context.ts
@@ -1,7 +1,6 @@
import { createContext } from '@rc-component/context';
export interface StaticContextProps {
- scrollX: number;
scrollY: number;
listItemHeight: number;
}
diff --git a/src/VirtualTable/index.tsx b/src/VirtualTable/index.tsx
index 73064b5b8..fcb2102a8 100644
--- a/src/VirtualTable/index.tsx
+++ b/src/VirtualTable/index.tsx
@@ -49,10 +49,7 @@ function VirtualTable(props: VirtualTableProps) {
}
// ========================= Context ==========================
- const context = React.useMemo(
- () => ({ scrollX, scrollY, listItemHeight }),
- [scrollX, scrollY, listItemHeight],
- );
+ const context = React.useMemo(() => ({ scrollY, listItemHeight }), [scrollY, listItemHeight]);
// ========================== Render ==========================
return (
diff --git a/src/context/TableContext.tsx b/src/context/TableContext.tsx
index 625531ff9..ee5eeae2a 100644
--- a/src/context/TableContext.tsx
+++ b/src/context/TableContext.tsx
@@ -19,6 +19,9 @@ const { makeImmutable, responseImmutable, useImmutableMark } = createImmutable()
export { makeImmutable, responseImmutable, useImmutableMark };
export interface TableContextProps {
+ // Scroll
+ scrollX: number | string | true;
+
// Table
prefixCls: string;
getComponent: GetComponent;
diff --git a/src/hooks/useColumns/index.tsx b/src/hooks/useColumns/index.tsx
index 174486e1a..baa026f32 100644
--- a/src/hooks/useColumns/index.tsx
+++ b/src/hooks/useColumns/index.tsx
@@ -151,7 +151,11 @@ function useColumns(
scrollWidth?: number;
},
transformColumns: (columns: ColumnsType) => ColumnsType,
-): [ColumnsType, readonly ColumnType[]] {
+): [
+ columns: ColumnsType,
+ flattenColumns: readonly ColumnType[],
+ realScrollWidth: undefined | number,
+] {
const baseColumns = React.useMemo>(
() => columns || convertChildrenToColumns(children),
[columns, children],
@@ -274,9 +278,9 @@ function useColumns(
}
// ========================= FillWidth ========================
- const filledColumns = useWidthColumns(flattenColumns, scrollWidth);
+ const [filledColumns, realScrollWidth] = useWidthColumns(flattenColumns, scrollWidth);
- return [mergedColumns, filledColumns];
+ return [mergedColumns, filledColumns, realScrollWidth];
}
export default useColumns;
diff --git a/src/hooks/useColumns/useWidthColumns.tsx b/src/hooks/useColumns/useWidthColumns.tsx
index a85863643..34bcb6afe 100644
--- a/src/hooks/useColumns/useWidthColumns.tsx
+++ b/src/hooks/useColumns/useWidthColumns.tsx
@@ -15,15 +15,15 @@ function parseColWidth(totalWidth: number, width: string | number = '') {
/**
* Fill all column with width
*/
-export default function useWidthColumns(columns: ColumnsType, scrollWidth: number) {
- const filledColumns = React.useMemo(() => {
+export default function useWidthColumns(flattenColumns: ColumnsType, scrollWidth: number) {
+ return React.useMemo<[columns: ColumnsType, realScrollWidth: number]>(() => {
// Fill width if needed
if (scrollWidth && scrollWidth > 0) {
let totalWidth = 0;
let missWidthCount = 0;
// collect not given width column
- columns.forEach((col: any) => {
+ flattenColumns.forEach((col: any) => {
const colWidth = parseColWidth(scrollWidth, col.width);
if (colWidth) {
@@ -38,7 +38,9 @@ export default function useWidthColumns(columns: ColumnsType, scrollWidth:
let restCount = missWidthCount;
const avgWidth = restWidth / missWidthCount;
- return columns.map((col: any) => {
+ let realTotal = 0;
+
+ const filledColumns = flattenColumns.map((col: any) => {
const clone = {
...col,
};
@@ -56,12 +58,14 @@ export default function useWidthColumns(columns: ColumnsType, scrollWidth:
restCount -= 1;
}
+ realTotal += clone.width;
+
return clone;
});
- }
- return columns;
- }, [columns, scrollWidth]);
+ return [filledColumns, realTotal];
+ }
- return filledColumns;
+ return [flattenColumns, scrollWidth];
+ }, [flattenColumns, scrollWidth]);
}
diff --git a/tests/Virtual.spec.tsx b/tests/Virtual.spec.tsx
index fedd372ed..d54bf79be 100644
--- a/tests/Virtual.spec.tsx
+++ b/tests/Virtual.spec.tsx
@@ -1,10 +1,22 @@
-import { resetWarned } from 'rc-util/lib/warning';
-import React from 'react';
-import { type VirtualTableProps, VirtualTable } from '../src';
import { act, fireEvent, render } from '@testing-library/react';
-import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
import { _rs as onEsResize } from 'rc-resize-observer/es/utils/observerUtil';
import { _rs as onLibResize } from 'rc-resize-observer/lib/utils/observerUtil';
+import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
+import { resetWarned } from 'rc-util/lib/warning';
+import React from 'react';
+import { VirtualTable, type VirtualTableProps } from '../src';
+
+vi.mock('rc-virtual-list', async () => {
+ const RealVirtualList = ((await vi.importActual('rc-virtual-list')) as any).default;
+
+ const WrapperVirtualList = React.forwardRef((props: any, ref) => (
+
+ ));
+
+ return {
+ default: WrapperVirtualList,
+ };
+});
describe('Table.Virtual', () => {
let scrollLeftCalled = false;
@@ -170,14 +182,30 @@ describe('Table.Virtual', () => {
scrollLeftCalled = false;
expect(scrollLeftCalled).toBeFalsy();
- console.log('!!!!!');
- // fireEvent.scroll(container.querySelector('.rc-table-header')!);
fireEvent.wheel(container.querySelector('.rc-virtual-list-holder')!, {
deltaX: 10,
});
expect(scrollLeftCalled).toBeTruthy();
+ });
+
+ it('should follow correct width', () => {
+ const { container } = getTable({
+ columns: [
+ {
+ width: 93,
+ },
+ {
+ width: 510,
+ },
+ ],
+ scroll: {
+ x: 1128,
+ y: 10,
+ },
+ data: [{}],
+ });
- console.log(container.innerHTML);
+ expect(container.querySelector('.rc-virtual-list')).toHaveAttribute('data-scroll-width', '603');
});
});