Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 56 additions & 129 deletions docs/examples/fixedColumnsAndHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,141 +4,68 @@ import '../../assets/index.less';
import { ColumnsType } from '@/interface';
import { useCheckbox } from './utils/useInput';

interface RecordType {
a: string;
b?: string;
c: string;
d: number;
key: string;
}

const originData: RecordType[] = [
{ a: 'aaa', b: 'bbb', c: '内容内容内容内容内容', d: 3, key: '1' },
{ a: 'aaa', b: 'bbb', c: '内容内容内容内容内容', d: 3, key: '2' },
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '3' },
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '4' },
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '5' },
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '6' },
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '7' },
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '8' },
{ a: 'aaa', c: '内容内容内容内容内容', d: 2, key: '9' },
const columns = [
{
title: 'Full Name',
width: 100,
dataIndex: 'name',
key: 'name',
},
{
title: 'Age',
dataIndex: 'age',
key: 'age',
},
{
title: 'Column 1',
dataIndex: 'address',
key: '1',
},
{
title: 'Column 2',
dataIndex: 'address',
key: '2',
},
{
title: 'Column 3',
dataIndex: 'address',
key: '3',
width: 150,
},
{
title: 'Column 4',
dataIndex: 'address',
key: '4',
},
{
title: 'Column 5',
dataIndex: 'address',
key: '5',
},
{
title: 'Column 6',
dataIndex: 'address',
key: '6',
},
{
title: 'Column 7',
dataIndex: 'address',
key: '7',
},
{ title: 'Column 8', dataIndex: 'address', key: '8' },
{
title: 'Action',
key: 'operation',
fixed: 'right',
render: () => <a>action</a>,
},
];

const longTextData: RecordType[] = [...originData];
longTextData[0] = {
...longTextData[0],
a: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
};

const useColumn = (
fixLeft: boolean,
fixTitle: boolean,
fixRight: boolean,
ellipsis: boolean,
percentage: boolean,
) => {
const columns: ColumnsType<RecordType> = React.useMemo(
() => [
{
title: 'title1',
dataIndex: 'a',
key: 'a',
width: percentage ? '10%' : 80,
fixed: fixLeft ? 'left' : null,
ellipsis,
},
{ title: 'title2', dataIndex: 'b', key: 'b', width: 80, fixed: fixLeft ? 'left' : null },
{
title: 'title3',
fixed: fixLeft && fixTitle ? 'left' : null,
children: [
{ title: 'title4', dataIndex: 'c', key: 'd', width: 100 },
{ title: 'title5', dataIndex: 'c', key: 'e', width: 100 },
],
},
{ title: 'title6', dataIndex: 'c', key: 'f' },
{ title: 'title7', dataIndex: 'c', key: 'g' },
{ title: 'title8', dataIndex: 'c', key: 'h' },
{ title: 'title9', dataIndex: 'b', key: 'i' },
{ title: 'title10', dataIndex: 'b', key: 'j' },
{ title: 'title11', dataIndex: 'b', key: 'k', width: 100, fixed: fixRight ? 'right' : null },
{ title: 'title12', dataIndex: 'b', key: 'l', width: 80, fixed: fixRight ? 'right' : null },
],
[fixLeft, fixTitle, fixRight, ellipsis, percentage],
);

return columns;
};

const Demo = () => {
const [autoWidth, autoWidthProps] = useCheckbox(false);
const [longText, longTextProps] = useCheckbox(false);
const [fixHeader, fixHeaderProps] = useCheckbox(true);
const [fixLeft, fixLeftProps] = useCheckbox(true);
const [fixRight, fixRightProps] = useCheckbox(true);
const [fixTitle3, fixTitle3Props] = useCheckbox(false);
const [ellipsis, ellipsisProps] = useCheckbox(false);
const [percentage, percentageProps] = useCheckbox(false);
const [empty, emptyProps] = useCheckbox(false);
const columns = useColumn(fixLeft, fixTitle3, fixRight, ellipsis, percentage);

let mergedData: RecordType[];
if (empty) {
mergedData = null;
} else if (longText) {
mergedData = longTextData;
} else {
mergedData = originData;
}

return (
<React.StrictMode>
<div>
<h2>Fixed columns and header</h2>

<label>
<input {...autoWidthProps} />
Auto Width
</label>
<label>
<input {...longTextProps} />
Long Text
</label>
<label>
<input {...fixHeaderProps} />
Fix Header
</label>
<label>
<input {...fixLeftProps} />
Fix Left
</label>
<label>
<input {...fixTitle3Props} />
Fix title3
</label>
<label>
<input {...fixRightProps} />
Fix Right
</label>
<label>
<input {...ellipsisProps} />
Ellipsis First Column
</label>
<label>
<input {...percentageProps} />
Percentage Width
</label>
<label>
<input {...emptyProps} />
Empty
</label>

<Table<RecordType>
columns={columns}
scroll={{ x: 1650, y: fixHeader ? 300 : null }}
data={mergedData}
style={{ width: autoWidth ? null : 800 }}
/>
<Table columns={columns as any} data={[]} scroll={{ x: 'max-content' }} sticky />
</div>
</React.StrictMode>
);
Expand Down
23 changes: 16 additions & 7 deletions src/Header/FixedHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import * as React from 'react';
import { useMemo } from 'react';
import classNames from 'classnames';
import { fillRef } from 'rc-util/lib/ref';
import Header, { HeaderProps } from './Header';
import type { HeaderProps } from './Header';
import Header from './Header';
import ColGroup from '../ColGroup';
import { ColumnsType, ColumnType } from '../interface';
import type { ColumnsType, ColumnType } from '../interface';
import TableContext from '../context/TableContext';

function useColumnWidth(colWidths: readonly number[], columCount: number) {
Expand Down Expand Up @@ -78,6 +79,12 @@ const FixedHeader = React.forwardRef<HTMLDivElement, FixedHeaderProps<unknown>>(
};
}, []);

