@etsoo/materialui 1.1.30 → 1.1.31

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,6 +1,6 @@
1
- import { DataTypes, IdDefaultType, LabelDefaultType } from '@etsoo/shared';
2
- import { SelectChangeEvent } from '@mui/material';
3
- import React from 'react';
1
+ import { DataTypes, IdDefaultType, LabelDefaultType } from "@etsoo/shared";
2
+ import { SelectChangeEvent } from "@mui/material";
3
+ import React from "react";
4
4
  /**
5
5
  * Hierarchy selector props
6
6
  */
@@ -49,6 +49,10 @@ export type HiSelectorProps<T extends object, D extends DataTypes.Keys<T> = IdDe
49
49
  * Required
50
50
  */
51
51
  required?: boolean;
52
+ /**
53
+ * Search mode
54
+ */
55
+ search?: boolean;
52
56
  /**
53
57
  * Values
54
58
  */
package/lib/HiSelector.js CHANGED
@@ -1,6 +1,6 @@
1
- import { FormLabel, Grid } from '@mui/material';
2
- import React from 'react';
3
- import { SelectEx } from './SelectEx';
1
+ import { FormLabel, Grid } from "@mui/material";
2
+ import React from "react";
3
+ import { SelectEx } from "./SelectEx";
4
4
  /**
5
5
  * Hierarchy selector
6
6
  * @param props Prop
@@ -8,7 +8,7 @@ import { SelectEx } from './SelectEx';
8
8
  */
9
9
  export function HiSelector(props) {
10
10
  // Destruct
11
- const { idField = 'id', error, helperText, name, label = name, labelField = 'name', loadData, onChange, onSelectChange, onItemChange, required, values = [] } = props;
11
+ const { idField = "id", error, helperText, name, label = name, labelField = "name", loadData, onChange, onSelectChange, onItemChange, required, search = true, values = [] } = props;
12
12
  const [localValues, setValues] = React.useState(values);
13
13
  const updateValue = (value) => {
14
14
  if (onChange)
@@ -16,7 +16,7 @@ export function HiSelector(props) {
16
16
  };
17
17
  const doChange = (event, index) => {
18
18
  const value = event.target.value;
19
- const itemValue = value === '' ? undefined : value;
19
+ const itemValue = value === "" ? undefined : value;
20
20
  updateValue(itemValue);
21
21
  const newValues = [...localValues.slice(0, index)];
22
22
  if (itemValue != null)
@@ -28,8 +28,7 @@ export function HiSelector(props) {
28
28
  const doItemChange = (option, userAction) => {
29
29
  if (onItemChange == null)
30
30
  return;
31
- if (!userAction &&
32
- (option == null || option[idField] !== values.at(-1)))
31
+ if (!userAction && (option == null || option[idField] !== values.at(-1)))
33
32
  return;
34
33
  onItemChange(option, userAction);
35
34
  };
@@ -43,13 +42,13 @@ export function HiSelector(props) {
43
42
  return (React.createElement(React.Fragment, null,
44
43
  React.createElement(Grid, { item: true, xs: 12 },
45
44
  React.createElement(FormLabel, { required: required, sx: { fontSize: (theme) => theme.typography.caption } }, label),
46
- React.createElement("input", { type: "hidden", name: name, value: `${currentValue !== null && currentValue !== void 0 ? currentValue : ''}` })),
45
+ React.createElement("input", { type: "hidden", name: name, value: `${currentValue !== null && currentValue !== void 0 ? currentValue : ""}` })),
47
46
  React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
48
- React.createElement(SelectEx, { idField: idField, labelField: labelField, name: "tab1", search: true, fullWidth: true, loadData: () => loadData(), value: values[0], onChange: (event) => doChange(event, 0), onItemChange: doItemChange, inputRequired: required, error: error, helperText: helperText })),
47
+ React.createElement(SelectEx, { idField: idField, labelField: labelField, name: "tab1", search: search, fullWidth: true, loadData: () => loadData(), value: values[0], onChange: (event) => doChange(event, 0), onItemChange: doItemChange, inputRequired: required, error: error, helperText: helperText })),
49
48
  localValues[0] != null && (React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
50
- React.createElement(SelectEx, { key: `${localValues[0]}`, idField: idField, labelField: labelField, name: "tab2", search: true, fullWidth: true, loadData: () => loadData(localValues[0]), value: values[1], onChange: (event) => doChange(event, 1), onItemChange: doItemChange }))),
49
+ React.createElement(SelectEx, { key: `${localValues[0]}`, idField: idField, labelField: labelField, name: "tab2", search: search, fullWidth: true, loadData: () => loadData(localValues[0]), value: values[1], onChange: (event) => doChange(event, 1), onItemChange: doItemChange }))),
51
50
  localValues[1] != null && (React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
52
- React.createElement(SelectEx, { key: `${localValues[1]}`, idField: idField, labelField: labelField, name: "tab3", search: true, fullWidth: true, loadData: () => loadData(localValues[1]), value: values[2], onChange: (event) => doChange(event, 2), onItemChange: doItemChange }))),
51
+ React.createElement(SelectEx, { key: `${localValues[1]}`, idField: idField, labelField: labelField, name: "tab3", search: search, fullWidth: true, loadData: () => loadData(localValues[1]), value: values[2], onChange: (event) => doChange(event, 2), onItemChange: doItemChange }))),
53
52
  localValues[2] != null && (React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
54
- React.createElement(SelectEx, { key: `${localValues[2]}`, idField: idField, labelField: labelField, name: "tab4", search: true, fullWidth: true, loadData: () => loadData(localValues[2]), value: values[3], onChange: (event) => doChange(event, 3), onItemChange: doItemChange })))));
53
+ React.createElement(SelectEx, { key: `${localValues[2]}`, idField: idField, labelField: labelField, name: "tab4", search: search, fullWidth: true, loadData: () => loadData(localValues[2]), value: values[3], onChange: (event) => doChange(event, 3), onItemChange: doItemChange })))));
55
54
  }
