@etsoo/materialui 1.1.71 → 1.1.72

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.
@@ -0,0 +1,34 @@
1
+ /// <reference types="react" />
2
+ import { AutocompleteProps } from "@mui/material";
3
+ import { InputFieldProps } from "./InputField";
4
+ type DataType = {
5
+ id: number | string;
6
+ } & ({
7
+ label: string;
8
+ } | {
9
+ name: string;
10
+ });
11
+ export type ComboBoxProProps<D extends DataType = DataType> = Omit<AutocompleteProps<D, false, false, true>, "open" | "multiple" | "options" | "renderInput"> & {
12
+ /**
13
+ * Label
14
+ */
15
+ label?: string;
16
+ /**
17
+ * Field name
18
+ */
19
+ name?: string;
20
+ /**
21
+ * Id value
22
+ */
23
+ idValue?: D["id"] | null;
24
+ /**
25
+ * Options
26
+ */
27
+ options: (() => PromiseLike<D[] | null | undefined>) | D[];
28
+ /**
29
+ * Input props
30
+ */
31
+ inputProps?: Omit<InputFieldProps, "onChange">;
32
+ };
33
+ export declare function ComboBoxPro<D extends DataType = DataType>(props: ComboBoxProProps<D>): JSX.Element;
34
+ export {};
@@ -0,0 +1,50 @@
1
+ import { Autocomplete } from "@mui/material";
2
+ import React from "react";
3
+ import { globalApp } from "./app/ReactApp";
4
+ import { InputField } from "./InputField";
5
+ export function ComboBoxPro(props) {
6
+ var _a;
7
+ // Labels
8
+ const { noOptions, loading: loadingLabel, open: openDefault } = (_a = globalApp === null || globalApp === void 0 ? void 0 : globalApp.getLabels("noOptions", "loading", "open")) !== null && _a !== void 0 ? _a : {};
9
+ const getLabel = (item) => "label" in item ? item.label : "name" in item ? item.name : "";
10
+ // Destruct
11
+ const { noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, options, openOnFocus = true, label, inputProps, name, value, idValue, onChange, ...rest } = props;
12
+ const [open, setOpen] = React.useState(false);
13
+ const [localOptions, setOptions] = React.useState([]);
14
+ const [localValue, setValue] = React.useState(null);
15
+ const [loading, setLoading] = React.useState(false);
16
+ React.useEffect(() => {
17
+ if (value == null)
18
+ return;
19
+ setValue(value);
20
+ }, [value]);
21
+ React.useEffect(() => {
22
+ if (idValue == null)
23
+ return;
24
+ const option = localOptions.find((option) => option.id === idValue);
25
+ if (option)
26
+ setValue(option);
27
+ }, [localOptions]);
28
+ React.useEffect(() => {
29
+ if (typeof options === "function") {
30
+ setLoading(true);
31
+ options().then((result) => {
32
+ setLoading(false);
33
+ if (result != null)
34
+ setOptions(result);
35
+ });
36
+ }
37
+ else {
38
+ setOptions(options);
39
+ }
40
+ }, [options]);
41
+ return (React.createElement(Autocomplete, { id: name, value: localValue, open: open, freeSolo: true, onOpen: () => {
42
+ setOpen(true);
43
+ }, onClose: () => {
44
+ setOpen(false);
45
+ }, options: localOptions, loading: loading, openOnFocus: openOnFocus, renderInput: (params) => (React.createElement(InputField, { ...inputProps, ...params, label: label, name: name })), getOptionLabel: (item) => typeof item === "object" ? getLabel(item) : item, isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, onChange: (event, value, reason, details) => {
46
+ setValue(value);
47
+ if (onChange)
48
+ onChange(event, value, reason, details);
49
+ }, ...rest }));
50
+ }
package/lib/SelectEx.d.ts CHANGED
@@ -1,10 +1,10 @@
1
- import { SelectProps } from '@mui/material';
2
- import React from 'react';
3
- import { DataTypes, IdDefaultType, LabelDefaultType, ListType } from '@etsoo/shared';
1
+ import { SelectProps } from "@mui/material";
2
+ import React from "react";
3
+ import { DataTypes, IdDefaultType, LabelDefaultType, ListType } from "@etsoo/shared";
4
4
  /**
5
5
  * Extended select component props
6
6
  */
