@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.
@@ -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
- "outerRef" | "height" | "width" | "children" | "itemCount" // Exclude these props, shoud be exisited otherwise will be failed
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
- * Item renderer
41
+ * Methods ref
56
42
  */
57
- itemRenderer: (props: ListChildComponentProps<T>) => React.ReactElement;
43
+ mRef?: React.Ref<ScrollerListForwardRef<T>>;
58
44
 
59
45
  /**
60
- * Item size, a function indicates its a variable size list
46
+ * Width of the list
61
47
  */
62
- itemSize: ((index: number) => number) | number;
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
- height: number,
93
- itemSize: ((index: number) => number) | number
94
- ) => {
95
- const size = Utils.getResult<number>(itemSize, 0);
96
- return 2 + Math.ceil(height / size);
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 = document.documentElement.clientHeight,
74
+ height = "100%",
110
75
  width = "100%",
111
76
  mRef,
112
- oRef,
113
77
  style = {},
114
78
  idField = "id" as DataTypes.Keys<T>,
115
- itemRenderer,
116
- itemSize,
117
- loadBatchSize = calculateBatchSize(height, itemSize),
79
+ rowHeight,
80
+ listRef,
81
+ loadBatchSize = calculateBatchSize(height, rowHeight),
118
82
  loadData,
119
- threshold = GridSizeGet(loadBatchSize, height) / 2,
120
- onItemsRendered,
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: "100%",
129
- height: "100%",
130
- display: "inline-block"
92
+ width,
93
+ height
131
94
  });
132
95
 
133
- // Refs
134
- const listRef = React.useRef<any>(null);
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
- // States
149
- const batchSize = GridSizeGet(loadBatchSize, height);
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
- scrollToRef(scrollOffset: number): void {
293
- refMethods.scrollTo(scrollOffset);
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
- // Row count
305
- const rowCount = rows.length;
306
-
307
- // Local items renderer callback
308
- const onItemsRenderedLocal = (props: ListOnItemsRenderedProps) => {
309
- // No items, means no necessary to load more data during reset
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(listRef.current);
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
- // When layout ready
337
- React.useEffect(() => {
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 typeof itemSize === "function" ? (
346
- <VariableSizeList<T>
347
- height={height}
348
- width={width}
349
- itemCount={itemCount}
350
- itemKey={(index, data) => DataTypes.getIdValue1(data, idField) ?? index}
351
- itemSize={itemSize}
352
- outerRef={refs}
353
- ref={listRef}
354
- style={style}
355
- onItemsRendered={onItemsRenderedLocal}
356
- {...rest}
357
- >
358
- {itemRendererLocal}
359
- </VariableSizeList>
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";
package/vite.config.mts CHANGED
@@ -6,6 +6,7 @@ export default defineConfig({
6
6
  test: {
7
7
  globals: true,
8
8
  environment: "jsdom",
9
+ setupFiles: "./setupTests.ts",
9
10
  include: ["__tests__/**/*.ts(x)?"]
10
11
  }
11
12
  });