Skip to content

Commit 833f5ce

Browse files
刘欢claude
andcommitted
fix: virtual table scrollTo align support
- Add VirtualScrollConfig type with Exclude<ScrollLogicalPosition, 'center'> - Implement align mapping for virtual table (start->top, end->bottom, nearest->auto) - Add default align 'auto' when neither align nor offset provided - Add backward compatibility: default to 'top' when offset provided but align not - Update tests to cover align parameter scenarios - Fix offset JSDoc comment Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1027f17 commit 833f5ce

3 files changed

Lines changed: 53 additions & 11 deletions

File tree

src/VirtualTable/BodyGrid.tsx

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import VirtualList, { type ListProps, type ListRef } from '@rc-component/virtual
33
import * as React from 'react';
44
import TableContext, { responseImmutable } from '../context/TableContext';
55
import useFlattenRecords, { type FlattenData } from '../hooks/useFlattenRecords';
6-
import type { ColumnType, OnCustomizeScroll, ScrollConfig } from '../interface';
6+
import type {
7+
ColumnType,
8+
OnCustomizeScroll,
9+
ScrollConfig,
10+
VirtualScrollConfig,
11+
} from '../interface';
712
import BodyLine from './BodyLine';
813
import { GridContext, StaticContext } from './context';
914

@@ -79,15 +84,22 @@ const Grid = React.forwardRef<GridRef, GridProps>((props, ref) => {
7984
// =========================== Ref ============================
8085
React.useImperativeHandle(ref, () => {
8186
const obj = {
82-
scrollTo: (config: ScrollConfig) => {
83-
const { offset, ...restConfig } = config;
84-
85-
// If offset is provided, force align to 'top' for consistent behavior
86-
if (offset) {
87-
listRef.current?.scrollTo({ ...restConfig, offset, align: 'top' });
88-
} else {
89-
listRef.current?.scrollTo(config);
90-
}
87+
scrollTo: (config: VirtualScrollConfig) => {
88+
const { align, offset, ...restConfig } = config;
89+
90+
const alignMap: Record<string, 'top' | 'bottom' | 'auto'> = {
91+
start: 'top',
92+
end: 'bottom',
93+
nearest: 'auto',
94+
};
95+
96+
const virtualAlign = align ? alignMap[align] : offset ? 'top' : 'auto';
97+
98+
listRef.current?.scrollTo({
99+
...restConfig,
100+
offset,
101+
align: virtualAlign,
102+
});
91103
},
92104
nativeElement: listRef.current?.nativeElement,
93105
} as unknown as GridRef;

src/interface.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,17 @@ export type ScrollConfig = {
4040
* Additional offset in pixels to apply to the scroll position.
4141
* Only effective when using `key` or `index` mode.
4242
* Ignored when using `top` mode.
43-
* When offset is set, the target element will be aligned according to the `align` parameter.
43+
* In `key` / `index` mode, `offset` is added to the position resolved by `align`.
4444
*/
4545
offset?: number;
4646

4747
align?: ScrollLogicalPosition;
4848
};
4949

50+
export type VirtualScrollConfig = ScrollConfig & {
51+
align?: Exclude<ScrollLogicalPosition, 'center'>;
52+
};
53+
5054
export type Reference = {
5155
nativeElement: HTMLDivElement;
5256
scrollTo: (config: ScrollConfig) => void;

tests/Virtual.spec.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ describe('Table.Virtual', () => {
373373

374374
expect(global.scrollToConfig).toEqual({
375375
index: 99,
376+
align: 'auto',
376377
});
377378
});
378379

@@ -423,6 +424,31 @@ describe('Table.Virtual', () => {
423424
});
424425
});
425426

427+
it('scrollTo with align should pass', async () => {
428+
const tblRef = React.createRef<Reference>();
429+
getTable({ ref: tblRef });
430+
431+
// align start -> top
432+
tblRef.current.scrollTo({ index: 50, align: 'start' });
433+
await waitFakeTimer();
434+
expect(global.scrollToConfig).toEqual({ index: 50, align: 'top' });
435+
436+
// align end -> bottom
437+
tblRef.current.scrollTo({ index: 50, align: 'end' });
438+
await waitFakeTimer();
439+
expect(global.scrollToConfig).toEqual({ index: 50, align: 'bottom' });
440+
441+
// align nearest -> auto
442+
tblRef.current.scrollTo({ index: 50, align: 'nearest' });
443+
await waitFakeTimer();
444+
expect(global.scrollToConfig).toEqual({ index: 50, align: 'auto' });
445+
446+
// offset + align
447+
tblRef.current.scrollTo({ index: 50, offset: 20, align: 'end' });
448+
await waitFakeTimer();
449+
expect(global.scrollToConfig).toEqual({ index: 50, offset: 20, align: 'bottom' });
450+
});
451+
426452
describe('auto width', () => {
427453
async function prepareTable(columns: any[]) {
428454
const { container } = getTable({

0 commit comments

Comments
 (0)