@etsoo/materialui 1.3.32 → 1.3.34

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.
@@ -2,8 +2,7 @@ import { Autocomplete, AutocompleteProps } from "@mui/material";
2
2
  import React from "react";
3
3
  import { globalApp } from "./app/ReactApp";
4
4
  import { InputField, InputFieldProps } from "./InputField";
5
- import { ListType2 } from "@etsoo/shared";
6
- import { MUUtils } from "./MUUtils";
5
+ import { DataTypes, ListType2 } from "@etsoo/shared";
7
6
 
8
7
  export type ComboBoxProProps<D extends ListType2 = ListType2> = Omit<
9
8
  AutocompleteProps<D, false, false, true>,
@@ -131,7 +130,7 @@ export function ComboBoxPro<D extends ListType2 = ListType2>(
131
130
  />
132
131
  )}
133
132
  getOptionLabel={(item) =>
134
- typeof item === "object" ? MUUtils.getListItemLabel(item) : item
133
+ typeof item === "object" ? DataTypes.getListItemLabel(item) : item
135
134
  }
136
135
  isOptionEqualToValue={(option, value) => option.id === value.id}
137
136
  noOptionsText={noOptionsText}
@@ -0,0 +1,71 @@
1
+ import {
2
+ FormControl,
3
+ FormControlProps,
4
+ FormHelperText,
5
+ InputLabel
6
+ } from "@mui/material";
7
+ import NotchedOutline from "@mui/material/OutlinedInput";
8
+ import React from "react";
9
+
10
+ /**
11
+ * FieldSetEx props
12
+ */
13
+ export type FieldSetExProps = Omit<
14
+ FormControlProps,
15
+ "defaultValue" | "variant"
16
+ > & {
17
+ /**
18
+ * Label
19
+ */
20
+ label?: string;
21
+
22
+ /**
23
+ * Helper text
24
+ */
25
+ helperText?: React.ReactNode;
26
+ };
27
+
28
+ /**
29
+ * FieldSetEx
30
+ * @param props Props
31
+ * @returns Component
32
+ */
33
+ export function FieldSetEx(props: FieldSetExProps) {
34
+ // Destruct
35
+ const { label, helperText, required, fullWidth, children, ...rest } = props;
36
+
37
+ // Layout
38
+ return (
39
+ <React.Fragment>
40
+ <FormControl fullWidth={fullWidth} {...rest}>
41
+ {label && (
42
+ <InputLabel required={required} variant="outlined" shrink>
43
+ {label}
44
+ </InputLabel>
45
+ )}
46
+ <NotchedOutline
47
+ label={label && required ? label + " *" : label}
48
+ notched
49
+ endAdornment={children}
50
+ sx={{
51
+ cursor: "default",
52
+ display: "flex",
53
+ flexWrap: "wrap",
54
+ gap: 1,
55
+ paddingX: 2,
56
+ paddingY: "7px",
57
+ width: fullWidth ? "100%" : "auto",
58
+ "& input": {
59
+ display: "none"
60
+ }
61
+ }}
62
+ />
63
+ </FormControl>
64
+ {helperText && (
65
+ <FormHelperText sx={{ marginLeft: 2, marginRight: 2 }}>
66
+ {helperText}
67
+ </FormHelperText>
68
+ )}
69
+ </React.Fragment>
70
+ );
71
+ }
package/src/MUUtils.ts CHANGED
@@ -1,23 +1,9 @@
1
- import { ListType2 } from "@etsoo/shared";
2
1
  import { GridApiCommunity } from "@mui/x-data-grid/models/api/gridApiCommunity";
3
2
 
4
3
  /**
5
4
  * MU utilities
6
5
  */
