@etsoo/materialui 1.0.28 → 1.0.30

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/lib/SelectEx.d.ts CHANGED
@@ -53,6 +53,10 @@ export declare type SelectExProps<T extends object, D extends DataTypes.Keys<T>
53
53
  * Array of options.
54
54
  */
55
55
  options?: ReadonlyArray<T>;
56
+ /**
57
+ * Supports refresh label or component
58
+ */
59
+ refresh?: string | React.ReactNode;
56
60
  /**
57
61
  * Is search case?
58
62
  */
package/lib/SelectEx.js CHANGED
@@ -1,7 +1,8 @@
1
- import { Checkbox, FormControl, FormHelperText, InputLabel, ListItemText, MenuItem, OutlinedInput, Select } from '@mui/material';
1
+ import { Checkbox, FormControl, FormHelperText, IconButton, InputLabel, ListItemText, MenuItem, OutlinedInput, Select, Stack } from '@mui/material';
2
2
  import React from 'react';
3
3
  import { MUGlobal } from './MUGlobal';
4
4
  import { ListItemRightIcon } from './ListItemRightIcon';
5
+ import RefreshIcon from '@mui/icons-material/Refresh';
5
6
  import { Utils } from '@etsoo/shared';
6
7
  /**
7
8
  * Extended select component
@@ -11,7 +12,7 @@ import { Utils } from '@etsoo/shared';
11
12
  export function SelectEx(props) {
12
13
  var _a;
13
14
  // Destruct
14
- const { defaultValue, idField = 'id', error, helperText, inputRequired, itemIconRenderer, itemStyle, label, labelField = 'label', loadData, onItemChange, onItemClick, onLoadData, multiple = false, name, options, search = false, autoAddBlankItem = search, value, onChange, fullWidth, ...rest } = props;
15
+ const { defaultValue, idField = 'id', error, helperText, inputRequired, itemIconRenderer, itemStyle, label, labelField = 'label', loadData, onItemChange, onItemClick, onLoadData, multiple = false, name, options, refresh, search = false, autoAddBlankItem = search, value, onChange, fullWidth, ...rest } = props;
15
16
  // Options state
16
17
  const [localOptions, setOptions] = React.useState([]);
17
18
  const isMounted = React.useRef(true);
@@ -97,20 +98,24 @@ export function SelectEx(props) {
97
98
  };
98
99
  // Refs
99
100
  const divRef = React.useRef();
101
+ // Refresh list data
102
+ const refreshData = () => {
103
+ if (loadData == null)
104
+ return;
105
+ loadData().then((result) => {
106
+ if (result == null || !isMounted.current)
107
+ return;
108
+ if (onLoadData)
109
+ onLoadData(result);
110
+ if (autoAddBlankItem) {
111
+ Utils.addBlankItem(result, idField, labelField);
112
+ }
113
+ setOptionsAdd(result);
114
+ });
115
+ };
100
116
  // When value change
101
117
  React.useEffect(() => {
102
- if (loadData) {
103
- loadData().then((result) => {
104
- if (result == null || !isMounted.current)
105
- return;
106
- if (onLoadData)
107
- onLoadData(result);
108
- if (autoAddBlankItem) {
109
- Utils.addBlankItem(result, idField, labelField);
110
- }
111
- setOptionsAdd(result);
112
- });
113
- }
118
+ refreshData();
114
119
  }, [localValue]);
115
120
  // When layout ready
116
121
  React.useEffect(() => {
@@ -128,48 +133,53 @@ export function SelectEx(props) {
128
133
  };
129
134
  }, []);
130
135
  // Layout
131
- return (React.createElement(FormControl, { size: search ? MUGlobal.searchFieldSize : MUGlobal.inputFieldSize, fullWidth: fullWidth, error: error },
132
- React.createElement(InputLabel, { id: labelId, shrink: search
133
- ? MUGlobal.searchFieldShrink
134
- : MUGlobal.inputFieldShrink }, label),
135
- React.createElement(Select, { ref: divRef, value: localOptions.some((option) => itemChecked(getId(option)))
136
- ? valueState !== null && valueState !== void 0 ? valueState : ''
137
- : '', input: React.createElement(OutlinedInput, { notched: true, label: label, required: inputRequired }), labelId: labelId, name: name, multiple: multiple, onChange: (event, child) => {
138
- if (onChange) {
139
- onChange(event, child);
140
- // event.preventDefault() will block executing
141
- if (event.defaultPrevented)
142
- return;
143
- }
144
- doItemChange(localOptions, event.target.value, true);
145
- handleChange(event);
146
- }, renderValue: (selected) => {
147
- // The text shows up
148
- return localOptions
149
- .filter((option) => {
150
- const id = getId(option);
151
- return Array.isArray(selected)
152
- ? selected.indexOf(id) !== -1
153
- : selected === id;
154
- })
155
- .map((option) => getLabel(option))
156
- .join(', ');
157
- }, sx: { minWidth: '150px' }, fullWidth: fullWidth, ...rest }, localOptions.map((option) => {
158
- // Option id
159
- const id = getId(option);
160
- // Option label
161
- const label = getLabel(option);
162
- // Option
163
- return (React.createElement(MenuItem, { key: id, value: id, onClick: (event) => {
164
- if (onItemClick) {
165
- onItemClick(event, option);
136
+ return (React.createElement(Stack, { direction: "row" },
137
+ React.createElement(FormControl, { size: search ? MUGlobal.searchFieldSize : MUGlobal.inputFieldSize, fullWidth: fullWidth, error: error },
138
+ React.createElement(InputLabel, { id: labelId, shrink: search
139
+ ? MUGlobal.searchFieldShrink
140
+ : MUGlobal.inputFieldShrink }, label),
141
+ React.createElement(Select, { ref: divRef, value: localOptions.some((option) => itemChecked(getId(option)))
142
+ ? valueState !== null && valueState !== void 0 ? valueState : ''
143
+ : '', input: React.createElement(OutlinedInput, { notched: true, label: label, required: inputRequired }), labelId: labelId, name: name, multiple: multiple, onChange: (event, child) => {
144
+ if (onChange) {
145
+ onChange(event, child);
146
+ // event.preventDefault() will block executing
147
+ if (event.defaultPrevented)
148
+ return;
166
149
  }
167
- }, style: itemStyle == null
168
- ? undefined
169
- : itemStyle(option) },
170
- multiple && React.createElement(Checkbox, { checked: itemChecked(id) }),
171
- React.createElement(ListItemText, { primary: label }),
172
- itemIconRenderer && (React.createElement(ListItemRightIcon, null, itemIconRenderer(option[idField])))));
173
- })),
174
- helperText != null && (React.createElement(FormHelperText, null, helperText))));
150
+ doItemChange(localOptions, event.target.value, true);
151
+ handleChange(event);
152
+ }, renderValue: (selected) => {
153
+ // The text shows up
154
+ return localOptions
155
+ .filter((option) => {
156
+ const id = getId(option);
157
+ return Array.isArray(selected)
158
+ ? selected.indexOf(id) !== -1
159
+ : selected === id;
160
+ })
161
+ .map((option) => getLabel(option))
162
+ .join(', ');
163
+ }, sx: { minWidth: '150px' }, fullWidth: fullWidth, ...rest }, localOptions.map((option) => {
164
+ // Option id
165
+ const id = getId(option);
166
+ // Option label
167
+ const label = getLabel(option);
168
+ // Option
169
+ return (React.createElement(MenuItem, { key: id, value: id, onClick: (event) => {
170
+ if (onItemClick) {
171
+ onItemClick(event, option);
172
+ }
173
+ }, style: itemStyle == null
174
+ ? undefined
175
+ : itemStyle(option) },
176
+ multiple && (React.createElement(Checkbox, { checked: itemChecked(id) })),
177
+ React.createElement(ListItemText, { primary: label }),
178
+ itemIconRenderer && (React.createElement(ListItemRightIcon, null, itemIconRenderer(option[idField])))));
179
+ })),
180
+ helperText != null && (React.createElement(FormHelperText, null, helperText))),
181
+ refresh != null &&
182
+ loadData != null &&
183
+ (typeof refresh === 'string' ? (React.createElement(IconButton, { size: "small", title: refresh, onClick: refreshData },
184
+ React.createElement(RefreshIcon, null))) : (refresh))));
175
185
  }
@@ -28,6 +28,25 @@ export interface IReactAppBase {
28
28
  * User state
29
29
  */