7
- export type SelectExProps<T extends object, D extends DataTypes.Keys<T> = IdDefaultType<T>, L extends DataTypes.Keys<T, string> = LabelDefaultType<T>> = Omit<SelectProps, 'labelId' | 'input' | 'native'> & {
7
+ export type SelectExProps<T extends object, D extends DataTypes.Keys<T> = IdDefaultType<T>, L extends DataTypes.Keys<T, string> = LabelDefaultType<T>> = Omit<SelectProps, "labelId" | "input" | "native"> & {
8
8
  /**
9
9
  * Auto add blank item
10
10
  */
package/lib/SelectEx.js CHANGED
@@ -1,10 +1,10 @@
1
- import { Checkbox, FormControl, FormHelperText, IconButton, InputLabel, ListItemText, MenuItem, OutlinedInput, Select, Stack } from '@mui/material';
2
- import React from 'react';
3
- import { MUGlobal } from './MUGlobal';
4
- import { ListItemRightIcon } from './ListItemRightIcon';
5
- import RefreshIcon from '@mui/icons-material/Refresh';
6
- import { Utils } from '@etsoo/shared';
7
- import { ReactUtils } from '@etsoo/react';
1
+ import { Checkbox, FormControl, FormHelperText, IconButton, InputLabel, ListItemText, MenuItem, OutlinedInput, Select, Stack } from "@mui/material";
2
+ import React from "react";
3
+ import { MUGlobal } from "./MUGlobal";
4
+ import { ListItemRightIcon } from "./ListItemRightIcon";
5
+ import RefreshIcon from "@mui/icons-material/Refresh";
6
+ import { ArrayUtils, Utils } from "@etsoo/shared";
7
+ import { ReactUtils } from "@etsoo/react";
8
8
  /**
9
9
  * Extended select component
10
10
  * @param props Props
@@ -12,7 +12,7 @@ import { ReactUtils } from '@etsoo/react';
12
12
  */
13
13
  export function SelectEx(props) {
14
14
  // Destruct
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
+ 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;
16
16
  // Options state
17
17
  const [localOptions, setOptions] = React.useState([]);
18
18
  const isMounted = React.useRef(false);
@@ -23,7 +23,7 @@ export function SelectEx(props) {
23
23
  if (multiple && Array.isArray(value)) {
24
24
  option = options.find((option) => value.includes(option[idField]));
25
25
  }
26
- else if (value == null || value === '') {
26
+ else if (value == null || value === "") {
27
27
  option = undefined;
28
28
  }
29
29
  else {
@@ -46,7 +46,7 @@ export function SelectEx(props) {
46
46
  }, [options, propertyWay]);
47
47
  // Local value
48
48
  const v = defaultValue !== null && defaultValue !== void 0 ? defaultValue : value;
49
- const valueSource = React.useMemo(() => (multiple ? (v ? (Array.isArray(v) ? v : [v]) : []) : v !== null && v !== void 0 ? v : ''), [multiple, v]);
49
+ const valueSource = React.useMemo(() => (multiple ? (v ? (Array.isArray(v) ? v : [v]) : []) : v !== null && v !== void 0 ? v : ""), [multiple, v]);
50
50
  // Value state
51
51
  const [valueState, setValueStateBase] = React.useState(valueSource);
52
52
  const valueRef = React.useRef();
@@ -66,10 +66,10 @@ export function SelectEx(props) {
66
66
  if (id !== valueRef.current) {
67
67
  // Difference
68
68
  const diff = multiple
69
- ? Utils.arrayDifferences(id, valueRef.current)
69
+ ? ArrayUtils.differences(id, valueRef.current)
70
70
  : id;
71
71
  setValueState(id);
72
- const input = (_a = divRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('input');
72
+ const input = (_a = divRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("input");
73
73
  if (input) {
74
74
  // Different value, trigger change event
75
75
  ReactUtils.triggerChange(input, id, false);
@@ -84,7 +84,7 @@ export function SelectEx(props) {
84
84
  };
85
85
  // Get option label
86
86
  const getLabel = (option) => {
87
- return typeof labelField === 'function'
87
+ return typeof labelField === "function"
88
88
  ? labelField(option)
89
89
  : option[labelField];
90
90
  };
@@ -112,30 +112,28 @@ export function SelectEx(props) {
112
112
  // When layout ready
113
113
  React.useEffect(() => {
114
114
  var _a;
115
- const input = (_a = divRef.current) === null || _a === void 0 ? void 0 : _a.querySelector('input');
115
+ const input = (_a = divRef.current) === null || _a === void 0 ? void 0 : _a.querySelector("input");
116
116
  const inputChange = (event) => {
117
117
  // Reset case
118
118
  if (event.cancelable)
119
- setValueState(multiple ? [] : '');
119
+ setValueState(multiple ? [] : "");
120
120
  };
121
- input === null || input === void 0 ? void 0 : input.addEventListener('change', inputChange);
121
+ input === null || input === void 0 ? void 0 : input.addEventListener("change", inputChange);
122
122
  isMounted.current = true;
123
123
  return () => {
124
124
  isMounted.current = false;
125
- input === null || input === void 0 ? void 0 : input.removeEventListener('change', inputChange);
125
+ input === null || input === void 0 ? void 0 : input.removeEventListener("change", inputChange);
126
126
  };
127
127
  }, [multiple]);
128
128
  // Layout
129
129
  return (React.createElement(Stack, { direction: "row" },
130
130
  React.createElement(FormControl, { size: search ? MUGlobal.searchFieldSize : MUGlobal.inputFieldSize, fullWidth: fullWidth, error: error },
131
- React.createElement(InputLabel, { id: labelId, shrink: search
132
- ? MUGlobal.searchFieldShrink
133
- : MUGlobal.inputFieldShrink }, label),
131
+ React.createElement(InputLabel, { id: labelId, shrink: search ? MUGlobal.searchFieldShrink : MUGlobal.inputFieldShrink }, label),
134
132
  React.createElement(Select, { ref: divRef, value: multiple
135
133
  ? valueState
136
134
  : localOptions.some((o) => o[idField] === valueState)
137
135
  ? valueState
138
- : '', input: React.createElement(OutlinedInput, { notched: true, label: label, required: inputRequired }), labelId: labelId, name: name, multiple: multiple, onChange: (event, child) => {
136
+ : "", input: React.createElement(OutlinedInput, { notched: true, label: label, required: inputRequired }), labelId: labelId, name: name, multiple: multiple, onChange: (event, child) => {
139
137
  if (onChange) {
140
138
  onChange(event, child);
141
139
  // event.preventDefault() will block executing
@@ -160,8 +158,8 @@ export function SelectEx(props) {
160
158
  : selected === id;
161
159
  })
162
160
  .map((option) => getLabel(option))
163
- .join(', ');
164
- }, sx: { minWidth: '150px' }, fullWidth: fullWidth, ...rest }, localOptions.map((option) => {
161
+ .join(", ");
162
+ }, sx: { minWidth: "150px" }, fullWidth: fullWidth, ...rest }, localOptions.map((option) => {
165
163
  // Option id
166
164
  const id = getId(option);
167
165
  // Option label
@@ -171,18 +169,16 @@ export function SelectEx(props) {
171
169
  if (onItemClick) {
172
170
  onItemClick(event, option);
173
171
  }
174
- }, style: itemStyle == null
175
- ? undefined
176
- : itemStyle(option) },
172
+ }, style: itemStyle == null ? undefined : itemStyle(option) },
177
173
  multiple && (React.createElement(Checkbox, { checked: Array.isArray(valueState)
178
174
  ? valueState.includes(id)
179
175
  : valueState === id })),
180
176
  React.createElement(ListItemText, { primary: label }),
181
177
  itemIconRenderer && (React.createElement(ListItemRightIcon, null, itemIconRenderer(option[idField])))));
182
178
  })),
183
- helperText != null && (React.createElement(FormHelperText, null, helperText))),
179
+ helperText != null && React.createElement(FormHelperText, null, helperText)),
184
180
  refresh != null &&
185
181
  loadData != null &&
186
- (typeof refresh === 'string' ? (React.createElement(IconButton, { size: "small", title: refresh, onClick: refreshData },
182
+ (typeof refresh === "string" ? (React.createElement(IconButton, { size: "small", title: refresh, onClick: refreshData },
187
183
  React.createElement(RefreshIcon, null))) : (refresh))));
188
184
  }
package/lib/TagList.js CHANGED
@@ -12,15 +12,22 @@ export function TagList(props) {
12
12
  // Destruct
13
13
  const { renderOption = (props, option, { selected }) => (React.createElement("li", { ...props },
14
14
  React.createElement(Checkbox, { icon: React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" }), checkedIcon: React.createElement(CheckBoxIcon, { fontSize: "small" }), style: { marginRight: 8 }, checked: selected }),
15
- option)), renderTags = (value, getTagProps) => value.map((option, index) => (React.createElement(Chip, { variant: "outlined", label: option, ...getTagProps({ index }) }))), noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, loadData, maxItems = 16, disableCloseOnSelect = true, openOnFocus = true, label, inputProps, ...rest } = props;
15
+ option)), renderTags = (value, getTagProps) => value.map((option, index) => (React.createElement(Chip, { variant: "outlined", label: option, ...getTagProps({ index }) }))), noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, loadData, maxItems = 16, disableCloseOnSelect = true, openOnFocus = true, label, inputProps, onChange, value, ...rest } = props;
16
16
  const [open, setOpen] = React.useState(false);
17
17
  const [options, setOptions] = React.useState([]);
18
18
  const [loading, setLoading] = React.useState(false);
19
+ const currentValue = React.useRef([]);
20
+ currentValue.current = value !== null && value !== void 0 ? value : [];
19
21
  const loadDataLocal = async (keyword) => {
20
22
  var _a;
21
23
  setLoading(true);
22
24
  const result = (_a = (await loadData(keyword, maxItems))) !== null && _a !== void 0 ? _a : [];
23
- if (result.length >= maxItems) {
25
+ const len = result.length;
26
+ currentValue.current.forEach((item) => {
27
+ if (!result.includes(item))
28
+ result.push(item);
29
+ });
30
+ if (len >= maxItems) {
24
31
  result.push(moreLabel);
25
32
  }
26
33
  setOptions(result);
@@ -40,5 +47,9 @@ export function TagList(props) {
40
47
  await loadDataLocal(event.target.value);
41
48
  }, ...inputProps, ...params })), getOptionDisabled: (item) => {
42
49
  return item === moreLabel;
43
- }, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, ...rest }));
50
+ }, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, value: value, onChange: (event, value, reason, details) => {
51
+ currentValue.current = value;
52
+ if (onChange)
53
+ onChange(event, value, reason, details);
54
+ }, ...rest }));
44
55
  }