@@ -0,0 +1,58 @@
1
+ import { DataTypes, IdDefaultType } from "@etsoo/shared";
2
+ import { AutocompleteChangeReason } from "@mui/material";
3
+ import React from "react";
4
+ /**
5
+ * Hierarchy tiplist selector props
6
+ */
7
+ export type HiSelectorTLProps<T extends object, D extends DataTypes.Keys<T> = IdDefaultType<T>> = {
8
+ /**
9
+ * Id field
10
+ */
11
+ idField?: D;
12
+ /**
13
+ * Error
14
+ */
15
+ error?: boolean;
16
+ /**
17
+ * The helper text content.
18
+ */
19
+ helperText?: React.ReactNode;
20
+ /**
21
+ * Name, also hidden input field name
22
+ */
23
+ name: string;
24
+ /**
25
+ * Label
26
+ */
27
+ label?: string;
28
+ /**
29
+ * Load data callback
30
+ */
31
+ loadData: (keyword: string | undefined, id: T[D] | undefined, maxItems: number, parent?: T[D]) => PromiseLike<T[] | null | undefined>;
32
+ /**
33
+ * On value change event
34
+ */
35
+ onChange?: (value: unknown) => void;
36
+ /**
37
+ * Item change callback
38
+ */
39
+ onItemChange?: (event: React.SyntheticEvent, option: T | null, reason: AutocompleteChangeReason) => void;
40
+ /**
41
+ * Required
42
+ */
43
+ required?: boolean;
44
+ /**
45
+ * Search mode
46
+ */
47
+ search?: boolean;
48
+ /**
49
+ * Values
50
+ */
51
+ values?: T[D][];
52
+ };
53
+ /**
54
+ * Hierarchy tiplist selector
55
+ * @param props Prop
56
+ * @returns Component
57
+ */
58
+ export declare function HiSelectorTL<T extends object, D extends DataTypes.Keys<T> = IdDefaultType<T>>(props: HiSelectorTLProps<T, D>): JSX.Element;
@@ -0,0 +1,49 @@
1
+ import { FormLabel, Grid } from "@mui/material";
2
+ import React from "react";
3
+ import { Tiplist } from "./Tiplist";
4
+ /**
5
+ * Hierarchy tiplist selector
6
+ * @param props Prop
7
+ * @returns Component
8
+ */
9
+ export function HiSelectorTL(props) {
10
+ // Destruct
11
+ const { idField = "id", error, helperText, name, label = name, loadData, onChange, onItemChange, required, search = false, values = [] } = props;
12
+ const [localValues, setValues] = React.useState(values);
13
+ const updateValue = (value) => {
14
+ if (onChange)
15
+ onChange(value);
16
+ };
17
+ const doChange = (index, event, value, reason) => {
18
+ if (onItemChange) {
19
+ onItemChange(event, value, reason);
20
+ if (event.isDefaultPrevented())
21
+ return;
22
+ }
23
+ const itemValue = value ? value[idField] : undefined;
24
+ updateValue(itemValue);
25
+ const newValues = [...localValues.slice(0, index)];
26
+ if (itemValue != null)
27
+ newValues.push(itemValue);
28
+ setValues(newValues);
29
+ };
30
+ React.useEffect(() => {
31
+ if (values.length > 0) {
32
+ setValues(values);
33
+ updateValue(values.at(-1));
34
+ }
35
+ }, [values.toString()]);
36
+ const currentValue = localValues.at(-1);
37
+ return (React.createElement(React.Fragment, null,
38
+ React.createElement(Grid, { item: true, xs: 12 },
39
+ React.createElement(FormLabel, { required: required, sx: { fontSize: (theme) => theme.typography.caption } }, label),
40
+ React.createElement("input", { type: "hidden", name: name, value: `${currentValue !== null && currentValue !== void 0 ? currentValue : ""}` })),
41
+ React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
42
+ React.createElement(Tiplist, { idField: idField, label: "1", name: "tab1", search: search, fullWidth: true, idValue: values[0], loadData: (keyword, id, items) => loadData(keyword, id, items), inputRequired: required, inputError: error, inputHelperText: helperText, onChange: (event, value, reason) => doChange(0, event, value, reason) })),
43
+ localValues[0] != null && (React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
44
+ React.createElement(Tiplist, { key: `${localValues[0]}`, label: "2", idField: idField, name: "tab2", search: search, fullWidth: true, loadData: (keyword, id, items) => loadData(keyword, id, items, localValues[0]), idValue: values[1], onChange: (event, value, reason) => doChange(1, event, value, reason) }))),
45
+ localValues[1] != null && (React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
46
+ React.createElement(Tiplist, { key: `${localValues[1]}`, label: "3", idField: idField, name: "tab3", search: search, fullWidth: true, loadData: (keyword, id, items) => loadData(keyword, id, items, localValues[1]), idValue: values[2], onChange: (event, value, reason) => doChange(2, event, value, reason) }))),
47
+ localValues[2] != null && (React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
48
+ React.createElement(Tiplist, { key: `${localValues[2]}`, label: "4", idField: idField, name: "tab4", search: search, fullWidth: true, loadData: (keyword, id, items) => loadData(keyword, id, items, localValues[2]), idValue: values[3], onChange: (event, value, reason) => doChange(3, event, value, reason) })))));
49
+ }
package/lib/Tiplist.js CHANGED
@@ -161,20 +161,16 @@ export function Tiplist(props) {
161
161
  return getOptionDisabled ? getOptionDisabled(item) : false;
162
162
  }, getOptionLabel: (item) => {
163
163
  var _a;
164
+ if (typeof item !== "object")
165
+ return `${item}`;
164
166
  if (item[idField] === "n/a")
165
167
  return ((_a = labels.more) !== null && _a !== void 0 ? _a : "More") + "...";
166
- try {
167
- return getOptionLabel
168
- ? getOptionLabel(item)
169
- : "label" in item
170
- ? `${item.label}`
171
- : "name" in item
172
- ? `${item.name}`
173
- : `${item}`;
174
- }
175
- catch (e) {
176
- console.log(typeof item, item, e);
177
- return "";
178
- }
168
+ return getOptionLabel
169
+ ? getOptionLabel(item)
170
+ : "label" in item
171
+ ? `${item.label}`
172
+ : "name" in item
173
+ ? `${item.name}`
174
+ : `${item}`;
179
175
  }, ...rest })));