30
30
  readonly userState: UserState<any>;
31
+ /**
32
+ * Is screen size down 'sm'
33
+ */
34
+ smDown?: boolean;
35
+ /**
36
+ * Is screen size up 'md'
37
+ */
38
+ mdUp?: boolean;
39
+ /**
40
+ * Get date format props
41
+ * @returns Props
42
+ */
43
+ getDateFormatProps(): object;
44
+ /**
45
+ * Get money format props
46
+ * @param currency Currency, if undefined, default currency applied
47
+ * @returns Props
48
+ */
49
+ getMoneyFormatProps(currency?: string): object;
31
50
  /**
32
51
  * Set page data
33
52
  * @param data Page data
@@ -43,6 +62,11 @@ export interface IReactAppBase {
43
62
  * @param title Page title
44
63
  */
45
64
  setPageTitle(title: string): void;
65
+ /**
66
+ * Show input dialog
67
+ * @param props Props
68
+ */
69
+ showInputDialog({ title, message, callback, ...rest }: InputDialogProps): INotificationReact;
46
70
  }
47
71
  /**
48
72
  * Core application interface
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -51,15 +51,15 @@
51
51
  "@emotion/css": "^11.10.0",
52
52
  "@emotion/react": "^11.10.4",
53
53
  "@emotion/styled": "^11.10.4",
54
- "@etsoo/appscript": "^1.2.96",
54
+ "@etsoo/appscript": "^1.2.97",
55
55
  "@etsoo/notificationbase": "^1.1.7",
56
- "@etsoo/react": "^1.6.2",
57
- "@etsoo/shared": "^1.1.57",
56
+ "@etsoo/react": "^1.6.3",
57
+ "@etsoo/shared": "^1.1.58",
58
58
  "@mui/icons-material": "^5.10.6",
59
59
  "@mui/material": "^5.10.6",
60
60
  "@types/pica": "^9.0.1",
61
61
  "@types/pulltorefreshjs": "^0.1.5",
62
- "@types/react": "^18.0.20",
62
+ "@types/react": "^18.0.21",
63
63
  "@types/react-avatar-editor": "^13.0.0",
64
64
  "@types/react-dom": "^18.0.6",
65
65
  "@types/react-input-mask": "^3.0.1",
@@ -71,7 +71,7 @@
71
71
  "react-dom": "^18.2.0",
72
72
  "react-draggable": "^4.4.5",
73
73
  "react-imask": "^6.4.3",
74
- "react-router-dom": "^6.4.0",
74
+ "react-router-dom": "^6.4.1",
75
75
  "react-window": "^1.8.7"
76
76
  },
77
77
  "devDependencies": {
@@ -83,15 +83,15 @@
83
83
  "@testing-library/jest-dom": "^5.16.5",
84
84
  "@testing-library/react": "^13.4.0",
85
85
  "@types/jest": "^29.0.3",
86
- "@typescript-eslint/eslint-plugin": "^5.38.0",
87
- "@typescript-eslint/parser": "^5.38.0",
88
- "eslint": "^8.23.1",
86
+ "@typescript-eslint/eslint-plugin": "^5.38.1",
87
+ "@typescript-eslint/parser": "^5.38.1",
88
+ "eslint": "^8.24.0",
89
89
  "eslint-config-airbnb-base": "^15.0.0",
90
90
  "eslint-plugin-import": "^2.26.0",
91
91
  "eslint-plugin-react": "^7.31.8",
92
92
  "jest": "^29.0.3",
93
93
  "jest-environment-jsdom": "^29.0.3",
94
- "ts-jest": "^29.0.1",
94
+ "ts-jest": "^29.0.2",
95
95
  "typescript": "^4.8.3"
96
96
  }
97
97
  }
package/src/SelectEx.tsx CHANGED
@@ -2,17 +2,20 @@ import {
2
2
  Checkbox,
3
3
  FormControl,
4
4
  FormHelperText,
5
+ IconButton,
5
6
  InputLabel,
6
7
  ListItemText,
7
8
  MenuItem,
8
9
  OutlinedInput,
9
10
  Select,
10
11
  SelectChangeEvent,
11
- SelectProps
12
+ SelectProps,
13
+ Stack
12
14
  } from '@mui/material';
13
15
  import React from 'react';
14
16
  import { MUGlobal } from './MUGlobal';
15
17
  import { ListItemRightIcon } from './ListItemRightIcon';
18
+ import RefreshIcon from '@mui/icons-material/Refresh';
16
19
  import {
17
20
  DataTypes,
18
21
  IdDefaultType,
@@ -89,6 +92,11 @@ export type SelectExProps<
89
92
  */
