@etsoo/materialui 1.2.41 → 1.2.43

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.
@@ -1,17 +1,21 @@
1
1
  import {
2
- GridDataGet,
3
- GridLoadDataProps,
4
- ScrollerListForwardRef,
5
- useCombinedRefs
6
- } from '@etsoo/react';
7
- import { DataTypes, IdDefaultType } from '@etsoo/shared';
8
- import { Box, Stack } from '@mui/material';
9
- import React from 'react';
10
- import { MUGlobal } from '../MUGlobal';
11
- import { ScrollerListEx } from '../ScrollerListEx';
12
- import { SearchBar } from '../SearchBar';
13
- import { CommonPage, CommonPageScrollContainer } from './CommonPage';
14
- import { ListPageProps } from './ListPageProps';
2
+ GridDataGet,
3
+ GridLoadDataProps,
4
+ GridLoaderStates,
5
+ ListOnScrollProps,
6
+ ScrollerListForwardRef,
7
+ ScrollerListRef,
8
+ useCombinedRefs
9
+ } from "@etsoo/react";
10
+ import { DataTypes, IdDefaultType } from "@etsoo/shared";
11
+ import { Box, Stack } from "@mui/material";
12
+ import React from "react";
13
+ import { MUGlobal } from "../MUGlobal";
14
+ import { ScrollerListEx } from "../ScrollerListEx";
15
+ import { SearchBar } from "../SearchBar";
16
+ import { CommonPage, CommonPageScrollContainer } from "./CommonPage";
17
+ import { ListPageProps } from "./ListPageProps";
18
+ import { GridDataCacheType } from "../GridDataCacheType";
15
19
 
16
20
  /**
17
21
  * List page
@@ -19,72 +23,136 @@ import { ListPageProps } from './ListPageProps';
19
23
  * @returns Component
20
24
  */
21
25
  export function ListPage<