// Check if all flattenColumns has width
const allFlattenColumnsWithWidth = React.useMemo(
() => flattenColumns.every(column => column.width >= 0),
[flattenColumns],
);

// Add scrollbar column
const lastColumn = flattenColumns[flattenColumns.length - 1];
const ScrollBarColumn: ColumnType<unknown> = {
Expand Down Expand Up @@ -131,11 +138,13 @@ const FixedHeader = React.forwardRef<HTMLDivElement, FixedHeaderProps<unknown>>(
visibility: noData || mergedColumnWidth ? null : 'hidden',
}}
>
<ColGroup
colWidths={mergedColumnWidth ? [...mergedColumnWidth, combinationScrollBarSize] : []}
columCount={columCount + 1}
columns={flattenColumnsWithScrollbar}
/>
{(!noData || allFlattenColumnsWithWidth) && (
<ColGroup
colWidths={mergedColumnWidth ? [...mergedColumnWidth, combinationScrollBarSize] : []}
columCount={columCount + 1}
columns={flattenColumnsWithScrollbar}
/>
)}
<Header
{...props}
stickyOffsets={headerStickyOffsets}
Expand Down
3 changes: 2 additions & 1 deletion src/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import ColumnGroup from './sugar/ColumnGroup';
import Column from './sugar/Column';
import FixedHeader from './Header/FixedHeader';
import Header from './Header/Header';
import {
import type {
GetRowKey,
ColumnsType,
TableComponents,
Expand Down Expand Up @@ -583,6 +583,7 @@ function Table<RecordType extends DefaultRecordType>(props: TableProps<RecordTyp
ref: scrollBodyRef,
onScroll,
});

headerProps.colWidths = flattenColumns.map(({ width }, index) => {
const colWidth = index === columns.length - 1 ? (width as number) - scrollbarSize : width;
if (typeof colWidth === 'number' && !Number.isNaN(colWidth)) {
Expand Down
58 changes: 37 additions & 21 deletions tests/FixedColumn.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,29 +49,45 @@ describe('Table.FixedColumn', () => {
{ scrollName: 'scrollX', scroll: { x: 1200 } },
{ scrollName: 'scrollXY', scroll: { x: 1200, y: 100 } },
].forEach(({ scrollName, scroll }) => {
[{ name: 'with data', data }, { name: 'without data', data: [] }].forEach(
({ name, data: testData }) => {
it(`${scrollName} - ${name}`, async () => {
jest.useFakeTimers();
const wrapper = mount(<Table columns={columns} data={testData} scroll={scroll} />);

act(() => {
wrapper
.find('table ResizeObserver')
.first()
.props()
.onResize({ width: 93, offsetWidth: 93 });
});
await act(async () => {
jest.runAllTimers();
await Promise.resolve();
wrapper.update();
});
expect(wrapper.render()).toMatchSnapshot();
jest.useRealTimers();
[
{ name: 'with data', data },
{ name: 'without data', data: [] },
].forEach(({ name, data: testData }) => {
it(`${scrollName} - ${name}`, async () => {
jest.useFakeTimers();
const wrapper = mount(<Table columns={columns} data={testData} scroll={scroll} />);

act(() => {
wrapper
.find('table ResizeObserver')
.first()
.props()
.onResize({ width: 93, offsetWidth: 93 });
});
},
await act(async () => {
jest.runAllTimers();
await Promise.resolve();
wrapper.update();
});
expect(wrapper.render()).toMatchSnapshot();
jest.useRealTimers();
});
});
});

it('all column has width should use it', () => {
const wrapper = mount(
<Table
columns={[
{ title: 'title1', dataIndex: 'a', key: 'a', width: 100 },
{ title: 'title2', dataIndex: 'b', key: 'b', width: 100 },
]}
data={[]}
scroll={{ x: 'max-content' }}
/>,
);

expect(wrapper.find('colgroup').render()).toMatchSnapshot();
});
});

Expand Down
52 changes: 11 additions & 41 deletions tests/__snapshots__/FixedColumn.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -695,6 +695,17 @@ exports[`Table.FixedColumn fixed column renders correctly RTL 1`] = `
</div>
`;

exports[`Table.FixedColumn renders correctly all column has width should use it 1`] = `
<colgroup>
<col
style="width: 100px; min-width: 100px;"
/>
<col
style="width: 100px; min-width: 100px;"
/>
</colgroup>
`;

exports[`Table.FixedColumn renders correctly scrollX - with data 1`] = `
<div
class="rc-table rc-table-fixed-column rc-table-scroll-horizontal rc-table-has-fix-left rc-table-has-fix-right"
Expand Down Expand Up @@ -2395,47 +2406,6 @@ exports[`Table.FixedColumn renders correctly scrollXY - without data 1`] = `
<table
style="table-layout: fixed;"
>
<colgroup>
<col
style="width: 93px; min-width: 93px;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 0px; min-width: 0;"
/>
<col
style="width: 15px; min-width: 15px;"
/>
</colgroup>
<thead
class="rc-table-thead"
>
Expand Down