@etsoo/materialui 1.2.42 → 1.2.44

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.2.42",
3
+ "version": "1.2.44",
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.84",
55
+ "@etsoo/react": "^1.6.85",
56
56
  "@etsoo/shared": "^1.2.5",
57
57
  "@mui/icons-material": "^5.11.16",
58
58
  "@mui/material": "^5.13.0",
@@ -51,6 +51,16 @@ export type DataGridExProps<
51
51
  */
52
52
  alternatingColors?: [string?, string?];
53
53
 
54
+ /**
55
+ * Cache key
56
+ */
57
+ cacheKey?: string;
58
+
59
+ /**
60
+ * Cache minutes
61
+ */
62
+ cacheMinutes?: number;
63
+
54
64
  /**
55
65
  * Checkable to choose multiple items
56
66
  * @default false
@@ -0,0 +1,10 @@
1
+ import { GridLoaderStates } from "@etsoo/react";
2
+
3
+ /**
4
+ * Grid data cache type
5
+ */
6
+ export type GridDataCacheType<T> = {
7
+ rows: T[];
8
+ state: GridLoaderStates<T>;
9
+ creation: number;
10
+ };
@@ -0,0 +1,99 @@
1
+ import {
2
+ GridDataGetData,
3
+ GridLoadDataProps,
4
+ GridLoaderStates
5
+ } from "@etsoo/react";
6
+ import { DataTypes } from "@etsoo/shared";
7
+ import { GridDataCacheType } from "./GridDataCacheType";
8
+
9
+ /**
10
+ * Grid utilities
11
+ */
12
+ export namespace GridUtils {
13
+ /**
14
+ * Create data loader
15
+ * @param props Props
16
+ * @param template Field template
17
+ * @param cacheKey Cache key
18
+ * @returns Request data
19
+ */
20
+ export function createLoader<F extends DataTypes.BasicTemplate>(
21
+ props: GridLoadDataProps,
22
+ template?: F,
23
+ cacheKey?: string
24
+ ) {
25
+ const { data, ...rest } = props;
26
+ const formData = GridDataGetData(data, template);
27
+
28
+ if (cacheKey)
29
+ sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(formData));
30
+
31
+ return { ...formData, ...rest };
32
+ }
33
+
34
+ /**
35
+ * Get cache data
36
+ * @param cacheKey Cache key
37
+ * @param cacheMinutes Cache minutes
38
+ * @returns
39
+ */
40
+ export function getCacheData<T>(cacheKey: string, cacheMinutes: number) {
41
+ const cacheSource = sessionStorage.getItem(cacheKey);
42
+ if (cacheSource) {
43
+ const cacheData = JSON.parse(cacheSource) as GridDataCacheType<T>;
44
+ if (new Date().valueOf() - cacheData.creation > cacheMinutes * 60000) {
45
+ sessionStorage.removeItem(cacheKey);
46
+ return;
47
+ }
48
+ return cacheData;
49
+ }
50
+ }
51
+
52
+ /**
53
+ * Get search data
54
+ * @param cacheKey Cache key
55
+ * @returns Result
56
+ */
57
+ export function getSearchData<F extends DataTypes.BasicTemplate>(
58
+ cacheKey?: string
59
+ ) {
60
+ if (cacheKey) {
61
+ const data = sessionStorage.getItem(`${cacheKey}-searchbar`);
62
+ if (data) {
63
+ return JSON.parse(data) as DataTypes.BasicTemplateType<F>;
64
+ }
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Get update rows handler
70
+ * @param cacheKey Cache key
71
+ * @returns Handler
72
+ */
73
+ export function getUpdateRowsHandler<T extends object>(cacheKey?: string) {
74
+ return (rows: T[], state: GridLoaderStates<T>) => {
75
+ if (state.currentPage > 0 && cacheKey) {
76
+ const data: GridDataCacheType<T> = {
77
+ rows,
78
+ state,
79
+ creation: new Date().valueOf()
80
+ };
81
+ sessionStorage.setItem(cacheKey, JSON.stringify(data));
82
+ }
83
+ };
84
+ }
85
+
86
+ /**
87
+ * Merget search date to state
88
+ * @param state State
89
+ * @param searchData Search data
90
+ */
91
+ export function mergeSearchData<T, F extends DataTypes.BasicTemplate>(
92
+ state: GridLoaderStates<T>,
93
+ searchData?: DataTypes.BasicTemplateType<F>
94
+ ) {
95
+ if (searchData == null) return;
96
+ state.data ??= {};
97
+ Object.assign(state.data, searchData);
98
+ }
99
+ }
@@ -9,7 +9,6 @@ import {
9
9
  } from "react-window";
10
10
  import {
11
11
  GridColumn,
12
- GridDataGet,
13
12
  GridJsonData,
14
13
  GridLoadDataProps,
15
14
  GridLoaderStates,
@@ -33,6 +32,7 @@ import {
33
32
  } from "./ScrollerListEx";
34
33
  import { SearchBar } from "./SearchBar";
35
34
  import { Labels } from "./app/Labels";
35
+ import { GridUtils } from "./GridUtils";
36
36
 
37
37
  /**
38
38
  * ResponsibleContainer props
@@ -67,16 +67,6 @@ export type ResponsibleContainerProps<
67
67
  */
68
68
  adjustFabHeight?: (height: number, isGrid: boolean) => number;
69
69
 
70
- /**
71
- * Cache key
72
- */
73
- cacheKey?: string;
74
-
75
- /**
76
- * Cache minutes
77
- */
78
- cacheMinutes?: number;
79
-
80
70
  /**
81
71
  * Columns
82
72
  */
@@ -251,14 +241,12 @@ export function ResponsibleContainer<
251
241
  // Load data
252
242
  const localLoadData = (props: GridLoadDataProps) => {
253
243
  state.mounted = true;
254
- const data = GridDataGet(props, fieldTemplate);
255
-
256
- if (cacheKey)
257
- sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
258
-
259
- return loadData(data);
244
+ return loadData(GridUtils.createLoader<F>(props, fieldTemplate, cacheKey));
260
245
  };
261
246
 
247
+ // Search data
248
+ const searchData = GridUtils.getSearchData<F>(cacheKey);
249
+
262
250
  // On submit callback
263
251
  const onSubmit = (data: FormData, _reset: boolean) => {
264
252
  if (data == null || state.ref == null) return;
@@ -293,15 +281,6 @@ export function ResponsibleContainer<
293
281
  }
294
282
  );
295
283
 
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
284
  const onInitLoad = (
306
285
  ref: VariableSizeGrid<T> | ScrollerListRef
307
286
  ): [T[], Partial<GridLoaderStates<T>>?] | null | undefined => {
@@ -309,15 +288,11 @@ export function ResponsibleContainer<
309
288
  if (refs.current.initLoaded || !cacheKey) return undefined;
310
289
 
311
290
  // Cache data
312
- const cacheData = sessionStorage.getItem(cacheKey);
291
+ const cacheData = GridUtils.getCacheData<T>(cacheKey, cacheMinutes);
313
292
  if (cacheData) {
314
- const { rows, state, creation } = JSON.parse(cacheData) as DataType;
293
+ const { rows, state } = cacheData;
315
294
 
316
- // 120 minutes
317
- if (new Date().valueOf() - creation > cacheMinutes * 60000) {
318
- sessionStorage.removeItem(cacheKey);
319
- return undefined;
320
- }
295
+ GridUtils.mergeSearchData(state, searchData);
321
296
 
322
297
  // Scroll position
323
298
  const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
@@ -408,7 +383,7 @@ export function ResponsibleContainer<
408
383
  }}
409
384
  onScroll={onGridScroll}
410
385
  columns={columns}
411
- onUpdateRows={onUpdateRows}
386
+ onUpdateRows={GridUtils.getUpdateRowsHandler<T>(cacheKey)}
412
387
  onInitLoad={onInitLoad}
413
388
  {...rest}
414
389
  />
@@ -433,7 +408,7 @@ export function ResponsibleContainer<
433
408
  autoLoad={!hasFields}
434
409
  height={heightLocal}
435
410
  loadData={localLoadData}
436
- onUpdateRows={onUpdateRows}
411
+ onUpdateRows={GridUtils.getUpdateRowsHandler<T>(cacheKey)}
437
412
  onInitLoad={onInitLoad}
438
413
  mRef={mRefs}
439
414
  onClick={(event, data) =>
@@ -453,14 +428,7 @@ export function ResponsibleContainer<
453
428
  const searchBar = React.useMemo(() => {
454
429
  if (!hasFields || showDataGrid == null) return;
455
430
 
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;
431
+ const f = typeof fields == "function" ? fields(searchData ?? {}) : fields;
464
432
 
465
433
  return (
466
434
  <SearchBar
@@ -1,7 +1,9 @@
1
1
  import {
2
- GridDataGet,
3
2
  GridLoadDataProps,
3
+ GridLoaderStates,
4
+ GridOnScrollProps,
4
5
  ScrollerGridForwardRef,
6
+ VariableSizeGrid,
5
7
  useCombinedRefs,
6
8
  useDimensions
7
9
  } from "@etsoo/react";
@@ -13,6 +15,7 @@ import { MUGlobal } from "../MUGlobal";
13
15
  import { SearchBar } from "../SearchBar";
14
16
  import { CommonPage } from "./CommonPage";
15
17
  import { DataGridPageProps } from "./DataGridPageProps";
18
+ import { GridUtils } from "../GridUtils";
16
19
 
17
20
  interface LocalStates<T> {
18
21
  data?: FormData;
@@ -41,6 +44,8 @@ export function DataGridPage<
41
44
  mRef,
42
45
  sizeReadyMiliseconds = 100,
43
46
  pageProps = {},
47
+ cacheKey,
48
+ cacheMinutes = 120,
44
49
  ...rest
45
50
  } = props;
46
51
 
@@ -65,14 +70,56 @@ export function DataGridPage<
65
70
  }
66
71
  );
67
72
 
73
+ const initLoadedRef = React.useRef<boolean>();
74
+
68
75
  // On submit callback
69
76
  const onSubmit = (data: FormData, _reset: boolean) => {
70
77
  setStates({ data });
71
78
  };
72
79
 
73
80
  const localLoadData = (props: GridLoadDataProps) => {
74
- const data = GridDataGet(props, fieldTemplate);
75
- return loadData(data);
81
+ return loadData(GridUtils.createLoader<F>(props, fieldTemplate, cacheKey));
82
+ };
83
+
84
+ // Search data
85
+ const searchData = GridUtils.getSearchData<F>(cacheKey);
86
+
87
+ const onInitLoad = (
88
+ ref: VariableSizeGrid<T>
89
+ ): [T[], Partial<GridLoaderStates<T>>?] | null | undefined => {
90
+ // Avoid repeatedly load from cache
91
+ if (initLoadedRef.current || !cacheKey) return undefined;
92
+
93
+ // Cache data
94
+ const cacheData = GridUtils.getCacheData<T>(cacheKey, cacheMinutes);
95
+ if (cacheData) {
96
+ const { rows, state } = cacheData;
97
+
98
+ GridUtils.mergeSearchData(state, searchData);
99
+
100
+ // Scroll position
101
+ const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
102
+ if (scrollData) {
103
+ const { scrollLeft, scrollTop } = JSON.parse(
104
+ scrollData
105
+ ) as GridOnScrollProps;
106
+
107
+ globalThis.setTimeout(() => ref.scrollTo({ scrollLeft, scrollTop }), 0);
108
+ }
109
+
110
+ // Update flag value
111
+ initLoadedRef.current = true;
112
+
113
+ // Return cached rows and state
114
+ return [rows, state];
115
+ }
116
+
117
+ return undefined;
118
+ };
119
+
120
+ const onGridScroll = (props: GridOnScrollProps) => {
121
+ if (!cacheKey || !initLoadedRef.current) return;
122
+ sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
76
123
  };
77
124
 
78
125
  // Watch container
@@ -105,6 +152,9 @@ export function DataGridPage<
105
152
  height={gridHeight}
106
153
  loadData={localLoadData}
107
154
  mRef={refs}
155
+ onUpdateRows={GridUtils.getUpdateRowsHandler<T>(cacheKey)}
156
+ onInitLoad={onInitLoad}
157
+ onScroll={onGridScroll}
108
158
  outerRef={(element?: HTMLDivElement) => {
109
159
  if (element != null) setStates({ element });
110
160
  }}
@@ -119,6 +169,8 @@ export function DataGridPage<
119
169
  ref.reset({ data });
120
170
  }, [ref, data]);
121
171
 
172
+ const f = typeof fields == "function" ? fields(searchData ?? {}) : fields;
173
+
122
174
  // Layout
123
175
  return (
124
176
  <CommonPage {...pageProps} scrollContainer={states.element}>
@@ -129,7 +181,7 @@ export function DataGridPage<
129
181
  paddingBottom: pageProps.paddings
130
182
  }}
