@etsoo/react 1.4.39 → 1.4.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.
@@ -8,6 +8,7 @@ export declare namespace Labels {
8
8
  */
9
9
  const CommonPage: {
10
10
  add: string;
11
+ delete: string;
11
12
  more: string;
12
13
  pullToRefresh: string;
13
14
  refresh: string;
package/lib/app/Labels.js CHANGED
@@ -9,6 +9,7 @@ export var Labels;
9
9
  */
10
10
  Labels.CommonPage = {
11
11
  add: 'Add',
12
+ delete: 'Delete',
12
13
  more: 'More',
13
14
  pullToRefresh: 'Pull down to refresh',
14
15
  refresh: 'Refresh',
@@ -67,7 +67,7 @@ export var DataGridRenderers;
67
67
  if (value)
68
68
  return React.createElement(CheckIcon, { fontSize: "small" });
69
69
  else
70
- return React.createElement(ClearIcon, { fontSize: "small", color: "error" });
70
+ return React.createElement(ClearIcon, { fontSize: "small", color: "warning" });
71
71
  }
72
72
  // To string
73
73
  return new String(value);
@@ -63,8 +63,15 @@ export declare class MUGlobal {
63
63
  * @returns Updated object
64
64
  */
65
65
  static adjustWithTheme(size: number, adjust: {}, updateFunc: (value: number) => string): {};
66
+ /**
67
+ * Break points defined
68
+ */
69
+ static breakpoints: readonly ["xs", "sm", "md", "lg", "xl"];
66
70
  /**
67
71
  * Get multple medias theme space
72
+ * Responsive values and Breakpoints as an object
73
+ * xs = theme.breakpoints.up('xs')
74
+ * https://mui.com/system/basics/
68
75
  * @param spaces Spaces
69
76
  * @param theme Theme
70
77
  * @returns Result
@@ -72,14 +72,19 @@ export class MUGlobal {
72
72
  }
73
73
  /**
74
74
  * Get multple medias theme space
75
+ * Responsive values and Breakpoints as an object
76
+ * xs = theme.breakpoints.up('xs')
77
+ * https://mui.com/system/basics/
75
78
  * @param spaces Spaces
76
79
  * @param theme Theme
77
80
  * @returns Result
78
81
  */
79
82
  static getSpace(spaces, theme) {
80
- for (const [key, value] of Object.entries(spaces)) {
81
- if (typeof value === 'number' &&
82
- theme.breakpoints.keys.findIndex((bk) => bk === key) != -1) {
83
+ const start = this.breakpoints.length - 1;
84
+ for (let i = start; i >= 0; i--) {
85
+ const key = this.breakpoints[i];
86
+ const value = Reflect.get(spaces, key);
87
+ if (typeof value === 'number') {
83
88
  const mediaRaw = theme.breakpoints.up(key);
84
89
  const mediaQuery = mediaRaw.substring(mediaRaw.indexOf('('));
85
90
  if (window.matchMedia(mediaQuery).matches) {
@@ -137,3 +142,7 @@ MUGlobal.textFieldVariant = 'filled';
137
142
  * Page default paddings
138
143
  */
139
144
  MUGlobal.pagePaddings = { xs: 2, sm: 3 };
145
+ /**
146
+ * Break points defined
147
+ */
148
+ MUGlobal.breakpoints = ['xs', 'sm', 'md', 'lg', 'xl'];
@@ -111,18 +111,25 @@ export function ScrollerListEx(props) {
111
111
  : false;
112
112
  return selected;
113
113
  };
114
+ // Destruct
115
+ const { alternatingColors = [undefined, undefined], className, idField = 'id', innerItemRenderer, itemSize, itemKey = (index, data) => { var _a; return (_a = DataTypes.getIdValue(data, idField)) !== null && _a !== void 0 ? _a : index; }, itemRenderer = (itemProps) => {
116
+ const [itemHeight, space, margins] = calculateItemSize(itemProps.index);
117
+ return defaultItemRenderer({
118
+ itemHeight,
119
+ innerItemRenderer,
120
+ onMouseDown,
121
+ space,
122
+ margins,
123
+ selected: isSelected(itemProps.data),
124
+ ...itemProps
125
+ });
126
+ }, onSelectChange, selectedColor = '#edf4fb', ...rest } = props;
114
127
  // Theme
115
128
  const theme = useTheme();
116
- // Calculate size
117
- const calculateItemSize = (index) => {
118
- // Callback function
119
- if (typeof itemSize === 'function') {
120
- const result = itemSize(index);
121
- if (result.length == 2)
122
- return [...result, defaultMargin(MUGlobal.pagePaddings)];
123
- return result;
124
- }
125
- // Calculation
129
+ // Cache calculation
130
+ const itemSizeResult = React.useMemo(() => {
131
+ if (typeof itemSize === 'function')
132
+ return undefined;
126
133
  const [size, spaces, isNarrow] = itemSize;
127
134
  if (typeof spaces === 'number')
128
135
  return [
@@ -135,25 +142,24 @@ export function ScrollerListEx(props) {
135
142
  MUGlobal.getSpace(spaces, theme),
136
143
  defaultMargin(spaces, isNarrow)
137
144
  ];
145
+ }, [itemSize]);
146
+ // Calculate size
147
+ const calculateItemSize = (index) => {
148
+ // Callback function
149
+ if (typeof itemSize === 'function') {
150
+ const result = itemSize(index);
151
+ if (result.length == 2)
152
+ return [...result, defaultMargin(MUGlobal.pagePaddings)];
153
+ return result;
154
+ }
155
+ // Calculation
156
+ return itemSizeResult;
138
157
  };
139
158
  // Local item size
140
159
  const itemSizeLocal = (index) => {
141
160
  const [size, space] = calculateItemSize(index);
142
161
  return size + space;
143
162
  };
144
- // Destruct
145
- const { alternatingColors = [undefined, undefined], className, idField = 'id', innerItemRenderer, itemSize, itemKey = (index, data) => { var _a; return (_a = DataTypes.getIdValue(data, idField)) !== null && _a !== void 0 ? _a : index; }, itemRenderer = (itemProps) => {
146
- const [itemHeight, space, margins] = calculateItemSize(itemProps.index);
147
- return defaultItemRenderer({
148
- itemHeight,
149
- innerItemRenderer,
150
- onMouseDown,
151
- space,
152
- margins,
153
- selected: isSelected(itemProps.data),
154
- ...itemProps
155
- });
156
- }, onSelectChange, selectedColor = '#edf4fb', ...rest } = props;
157
163
  // Layout
158
164
  return (React.createElement(ScrollerList, { className: Utils.mergeClasses('ScrollerListEx-Body', className, createGridStyle(alternatingColors, selectedColor)), itemKey: itemKey, itemRenderer: itemRenderer, itemSize: itemSizeLocal, ...rest }));
159
165
  }
@@ -12,6 +12,10 @@ export interface TabBoxPanel extends Omit<TabProps, 'value' | 'children'> {
12
12
  * Panel box props
13
13
  */
14
14
  panel?: Omit<BoxProps, 'hidden'>;
15
+ /**
16
+ * To URL
17
+ */
18
+ to?: string;
15
19
  }
16
20
  /**
17
21
  * Tabs with box props
package/lib/mu/TabBox.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Utils } from '@etsoo/shared';
2
2
  import { Box, Tab, Tabs } from '@mui/material';
3
+ import { Link } from '@reach/router';
3
4
  import React from 'react';
4
5
  /**
5
6
  * Tabs with box
@@ -25,6 +26,6 @@ export function TabBox(props) {
25
26
  setValue(newValue);
26
27
  if (onChange)
27
28
  onChange(event, newValue);
28
- }, ...rest }, tabs.map(({ children, panel, ...tabRest }, index) => (React.createElement(Tab, { key: index, value: index, ...tabRest }))))),
29
+ }, ...rest }, tabs.map(({ children, panel, ...tabRest }, index) => (React.createElement(Tab, { key: index, value: index, LinkComponent: tabRest.to ? Link : undefined, ...tabRest }))))),
29
30
  tabs.map(({ children, panel }, index) => (React.createElement(Box, { key: index, hidden: value !== index, ...panel }, Utils.getResult(children, value === index))))));
30
31
  }
@@ -4,10 +4,18 @@ import { CommonPageProps } from './CommonPageProps';
4
4
  * Add / Edit page props
5
5
  */
6
6
  export interface EditPageProps extends Omit<CommonPageProps, 'onSubmit'> {
7
+ /**
8
+ * Is editing
9
+ */
10
+ isEditing?: boolean;
7
11
  /**
8
12
  * On form submit
9
13
  */
10
14
  onSubmit?: FormEventHandler<HTMLFormElement>;
15
+ /**
16
+ * On delete callback
17
+ */
18
+ onDelete?: () => Promise<void> | void;
11
19
  }
12
20
  /**
13
21
  * Add / Edit page
@@ -4,22 +4,24 @@ import { Labels } from '../../app/Labels';
4
4
  import { MUGlobal } from '../MUGlobal';
5
5
  import { CommonPage, CommonPageScrollContainer } from './CommonPage';
6
6
  import SaveIcon from '@mui/icons-material/Save';
7
+ import DeleteIcon from '@mui/icons-material/Delete';
7
8
  /**
8
9
  * Add / Edit page
9
10
  * @param props Props
10
11
  */
11
12
  export function EditPage(props) {
12
13
  // Destruct
13
- const { children, onSubmit, paddings = MUGlobal.pagePaddings, scrollContainer = CommonPageScrollContainer, ...rest } = props;
14
+ const { children, isEditing, onDelete, onSubmit, paddings = MUGlobal.pagePaddings, scrollContainer = CommonPageScrollContainer, ...rest } = props;
14
15
  // Labels
15
16
  const labels = Labels.CommonPage;
16
17
  return (React.createElement(CommonPage, { paddings: paddings, scrollContainer: scrollContainer, ...rest },
17
18
  React.createElement("form", { onSubmit: onSubmit },
18
19
  React.createElement(Grid, { container: true, justifyContent: "left", spacing: paddings, paddingTop: 1 }, children),
19
- React.createElement(Grid, { container: true, position: "sticky", sx: {
20
+ React.createElement(Grid, { container: true, position: "sticky", display: "flex", gap: paddings, sx: {
20
21
  top: 'auto',
21
22
  bottom: (theme) => MUGlobal.updateWithTheme(paddings, theme.spacing),
22
23
  paddingTop: paddings
23
24
  } },
24
- React.createElement(Button, { variant: "contained", type: "submit", fullWidth: true, startIcon: React.createElement(SaveIcon, null) }, labels.save)))));
25
+ isEditing && onDelete && (React.createElement(Button, { color: "primary", variant: "outlined", onClick: () => onDelete(), startIcon: React.createElement(DeleteIcon, { color: "warning" }) }, labels.delete)),
26
+ React.createElement(Button, { variant: "contained", type: "submit", startIcon: React.createElement(SaveIcon, null), sx: { flexGrow: 1 } }, labels.save)))));
25
27
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/react",
3
- "version": "1.4.39",
3
+ "version": "1.4.43",
4
4
  "description": "TypeScript ReactJs framework",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -50,7 +50,7 @@
50
50
  "@emotion/react": "^11.7.1",
51
51
  "@emotion/style": "^0.8.0",
52
52
  "@emotion/styled": "^11.6.0",
53
- "@etsoo/appscript": "^1.2.22",
53
+ "@etsoo/appscript": "^1.2.23",
54
54
  "@etsoo/notificationbase": "^1.1.0",
55
55
  "@etsoo/shared": "^1.1.3",
56
56
  "@mui/icons-material": "^5.2.5",
package/src/app/Labels.ts CHANGED
@@ -9,6 +9,7 @@ export namespace Labels {
9
9
  */
10
10
  export const CommonPage = {
11
11
  add: 'Add',
12
+ delete: 'Delete',
12
13
  more: 'More',
13
14
  pullToRefresh: 'Pull down to refresh',
14
15
  refresh: 'Refresh',
@@ -103,7 +103,7 @@ export namespace DataGridRenderers {
103
103
  }
104
104
 
105
105
  if (value) return <CheckIcon fontSize="small" />;
106
- else return <ClearIcon fontSize="small" color="error" />;
106
+ else return <ClearIcon fontSize="small" color="warning" />;
107
107
  }
108
108
 
109
109
  // To string
@@ -126,18 +126,26 @@ export class MUGlobal {
126
126
  return newObj;
127
127
  }
128
128
 
129
+ /**
130
+ * Break points defined
131
+ */
132
+ static breakpoints = ['xs', 'sm', 'md', 'lg', 'xl'] as const;
133
+
129
134
  /**
130
135
  * Get multple medias theme space
136
+ * Responsive values and Breakpoints as an object
137
+ * xs = theme.breakpoints.up('xs')
138
+ * https://mui.com/system/basics/
131
139
  * @param spaces Spaces
132
140
  * @param theme Theme
133
141
  * @returns Result
134
142
  */
135
143
  static getSpace(spaces: {}, theme: Theme) {
136
- for (const [key, value] of Object.entries(spaces)) {
137
- if (
138
- typeof value === 'number' &&
139
- theme.breakpoints.keys.findIndex((bk) => bk === key) != -1
140
- ) {
144
+ const start = this.breakpoints.length - 1;
145
+ for (let i = start; i >= 0; i--) {
146
+ const key = this.breakpoints[i];
147
+ const value = Reflect.get(spaces, key);
148
+ if (typeof value === 'number') {
141
149
  const mediaRaw = theme.breakpoints.up(key as Breakpoint);
142
150
  const mediaQuery = mediaRaw.substring(mediaRaw.indexOf('('));
143
151
  if (window.matchMedia(mediaQuery).matches) {
@@ -145,6 +153,7 @@ export class MUGlobal {
145
153
  }
146
154
  }
147
155
  }
156
+
148
157
  return 0;
149
158
  }
150
159
 
@@ -265,41 +265,6 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
265
265
  return selected;
266
266
  };
267
267
 
268
- // Theme
269
- const theme = useTheme();
270
-
271
- // Calculate size
272
- const calculateItemSize = (index: number): [number, number, {}] => {
273
- // Callback function
274
- if (typeof itemSize === 'function') {
275
- const result = itemSize(index);
276
- if (result.length == 2)
277
- return [...result, defaultMargin(MUGlobal.pagePaddings)];
278
- return result;
279
- }
280
-
281
- // Calculation
282
- const [size, spaces, isNarrow] = itemSize;
283
- if (typeof spaces === 'number')
284
- return [
285
- size,
286
- spaces,
287
- defaultMargin(MUGlobal.pagePaddings, undefined)
288
- ];
289
-
290
- return [
291
- size,
292
- MUGlobal.getSpace(spaces, theme),
293
- defaultMargin(spaces, isNarrow)
294
- ];
295
- };
296
-
297
- // Local item size
298
- const itemSizeLocal = (index: number) => {
299
- const [size, space] = calculateItemSize(index);
300
- return size + space;
301
- };
302
-
303
268
  // Destruct
304
269
  const {
305
270
  alternatingColors = [undefined, undefined],
@@ -328,6 +293,49 @@ export function ScrollerListEx<T extends Record<string, unknown>>(
328
293
  ...rest
329
294
  } = props;
330
295
 
296
+ // Theme
297
+ const theme = useTheme();
298
+
299
+ // Cache calculation
300
+ const itemSizeResult = React.useMemo(():
301
+ | [number, number, {}]
302
+ | undefined => {
303
+ if (typeof itemSize === 'function') return undefined;
304
+ const [size, spaces, isNarrow] = itemSize;
305
+ if (typeof spaces === 'number')
306
+ return [
307
+ size,
308
+ spaces,
309
+ defaultMargin(MUGlobal.pagePaddings, undefined)
310
+ ];
311
+
312
+ return [
313
+ size,
314
+ MUGlobal.getSpace(spaces, theme),
315
+ defaultMargin(spaces, isNarrow)
316
+ ];
317
+ }, [itemSize]);
318
+
319
+ // Calculate size
320
+ const calculateItemSize = (index: number): [number, number, {}] => {
321
+ // Callback function
322
+ if (typeof itemSize === 'function') {
323
+ const result = itemSize(index);
324
+ if (result.length == 2)
325
+ return [...result, defaultMargin(MUGlobal.pagePaddings)];
326
+ return result;
327
+ }
328
+
329
+ // Calculation
330
+ return itemSizeResult!;
331
+ };
332
+
333
+ // Local item size
334
+ const itemSizeLocal = (index: number) => {
335
+ const [size, space] = calculateItemSize(index);
336
+ return size + space;
337
+ };
338
+
331
339
  // Layout
332
340
  return (
333
341
  <ScrollerList<T>
package/src/mu/TabBox.tsx CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Utils } from '@etsoo/shared';
2
2
  import { Box, BoxProps, Tab, TabProps, Tabs, TabsProps } from '@mui/material';
3
+ import { Link } from '@reach/router';
3
4
  import React from 'react';
4
5
 
5
6
  /**
@@ -15,6 +16,11 @@ export interface TabBoxPanel extends Omit<TabProps, 'value' | 'children'> {
15
16
  * Panel box props
16
17
  */
17
18
  panel?: Omit<BoxProps, 'hidden'>;
19
+
20
+ /**
21
+ * To URL
22
+ */
23
+ to?: string;
18
24
  }
19
25
 
20
26
  /**
@@ -93,7 +99,12 @@ export function TabBox(props: TabBoxPros) {
93
99
  {...rest}
94
100
  >
95
101
  {tabs.map(({ children, panel, ...tabRest }, index) => (
96
- <Tab key={index} value={index} {...tabRest} />
102
+ <Tab
103
+ key={index}
104
+ value={index}
105
+ LinkComponent={tabRest.to ? Link : undefined}
106
+ {...tabRest}
107
+ />
97
108
  ))}
98
109
  </Tabs>
99
110
  </Box>
@@ -5,15 +5,26 @@ import { MUGlobal } from '../MUGlobal';
5
5
  import { CommonPage, CommonPageScrollContainer } from './CommonPage';
6
6
  import { CommonPageProps } from './CommonPageProps';
7
7
  import SaveIcon from '@mui/icons-material/Save';
8
+ import DeleteIcon from '@mui/icons-material/Delete';
8
9
 
9
10
  /**
10
11
  * Add / Edit page props
11
12
  */
12
13
  export interface EditPageProps extends Omit<CommonPageProps, 'onSubmit'> {
14
+ /**
15
+ * Is editing
16
+ */
17
+ isEditing?: boolean;
18
+
13
19
  /**
14
20
  * On form submit
15
21
  */
16
22
  onSubmit?: FormEventHandler<HTMLFormElement>;
23
+
24
+ /**
25
+ * On delete callback
26
+ */
27
+ onDelete?: () => Promise<void> | void;
17
28
  }
18
29
 
19
30
  /**
@@ -24,6 +35,8 @@ export function EditPage(props: EditPageProps) {
24
35
  // Destruct
25
36
  const {
26
37
  children,
38
+ isEditing,
39
+ onDelete,
27
40
  onSubmit,
28
41
  paddings = MUGlobal.pagePaddings,
29
42
  scrollContainer = CommonPageScrollContainer,
@@ -51,6 +64,8 @@ export function EditPage(props: EditPageProps) {
51
64
  <Grid
52
65
  container
53
66
  position="sticky"
67
+ display="flex"
68
+ gap={paddings}
54
69
  sx={{
55
70
  top: 'auto',
56
71
  bottom: (theme) =>
@@ -58,11 +73,21 @@ export function EditPage(props: EditPageProps) {
58
73
  paddingTop: paddings
59
74
  }}
60
75
  >
76
+ {isEditing && onDelete && (
77
+ <Button
78
+ color="primary"
79
+ variant="outlined"
80
+ onClick={() => onDelete()}
81
+ startIcon={<DeleteIcon color="warning" />}
82
+ >
83
+ {labels.delete}
84
+ </Button>
85
+ )}
61
86
  <Button
62
87
  variant="contained"
63
88
  type="submit"
64
- fullWidth
65
89
  startIcon={<SaveIcon />}
90
+ sx={{ flexGrow: 1 }}
66
91
  >
67
92
  {labels.save}
68
93
  </Button>