22
- T extends object,
23
- F extends DataTypes.BasicTemplate = DataTypes.BasicTemplate,
24
- D extends DataTypes.Keys<T> = IdDefaultType<T>
26
+ T extends object,
27
+ F extends DataTypes.BasicTemplate = DataTypes.BasicTemplate,
28
+ D extends DataTypes.Keys<T> = IdDefaultType<T>
25
29
  >(props: ListPageProps<T, F, D>) {
26
- // Destruct
27
- const {
28
- fields,
29
- fieldTemplate,
30
- loadData,
31
- mRef,
32
- pageProps = {},
33
- ...rest
34
- } = props;
35
-
36
- pageProps.paddings ??= MUGlobal.pagePaddings;
37
-
38
- // States
39
- const [states] = React.useState<{
40
- data?: FormData;
41
- ref?: ScrollerListForwardRef<T>;
42
- }>({});
43
-
44
- const refs = useCombinedRefs(mRef, (ref: ScrollerListForwardRef<T>) => {
45
- if (ref == null) return;
46
-
47
- const first = states.ref == null;
48
-
49
- states.ref = ref;
50
-
51
- if (first) reset();
52
- });
53
-
54
- const reset = () => {
55
- if (states.data == null || states.ref == null) return;
56
- states.ref.reset({ data: states.data });
57
- };
58
-
59
- // On submit callback
60
- const onSubmit = (data: FormData, _reset: boolean) => {
61
- states.data = data;
62
- reset();
63
- };
64
-
65
- const localLoadData = (props: GridLoadDataProps) => {
66
- const data = GridDataGet(props, fieldTemplate);
67
- return loadData(data);
68
- };
69
-
70
- // Layout
71
- return (
72
- <CommonPage {...pageProps} scrollContainer={CommonPageScrollContainer}>
73
- <Stack>
74
- <Box
75
- sx={{
76
- paddingBottom: pageProps.paddings
77
- }}
78
- >
79
- <SearchBar fields={fields} onSubmit={onSubmit} />
80
- </Box>
81
- <ScrollerListEx<T, D>
82
- autoLoad={false}
83
- loadData={localLoadData}
84
- mRef={refs}
85
- {...rest}
86
- />
87
- </Stack>
88
- </CommonPage>
89
- );
30
+ // Destruct
31
+ const {
32
+ fields,
33
+ fieldTemplate,
34
+ loadData,
35
+ mRef,
36
+ pageProps = {},
37
+ cacheKey,
38
+ cacheMinutes = 120,
39
+ ...rest
40
+ } = props;
41
+
42
+ pageProps.paddings ??= MUGlobal.pagePaddings;
43
+
44
+ // States
45
+ const [states] = React.useState<{
46
+ data?: FormData;
47
+ ref?: ScrollerListForwardRef<T>;
48
+ }>({});
49
+
50
+ const refs = useCombinedRefs(mRef, (ref: ScrollerListForwardRef<T>) => {
51
+ if (ref == null) return;
52
+
53
+ const first = states.ref == null;
54
+
55
+ states.ref = ref;
56
+
57
+ if (first) reset();
58
+ });
59
+
60
+ const initLoadedRef = React.useRef<boolean>();
61
+
62
+ const reset = () => {
63
+ if (states.data == null || states.ref == null) return;
64
+ states.ref.reset({ data: states.data });
65
+ };
66
+
67
+ // On submit callback
68
+ const onSubmit = (data: FormData, _reset: boolean) => {
69
+ states.data = data;
70
+ reset();
71
+ };
72
+
73
+ const localLoadData = (props: GridLoadDataProps) => {
74
+ const data = GridDataGet(props, fieldTemplate);
75
+ return loadData(data);
76
+ };
77
+
78
+ type DataType = GridDataCacheType<T>;
79
+
80
+ const onUpdateRows = (rows: T[], state: GridLoaderStates<T>) => {
81
+ if (state.currentPage > 0 && cacheKey) {
82
+ const data: DataType = { rows, state, creation: new Date().valueOf() };
83
+ sessionStorage.setItem(cacheKey, JSON.stringify(data));
84
+ }
85
+ };
86
+
87
+ const onInitLoad = (
88
+ ref: ScrollerListRef
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 = sessionStorage.getItem(cacheKey);
95
+ if (cacheData) {
96
+ const { rows, state, creation } = JSON.parse(cacheData) as DataType;
97
+
98
+ // 120 minutes
99
+ if (new Date().valueOf() - creation > cacheMinutes * 60000) {
100
+ sessionStorage.removeItem(cacheKey);
101
+ return undefined;
102
+ }
103
+
104
+ // Scroll position
105
+ const scrollData = sessionStorage.getItem(`${cacheKey}-scroll`);
106
+ if (scrollData) {
107
+ const { scrollOffset } = JSON.parse(scrollData) as ListOnScrollProps;
108
+ globalThis.setTimeout(() => ref.scrollTo(scrollOffset), 0);
109
+ }
110
+
111
+ // Update flag value
112
+ initLoadedRef.current = true;
113
+
114
+ // Return cached rows and state
115
+ return [rows, state];
116
+ }
117
+
118
+ return undefined;
119
+ };
120
+
121
+ const onListScroll = (props: ListOnScrollProps) => {
122
+ if (!cacheKey || !initLoadedRef.current) return;
123
+ sessionStorage.setItem(`${cacheKey}-scroll`, JSON.stringify(props));
124
+ };
125
+
126
+ const f =
127
+ typeof fields == "function"
128
+ ? fields(
129
+ JSON.parse(
130
+ sessionStorage.getItem(`${cacheKey}-searchbar`) ?? "{}"
131
+ ) as DataTypes.BasicTemplateType<F>
132
+ )
133
+ : fields;
134
+
135
+ // Layout
136
+ return (
137
+ <CommonPage {...pageProps} scrollContainer={CommonPageScrollContainer}>
138
+ <Stack>
139
+ <Box
140
+ sx={{
141
+ paddingBottom: pageProps.paddings
142
+ }}
143
+ >
144
+ <SearchBar fields={f} onSubmit={onSubmit} />
145
+ </Box>
146
+ <ScrollerListEx<T, D>
147
+ autoLoad={false}
148
+ loadData={localLoadData}
149
+ onUpdateRows={onUpdateRows}
150
+ onInitLoad={onInitLoad}
151
+ onScroll={onListScroll}
152
+ mRef={refs}
153
+ {...rest}
154
+ />
155
+ </Stack>
156
+ </CommonPage>
157
+ );
90
158
  }
@@ -1,12 +1,12 @@
1
- import { DataTypes } from '@etsoo/shared';
2
- import { ScrollerListExProps } from '../ScrollerListEx';
3
- import { SearchPageProps } from './SearchPageProps';
1
+ import { DataTypes } from "@etsoo/shared";
2
+ import { ScrollerListExProps } from "../ScrollerListEx";
3
+ import { SearchPageProps } from "./SearchPageProps";
4
4
 
5
5
  /**
6
6
  * List page props
7
7
  */
8
8
  export type ListPageProps<
9
- T extends object,
10
- F extends DataTypes.BasicTemplate,
11
- D extends DataTypes.Keys<T>
12
- > = SearchPageProps<T, F> & Omit<ScrollerListExProps<T, D>, 'loadData'>;
9
+ T extends object,
10
+ F extends DataTypes.BasicTemplate,
11
+ D extends DataTypes.Keys<T>
12
+ > = SearchPageProps<T, F> & Omit<ScrollerListExProps<T, D>, "loadData">;
@@ -9,10 +9,22 @@ export type SearchPageProps<
9
9
  T extends object,