@@ -0,0 +1,30 @@
1
+ /// <reference types="react" />
2
+ import { AutocompleteProps } from "@mui/material";
3
+ import { InputFieldProps } from "./InputField";
4
+ type DataType = {
5
+ id: number | string;
6
+ } & ({
7
+ label: string;
8
+ } | {
9
+ name: string;
10
+ });
11
+ export type TagListProProps<D extends DataType = DataType> = Omit<AutocompleteProps<D, true, false, false>, "open" | "multiple" | "options" | "renderInput"> & {
12
+ /**
13
+ * Label
14
+ */
15
+ label?: string;
16
+ /**
17
+ * Load data callback
18
+ */
19
+ loadData: (keyword: string | undefined, items: number) => PromiseLike<D[] | null | undefined>;
20
+ /**
21
+ * Input props
22
+ */
23
+ inputProps?: Omit<InputFieldProps, "onChange">;
24
+ /**
25
+ * Max items
26
+ */
27
+ maxItems?: number;
28
+ };
29
+ export declare function TagListPro<D extends DataType = DataType>(props: TagListProProps<D>): JSX.Element;
30
+ export {};
@@ -0,0 +1,59 @@
1
+ import { Autocomplete, Checkbox, Chip } from "@mui/material";
2
+ import CheckBoxOutlineBlankIcon from "@mui/icons-material/CheckBoxOutlineBlank";
3
+ import CheckBoxIcon from "@mui/icons-material/CheckBox";
4
+ import React from "react";
5
+ import { InputField } from "./InputField";
6
+ import { globalApp } from "./app/ReactApp";
7
+ export function TagListPro(props) {
8
+ var _a;
9
+ // Labels
10
+ const { noOptions, loading: loadingLabel, more = "More", open: openDefault } = (_a = globalApp === null || globalApp === void 0 ? void 0 : globalApp.getLabels("noOptions", "loading", "more", "open")) !== null && _a !== void 0 ? _a : {};
11
+ const moreLabel = more + "...";
12
+ const getLabel = (item) => "label" in item ? item.label : "name" in item ? item.name : "";
13
+ // Destruct
14
+ const { renderOption = (props, option, { selected }) => (React.createElement("li", { ...props },
15
+ React.createElement(React.Fragment, null,
16
+ React.createElement(Checkbox, { icon: React.createElement(CheckBoxOutlineBlankIcon, { fontSize: "small" }), checkedIcon: React.createElement(CheckBoxIcon, { fontSize: "small" }), style: { marginRight: 8 }, checked: selected }),
17
+ getLabel(option)))), renderTags = (value, getTagProps) => value.map((option, index) => (React.createElement(Chip, { variant: "outlined", label: getLabel(option), ...getTagProps({ index }) }))), noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, loadData, maxItems = 16, disableCloseOnSelect = true, openOnFocus = true, label, inputProps, onChange, value, ...rest } = props;
18
+ const [open, setOpen] = React.useState(false);
19
+ const [options, setOptions] = React.useState([]);
20
+ const [loading, setLoading] = React.useState(false);
21
+ const currentValue = React.useRef([]);
22
+ currentValue.current = value !== null && value !== void 0 ? value : [];
23
+ const loadDataLocal = async (keyword) => {
24
+ var _a;
25
+ setLoading(true);
26
+ const result = (_a = (await loadData(keyword, maxItems))) !== null && _a !== void 0 ? _a : [];
27
+ const len = result.length;
28
+ currentValue.current.forEach((item) => {
29
+ if (!result.some((r) => r.id === item.id))
30
+ result.push(item);
31
+ });
32
+ if (len >= maxItems) {
33
+ result.push({ id: -1, name: moreLabel });
34
+ }
35
+ setOptions(result);
36
+ setLoading(false);
37
+ };
38
+ return (React.createElement(Autocomplete, { multiple: true, filterOptions: (options, _state) => options, open: open, onOpen: () => {
39
+ setOpen(true);
40
+ if (options.length === 0) {
41
+ loadDataLocal();
42
+ }
43
+ }, onClose: () => {
44
+ setOpen(false);
45
+ }, options: options, loading: loading, disableCloseOnSelect: disableCloseOnSelect, openOnFocus: openOnFocus, renderOption: renderOption, renderTags: renderTags, renderInput: (params) => (React.createElement(InputField, { label: label, changeDelay: 480, onChange: async (event) => {
46
+ // Stop bubble
47
+ event.preventDefault();
48
+ event.stopPropagation();
49
+ await loadDataLocal(event.target.value);
50
+ }, ...inputProps, ...params })), getOptionDisabled: (item) => {
51
+ return (typeof item.id === "number" &&
52
+ item.id < 0 &&
53
+ getLabel(item) === moreLabel);
54
+ }, getOptionLabel: (item) => getLabel(item), isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, value: value, onChange: (event, value, reason, details) => {
55
+ currentValue.current = value;
56
+ if (onChange)
57
+ onChange(event, value, reason, details);
58
+ }, ...rest }));
59
+ }
package/lib/index.d.ts CHANGED
@@ -34,6 +34,7 @@ export * from "./BridgeCloseButton";
34
34
  export * from "./ButtonLink";
