Skip to content

Commit 569faf9

Browse files
afc163gemini-code-assist[bot]yoyo837
authored
chore: sync antd 5.x branch to master (#1350)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Amumu <[email protected]>
2 parents 77a3daa + 523414b commit 569faf9

File tree

14 files changed

+197
-53
lines changed

14 files changed

+197
-53
lines changed

assets/index.less

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444

4545
padding: @cell-padding;
4646
white-space: normal;
47-
word-break: break-word;
4847
border: @border;
4948
border-top: 0;
5049
border-left: 0;

docs/examples/measureRowRender.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import React from 'react';
2+
import Table from 'rc-table';
3+
4+
// 示例:使用 measureRowRender 来隐藏 MeasureRow 中的弹层
5+
const MeasureRowRenderExample = () => {
6+
const columns = [
7+
{
8+
title: (
9+
<div>
10+
Name
11+
<div className="filter-dropdown" style={{ display: 'none' }}>
12+
Filter Content
13+
</div>
14+
</div>
15+
),
16+
dataIndex: 'name',
17+
key: 'name',
18+
width: 100,
19+
},
20+
{
21+
title: 'Age',
22+
dataIndex: 'age',
23+
key: 'age',
24+
width: 80,
25+
},
26+
];
27+
28+
const data = [
29+
{ key: 1, name: 'John', age: 25 },
30+
{ key: 2, name: 'Jane', age: 30 },
31+
];
32+
33+
// 自定义 MeasureRow 渲染,隐藏弹层内容
34+
const measureRowRender = measureRow => <div style={{ display: 'none' }}>{measureRow}</div>;
35+
36+
return (
37+
<Table
38+
columns={columns}
39+
data={data}
40+
sticky
41+
scroll={{ x: true }}
42+
measureRowRender={measureRowRender}
43+
/>
44+
);
45+
};
46+
47+
export default MeasureRowRenderExample;

docs/examples/scrollY.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ const Test = () => {
9696
rowKey={record => record.key}
9797
onRow={(record, index) => ({ style: { backgroundColor: 'red' } })}
9898
/>
99+
<h3>Column align issue</h3>
100+
<p>https://github.com/ant-design/ant-design/issues/54889</p>
101+
<Table columns={columns} data={data} sticky scroll={{ y: 300, x: 2000 }} />
99102
</div>
100103
);
101104
};

docs/examples/stickyHeader.tsx

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,34 @@ const data = [
137137
{ a: '1333', c: 'eee', d: 2, key: '20' },
138138
];
139139

