Skip to content

Commit

Permalink
feat: ScrollTo support key directly
Browse files Browse the repository at this point in the history
  • Loading branch information
zombieJ committed Sep 18, 2019
1 parent c564374 commit 0444789
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 19 deletions.
17 changes: 14 additions & 3 deletions examples/basic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import * as React from 'react';
import List from '../src/List';

interface Item {
id: number;
id: string;
}

const MyItem: React.FC<Item> = ({ id }, ref) => (
Expand All @@ -24,7 +24,7 @@ const MyItem: React.FC<Item> = ({ id }, ref) => (

const ForwardMyItem = React.forwardRef(MyItem);

class TestItem extends React.Component<{ id: number }, {}> {
class TestItem extends React.Component<Item, {}> {
state = {};

render() {
Expand All @@ -35,7 +35,7 @@ class TestItem extends React.Component<{ id: number }, {}> {
const data: Item[] = [];
for (let i = 0; i < 100; i += 1) {
data.push({
id: i,
id: String(i),
});
}

Expand Down Expand Up @@ -127,6 +127,17 @@ const Demo = () => {
>
Scroll To 50 (auto)
</button>
<button
type="button"
onClick={() => {
listRef.current.scrollTo({
key: '50',
align: 'auto',
});
}}
>
Scroll To key 50 (auto)
</button>
</div>
</React.StrictMode>
);
Expand Down
29 changes: 25 additions & 4 deletions src/List.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
getCompareItemRelativeTop,
alignScrollTop,
requireVirtual,
Key,
} from './utils/itemUtil';
import { getIndexByStartLoc, findListDiffIndex } from './utils/algorithmUtil';

Expand All @@ -20,6 +21,17 @@ const ScrollStyle = {
overflowAnchor: 'none',
};

type ScrollAlign = 'top' | 'bottom' | 'auto';
type ScrollConfig =
| {
index: number;
align?: ScrollAlign;
}
| {
key: Key;
align?: ScrollAlign;
};

export type RenderFunc<T> = (
item: T,
index: number,
Expand Down Expand Up @@ -47,7 +59,7 @@ export interface ListProps<T> extends React.HTMLAttributes<any> {
itemHeight?: number;
/** If not match virtual scroll condition, Set List still use height of container. */
fullHeight?: boolean;
itemKey: string | ((item: T) => string);
itemKey: Key | ((item: T) => Key);
component?: string | React.FC<any> | React.ComponentClass<any>;
disabled?: boolean;

Expand Down Expand Up @@ -417,7 +429,7 @@ class List<T = any> extends React.Component<ListProps<T>, ListState<T>> {
return this.getItemKey(item, mergedProps);
};

public getItemKey = (item: T, props?: Partial<ListProps<T>>): string => {
public getItemKey = (item: T, props?: Partial<ListProps<T>>): Key => {
const { itemKey } = props || this.props;

return typeof itemKey === 'function' ? itemKey(item) : item[itemKey];
Expand All @@ -444,14 +456,23 @@ class List<T = any> extends React.Component<ListProps<T>, ListState<T>> {

public scrollTo(scrollTop: number): void;

public scrollTo(config: { index: number; align?: 'top' | 'bottom' | 'auto' }): void;
public scrollTo(config: ScrollConfig): void;

public scrollTo(arg0: any) {
// Number top
if (typeof arg0 === 'object') {
const { isVirtual } = this.state;
const { height, itemHeight, data } = this.props;
const { index, align = 'auto' } = arg0;
const { align = 'auto' } = arg0;

let index = 0;
if ('index' in arg0) {
({ index } = arg0);
} else if ('key' in arg0) {
const { key } = arg0;
index = data.findIndex(item => this.getItemKey(item) === key);
}

const visibleCount = Math.ceil(height / itemHeight);
const item = data[index];
if (item) {
Expand Down
4 changes: 3 additions & 1 deletion src/utils/algorithmUtil.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { Key } from './itemUtil';

/**
* Get index with specific start index one by one. e.g.
* min: 3, max: 9, start: 6
Expand Down Expand Up @@ -39,7 +41,7 @@ export function getIndexByStartLoc(min: number, max: number, start: number, inde
export function findListDiffIndex<T>(
originList: T[],
targetList: T[],
getKey: (item: T) => string,
getKey: (item: T) => Key,
): { index: number; multiple: boolean } | null {
const originLen = originList.length;
const targetLen = targetList.length;
Expand Down
6 changes: 4 additions & 2 deletions src/utils/itemUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import findDOMNode from 'rc-util/lib/Dom/findDOMNode';
*/
export const GHOST_ITEM_KEY = '__rc_ghost_item__';

export type Key = string | number;

interface LocationItemResult {
/** Located item index */
index: number;
Expand Down Expand Up @@ -108,7 +110,7 @@ interface ItemTopConfig {
scrollPtg: number;
clientHeight: number;

getItemKey: (index: number) => string;
getItemKey: (index: number) => Key;
}

/**
Expand Down Expand Up @@ -139,7 +141,7 @@ interface CompareItemConfig {
locatedItemRelativeTop: number;
locatedItemIndex: number;
compareItemIndex: number;
getItemKey: (index: number) => string;
getItemKey: (index: number) => Key;
startIndex: number;
endIndex: number;
itemElementHeights: { [key: string]: number };
Expand Down
20 changes: 11 additions & 9 deletions tests/scroll.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import List from '../src';
import { spyElementPrototypes } from './utils/domHook';

function genData(count) {
return new Array(count).fill(null).map((_, id) => ({ id }));
return new Array(count).fill(null).map((_, index) => ({ id: String(index) }));
}

describe('List.Scroll', () => {
Expand Down Expand Up @@ -60,7 +60,7 @@ describe('List.Scroll', () => {
mockElement.mockRestore();
});

function testPlots(type, props) {
function testPlots(type, scrollConfig, props) {
describe(`${type} list`, () => {
let listRef;
let wrapper;
Expand All @@ -81,11 +81,11 @@ describe('List.Scroll', () => {
});

it('top', () => {
listRef.current.scrollTo({ index: 10, align: 'top' });
listRef.current.scrollTo({ ...scrollConfig, align: 'top' });
expect(scrollTop).toEqual(200);
});
it('bottom', () => {
listRef.current.scrollTo({ index: 10, align: 'bottom' });
listRef.current.scrollTo({ ...scrollConfig, align: 'bottom' });
expect(scrollTop).toEqual(120);
});
describe('auto', () => {
Expand All @@ -96,7 +96,7 @@ describe('List.Scroll', () => {
.last()
.simulate('scroll');
expect(onScroll).toHaveBeenCalled();
listRef.current.scrollTo({ index: 10, align: 'auto' });
listRef.current.scrollTo({ ...scrollConfig, align: 'auto' });
expect(scrollTop).toEqual(200);
});
it('lower of', () => {
Expand All @@ -106,7 +106,7 @@ describe('List.Scroll', () => {
.last()
.simulate('scroll');
expect(onScroll).toHaveBeenCalled();
listRef.current.scrollTo({ index: 10, align: 'auto' });
listRef.current.scrollTo({ ...scrollConfig, align: 'auto' });
expect(scrollTop).toEqual(120);
});
it('in range', () => {
Expand All @@ -116,14 +116,16 @@ describe('List.Scroll', () => {
.last()
.simulate('scroll');
expect(onScroll).toHaveBeenCalled();
listRef.current.scrollTo({ index: 10, align: 'auto' });
listRef.current.scrollTo({ ...scrollConfig, align: 'auto' });
expect(scrollTop).toEqual(150);
});
});
});
}

testPlots('virtual list');
testPlots('raw list', { itemHeight: null });
testPlots('virtual list', { index: 10 });
testPlots('raw list', { index: 10 }, { itemHeight: null });
testPlots('virtual list by key', { key: '10' });
testPlots('raw list by key', { key: '10' }, { itemHeight: null });
});
});

0 comments on commit 0444789

Please sign in to comment.