@etsoo/react 1.8.51 → 1.8.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/__tests__/ScrollerGrid.tsx +95 -0
- package/__tests__/ScrollerList.tsx +85 -0
- package/lib/cjs/components/GridLoader.d.ts +2 -2
- package/lib/cjs/components/GridMethodRef.d.ts +12 -7
- package/lib/cjs/components/ScrollerGrid.d.ts +26 -51
- package/lib/cjs/components/ScrollerGrid.js +67 -101
- package/lib/cjs/components/ScrollerList.d.ts +16 -41
- package/lib/cjs/components/ScrollerList.js +33 -52
- package/lib/cjs/index.d.ts +0 -1
- package/lib/mjs/components/GridLoader.d.ts +2 -2
- package/lib/mjs/components/GridMethodRef.d.ts +12 -7
- package/lib/mjs/components/ScrollerGrid.d.ts +26 -51
- package/lib/mjs/components/ScrollerGrid.js +68 -102
- package/lib/mjs/components/ScrollerList.d.ts +16 -41
- package/lib/mjs/components/ScrollerList.js +35 -54
- package/lib/mjs/index.d.ts +0 -1
- package/package.json +13 -13
- package/setupTests.ts +13 -0
- package/src/components/GridLoader.ts +2 -2
- package/src/components/GridMethodRef.ts +14 -8
- package/src/components/ScrollerGrid.tsx +163 -251
- package/src/components/ScrollerList.tsx +71 -152
- package/src/index.ts +0 -5
- package/vite.config.mts +1 -0
|
@@ -1,50 +1,36 @@
|
|
|
1
1
|
import { DataTypes, Utils } from "@etsoo/shared";
|
|
2
2
|
import React from "react";
|
|
3
|
-
import {
|
|
4
|
-
Align,
|
|
5
|
-
FixedSizeList,
|
|
6
|
-
ListChildComponentProps,
|
|
7
|
-
ListOnItemsRenderedProps,
|
|
8
|
-
ListProps,
|
|
9
|
-
VariableSizeList
|
|
10
|
-
} from "react-window";
|
|
3
|
+
import { List, ListProps, useListRef } from "react-window";
|
|
11
4
|
import { useCombinedRefs } from "../uses/useCombinedRefs";
|
|
12
5
|
import {
|
|
13
6
|
GridLoadDataProps,
|
|
14
7
|
GridLoader,
|
|
15
8
|
GridLoaderPartialStates,
|
|
16
|
-
GridLoaderStates
|
|
17
|
-
GridSizeGet
|
|
9
|
+
GridLoaderStates
|
|
18
10
|
} from "./GridLoader";
|
|
19
|
-
import { GridMethodRef } from "./GridMethodRef";
|
|
11
|
+
import { GridMethodRef, ScrollToRowParam } from "./GridMethodRef";
|
|
12
|
+
|
|
13
|
+
type ScrollerListRowProps<T extends object> = {
|
|
14
|
+
items: T[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Scroller list forward ref
|
|
19
|
+
*/
|
|
20
|
+
export interface ScrollerListForwardRef<T> extends GridMethodRef<T> {}
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* Scroller vertical list props
|
|
23
24
|
*/
|
|
24
25
|
export type ScrollerListProps<T extends object> = GridLoader<T> &
|
|
25
26
|
Omit<
|
|
26
|
-
ListProps<T
|
|
27
|
-
"
|
|
27
|
+
ListProps<ScrollerListRowProps<T>>,
|
|
28
|
+
"rowCount" | "rowProps" | "overscanCount"
|
|
28
29
|
> & {
|
|
29
|
-
/**
|
|
30
|
-
* Methods ref
|
|
31
|
-
*/
|
|
32
|
-
mRef?: React.Ref<ScrollerListForwardRef<T>>;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Outer div ref
|
|
36
|
-
*/
|
|
37
|
-
oRef?: React.Ref<HTMLDivElement>;
|
|
38
|
-
|
|
39
30
|
/**
|
|
40
31
|
* Height of the list
|
|
41
32
|
*/
|
|
42
|
-
height?: number;
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Width of the list
|
|
46
|
-
*/
|
|
47
|
-
width?: number | string;
|
|
33
|
+
height?: number | string;
|
|
48
34
|
|
|
49
35
|
/**
|
|
50
36
|
* Id field
|
|
@@ -52,48 +38,27 @@ export type ScrollerListProps<T extends object> = GridLoader<T> &
|
|
|
52
38
|
idField?: DataTypes.Keys<T>;
|
|
53
39
|
|
|
54
40
|
/**
|
|
55
|
-
*
|
|
41
|
+
* Methods ref
|
|
56
42
|
*/
|
|
57
|
-
|
|
43
|
+
mRef?: React.Ref<ScrollerListForwardRef<T>>;
|
|
58
44
|
|
|
59
45
|
/**
|
|
60
|
-
*
|
|
46
|
+
* Width of the list
|
|
61
47
|
*/
|
|
62
|
-
|
|
48
|
+
width?: number | string;
|
|
63
49
|
};
|
|
64
50
|
|
|
65
|
-
/**
|
|
66
|
-
* Scroller list ref
|
|
67
|
-
*/
|
|
68
|
-
export interface ScrollerListRef {
|
|
69
|
-
/**
|
|
70
|
-
* Scroll to the specified offset (scrollTop or scrollLeft, depending on the direction prop).
|
|
71
|
-
*/
|
|
72
|
-
scrollTo(scrollOffset: number): void;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Scroll to the specified item.
|
|
76
|
-
*/
|
|
77
|
-
scrollToItem(index: number, align?: Align): void;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Scroller list forward ref
|
|
82
|
-
*/
|
|
83
|
-
export interface ScrollerListForwardRef<T> extends GridMethodRef<T> {
|
|
84
|
-
/**
|
|
85
|
-
* Refresh latest page data
|
|
86
|
-
*/
|
|
87
|
-
refresh(): void;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
51
|
// Calculate loadBatchSize
|
|
91
|
-
const calculateBatchSize = (
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
52
|
+
const calculateBatchSize = (height: unknown, rowHeight: unknown) => {
|
|
53
|
+
if (
|
|
54
|
+
typeof height === "number" &&
|
|
55
|
+
typeof rowHeight === "number" &&
|
|
56
|
+
rowHeight > 0
|
|
57
|
+
) {
|
|
58
|
+
return 1 + Math.ceil(height / rowHeight);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return 10;
|
|
97
62
|
};
|
|
98
63
|
|
|
99
64
|
/**
|
|
@@ -106,18 +71,17 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
|
|
|
106
71
|
const {
|
|
107
72
|
autoLoad = true,
|
|
108
73
|
defaultOrderBy,
|
|
109
|
-
height =
|
|
74
|
+
height = "100%",
|
|
110
75
|
width = "100%",
|
|
111
76
|
mRef,
|
|
112
|
-
oRef,
|
|
113
77
|
style = {},
|
|
114
78
|
idField = "id" as DataTypes.Keys<T>,
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
loadBatchSize = calculateBatchSize(height,
|
|
79
|
+
rowHeight,
|
|
80
|
+
listRef,
|
|
81
|
+
loadBatchSize = calculateBatchSize(height, rowHeight),
|
|
118
82
|
loadData,
|
|
119
|
-
threshold =
|
|
120
|
-
|
|
83
|
+
threshold = 3,
|
|
84
|
+
onRowsRendered,
|
|
121
85
|
onInitLoad,
|
|
122
86
|
onUpdateRows,
|
|
123
87
|
...rest
|
|
@@ -125,19 +89,15 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
|
|
|
125
89
|
|
|
126
90
|
// Style
|
|
127
91
|
Object.assign(style, {
|
|
128
|
-
width
|
|
129
|
-
height
|
|
130
|
-
display: "inline-block"
|
|
92
|
+
width,
|
|
93
|
+
height
|
|
131
94
|
});
|
|
132
95
|
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
const outerRef = React.useRef<HTMLDivElement>(null);
|
|
136
|
-
|
|
137
|
-
const refs = useCombinedRefs(oRef, outerRef);
|
|
96
|
+
const localRef = useListRef(null);
|
|
97
|
+
const refs = useCombinedRefs(listRef, localRef);
|
|
138
98
|
|
|
139
|
-
// Rows
|
|
140
99
|
const [rows, updateRows] = React.useState<T[]>([]);
|
|
100
|
+
|
|
141
101
|
const setRows = (rows: T[], reset: boolean = false) => {
|
|
142
102
|
stateRefs.current.loadedItems = rows.length;
|
|
143
103
|
updateRows(rows);
|
|
@@ -145,8 +105,8 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
|
|
|
145
105
|
if (!reset && onUpdateRows) onUpdateRows(rows, stateRefs.current);
|
|
146
106
|
};
|
|
147
107
|
|
|
148
|
-
|
|
149
|
-
|
|
108
|
+
const batchSize = Utils.getResult<number>(loadBatchSize, height);
|
|
109
|
+
|
|
150
110
|
const stateRefs = React.useRef<GridLoaderStates<T>>({
|
|
151
111
|
queryPaging: {
|
|
152
112
|
currentPage: 0,
|
|
@@ -233,14 +193,6 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
|
|
|
233
193
|
});
|
|
234
194
|
};
|
|
235
195
|
|
|
236
|
-
const itemRendererLocal = (itemProps: ListChildComponentProps<T>) => {
|
|
237
|
-
// Custom render
|
|
238
|
-
return itemRenderer({
|
|
239
|
-
...itemProps,
|
|
240
|
-
data: rows[itemProps.index]
|
|
241
|
-
});
|
|
242
|
-
};
|
|
243
|
-
|
|
244
196
|
// Reset the state and load again
|
|
245
197
|
const reset = (add?: GridLoaderPartialStates<T>, items: T[] = []) => {
|
|
246
198
|
const { queryPaging, ...rest } = add ?? {};
|
|
@@ -266,8 +218,6 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
|
|
|
266
218
|
React.useImperativeHandle(
|
|
267
219
|
mRef,
|
|
268
220
|
() => {
|
|
269
|
-
const refMethods = listRef.current as ScrollerListRef;
|
|
270
|
-
|
|
271
221
|
return {
|
|
272
222
|
delete(index) {
|
|
273
223
|
const item = rows.at(index);
|
|
@@ -289,36 +239,21 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
|
|
|
289
239
|
|
|
290
240
|
reset,
|
|
291
241
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
},
|
|
295
|
-
|
|
296
|
-
scrollToItemRef(index: number, align?: Align): void {
|
|
297
|
-
refMethods.scrollToItem(index, align);
|
|
242
|
+
scrollToRow(param: ScrollToRowParam): void {
|
|
243
|
+
localRef.current?.scrollToRow(param);
|
|
298
244
|
}
|
|
299
245
|
};
|
|
300
246
|
},
|
|
301
247
|
[]
|
|
302
248
|
);
|
|
303
249
|
|
|
304
|
-
//
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
if (rowCount > 0 && props.visibleStopIndex + threshold > rowCount) {
|
|
312
|
-
// Auto load next page
|
|
313
|
-
loadDataLocal();
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
// Custom
|
|
317
|
-
if (onItemsRendered) onItemsRendered(props);
|
|
318
|
-
};
|
|
319
|
-
|
|
320
|
-
// Item count
|
|
321
|
-
const itemCount = stateRefs.current.hasNextPage ? rowCount + 1 : rowCount;
|
|
250
|
+
// When layout ready
|
|
251
|
+
React.useEffect(() => {
|
|
252
|
+
// Return clear function
|
|
253
|
+
return () => {
|
|
254
|
+
stateRefs.current.isMounted = false;
|
|
255
|
+
};
|
|
256
|
+
}, []);
|
|
322
257
|
|
|
323
258
|
React.useEffect(() => {
|
|
324
259
|
// Auto load data when current page is 0
|
|
@@ -327,50 +262,34 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
|
|
|
327
262
|
stateRefs.current.autoLoad
|
|
328
263
|
) {
|
|
329
264
|
const initItems =
|
|
330
|
-
onInitLoad == null ? undefined : onInitLoad(
|
|
265
|
+
onInitLoad == null ? undefined : onInitLoad(localRef.current);
|
|
331
266
|
if (initItems) reset(initItems[1], initItems[0]);
|
|
332
267
|
else loadDataLocal();
|
|
333
268
|
}
|
|
334
269
|
}, [onInitLoad, loadDataLocal]);
|
|
335
270
|
|
|
336
|
-
//
|
|
337
|
-
|
|
338
|
-
// Return clear function
|
|
339
|
-
return () => {
|
|
340
|
-
stateRefs.current.isMounted = false;
|
|
341
|
-
};
|
|
342
|
-
}, []);
|
|
271
|
+
// Row count
|
|
272
|
+
const rowCount = rows.length;
|
|
343
273
|
|
|
344
274
|
// Layout
|
|
345
|
-
return
|
|
346
|
-
<
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
{
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
<FixedSizeList<T>
|
|
362
|
-
height={height}
|
|
363
|
-
width={width}
|
|
364
|
-
itemCount={itemCount}
|
|
365
|
-
itemKey={(index, data) => DataTypes.getIdValue1(data, idField) ?? index}
|
|
366
|
-
itemSize={itemSize}
|
|
367
|
-
outerRef={refs}
|
|
368
|
-
ref={listRef}
|
|
275
|
+
return (
|
|
276
|
+
<List<ScrollerListRowProps<T>>
|
|
277
|
+
listRef={refs}
|
|
278
|
+
onRowsRendered={(visibleCells, allCells) => {
|
|
279
|
+
// No items, means no necessary to load more data during reset
|
|
280
|
+
if (rowCount > 0 && visibleCells.stopIndex + threshold > rowCount) {
|
|
281
|
+
// Auto load next page
|
|
282
|
+
loadDataLocal();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
onRowsRendered?.(visibleCells, allCells);
|
|
286
|
+
}}
|
|
287
|
+
overscanCount={threshold}
|
|
288
|
+
rowHeight={rowHeight}
|
|
289
|
+
rowCount={rowCount}
|
|
290
|
+
rowProps={{ items: rows }}
|
|
369
291
|
style={style}
|
|
370
|
-
onItemsRendered={onItemsRenderedLocal}
|
|
371
292
|
{...rest}
|
|
372
|
-
|
|
373
|
-
{itemRendererLocal}
|
|
374
|
-
</FixedSizeList>
|
|
293
|
+
/>
|
|
375
294
|
);
|
|
376
295
|
};
|
package/src/index.ts
CHANGED
|
@@ -13,11 +13,6 @@ export * from "./components/ListItemReact";
|
|
|
13
13
|
export * from "./components/ScrollerGrid";
|
|
14
14
|
export * from "./components/ScrollerList";
|
|
15
15
|
export * from "./components/ScrollRestoration";
|
|
16
|
-
export type {
|
|
17
|
-
ListOnScrollProps,
|
|
18
|
-
GridOnScrollProps,
|
|
19
|
-
VariableSizeGrid
|
|
20
|
-
} from "react-window";
|
|
21
16
|
|
|
22
17
|
// custom
|
|
23
18
|
export * from "./custom/CustomFieldReact";
|