35
35
  export * from "./ComboBox";
36
36
  export * from "./ComboBoxMultiple";
37
+ export * from "./ComboBoxPro";
37
38
  export * from "./CountdownButton";
38
39
  export * from "./CountryList";
39
40
  export * from "./CustomFabProps";
@@ -87,6 +88,7 @@ export * from "./TableEx";
87
88
  export * from "./TextFieldEx";
88
89
  export * from "./Tiplist";
89
90
  export * from "./TagList";
91
+ export * from "./TagListPro";
90
92
  export * from "./TwoFieldInput";
91
93
  export * from "./TooltipClick";
92
94
  export * from "./UserAvatar";
package/lib/index.js CHANGED
@@ -34,6 +34,7 @@ export * from "./BridgeCloseButton";
34
34
  export * from "./ButtonLink";
35
35
  export * from "./ComboBox";
36
36
  export * from "./ComboBoxMultiple";
37
+ export * from "./ComboBoxPro";
37
38
  export * from "./CountdownButton";
38
39
  export * from "./CountryList";
39
40
  export * from "./CustomFabProps";
@@ -87,6 +88,7 @@ export * from "./TableEx";
87
88
  export * from "./TextFieldEx";
88
89
  export * from "./Tiplist";
89
90
  export * from "./TagList";