180
176
  }
package/lib/index.d.ts CHANGED
@@ -46,6 +46,7 @@ export * from "./FabBox";
46
46
  export * from "./FlexBox";
47
47
  export * from "./GridDataFormat";
48
48
  export * from "./HiSelector";
49
+ export * from "./HiSelectorTL";
49
50
  export * from "./IconButtonLink";
50
51
  export * from "./InputField";
51
52
  export * from "./ItemList";
package/lib/index.js CHANGED
@@ -46,6 +46,7 @@ export * from "./FabBox";
46
46
  export * from "./FlexBox";
47
47
  export * from "./GridDataFormat";
48
48
  export * from "./HiSelector";
49
+ export * from "./HiSelectorTL";
49
50
  export * from "./IconButtonLink";
50
51
  export * from "./InputField";
51
52
  export * from "./ItemList";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.1.30",
3
+ "version": "1.1.31",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -1,75 +1,80 @@
1
- import { DataTypes, IdDefaultType, LabelDefaultType } from '@etsoo/shared';
2
- import { FormLabel, Grid, SelectChangeEvent } from '@mui/material';
3
- import React from 'react';
4
- import { SelectEx } from './SelectEx';
1
+ import { DataTypes, IdDefaultType, LabelDefaultType } from "@etsoo/shared";
2
+ import { FormLabel, Grid, SelectChangeEvent } from "@mui/material";
3
+ import React from "react";
4
+ import { SelectEx } from "./SelectEx";
5
5
 
