@etsoo/react 1.5.87 → 1.5.90

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.
@@ -107,4 +107,8 @@ export declare type GridLoaderStates<T> = GridLoadDataProps & {
107
107
  * Selected items of id
108
108
  */
109
109
  selectedItems: T[];
110
+ /**
111
+ * Id cache
112
+ */
113
+ idCache: Record<any, null>;
110
114
  };
@@ -24,7 +24,8 @@ export const ScrollerGrid = (props) => {
24
24
  orderByAsc: defaultOrderByAsc,
25
25
  batchSize: 10,
26
26
  loadedItems: 0,
27
- selectedItems: []
27
+ selectedItems: [],
28
+ idCache: {}
28
29
  });
29
30
  const state = refs.current;
30
31
  const ref = React.useRef(null);
@@ -60,14 +61,26 @@ export const ScrollerGrid = (props) => {
60
61
  .splice(rows.length - state.lastLoadedItems, state.lastLoadedItems)
61
62
  .concat(result)
62
63
  : result;
64
+ state.idCache = {};
65
+ for (const row of newRows) {
66
+ const id = row[idField];
67
+ state.idCache[id] = null;
68
+ }
63
69
  // Update rows
64
70
  setRows(newRows);
65
71
  }
66
72
  else {
67
73
  // Set current page
68
74
  state.currentPage = state.currentPage + pageAdd;
69
- // Update rows
70
- setRows([...rows, ...result]);
75
+ // Update rows, avoid duplicate items
76
+ const newRows = [...rows];
77
+ for (const item of result) {
78
+ const id = item[idField];
79
+ if (state.idCache[id] === undefined) {
80
+ newRows.push(item);
81
+ }
82
+ }
83
+ setRows(newRows);
71
84
  }
72
85
  });
73
86
  };
@@ -1,3 +1,4 @@
1
+ import { DataTypes, IdDefaultType } from '@etsoo/shared';
1
2
  import React from 'react';
2
3
  import { Align, ListChildComponentProps, ListProps } from 'react-window';
3
4
  import { GridLoader } from './GridLoader';
@@ -5,7 +6,7 @@ import { GridMethodRef } from './GridMethodRef';
5
6
  /**
6
7
  * Scroller vertical list props
7
8
  */