140+
const columns3: ColumnType<RecordType>[] = [
141+
{ title: '', dataIndex: 'name', key: '0' },
142+
{ title: 'First column', dataIndex: 'name', key: '1' },
143+
{ title: 'Second column', dataIndex: 'address', key: '2' },
144+
{ title: 'Third column', dataIndex: 'age', key: '3' },
145+
{ title: 'Another column', dataIndex: 'address', key: '4' },
146+
{ title: 'Extra column', dataIndex: 'name', key: '5' },
147+
{ title: 'And yet another column', dataIndex: 'address', key: '6' },
148+
{
149+
title: 'Column 7 with extraaaaaaaaa long word',
150+
dataIndex: 'age',
151+
key: '7',
152+
},
153+
{ title: 'Column 8', dataIndex: 'address', key: '8' },
154+
{ title: 'Column 9', dataIndex: 'name', key: '9' },
155+
{ title: 'Column 10', dataIndex: 'address', key: '10' },
156+
{ title: 'Column 11', dataIndex: 'address', key: '11' },
157+
{ title: 'Column 12', dataIndex: 'age', key: '12' },
158+
{ title: 'Column 13', dataIndex: 'address', key: '13' },
159+
{ title: 'Column 14', dataIndex: 'name', key: '14' },
160+
{ title: 'Column 15', dataIndex: 'address', key: '15' },
161+
{ title: 'Column 16', dataIndex: 'address', key: '16' },
162+
{ title: 'Column 17', dataIndex: 'name', key: '17' },
163+
{ title: 'Column 18', dataIndex: 'address', key: '18' },
164+
{ title: 'Column 19', dataIndex: 'address', key: '19' },
165+
{ title: 'Column 20', dataIndex: 'age', key: '20' },
166+
];
167+
140168
const Demo = () => {
141169
const container = useRef();
142170
return (
@@ -274,7 +302,7 @@ const Demo = () => {
274302
<br />
275303
<Table
276304
columns={fixedColumns}
277-
data={[{}]}
305+
data={[{ key: '1' }]}
278306
scroll={{
279307
x: 'max-content',
280308
}}
@@ -283,7 +311,7 @@ const Demo = () => {
283311
<br />
284312
<Table
285313
columns={columnsWithWidth}
286-
data={[{}]}
314+
data={[{ key: '1' }]}
287315
scroll={{
288316
x: 1200,
289317
}}
@@ -301,7 +329,7 @@ const Demo = () => {
301329
<br />
302330
<Table
303331
columns={fixedColumns.map(column => ({ ...column, width: undefined }))}
304-
data={[{}]}
332+
data={[{ key: '1' }]}
305333
scroll={{
306334
x: 'max-content',
307335
}}
@@ -310,12 +338,26 @@ const Demo = () => {
310338
<br />
311339
<Table
312340
columns={columnsGrouped}
313-
data={[{}, {}]}
341+
data={[{ key: '1' }, { key: '2' }]}
314342
scroll={{
315343
x: 'max-content',
316344
}}
317345
sticky
318346
/>
347+
<br />
348+
<h3>scroll.x is true</h3>
349+
<p>https://github.com/ant-design/ant-design/issues/54894</p>
350+
<Table
351+
columns={columns3}
352+
data={
353+
[
354+
{ key: '1', name: 'Test', age: 1, address: '2' },
355+
{ key: '2', name: '0', age: 1, address: '2' },
356+
] as any
357+
}
358+
sticky
359+
scroll={{ x: true }}
360+
/>
319361
</div>
320362
);
321363
};

src/Body/MeasureRow.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import * as React from 'react';
22
import ResizeObserver from '@rc-component/resize-observer';
33
import MeasureCell from './MeasureCell';
44
import isVisible from '@rc-component/util/lib/Dom/isVisible';
5+
import { useContext } from '@rc-component/context';
6+
import TableContext from '../context/TableContext';
57
import type { ColumnType } from '../interface';
68

79
export interface MeasureRowProps {
@@ -18,8 +20,9 @@ export default function MeasureRow({
1820
columns,
1921
}: MeasureRowProps) {
2022
const ref = React.useRef<HTMLTableRowElement>(null);
23+
const { measureRowRender } = useContext(TableContext, ['measureRowRender']);
2124

22-
return (
25+
const measureRow = (
2326
<tr aria-hidden="true" className={`${prefixCls}-measure-row`} style={{ height: 0 }} ref={ref}>
2427
<ResizeObserver.Collection
2528
onBatchResize={infoList => {
@@ -44,4 +47,6 @@ export default function MeasureRow({
4447
</ResizeObserver.Collection>
4548
</tr>
4649
);
50+
51+
return measureRowRender ? measureRowRender(measureRow) : measureRow;
4752
}

src/ColGroup.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function ColGroup<RecordType>({ colWidths, columns, columCount }: ColGroupProps<
4040
}
4141
}
4242

43-
return <colgroup>{cols}</colgroup>;
43+
return cols.length > 0 ? <colgroup>{cols}</colgroup> : null;
4444
}
4545

4646
export default ColGroup;

src/FixedHolder/index.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export interface FixedHeaderProps<RecordType> extends HeaderProps<RecordType> {
3636
stickyTopOffset?: number;
3737
stickyBottomOffset?: number;
3838
stickyClassName?: string;
39-
scrollTableStyle?: React.CSSProperties;
39+
scrollX?: number | string | true;
4040
tableLayout?: TableLayout;
4141
onScroll: (info: { currentTarget: HTMLDivElement; scrollLeft?: number }) => void;
4242
children: (info: HeaderProps<RecordType>) => React.ReactNode;
@@ -61,7 +61,7 @@ const FixedHolder = React.forwardRef<HTMLDivElement, FixedHeaderProps<any>>((pro
6161
stickyTopOffset,
6262
stickyBottomOffset,
6363
stickyClassName,
64-
scrollTableStyle,
64+
scrollX,
6565
tableLayout = 'fixed',
6666
onScroll,
6767
maxContentScroll,
@@ -197,8 +197,9 @@ const FixedHolder = React.forwardRef<HTMLDivElement, FixedHeaderProps<any>>((pro
197197
<TableComponent
198198
style={{
199199
tableLayout,
200-
visibility: noData || mergedColumnWidth ? null : 'hidden',
201-
...scrollTableStyle,
200+
minWidth: '100%',
201+
// https://github.com/ant-design/ant-design/issues/54894
202+
width: scrollX,
202203
}}
203204
>
204205
{colGroupNode}

src/Table.tsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,12 @@ export interface TableProps<RecordType = any>
178178
internalRefs?: {
179179
body: React.MutableRefObject<HTMLDivElement>;
180180
};
181+
/**
182+
* @private Internal usage, may remove by refactor.
183+
*
184+
* !!! DO NOT USE IN PRODUCTION ENVIRONMENT !!!
185+
*/
186+
measureRowRender?: (measureRow: React.ReactNode) => React.ReactNode;
181187
}
182188

183189
function defaultEmpty() {
@@ -222,6 +228,9 @@ function Table<RecordType extends DefaultRecordType>(
222228
onRow,
223229
onHeaderRow,
224230

231+
// Measure Row
232+
measureRowRender,
233+
225234
// Events
226235
onScroll,
227236

@@ -719,7 +728,7 @@ function Table<RecordType extends DefaultRecordType>(
719728
...columnContext,
720729
direction,
721730
stickyClassName,
722-
scrollTableStyle,
731+
scrollX: mergedScrollX,
723732
tableLayout: mergedTableLayout,
724733
onScroll: onInternalScroll,
725734
};
@@ -911,6 +920,9 @@ function Table<RecordType extends DefaultRecordType>(
911920
childrenColumnName: mergedChildrenColumnName,
912921

913922
rowHoverable,
923+
924+
// Measure Row
925+
measureRowRender,
914926
}),
915927
[
916928
// Scroll
@@ -962,6 +974,8 @@ function Table<RecordType extends DefaultRecordType>(
962974
mergedChildrenColumnName,
963975

964976
rowHoverable,
977+
978+
measureRowRender,
965979
],
966980
);
967981

src/context/TableContext.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ export interface TableContextProps<RecordType = any> {
7777
rowHoverable?: boolean;
7878

7979
expandedRowOffset: ExpandableConfig<RecordType>['expandedRowOffset'];
80+
81+
// Measure Row
82+
measureRowRender?: (measureRow: React.ReactNode) => React.ReactNode;
8083
}
8184

8285
const TableContext = createContext<TableContextProps>();

tests/FixedHeader.spec.jsx

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { render, act, fireEvent } from '@testing-library/react';
2-
import RcResizeObserver, { _rs } from '@rc-component/resize-observer';
3-
import { spyElementPrototype, spyElementPrototypes } from '@rc-component/util/lib/test/domHook';
1+
import { render, act } from '@testing-library/react';
2+
import { _rs } from '@rc-component/resize-observer';
3+
import { spyElementPrototypes } from '@rc-component/util/lib/test/domHook';
44
import React from 'react';
55
import Table, { INTERNAL_COL_DEFINE } from '../src';
66
import { safeAct } from './utils';
@@ -42,7 +42,7 @@ describe('Table.FixedHeader', () => {
4242
const col1 = { dataIndex: 'light', width: 100 };
4343
const col2 = { dataIndex: 'bamboo', width: 200 };
4444
const col3 = { dataIndex: 'empty', width: 0 };
45-
const { container, rerender } = render(
45+
const { container } = render(
4646
<Table
4747
columns={[col1, col2, col3]}
4848
data={[{ light: 'bamboo', bamboo: 'light', key: 1 }]}
@@ -91,26 +91,13 @@ describe('Table.FixedHeader', () => {
9191
expect(tables[0].querySelector('colgroup col').className).toEqual('test-internal');
9292
});
9393

94-
it('show header when data is null', async () => {
95-
const columns = [
96-
{
97-
title: 'Name',
98-
dataIndex: 'name',
99-
key: 'name',
100-
},
101-
{
102-
title: 'Age',
103-
dataIndex: 'age',
104-
key: 'age',
105-
},
106-
];
107-
94+
it('rtl', async () => {
10895
const { container } = render(
10996
<Table
110-
columns={columns}
111-
data={[]}
97+
columns={[{ dataIndex: 'light', width: 100 }]}
98+
data={[{ key: 0, light: 'bamboo' }]}
99+
direction="rtl"
112100
scroll={{
113-
x: true,
114101
y: 100,
115102
}}
116103
/>,
@@ -208,4 +195,62 @@ describe('Table.FixedHeader', () => {
208195
expect(container.querySelectorAll('th.rc-table-cell-fix-start')).toHaveLength(2);
209196
expect(container.querySelectorAll('th.rc-table-cell-fix-end')).toHaveLength(1);
210197
});
198+
199+
it('should support measureRowRender to wrap MeasureRow with custom provider', async () => {
200+
const FilterDropdown = ({ visible, onVisibleChange }) => (
201+
<div className="test-filter-dropdown" style={{ display: visible ? 'block' : 'none' }}>
202+
Filter Content
203+
<button onClick={() => onVisibleChange && onVisibleChange(!visible)}>Toggle</button>
204+
</div>
205+
);
206+
207+
const columns = [
208+
{
209+
title: (
210+
<div>
211+
Name
212+
<FilterDropdown visible={true} onVisibleChange={() => {}} />
213+
</div>
214+
),
215+
dataIndex: 'name',
216+
key: 'name',
217+
width: 100,
218+
},
219+
];
220+
221+
const data = [
222+
{
223+
key: 1,
224+
name: 'Jack',
225+
},
226+
];
227+
228+
// Mock ConfigProvider-like wrapper
229+
const measureRowRender = measureRow => (
230+
<div data-testid="measure-row-wrapper" style={{ display: 'none' }}>
231+
{measureRow}
232+
</div>
233+
);
234+
235+
const { container } = render(
236+
<Table
237+
columns={columns}
238+
data={data}
239+
sticky
240+
scroll={{ x: true }}
241+
measureRowRender={measureRowRender}
242+
/>,
243+
);
244+
245+
await safeAct(container);
246+
247+
// Check that measureRowRender wrapper is applied
248+
const measureRowWrapper = container.querySelectorAll('[data-testid="measure-row-wrapper"]');
249+
expect(measureRowWrapper).toHaveLength(1);
250+
expect(measureRowWrapper[0].style.display).toBe('none');
251+
252+
// Check that MeasureRow is inside the wrapper
253+
const measureRowInWrapper = measureRowWrapper[0].querySelectorAll('.rc-table-measure-row');
254+
expect(measureRowInWrapper).toHaveLength(1);
255+
});
211256
});

0 commit comments

Comments
 (0)