@etsoo/react 1.4.20 → 1.4.21
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 +6 -2
- package/lib/components/ScrollerGrid.d.ts +1 -1
- package/lib/components/ScrollerGrid.js +48 -43
- package/lib/components/ScrollerList.js +30 -32
- package/lib/mu/DataGridEx.d.ts +1 -1
- package/lib/mu/DataGridEx.js +23 -49
- package/lib/mu/DataGridRenderers.d.ts +1 -1
- package/lib/mu/DataGridRenderers.js +4 -4
- package/lib/mu/GridMethodRef.d.ts +2 -1
- package/lib/mu/ResponsibleContainer.d.ts +12 -0
- package/lib/mu/ResponsibleContainer.js +77 -30
- package/lib/mu/ScrollerListEx.js +1 -2
- package/lib/mu/TableEx.js +27 -25
- package/lib/uses/useDimensions.js +0 -8
- package/package.json +1 -1
- package/src/components/GridLoader.ts +7 -2
- package/src/components/ScrollerGrid.tsx +66 -63
- package/src/components/ScrollerList.tsx +44 -48
- package/src/mu/DataGridEx.tsx +51 -91
- package/src/mu/DataGridRenderers.tsx +7 -8
- package/src/mu/GridMethodRef.ts +3 -1
- package/src/mu/ResponsibleContainer.tsx +117 -36
- package/src/mu/ScrollerListEx.tsx +1 -2
- package/src/mu/TableEx.tsx +40 -46
- package/src/uses/useDimensions.ts +0 -11
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
import { Box, Stack } from '@mui/material';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { Labels } from '../app/Labels';
|
|
3
4
|
import { GridDataGet } from '../components/GridLoader';
|
|
4
5
|
import useCombinedRefs from '../uses/useCombinedRefs';
|
|
5
6
|
import { useDimensions } from '../uses/useDimensions';
|
|
6
7
|
import { DataGridEx, DataGridExCalColumns } from './DataGridEx';
|
|
8
|
+
import { PullToRefreshUI } from './PullToRefreshUI';
|
|
7
9
|
import { ScrollerListEx } from './ScrollerListEx';
|
|
8
10
|
import { SearchBar } from './SearchBar';
|
|
11
|
+
/**
|
|
12
|
+
* Responsible container
|
|
13
|
+
* @param props Props
|
|
14
|
+
* @returns Layout
|
|
15
|
+
*/
|
|
9
16
|
export function ResponsibleContainer(props) {
|
|
10
17
|
// Destruct
|
|
11
|
-
const { adjustHeight, columns, dataGridMinWidth = DataGridExCalColumns(columns).total, fields, fieldTemplate, height, listBoxSx, loadData, mRef, searchBoxSx, sizeReadyMiliseconds = 0, ...rest } = props;
|
|
18
|
+
const { adjustHeight, columns, dataGridMinWidth = DataGridExCalColumns(columns).total, fields, fieldTemplate, height, listBoxSx, loadData, mRef, pullToRefresh = true, searchBoxSx, sizeReadyMiliseconds = 0, ...rest } = props;
|
|
19
|
+
// Labels
|
|
20
|
+
const labels = Labels.CommonPage;
|
|
12
21
|
// Refs
|
|
13
22
|
const refs = React.useRef({});
|
|
14
23
|
const mRefs = useCombinedRefs(mRef, (ref) => {
|
|
@@ -16,20 +25,55 @@ export function ResponsibleContainer(props) {
|
|
|
16
25
|
return;
|
|
17
26
|
refs.current.ref = ref;
|
|
18
27
|
});
|
|
28
|
+
// Update mounted state
|
|
29
|
+
React.useEffect(() => {
|
|
30
|
+
return () => {
|
|
31
|
+
refs.current.mounted = false;
|
|
32
|
+
};
|
|
33
|
+
}, []);
|
|
19
34
|
// Has fields
|
|
20
35
|
const hasFields = fields != null && fields.length > 0;
|
|
21
|
-
//
|
|
22
|
-
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
|
|
23
|
-
const rect = dimensions[0][2];
|
|
36
|
+
// Load data
|
|
24
37
|
const localLoadData = (props) => {
|
|
38
|
+
refs.current.mounted = true;
|
|
25
39
|
const data = GridDataGet(props, fieldTemplate);
|
|
26
40
|
return loadData(data);
|
|
27
41
|
};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (rect == null)
|
|
42
|
+
// On submit callback
|
|
43
|
+
const onSubmit = (data, _reset) => {
|
|
44
|
+
if (data == null || rect == null || refs.current.ref == null)
|
|
31
45
|
return;
|
|
32
|
-
|
|
46
|
+
refs.current.ref.reset({ data });
|
|
47
|
+
};
|
|
48
|
+
// Watch container
|
|
49
|
+
const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds, (_preRect, rect) => {
|
|
50
|
+
// Check
|
|
51
|
+
if (rect == null)
|
|
52
|
+
return true;
|
|
53
|
+
// Last rect
|
|
54
|
+
const lastRect = refs.current.rect;
|
|
55
|
+
// 32 = scroll bar width
|
|
56
|
+
if (lastRect != null &&
|
|
57
|
+
refs.current.mounted !== true &&
|
|
58
|
+
Math.abs(rect.width - lastRect.width) <= 32 &&
|
|
59
|
+
Math.abs(rect.height - lastRect.height) <= 32)
|
|
60
|
+
return true;
|
|
61
|
+
// Hold the new rect
|
|
62
|
+
refs.current.rect = rect;
|
|
63
|
+
return false;
|
|
64
|
+
});
|
|
65
|
+
// Rect
|
|
66
|
+
const rect = dimensions[0][2];
|
|
67
|
+
// Create list
|
|
68
|
+
const [list, showDataGrid] = (() => {
|
|
69
|
+
// No layout
|
|
70
|
+
if (rect == null)
|
|
71
|
+
return [null, false];
|
|
72
|
+
// Width
|
|
73
|
+
const width = rect.width;
|
|
74
|
+
// Show DataGrid or List dependng on width
|
|
75
|
+
const showDataGrid = width >= dataGridMinWidth;
|
|
76
|
+
// Height
|
|
33
77
|
let heightLocal;
|
|
34
78
|
if (height != null) {
|
|
35
79
|
heightLocal = height;
|
|
@@ -46,18 +90,14 @@ export function ResponsibleContainer(props) {
|
|
|
46
90
|
heightLocal -= adjustHeight(heightLocal);
|
|
47
91
|
}
|
|
48
92
|
}
|
|
49
|
-
console.log(rect, heightLocal, refs.current.height);
|
|
50
|
-
// Same height
|
|
51
|
-
if (heightLocal === refs.current.height)
|
|
52
|
-
return;
|
|
53
|
-
refs.current.height = heightLocal;
|
|
54
|
-
// Show DataGrid or List dependng on width
|
|
55
|
-
const showDataGrid = rect.width >= dataGridMinWidth;
|
|
56
93
|
if (showDataGrid) {
|
|
57
94
|
// Delete
|
|
58
95
|
delete rest.itemRenderer;
|
|
59
|
-
return
|
|
60
|
-
React.createElement(
|
|
96
|
+
return [
|
|
97
|
+
React.createElement(Box, { sx: listBoxSx == null ? undefined : listBoxSx(true) },
|
|
98
|
+
React.createElement(DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, columns: columns, ...rest })),
|
|
99
|
+
true
|
|
100
|
+
];
|
|
61
101
|
}
|
|
62
102
|
// Delete
|
|
63
103
|
delete rest.checkable;
|
|
@@ -68,18 +108,25 @@ export function ResponsibleContainer(props) {
|
|
|
68
108
|
delete rest.hideFooter;
|
|
69
109
|
delete rest.hoverColor;
|
|
70
110
|
delete rest.selectable;
|
|
71
|
-
return
|
|
72
|
-
React.createElement(
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
111
|
+
return [
|
|
112
|
+
React.createElement(Box, { sx: listBoxSx == null ? undefined : listBoxSx(false) },
|
|
113
|
+
React.createElement(ScrollerListEx, { autoLoad: !hasFields, width: rect.width, height: heightLocal, loadData: localLoadData, mRef: mRefs, ...rest })),
|
|
114
|
+
false
|
|
115
|
+
];
|
|
116
|
+
})();
|
|
117
|
+
// Pull container
|
|
118
|
+
const pullContainer = list
|
|
119
|
+
? showDataGrid
|
|
120
|
+
? '.DataGridEx-Body'
|
|
121
|
+
: '.ScrollerListEx-Body'
|
|
122
|
+
: undefined;
|
|
80
123
|
// Layout
|
|
81
|
-
return (React.createElement(
|
|
82
|
-
|
|
83
|
-
React.createElement(SearchBar, { fields: fields, onSubmit: onSubmit }))),
|
|
84
|
-
|
|
124
|
+
return (React.createElement(React.Fragment, null,
|
|
125
|
+
React.createElement(Stack, null,
|
|
126
|
+
React.createElement(Box, { ref: dimensions[0][0], sx: searchBoxSx }, hasFields && (React.createElement(SearchBar, { fields: fields, onSubmit: onSubmit }))),
|
|
127
|
+
list),
|
|
128
|
+
pullToRefresh && pullContainer && (React.createElement(PullToRefreshUI, { mainElement: pullContainer, triggerElement: pullContainer, instructionsPullToRefresh: labels.pullToRefresh, instructionsReleaseToRefresh: labels.releaseToRefresh, instructionsRefreshing: labels.refreshing, onRefresh: () => { var _a; return (_a = refs.current.ref) === null || _a === void 0 ? void 0 : _a.reset(); }, shouldPullToRefresh: () => {
|
|
129
|
+
const container = document.querySelector(pullContainer);
|
|
130
|
+
return !(container === null || container === void 0 ? void 0 : container.scrollTop);
|
|
131
|
+
} }))));
|
|
85
132
|
}
|
package/lib/mu/ScrollerListEx.js
CHANGED
|
@@ -66,8 +66,7 @@ export function ScrollerListEx(props) {
|
|
|
66
66
|
const [selectedDiv, selectedData] = (_a = selectedItem.current) !== null && _a !== void 0 ? _a : [];
|
|
67
67
|
if (selectedData != null && selectedData[idField] === data[idField])
|
|
68
68
|
return;
|
|
69
|
-
|
|
70
|
-
selectedDiv.classList.remove(selectedClassName);
|
|
69
|
+
selectedDiv === null || selectedDiv === void 0 ? void 0 : selectedDiv.classList.remove(selectedClassName);
|
|
71
70
|
div.classList.add(selectedClassName);
|
|
72
71
|
selectedItem.current = [div, data];
|
|
73
72
|
if (onSelectChange)
|
package/lib/mu/TableEx.js
CHANGED
|
@@ -34,35 +34,39 @@ export function TableEx(props) {
|
|
|
34
34
|
else {
|
|
35
35
|
rowsPerPageLocal = 10;
|
|
36
36
|
}
|
|
37
|
+
// Rows
|
|
38
|
+
const [rows, updateRows] = React.useState([]);
|
|
39
|
+
const setRows = (rows) => {
|
|
40
|
+
state.loadedItems = rows.length;
|
|
41
|
+
updateRows(rows);
|
|
42
|
+
};
|
|
37
43
|
// States
|
|
38
|
-
const
|
|
39
|
-
return { ...currentState, ...newState };
|
|
40
|
-
}, {
|
|
44
|
+
const stateRefs = React.useRef({
|
|
41
45
|
autoLoad,
|
|
42
46
|
currentPage: 0,
|
|
47
|
+
loadedItems: 0,
|
|
43
48
|
hasNextPage: true,
|
|
44
49
|
isNextPageLoading: false,
|
|
45
50
|
orderBy: defaultOrderBy,
|
|
46
51
|
orderByAsc: defaultOrderBy
|
|
47
52
|
? (_a = columns.find((column) => column.field === defaultOrderBy)) === null || _a === void 0 ? void 0 : _a.sortAsc
|
|
48
53
|
: undefined,
|
|
49
|
-
rows: [],
|
|
50
54
|
batchSize: rowsPerPageLocal,
|
|
51
55
|
selectedItems: []
|
|
52
56
|
});
|
|
53
|
-
const
|
|
57
|
+
const state = stateRefs.current;
|
|
54
58
|
// Reset the state and load again
|
|
55
59
|
const reset = (add) => {
|
|
56
|
-
const
|
|
60
|
+
const resetState = {
|
|
57
61
|
autoLoad: true,
|
|
58
62
|
currentPage: 0,
|
|
63
|
+
loadedItems: 0,
|
|
59
64
|
hasNextPage: true,
|
|
60
65
|
isNextPageLoading: false,
|
|
61
66
|
lastLoadedItems: undefined,
|
|
62
|
-
rows: [],
|
|
63
67
|
...add
|
|
64
68
|
};
|
|
65
|
-
|
|
69
|
+
Object.assign(state, resetState);
|
|
66
70
|
};
|
|
67
71
|
React.useImperativeHandle(mRef, () => ({
|
|
68
72
|
/**
|
|
@@ -84,7 +88,7 @@ export function TableEx(props) {
|
|
|
84
88
|
// Update state
|
|
85
89
|
state.isNextPageLoading = true;
|
|
86
90
|
// Parameters
|
|
87
|
-
const { currentPage, batchSize, orderBy, orderByAsc, data } = state;
|
|
91
|
+
const { currentPage, batchSize, orderBy, orderByAsc, data, isMounted } = state;
|
|
88
92
|
const loadProps = {
|
|
89
93
|
currentPage,
|
|
90
94
|
batchSize,
|
|
@@ -93,16 +97,16 @@ export function TableEx(props) {
|
|
|
93
97
|
data
|
|
94
98
|
};
|
|
95
99
|
loadData(loadProps).then((result) => {
|
|
96
|
-
|
|
100
|
+
state.isMounted = true;
|
|
101
|
+
if (result == null || isMounted === false) {
|
|
97
102
|
return;
|
|
98
103
|
}
|
|
99
104
|
const newItems = result.length;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
});
|
|
105
|
+
state.lastLoadedItems = newItems;
|
|
106
|
+
state.hasNextPage = newItems >= batchSize;
|
|
107
|
+
state.isNextPageLoading = false;
|
|
108
|
+
// Update rows
|
|
109
|
+
setRows(result);
|
|
106
110
|
});
|
|
107
111
|
};
|
|
108
112
|
const handleChangePage = (_event, newPage) => {
|
|
@@ -111,11 +115,11 @@ export function TableEx(props) {
|
|
|
111
115
|
loadDataLocal();
|
|
112
116
|
};
|
|
113
117
|
const handleChangeRowsPerPage = (event) => {
|
|
114
|
-
const
|
|
115
|
-
reset({
|
|
118
|
+
const batchSize = parseInt(event.target.value);
|
|
119
|
+
reset({ batchSize });
|
|
116
120
|
};
|
|
117
121
|
const handleSelect = (item, checked) => {
|
|
118
|
-
const selectedItems =
|
|
122
|
+
const selectedItems = state.selectedItems;
|
|
119
123
|
const index = selectedItems.findIndex((selectedItem) => selectedItem[idField] === item[idField]);
|
|
120
124
|
if (checked) {
|
|
121
125
|
if (index === -1)
|
|
@@ -128,11 +132,10 @@ export function TableEx(props) {
|
|
|
128
132
|
if (onSelectChange != null) {
|
|
129
133
|
onSelectChange(selectedItems);
|
|
130
134
|
}
|
|
131
|
-
stateUpdate({ selectedItems });
|
|
132
135
|
};
|
|
133
136
|
const handleSelectAll = (checked) => {
|
|
134
|
-
const selectedItems =
|
|
135
|
-
|
|
137
|
+
const selectedItems = state.selectedItems;
|
|
138
|
+
rows.forEach((row) => {
|
|
136
139
|
const index = selectedItems.findIndex((selectedItem) => selectedItem[idField] === row[idField]);
|
|
137
140
|
if (checked) {
|
|
138
141
|
if (index === -1)
|
|
@@ -145,14 +148,13 @@ export function TableEx(props) {
|
|
|
145
148
|
if (onSelectChange != null) {
|
|
146
149
|
onSelectChange(selectedItems);
|
|
147
150
|
}
|
|
148
|
-
stateUpdate({ selectedItems });
|
|
149
151
|
};
|
|
150
152
|
// New sort
|
|
151
153
|
const handleSort = (field, asc) => {
|
|
152
154
|
reset({ orderBy: field, orderByAsc: asc });
|
|
153
155
|
};
|
|
154
156
|
// Destruct states
|
|
155
|
-
const { autoLoad: stateAutoLoad, currentPage, hasNextPage, lastLoadedItems, orderBy,
|
|
157
|
+
const { autoLoad: stateAutoLoad, currentPage, hasNextPage, lastLoadedItems, orderBy, batchSize, selectedItems } = state;
|
|
156
158
|
// Current page selected items
|
|
157
159
|
const pageSelectedItems = selectable
|
|
158
160
|
? rows.reduce((previousValue, currentItem) => {
|
|
@@ -170,7 +172,7 @@ export function TableEx(props) {
|
|
|
170
172
|
loadDataLocal();
|
|
171
173
|
React.useEffect(() => {
|
|
172
174
|
return () => {
|
|
173
|
-
isMounted
|
|
175
|
+
state.isMounted = false;
|
|
174
176
|
};
|
|
175
177
|
}, []);
|
|
176
178
|
// Layout
|
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import { DomUtils } from '@etsoo/shared';
|
|
2
2
|
import React from 'react';
|
|
3
|
-
const createRef = (source, index) => {
|
|
4
|
-
return [
|
|
5
|
-
(instance) => {
|
|
6
|
-
if (instance != null)
|
|
7
|
-
source[index][1] = instance;
|
|
8
|
-
}
|
|
9
|
-
];
|
|
10
|
-
};
|
|
11
3
|
/**
|
|
12
4
|
* Calculate element(s) dimensions
|
|
13
5
|
* @param elements Observed elments count
|
package/package.json
CHANGED
|
@@ -126,6 +126,11 @@ export interface GridLoaderStates<T> extends GridLoadDataProps {
|
|
|
126
126
|
*/
|
|
127
127
|
lastLoadedItems?: number;
|
|
128
128
|
|
|
129
|
+
/**
|
|
130
|
+
* All loaded items count
|
|
131
|
+
*/
|
|
132
|
+
loadedItems: number;
|
|
133
|
+
|
|
129
134
|
/**
|
|
130
135
|
* Has next page?
|
|
131
136
|
*/
|
|
@@ -137,9 +142,9 @@ export interface GridLoaderStates<T> extends GridLoadDataProps {
|
|
|
137
142
|
isNextPageLoading: boolean;
|
|
138
143
|
|
|
139
144
|
/**
|
|
140
|
-
*
|
|
145
|
+
* Is mounted
|
|
141
146
|
*/
|
|
142
|
-
|
|
147
|
+
isMounted?: boolean;
|
|
143
148
|
|
|
144
149
|
/**
|
|
145
150
|
* Selected items of id
|
|
@@ -40,7 +40,10 @@ export interface ScrollerGridProps<T>
|
|
|
40
40
|
/**
|
|
41
41
|
* Footer renderer
|
|
42
42
|
*/
|
|
43
|
-
footerRenderer?: (
|
|
43
|
+
footerRenderer?: (
|
|
44
|
+
rows: T[],
|
|
45
|
+
states: GridLoaderStates<T>
|
|
46
|
+
) => React.ReactNode;
|
|
44
47
|
|
|
45
48
|
/**
|
|
46
49
|
* Header renderer
|
|
@@ -163,29 +166,28 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
163
166
|
...rest
|
|
164
167
|
} = props;
|
|
165
168
|
|
|
166
|
-
//
|
|
167
|
-
const [
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return { ...currentState, ...newState };
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
autoLoad,
|
|
176
|
-
currentPage: 0,
|
|
177
|
-
hasNextPage: true,
|
|
178
|
-
isNextPageLoading: false,
|
|
179
|
-
orderBy: defaultOrderBy,
|
|
180
|
-
orderByAsc: defaultOrderByAsc,
|
|
181
|
-
rows: [],
|
|
182
|
-
batchSize: 10,
|
|
183
|
-
selectedItems: []
|
|
184
|
-
}
|
|
185
|
-
);
|
|
186
|
-
const isMounted = React.useRef(true);
|
|
169
|
+
// Rows
|
|
170
|
+
const [rows, updateRows] = React.useState<T[]>([]);
|
|
171
|
+
const setRows = (rows: T[]) => {
|
|
172
|
+
state.loadedItems = rows.length;
|
|
173
|
+
updateRows(rows);
|
|
174
|
+
};
|
|
187
175
|
|
|
188
|
-
|
|
176
|
+
// Refs
|
|
177
|
+
const refs = React.useRef<GridLoaderStates<T>>({
|
|
178
|
+
autoLoad,
|
|
179
|
+
currentPage: 0,
|
|
180
|
+
hasNextPage: true,
|
|
181
|
+
isNextPageLoading: false,
|
|
182
|
+
orderBy: defaultOrderBy,
|
|
183
|
+
orderByAsc: defaultOrderByAsc,
|
|
184
|
+
batchSize: 10,
|
|
185
|
+
loadedItems: 0,
|
|
186
|
+
selectedItems: []
|
|
187
|
+
});
|
|
188
|
+
const state = refs.current;
|
|
189
|
+
|
|
190
|
+
const ref = React.useRef<VariableSizeGrid<T>>(null);
|
|
189
191
|
|
|
190
192
|
// Load data
|
|
191
193
|
const loadDataLocal = (pageAdd: number = 1) => {
|
|
@@ -194,10 +196,10 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
194
196
|
|
|
195
197
|
// Update state
|
|
196
198
|
state.isNextPageLoading = true;
|
|
197
|
-
// stateUpdate({ isNextPageLoading: true });
|
|
198
199
|
|
|
199
200
|
// Parameters
|
|
200
|
-
const { currentPage, batchSize, orderBy, orderByAsc, data } =
|
|
201
|
+
const { currentPage, batchSize, orderBy, orderByAsc, data, isMounted } =
|
|
202
|
+
state;
|
|
201
203
|
|
|
202
204
|
const loadProps: GridLoadDataProps = {
|
|
203
205
|
currentPage,
|
|
@@ -208,38 +210,36 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
208
210
|
};
|
|
209
211
|
|
|
210
212
|
loadData(loadProps).then((result) => {
|
|
211
|
-
|
|
213
|
+
state.isMounted = true;
|
|
214
|
+
|
|
215
|
+
if (result == null || isMounted === false) {
|
|
212
216
|
return;
|
|
213
217
|
}
|
|
214
218
|
|
|
215
219
|
const newItems = result.length;
|
|
220
|
+
state.lastLoadedItems = newItems;
|
|
221
|
+
state.isNextPageLoading = false;
|
|
222
|
+
state.hasNextPage = newItems >= batchSize;
|
|
216
223
|
|
|
217
224
|
if (pageAdd === 0) {
|
|
218
225
|
// New items
|
|
219
|
-
const
|
|
220
|
-
?
|
|
226
|
+
const newRows = state.lastLoadedItems
|
|
227
|
+
? [...rows]
|
|
221
228
|
.splice(
|
|
222
|
-
|
|
229
|
+
rows.length - state.lastLoadedItems,
|
|
223
230
|
state.lastLoadedItems
|
|
224
231
|
)
|
|
225
232
|
.concat(result)
|
|
226
233
|
: result;
|
|
227
234
|
|
|
228
|
-
//
|
|
229
|
-
|
|
230
|
-
rows,
|
|
231
|
-
lastLoadedItems: newItems,
|
|
232
|
-
isNextPageLoading: false,
|
|
233
|
-
hasNextPage: newItems >= batchSize
|
|
234
|
-
});
|
|
235
|
+
// Update rows
|
|
236
|
+
setRows(newRows);
|
|
235
237
|
} else {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
hasNextPage: newItems >= batchSize
|
|
242
|
-
});
|
|
238
|
+
// Set current page
|
|
239
|
+
state.currentPage = state.currentPage + pageAdd;
|
|
240
|
+
|
|
241
|
+
// Update rows
|
|
242
|
+
setRows([...rows, ...result]);
|
|
243
243
|
}
|
|
244
244
|
});
|
|
245
245
|
};
|
|
@@ -251,8 +251,8 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
251
251
|
) => {
|
|
252
252
|
// Custom render
|
|
253
253
|
const data =
|
|
254
|
-
itemProps.rowIndex <
|
|
255
|
-
?
|
|
254
|
+
itemProps.rowIndex < rows.length
|
|
255
|
+
? rows[itemProps.rowIndex]
|
|
256
256
|
: undefined;
|
|
257
257
|
return itemRenderer({
|
|
258
258
|
...itemProps,
|
|
@@ -264,7 +264,7 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
264
264
|
// Local items renderer callback
|
|
265
265
|
const onItemsRenderedLocal = (props: GridOnItemsRenderedProps) => {
|
|
266
266
|
// No items, means no necessary to load more data during reset
|
|
267
|
-
const itemCount =
|
|
267
|
+
const itemCount = rows.length;
|
|
268
268
|
if (
|
|
269
269
|
itemCount > 0 &&
|
|
270
270
|
props.visibleRowStopIndex + threshold > itemCount
|
|
@@ -278,17 +278,17 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
278
278
|
};
|
|
279
279
|
|
|
280
280
|
// Reset the state and load again
|
|
281
|
-
const reset = (add?:
|
|
282
|
-
const
|
|
281
|
+
const reset = (add?: Partial<GridLoaderStates<T>>) => {
|
|
282
|
+
const resetState: Partial<GridLoaderStates<T>> = {
|
|
283
283
|
autoLoad: true,
|
|
284
284
|
currentPage: 0,
|
|
285
|
+
loadedItems: 0,
|
|
285
286
|
hasNextPage: true,
|
|
286
287
|
isNextPageLoading: false,
|
|
287
288
|
lastLoadedItems: undefined,
|
|
288
|
-
rows: [],
|
|
289
289
|
...add
|
|
290
290
|
};
|
|
291
|
-
|
|
291
|
+
Object.assign(state, resetState);
|
|
292
292
|
};
|
|
293
293
|
|
|
294
294
|
React.useImperativeHandle(
|
|
@@ -307,16 +307,14 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
307
307
|
select(rowIndex: number) {
|
|
308
308
|
// Select only one item
|
|
309
309
|
const selectedItems = state.selectedItems;
|
|
310
|
-
selectedItems[0] =
|
|
310
|
+
selectedItems[0] = rows[rowIndex];
|
|
311
311
|
|
|
312
312
|
if (onSelectChange) onSelectChange(selectedItems);
|
|
313
|
-
|
|
314
|
-
stateUpdate({ selectedItems });
|
|
315
313
|
},
|
|
316
314
|
selectAll(checked: boolean) {
|
|
317
315
|
const selectedItems = state.selectedItems;
|
|
318
316
|
|
|
319
|
-
|
|
317
|
+
rows.forEach((row) => {
|
|
320
318
|
const index = selectedItems.findIndex(
|
|
321
319
|
(selectedItem) => selectedItem[idField] === row[idField]
|
|
322
320
|
);
|
|
@@ -329,8 +327,6 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
329
327
|
});
|
|
330
328
|
|
|
331
329
|
if (onSelectChange) onSelectChange(selectedItems);
|
|
332
|
-
|
|
333
|
-
stateUpdate({ selectedItems });
|
|
334
330
|
},
|
|
335
331
|
selectItem(item: T, checked: boolean) {
|
|
336
332
|
const selectedItems = state.selectedItems;
|
|
@@ -345,8 +341,6 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
345
341
|
}
|
|
346
342
|
|
|
347
343
|
if (onSelectChange) onSelectChange(selectedItems);
|
|
348
|
-
|
|
349
|
-
stateUpdate({ selectedItems });
|
|
350
344
|
},
|
|
351
345
|
reset,
|
|
352
346
|
resetAfterColumnIndex(index: number, shouldForceUpdate?: boolean) {
|
|
@@ -363,17 +357,26 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
363
357
|
ref.current?.resetAfterRowIndex(index, shouldForceUpdate);
|
|
364
358
|
}
|
|
365
359
|
}),
|
|
366
|
-
[
|
|
360
|
+
[rows]
|
|
367
361
|
);
|
|
368
362
|
|
|
369
363
|
React.useEffect(() => {
|
|
370
364
|
return () => {
|
|
371
|
-
isMounted
|
|
365
|
+
state.isMounted = false;
|
|
372
366
|
};
|
|
373
367
|
}, []);
|
|
374
368
|
|
|
369
|
+
// Force update to work with the new width
|
|
370
|
+
React.useEffect(() => {
|
|
371
|
+
ref.current?.resetAfterIndices({
|
|
372
|
+
columnIndex: 0,
|
|
373
|
+
rowIndex: 0,
|
|
374
|
+
shouldForceUpdate: true
|
|
375
|
+
});
|
|
376
|
+
}, [width]);
|
|
377
|
+
|
|
375
378
|
// Destruct state
|
|
376
|
-
const { autoLoad: stateAutoLoad,
|
|
379
|
+
const { autoLoad: stateAutoLoad, hasNextPage, currentPage } = state;
|
|
377
380
|
const rowLength = rows.length;
|
|
378
381
|
|
|
379
382
|
// Row count
|
|
@@ -388,7 +391,7 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
388
391
|
{headerRenderer && headerRenderer(state)}
|
|
389
392
|
<VariableSizeGrid<T>
|
|
390
393
|
itemKey={({ columnIndex, rowIndex }) => {
|
|
391
|
-
const data =
|
|
394
|
+
const data = rows[rowIndex];
|
|
392
395
|
if (data == null) return [rowIndex, columnIndex].join(',');
|
|
393
396
|
return [data[idField], columnIndex].join(',');
|
|
394
397
|
}}
|
|
@@ -406,7 +409,7 @@ export const ScrollerGrid = <T extends Record<string, unknown>>(
|
|
|
406
409
|
>
|
|
407
410
|
{(props) => itemRendererLocal(props, state)}
|
|
408
411
|
</VariableSizeGrid>
|
|
409
|
-
{footerRenderer && footerRenderer(state)}
|
|
412
|
+
{footerRenderer && footerRenderer(rows, state)}
|
|
410
413
|
</React.Fragment>
|
|
411
414
|
);
|
|
412
415
|
};
|