131
183
  >
132
- <SearchBar fields={fields} onSubmit={onSubmit} />
184
+ <SearchBar fields={f} onSubmit={onSubmit} />
133
185
  </Box>
134
186
  {list}
135
187
  </Stack>
@@ -1,7 +1,9 @@
1
1
  import {
2
- GridDataGet,
3
2
  GridLoadDataProps,
3
+ GridLoaderStates,
4
+ ListOnScrollProps,
4
5
  ScrollerListForwardRef,
6
+ ScrollerListRef,
5
7
  useCombinedRefs,
6
8
  useDimensions
7
9
  } from "@etsoo/react";
@@ -13,6 +15,7 @@ import { ScrollerListEx } from "../ScrollerListEx";
13
15
  import { SearchBar } from "../SearchBar";
14
16
  import { CommonPage } from "./CommonPage";
15
17
  import { ListPageProps } from "./ListPageProps";
18
+ import { GridUtils } from "../GridUtils";
16
19
 
17
20
  /**
18
21
  * Fixed height list page
@@ -42,6 +45,8 @@ export function FixedListPage<
42
45
  mRef,
43
46
  sizeReadyMiliseconds = 0,
44
47
  pageProps = {},
48
+ cacheKey,
49
+ cacheMinutes = 120,
45
50
  ...rest
46
51
  } = props;
47
52
 
@@ -53,6 +58,8 @@ export function FixedListPage<
53
58
  ref?: ScrollerListForwardRef<T>;
54
59
  }>({});
55
60
 
61
+ const initLoadedRef = React.useRef<boolean>();
62
+
56
63
  // Scroll container
57
64
  const [scrollContainer, updateScrollContainer] = React.useState<
58
65
  HTMLElement | undefined
@@ -83,8 +90,45 @@ export function FixedListPage<
83
90
  };
84
91
 
85
92
  const localLoadData = (props: GridLoadDataProps) => {
86
- const data = GridDataGet(props, fieldTemplate);
87
- return loadData(data);
93
+ return loadData(GridUtils.createLoader<F>(props, fieldTemplate, cacheKey));
94
+ };
95
+
96
+ // Search data
97
+ const searchData = GridUtils.getSearchData<F>(cacheKey);
98
+
99
+ const onInitLoad = (
100
+ ref: ScrollerListRef
101
+ ): [T[], Partial<GridLoaderStates<T>>?] | null | undefined => {
102
+ // Avoid repeatedly load from cache
103
+ if (initLoadedRef.current || !cacheKey) return undefined;
104
+
105
+ // Cache data
106
+ const cacheData = GridUtils.getCacheData<T>(cacheKey, cacheMinutes);
107
+ if (cacheData) {
108
+ const { rows, state } = cacheData;
109
+
110
+ GridUtils.mergeSearchData(state, searchData);
111
+
112
+ // Scroll position
113
+ const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
114
+ if (scrollData) {
115
+ const { scrollOffset } = JSON.parse(scrollData) as ListOnScrollProps;
116
+ globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
117
+ }
118
+
119
+ // Update flag value
120
+ initLoadedRef.current = true;
121
+
122
+ // Return cached rows and state
123
+ return [rows, state];
124
+ }
125
+
126
+ return undefined;
127
+ };
128
+
129
+ const onListScroll = (props: ListOnScrollProps) => {
130
+ if (!cacheKey || !initLoadedRef.current) return;
131
+ sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
88
132
  };
89
133
 
90
134
  // Watch container
@@ -110,6 +154,9 @@ export function FixedListPage<
110
154
  height={height}
111
155
  loadData={localLoadData}
112
156
  mRef={refs}
157
+ onUpdateRows={GridUtils.getUpdateRowsHandler<T>(cacheKey)}
158
+ onInitLoad={onInitLoad}
159
+ onScroll={onListScroll}
113
160
  oRef={(element) => {
114
161
  if (element != null) updateScrollContainer(element);
115
162
  }}
@@ -120,6 +167,8 @@ export function FixedListPage<
120
167
  }
121
168
  }, [rect]);
122
169
 
170
+ const f = typeof fields == "function" ? fields(searchData ?? {}) : fields;
171
+
123
172
  const { paddings, ...pageRest } = pageProps;
124
173
 
125
174
  // Layout
@@ -127,7 +176,7 @@ export function FixedListPage<
127
176
  <CommonPage {...pageRest} paddings={{}} scrollContainer={scrollContainer}>
128
177
  <Stack>
129
178
  <Box ref={dimensions[0][0]} sx={{ padding: paddings }}>
130
- <SearchBar fields={fields} onSubmit={onSubmit} />
179
+ <SearchBar fields={f} onSubmit={onSubmit} />
131
180
  </Box>
132
181
  {list}
133
182
  </Stack>