7
6
  export namespace MUUtils {
8
- /**
9
- * Get ListType2 item label
10
- * @param item Item
11
- * @returns Result
12
- */
13
- export function getListItemLabel(item: ListType2) {
14
- return "label" in item
15
- ? item.label
16
- : "name" in item
17
- ? item.name
18
- : item.title;
19
- }
20
-
21
7
  /**
22
8
  * Get grid data
23
9
  * @param grid Grid
@@ -38,7 +38,7 @@ export type OptionGroupProps<
38
38
  T extends object,
39
39
  D extends DataTypes.Keys<T>,
40
40
  L extends DataTypes.Keys<T, string>
41
- > = Omit<FormControlProps<"fieldset">, "defaultValue"> & {
41
+ > = Omit<FormControlProps, "defaultValue"> & {
42
42
  /**
43
43
  * Default value
44
44
  */
@@ -104,11 +104,6 @@ export type OptionGroupProps<
104
104
  */
105
105
  itemSize?: "small" | "medium";
106
106
 
107
- /**
108
- * Item height in px
109
- */
110
- itemHeight?: number;
111
-
112
107
  /**
113
108
  * Helper text
114
109
  */
@@ -140,28 +135,16 @@ export function OptionGroup<
140
135
  readOnly,
141
136
  row,
142
137
  itemSize,
143
- itemHeight = row ? 56 : 42,
144
138
  helperText,
145
139
  variant,
146
140
  required,
147
141
  fullWidth,
148
- sx = {},
149
142
  ...rest
150
143
  } = props;
151
144
 
152
145
  // Outlined
153
146
  const outlined = variant === "outlined";
154
147
 
155
- if (sx) {
156
- Object.assign(sx, {
157
- height: outlined
158
- ? row
159
- ? `${itemHeight}px`
160
- : `${options.length * itemHeight + 14}px`
161
- : undefined
162
- });
163
- }
164
-
165
148
  // Get option value
166
149
  // D type should be the source id type