8
- export interface ScrollerListProps<T extends object> extends GridLoader<T>, Omit<ListProps<T>, 'ref' | 'outerRef' | 'height' | 'width' | 'children' | 'itemCount'> {
9
+ export interface ScrollerListProps<T extends object, D extends DataTypes.Keys<T>> extends GridLoader<T>, Omit<ListProps<T>, 'ref' | 'outerRef' | 'height' | 'width' | 'children' | 'itemCount'> {
9
10
  /**
10
11
  * Default order by asc/desc
11
12
  */
@@ -26,6 +27,10 @@ export interface ScrollerListProps<T extends object> extends GridLoader<T>, Omit
26
27
  * Width of the list
27
28
  */
28
29
  width?: number | string;
30
+ /**
31
+ * Id field
32
+ */
33
+ idField?: D;
29
34
  /**
30
35
  * Item renderer
31
36
  */
@@ -59,5 +64,5 @@ export interface ScrollerListForwardRef<T> extends GridMethodRef<T>, ScrollerLis
59
64
  * @param props Props
60
65
  * @returns Component
61
66
  */
62
- export declare const ScrollerList: <T extends object>(props: ScrollerListProps<T>) => JSX.Element;
67
+ export declare const ScrollerList: <T extends object, D extends DataTypes.Keys<T, string | number> = IdDefaultType<T>>(props: ScrollerListProps<T, D>) => JSX.Element;
63
68
  export {};
@@ -1,4 +1,4 @@
1
- import { Utils } from '@etsoo/shared';
1
+ import { DataTypes, Utils } from '@etsoo/shared';
2
2
  import React from 'react';
3
3
  import { FixedSizeList, VariableSizeList } from 'react-window';
4
4
  import { useCombinedRefs } from '../uses/useCombinedRefs';
@@ -15,7 +15,7 @@ const calculateBatchSize = (height, itemSize) => {
15
15
  */
16
16
  export const ScrollerList = (props) => {
17
17
  // Destruct
18
- const { autoLoad = true, defaultOrderBy, defaultOrderByAsc, height = document.documentElement.clientHeight, width = '100%', mRef, oRef, style = {}, itemRenderer, itemSize, loadBatchSize = calculateBatchSize(height, itemSize), loadData, threshold = GridSizeGet(loadBatchSize, height) / 2, onItemsRendered, ...rest } = props;
18
+ const { autoLoad = true, defaultOrderBy, defaultOrderByAsc, height = document.documentElement.clientHeight, width = '100%', mRef, oRef, style = {}, idField = 'id', itemRenderer, itemSize, loadBatchSize = calculateBatchSize(height, itemSize), loadData, threshold = GridSizeGet(loadBatchSize, height) / 2, onItemsRendered, ...rest } = props;
19
19
  // Style
20
20
  Object.assign(style, {
21
21
  width: '100%',
@@ -42,7 +42,8 @@ export const ScrollerList = (props) => {
42
42
  orderBy: defaultOrderBy,
43
43
  orderByAsc: defaultOrderByAsc,
44
44
  batchSize: GridSizeGet(loadBatchSize, height),
45
- selectedItems: []
45
+ selectedItems: [],
46
+ idCache: {}
46
47
  });
47
48
  const state = stateRefs.current;
48
49
  // Load data
@@ -77,13 +78,25 @@ export const ScrollerList = (props) => {
77
78
  .splice(rows.length - state.lastLoadedItems, state.lastLoadedItems)
78
79
  .concat(result)
79
80
  : result;
81
+ state.idCache = {};
82
+ for (const row of newRows) {
83
+ const id = row[idField];
84
+ state.idCache[id] = null;
85
+ }
80
86
  // Update rows
81
87
  setRows(newRows);
82
88
  }
83
89
  else {
84
90
  state.currentPage = state.currentPage + pageAdd;
85
- // Update rows
86
- setRows([...rows, ...result]);
91
+ // Update rows, avoid duplicate items
92
+ const newRows = [...rows];
93
+ for (const item of result) {
94
+ const id = item[idField];
95
+ if (state.idCache[id] === undefined) {
96
+ newRows.push(item);
97
+ }
98
+ }
99
+ setRows(newRows);
87
100
  }
88
101
  });
89
102
  };
@@ -180,5 +193,5 @@ export const ScrollerList = (props) => {
180
193
  if (state.currentPage === 0 && state.autoLoad)
181
194
  loadDataLocal();
182
195
  // Layout
183
- return typeof itemSize === 'function' ? (React.createElement(VariableSizeList, { height: height, width: width, itemCount: itemCount, itemSize: itemSize, outerRef: refs, ref: listRef, style: style, onItemsRendered: onItemsRenderedLocal, ...rest }, itemRendererLocal)) : (React.createElement(FixedSizeList, { height: height, width: width, itemCount: itemCount, itemSize: itemSize, outerRef: refs, ref: listRef, style: style, onItemsRendered: onItemsRenderedLocal, ...rest }, itemRendererLocal));
196
+ return typeof itemSize === 'function' ? (React.createElement(VariableSizeList, { height: height, width: width, itemCount: itemCount, itemKey: (index, data) => { var _a; return (_a = DataTypes.getIdValue1(data, idField)) !== null && _a !== void 0 ? _a : index; }, itemSize: itemSize, outerRef: refs, ref: listRef, style: style, onItemsRendered: onItemsRenderedLocal, ...rest }, itemRendererLocal)) : (React.createElement(FixedSizeList, { height: height, width: width, itemCount: itemCount, itemKey: (index, data) => { var _a; return (_a = DataTypes.getIdValue1(data, idField)) !== null && _a !== void 0 ? _a : index; }, itemSize: itemSize, outerRef: refs, ref: listRef, style: style, onItemsRendered: onItemsRenderedLocal, ...rest }, itemRendererLocal));
184
197
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.5.87",
3
+ "version": "1.5.90",
4
4
  "description": "TypeScript ReactJs UI Independent Framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -50,10 +50,10 @@
50
50
  "@emotion/css": "^11.10.0",
51
51
  "@emotion/react": "^11.10.4",
52
52
  "@emotion/styled": "^11.10.4",
53
- "@etsoo/appscript": "^1.2.89",
53
+ "@etsoo/appscript": "^1.2.91",
54
54
  "@etsoo/notificationbase": "^1.1.7",
55
- "@etsoo/shared": "^1.1.52",
56
- "@types/react": "^18.0.18",
55
+ "@etsoo/shared": "^1.1.55",
56
+ "@types/react": "^18.0.19",
57
57
  "@types/react-dom": "^18.0.6",
58
58
  "@types/react-window": "^1.8.5",
59
59
  "react": "^18.2.0",
@@ -69,16 +69,16 @@
69
69
  "@babel/runtime-corejs3": "^7.19.0",
70
70
  "@testing-library/jest-dom": "^5.16.5",
71
71
  "@testing-library/react": "^13.4.0",
72
- "@types/jest": "^29.0.0",
72
+ "@types/jest": "^29.0.1",
73
73
  "@typescript-eslint/eslint-plugin": "^5.36.2",
74
74
  "@typescript-eslint/parser": "^5.36.2",
75
- "eslint": "^8.23.0",
75
+ "eslint": "^8.23.1",
76
76
  "eslint-config-airbnb-base": "^15.0.0",
77
77
  "eslint-plugin-import": "^2.26.0",
78
- "eslint-plugin-react": "^7.31.7",
79
- "jest": "^28.1.3",
80
- "jest-environment-jsdom": "^28.1.3",
81
- "ts-jest": "^28.0.8",
82
- "typescript": "^4.8.2"
78
+ "eslint-plugin-react": "^7.31.8",
79
+ "jest": "^29.0.3",
80
+ "jest-environment-jsdom": "^29.0.3",
81
+ "ts-jest": "^29.0.0",
82
+ "typescript": "^4.8.3"
83
83
  }
84
84
  }
@@ -150,4 +150,9 @@ export type GridLoaderStates<T> = GridLoadDataProps & {
150
150
  * Selected items of id
151
151
  */
152
152
  selectedItems: T[];
153
+
154
+ /**
155
+ * Id cache
156
+ */
157
+ idCache: Record<any, null>;
153
158
  };
@@ -190,7 +190,8 @@ export const ScrollerGrid = <
190
190
  orderByAsc: defaultOrderByAsc,
191
191
  batchSize: 10,
192
192
  loadedItems: 0,
193
- selectedItems: []
193
+ selectedItems: [],
194
+ idCache: {}
194
195
  });