91
+ export * from "./TagListPro";
90
92
  export * from "./TwoFieldInput";
91
93
  export * from "./TooltipClick";
92
94
  export * from "./UserAvatar";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.1.71",
3
+ "version": "1.1.72",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -50,10 +50,10 @@
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.82",
53
+ "@etsoo/appscript": "^1.3.83",
54
54
  "@etsoo/notificationbase": "^1.1.24",
55
- "@etsoo/react": "^1.6.55",
56
- "@etsoo/shared": "^1.1.92",
55
+ "@etsoo/react": "^1.6.56",
56
+ "@etsoo/shared": "^1.1.93",
57
57
  "@mui/icons-material": "^5.11.11",
58
58
  "@mui/material": "^5.11.14",
59
59
  "@mui/x-data-grid": "^6.0.3",
@@ -0,0 +1,129 @@
1
+ import { Autocomplete, AutocompleteProps } from "@mui/material";
2
+ import React from "react";
3
+ import { globalApp } from "./app/ReactApp";
4
+ import { InputField, InputFieldProps } from "./InputField";
5
+
6
+ type DataType = {
7
+ id: number | string;
8
+ } & ({ label: string } | { name: string });
9
+
10
+ export type ComboBoxProProps<D extends DataType = DataType> = Omit<
11
+ AutocompleteProps<D, false, false, true>,
12
+ "open" | "multiple" | "options" | "renderInput"
13
+ > & {
14
+ /**
15
+ * Label
16
+ */
17
+ label?: string;
18
+
19
+ /**
20
+ * Field name
21
+ */
22
+ name?: string;
23
+
24
+ /**
25
+ * Id value
26
+ */
27
+ idValue?: D["id"] | null;
28
+
29
+ /**
30
+ * Options
31
+ */
32
+ options: (() => PromiseLike<D[] | null | undefined>) | D[];
33
+
34
+ /**
35
+ * Input props
36
+ */
37
+ inputProps?: Omit<InputFieldProps, "onChange">;
38
+ };
39
+
40
+ export function ComboBoxPro<D extends DataType = DataType>(
41
+ props: ComboBoxProProps<D>
42
+ ) {
43
+ // Labels
44
+ const {
45
+ noOptions,
46
+ loading: loadingLabel,
47
+ open: openDefault
48
+ } = globalApp?.getLabels("noOptions", "loading", "open") ?? {};
49
+
50
+ const getLabel = (item: D) =>
51
+ "label" in item ? item.label : "name" in item ? item.name : "";
52
+
53
+ // Destruct
54
+ const {
55
+ noOptionsText = noOptions,
56
+ loadingText = loadingLabel,
57
+ openText = openDefault,
58
+ options,
59
+ openOnFocus = true,
60
+ label,
61
+ inputProps,
62
+ name,
63
+ value,
64
+ idValue,
65
+ onChange,
66
+ ...rest
67
+ } = props;
68
+
69
+ const [open, setOpen] = React.useState(false);
70
+ const [localOptions, setOptions] = React.useState<readonly D[]>([]);
71
+ const [localValue, setValue] = React.useState<string | D | null>(null);
72
+ const [loading, setLoading] = React.useState(false);
73
+
74
+ React.useEffect(() => {
75
+ if (value == null) return;
76
+ setValue(value);
77
+ }, [value]);
78
+
79
+ React.useEffect(() => {
80
+ if (idValue == null) return;
81
+ const option = localOptions.find((option) => option.id === idValue);
82
+ if (option) setValue(option);
83
+ }, [localOptions]);
84
+
85
+ React.useEffect(() => {
86
+ if (typeof options === "function") {
87
+ setLoading(true);
88
+ options().then((result) => {
89
+ setLoading(false);
90
+ if (result != null) setOptions(result);
91
+ });
92
+ } else {
93
+ setOptions(options);
94
+ }
95
+ }, [options]);
96
+
97
+ return (
98
+ <Autocomplete<D, false, false, true>
99
+ id={name}
100
+ value={localValue}
101
+ open={open}
102
+ freeSolo
103
+ onOpen={() => {
104
+ setOpen(true);
105
+ }}
106
+ onClose={() => {
107
+ setOpen(false);
108
+ }}
109
+ options={localOptions}
110
+ loading={loading}
111
+ openOnFocus={openOnFocus}
112
+ renderInput={(params) => (
113
+ <InputField {...inputProps} {...params} label={label} name={name} />
114
+ )}
115
+ getOptionLabel={(item) =>
116
+ typeof item === "object" ? getLabel(item) : item
117
+ }
118
+ isOptionEqualToValue={(option, value) => option.id === value.id}
119
+ noOptionsText={noOptionsText}
120
+ loadingText={loadingText}
121
+ openText={openText}
122
+ onChange={(event, value, reason, details) => {
123
+ setValue(value);
124
+ if (onChange) onChange(event, value, reason, details);
125
+ }}
126
+ {...rest}
127
+ />
128
+ );
129
+ }