@etsoo/react 1.6.80 → 1.6.82
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/lib/components/GridLoader.d.ts +12 -0
- package/lib/components/ScrollerGrid.js +13 -6
- package/lib/components/ScrollerList.js +27 -49
- package/package.json +2 -2
- package/src/components/GridLoader.ts +16 -0
- package/src/components/ScrollerGrid.tsx +13 -4
- package/src/components/ScrollerList.tsx +26 -53
|
@@ -69,6 +69,18 @@ export type GridLoader<T extends object> = {
|
|
|
69
69
|
* Load data
|
|
70
70
|
*/
|
|
71
71
|
loadData: (props: GridLoadDataProps) => PromiseLike<T[] | null | undefined>;
|
|
72
|
+
/**
|
|
73
|
+
* Handler for init load
|
|
74
|
+
* @param ref Ref
|
|
75
|
+
* @returns Result
|
|
76
|
+
*/
|
|
77
|
+
onInitLoad?: (ref: any) => [T[], Partial<GridLoaderStates<T>>?] | null | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* Handler for updating rows
|
|
80
|
+
* @param rows Rows
|
|
81
|
+
* @param state State
|
|
82
|
+
*/
|
|
83
|
+
onUpdateRows?: (rows: T[], state: GridLoaderStates<T>) => void;
|
|
72
84
|
/**
|
|
73
85
|
* Threshold at which to pre-fetch data; default is half of loadBatchSize
|
|
74
86
|
*/
|
|
@@ -7,12 +7,14 @@ import { VariableSizeGrid } from 'react-window';
|
|
|
7
7
|
*/
|
|
8
8
|
export const ScrollerGrid = (props) => {
|
|
9
9
|
// Destruct
|
|
10
|
-
const { autoLoad = true, defaultOrderBy, defaultOrderByAsc, footerRenderer, headerRenderer, itemRenderer, idField = 'id', loadBatchSize, loadData, mRef, onItemsRendered, onSelectChange, rowHeight = 53, threshold = 6, width, ...rest } = props;
|
|
10
|
+
const { autoLoad = true, defaultOrderBy, defaultOrderByAsc, footerRenderer, headerRenderer, itemRenderer, idField = 'id', loadBatchSize, loadData, mRef, onItemsRendered, onSelectChange, rowHeight = 53, threshold = 6, width, onInitLoad, onUpdateRows, ...rest } = props;
|
|
11
11
|
// Rows
|
|
12
12
|
const [rows, updateRows] = React.useState([]);
|
|
13
|
-
const setRows = (rows) => {
|
|
13
|
+
const setRows = (rows, reset = false) => {
|
|
14
14
|
state.loadedItems = rows.length;
|
|
15
15
|
updateRows(rows);
|
|
16
|
+
if (!reset && onUpdateRows)
|
|
17
|
+
onUpdateRows(rows, state);
|
|
16
18
|
};
|
|
17
19
|
// Refs
|
|
18
20
|
const refs = React.useRef({
|
|
@@ -116,7 +118,7 @@ export const ScrollerGrid = (props) => {
|
|
|
116
118
|
onItemsRendered(props);
|
|
117
119
|
};
|
|
118
120
|
// Reset the state and load again
|
|
119
|
-
const reset = (add) => {
|
|
121
|
+
const reset = (add, items = []) => {
|
|
120
122
|
const resetState = {
|
|
121
123
|
autoLoad: true,
|
|
122
124
|
currentPage: 0,
|
|
@@ -129,7 +131,7 @@ export const ScrollerGrid = (props) => {
|
|
|
129
131
|
Object.assign(state, resetState);
|
|
130
132
|
// Reset items
|
|
131
133
|
if (state.isMounted !== false)
|
|
132
|
-
setRows(
|
|
134
|
+
setRows(items, true);
|
|
133
135
|
};
|
|
134
136
|
const instance = {
|
|
135
137
|
scrollTo(params) {
|
|
@@ -210,8 +212,13 @@ export const ScrollerGrid = (props) => {
|
|
|
210
212
|
// Row count
|
|
211
213
|
const rowCount = state.hasNextPage ? rowLength + 1 : rowLength;
|
|
212
214
|
// Auto load data when current page is 0
|
|
213
|
-
if (state.currentPage === 0 && state.autoLoad)
|
|
214
|
-
|
|
215
|
+
if (state.currentPage === 0 && state.autoLoad) {
|
|
216
|
+
const initItems = onInitLoad == null ? undefined : onInitLoad(ref.current);
|
|
217
|
+
if (initItems)
|
|
218
|
+
reset(initItems[1], initItems[0]);
|
|
219
|
+
else
|
|
220
|
+
loadDataLocal();
|
|
221
|
+
}
|
|
215
222
|
// Layout
|
|
216
223
|
return (React.createElement(React.Fragment, null,
|
|
217
224
|
headerRenderer && headerRenderer(state),
|
|
@@ -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 = {}, idField = 'id', 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, onInitLoad, onUpdateRows, ...rest } = props;
|
|
19
19
|
// Style
|
|
20
20
|
Object.assign(style, {
|
|
21
21
|
width: '100%',
|
|
@@ -28,9 +28,11 @@ export const ScrollerList = (props) => {
|
|
|
28
28
|
const refs = useCombinedRefs(oRef, outerRef);
|
|
29
29
|
// Rows
|
|
30
30
|
const [rows, updateRows] = React.useState([]);
|
|
31
|
-
const setRows = (rows) => {
|
|
31
|
+
const setRows = (rows, reset = false) => {
|
|
32
32
|
state.loadedItems = rows.length;
|
|
33
33
|
updateRows(rows);
|
|
34
|
+
if (!reset && onUpdateRows)
|
|
35
|
+
onUpdateRows(rows, state);
|
|
34
36
|
};
|
|
35
37
|
// States
|
|
36
38
|
const batchSize = GridSizeGet(loadBatchSize, height);
|
|
@@ -108,14 +110,21 @@ export const ScrollerList = (props) => {
|
|
|
108
110
|
data: rows[itemProps.index]
|
|
109
111
|
});
|
|
110
112
|
};
|
|
111
|
-
//
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
// Reset the state and load again
|
|
114
|
+
const reset = (add, items = []) => {
|
|
115
|
+
const resetState = {
|
|
116
|
+
autoLoad: true,
|
|
117
|
+
lastLoadedItems: undefined,
|
|
118
|
+
loadedItems: 0,
|
|
119
|
+
currentPage: 0,
|
|
120
|
+
hasNextPage: true,
|
|
121
|
+
isNextPageLoading: false,
|
|
122
|
+
...add
|
|
123
|
+
};
|
|
124
|
+
Object.assign(state, resetState);
|
|
125
|
+
// Reset
|
|
126
|
+
if (state.isMounted !== false)
|
|
127
|
+
setRows(items, true);
|
|
119
128
|
};
|
|
120
129
|
React.useImperativeHandle(mRef, () => {
|
|
121
130
|
const refMethods = listRef.current;
|
|
@@ -123,21 +132,7 @@ export const ScrollerList = (props) => {
|
|
|
123
132
|
refresh() {
|
|
124
133
|
loadDataLocal(0);
|
|
125
134
|
},
|
|
126
|
-
reset
|
|
127
|
-
const resetState = {
|
|
128
|
-
autoLoad: true,
|
|
129
|
-
lastLoadedItems: undefined,
|
|
130
|
-
loadedItems: 0,
|
|
131
|
-
currentPage: 0,
|
|
132
|
-
hasNextPage: true,
|
|
133
|
-
isNextPageLoading: false,
|
|
134
|
-
...add
|
|
135
|
-
};
|
|
136
|
-
Object.assign(state, resetState);
|
|
137
|
-
// Reset
|
|
138
|
-
if (state.isMounted !== false)
|
|
139
|
-
setRows([]);
|
|
140
|
-
},
|
|
135
|
+
reset,
|
|
141
136
|
scrollTo(scrollOffset) {
|
|
142
137
|
refMethods.scrollTo(scrollOffset);
|
|
143
138
|
},
|
|
@@ -148,30 +143,8 @@ export const ScrollerList = (props) => {
|
|
|
148
143
|
}, []);
|
|
149
144
|
// When layout ready
|
|
150
145
|
React.useEffect(() => {
|
|
151
|
-
let ticking = false;
|
|
152
|
-
let lastKnownScrollPosition = 0;
|
|
153
|
-
let requestAnimationFrameSeed = 0;
|
|
154
|
-
// Window scroll handler
|
|
155
|
-
const handleWindowScroll = () => {
|
|
156
|
-
lastKnownScrollPosition = window.scrollY;
|
|
157
|
-
if (!ticking) {
|
|
158
|
-
requestAnimationFrameSeed = window.requestAnimationFrame(() => {
|
|
159
|
-
updateScroll(lastKnownScrollPosition);
|
|
160
|
-
ticking = false;
|
|
161
|
-
requestAnimationFrameSeed = 0;
|
|
162
|
-
});
|
|
163
|
-
ticking = true;
|
|
164
|
-
}
|
|
165
|
-
};
|
|
166
|
-
// Add scroll event
|
|
167
|
-
window.addEventListener('scroll', handleWindowScroll);
|
|
168
146
|
// Return clear function
|
|
169
147
|
return () => {
|
|
170
|
-
// Cancel animation frame
|
|
171
|
-
if (requestAnimationFrameSeed > 0)
|
|
172
|
-
window.cancelAnimationFrame(requestAnimationFrameSeed);
|
|
173
|
-
// Remove scroll event
|
|
174
|
-
window.removeEventListener('scroll', handleWindowScroll);
|
|
175
148
|
state.isMounted = false;
|
|
176
149
|
};
|
|
177
150
|
}, []);
|
|
@@ -191,8 +164,13 @@ export const ScrollerList = (props) => {
|
|
|
191
164
|
// Item count
|
|
192
165
|
const itemCount = state.hasNextPage ? rowCount + 1 : rowCount;
|
|
193
166
|
// Auto load data when current page is 0
|
|
194
|
-
if (state.currentPage === 0 && state.autoLoad)
|
|
195
|
-
|
|
167
|
+
if (state.currentPage === 0 && state.autoLoad) {
|
|
168
|
+
const initItems = onInitLoad == null ? undefined : onInitLoad(listRef.current);
|
|
169
|
+
if (initItems)
|
|
170
|
+
reset(initItems[1], initItems[0]);
|
|
171
|
+
else
|
|
172
|
+
loadDataLocal();
|
|
173
|
+
}
|
|
196
174
|
// Layout
|
|
197
175
|
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));
|
|
198
176
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/react",
|
|
3
|
-
"version": "1.6.
|
|
3
|
+
"version": "1.6.82",
|
|
4
4
|
"description": "TypeScript ReactJs UI Independent Framework",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@emotion/css": "^11.11.0",
|
|
51
51
|
"@emotion/react": "^11.11.0",
|
|
52
52
|
"@emotion/styled": "^11.11.0",
|
|
53
|
-
"@etsoo/appscript": "^1.4.
|
|
53
|
+
"@etsoo/appscript": "^1.4.8",
|
|
54
54
|
"@etsoo/notificationbase": "^1.1.25",
|
|
55
55
|
"@etsoo/shared": "^1.2.5",
|
|
56
56
|
"@types/react": "^18.2.6",
|
|
@@ -105,6 +105,22 @@ export type GridLoader<T extends object> = {
|
|
|
105
105
|
*/
|
|
106
106
|
loadData: (props: GridLoadDataProps) => PromiseLike<T[] | null | undefined>;
|
|
107
107
|
|
|
108
|
+
/**
|
|
109
|
+
* Handler for init load
|
|
110
|
+
* @param ref Ref
|
|
111
|
+
* @returns Result
|
|
112
|
+
*/
|
|
113
|
+
onInitLoad?: (
|
|
114
|
+
ref: any
|
|
115
|
+
) => [T[], Partial<GridLoaderStates<T>>?] | null | undefined;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Handler for updating rows
|
|
119
|
+
* @param rows Rows
|
|
120
|
+
* @param state State
|
|
121
|
+
*/
|
|
122
|
+
onUpdateRows?: (rows: T[], state: GridLoaderStates<T>) => void;
|
|
123
|
+
|
|
108
124
|
/**
|
|
109
125
|
* Threshold at which to pre-fetch data; default is half of loadBatchSize
|
|
110
126
|
*/
|
|
@@ -181,14 +181,18 @@ export const ScrollerGrid = <
|
|
|
181
181
|
rowHeight = 53,
|
|
182
182
|
threshold = 6,
|
|
183
183
|
width,
|
|
184
|
+
onInitLoad,
|
|
185
|
+
onUpdateRows,
|
|
184
186
|
...rest
|
|
185
187
|
} = props;
|
|
186
188
|
|
|
187
189
|
// Rows
|
|
188
190
|
const [rows, updateRows] = React.useState<T[]>([]);
|
|
189
|
-
const setRows = (rows: T[]) => {
|
|
191
|
+
const setRows = (rows: T[], reset: boolean = false) => {
|
|
190
192
|
state.loadedItems = rows.length;
|
|
191
193
|
updateRows(rows);
|
|
194
|
+
|
|
195
|
+
if (!reset && onUpdateRows) onUpdateRows(rows, state);
|
|
192
196
|
};
|
|
193
197
|
|
|
194
198
|
// Refs
|
|
@@ -320,7 +324,7 @@ export const ScrollerGrid = <
|
|
|
320
324
|
};
|
|
321
325
|
|
|
322
326
|
// Reset the state and load again
|
|
323
|
-
const reset = (add?: Partial<GridLoaderStates<T
|
|
327
|
+
const reset = (add?: Partial<GridLoaderStates<T>>, items: T[] = []) => {
|
|
324
328
|
const resetState: Partial<GridLoaderStates<T>> = {
|
|
325
329
|
autoLoad: true,
|
|
326
330
|
currentPage: 0,
|
|
@@ -333,7 +337,7 @@ export const ScrollerGrid = <
|
|
|
333
337
|
Object.assign(state, resetState);
|
|
334
338
|
|
|
335
339
|
// Reset items
|
|
336
|
-
if (state.isMounted !== false) setRows(
|
|
340
|
+
if (state.isMounted !== false) setRows(items, true);
|
|
337
341
|
};
|
|
338
342
|
|
|
339
343
|
const instance: ScrollerGridForwardRef<T> = {
|
|
@@ -425,7 +429,12 @@ export const ScrollerGrid = <
|
|
|
425
429
|
const rowCount = state.hasNextPage ? rowLength + 1 : rowLength;
|
|
426
430
|
|
|
427
431
|
// Auto load data when current page is 0
|
|
428
|
-
if (state.currentPage === 0 && state.autoLoad)
|
|
432
|
+
if (state.currentPage === 0 && state.autoLoad) {
|
|
433
|
+
const initItems =
|
|
434
|
+
onInitLoad == null ? undefined : onInitLoad(ref.current);
|
|
435
|
+
if (initItems) reset(initItems[1], initItems[0]);
|
|
436
|
+
else loadDataLocal();
|
|
437
|
+
}
|
|
429
438
|
|
|
430
439
|
// Layout
|
|
431
440
|
return (
|
|
@@ -130,6 +130,8 @@ export const ScrollerList = <
|
|
|
130
130
|
loadData,
|
|
131
131
|
threshold = GridSizeGet(loadBatchSize, height) / 2,
|
|
132
132
|
onItemsRendered,
|
|
133
|
+
onInitLoad,
|
|
134
|
+
onUpdateRows,
|
|
133
135
|
...rest
|
|
134
136
|
} = props;
|
|
135
137
|
|
|
@@ -148,9 +150,11 @@ export const ScrollerList = <
|
|
|
148
150
|
|
|
149
151
|
// Rows
|
|
150
152
|
const [rows, updateRows] = React.useState<T[]>([]);
|
|
151
|
-
const setRows = (rows: T[]) => {
|
|
153
|
+
const setRows = (rows: T[], reset: boolean = false) => {
|
|
152
154
|
state.loadedItems = rows.length;
|
|
153
155
|
updateRows(rows);
|
|
156
|
+
|
|
157
|
+
if (!reset && onUpdateRows) onUpdateRows(rows, state);
|
|
154
158
|
};
|
|
155
159
|
|
|
156
160
|
// States
|
|
@@ -244,15 +248,21 @@ export const ScrollerList = <
|
|
|
244
248
|
});
|
|
245
249
|
};
|
|
246
250
|
|
|
247
|
-
//
|
|
248
|
-
const
|
|
249
|
-
const
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
251
|
+
// Reset the state and load again
|
|
252
|
+
const reset = (add?: Partial<GridLoaderStates<T>>, items: T[] = []) => {
|
|
253
|
+
const resetState: Partial<GridLoaderStates<T>> = {
|
|
254
|
+
autoLoad: true,
|
|
255
|
+
lastLoadedItems: undefined,
|
|
256
|
+
loadedItems: 0,
|
|
257
|
+
currentPage: 0,
|
|
258
|
+
hasNextPage: true,
|
|
259
|
+
isNextPageLoading: false,
|
|
260
|
+
...add
|
|
261
|
+
};
|
|
262
|
+
Object.assign(state, resetState);
|
|
254
263
|
|
|
255
|
-
|
|
264
|
+
// Reset
|
|
265
|
+
if (state.isMounted !== false) setRows(items, true);
|
|
256
266
|
};
|
|
257
267
|
|
|
258
268
|
React.useImperativeHandle(
|
|
@@ -265,21 +275,7 @@ export const ScrollerList = <
|
|
|
265
275
|
loadDataLocal(0);
|
|
266
276
|
},
|
|
267
277
|
|
|
268
|
-
reset
|
|
269
|
-
const resetState: Partial<GridLoaderStates<T>> = {
|
|
270
|
-
autoLoad: true,
|
|
271
|
-
lastLoadedItems: undefined,
|
|
272
|
-
loadedItems: 0,
|
|
273
|
-
currentPage: 0,
|
|
274
|
-
hasNextPage: true,
|
|
275
|
-
isNextPageLoading: false,
|
|
276
|
-
...add
|
|
277
|
-
};
|
|
278
|
-
Object.assign(state, resetState);
|
|
279
|
-
|
|
280
|
-
// Reset
|
|
281
|
-
if (state.isMounted !== false) setRows([]);
|
|
282
|
-
},
|
|
278
|
+
reset,
|
|
283
279
|
|
|
284
280
|
scrollTo(scrollOffset: number): void {
|
|
285
281
|
refMethods.scrollTo(scrollOffset);
|
|
@@ -295,36 +291,8 @@ export const ScrollerList = <
|
|
|
295
291
|
|
|
296
292
|
// When layout ready
|
|
297
293
|
React.useEffect(() => {
|
|
298
|
-
let ticking = false;
|
|
299
|
-
let lastKnownScrollPosition = 0;
|
|
300
|
-
let requestAnimationFrameSeed = 0;
|
|
301
|
-
|
|
302
|
-
// Window scroll handler
|
|
303
|
-
const handleWindowScroll = () => {
|
|
304
|
-
lastKnownScrollPosition = window.scrollY;
|
|
305
|
-
|
|
306
|
-
if (!ticking) {
|
|
307
|
-
requestAnimationFrameSeed = window.requestAnimationFrame(() => {
|
|
308
|
-
updateScroll(lastKnownScrollPosition);
|
|
309
|
-
ticking = false;
|
|
310
|
-
requestAnimationFrameSeed = 0;
|
|
311
|
-
});
|
|
312
|
-
ticking = true;
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
// Add scroll event
|
|
317
|
-
window.addEventListener('scroll', handleWindowScroll);
|
|
318
|
-
|
|
319
294
|
// Return clear function
|
|
320
295
|
return () => {
|
|
321
|
-
// Cancel animation frame
|
|
322
|
-
if (requestAnimationFrameSeed > 0)
|
|
323
|
-
window.cancelAnimationFrame(requestAnimationFrameSeed);
|
|
324
|
-
|
|
325
|
-
// Remove scroll event
|
|
326
|
-
window.removeEventListener('scroll', handleWindowScroll);
|
|
327
|
-
|
|
328
296
|
state.isMounted = false;
|
|
329
297
|
};
|
|
330
298
|
}, []);
|
|
@@ -349,7 +317,12 @@ export const ScrollerList = <
|
|
|
349
317
|
const itemCount = state.hasNextPage ? rowCount + 1 : rowCount;
|
|
350
318
|
|
|
351
319
|
// Auto load data when current page is 0
|
|
352
|
-
if (state.currentPage === 0 && state.autoLoad)
|
|
320
|
+
if (state.currentPage === 0 && state.autoLoad) {
|
|
321
|
+
const initItems =
|
|
322
|
+
onInitLoad == null ? undefined : onInitLoad(listRef.current);
|
|
323
|
+
if (initItems) reset(initItems[1], initItems[0]);
|
|
324
|
+
else loadDataLocal();
|
|
325
|
+
}
|
|
353
326
|
|
|
354
327
|
// Layout
|
|
355
328
|
return typeof itemSize === 'function' ? (
|