6
6
  /**
7
7
  * Hierarchy selector props
8
8
  */
9
9
  export type HiSelectorProps<
10
- T extends object,
11
- D extends DataTypes.Keys<T> = IdDefaultType<T>,
12
- L extends DataTypes.Keys<T, string> = LabelDefaultType<T>
10
+ T extends object,
11
+ D extends DataTypes.Keys<T> = IdDefaultType<T>,
12
+ L extends DataTypes.Keys<T, string> = LabelDefaultType<T>
13
13
  > = {
14
- /**
15
- * Id field
16
- */
17
- idField?: D;
18
-
19
- /**
20
- * Error
21
- */
22
- error?: boolean;
23
-
24
- /**
25
- * The helper text content.
26
- */
27
- helperText?: React.ReactNode;
28
-
29
- /**
30
- * Name, also hidden input field name
31
- */
32
- name: string;
33
-
34
- /**
35
- * Label
36
- */
37
- label?: string;
38
-
39
- /**
40
- * Label field
41
- */
42
- labelField?: L;
43
-
44
- /**
45
- * Load data callback
46
- */
47
- loadData: (parent?: T[D]) => PromiseLike<T[] | null | undefined>;
48
-
49
- /**
50
- * On value change event
51
- */
52
- onChange?: (value: unknown) => void;
53
-
54
- /**
55
- * On select change event
56
- */
57
- onSelectChange?: (e: SelectChangeEvent<unknown>) => void;
58
-
59
- /**
60
- * Item change callback
61
- */
62
- onItemChange?: (option: T | undefined, userAction: boolean) => void;
63
-
64
- /**
65
- * Required
66
- */
67
- required?: boolean;
68
-
69
- /**
70
- * Values
71
- */
72
- values?: T[D][];
14
+ /**
15
+ * Id field
16
+ */
17
+ idField?: D;
18
+
19
+ /**
20
+ * Error
21
+ */
22
+ error?: boolean;
23
+
24
+ /**
25
+ * The helper text content.
26
+ */
27
+ helperText?: React.ReactNode;
28
+
29
+ /**
30
+ * Name, also hidden input field name
31
+ */
32
+ name: string;
33
+
34
+ /**
35
+ * Label
36
+ */
37
+ label?: string;
38
+
39
+ /**
40
+ * Label field
41
+ */
42
+ labelField?: L;
43
+
44
+ /**
45
+ * Load data callback
46
+ */
47
+ loadData: (parent?: T[D]) => PromiseLike<T[] | null | undefined>;
48
+
49
+ /**
50
+ * On value change event
51
+ */
52
+ onChange?: (value: unknown) => void;
53
+
54
+ /**
55
+ * On select change event
56
+ */
57
+ onSelectChange?: (e: SelectChangeEvent<unknown>) => void;
58
+
59
+ /**
60
+ * Item change callback
61
+ */
62
+ onItemChange?: (option: T | undefined, userAction: boolean) => void;
63
+
64
+ /**
65
+ * Required
66
+ */
67
+ required?: boolean;
68
+
69
+ /**
70
+ * Search mode
71
+ */
72
+ search?: boolean;
73
+
74
+ /**
75
+ * Values
76
+ */
77
+ values?: T[D][];
73
78
  };
74
79
 
75
80
  /**
@@ -78,144 +83,138 @@ export type HiSelectorProps<
78
83
  * @returns Component
79
84
  */
80
85
  export function HiSelector<