10
10
  F extends DataTypes.BasicTemplate
11
11
  > = Omit<GridLoader<T>, "loadData"> & {
12
+ /**
13
+ * Cache key
14
+ */
15
+ cacheKey?: string;
16
+
17
+ /**
18
+ * Cache minutes
19
+ */
20
+ cacheMinutes?: number;
21
+
12
22
  /**
13
23
  * Search fields
14
24
  */
15
- fields: React.ReactElement[];
25
+ fields:
26
+ | React.ReactElement[]
27
+ | ((data: DataTypes.BasicTemplateType<F>) => React.ReactElement[]);
16
28
 
17
29
  /**
18
30
  * Search field template
@@ -1,17 +1,17 @@
1
1
  import {
2
- GridDataGet,
3
- GridLoadDataProps,
4
- useCombinedRefs,
5
- useDimensions
6
- } from '@etsoo/react';
7
- import { DataTypes, IdDefaultType } from '@etsoo/shared';
8
- import { Box, Stack } from '@mui/material';
9
- import React from 'react';
10
- import { MUGlobal } from '../MUGlobal';
11
- import { SearchBar } from '../SearchBar';
12
- import { TableEx, TableExMethodRef, TableExMinWidth } from '../TableEx';
13
- import { CommonPage, CommonPageScrollContainer } from './CommonPage';
14
- import { TablePageProps } from './TablePageProps';
2
+ GridDataGet,
3
+ GridLoadDataProps,
4
+ useCombinedRefs,
5
+ useDimensions
6
+ } from "@etsoo/react";
7
+ import { DataTypes, IdDefaultType } from "@etsoo/shared";
8
+ import { Box, Stack } from "@mui/material";
9
+ import React from "react";
10
+ import { MUGlobal } from "../MUGlobal";
11
+ import { SearchBar } from "../SearchBar";
12
+ import { TableEx, TableExMethodRef, TableExMinWidth } from "../TableEx";
13
+ import { CommonPage, CommonPageScrollContainer } from "./CommonPage";
14
+ import { TablePageProps } from "./TablePageProps";
15
15
 
16
16
  /**
17
17
  * Table page
@@ -19,108 +19,122 @@ import { TablePageProps } from './TablePageProps';
19
19
  * @returns Component
20
20
  */
21
21
  export function TablePage<
22
- T extends object,
23
- F extends DataTypes.BasicTemplate = DataTypes.BasicTemplate,
24
- D extends DataTypes.Keys<T> = IdDefaultType<T>
22
+ T extends object,
23
+ F extends DataTypes.BasicTemplate = DataTypes.BasicTemplate,
24
+ D extends DataTypes.Keys<T> = IdDefaultType<T>
25
25
  >(props: TablePageProps<T, F, D>) {
26
- // Destruct
27
- const {
28
- columns,
29
- fields,
30
- fieldTemplate,
31
- loadData,
32
- mRef,
33
- sizeReadyMiliseconds = 0,
34
- pageProps = {},
35
- ...rest
36
- } = props;
37
-
38
- pageProps.paddings ??= MUGlobal.pagePaddings;
39
-
40
- // States
41
- const [states] = React.useState<{
42
- data?: FormData;
43
- ref?: TableExMethodRef<T>;
44
- }>({});
45
-
46
- const refs = useCombinedRefs(
47
- mRef,
48
- (ref: TableExMethodRef<T> | null | undefined) => {
49
- if (ref == null) return;
50
-
51
- const first = states.ref == null;
52
-
53
- states.ref = ref;
54
-
55
- if (first) reset();
56
- }
57
- );
58
-
59
- const reset = () => {
60
- if (states.data == null || states.ref == null) return;
61
- states.ref.reset({ data: states.data });
62
- };
63
-
64
- // On submit callback
65
- const onSubmit = (data: FormData, _reset: boolean) => {
66
- states.data = data;
67
- reset();
68
- };
69
-
70
- const localLoadData = (props: GridLoadDataProps) => {
71
- const data = GridDataGet(props, fieldTemplate);
72
- return loadData(data);
73
- };
74
-
75
- // Total width
76
- const totalWidth = React.useMemo(
77
- () =>
78
- columns.reduce((previousValue, { width, minWidth }) => {
79
- return previousValue + (width ?? minWidth ?? TableExMinWidth);
80
- }, 0),
81
- [columns]
82
- );
83
-
84
- // Watch container
85
- const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
86
- const rect = dimensions[0][2];
87
- const list = React.useMemo(() => {
88
- if (rect != null && rect.height > 50 && rect.width >= totalWidth) {
89
- let maxHeight =
90
- document.documentElement.clientHeight -
91
- (rect.top + rect.height + 1);
92
-
93
- const style = window.getComputedStyle(dimensions[0][1]!);
94
- const paddingBottom = parseFloat(style.paddingBottom);
95
- if (!isNaN(paddingBottom)) maxHeight -= paddingBottom;
96
-
97
- return (
98
- <TableEx<T, D>
99
- autoLoad={false}
100
- columns={columns}
101
- loadData={localLoadData}
102
- maxHeight={maxHeight}
103
- mRef={refs}
104
- {...rest}
105
- />
106
- );
107
- }
108
- }, [rect]);
109
-
110
- // Layout
111
- return (
112
- <CommonPage {...pageProps} scrollContainer={CommonPageScrollContainer}>
113
- <Stack>
114
- <Box
115
- ref={dimensions[0][0]}
116
- sx={{
117
- paddingBottom: pageProps.paddings
118
- }}
119
- >
120
- <SearchBar fields={fields} onSubmit={onSubmit} />
121
- </Box>
122
- {list}
123
- </Stack>
124
- </CommonPage>
125
- );
26
+ // Destruct
27
+ const {
28
+ columns,
29
+ fields,
30
+ fieldTemplate,
31
+ loadData,
32
+ mRef,
33
+ sizeReadyMiliseconds = 0,
34
+ pageProps = {},
35
+ cacheKey,
36
+ cacheMinutes = 120,
37
+ ...rest
38
+ } = props;
39
+
40
+ pageProps.paddings ??= MUGlobal.pagePaddings;
41
+
42
+ // States
43
+ const [states] = React.useState<{
44
+ data?: FormData;
45
+ ref?: TableExMethodRef<T>;
46
+ }>({});
47
+
48
+ const refs = useCombinedRefs(
49
+ mRef,
50
+ (ref: TableExMethodRef<T> | null | undefined) => {
51
+ if (ref == null) return;
52
+
53
+ const first = states.ref == null;
54
+
55
+ states.ref = ref;
56
+
57
+ if (first) reset();
58
+ }
59
+ );
60
+
61
+ const reset = () => {
62
+ if (states.data == null || states.ref == null) return;
63
+ states.ref.reset({ data: states.data });
64
+ };
65
+
66
+ // On submit callback
67
+ const onSubmit = (data: FormData, _reset: boolean) => {
68
+ states.data = data;
69
+ reset();
70
+ };
71
+
72
+ const localLoadData = (props: GridLoadDataProps) => {
73
+ const data = GridDataGet(props, fieldTemplate);
74
+
75
+ if (cacheKey)
76
+ sessionStorage.setItem(`${cacheKey}-searchbar`, JSON.stringify(data));
77
+
78
+ return loadData(data);
79
+ };
80
+
81
+ // Total width
82
+ const totalWidth = React.useMemo(
83
+ () =>
84
+ columns.reduce((previousValue, { width, minWidth }) => {
85
+ return previousValue + (width ?? minWidth ?? TableExMinWidth);
86
+ }, 0),
87
+ [columns]
88
+ );
89
+
90
+ // Watch container
91
+ const { dimensions } = useDimensions(1, undefined, sizeReadyMiliseconds);
92
+ const rect = dimensions[0][2];
93
+ const list = React.useMemo(() => {
94
+ if (rect != null && rect.height > 50 && rect.width >= totalWidth) {
95
+ let maxHeight =
96
+ document.documentElement.clientHeight - (rect.top + rect.height + 1);
97
+
98
+ const style = window.getComputedStyle(dimensions[0][1]!);
99
+ const paddingBottom = parseFloat(style.paddingBottom);
100
+ if (!isNaN(paddingBottom)) maxHeight -= paddingBottom;
101
+
102
+ return (
103
+ <TableEx<T, D>
104
+ autoLoad={false}
105
+ columns={columns}
106
+ loadData={localLoadData}
107
+ maxHeight={maxHeight}
108
+ mRef={refs}
109
+ {...rest}
110
+ />
111
+ );
112
+ }
113
+ }, [rect]);
114
+
115
+ const f =
116
+ typeof fields == "function"
117
+ ? fields(
118
+ JSON.parse(
119
+ sessionStorage.getItem(`${cacheKey}-searchbar`) ?? "{}"
120
+ ) as DataTypes.BasicTemplateType<F>
121
+ )
122
+ : fields;
123
+
124
+ // Layout
125
+ return (
126
+ <CommonPage {...pageProps} scrollContainer={CommonPageScrollContainer}>
127
+ <Stack>
128
+ <Box
129
+ ref={dimensions[0][0]}
130
+ sx={{
131
+ paddingBottom: pageProps.paddings
132
+ }}
133
+ >
134
+ <SearchBar fields={f} onSubmit={onSubmit} />
135
+ </Box>
136
+ {list}
137
+ </Stack>
138
+ </CommonPage>
139
+ );
126
140
  }