195
196
  const state = refs.current;
196
197
 
@@ -237,14 +238,29 @@ export const ScrollerGrid = <
237
238
  .concat(result)
238
239
  : result;
239
240
 
241
+ state.idCache = {};
242
+ for (const row of newRows) {
243
+ const id = row[idField] as any;
244
+ state.idCache[id] = null;
245
+ }
246
+
240
247
  // Update rows
241
248
  setRows(newRows);
242
249
  } else {
243
250
  // Set current page
244
251
  state.currentPage = state.currentPage + pageAdd;
245
252
 
246
- // Update rows
247
- setRows([...rows, ...result]);
253
+ // Update rows, avoid duplicate items
254
+ const newRows = [...rows];
255
+
256
+ for (const item of result) {
257
+ const id = item[idField] as any;
258
+ if (state.idCache[id] === undefined) {
259
+ newRows.push(item);
260
+ }
261
+ }
262
+
263
+ setRows(newRows);
248
264
  }
249
265
  });
250
266
  };
@@ -1,4 +1,4 @@
1
- import { Utils } from '@etsoo/shared';
1
+ import { DataTypes, IdDefaultType, Utils } from '@etsoo/shared';
2
2
  import React from 'react';
3
3
  import {
4
4
  Align,
@@ -20,8 +20,10 @@ import { GridMethodRef } from './GridMethodRef';
20
20
  /**
21
21
  * Scroller vertical list props
22
22
  */
23
- export interface ScrollerListProps<T extends object>
24
- extends GridLoader<T>,
23
+ export interface ScrollerListProps<
24
+ T extends object,
25
+ D extends DataTypes.Keys<T>
26
+ > extends GridLoader<T>,
25
27
  Omit<
26
28
  ListProps<T>,
27
29
  'ref' | 'outerRef' | 'height' | 'width' | 'children' | 'itemCount'
@@ -51,6 +53,11 @@ export interface ScrollerListProps<T extends object>
51
53
  */
52
54
  width?: number | string;
53
55
 
56
+ /**
57
+ * Id field
58
+ */
59
+ idField?: D;
60
+
54
61
  /**
55
62
  * Item renderer
56
63
  */
@@ -100,7 +107,12 @@ const calculateBatchSize = (
100
107
  * @param props Props
101
108
  * @returns Component
102
109
  */
103
- export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
110
+ export const ScrollerList = <
111
+ T extends object,
112
+ D extends DataTypes.Keys<T> = IdDefaultType<T>
113
+ >(
114
+ props: ScrollerListProps<T, D>
115
+ ) => {
104
116
  // Destruct
105
117
  const {
106
118
  autoLoad = true,
@@ -111,6 +123,7 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
111
123
  mRef,
112
124
  oRef,
113
125
  style = {},
126
+ idField = 'id' as D,
114
127
  itemRenderer,
115
128
  itemSize,
116
129
  loadBatchSize = calculateBatchSize(height, itemSize),
@@ -150,7 +163,8 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
150
163
  orderBy: defaultOrderBy,
151
164
  orderByAsc: defaultOrderByAsc,
152
165
  batchSize: GridSizeGet(loadBatchSize, height),
153
- selectedItems: []
166
+ selectedItems: [],
167
+ idCache: {}
154
168
  });
155
169
  const state = stateRefs.current;
156
170
 
@@ -195,13 +209,28 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
195
209
  .concat(result)
196
210
  : result;
197
211
 
212
+ state.idCache = {};
213
+ for (const row of newRows) {
214
+ const id = row[idField] as any;
215
+ state.idCache[id] = null;
216
+ }
217
+
198
218
  // Update rows
199
219
  setRows(newRows);
200
220
  } else {
201
221
  state.currentPage = state.currentPage + pageAdd;
202
222
 
203
- // Update rows
204
- setRows([...rows, ...result]);
223
+ // Update rows, avoid duplicate items
224
+ const newRows = [...rows];
225
+
226
+ for (const item of result) {
227
+ const id = item[idField] as any;
228
+ if (state.idCache[id] === undefined) {
229
+ newRows.push(item);
230
+ }
231
+ }
232
+
233
+ setRows(newRows);
205
234
  }
206
235
  });
207
236
  };
@@ -327,6 +356,9 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
327
356
  height={height}
328
357
  width={width}
329
358
  itemCount={itemCount}
359
+ itemKey={(index, data) =>
360
+ DataTypes.getIdValue1(data, idField) ?? index
361
+ }
330
362
  itemSize={itemSize}
331
363
  outerRef={refs}
332
364
  ref={listRef}
@@ -341,6 +373,9 @@ export const ScrollerList = <T extends object>(props: ScrollerListProps<T>) => {
341
373
  height={height}
342
374
  width={width}
343
375
  itemCount={itemCount}
376
+ itemKey={(index, data) =>
377
+ DataTypes.getIdValue1(data, idField) ?? index
378
+ }
344
379
  itemSize={itemSize}
345
380
  outerRef={refs}
346
381
  ref={listRef}