81
- T extends object,
82
- D extends DataTypes.Keys<T> = IdDefaultType<T>,
83
- L extends DataTypes.Keys<T, string> = LabelDefaultType<T>
86
+ T extends object,
87
+ D extends DataTypes.Keys<T> = IdDefaultType<T>,
88
+ L extends DataTypes.Keys<T, string> = LabelDefaultType<T>
84
89
  >(props: HiSelectorProps<T, D, L>) {
85
- // Destruct
86
- const {
87
- idField = 'id' as D,
88
- error,
89
- helperText,
90
- name,
91
- label = name,
92
- labelField = 'name' as L,
93
- loadData,
94
- onChange,
95
- onSelectChange,
96
- onItemChange,
97
- required,
98
- values = []
99
- } = props;
100
-
101
- // Value type
102
- type ValueType = T[D];
103
- const [localValues, setValues] = React.useState<ValueType[]>(values);
104
-
105
- const updateValue = (value?: T[D]) => {
106
- if (onChange) onChange(value);
107
- };
108
-
109
- const doChange = (event: SelectChangeEvent<unknown>, index: number) => {
110
- const value = event.target.value;
111
- const itemValue = value === '' ? undefined : (value as T[D]);
112
- updateValue(itemValue);
113
-
114
- const newValues = [...localValues.slice(0, index)];
115
- if (itemValue != null) newValues.push(itemValue);
116
- setValues(newValues);
117
-
118
- if (onSelectChange) onSelectChange(event);
119
- };
120
-
121
- const doItemChange = (option: T | undefined, userAction: boolean) => {
122
- if (onItemChange == null) return;
123
- if (
124
- !userAction &&
125
- (option == null || option[idField] !== values.at(-1))
126
- )
127
- return;
128
- onItemChange(option, userAction);
129
- };
130
-
131
- React.useEffect(() => {
132
- if (values.length > 0) {
133
- setValues(values);
134
- updateValue(values.at(-1));
135
- }
136
- }, [values]);
137
-
138
- const currentValue = localValues.at(-1);
139
-
140
- return (
141
- <React.Fragment>
142
- <Grid item xs={12}>
143
- <FormLabel
144
- required={required}
145
- sx={{ fontSize: (theme) => theme.typography.caption }}
146
- >
147
- {label}
148
- </FormLabel>
149
- <input
150
- type="hidden"
151
- name={name}
152
- value={`${currentValue ?? ''}`}
153
- />
154
- </Grid>
155
- <Grid item xs={6} md={4} lg={3}>
156
- <SelectEx<T, D, L>
157
- idField={idField}
158
- labelField={labelField}
159
- name="tab1"
160
- search
161
- fullWidth
162
- loadData={() => loadData()}
163
- value={values[0]}
164
- onChange={(event) => doChange(event, 0)}
165
- onItemChange={doItemChange}
166
- inputRequired={required}
167
- error={error}
168
- helperText={helperText}
169
- />
170
- </Grid>
171
- {localValues[0] != null && (
172
- <Grid item xs={6} md={4} lg={3}>
173
- <SelectEx<T, D, L>
174
- key={`${localValues[0]}`}
175
- idField={idField}
176
- labelField={labelField}
177
- name="tab2"
178
- search
179
- fullWidth
180
- loadData={() => loadData(localValues[0])}
181
- value={values[1]}
182
- onChange={(event) => doChange(event, 1)}
183
- onItemChange={doItemChange}
184
- />
185
- </Grid>
186
- )}
187
- {localValues[1] != null && (
188
- <Grid item xs={6} md={4} lg={3}>
189
- <SelectEx<T, D, L>
190
- key={`${localValues[1]}`}
191
- idField={idField}
192
- labelField={labelField}
193
- name="tab3"
194
- search
195
- fullWidth
196
- loadData={() => loadData(localValues[1])}
197
- value={values[2]}
198
- onChange={(event) => doChange(event, 2)}
199
- onItemChange={doItemChange}
200
- />
201
- </Grid>
202
- )}
203
- {localValues[2] != null && (
204
- <Grid item xs={6} md={4} lg={3}>
205
- <SelectEx<T, D, L>
206
- key={`${localValues[2]}`}
207
- idField={idField}
208
- labelField={labelField}
209
- name="tab4"
210
- search
211
- fullWidth
212
- loadData={() => loadData(localValues[2])}
213
- value={values[3]}
214
- onChange={(event) => doChange(event, 3)}
215
- onItemChange={doItemChange}
216
- />
217
- </Grid>
218
- )}
219
- </React.Fragment>
220
- );
90
+ // Destruct
91
+ const {
92
+ idField = "id" as D,
93
+ error,
94
+ helperText,
95
+ name,
96
+ label = name,
97
+ labelField = "name" as L,
98
+ loadData,
99
+ onChange,
100
+ onSelectChange,
101
+ onItemChange,
102
+ required,
103
+ search = true,
104
+ values = []
105
+ } = props;
106
+
107
+ // Value type
108
+ type ValueType = T[D];
109
+ const [localValues, setValues] = React.useState<ValueType[]>(values);
110
+
111
+ const updateValue = (value?: T[D]) => {
112
+ if (onChange) onChange(value);
113
+ };
114
+
115
+ const doChange = (event: SelectChangeEvent<unknown>, index: number) => {
116
+ const value = event.target.value;
117
+ const itemValue = value === "" ? undefined : (value as T[D]);
118
+ updateValue(itemValue);
119
+
120
+ const newValues = [...localValues.slice(0, index)];
121
+ if (itemValue != null) newValues.push(itemValue);
122
+ setValues(newValues);
123
+
124
+ if (onSelectChange) onSelectChange(event);
125
+ };
126
+
127
+ const doItemChange = (option: T | undefined, userAction: boolean) => {
128
+ if (onItemChange == null) return;
129
+ if (!userAction && (option == null || option[idField] !== values.at(-1)))
130
+ return;
131
+ onItemChange(option, userAction);
132
+ };
133
+
134
+ React.useEffect(() => {
135
+ if (values.length > 0) {
136
+ setValues(values);
137
+ updateValue(values.at(-1));
138
+ }
139
+ }, [values]);
140
+
141
+ const currentValue = localValues.at(-1);
142
+
143
+ return (
144
+ <React.Fragment>
145
+ <Grid item xs={12}>
146
+ <FormLabel
147
+ required={required}
148
+ sx={{ fontSize: (theme) => theme.typography.caption }}
149
+ >
150
+ {label}
151
+ </FormLabel>
152
+ <input type="hidden" name={name} value={`${currentValue ?? ""}`} />
153
+ </Grid>
154
+ <Grid item xs={6} md={4} lg={3}>
155
+ <SelectEx<T, D, L>
156
+ idField={idField}
157
+ labelField={labelField}
158
+ name="tab1"
159
+ search={search}
160
+ fullWidth
161
+ loadData={() => loadData()}
162
+ value={values[0]}
163
+ onChange={(event) => doChange(event, 0)}
164
+ onItemChange={doItemChange}
165
+ inputRequired={required}
166
+ error={error}
167
+ helperText={helperText}
168
+ />
169
+ </Grid>
170
+ {localValues[0] != null && (
171
+ <Grid item xs={6} md={4} lg={3}>
172
+ <SelectEx<T, D, L>
173
+ key={`${localValues[0]}`}
174
+ idField={idField}
175
+ labelField={labelField}
176
+ name="tab2"
177
+ search={search}
178
+ fullWidth
179
+ loadData={() => loadData(localValues[0])}
180
+ value={values[1]}
181
+ onChange={(event) => doChange(event, 1)}
182
+ onItemChange={doItemChange}
183
+ />
184
+ </Grid>
185
+ )}
186
+ {localValues[1] != null && (
187
+ <Grid item xs={6} md={4} lg={3}>
188
+ <SelectEx<T, D, L>
189
+ key={`${localValues[1]}`}
190
+ idField={idField}
191
+ labelField={labelField}
192
+ name="tab3"
193
+ search={search}
194
+ fullWidth
195
+ loadData={() => loadData(localValues[1])}
196
+ value={values[2]}
197
+ onChange={(event) => doChange(event, 2)}
198
+ onItemChange={doItemChange}
199
+ />
200
+ </Grid>
201
+ )}
202
+ {localValues[2] != null && (
203
+ <Grid item xs={6} md={4} lg={3}>
204
+ <SelectEx<T, D, L>
205
+ key={`${localValues[2]}`}
206
+ idField={idField}
207
+ labelField={labelField}
208
+ name="tab4"
209
+ search={search}
210
+ fullWidth
211
+ loadData={() => loadData(localValues[2])}
212
+ value={values[3]}
213
+ onChange={(event) => doChange(event, 3)}
214
+ onItemChange={doItemChange}
215
+ />
216
+ </Grid>
217
+ )}
218
+ </React.Fragment>
219
+ );
221
220
  }