90
93
  options?: ReadonlyArray<T>;
91
94
 
95
+ /**
96
+ * Supports refresh label or component
97
+ */
98
+ refresh?: string | React.ReactNode;
99
+
92
100
  /**
93
101
  * Is search case?
94
102
  */
@@ -123,6 +131,7 @@ export function SelectEx<
123
131
  multiple = false,
124
132
  name,
125
133
  options,
134
+ refresh,
126
135
  search = false,
127
136
  autoAddBlankItem = search,
128
137
  value,
@@ -226,18 +235,22 @@ export function SelectEx<
226
235
  // Refs
227
236
  const divRef = React.useRef<HTMLDivElement>();
228
237
 
238
+ // Refresh list data
239
+ const refreshData = () => {
240
+ if (loadData == null) return;
241
+ loadData().then((result) => {
242
+ if (result == null || !isMounted.current) return;
243
+ if (onLoadData) onLoadData(result);
244
+ if (autoAddBlankItem) {
245
+ Utils.addBlankItem(result, idField, labelField);
246
+ }
247
+ setOptionsAdd(result);
248
+ });
249
+ };
250
+
229
251
  // When value change
230
252
  React.useEffect(() => {
231
- if (loadData) {
232
- loadData().then((result) => {
233
- if (result == null || !isMounted.current) return;
234
- if (onLoadData) onLoadData(result);
235
- if (autoAddBlankItem) {
236
- Utils.addBlankItem(result, idField, labelField);
237
- }
238
- setOptionsAdd(result);
239
- });
240
- }
253
+ refreshData();
241
254
  }, [localValue]);
