@etsoo/materialui 1.4.99 → 1.5.0

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,78 +1,12 @@
1
- import { GridColumnRenderProps, GridDataType } from "@etsoo/react";
2
1
  import { DataTypes } from "@etsoo/shared";
3
- import { Breakpoint, Grid2Props } from "@mui/material";
4
2
  import React from "react";
5
3
  import { CommonPageProps } from "./CommonPage";
6
4
  import type { OperationMessageHandlerAll } from "../messages/OperationMessageHandler";
7
- /**
8
- * View page item size
9
- */
10
- export type ViewPageItemSize = Record<Breakpoint, number | undefined>;
11
- /**
12
- * View page grid item size
13
- */
14
- export declare namespace ViewPageSize {
15
- const large: ViewPageItemSize;
16
- const medium: ViewPageItemSize;
17
- const line: ViewPageItemSize;
18
- const small: ViewPageItemSize;
19
- const smallLine: ViewPageItemSize;
20
- function matchSize(size: ViewPageItemSize): {
21
- [k: string]: number | undefined;
22
- };
23
- }
24
- /**
25
- * View page grid item properties
26
- */
27
- export type ViewPageGridItemProps = Grid2Props & {
28
- data: React.ReactNode;
29
- label?: React.ReactNode;
30
- singleRow?: ViewPageRowType;
31
- };
32
- /**
33
- * View page grid item
34
- * @param props Props
35
- * @returns Result
36
- */
37
- export declare function ViewPageGridItem(props: ViewPageGridItemProps): import("react/jsx-runtime").JSX.Element;
38
- /**
39
- * View page row width type
40
- */
41
- export type ViewPageRowType = boolean | "default" | "small" | "medium" | "large" | ViewPageItemSize;
42
- /**
43
- * View page display field
44
- */
45
- export interface ViewPageField<T extends object> extends Grid2Props {
46
- /**
47
- * Data field
48
- */
49
- data: (string & keyof T) | ((item: T) => React.ReactNode);
50
- /**
51
- * Data type
52
- */
53
- dataType?: GridDataType;
54
- /**
55
- * Label field
56
- */
57
- label?: string | ((item: T) => React.ReactNode);
58
- /**
59
- * Display as single row
60
- */
61
- singleRow?: ViewPageRowType;
62
- /**
63
- * Render props
64
- */
65
- renderProps?: GridColumnRenderProps;
66
- }
67
- type ViewPageFieldTypeNarrow<T extends object> = (string & keyof T) | [string & keyof T, GridDataType, GridColumnRenderProps?, ViewPageRowType?] | ViewPageField<T>;
68
- /**
69
- * View page field type
70
- */
71
- export type ViewPageFieldType<T extends object> = ViewPageFieldTypeNarrow<T> | ((data: T, refresh: () => Promise<void>) => React.ReactNode | [React.ReactNode, ViewPageItemSize]);
5
+ import { ViewContainerProps } from "../ViewContainer";
72
6
  /**
73
7
  * View page props
74
8
  */