@@ -0,0 +1,228 @@
1
+ import { DataTypes, IdDefaultType } from "@etsoo/shared";
2
+ import {
3
+ AutocompleteChangeReason,
4
+ AutocompleteValue,
5
+ FormLabel,
6
+ Grid
7
+ } from "@mui/material";
8
+ import React from "react";
9
+ import { Tiplist } from "./Tiplist";
10
+
11
+ /**
12
+ * Hierarchy tiplist selector props
13
+ */
14
+ export type HiSelectorTLProps<
15
+ T extends object,
16
+ D extends DataTypes.Keys<T> = IdDefaultType<T>
17
+ > = {
18
+ /**
19
+ * Id field
20
+ */
21
+ idField?: D;
22
+
23
+ /**
24
+ * Error
25
+ */
26
+ error?: boolean;
27
+
28
+ /**
29
+ * The helper text content.
30
+ */
31
+ helperText?: React.ReactNode;
32
+
33
+ /**
34
+ * Name, also hidden input field name
35
+ */
36
+ name: string;
37
+
38
+ /**
39
+ * Label
40
+ */
41
+ label?: string;
42
+
43
+ /**
44
+ * Load data callback
45
+ */
46
+ loadData: (
47
+ keyword: string | undefined,
48
+ id: T[D] | undefined,
49
+ maxItems: number,
50
+ parent?: T[D]
51
+ ) => PromiseLike<T[] | null | undefined>;
52
+
53
+ /**
54
+ * On value change event
55
+ */
56
+ onChange?: (value: unknown) => void;
57
+
58
+ /**
59
+ * Item change callback
60
+ */
61
+ onItemChange?: (
62
+ event: React.SyntheticEvent,
63
+ option: T | null,
64
+ reason: AutocompleteChangeReason
65
+ ) => void;
66
+
67
+ /**
68
+ * Required
69
+ */
70
+ required?: boolean;
71
+
72
+ /**
73
+ * Search mode
74
+ */
75
+ search?: boolean;
76
+
77
+ /**
78
+ * Values
79
+ */
80
+ values?: T[D][];
81
+ };
82
+
83
+ /**
84
+ * Hierarchy tiplist selector
85
+ * @param props Prop
86
+ * @returns Component
87
+ */
88
+ export function HiSelectorTL<
89
+ T extends object,
90
+ D extends DataTypes.Keys<T> = IdDefaultType<T>
91
+ >(props: HiSelectorTLProps<T, D>) {
92
+ // Destruct
93
+ const {
94
+ idField = "id" as D,
95
+ error,
96
+ helperText,
97
+ name,
98
+ label = name,
99
+ loadData,
100
+ onChange,
101
+ onItemChange,
102
+ required,
103
+ search = false,
104
+ values = []
105
+ } = props;
106
+
107
+ // Value type
108
+ type ValueType = T[D];
109
+ const [localValues, setValues] = React.useState<ValueType[]>(values);
110
+
111
+ const updateValue = (value?: T[D]) => {
112
+ if (onChange) onChange(value);
113
+ };
114
+
115
+ const doChange = (
116
+ index: number,
117
+ event: React.SyntheticEvent,
118
+ value: AutocompleteValue<T, false, false, false>,
119
+ reason: AutocompleteChangeReason
120
+ ) => {
121
+ if (onItemChange) {
122
+ onItemChange(event, value, reason);
123
+ if (event.isDefaultPrevented()) return;
124
+ }
125
+
126
+ const itemValue = value ? value[idField] : undefined;
127
+ updateValue(itemValue);
128
+
129
+ const newValues = [...localValues.slice(0, index)];
130
+ if (itemValue != null) newValues.push(itemValue);
131
+ setValues(newValues);
132
+ };
133
+
134
+ React.useEffect(() => {
135
+ if (values.length > 0) {
136
+ setValues(values);
137
+ updateValue(values.at(-1));
138
+ }
139
+ }, [values.toString()]);
140
+
141
+ const currentValue = localValues.at(-1);
142
+
143
+ return (
144
+ <React.Fragment>
145
+ <Grid item xs={12}>
146
+ <FormLabel
147
+ required={required}
148
+ sx={{ fontSize: (theme) => theme.typography.caption }}
149
+ >
150
+ {label}
151
+ </FormLabel>
152
+ <input type="hidden" name={name} value={`${currentValue ?? ""}`} />
153
+ </Grid>
154
+ <Grid item xs={6} md={4} lg={3}>
155
+ <Tiplist<T, D>
156
+ idField={idField}
157
+ label="1"
158
+ name="tab1"
159
+ search={search}
160
+ fullWidth
161
+ idValue={values[0]}
162
+ loadData={(keyword, id, items) => loadData(keyword, id, items)}
163
+ inputRequired={required}
164
+ inputError={error}
165
+ inputHelperText={helperText}
166
+ onChange={(event, value, reason) => doChange(0, event, value, reason)}
167
+ />
168
+ </Grid>
169
+ {localValues[0] != null && (
170
+ <Grid item xs={6} md={4} lg={3}>
171
+ <Tiplist<T, D>
172
+ key={`${localValues[0]}`}
173
+ label="2"
174
+ idField={idField}
175
+ name="tab2"
176
+ search={search}
177
+ fullWidth
178
+ loadData={(keyword, id, items) =>
179
+ loadData(keyword, id, items, localValues[0])
180
+ }
181
+ idValue={values[1]}
182
+ onChange={(event, value, reason) =>
183
+ doChange(1, event, value, reason)
184
+ }
185
+ />
186
+ </Grid>
187
+ )}
188
+ {localValues[1] != null && (
189
+ <Grid item xs={6} md={4} lg={3}>
190
+ <Tiplist<T, D>
191
+ key={`${localValues[1]}`}
192
+ label="3"
193
+ idField={idField}
194
+ name="tab3"
195
+ search={search}
196
+ fullWidth
197
+ loadData={(keyword, id, items) =>
198
+ loadData(keyword, id, items, localValues[1])
199
+ }
200
+ idValue={values[2]}
201
+ onChange={(event, value, reason) =>
202
+ doChange(2, event, value, reason)
203
+ }
204
+ />
205
+ </Grid>
206
+ )}
207
+ {localValues[2] != null && (
208
+ <Grid item xs={6} md={4} lg={3}>
209
+ <Tiplist<T, D>
210
+ key={`${localValues[2]}`}
211
+ label="4"
212
+ idField={idField}
213
+ name="tab4"
214
+ search={search}
215
+ fullWidth
216
+ loadData={(keyword, id, items) =>
217
+ loadData(keyword, id, items, localValues[2])
218
+ }
219
+ idValue={values[3]}
220
+ onChange={(event, value, reason) =>
221
+ doChange(3, event, value, reason)
222
+ }
223
+ />
224
+ </Grid>
225
+ )}
226
+ </React.Fragment>
227
+ );
228
+ }
package/src/Tiplist.tsx CHANGED
@@ -317,19 +317,15 @@ export function Tiplist<
317
317
  return getOptionDisabled ? getOptionDisabled(item) : false;
318
318
  }}
319
319
  getOptionLabel={(item) => {
320
+ if (typeof item !== "object") return `${item}`;
320
321
  if (item[idField] === "n/a") return (labels.more ?? "More") + "...";
321
- try {
322
- return getOptionLabel
323
- ? getOptionLabel(item)
324
- : "label" in item
325
- ? `${item.label}`
326
- : "name" in item
327
- ? `${item.name}`
328
- : `${item}`;
329
- } catch (e) {
330
- console.log(typeof item, item, e);
331
- return "";
332
- }
322
+ return getOptionLabel
323
+ ? getOptionLabel(item)
324
+ : "label" in item
325
+ ? `${item.label}`
326
+ : "name" in item
327
+ ? `${item.name}`
328
+ : `${item}`;
333
329
  }}
334
330
  {...rest}
335
331
  />
package/src/index.ts CHANGED
@@ -49,6 +49,7 @@ export * from "./FabBox";
49
49
  export * from "./FlexBox";
50
50
  export * from "./GridDataFormat";
51
51
  export * from "./HiSelector";
52
+ export * from "./HiSelectorTL";
52
53
  export * from "./IconButtonLink";
53
54
  export * from "./InputField";
54
55
  export * from "./ItemList";