@etsoo/materialui 1.2.41 → 1.2.42
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.
|
@@ -8,7 +8,7 @@ import { ScrollerListExInnerItemRendererProps, ScrollerListExItemSize } from "./
|
|
|
8
8
|
/**
|
|
9
9
|
* ResponsibleContainer props
|
|
10
10
|
*/
|
|
11
|
-
export type ResponsibleContainerProps<T extends object, F extends DataTypes.BasicTemplate = DataTypes.BasicTemplate, D extends DataTypes.Keys<T> = IdDefaultType<T>> = Omit<DataGridExProps<T, D>, "height" | "itemKey" | "loadData" | "mRef" | "onScroll" | "onItemsRendered"> & {
|
|
11
|
+
export type ResponsibleContainerProps<T extends object, F extends DataTypes.BasicTemplate = DataTypes.BasicTemplate, D extends DataTypes.Keys<T> = IdDefaultType<T>> = Omit<DataGridExProps<T, D>, "height" | "itemKey" | "loadData" | "mRef" | "onScroll" | "onItemsRendered" | "onInitLoad" | "onUpdateRows"> & {
|
|
12
12
|
/**
|
|
13
13
|
* Height will be deducted
|
|
14
14
|
* @param height Current calcuated height
|
|
@@ -22,6 +22,14 @@ export type ResponsibleContainerProps<T extends object, F extends DataTypes.Basi
|
|
|
22
22
|
* @returns Adjusted height
|
|
23
23
|
*/
|
|
24
24
|
adjustFabHeight?: (height: number, isGrid: boolean) => number;
|
|
25
|
+
/**
|
|
26
|
+
* Cache key
|
|
27
|
+
*/
|
|
28
|
+
cacheKey?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Cache minutes
|
|
31
|
+
*/
|
|
32
|
+
cacheMinutes?: number;
|
|
25
33
|
/**
|
|
26
34
|
* Columns
|
|
27
35
|
*/
|
|
@@ -37,7 +45,7 @@ export type ResponsibleContainerProps<T extends object, F extends DataTypes.Basi
|
|
|
37
45
|
/**
|
|
38
46
|
* Search fields
|
|
39
47
|
*/
|
|
40
|
-
fields?: React.ReactElement[];
|
|
48
|
+
fields?: React.ReactElement[] | ((data: DataTypes.BasicTemplateType<F>) => React.ReactElement[]);
|
|
41
49
|
/**
|
|
42
50
|
* Search field template
|
|
43
51
|
*/
|
|
@@ -22,7 +22,7 @@ function defaultContainerBoxSx(paddings, hasField, _dataGrid) {
|
|
|
22
22
|
*/
|
|
23
23
|
export function ResponsibleContainer(props) {
|
|
24
24
|
// Destruct
|
|
25
|
-
const { adjustHeight, adjustFabHeight, columns, containerBoxSx = defaultContainerBoxSx, dataGridMinWidth = Math.max(576, DataGridExCalColumns(columns).total), elementReady, fields, fieldTemplate, height, loadData, mRef, paddings = MUGlobal.pagePaddings, pullToRefresh = true, quickAction, sizeReadyMiliseconds = 0, searchBarHeight = 45.6, ...rest } = props;
|
|
25
|
+
const { adjustHeight, adjustFabHeight, cacheKey, cacheMinutes = 120, columns, containerBoxSx = defaultContainerBoxSx, dataGridMinWidth = Math.max(576, DataGridExCalColumns(columns).total), elementReady, fields, fieldTemplate, height, loadData, mRef, paddings = MUGlobal.pagePaddings, pullToRefresh = true, quickAction, sizeReadyMiliseconds = 0, searchBarHeight = 45.6, ...rest } = props;
|
|
26
26
|
// Labels
|
|
27
27
|
const labels = Labels.CommonPage;
|
|
28
28
|
// Refs
|
|
@@ -45,6 +45,8 @@ export function ResponsibleContainer(props) {
|
|
|
45
45
|
const localLoadData = (props) => {
|
|
46
46
|
state.mounted = true;
|
|
47
47
|
const data = GridDataGet(props, fieldTemplate);
|
|
48
|
+
if (cacheKey)
|
|
49
|
+
sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
|
|
48
50
|
return loadData(data);
|
|
49
51
|
};
|
|
50
52
|
// On submit callback
|
|
@@ -70,6 +72,54 @@ export function ResponsibleContainer(props) {
|
|
|
70
72
|
state.rect = rect;
|
|
71
73
|
return false;
|
|
72
74
|
});
|
|
75
|
+
const onUpdateRows = (rows, state) => {
|
|
76
|
+
if (state.currentPage > 0 && cacheKey) {
|
|
77
|
+
const data = { rows, state, creation: new Date().valueOf() };
|
|
78
|
+
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const onInitLoad = (ref) => {
|
|
82
|
+
// Avoid repeatedly load from cache
|
|
83
|
+
if (refs.current.initLoaded || !cacheKey)
|
|
84
|
+
return undefined;
|
|
85
|
+
// Cache data
|
|
86
|
+
const cacheData = sessionStorage.getItem(cacheKey);
|
|
87
|
+
if (cacheData) {
|
|
88
|
+
const { rows, state, creation } = JSON.parse(cacheData);
|
|
89
|
+
// 120 minutes
|
|
90
|
+
if (new Date().valueOf() - creation > cacheMinutes * 60000) {
|
|
91
|
+
sessionStorage.removeItem(cacheKey);
|
|
92
|
+
return undefined;
|
|
93
|
+
}
|
|
94
|
+
// Scroll position
|
|
95
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
96
|
+
if (scrollData) {
|
|
97
|
+
if ("resetAfterColumnIndex" in ref) {
|
|
98
|
+
const { scrollLeft, scrollTop } = JSON.parse(scrollData);
|
|
99
|
+
globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const { scrollOffset } = JSON.parse(scrollData);
|
|
103
|
+
globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Update flag value
|
|
107
|
+
refs.current.initLoaded = true;
|
|
108
|
+
// Return cached rows and state
|
|
109
|
+
return [rows, state];
|
|
110
|
+
}
|
|
111
|
+
return undefined;
|
|
112
|
+
};
|
|
113
|
+
const onListScroll = (props) => {
|
|
114
|
+
if (!cacheKey || !refs.current.initLoaded)
|
|
115
|
+
return;
|
|
116
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
117
|
+
};
|
|
118
|
+
const onGridScroll = (props) => {
|
|
119
|
+
if (!cacheKey || !refs.current.initLoaded)
|
|
120
|
+
return;
|
|
121
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
122
|
+
};
|
|
73
123
|
// Rect
|
|
74
124
|
const rect = dimensions[0][2];
|
|
75
125
|
// Create list
|
|
@@ -107,7 +157,7 @@ export function ResponsibleContainer(props) {
|
|
|
107
157
|
React.createElement(DataGridEx, { autoLoad: !hasFields, height: heightLocal, width: rect.width, loadData: localLoadData, mRef: mRefs, onDoubleClick: (_, data) => quickAction && quickAction(data), outerRef: (element) => {
|
|
108
158
|
if (element != null && elementReady)
|
|
109
159
|
elementReady(element, true);
|
|
110
|
-
}, columns: columns, ...rest })),
|
|
160
|
+
}, onScroll: onGridScroll, columns: columns, onUpdateRows: onUpdateRows, onInitLoad: onInitLoad, ...rest })),
|
|
111
161
|
true
|
|
112
162
|
];
|
|
113
163
|
}
|
|
@@ -122,17 +172,21 @@ export function ResponsibleContainer(props) {
|
|
|
122
172
|
delete rest.selectable;
|
|
123
173
|
return [
|
|
124
174
|
React.createElement(Box, { className: "ListBox", sx: { height: heightLocal } },
|
|
125
|
-
React.createElement(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, mRef: mRefs, onClick: (event, data) => quickAction && ReactUtils.isSafeClick(event) && quickAction(data), oRef: (element) => {
|
|
175
|
+
React.createElement(ScrollerListEx, { autoLoad: !hasFields, height: heightLocal, loadData: localLoadData, onUpdateRows: onUpdateRows, onInitLoad: onInitLoad, mRef: mRefs, onClick: (event, data) => quickAction && ReactUtils.isSafeClick(event) && quickAction(data), oRef: (element) => {
|
|
126
176
|
if (element != null && elementReady)
|
|
127
177
|
elementReady(element, false);
|
|
128
|
-
}, ...rest })),
|
|
178
|
+
}, onScroll: onListScroll, ...rest })),
|
|
129
179
|
false
|
|
130
180
|
];
|
|
131
181
|
})();
|
|
132
182
|
const searchBar = React.useMemo(() => {
|
|
183
|
+
var _a;
|
|
133
184
|
if (!hasFields || showDataGrid == null)
|
|
134
185
|
return;
|
|
135
|
-
|
|
186
|
+
const f = typeof fields == "function"
|
|
187
|
+
? fields(JSON.parse((_a = sessionStorage.getItem(`${cacheKey}-searchbar`)) !== null && _a !== void 0 ? _a : "{}"))
|
|
188
|
+
: fields;
|
|
189
|
+
return (React.createElement(SearchBar, { fields: f, onSubmit: onSubmit, className: `searchBar${showDataGrid ? "Grid" : "List"}` }));
|
|
136
190
|
}, [showDataGrid, hasFields, searchBarHeight]);
|
|
137
191
|
// Pull container
|
|
138
192
|
const pullContainer = showDataGrid == null
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/materialui",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.42",
|
|
4
4
|
"description": "TypeScript Material-UI Implementation",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@emotion/styled": "^11.11.0",
|
|
53
53
|
"@etsoo/appscript": "^1.4.8",
|
|
54
54
|
"@etsoo/notificationbase": "^1.1.25",
|
|
55
|
-
"@etsoo/react": "^1.6.
|
|
55
|
+
"@etsoo/react": "^1.6.84",
|
|
56
56
|
"@etsoo/shared": "^1.2.5",
|
|
57
57
|
"@mui/icons-material": "^5.11.16",
|
|
58
58
|
"@mui/material": "^5.13.0",
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
import { DataTypes, IdDefaultType } from "@etsoo/shared";
|
|
2
2
|
import { Box, Stack, SxProps, Theme } from "@mui/material";
|
|
3
3
|
import React from "react";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
GridOnScrollProps,
|
|
6
|
+
ListChildComponentProps,
|
|
7
|
+
ListOnScrollProps,
|
|
8
|
+
VariableSizeGrid
|
|
9
|
+
} from "react-window";
|
|
5
10
|
import {
|
|
6
11
|
GridColumn,
|
|
7
12
|
GridDataGet,
|
|
8
13
|
GridJsonData,
|
|
9
14
|
GridLoadDataProps,
|
|
15
|
+
GridLoaderStates,
|
|
10
16
|
GridMethodRef,
|
|
11
17
|
ReactUtils,
|
|
18
|
+
ScrollerListRef,
|
|
12
19
|
useCombinedRefs,
|
|
13
20
|
useDimensions
|
|
14
21
|
} from "@etsoo/react";
|
|
@@ -36,7 +43,14 @@ export type ResponsibleContainerProps<
|
|
|
36
43
|
D extends DataTypes.Keys<T> = IdDefaultType<T>
|
|
37
44
|
> = Omit<
|
|
38
45
|
DataGridExProps<T, D>,
|
|
39
|
-
|
|
46
|
+
| "height"
|
|
47
|
+
| "itemKey"
|
|
48
|
+
| "loadData"
|
|
49
|
+
| "mRef"
|
|
50
|
+
| "onScroll"
|
|
51
|
+
| "onItemsRendered"
|
|
52
|
+
| "onInitLoad"
|
|
53
|
+
| "onUpdateRows"
|
|
40
54
|
> & {
|
|
41
55
|
/**
|
|
42
56
|
* Height will be deducted
|
|
@@ -53,6 +67,16 @@ export type ResponsibleContainerProps<
|
|
|
53
67
|
*/
|
|
54
68
|
adjustFabHeight?: (height: number, isGrid: boolean) => number;
|
|
55
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Cache key
|
|
72
|
+
*/
|
|
73
|
+
cacheKey?: string;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Cache minutes
|
|
77
|
+
*/
|
|
78
|
+
cacheMinutes?: number;
|
|
79
|
+
|
|
56
80
|
/**
|
|
57
81
|
* Columns
|
|
58
82
|
*/
|
|
@@ -75,7 +99,9 @@ export type ResponsibleContainerProps<
|
|
|
75
99
|
/**
|
|
76
100
|
* Search fields
|
|
77
101
|
*/
|
|
78
|
-
fields?:
|
|
102
|
+
fields?:
|
|
103
|
+
| React.ReactElement[]
|
|
104
|
+
| ((data: DataTypes.BasicTemplateType<F>) => React.ReactElement[]);
|
|
79
105
|
|
|
80
106
|
/**
|
|
81
107
|
* Search field template
|
|
@@ -151,6 +177,7 @@ interface LocalRefs<T> {
|
|
|
151
177
|
rect?: DOMRect;
|
|
152
178
|
ref?: GridMethodRef<T>;
|
|
153
179
|
mounted?: boolean;
|
|
180
|
+
initLoaded?: boolean;
|
|
154
181
|
}
|
|
155
182
|
|
|
156
183
|
function defaultContainerBoxSx(
|
|
@@ -180,6 +207,8 @@ export function ResponsibleContainer<
|
|
|
180
207
|
const {
|
|
181
208
|
adjustHeight,
|
|
182
209
|
adjustFabHeight,
|
|
210
|
+
cacheKey,
|
|
211
|
+
cacheMinutes = 120,
|
|
183
212
|
columns,
|
|
184
213
|
containerBoxSx = defaultContainerBoxSx,
|
|
185
214
|
dataGridMinWidth = Math.max(576, DataGridExCalColumns(columns).total),
|
|
@@ -223,6 +252,10 @@ export function ResponsibleContainer<
|
|
|
223
252
|
const localLoadData = (props: GridLoadDataProps) => {
|
|
224
253
|
state.mounted = true;
|
|
225
254
|
const data = GridDataGet(props, fieldTemplate);
|
|
255
|
+
|
|
256
|
+
if (cacheKey)
|
|
257
|
+
sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
|
|
258
|
+
|
|
226
259
|
return loadData(data);
|
|
227
260
|
};
|
|
228
261
|
|
|
@@ -260,6 +293,70 @@ export function ResponsibleContainer<
|
|
|
260
293
|
}
|
|
261
294
|
);
|
|
262
295
|
|
|
296
|
+
type DataType = { rows: T[]; state: GridLoaderStates<T>; creation: number };
|
|
297
|
+
|
|
298
|
+
const onUpdateRows = (rows: T[], state: GridLoaderStates<T>) => {
|
|
299
|
+
if (state.currentPage > 0 && cacheKey) {
|
|
300
|
+
const data: DataType = { rows, state, creation: new Date().valueOf() };
|
|
301
|
+
sessionStorage.setItem(cacheKey, JSON.stringify(data));
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const onInitLoad = (
|
|
306
|
+
ref: VariableSizeGrid<T> | ScrollerListRef
|
|
307
|
+
): [T[], Partial<GridLoaderStates<T>>?] | null | undefined => {
|
|
308
|
+
// Avoid repeatedly load from cache
|
|
309
|
+
if (refs.current.initLoaded || !cacheKey) return undefined;
|
|
310
|
+
|
|
311
|
+
// Cache data
|
|
312
|
+
const cacheData = sessionStorage.getItem(cacheKey);
|
|
313
|
+
if (cacheData) {
|
|
314
|
+
const { rows, state, creation } = JSON.parse(cacheData) as DataType;
|
|
315
|
+
|
|
316
|
+
// 120 minutes
|
|
317
|
+
if (new Date().valueOf() - creation > cacheMinutes * 60000) {
|
|
318
|
+
sessionStorage.removeItem(cacheKey);
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Scroll position
|
|
323
|
+
const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
|
|
324
|
+
if (scrollData) {
|
|
325
|
+
if ("resetAfterColumnIndex" in ref) {
|
|
326
|
+
const { scrollLeft, scrollTop } = JSON.parse(
|
|
327
|
+
scrollData
|
|
328
|
+
) as GridOnScrollProps;
|
|
329
|
+
|
|
330
|
+
globalThis.setTimeout(
|
|
331
|
+
() => ref.scrollTo({ scrollLeft, scrollTop }),
|
|
332
|
+
0
|
|
333
|
+
);
|
|
334
|
+
} else {
|
|
335
|
+
const { scrollOffset } = JSON.parse(scrollData) as ListOnScrollProps;
|
|
336
|
+
|
|
337
|
+
globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Update flag value
|
|
342
|
+
refs.current.initLoaded = true;
|
|
343
|
+
|
|
344
|
+
// Return cached rows and state
|
|
345
|
+
return [rows, state];
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return undefined;
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
const onListScroll = (props: ListOnScrollProps) => {
|
|
352
|
+
if (!cacheKey || !refs.current.initLoaded) return;
|
|
353
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
354
|
+
};
|
|
355
|
+
const onGridScroll = (props: GridOnScrollProps) => {
|
|
356
|
+
if (!cacheKey || !refs.current.initLoaded) return;
|
|
357
|
+
sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
|
|
358
|
+
};
|
|
359
|
+
|
|
263
360
|
// Rect
|
|
264
361
|
const rect = dimensions[0][2];
|
|
265
362
|
|
|
@@ -309,7 +406,10 @@ export function ResponsibleContainer<
|
|
|
309
406
|
outerRef={(element?: HTMLDivElement) => {
|
|
310
407
|
if (element != null && elementReady) elementReady(element, true);
|
|
311
408
|
}}
|
|
409
|
+
onScroll={onGridScroll}
|
|
312
410
|
columns={columns}
|
|
411
|
+
onUpdateRows={onUpdateRows}
|
|
412
|
+
onInitLoad={onInitLoad}
|
|
313
413
|
{...rest}
|
|
314
414
|
/>
|
|
315
415
|
</Box>,
|
|
@@ -333,6 +433,8 @@ export function ResponsibleContainer<
|
|
|
333
433
|
autoLoad={!hasFields}
|
|
334
434
|
height={heightLocal}
|
|
335
435
|
loadData={localLoadData}
|
|
436
|
+
onUpdateRows={onUpdateRows}
|
|
437
|
+
onInitLoad={onInitLoad}
|
|
336
438
|
mRef={mRefs}
|
|
337
439
|
onClick={(event, data) =>
|
|
338
440
|
quickAction && ReactUtils.isSafeClick(event) && quickAction(data)
|
|
@@ -340,6 +442,7 @@ export function ResponsibleContainer<
|
|
|
340
442
|
oRef={(element) => {
|
|
341
443
|
if (element != null && elementReady) elementReady(element, false);
|
|
342
444
|
}}
|
|
445
|
+
onScroll={onListScroll}
|
|
343
446
|
{...rest}
|
|
344
447
|
/>
|
|
345
448
|
</Box>,
|
|
@@ -349,9 +452,19 @@ export function ResponsibleContainer<
|
|
|
349
452
|
|
|
350
453
|
const searchBar = React.useMemo(() => {
|
|
351
454
|
if (!hasFields || showDataGrid == null) return;
|
|
455
|
+
|
|
456
|
+
const f =
|
|
457
|
+
typeof fields == "function"
|
|
458
|
+
? fields(
|
|
459
|
+
JSON.parse(
|
|
460
|
+
sessionStorage.getItem(`${cacheKey}-searchbar`) ?? "{}"
|
|
461
|
+
) as DataTypes.BasicTemplateType<F>
|
|
462
|
+
)
|
|
463
|
+
: fields;
|
|
464
|
+
|
|
352
465
|
return (
|
|
353
466
|
<SearchBar
|
|
354
|
-
fields={
|
|
467
|
+
fields={f}
|
|
355
468
|
onSubmit={onSubmit}
|
|
356
469
|
className={`searchBar${showDataGrid ? "Grid" : "List"}`}
|
|
357
470
|
/>
|