@etsoo/materialui 1.1.43 → 1.1.45
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/AddresSelector.d.ts +88 -0
- package/lib/AddresSelector.js +127 -0
- package/lib/ComboBox.d.ts +1 -9
- package/lib/ComboBox.js +14 -32
- package/lib/ComboBoxMultiple.d.ts +42 -0
- package/lib/ComboBoxMultiple.js +137 -0
- package/lib/HiSelector.js +4 -4
- package/lib/HiSelectorTL.js +3 -3
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/package.json +2 -2
- package/src/AddresSelector.tsx +318 -0
- package/src/ComboBox.tsx +21 -64
- package/src/ComboBoxMultiple.tsx +314 -0
- package/src/HiSelector.tsx +12 -10
- package/src/HiSelectorTL.tsx +11 -9
- package/src/index.ts +2 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { AddressApi, AddressCity, AddressDistrict, AddressRegionDb, AddressState } from "@etsoo/appscript";
|
|
2
|
+
import React from "react";
|
|
3
|
+
/**
|
|
4
|
+
* Address field
|
|
5
|
+
*/
|
|
6
|
+
export declare enum AddressField {
|
|
7
|
+
Region = "region",
|
|
8
|
+
State = "state",
|
|
9
|
+
City = "city",
|
|
10
|
+
District = "district"
|
|
11
|
+
}
|
|
12
|
+
type AddressFieldType<F extends AddressField> = F extends AddressField.Region ? [F, AddressRegionDb | null] : F extends AddressField.State ? [F, AddressState | null] : F extends AddressField.City ? [F, AddressCity | null] : [F, AddressDistrict | null];
|
|
13
|
+
/**
|
|
14
|
+
* Address selector props
|
|
15
|
+
*/
|
|
16
|
+
export type AddressSelectorProps = {
|
|
17
|
+
/**
|
|
18
|
+
* Address API
|
|
19
|
+
*/
|
|
20
|
+
api: AddressApi;
|
|
21
|
+
/**
|
|
22
|
+
* City
|
|
23
|
+
*/
|
|
24
|
+
city?: number;
|
|
25
|
+
/**
|
|
26
|
+
* City label
|
|
27
|
+
*/
|
|
28
|
+
cityLabel?: string;
|
|
29
|
+
/**
|
|
30
|
+
* District
|
|
31
|
+
*/
|
|
32
|
+
district?: number;
|
|
33
|
+
/**
|
|
34
|
+
* District label
|
|
35
|
+
*/
|
|
36
|
+
districtLabel?: string;
|
|
37
|
+
/**
|
|
38
|
+
* Error
|
|
39
|
+
*/
|
|
40
|
+
error?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The helper text content.
|
|
43
|
+
*/
|
|
44
|
+
helperText?: React.ReactNode;
|
|
45
|
+
/**
|
|
46
|
+
* Hide the region
|
|
47
|
+
*/
|
|
48
|
+
hideRegion?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Label
|
|
51
|
+
*/
|
|
52
|
+
label?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Onchange hanlder
|
|
55
|
+
* @param event Event
|
|
56
|
+
*/
|
|
57
|
+
onChange?: <F extends AddressField>(event: AddressFieldType<F>) => void;
|
|
58
|
+
/**
|
|
59
|
+
* Country or region
|
|
60
|
+
*/
|
|
61
|
+
region?: string;
|
|
62
|
+
/**
|
|
63
|
+
* Region label
|
|
64
|
+
*/
|
|
65
|
+
regionLabel?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Required
|
|
68
|
+
*/
|
|
69
|
+
required?: boolean;
|
|
70
|
+
/**
|
|
71
|
+
* Search mode
|
|
72
|
+
*/
|
|
73
|
+
search?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* State
|
|
76
|
+
*/
|
|
77
|
+
state?: string;
|
|
78
|
+
/**
|
|
79
|
+
* State label
|
|
80
|
+
*/
|
|
81
|
+
stateLabel?: string;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Address selector
|
|
85
|
+
* @param props Props
|
|
86
|
+
*/
|
|
87
|
+
export declare function AddressSelector(props: AddressSelectorProps): JSX.Element;
|
|
88
|
+
export {};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { FormLabel, Grid } from "@mui/material";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { globalApp } from "./app/ReactApp";
|
|
4
|
+
import { ComboBox } from "./ComboBox";
|
|
5
|
+
import { Tiplist } from "./Tiplist";
|
|
6
|
+
/**
|
|
7
|
+
* Address field
|
|
8
|
+
*/
|
|
9
|
+
export var AddressField;
|
|
10
|
+
(function (AddressField) {
|
|
11
|
+
AddressField["Region"] = "region";
|
|
12
|
+
AddressField["State"] = "state";
|
|
13
|
+
AddressField["City"] = "city";
|
|
14
|
+
AddressField["District"] = "district";
|
|
15
|
+
})(AddressField || (AddressField = {}));
|
|
16
|
+
/**
|
|
17
|
+
* Address selector
|
|
18
|
+
* @param props Props
|
|
19
|
+
*/
|
|
20
|
+
export function AddressSelector(props) {
|
|
21
|
+
var _a;
|
|
22
|
+
// Labels
|
|
23
|
+
const { city: cityDefault = "City", district: districtDefault = "District", region: regionDefault = "Region", state: stateDefault = "State" } = (_a = globalApp === null || globalApp === void 0 ? void 0 : globalApp.getLabels("region", "state", "city", "district")) !== null && _a !== void 0 ? _a : {};
|
|
24
|
+
// Destruct
|
|
25
|
+
const { api, city, cityLabel = cityDefault, district, districtLabel = districtDefault, error, helperText, hideRegion, label, onChange, region, regionLabel = regionDefault, required, search, state, stateLabel = stateDefault } = props;
|
|
26
|
+
// States
|
|
27
|
+
const [regionState, setRegion] = React.useState(region);
|
|
28
|
+
const [stateState, setState] = React.useState(state);
|
|
29
|
+
const [cityState, setCity] = React.useState(city);
|
|
30
|
+
const [districtState, setDistrict] = React.useState(district);
|
|
31
|
+
React.useEffect(() => setRegion(region), [region]);
|
|
32
|
+
React.useEffect(() => setState(state), [state]);
|
|
33
|
+
React.useEffect(() => setCity(city), [city]);
|
|
34
|
+
React.useEffect(() => setDistrict(district), [district]);
|
|
35
|
+
const [states, setStates] = React.useState([]);
|
|
36
|
+
const [cities, setCities] = React.useState([]);
|
|
37
|
+
const [districts, setDistricts] = React.useState([]);
|
|
38
|
+
React.useEffect(() => {
|
|
39
|
+
if (regionState == null)
|
|
40
|
+
setStates([]);
|
|
41
|
+
else
|
|
42
|
+
api.states(regionState).then((items) => {
|
|
43
|
+
if (items == null)
|
|
44
|
+
return;
|
|
45
|
+
setStates(items);
|
|
46
|
+
});
|
|
47
|
+
}, [regionState]);
|
|
48
|
+
React.useEffect(() => {
|
|
49
|
+
if (stateState == null)
|
|
50
|
+
setCities([]);
|
|
51
|
+
else
|
|
52
|
+
api.cities(stateState).then((items) => {
|
|
53
|
+
if (items == null)
|
|
54
|
+
return;
|
|
55
|
+
setCities(items);
|
|
56
|
+
});
|
|
57
|
+
}, [stateState]);
|
|
58
|
+
React.useEffect(() => {
|
|
59
|
+
if (cityState == null)
|
|
60
|
+
setDistricts([]);
|
|
61
|
+
else
|
|
62
|
+
api.districts(cityState).then((items) => {
|
|
63
|
+
if (items == null)
|
|
64
|
+
return;
|
|
65
|
+
setDistricts(items);
|
|
66
|
+
});
|
|
67
|
+
}, [cityState]);
|
|
68
|
+
// Field size
|
|
69
|
+
const fieldSize = hideRegion ? 4 : 3;
|
|
70
|
+
// Handle field change
|
|
71
|
+
const handleChange = (event) => {
|
|
72
|
+
if (onChange)
|
|
73
|
+
onChange(event);
|
|
74
|
+
const [field, data] = event;
|
|
75
|
+
if (field === AddressField.Region) {
|
|
76
|
+
if (data == null) {
|
|
77
|
+
setRegion(undefined);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
setRegion(data.id);
|
|
81
|
+
}
|
|
82
|
+
setState(undefined);
|
|
83
|
+
setCity(undefined);
|
|
84
|
+
setDistrict(undefined);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (field === AddressField.State) {
|
|
88
|
+
if (data == null) {
|
|
89
|
+
setState(undefined);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
setState(data.id);
|
|
93
|
+
}
|
|
94
|
+
setCity(undefined);
|
|
95
|
+
setDistrict(undefined);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (field === AddressField.City) {
|
|
99
|
+
if (data == null) {
|
|
100
|
+
setCity(undefined);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
setCity(data.id);
|
|
104
|
+
}
|
|
105
|
+
setDistrict(undefined);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (data == null) {
|
|
109
|
+
setDistrict(undefined);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
setDistrict(data.id);
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
// Layout
|
|
116
|
+
return (React.createElement(React.Fragment, null,
|
|
117
|
+
label && (React.createElement(Grid, { item: true, xs: 12 },
|
|
118
|
+
React.createElement(FormLabel, { required: required, sx: { fontSize: (theme) => theme.typography.caption } }, label))),
|
|
119
|
+
!hideRegion && (React.createElement(Grid, { item: true, xs: 12, md: 6, lg: fieldSize },
|
|
120
|
+
React.createElement(Tiplist, { label: regionLabel, name: AddressField.Region, search: search, fullWidth: true, idValue: regionState, loadData: (keyword, id, items) => api.getRegions({ keyword, id, items }), inputRequired: required, inputError: error, inputHelperText: helperText, onChange: (_event, value) => handleChange([AddressField.Region, value]) }))),
|
|
121
|
+
React.createElement(Grid, { item: true, xs: 12, md: 6, lg: fieldSize },
|
|
122
|
+
React.createElement(ComboBox, { name: AddressField.State, label: stateLabel, search: search, fullWidth: true, idValue: stateState, options: states, inputRequired: hideRegion ? required : undefined, inputError: hideRegion ? error : undefined, inputHelperText: hideRegion ? helperText : undefined, onChange: (_event, value) => handleChange([AddressField.State, value]) })),
|
|
123
|
+
React.createElement(Grid, { item: true, xs: 12, md: 6, lg: fieldSize },
|
|
124
|
+
React.createElement(ComboBox, { name: AddressField.City, label: cityLabel, search: search, fullWidth: true, idValue: cityState, options: cities, onChange: (_event, value) => handleChange([AddressField.City, value]) })),
|
|
125
|
+
React.createElement(Grid, { item: true, xs: 12, md: 6, lg: fieldSize },
|
|
126
|
+
React.createElement(ComboBox, { name: AddressField.District, label: districtLabel, search: search, fullWidth: true, idValue: districtState, options: districts, onChange: (_event, value) => handleChange([AddressField.District, value]) }))));
|
|
127
|
+
}
|
package/lib/ComboBox.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { AutocompleteExtendedProps } from "./AutocompleteExtendedProps";
|
|
|
4
4
|
/**
|
|
5
5
|
* ComboBox props
|
|
6
6
|
*/
|
|
7
|
-
export type ComboBoxProps<T extends object = ListType, D extends DataTypes.Keys<T> = IdDefaultType<T>, L extends DataTypes.Keys<T, string> = LabelDefaultType<T>> = AutocompleteExtendedProps<T, D> & {
|
|
7
|
+
export type ComboBoxProps<T extends object = ListType, D extends DataTypes.Keys<T> = IdDefaultType<T>, L extends DataTypes.Keys<T, string> = LabelDefaultType<T>> = AutocompleteExtendedProps<T, D, false> & {
|
|
8
8
|
/**
|
|
9
9
|
* Auto add blank item
|
|
10
10
|
*/
|
|
@@ -21,10 +21,6 @@ export type ComboBoxProps<T extends object = ListType, D extends DataTypes.Keys<
|
|
|
21
21
|
* Load data callback
|
|
22
22
|
*/
|
|
23
23
|
loadData?: () => PromiseLike<T[] | null | undefined>;
|
|
24
|
-
/**
|
|
25
|
-
* Multiple
|
|
26
|
-
*/
|
|
27
|
-
multiple?: boolean;
|
|
28
24
|
/**
|
|
29
25
|
* On load data handler
|
|
30
26
|
*/
|
|
@@ -33,10 +29,6 @@ export type ComboBoxProps<T extends object = ListType, D extends DataTypes.Keys<
|
|
|
33
29
|
* Array of options.
|
|
34
30
|
*/
|
|
35
31
|
options?: ReadonlyArray<T>;
|
|
36
|
-
/**
|
|
37
|
-
* Id values
|
|
38
|
-
*/
|
|
39
|
-
idValues?: T[D][];
|
|
40
32
|
};
|
|
41
33
|
/**
|
|
42
34
|
* ComboBox
|
package/lib/ComboBox.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { Keyboard } from "@etsoo/shared";
|
|
2
|
-
import { Autocomplete
|
|
2
|
+
import { Autocomplete } from "@mui/material";
|
|
3
3
|
import React from "react";
|
|
4
4
|
import { Utils as SharedUtils } from "@etsoo/shared";
|
|
5
5
|
import { ReactUtils } from "@etsoo/react";
|
|
6
|
-
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
|
|
7
|
-
import CheckBoxIcon from "@mui/icons-material/CheckBox";
|
|
8
6
|
import { SearchField } from "./SearchField";
|
|
9
7
|
import { InputField } from "./InputField";
|
|
10
8
|
import { globalApp } from "./app/ReactApp";
|
|
11
|
-
const icon = React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
|
|
12
|
-
const checkedIcon = React.createElement(CheckBoxIcon, { fontSize: "small" });
|
|
13
9
|
/**
|
|
14
10
|
* ComboBox
|
|
15
11
|
* @param props Props
|
|
@@ -19,13 +15,8 @@ export function ComboBox(props) {
|
|
|
19
15
|
// Labels
|
|
20
16
|
const labels = globalApp === null || globalApp === void 0 ? void 0 : globalApp.getLabels("noOptions", "loading");
|
|
21
17
|
// Destruct
|
|
22
|
-
const { search = false, autoAddBlankItem = search, idField = "id", idValue,
|
|
23
|
-
options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect =
|
|
24
|
-
? (props, option, { selected }) => (React.createElement("li", { ...props },
|
|
25
|
-
React.createElement(React.Fragment, null,
|
|
26
|
-
React.createElement(Checkbox, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }),
|
|
27
|
-
option[labelField])))
|
|
28
|
-
: undefined, getOptionLabel = (option) => `${option[labelField]}`, sx = { minWidth: "150px" }, noOptionsText = labels === null || labels === void 0 ? void 0 : labels.noOptions, loadingText = labels === null || labels === void 0 ? void 0 : labels.loading, ...rest } = props;
|
|
18
|
+
const { search = false, autoAddBlankItem = search, idField = "id", idValue, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "new-password", // disable autocomplete and autofill, 'off' does not work
|
|
19
|
+
options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = false, getOptionLabel = (option) => `${option[labelField]}`, sx = { minWidth: "150px" }, noOptionsText = labels === null || labels === void 0 ? void 0 : labels.noOptions, loadingText = labels === null || labels === void 0 ? void 0 : labels.loading, ...rest } = props;
|
|
29
20
|
// Value input ref
|
|
30
21
|
const inputRef = React.createRef();
|
|
31
22
|
// Options state
|
|
@@ -35,27 +26,18 @@ export function ComboBox(props) {
|
|
|
35
26
|
// [options] will cause infinite loop
|
|
36
27
|
const propertyWay = loadData == null;
|
|
37
28
|
React.useEffect(() => {
|
|
38
|
-
if (propertyWay && options != null)
|
|
29
|
+
if (propertyWay && options != null) {
|
|
39
30
|
setOptions(options);
|
|
31
|
+
if (stateValue != null &&
|
|
32
|
+
!options.some((option) => option[idField] === stateValue[idField])) {
|
|
33
|
+
setStateValue(null);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
40
36
|
}, [options, propertyWay]);
|
|
41
37
|
// Local default value
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
idValue != null
|
|
46
|
-
? localOptions.filter((o) => o[idField] === idValue)
|
|
47
|
-
: idValues != null
|
|
48
|
-
? localOptions.filter((o) => idValues === null || idValues === void 0 ? void 0 : idValues.includes(o[idField]))
|
|
49
|
-
: defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
localValue =
|
|
53
|
-
idValue != null
|
|
54
|
-
? localOptions.find((o) => o[idField] === idValue)
|
|
55
|
-
: idValues != null
|
|
56
|
-
? localOptions.filter((o) => idValues === null || idValues === void 0 ? void 0 : idValues.includes(o[idField]))
|
|
57
|
-
: defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
|
|
58
|
-
}
|
|
38
|
+
const localValue = idValue != null
|
|
39
|
+
? localOptions.find((o) => o[idField] === idValue)
|
|
40
|
+
: defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
|
|
59
41
|
// State
|
|
60
42
|
// null for controlled
|
|
61
43
|
const [stateValue, setStateValue] = React.useState(null);
|
|
@@ -127,11 +109,11 @@ export function ComboBox(props) {
|
|
|
127
109
|
// Layout
|
|
128
110
|
return (React.createElement("div", null,
|
|
129
111
|
React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: "none" }, name: name, value: getValue(stateValue), readOnly: true, onChange: inputOnChange }),
|
|
130
|
-
React.createElement(Autocomplete, { value:
|
|
112
|
+
React.createElement(Autocomplete, { value: stateValue, disableCloseOnSelect: disableCloseOnSelect, getOptionLabel: getOptionLabel, isOptionEqualToValue: (option, value) => option[idField] === value[idField], onChange: (event, value, reason, details) => {
|
|
131
113
|
// Set value
|
|
132
114
|
setInputValue(value);
|
|
133
115
|
// Custom
|
|
134
116
|
if (onChange != null)
|
|
135
117
|
onChange(event, value, reason, details);
|
|
136
|
-
}, openOnFocus: openOnFocus, sx: sx, renderInput: (params) => search ? (React.createElement(SearchField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })) : (React.createElement(InputField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })), options: localOptions,
|
|
118
|
+
}, openOnFocus: openOnFocus, sx: sx, renderInput: (params) => search ? (React.createElement(SearchField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })) : (React.createElement(InputField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })), options: localOptions, noOptionsText: noOptionsText, loadingText: loadingText, ...rest })));
|
|
137
119
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
import { DataTypes, IdDefaultType, LabelDefaultType, ListType } from "@etsoo/shared";
|
|
3
|
+
import { AutocompleteExtendedProps } from "./AutocompleteExtendedProps";
|
|
4
|
+
/**
|
|
5
|
+
* ComboBox multiple props
|
|
6
|
+
*/
|
|
7
|
+
export type ComboBoxMultipleProps<T extends object = ListType, D extends DataTypes.Keys<T> = IdDefaultType<T>, L extends DataTypes.Keys<T, string> = LabelDefaultType<T>> = AutocompleteExtendedProps<T, D, true> & {
|
|
8
|
+
/**
|
|
9
|
+
* Auto add blank item
|
|
10
|
+
*/
|
|
11
|
+
autoAddBlankItem?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Data readonly
|
|
14
|
+
*/
|
|
15
|
+
dataReadonly?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Label field
|
|
18
|
+
*/
|
|
19
|
+
labelField?: L;
|
|
20
|
+
/**
|
|
21
|
+
* Load data callback
|
|
22
|
+
*/
|
|
23
|
+
loadData?: () => PromiseLike<T[] | null | undefined>;
|
|
24
|
+
/**
|
|
25
|
+
* On load data handler
|
|
26
|
+
*/
|
|
27
|
+
onLoadData?: (options: T[]) => void;
|
|
28
|
+
/**
|
|
29
|
+
* Array of options.
|
|
30
|
+
*/
|
|
31
|
+
options?: ReadonlyArray<T>;
|
|
32
|
+
/**
|
|
33
|
+
* Id values
|
|
34
|
+
*/
|
|
35
|
+
idValues?: T[D][];
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* ComboBox multiple
|
|
39
|
+
* @param props Props
|
|
40
|
+
* @returns Component
|
|
41
|
+
*/
|
|
42
|
+
export declare function ComboBoxMultiple<T extends object = ListType, D extends DataTypes.Keys<T> = IdDefaultType<T>, L extends DataTypes.Keys<T, string> = LabelDefaultType<T>>(props: ComboBoxMultipleProps<T, D, L>): JSX.Element;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Keyboard } from "@etsoo/shared";
|
|
2
|
+
import { Autocomplete, Checkbox } from "@mui/material";
|
|
3
|
+
import React from "react";
|
|
4
|
+
import { Utils as SharedUtils } from "@etsoo/shared";
|
|
5
|
+
import { ReactUtils } from "@etsoo/react";
|
|
6
|
+
import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
|
|
7
|
+
import CheckBoxIcon from "@mui/icons-material/CheckBox";
|
|
8
|
+
import { SearchField } from "./SearchField";
|
|
9
|
+
import { InputField } from "./InputField";
|
|
10
|
+
import { globalApp } from "./app/ReactApp";
|
|
11
|
+
const icon = React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" });
|
|
12
|
+
const checkedIcon = React.createElement(CheckBoxIcon, { fontSize: "small" });
|
|
13
|
+
/**
|
|
14
|
+
* ComboBox multiple
|
|
15
|
+
* @param props Props
|
|
16
|
+
* @returns Component
|
|
17
|
+
*/
|
|
18
|
+
export function ComboBoxMultiple(props) {
|
|
19
|
+
// Labels
|
|
20
|
+
const labels = globalApp === null || globalApp === void 0 ? void 0 : globalApp.getLabels("noOptions", "loading");
|
|
21
|
+
// Destruct
|
|
22
|
+
const { search = false, autoAddBlankItem = search, idField = "id", idValue, idValues, inputError, inputHelperText, inputMargin, inputOnChange, inputRequired, inputVariant, defaultValue, label, labelField = "label", loadData, onLoadData, name, inputAutoComplete = "new-password", // disable autocomplete and autofill, 'off' does not work
|
|
23
|
+
options, dataReadonly = true, readOnly, onChange, openOnFocus = true, value, disableCloseOnSelect = true, renderOption = (props, option, { selected }) => (React.createElement("li", { ...props },
|
|
24
|
+
React.createElement(React.Fragment, null,
|
|
25
|
+
React.createElement(Checkbox, { icon: icon, checkedIcon: checkedIcon, style: { marginRight: 8 }, checked: selected }),
|
|
26
|
+
option[labelField]))), getOptionLabel = (option) => `${option[labelField]}`, sx = { minWidth: "150px" }, noOptionsText = labels === null || labels === void 0 ? void 0 : labels.noOptions, loadingText = labels === null || labels === void 0 ? void 0 : labels.loading, ...rest } = props;
|
|
27
|
+
// Value input ref
|
|
28
|
+
const inputRef = React.createRef();
|
|
29
|
+
// Options state
|
|
30
|
+
const [localOptions, setOptions] = React.useState(options !== null && options !== void 0 ? options : []);
|
|
31
|
+
const isMounted = React.useRef(true);
|
|
32
|
+
// When options change
|
|
33
|
+
// [options] will cause infinite loop
|
|
34
|
+
const propertyWay = loadData == null;
|
|
35
|
+
React.useEffect(() => {
|
|
36
|
+
if (propertyWay && options != null) {
|
|
37
|
+
setOptions(options);
|
|
38
|
+
if (stateValue != null) {
|
|
39
|
+
if (Array.isArray(stateValue)) {
|
|
40
|
+
const newState = stateValue.filter((item) => options.some((option) => option[idField] === item[idField]));
|
|
41
|
+
setStateValue(newState);
|
|
42
|
+
}
|
|
43
|
+
else if (!options.some((option) => option[idField] === stateValue[idField])) {
|
|
44
|
+
setStateValue(null);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}, [options, propertyWay]);
|
|
49
|
+
// Local default value
|
|
50
|
+
const localValue = idValue != null
|
|
51
|
+
? localOptions.filter((o) => o[idField] === idValue)
|
|
52
|
+
: idValues != null
|
|
53
|
+
? localOptions.filter((o) => idValues === null || idValues === void 0 ? void 0 : idValues.includes(o[idField]))
|
|
54
|
+
: defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
|
|
55
|
+
// State
|
|
56
|
+
// null for controlled
|
|
57
|
+
const [stateValue, setStateValue] = React.useState(null);
|
|
58
|
+
React.useEffect(() => {
|
|
59
|
+
if (localValue != null && localValue != stateValue) {
|
|
60
|
+
setStateValue(localValue);
|
|
61
|
+
}
|
|
62
|
+
}, [localValue]);
|
|
63
|
+
// Add readOnly
|
|
64
|
+
const addReadOnly = (params) => {
|
|
65
|
+
if (readOnly != null) {
|
|
66
|
+
Object.assign(params, { readOnly });
|
|
67
|
+
if (readOnly) {
|
|
68
|
+
Object.assign(params.inputProps, { "data-reset": true });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (dataReadonly) {
|
|
72
|
+
params.inputProps.onKeyDown = (event) => {
|
|
73
|
+
if (Keyboard.isTypingContent(event.key)) {
|
|
74
|
+
event.preventDefault();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// https://stackoverflow.com/questions/15738259/disabling-chrome-autofill
|
|
79
|
+
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html
|
|
80
|
+
Object.assign(params.inputProps, { autoComplete: inputAutoComplete });
|
|
81
|
+
return params;
|
|
82
|
+
};
|
|
83
|
+
const getValue = (value) => {
|
|
84
|
+
if (value == null)
|
|
85
|
+
return "";
|
|
86
|
+
if (Array.isArray(value))
|
|
87
|
+
return value.map((item) => item[idField]).join(",");
|
|
88
|
+
return `${value[idField]}`;
|
|
89
|
+
};
|
|
90
|
+
const setInputValue = (value) => {
|
|
91
|
+
// Set state
|
|
92
|
+
setStateValue(value);
|
|
93
|
+
// Input value
|
|
94
|
+
const input = inputRef.current;
|
|
95
|
+
if (input) {
|
|
96
|
+
// Update value
|
|
97
|
+
const newValue = getValue(value);
|
|
98
|
+
if (newValue !== input.value) {
|
|
99
|
+
// Different value, trigger change event
|
|
100
|
+
ReactUtils.triggerChange(input, newValue, false);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
React.useEffect(() => {
|
|
105
|
+
if (propertyWay || loadData == null)
|
|
106
|
+
return;
|
|
107
|
+
loadData().then((result) => {
|
|
108
|
+
if (result == null || !isMounted.current)
|
|
109
|
+
return;
|
|
110
|
+
if (onLoadData)
|
|
111
|
+
onLoadData(result);
|
|
112
|
+
if (autoAddBlankItem) {
|
|
113
|
+
SharedUtils.addBlankItem(result, idField, labelField);
|
|
114
|
+
}
|
|
115
|
+
setOptions(result);
|
|
116
|
+
});
|
|
117
|
+
}, [propertyWay, autoAddBlankItem, idField, labelField]);
|
|
118
|
+
React.useEffect(() => {
|
|
119
|
+
return () => {
|
|
120
|
+
isMounted.current = false;
|
|
121
|
+
};
|
|
122
|
+
}, []);
|
|
123
|
+
// Layout
|
|
124
|
+
return (React.createElement("div", null,
|
|
125
|
+
React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: "none" }, name: name, value: getValue(stateValue), readOnly: true, onChange: inputOnChange }),
|
|
126
|
+
React.createElement(Autocomplete, { value: stateValue == null
|
|
127
|
+
? undefined
|
|
128
|
+
: Array.isArray(stateValue)
|
|
129
|
+
? stateValue
|
|
130
|
+
: [stateValue], disableCloseOnSelect: disableCloseOnSelect, getOptionLabel: getOptionLabel, isOptionEqualToValue: (option, value) => option[idField] === value[idField], onChange: (event, value, reason, details) => {
|
|
131
|
+
// Set value
|
|
132
|
+
setInputValue(value);
|
|
133
|
+
// Custom
|
|
134
|
+
if (onChange != null)
|
|
135
|
+
onChange(event, value, reason, details);
|
|
136
|
+
}, openOnFocus: openOnFocus, sx: sx, renderInput: (params) => search ? (React.createElement(SearchField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })) : (React.createElement(InputField, { ...addReadOnly(params), label: label, name: name + "Input", margin: inputMargin, variant: inputVariant, required: inputRequired, error: inputError, helperText: inputHelperText })), options: localOptions, renderOption: renderOption, noOptionsText: noOptionsText, loadingText: loadingText, ...rest })));
|
|
137
|
+
}
|
package/lib/HiSelector.js
CHANGED
|
@@ -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
|
|
11
|
+
const { idField = "id", error, helperText, name, label, 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)
|
|
@@ -40,9 +40,9 @@ export function HiSelector(props) {
|
|
|
40
40
|
}, [values]);
|
|
41
41
|
const currentValue = localValues.at(-1);
|
|
42
42
|
return (React.createElement(React.Fragment, null,
|
|
43
|
-
React.createElement(Grid, { item: true, xs: 12 },
|
|
44
|
-
React.createElement(FormLabel, { required: required, sx: { fontSize: (theme) => theme.typography.caption } }, label),
|
|
45
|
-
|
|
43
|
+
label && (React.createElement(Grid, { item: true, xs: 12 },
|
|
44
|
+
React.createElement(FormLabel, { required: required, sx: { fontSize: (theme) => theme.typography.caption } }, label))),
|
|
45
|
+
React.createElement("input", { type: "hidden", name: name, value: `${currentValue !== null && currentValue !== void 0 ? currentValue : ""}` }),
|
|
46
46
|
React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
|
|
47
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 })),
|
|
48
48
|
localValues[0] != null && (React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
|
package/lib/HiSelectorTL.js
CHANGED
|
@@ -35,9 +35,9 @@ export function HiSelectorTL(props) {
|
|
|
35
35
|
}, [values.toString()]);
|
|
36
36
|
const currentValue = localValues.at(-1);
|
|
37
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
|
-
|
|
38
|
+
label && (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
41
|
React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
|
|
42
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
43
|
localValues[0] != null && (React.createElement(Grid, { item: true, xs: 6, md: 4, lg: 3 },
|
package/lib/index.d.ts
CHANGED
|
@@ -26,12 +26,14 @@ export * from "./pages/ViewPage";
|
|
|
26
26
|
export * from "./texts/DateText";
|
|
27
27
|
export * from "./texts/MoneyText";
|
|
28
28
|
export * from "./texts/NumberText";
|
|
29
|
+
export * from "./AddresSelector";
|
|
29
30
|
export * from "./AuditDisplay";
|
|
30
31
|
export * from "./AutocompleteExtendedProps";
|
|
31
32
|
export * from "./BackButton";
|
|
32
33
|
export * from "./BridgeCloseButton";
|
|
33
34
|
export * from "./ButtonLink";
|
|
34
35
|
export * from "./ComboBox";
|
|
36
|
+
export * from "./ComboBoxMultiple";
|
|
35
37
|
export * from "./CountdownButton";
|
|
36
38
|
export * from "./CountryList";
|
|
37
39
|
export * from "./CustomFabProps";
|
package/lib/index.js
CHANGED
|
@@ -26,12 +26,14 @@ export * from "./pages/ViewPage";
|
|
|
26
26
|
export * from "./texts/DateText";
|
|
27
27
|
export * from "./texts/MoneyText";
|
|
28
28
|
export * from "./texts/NumberText";
|
|
29
|
+
export * from "./AddresSelector";
|
|
29
30
|
export * from "./AuditDisplay";
|
|
30
31
|
export * from "./AutocompleteExtendedProps";
|
|
31
32
|
export * from "./BackButton";
|
|
32
33
|
export * from "./BridgeCloseButton";
|
|
33
34
|
export * from "./ButtonLink";
|
|
34
35
|
export * from "./ComboBox";
|
|
36
|
+
export * from "./ComboBoxMultiple";
|
|
35
37
|
export * from "./CountdownButton";
|
|
36
38
|
export * from "./CountryList";
|
|
37
39
|
export * from "./CustomFabProps";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@etsoo/materialui",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.45",
|
|
4
4
|
"description": "TypeScript Material-UI Implementation",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"@emotion/css": "^11.10.6",
|
|
51
51
|
"@emotion/react": "^11.10.6",
|
|
52
52
|
"@emotion/styled": "^11.10.6",
|
|
53
|
-
"@etsoo/appscript": "^1.3.
|
|
53
|
+
"@etsoo/appscript": "^1.3.70",
|
|
54
54
|
"@etsoo/notificationbase": "^1.1.24",
|
|
55
55
|
"@etsoo/react": "^1.6.49",
|
|
56
56
|
"@etsoo/shared": "^1.1.89",
|