75
- export interface ViewPageProps<T extends DataTypes.StringRecord> extends Omit<CommonPageProps, "children"> {
9
+ export interface ViewPageProps<T extends DataTypes.StringRecord> extends Omit<CommonPageProps, "children">, Omit<ViewContainerProps<T>, "data"> {
76
10
  /**
77
11
  * Actions
78
12
  */
@@ -85,10 +19,6 @@ export interface ViewPageProps<T extends DataTypes.StringRecord> extends Omit<Co
85
19
  * Children
86
20
  */
87
21
  children?: React.ReactNode | ((data: T, refresh: () => PromiseLike<void>) => React.ReactNode);
88
- /**
89
- * Fields to display
90
- */
91
- fields: ViewPageFieldType<T>[];
92
22
  /**
93
23
  * Load data
94
24
  */
@@ -97,18 +27,10 @@ export interface ViewPageProps<T extends DataTypes.StringRecord> extends Omit<Co
97
27
  * Pull to refresh data
98
28
  */
99
29
  pullToRefresh?: boolean;
100
- /**
101
- * Grid spacing
102
- */
103
- spacing?: Record<string, string | number>;
104
30
  /**
105
31
  * Support refresh
106
32
  */
107
33
  supportRefresh?: boolean;
108
- /**
109
- * Grid container reference
110
- */
111
- gridRef?: React.Ref<HTMLDivElement>;
112
34
  /**
113
35
  * Operation message handler
114
36
  */
@@ -122,24 +44,9 @@ export interface ViewPageProps<T extends DataTypes.StringRecord> extends Omit<Co
122
44
  * @returns
123
45
  */
124
46
  titleBar?: (data: T) => React.ReactNode;
125
- /**
126
- * Left container
127
- */
128
- leftContainer?: (data: T) => React.ReactNode;
129
- /**
130
- * Left container height in lines
131
- */
132
- leftContainerLines?: number;
133
- /**
134
- * Left container properties
135
- */
136
- leftContainerProps?: Omit<Grid2Props, "size"> & {
137
- size?: ViewPageItemSize;
138
- };
139
47
  }
140
48
  /**
141
49
  * View page
142
50
  * @param props Props
143
51
  */
144
52
  export declare function ViewPage<T extends DataTypes.StringRecord>(props: ViewPageProps<T>): import("react/jsx-runtime").JSX.Element;
145
- export {};
@@ -1,244 +1,34 @@
1
- import { createElement as _createElement } from "react";
2
- import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
2
  import { ScrollRestoration } from "@etsoo/react";
4
3
  import { Utils } from "@etsoo/shared";
5
- import { Grid2, LinearProgress, Stack, Typography } from "@mui/material";
4
+ import { LinearProgress, Stack } from "@mui/material";
6
5
  import React from "react";
7
6
  import { Labels } from "../app/Labels";
8
- import { GridDataFormat } from "../GridDataFormat";
9
7
  import { MUGlobal } from "../MUGlobal";
10
8
  import { PullToRefreshUI } from "../PullToRefreshUI";
11
9
  import { CommonPage } from "./CommonPage";
12
10
  import { MessageUtils } from "../messages/MessageUtils";
13
11
  import { OperationMessageContainer } from "../messages/OperationMessageContainer";
14
- import { useRequiredAppContext } from "../app/ReactApp";
15
- import { useCurrentBreakpoint } from "../useCurrentBreakpoint";
16
- const breakpoints = ["xs", "sm", "md", "lg", "xl"];
17
- /**
18
- * View page grid item size
19
- */
20
- export var ViewPageSize;
21
- (function (ViewPageSize) {
22
- ViewPageSize.large = {
23
- xs: 12,
24
- sm: 12,
25
- md: 9,
26
- lg: 6,
27
- xl: 4
28
- };
29
- ViewPageSize.medium = {
30
- xs: 12,
31
- sm: 12,
32
- md: 6,
33
- lg: 4,
34
- xl: 3
35
- };
36
- ViewPageSize.line = {
37
- xs: 12,
38
- sm: 12,
39
- md: 12,
40
- lg: 12,
41
- xl: 12
42
- };
43
- ViewPageSize.small = { xs: 6, sm: 6, md: 4, lg: 3, xl: 2 };
44
- ViewPageSize.smallLine = {
45
- xs: 12,
46
- sm: 6,
47
- md: 4,
48
- lg: 3,
49
- xl: 2
50
- };
51
- function matchSize(size) {
52
- return Object.fromEntries(Object.entries(size).map(([key, value]) => [
53
- key,
54
- value == null ? undefined : value === 12 ? 12 : 12 - value
55
- ]));
56
- }
57
- ViewPageSize.matchSize = matchSize;
58
- })(ViewPageSize || (ViewPageSize = {}));
59
- /**
60
- * View page grid item
61
- * @param props Props
62
- * @returns Result
63
- */
64
- export function ViewPageGridItem(props) {
65
- // Destruct
66
- const { data, label, singleRow, ...gridProps } = props;
67
- // Default options
68
- let options = {};
69
- if (gridProps.size == null) {
70
- options = getResp(singleRow ?? "small");
71
- }
72
- else if (singleRow != null) {
73
- options = getResp(singleRow ?? "small");
74
- }
75
- // Layout
76
- return (_jsxs(Grid2, { ...gridProps, ...options, children: [label != null && (_jsxs(Typography, { variant: "caption", component: "div", children: [label, ":"] })), typeof data === "object" ? (data) : (_jsx(Typography, { variant: "subtitle2", children: data }))] }));
77
- }
78
- function formatItemData(app, fieldData) {
79
- if (fieldData == null)
80
- return undefined;
81
- if (typeof fieldData === "string")
82
- return fieldData;
83
- if (fieldData instanceof Date)
84
- return app.formatDate(fieldData, "d");
85
- return `${fieldData}`;
86
- }
87
- function getResp(singleRow) {
88
- const size = typeof singleRow === "object"
89
- ? singleRow
90
- : singleRow === "medium"
91
- ? ViewPageSize.medium
92
- : singleRow === "large"
93
- ? ViewPageSize.large
94
- : singleRow === true
95
- ? ViewPageSize.line
96
- : singleRow === false
97
- ? ViewPageSize.smallLine
98
- : ViewPageSize.small;
99
- return size;
100
- }
101
- function getItemField(app, field, data) {
102
- // Item data and label
103
- let itemData, itemLabel, gridProps = {}, size;
104
- if (Array.isArray(field)) {
105
- const [fieldData, fieldType, renderProps, singleRow = "small"] = field;
106
- itemData = GridDataFormat(data[fieldData], fieldType, renderProps);
107
- itemLabel = app.get(fieldData) ?? fieldData;
108
- size = getResp(singleRow);
109
- gridProps = { size };
110
- }
111
- else if (typeof field === "object") {
112
- // Destruct
113
- const { data: fieldData, dataType, label: fieldLabel, renderProps, singleRow = "default", ...rest } = field;
114
- // Size
115
- size = getResp(singleRow);
116
- gridProps = {
117
- ...rest,
118
- size
119
- };
120
- // Field data
121
- if (typeof fieldData === "function")
122
- itemData = fieldData(data);
123
- else if (dataType == null)
124
- itemData = formatItemData(app, data[fieldData]);
125
- else
126
- itemData = GridDataFormat(data[fieldData], dataType, renderProps);
127
- // Field label
128
- itemLabel =
129
- fieldLabel === ""
130
- ? undefined
131
- : fieldLabel == null && typeof fieldData === "string"
132
- ? app.get(fieldData) ?? fieldData
133
- : typeof fieldLabel === "function"
134
- ? fieldLabel(data)
135
- : fieldLabel != null
136
- ? app.get(fieldLabel) ?? fieldLabel
137
- : undefined;
138
- }
139
- else {
140
- // Single field format
141
- itemData = formatItemData(app, data[field]);
142
- itemLabel = app.get(field) ?? field;
143
- size = ViewPageSize.small;
144
- gridProps = { size };
145
- }
146
- return [itemData, itemLabel, gridProps, size];
147
- }
148
- function getItemSize(bp, size) {
149
- const v = size[bp];
150
- if (v != null)
151
- return v;
152
- const index = breakpoints.indexOf(bp);
153
- for (let i = index; i >= 0; i--) {
154
- const v = size[breakpoints[i]];
155
- if (v != null)
156
- return v;
157
- }
158
- return 12;
159
- }
12
+ import { ViewContainer } from "../ViewContainer";
160
13
  /**
161
14
  * View page
162
15
  * @param props Props
163
16
  */
164
17
  export function ViewPage(props) {
165
- // Global app
166
- const app = useRequiredAppContext();
167
18
  // Destruct
168
- const { actions, children, fields, loadData, paddings = MUGlobal.pagePaddings, spacing = MUGlobal.half(MUGlobal.pagePaddings), actionPaddings = MUGlobal.pagePaddings, supportRefresh = true, fabColumnDirection = true, fabTop = true, supportBack = true, pullToRefresh = true, gridRef, operationMessageHandler, titleBar, leftContainer, leftContainerLines = 3, leftContainerProps = {}, ...rest } = props;
169
- // Current breakpoint
170
- const bp = useCurrentBreakpoint();
19
+ const { actions, children, fields, loadData, paddings = MUGlobal.pagePaddings, spacing, actionPaddings = MUGlobal.pagePaddings, supportRefresh = true, fabColumnDirection = true, fabTop = true, supportBack = true, pullToRefresh = true, gridRef, operationMessageHandler, titleBar, leftContainer, leftContainerLines, leftContainerProps, ...rest } = props;
171
20
  // Data
172
21
  const [data, setData] = React.useState();
173
22
  // Labels
174
23
  const labels = Labels.CommonPage;
175
24
  // Container
176
25
  const pullContainer = "#page-container";
177
- // Left container
178
- const { size = ViewPageSize.smallLine, ...leftContainerPropsRest } = leftContainerProps;
179
26
  // Load data
180
27
  const refresh = React.useCallback(async () => {
181
28
  const result = await loadData();
182
29
  // When failed or no data returned, show the loading bar
183
30
  setData(result);
184
31
  }, [loadData]);
185
- // Create fields
186
- const fieldIndexRef = React.useRef(0);
187
- const createFields = React.useCallback((data, maxItems = 0) => {
188
- let validItems = 0;
189
- const items = [];
190
- let i = fieldIndexRef.current;
191
- for (; i < fields.length; i++) {
192
- const field = fields[i];
193
- let oneSize;
194
- let oneItem;
195
- if (typeof field === "function") {
196
- // Most flexible way, do whatever you want
197
- const createdResult = field(data, refresh);
198
- if (createdResult == null || createdResult === "")
199
- continue;
200
- if (Array.isArray(createdResult)) {
201
- const [created, size] = createdResult;
202
- oneSize = size;
203
- oneItem = created;
204
- }
205
- else {
206
- oneSize = ViewPageSize.line;
207
- oneItem = createdResult;
208
- }
209
- }
210
- else {
211
- const [itemData, itemLabel, gridProps, size] = getItemField(app, field, data);
212
- // Some callback function may return '' instead of undefined
213
- if (itemData == null || itemData === "")
214
- continue;
215
- oneSize = size;
216
- oneItem = (_createElement(ViewPageGridItem, { ...gridProps, key: i, data: itemData, label: itemLabel }));
217
- }
218
- // Max lines
219
- if (maxItems > 0) {
220
- const itemSize = getItemSize(bp, oneSize);
221
- if (maxItems < validItems + itemSize) {
222
- fieldIndexRef.current = i;
223
- break;
224
- }
225
- else {
226
- items.push(oneItem);
227
- validItems += itemSize;
228
- }
229
- }
230
- else {
231
- items.push(oneItem);
232
- }
233
- }
234
- if (maxItems === 0) {
235
- fieldIndexRef.current = 0;
236
- }
237
- else {
238
- fieldIndexRef.current = i;
239
- }
240
- return items;
241
- }, [app, refresh, fields, data, bp]);
242
32
  React.useEffect(() => {
243
33
  const refreshHandler = async () => {
244
34
  await refresh();
@@ -248,7 +38,6 @@ export function ViewPage(props) {
248
38
  MessageUtils.offRefresh(refreshHandler);
249
39
  };
250
40
  }, [refresh]);
251
- let leftResult;
252
41
  return (_jsx(CommonPage, { paddings: paddings, onRefresh: supportRefresh ? refresh : undefined, onUpdate: supportRefresh ? undefined : refresh, sx: {
253
42
  ".MuiTypography-subtitle2": {
254
43
  fontWeight: "bold"
@@ -259,7 +48,7 @@ export function ViewPage(props) {
259
48
  refresh,
260
49
  operationMessageHandler.id
261
50
  ]
262
- : operationMessageHandler })), titleBar && titleBar(data), _jsxs(Grid2, { container: true, justifyContent: "left", className: "ET-ViewPage", ref: gridRef, spacing: spacing, children: [leftContainer && (leftResult = leftContainer(data)) != null && (_jsxs(React.Fragment, { children: [_jsx(Grid2, { container: true, className: "ET-ViewPage-LeftContainer", spacing: spacing, size: size, ...leftContainerPropsRest, children: leftResult }), _jsx(Grid2, { container: true, className: "ET-ViewPage-LeftOthers", spacing: spacing, size: ViewPageSize.matchSize(size), children: createFields(data, leftContainerLines * (12 - getItemSize(bp, size))) })] })), createFields(data)] }), actions !== null && (_jsx(Stack, { className: "ET-ViewPage-Actions", direction: "row", width: "100%", flexWrap: "wrap", justifyContent: "center", paddingTop: actions == null ? undefined : actionPaddings, paddingBottom: actionPaddings, gap: actionPaddings, children: actions != null && Utils.getResult(actions, data, refresh) })), Utils.getResult(children, data, refresh), pullToRefresh && (_jsx(PullToRefreshUI, { mainElement: pullContainer, triggerElement: pullContainer, instructionsPullToRefresh: labels.pullToRefresh, instructionsReleaseToRefresh: labels.releaseToRefresh, instructionsRefreshing: labels.refreshing, onRefresh: refresh, shouldPullToRefresh: () => {
51
+ : operationMessageHandler })), titleBar && titleBar(data), _jsx(ViewContainer, { data: data, fields: fields, gridRef: gridRef, leftContainer: leftContainer, leftContainerLines: leftContainerLines, leftContainerProps: leftContainerProps, refresh: refresh, spacing: spacing }), actions !== null && (_jsx(Stack, { className: "ET-ViewPage-Actions", direction: "row", width: "100%", flexWrap: "wrap", justifyContent: "center", paddingTop: actions == null ? undefined : actionPaddings, paddingBottom: actionPaddings, gap: actionPaddings, children: actions != null && Utils.getResult(actions, data, refresh) })), Utils.getResult(children, data, refresh), pullToRefresh && (_jsx(PullToRefreshUI, { mainElement: pullContainer, triggerElement: pullContainer, instructionsPullToRefresh: labels.pullToRefresh, instructionsReleaseToRefresh: labels.releaseToRefresh, instructionsRefreshing: labels.refreshing, onRefresh: refresh, shouldPullToRefresh: () => {
263
52
  const container = document.querySelector(pullContainer);
264
53
  return !container?.scrollTop;
265
54
  } })), _jsx(ScrollRestoration, {})] })) }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.4.99",
3
+ "version": "1.5.0",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/mjs/index.js",
@@ -43,7 +43,7 @@
43
43
  "@etsoo/appscript": "^1.6.19",
44
44
  "@etsoo/notificationbase": "^1.1.59",
45
45
  "@etsoo/react": "^1.8.33",
46
- "@etsoo/shared": "^1.2.62",
46
+ "@etsoo/shared": "^1.2.63",
47
47
  "@mui/icons-material": "^6.4.8",
48
48
  "@mui/material": "^6.4.8",
49
49
  "@mui/x-data-grid": "^7.28.0",
@@ -75,7 +75,7 @@
75
75
  "@testing-library/react": "^16.2.0",
76
76
  "@types/pica": "^9.0.5",
77
77
  "@types/pulltorefreshjs": "^0.1.7",
78
- "@types/react": "^18.3.18",
78
+ "@types/react": "^18.3.19",
79
79
  "@types/react-avatar-editor": "^13.0.4",
80
80
  "@types/react-dom": "^18.3.5",
81
81
  "@types/react-input-mask": "^3.0.6",