242
255
 
243
256
  // When layout ready
@@ -257,101 +270,122 @@ export function SelectEx<
257
270
 
258
271
  // Layout
259
272
  return (
260
- <FormControl
261
- size={search ? MUGlobal.searchFieldSize : MUGlobal.inputFieldSize}
262
- fullWidth={fullWidth}
263
- error={error}
264
- >
265
- <InputLabel
266
- id={labelId}
267
- shrink={
268
- search
269
- ? MUGlobal.searchFieldShrink
270
- : MUGlobal.inputFieldShrink
273
+ <Stack direction="row">
274
+ <FormControl
275
+ size={
276
+ search ? MUGlobal.searchFieldSize : MUGlobal.inputFieldSize
271
277
  }
272
- >
273
- {label}
274
- </InputLabel>
275
- <Select
276
- ref={divRef}
277
- value={
278
- localOptions.some((option) => itemChecked(getId(option)))
279
- ? valueState ?? ''
280
- : ''
281
- }
282
- input={
283
- <OutlinedInput
284
- notched
285
- label={label}
286
- required={inputRequired}
287
- />
288
- }
289
- labelId={labelId}
290
- name={name}
291
- multiple={multiple}
292
- onChange={(event, child) => {
293
- if (onChange) {
294
- onChange(event, child);
295
-
296
- // event.preventDefault() will block executing
297
- if (event.defaultPrevented) return;
298
- }
299
- doItemChange(localOptions, event.target.value, true);
300
- handleChange(event);
301
- }}
302
- renderValue={(selected) => {
303
- // The text shows up
304
- return localOptions
305
- .filter((option) => {
306
- const id = getId(option);
307
- return Array.isArray(selected)
308
- ? selected.indexOf(id) !== -1
309
- : selected === id;
310
- })
311
- .map((option) => getLabel(option))
312
- .join(', ');
313
- }}
314
- sx={{ minWidth: '150px' }}
315
278
  fullWidth={fullWidth}
316
- {...rest}
279
+ error={error}
317
280
  >
318
- {localOptions.map((option) => {
319
- // Option id
320
- const id = getId(option);
321
-
322
- // Option label
323
- const label = getLabel(option);
324
-
325
- // Option
326
- return (
327
- <MenuItem
328
- key={id}
329
- value={id}
330
- onClick={(event) => {
331
- if (onItemClick) {
332
- onItemClick(event, option);
281
+ <InputLabel
282
+ id={labelId}
283
+ shrink={
284
+ search
285
+ ? MUGlobal.searchFieldShrink
286
+ : MUGlobal.inputFieldShrink
287
+ }
288
+ >
289
+ {label}
290
+ </InputLabel>
291
+ <Select
292
+ ref={divRef}
293
+ value={
294
+ localOptions.some((option) =>
295
+ itemChecked(getId(option))
296
+ )
297
+ ? valueState ?? ''
298
+ : ''
299
+ }
300
+ input={
301
+ <OutlinedInput
302
+ notched
303
+ label={label}
304
+ required={inputRequired}
305
+ />
306
+ }
307
+ labelId={labelId}
308
+ name={name}
309
+ multiple={multiple}
310
+ onChange={(event, child) => {
311
+ if (onChange) {
312
+ onChange(event, child);
313
+
314
+ // event.preventDefault() will block executing
315
+ if (event.defaultPrevented) return;
316
+ }
317
+ doItemChange(localOptions, event.target.value, true);
318
+ handleChange(event);
319
+ }}
320
+ renderValue={(selected) => {
321
+ // The text shows up
322
+ return localOptions
323
+ .filter((option) => {
324
+ const id = getId(option);
325
+ return Array.isArray(selected)
326
+ ? selected.indexOf(id) !== -1
327
+ : selected === id;
328
+ })
329
+ .map((option) => getLabel(option))
330
+ .join(', ');
331
+ }}
332
+ sx={{ minWidth: '150px' }}
333
+ fullWidth={fullWidth}
334
+ {...rest}
335
+ >
336
+ {localOptions.map((option) => {
337
+ // Option id
338
+ const id = getId(option);
339
+
340
+ // Option label
341
+ const label = getLabel(option);
342
+
343
+ // Option
344
+ return (
345
+ <MenuItem
346
+ key={id}
347
+ value={id}
348
+ onClick={(event) => {
349
+ if (onItemClick) {
350
+ onItemClick(event, option);
351
+ }
352
+ }}
353
+ style={
354
+ itemStyle == null
355
+ ? undefined
356
+ : itemStyle(option)
333
357
  }
334
- }}
335
- style={
336
- itemStyle == null
337
- ? undefined
338
- : itemStyle(option)
339
- }
340
- >
341
- {multiple && <Checkbox checked={itemChecked(id)} />}
342
- <ListItemText primary={label} />
343
- {itemIconRenderer && (
344
- <ListItemRightIcon>
345
- {itemIconRenderer(option[idField])}
346
- </ListItemRightIcon>
347
- )}
348
- </MenuItem>
349
- );
350
- })}
351
- </Select>
352
- {helperText != null && (
353
- <FormHelperText>{helperText}</FormHelperText>
354
- )}
355
- </FormControl>
358
+ >
359
+ {multiple && (
360
+ <Checkbox checked={itemChecked(id)} />
361
+ )}
362
+ <ListItemText primary={label} />
363
+ {itemIconRenderer && (
364
+ <ListItemRightIcon>
365
+ {itemIconRenderer(option[idField])}
366
+ </ListItemRightIcon>
367
+ )}
368
+ </MenuItem>
369
+ );
370
+ })}
371
+ </Select>
372
+ {helperText != null && (
373
+ <FormHelperText>{helperText}</FormHelperText>
374
+ )}
375
+ </FormControl>
376
+ {refresh != null &&
377
+ loadData != null &&
378
+ (typeof refresh === 'string' ? (
379
+ <IconButton
380
+ size="small"
381
+ title={refresh}
382
+ onClick={refreshData}
383
+ >
384
+ <RefreshIcon />
385
+ </IconButton>
386
+ ) : (
387
+ refresh
388
+ ))}
389
+ </Stack>
356
390
  );
357
391
  }
@@ -92,6 +92,29 @@ export interface IReactAppBase {
92
92
  */
93
93
  readonly userState: UserState<any>;
94
94
 
95
+ /**
96
+ * Is screen size down 'sm'
97
+ */
98
+ smDown?: boolean;
99
+
100
+ /**
101
+ * Is screen size up 'md'
102
+ */
103
+ mdUp?: boolean;
104
+
105
+ /**
106
+ * Get date format props
107
+ * @returns Props
108
+ */
109
+ getDateFormatProps(): object;
110
+
111
+ /**
112
+ * Get money format props
113
+ * @param currency Currency, if undefined, default currency applied
114
+ * @returns Props
115
+ */
116
+ getMoneyFormatProps(currency?: string): object;
117
+
95
118
  /**
96
119
  * Set page data
97
120
  * @param data Page data
@@ -109,6 +132,17 @@ export interface IReactAppBase {
109
132
  * @param title Page title
110
133
  */
111
134
  setPageTitle(title: string): void;
135
+
136
+ /**
137
+ * Show input dialog
138
+ * @param props Props
139
+ */
140
+ showInputDialog({
141
+ title,
142
+ message,
143
+ callback,
144
+ ...rest
145
+ }: InputDialogProps): INotificationReact;
112
146
  }
113
147
 
114
148
  /**