Skip to content

Commit bfaf8ff

Browse files
committed
add lastIndex to the returned data, undefined for empty lists
1 parent d694315 commit bfaf8ff

File tree

2 files changed

+59
-1
lines changed

2 files changed

+59
-1
lines changed

packages/virtual/src/index.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type VirtualListReturn<T extends readonly any[]> = [
1616
viewerTop: number;
1717
visibleItems: T;
1818
firstIndex: number;
19+
lastIndex: number | undefined;
1920
}>,
2021
onScroll: (e: Event) => void,
2122
];
@@ -55,6 +56,8 @@ export function createVirtualList<T extends readonly any[]>({
5556
viewerTop: firstIndex * rowHeight,
5657
visibleItems: items.slice(firstIndex, lastIndex) as unknown as T,
5758
firstIndex,
59+
lastIndex: lastIndex > 0 ? lastIndex - 1 : undefined,
60+
// -1 because slice is an exclusive range
5861
};
5962
},
6063
e => {

packages/virtual/test/index.test.tsx

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ describe("createVirtualList", () => {
5151
expect(virtual().visibleItems).toEqual([0, 1, 2]);
5252
});
5353

54-
test("returns firstIndex representing the index of the visibleList", () => {
54+
test("returns firstIndex representing the first index of the visibleList", () => {
5555
const [virtual] = createVirtualList({
5656
items: TEST_LIST,
5757
rootHeight: 20,
@@ -61,6 +61,16 @@ describe("createVirtualList", () => {
6161
expect(virtual().firstIndex).toEqual(0);
6262
});
6363

64+
test("returns lastIndex representing the last item in the visibleList's index", () => {
65+
const [virtual] = createVirtualList({
66+
items: TEST_LIST,
67+
rootHeight: 20,
68+
rowHeight: 10,
69+
});
70+
71+
expect(virtual().lastIndex).toEqual(2);
72+
});
73+
6474
test("returns onScroll which sets viewerTop and visibleItems based on rootElement's scrolltop", () => {
6575
const el = document.createElement("div");
6676

@@ -73,47 +83,54 @@ describe("createVirtualList", () => {
7383
expect(virtual().visibleItems).toEqual([0, 1, 2]);
7484
expect(virtual().viewerTop).toEqual(0);
7585
expect(virtual().firstIndex).toEqual(0);
86+
expect(virtual().lastIndex).toEqual(2);
7687

7788
el.scrollTop += 10;
7889

7990
// no change until onScroll is called
8091
expect(virtual().visibleItems).toEqual([0, 1, 2]);
8192
expect(virtual().viewerTop).toEqual(0);
8293
expect(virtual().firstIndex).toEqual(0);
94+
expect(virtual().lastIndex).toEqual(2);
8395

8496
onScroll(TARGETED_SCROLL_EVENT(el));
8597

8698
expect(virtual().visibleItems).toEqual([0, 1, 2, 3]);
8799
expect(virtual().viewerTop).toEqual(0);
88100
expect(virtual().firstIndex).toEqual(0);
101+
expect(virtual().lastIndex).toEqual(3);
89102

90103
el.scrollTop += 10;
91104
onScroll(TARGETED_SCROLL_EVENT(el));
92105

93106
expect(virtual().visibleItems).toEqual([1, 2, 3, 4]);
94107
expect(virtual().viewerTop).toEqual(10);
95108
expect(virtual().firstIndex).toEqual(1);
109+
expect(virtual().lastIndex).toEqual(4);
96110

97111
el.scrollTop -= 10;
98112
onScroll(TARGETED_SCROLL_EVENT(el));
99113

100114
expect(virtual().visibleItems).toEqual([0, 1, 2, 3]);
101115
expect(virtual().viewerTop).toEqual(0);
102116
expect(virtual().firstIndex).toEqual(0);
117+
expect(virtual().lastIndex).toEqual(3);
103118

104119
el.scrollTop -= 10;
105120
onScroll(TARGETED_SCROLL_EVENT(el));
106121

107122
expect(virtual().visibleItems).toEqual([0, 1, 2]);
108123
expect(virtual().viewerTop).toEqual(0);
109124
expect(virtual().firstIndex).toEqual(0);
125+
expect(virtual().lastIndex).toEqual(2);
110126

111127
el.scrollTop += 7_000;
112128
onScroll(TARGETED_SCROLL_EVENT(el));
113129

114130
expect(virtual().visibleItems).toEqual([699, 700, 701, 702]);
115131
expect(virtual().viewerTop).toEqual(6990);
116132
expect(virtual().firstIndex).toEqual(699);
133+
expect(virtual().lastIndex).toEqual(702);
117134
});
118135

119136
test("onScroll handles reaching the bottom of the list", () => {
@@ -150,6 +167,7 @@ describe("createVirtualList", () => {
150167

151168
expect(virtual().visibleItems).toEqual([8, 9, 10, 11, 12, 13]);
152169
expect(virtual().firstIndex).toEqual(8);
170+
expect(virtual().lastIndex).toEqual(13);
153171
});
154172

155173
test("overscanCount defaults to 1 if undefined or zero", () => {
@@ -171,6 +189,41 @@ describe("createVirtualList", () => {
171189
expect(virtualZero().visibleItems).toEqual([0, 1, 2]);
172190
});
173191

192+
test("lastIndex is undefined in an empty list", () => {
193+
const [virtual] = createVirtualList({
194+
items: [],
195+
rootHeight: 20,
196+
rowHeight: 10,
197+
});
198+
199+
expect(virtual().lastIndex).toEqual(undefined);
200+
});
201+
202+
test("lastIndex is 0 in a singleton list", () => {
203+
const [virtual] = createVirtualList({
204+
items: [10],
205+
rootHeight: 20,
206+
rowHeight: 10,
207+
});
208+
209+
expect(virtual().lastIndex).toEqual(0);
210+
});
211+
212+
test("handles singleton list", () => {
213+
const [virtual] = createVirtualList({
214+
items: [10],
215+
rootHeight: 20,
216+
rowHeight: 10,
217+
overscanCount: 0,
218+
});
219+
220+
expect(virtual().containerHeight).toEqual(10);
221+
expect(virtual().viewerTop).toEqual(0);
222+
expect(virtual().visibleItems).toEqual([10]);
223+
expect(virtual().firstIndex).toEqual(0);
224+
expect(virtual().lastIndex).toEqual(0);
225+
});
226+
174227
test("handles empty list", () => {
175228
const [virtual] = createVirtualList({
176229
items: [],
@@ -182,6 +235,8 @@ describe("createVirtualList", () => {
182235
expect(virtual().containerHeight).toEqual(0);
183236
expect(virtual().viewerTop).toEqual(0);
184237
expect(virtual().visibleItems).toEqual([]);
238+
expect(virtual().firstIndex).toEqual(0);
239+
expect(virtual().lastIndex).toEqual(undefined);
185240
});
186241
});
187242

0 commit comments

Comments
 (0)