167
150
  const getOptionValue = (option: T): T[D] | null => {
@@ -292,33 +275,34 @@ export function OptionGroup<
292
275
  // Layout
293
276
  return (
294
277
  <React.Fragment>
295
- <FormControl component="fieldset" fullWidth={fullWidth} sx={sx} {...rest}>
278
+ <FormControl fullWidth={fullWidth} {...rest}>
296
279
  {label && (
297
280
  <InputLabel required={required} variant={variant} shrink>
298
281
  {label}
299
282
  </InputLabel>
300
283
  )}
301
- {outlined && (
284
+ {outlined ? (
302
285
  <NotchedOutline
303
286
  label={label && required ? label + " *" : label}
304
287
  notched
288
+ endAdornment={group}
305
289
  sx={{
306
290
  cursor: "default",
307
- position: "absolute",
291
+ display: "flex",
292
+ gap: 1,
293
+ paddingX: 2,
294
+ paddingY: "7px",
308
295
  width: fullWidth ? "100%" : "auto",
309
296
  "& input": {
310
- visibility: "hidden"
297
+ display: "none"
311
298
  }
312
299
  }}
313
300
  />
301
+ ) : (
302
+ <Box paddingLeft={2} paddingY="7px">
303
+ {group}
304
+ </Box>
314
305
  )}
315
- <Box
316
- paddingLeft={2}
317
- paddingY="7px"
318
- position={outlined ? "absolute" : undefined}
319
- >
320
- {group}
321
- </Box>
322
306
  </FormControl>
323
307
  {helperText && (
324
308
  <FormHelperText sx={{ marginLeft: 2, marginRight: 2 }}>
@@ -0,0 +1,266 @@
1
+ import {
2
+ DataTypes,
3
+ IdDefaultType,
4
+ LabelDefaultType,
5
+ ListType,
6
+ Utils
7
+ } from "@etsoo/shared";
8
+ import {
9
+ Box,
10
+ Checkbox,
11
+ FormControl,
12
+ FormControlLabel,
13
+ FormControlProps,
14
+ FormGroup,
15
+ FormHelperText,
16
+ InputLabel
17
+ } from "@mui/material";
18
+ import NotchedOutline from "@mui/material/OutlinedInput";
19
+ import React from "react";
20
+
21
+ /**
22
+ * OptionGroupFlag methods ref
23
+ */
24
+ export interface OptionGroupFlagRef {
25
+ /**
26
+ * Disable specific items with their ids
27
+ * @param ids Ids
28
+ */
29
+ disable(ids: number[]): void;
30
+ }
31
+
32
+ /**
33
+ * OptionGroupFlag props
34
+ */
35
+ export type OptionGroupFlagProps<
36
+ T extends object,
37
+ D extends DataTypes.Keys<T, number>,
38
+ L extends DataTypes.Keys<T, string>
39
+ > = Omit<FormControlProps, "defaultValue"> & {
40
+ /**
41
+ * Default value
42
+ */
43
+ defaultValue?: T[D] & number;
44
+
45
+ /**
46
+ * Get option label function
47
+ */
48
+ getOptionLabel?: (option: T) => string;
49
+
50
+ /**
51
+ * Id field
52
+ */
53
+ idField?: D;
54
+
55
+ /**
56
+ * Label
57
+ */
58
+ label?: string;
59
+
60
+ /**
61
+ * Label field
62
+ */
63
+ labelField?: L;
64
+
65
+ /**
66
+ * Methods
67
+ */
68
+ mRef?: React.Ref<OptionGroupFlagRef>;
69
+
70
+ /**
71
+ * Field name
72
+ */
73
+ name: string;
74
+
75
+ /**
76
+ * On value change handler
77
+ */
78
+ onValueChange?: (value?: T[D] & number) => void;
79
+
80
+ /**
81
+ * Array of options.
82
+ */
83
+ options: ReadonlyArray<T>;
84
+
85
+ /**
86
+ * Is the field read only?
87
+ */
88
+ readOnly?: boolean;
89
+
90
+ /**
91
+ * Display group of elements in a compact row
92
+ */
93
+ row?: boolean;
94
+
95
+ /**
96
+ * Item size
97
+ */
98
+ itemSize?: "small" | "medium";
99
+
100
+ /**
101
+ * Helper text
102
+ */
103
+ helperText?: React.ReactNode;
104
+ };
105
+
106
+ /**
107
+ * OptionGroupFlag
108
+ * @param props Props
109
+ * @returns Component
110
+ */
111
+ export function OptionGroupFlag<
112
+ T extends object = ListType,
113
+ D extends DataTypes.Keys<T, number> = IdDefaultType<T, number>,
114
+ L extends DataTypes.Keys<T, string> = LabelDefaultType<T>
115
+ >(props: OptionGroupFlagProps<T, D, L>) {
116
+ // Destruct
117
+ const {
118
+ getOptionLabel,
119
+ defaultValue,
120
+ idField = "id" as D,
121
+ label,
122
+ labelField = "label" as L,
123
+ mRef,
124
+ name,
125
+ onValueChange,
126
+ options,
127
+ readOnly,
128
+ row,
129
+ itemSize,
130
+ helperText,
131
+ variant,
132
+ required,
133
+ fullWidth,
134
+ sx = {},
135
+ ...rest
136
+ } = props;
137
+
138
+ // Outlined
139
+ const outlined = variant === "outlined";
140
+
141
+ // Get option value
142
+ // D type should be the source id type
143
+ const getOptionValue = (option: T): (T[D] & number) | null => {
144
+ const value = DataTypes.getValue(option, idField);
145
+ if (value == null) return null;
146
+ return value as T[D] & number;
147
+ };
148
+
149
+ // Value
150
+ const [value, setValue] = React.useState(defaultValue);
151
+
152
+ React.useEffect(() => {
153
+ setValue(defaultValue);
154
+ }, [defaultValue]);
155
+
156
+ // Disabled ids
157
+ const [disabledIds, setDisabledIds] = React.useState<number[]>();
158
+
159
+ // Item checked
160
+ const itemChecked = (option: T) => {
161
+ // Value
162
+ const itemValue = getOptionValue(option);
163
+ if (itemValue == null || value == null) return false;
164
+
165
+ return (value & itemValue) > 0;
166
+ };
167
+
168
+ React.useImperativeHandle(mRef, () => ({
169
+ disable(ids: number[]) {
170
+ setDisabledIds(ids);
171
+ }
172
+ }));
173
+
174
+ // First item value
175
+ const firstOptionValue = getOptionValue(options[0]);
176
+
177
+ // Items
178
+ const list = options.map((option) => {
179
+ // Value
180
+ const ov = getOptionValue(option);
181
+ if (ov == null) return;
182
+
183
+ // Control
184
+ const control = (
185
+ <Checkbox
186
+ name={name}
187
+ readOnly={readOnly}
188
+ size={itemSize}
189
+ checked={itemChecked(option)}
190
+ disabled={disabledIds?.includes(ov)}
191
+ onChange={(event) => {
192
+ if (firstOptionValue == null) return;
193
+
194
+ const typeValue = Utils.parseString(
195
+ event.target.value,
196
+ firstOptionValue
197
+ );
198
+
199
+ const newValue = (
200
+ value == null
201
+ ? event.target.checked
202
+ ? typeValue
203
+ : undefined
204
+ : event.target.checked
205
+ ? value | typeValue
206
+ : value ^ typeValue
207
+ ) as (T[D] & number) | undefined;
208
+
209
+ if (onValueChange) onValueChange(newValue);
210
+ setValue(newValue);
211
+ }}
212
+ />
213
+ );
214
+
215
+ // Label
216
+ const label =
217
+ getOptionLabel == null ? `${option[labelField]}` : getOptionLabel(option);
218
+
219
+ return (
220
+ <FormControlLabel key={ov} control={control} value={ov} label={label} />
221
+ );
222
+ });
223
+
224
+ // Group
225
+ const group = <FormGroup row={row}>{list}</FormGroup>;
226
+
227
+ // Layout
228
+ return (
229
+ <React.Fragment>
230
+ <FormControl fullWidth={fullWidth} sx={sx} {...rest}>
231
+ {label && (
232
+ <InputLabel required={required} variant={variant} shrink>
233
+ {label}
234
+ </InputLabel>
235
+ )}
236
+ {outlined ? (
237
+ <NotchedOutline
238
+ label={label && required ? label + " *" : label}
239
+ notched
240
+ endAdornment={group}
241
+ sx={{
242
+ cursor: "default",
243
+ display: "flex",
244
+ gap: 1,
245
+ paddingX: 2,
246
+ paddingY: "7px",
247
+ width: fullWidth ? "100%" : "auto",
248
+ "& input": {
249
+ display: "none"
250
+ }
251
+ }}
252
+ />
253
+ ) : (
254
+ <Box paddingLeft={2} paddingY="7px">
255
+ {group}
256
+ </Box>
257
+ )}
258
+ </FormControl>
259
+ {helperText && (
260
+ <FormHelperText sx={{ marginLeft: 2, marginRight: 2 }}>
261
+ {helperText}
262
+ </FormHelperText>
263
+ )}
264
+ </React.Fragment>
265
+ );
266
+ }
package/src/QuickList.tsx CHANGED
@@ -1,4 +1,4 @@
1
- import { ListType2 } from "@etsoo/shared";
1
+ import { DataTypes, ListType2 } from "@etsoo/shared";
2
2
  import {
3
3
  LinearProgress,
4
4
  List,
@@ -13,7 +13,6 @@ import React from "react";
13
13
  import { InputField, InputFieldProps } from "./InputField";
14
14
  import { globalApp } from "./app/ReactApp";
15
15
  import { VBox } from "./FlexBox";
16
- import { MUUtils } from "./MUUtils";
17
16
 
18
17
  /**
19
18
  * Quick list props
@@ -83,7 +82,7 @@ export function QuickList<T extends ListType2 = ListType2>(
83
82
  buttonProps = {},
84
83
  label,
85
84
  inputProps,
86
- itemLabel = MUUtils.getListItemLabel,
85
+ itemLabel = DataTypes.getListItemLabel,
87
86
  itemRenderer = (item: T) => itemLabel(item),
88
87
  itemProps,
89
88
  loadData,
@@ -12,10 +12,7 @@ import { SwitchAnt } from "./SwitchAnt";
12
12
  /**
13
13
  * SwitchField props
14
14
  */
15
- export type SwitchFieldProps = Omit<
16
- FormControlProps<"fieldset">,
17
- "defaultValue"
18
- > & {
15
+ export type SwitchFieldProps = Omit<FormControlProps, "defaultValue"> & {
19
16
  /**
20
17
  * Helper text
21
18
  */
@@ -26,6 +23,11 @@ export type SwitchFieldProps = Omit<
26
23
  */
27
24
  label?: string;
28
25
 
26
+ /**
27
+ * Field name
28
+ */
29
+ name: string;
30
+
29
31
  /**
30
32
  * Checked
31
33
  */
@@ -46,11 +48,6 @@ export type SwitchFieldProps = Omit<
46
48
  */
47
49
  endLabel?: string;
48
50
 
49
- /**
50
- * Height in px
51
- */
52
- height?: number;
53
-
54
51
  /**
55
52
  * Value, default is true
56
53
  */
@@ -71,12 +68,10 @@ export function SwitchField(props: SwitchFieldProps) {
71
68
  value = true,
72
69
 
73
70
  fullWidth,
74
- height = 56,
75
71
  helperText,
76
72
  label,
77
73
  name,
78
74
  required,
79
- sx = {},
80
75
  checked,
81
76
  variant = "outlined",
82
77
  ...rest
@@ -85,47 +80,49 @@ export function SwitchField(props: SwitchFieldProps) {
85
80
  // Outlined
86
81
  const outlined = variant === "outlined";
87
82
 
88
- if (sx) {
89
- Object.assign(sx, { height: outlined ? `${height}px` : undefined });
90
- }
83
+ // Group
84
+ const group = (
85
+ <SwitchAnt
86
+ activeColor={activeColor}
87
+ name={name}
88
+ startLabel={startLabel}
89
+ endLabel={endLabel}
90
+ value={value}
91
+ checked={checked}
92
+ />
93
+ );
91
94
 
92
95
  // Layout
93
96
  return (
94
97
  <React.Fragment>
95
- <FormControl component="fieldset" fullWidth={fullWidth} sx={sx} {...rest}>
98
+ <FormControl fullWidth={fullWidth} {...rest}>
96
99
  {label && (
97
100
  <InputLabel required={required} variant={variant} shrink>
98
101
  {label}
99
102
  </InputLabel>
100
103
  )}
101
- {outlined && (
104
+ {outlined ? (
102
105
  <NotchedOutline
103
106
  label={label && required ? label + " *" : label}
104
107
  notched
108
+ endAdornment={group}
105
109
  sx={{
106
110
  cursor: "default",
107
- position: "absolute",
111
+ display: "flex",
112
+ gap: 1,
113
+ paddingX: 2,
114
+ paddingY: "7px",
108
115
  width: fullWidth ? "100%" : "auto",
109
116
  "& input": {
110
- visibility: "hidden"
117
+ display: "none"
111
118
  }
112
119
  }}
113
120
  />
121
+ ) : (
122
+ <Box paddingLeft={2} paddingY="7px">
123
+ {group}
124
+ </Box>
114
125
  )}
115
- <Box
116
- paddingLeft={2}
117
- paddingY="7px"
118
- position={outlined ? "absolute" : undefined}
119
- >
120
- <SwitchAnt
121
- activeColor={activeColor}
122
- name={name}
123
- startLabel={startLabel}
124
- endLabel={endLabel}
125
- value={value}
126
- checked={checked}
127
- />
128
- </Box>
129
126
  </FormControl>
130
127
  {helperText && <FormHelperText>{helperText}</FormHelperText>}
131
128
  </React.Fragment>
@@ -4,7 +4,7 @@ import CheckBoxIcon from "@mui/icons-material/CheckBox";
4
4
  import React from "react";
5
5
  import { InputField, InputFieldProps } from "./InputField";
6
6
  import { globalApp } from "./app/ReactApp";
7
- import { ListType2 } from "@etsoo/shared";
7
+ import { DataTypes, ListType2 } from "@etsoo/shared";
8
8
 
9
9
  export type TagListProProps<D extends ListType2 = ListType2> = Omit<
10
10
  AutocompleteProps<D, true, false, false>,
@@ -47,8 +47,7 @@ export function TagListPro<D extends ListType2 = ListType2>(
47
47
 
48
48
  const moreLabel = more + "...";
49
49
 
50
- const getLabel = (item: D) =>
51
- "label" in item ? item.label : "name" in item ? item.name : "";
50
+ const getLabel = (item: D) => DataTypes.getListItemLabel(item);
52
51
 
53
52
  // Destruct
54
53
  const {
package/src/Tiplist.tsx CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ReactUtils, useDelayedExecutor } from "@etsoo/react";
2
- import { DataTypes, IdDefaultType, ListType } from "@etsoo/shared";
2
+ import { DataTypes, IdDefaultType, ListType2 } from "@etsoo/shared";
3
3
  import { Autocomplete, AutocompleteRenderInputParams } from "@mui/material";
4
4
  import React from "react";
5
5
  import { AutocompleteExtendedProps } from "./AutocompleteExtendedProps";
@@ -48,7 +48,7 @@ interface States<T extends object> {
48
48
  * @returns Component
49
49
  */
50
50
  export function Tiplist<
51
- T extends object = ListType,
51
+ T extends object = ListType2,
52
52
  D extends DataTypes.Keys<T> = IdDefaultType<T>
53
53
  >(props: TiplistProps<T, D>) {
54
54
  // Labels
@@ -373,11 +373,7 @@ export function Tiplist<
373
373
  if (item[idField] === "n/a") return (more ?? "More") + "...";
374
374
  return getOptionLabel
375
375
  ? getOptionLabel(item)
376
- : "label" in item
377
- ? `${item.label}`
378
- : "name" in item
379
- ? `${item.name}`
380
- : `${item}`;
376
+ : DataTypes.getObjectItemLabel(item);
381
377
  }}
382
378
  {...rest}
383
379
  />
@@ -1,10 +1,9 @@
1
1
  import { ReactUtils, useDelayedExecutor } from "@etsoo/react";
2
- import { ListType2 } from "@etsoo/shared";
2
+ import { DataTypes, ListType2 } from "@etsoo/shared";
3
3
  import { Autocomplete, AutocompleteProps } from "@mui/material";
4
4
  import React, { ChangeEventHandler } from "react";
5
5
  import { InputField, InputFieldProps } from "./InputField";
6
6
  import { globalApp } from "./app/ReactApp";
7
- import { MUUtils } from "./MUUtils";
8
7
 
9
8
  /**
10
9
  * TiplistPro props
@@ -370,7 +369,7 @@ export function TiplistPro<T extends ListType2 = ListType2>(
370
369
  getOptionLabel={(item) => {
371
370
  if (typeof item === "string") return item;
372
371
  if (item["id"] === -1) return (more ?? "More") + "...";
373
- if (getOptionLabel == null) return MUUtils.getListItemLabel(item);
372
+ if (getOptionLabel == null) return DataTypes.getListItemLabel(item);
374
373
  return getOptionLabel(item);
375
374
  }}
376
375
  {...rest}
@@ -1,5 +1,4 @@
1
1
  import {
2
- IActionResult,
3
2
  IApiPayload,
4
3
  IAppSettings,
5
4
  IUser,
@@ -9,6 +8,7 @@ import {
9
8
  } from "@etsoo/appscript";
10
9
  import { CoreConstants, IPageData } from "@etsoo/react";
11
10
  import { ReactApp } from "./ReactApp";
11
+ import { IActionResult } from "@etsoo/shared";
12
12
 
13
13
  /**
14
14
  * Common independent application