@etsoo/materialui 1.2.1 → 1.2.3

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.
@@ -6,7 +6,6 @@ export function ComboBoxPro(props) {
6
6
  var _a;
7
7
  // Labels
8
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
9
  // Destruct
11
10
  const { noOptionsText = noOptions, loadingText = loadingLabel, openText = openDefault, options, openOnFocus = true, label, inputProps, name, value, idValue, onChange, ...rest } = props;
12
11
  const [open, setOpen] = React.useState(false);
@@ -47,7 +46,11 @@ export function ComboBoxPro(props) {
47
46
  }, options: localOptions, loading: loading, openOnFocus: openOnFocus, renderInput: (params) => (React.createElement(InputField, { ...inputProps, ...params, label: label, name: name, onBlur: (event) => {
48
47
  if (localValue == null && onChange)
49
48
  onChange(event, event.target.value, "blur", undefined);
50
- } })), 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) => {
49
+ } })), getOptionLabel: (item) => typeof item === "object"
50
+ ? "label" in item
51
+ ? item.label
52
+ : item.name
53
+ : item, isOptionEqualToValue: (option, value) => option.id === value.id, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, onChange: (event, value, reason, details) => {
51
54
  setValue(value);
52
55
  if (onChange)
53
56
  onChange(event, value, reason, details);
package/lib/SearchBar.js CHANGED
@@ -244,7 +244,7 @@ export function SearchBar(props) {
244
244
  React.createElement(IconButton, { title: labels.more, size: "medium", sx: { height: "40px" }, onClick: handleMore },
245
245
  React.createElement(MoreHorizIcon, null)),
246
246
  React.createElement(Button, { variant: "contained", size: "medium", ref: resetButtonRef, onClick: handleReset }, labels.reset))),
247
- hasMoreItems && (React.createElement(Drawer, { anchor: "right", sx: { minWidth: "250px" }, ModalProps: {
247
+ hasMoreItems && (React.createElement(Drawer, { anchor: "right", sx: { minWidth: "180px" }, ModalProps: {
248
248
  keepMounted: true
249
249
  }, open: open, onClose: () => updateOpen(false) },
250
250
  React.createElement("form", { onChange: moreFormChange, ref: (form) => {
@@ -0,0 +1,47 @@
1
+ import { ListType2 } from "@etsoo/shared";
2
+ import { AutocompleteProps } from "@mui/material";
3
+ import { ChangeEventHandler } from "react";
4
+ import { InputFieldProps } from "./InputField";
5
+ /**
6
+ * TiplistPro props
7
+ */
8
+ export type TiplistProProps<T extends ListType2 = ListType2> = Omit<AutocompleteProps<T, false, false, true>, "open" | "multiple" | "options" | "renderInput"> & {
9
+ /**
10
+ * Load data callback
11
+ */
12
+ loadData: (keyword: string | undefined, id: T["id"] | undefined, maxItems: number) => PromiseLike<T[] | null | undefined>;
13
+ /**
14
+ * Max items to read and display
15
+ */
16
+ maxItems?: number;
17
+ /**
18
+ * Width
19
+ */
20
+ width?: number;
21
+ /**
22
+ * Label
23
+ */
24
+ label?: string;
25
+ /**
26
+ * Field name
27
+ */
28
+ name?: string;
29
+ /**
30
+ * Id value
31
+ */
32
+ idValue?: T["id"] | null;
33
+ /**
34
+ * Input onChange hanlder
35
+ */
36
+ inputOnChange?: ChangeEventHandler<HTMLInputElement> | undefined;
37
+ /**
38
+ * Input props
39
+ */
40
+ inputProps?: Omit<InputFieldProps, "onChange">;
41
+ };
42
+ /**
43
+ * TiplistPro
44
+ * @param props Props
45
+ * @returns Component
46
+ */
47
+ export declare function TiplistPro<T extends ListType2 = ListType2>(props: TiplistProProps<T>): JSX.Element;
@@ -0,0 +1,173 @@
1
+ import { ReactUtils, useDelayedExecutor } from "@etsoo/react";
2
+ import { Autocomplete } from "@mui/material";
3
+ import React from "react";
4
+ import { InputField } from "./InputField";
5
+ import { globalApp } from "./app/ReactApp";
6
+ /**
7
+ * TiplistPro
8
+ * @param props Props
9
+ * @returns Component
10
+ */
11
+ export function TiplistPro(props) {
12
+ var _a;
13
+ // Labels
14
+ const { noOptions, loading, more, open: openDefault } = (_a = globalApp === null || globalApp === void 0 ? void 0 : globalApp.getLabels("noOptions", "loading", "more", "open")) !== null && _a !== void 0 ? _a : {};
15
+ // Destruct
16
+ const { label, loadData, defaultValue, value, idValue, maxItems = 16, width, name, inputOnChange, inputProps, sx, openOnFocus = true, noOptionsText = noOptions, loadingText = loading, openText = openDefault, getOptionDisabled, getOptionLabel, onChange, ...rest } = props;
17
+ if (width && sx)
18
+ Object.assign(sx, { width: `${width}px` });
19
+ // Value input ref
20
+ const inputRef = React.createRef();
21
+ // Local value
22
+ let localValue = value !== null && value !== void 0 ? value : defaultValue;
23
+ // One time calculation for input's default value (uncontrolled)
24
+ const localIdValue = idValue !== null && idValue !== void 0 ? idValue : (localValue != null && typeof localValue === "object"
25
+ ? localValue.id
26
+ : null);
27
+ // Changable states
28
+ const [states, stateUpdate] = React.useReducer((currentState, newState) => {
29
+ return { ...currentState, ...newState };
30
+ }, {
31
+ // Loading unknown
32
+ open: false,
33
+ options: [],
34
+ value: null
35
+ });
36
+ React.useEffect(() => {
37
+ if (localValue != value)
38
+ stateUpdate({ value: localValue });
39
+ }, [localValue]);
40
+ // Input value
41
+ const inputValue = React.useMemo(() => states.value && typeof states.value === "object"
42
+ ? states.value.id
43
+ : undefined, [states.value]);
44
+ // State
45
+ const [state] = React.useState({});
46
+ const isMounted = React.useRef(true);
47
+ // Change handler
48
+ const changeHandle = (event) => {
49
+ // Stop processing with auto trigger event
50
+ if (event.nativeEvent.cancelable && !event.nativeEvent.composed) {
51
+ stateUpdate({ options: [] });
52
+ return;
53
+ }
54
+ // Stop bubble
55
+ event.stopPropagation();
56
+ // Call with delay
57
+ delayed.call(undefined, event.currentTarget.value);
58
+ };
59
+ // Directly load data
60
+ const loadDataDirect = (keyword, id) => {
61
+ // Reset options
62
+ // setOptions([]);
63
+ if (id == null) {
64
+ // Reset real value
65
+ const input = inputRef.current;
66
+ if (input && input.value !== "") {
67
+ // Different value, trigger change event
68
+ ReactUtils.triggerChange(input, "", false);
69
+ }
70
+ if (states.options.length > 0) {
71
+ // Reset options
72
+ stateUpdate({ options: [] });
73
+ }
74
+ }
75
+ // Loading indicator
76
+ if (!states.loading)
77
+ stateUpdate({ loading: true });
78
+ // Load list
79
+ loadData(keyword, id, maxItems).then((options) => {
80
+ if (!isMounted.current)
81
+ return;
82
+ if (options != null && options.length >= maxItems) {
83
+ options.push({ id: -1, name: "n/a" });
84
+ }
85
+ // Indicates loading completed
86
+ stateUpdate({
87
+ loading: false,
88
+ ...(options != null && { options })
89
+ });
90
+ });
91
+ };
92
+ const delayed = useDelayedExecutor(loadDataDirect, 480);
93
+ const setInputValue = (value) => {
94
+ var _a;
95
+ stateUpdate({ value });
96
+ // Input value
97
+ const input = inputRef.current;
98
+ if (input) {
99
+ // Update value
100
+ const newValue = (_a = value === null || value === void 0 ? void 0 : value.id.toString()) !== null && _a !== void 0 ? _a : "";
101
+ if (newValue !== input.value) {
102
+ // Different value, trigger change event
103
+ ReactUtils.triggerChange(input, newValue, false);
104
+ }
105
+ }
106
+ };
107
+ if (localIdValue != null && localIdValue !== "") {
108
+ if (state.idLoaded) {
109
+ // Set default
110
+ if (!state.idSet && states.options.length == 1) {
111
+ stateUpdate({ value: states.options[0] });
112
+ state.idSet = true;
113
+ }
114
+ }
115
+ else {
116
+ // Load id data
117
+ loadDataDirect(undefined, localIdValue);
118
+ state.idLoaded = true;
119
+ }
120
+ }
121
+ React.useEffect(() => {
122
+ return () => {
123
+ isMounted.current = false;
124
+ delayed.clear();
125
+ };
126
+ }, []);
127
+ // Layout
128
+ return (React.createElement("div", null,
129
+ React.createElement("input", { ref: inputRef, "data-reset": "true", type: "text", style: { display: "none" }, name: name, value: inputValue !== null && inputValue !== void 0 ? inputValue : "", readOnly: true, onChange: inputOnChange }),
130
+ React.createElement(Autocomplete, { filterOptions: (options, _state) => options, value: states.value, options: states.options, freeSolo: true, clearOnBlur: false, onChange: (event, value, reason, details) => {
131
+ if (typeof value === "object") {
132
+ // Set value
133
+ setInputValue(value);
134
+ }
135
+ // Custom
136
+ if (onChange != null)
137
+ onChange(event, value, reason, details);
138
+ // For clear case
139
+ if (reason === "clear") {
140
+ stateUpdate({ options: [] });
141
+ loadDataDirect();
142
+ }
143
+ }, open: states.open, openOnFocus: openOnFocus, onOpen: () => {
144
+ // Should load
145
+ const loading = states.loading ? true : states.options.length === 0;
146
+ stateUpdate({ open: true, loading });
147
+ // If not loading
148
+ if (loading)
149
+ loadDataDirect(undefined, states.value && typeof states.value === "object"
150
+ ? states.value.id
151
+ : undefined);
152
+ }, onClose: () => {
153
+ stateUpdate({
154
+ open: false,
155
+ ...(!states.value && { options: [] })
156
+ });
157
+ }, loading: states.loading, renderInput: (params) => (React.createElement(InputField, { ...inputProps, ...params, onChange: changeHandle, label: label, name: name + "Input", onBlur: (event) => {
158
+ if (states.value == null && onChange)
159
+ onChange(event, event.target.value, "blur", undefined);
160
+ } })), isOptionEqualToValue: (option, value) => option.id === value.id, sx: sx, noOptionsText: noOptionsText, loadingText: loadingText, openText: openText, getOptionDisabled: (item) => {
161
+ if (item.id === -1)
162
+ return true;
163
+ return getOptionDisabled ? getOptionDisabled(item) : false;
164
+ }, getOptionLabel: (item) => {
165
+ if (typeof item === "string")
166
+ return item;
167
+ if (item["id"] === -1)
168
+ return (more !== null && more !== void 0 ? more : "More") + "...";
169
+ if (getOptionLabel == null)
170
+ return "label" in item ? item.label : item.name;
171
+ return getOptionLabel(item);
172
+ }, ...rest })));
173
+ }
package/lib/index.d.ts CHANGED
@@ -89,6 +89,7 @@ export * from "./TabBox";
89
89
  export * from "./TableEx";
90
90
  export * from "./TextFieldEx";
91
91
  export * from "./Tiplist";
92
+ export * from "./TiplistPro";
92
93
  export * from "./TagList";
93
94
  export * from "./TagListPro";
94
95
  export * from "./TwoFieldInput";
package/lib/index.js CHANGED
@@ -89,6 +89,7 @@ export * from "./TabBox";
89
89
  export * from "./TableEx";
90
90
  export * from "./TextFieldEx";
91
91
  export * from "./Tiplist";
92
+ export * from "./TiplistPro";
92
93
  export * from "./TagList";
93
94
  export * from "./TagListPro";
94
95
  export * from "./TwoFieldInput";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@etsoo/materialui",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "description": "TypeScript Material-UI Implementation",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -50,16 +50,16 @@
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.89",
53
+ "@etsoo/appscript": "^1.3.92",
54
54
  "@etsoo/notificationbase": "^1.1.24",
55
- "@etsoo/react": "^1.6.65",
56
- "@etsoo/shared": "^1.1.99",
55
+ "@etsoo/react": "^1.6.67",
56
+ "@etsoo/shared": "^1.2.1",
57
57
  "@mui/icons-material": "^5.11.16",
58
- "@mui/material": "^5.11.16",
59
- "@mui/x-data-grid": "^6.0.4",
58
+ "@mui/material": "^5.12.0",
59
+ "@mui/x-data-grid": "^6.2.0",
60
60
  "@types/pica": "^9.0.1",
61
61
  "@types/pulltorefreshjs": "^0.1.5",
62
- "@types/react": "^18.0.33",
62
+ "@types/react": "^18.0.35",
63
63
  "@types/react-avatar-editor": "^13.0.0",
64
64
  "@types/react-dom": "^18.0.11",
65
65
  "@types/react-input-mask": "^3.0.2",
@@ -70,7 +70,7 @@
70
70
  "react-avatar-editor": "^13.0.0",
71
71
  "react-dom": "^18.2.0",
72
72
  "react-draggable": "^4.4.5",
73
- "react-imask": "^6.5.0",
73
+ "react-imask": "^6.5.1",
74
74
  "react-router-dom": "^6.10.0",
75
75
  "react-window": "^1.8.8"
76
76
  },
@@ -85,8 +85,8 @@
85
85
  "@testing-library/jest-dom": "^5.16.5",
86
86
  "@testing-library/react": "^14.0.0",
87
87
  "@types/jest": "^29.5.0",
88
- "@typescript-eslint/eslint-plugin": "^5.57.1",
89
- "@typescript-eslint/parser": "^5.57.1",
88
+ "@typescript-eslint/eslint-plugin": "^5.58.0",
89
+ "@typescript-eslint/parser": "^5.58.0",
90
90
  "jest": "^29.5.0",
91
91
  "jest-environment-jsdom": "^29.5.0",
92
92
  "typescript": "^5.0.4"
@@ -44,9 +44,6 @@ export function ComboBoxPro<D extends ListType2 = ListType2>(
44
44
  open: openDefault
45
45
  } = globalApp?.getLabels("noOptions", "loading", "open") ?? {};
46
46
 
47
- const getLabel = (item: D) =>
48
- "label" in item ? item.label : "name" in item ? item.name : "";
49
-
50
47
  // Destruct
51
48
  const {
52
49
  noOptionsText = noOptions,
@@ -121,7 +118,11 @@ export function ComboBoxPro<D extends ListType2 = ListType2>(
121
118
  />
122
119
  )}
123
120
  getOptionLabel={(item) =>
124
- typeof item === "object" ? getLabel(item) : item
121
+ typeof item === "object"
122
+ ? "label" in item
123
+ ? item.label
124
+ : item.name
125
+ : item
125
126
  }
126
127
  isOptionEqualToValue={(option, value) => option.id === value.id}
127
128
  noOptionsText={noOptionsText}
package/src/SearchBar.tsx CHANGED
@@ -357,7 +357,7 @@ export function SearchBar(props: SearchBarProps) {
357
357
  {hasMoreItems && (
358
358
  <Drawer
359
359
  anchor="right"
360
- sx={{ minWidth: "250px" }}
360
+ sx={{ minWidth: "180px" }}
361
361
  ModalProps={{
362
362
  keepMounted: true
363
363
  }}
package/src/Tiplist.tsx CHANGED
@@ -1,7 +1,6 @@
1
1
  import { ReactUtils, useDelayedExecutor } from "@etsoo/react";
2
2
  import { DataTypes, IdDefaultType, ListType } from "@etsoo/shared";
3
3
  import { Autocomplete, AutocompleteRenderInputParams } from "@mui/material";
4
- import { width } from "@mui/system";
5
4
  import React from "react";
6
5
  import { globalApp } from "./app/ReactApp";
7
6
  import { AutocompleteExtendedProps } from "./AutocompleteExtendedProps";
@@ -0,0 +1,339 @@
1
+ import { ReactUtils, useDelayedExecutor } from "@etsoo/react";
2
+ import { ListType2 } from "@etsoo/shared";
3
+ import { Autocomplete, AutocompleteProps } from "@mui/material";
4
+ import React, { ChangeEventHandler } from "react";
5
+ import { InputField, InputFieldProps } from "./InputField";
6
+ import { globalApp } from "./app/ReactApp";
7
+
8
+ /**
9
+ * TiplistPro props
10
+ */
11
+ export type TiplistProProps<T extends ListType2 = ListType2> = Omit<
12
+ AutocompleteProps<T, false, false, true>,
13
+ "open" | "multiple" | "options" | "renderInput"
14
+ > & {
15
+ /**
16
+ * Load data callback
17
+ */
18
+ loadData: (
19
+ keyword: string | undefined,
20
+ id: T["id"] | undefined,
21
+ maxItems: number
22
+ ) => PromiseLike<T[] | null | undefined>;
23
+
24
+ /**
25
+ * Max items to read and display
26
+ */
27
+ maxItems?: number;
28
+
29
+ /**
30
+ * Width
31
+ */
32
+ width?: number;
33
+
34
+ /**
35
+ * Label
36
+ */
37
+ label?: string;
38
+
39
+ /**
40
+ * Field name
41
+ */
42
+ name?: string;
43
+
44
+ /**
45
+ * Id value
46
+ */
47
+ idValue?: T["id"] | null;
48
+
49
+ /**
50
+ * Input onChange hanlder
51
+ */
52
+ inputOnChange?: ChangeEventHandler<HTMLInputElement> | undefined;
53
+
54
+ /**
55
+ * Input props
56
+ */
57
+ inputProps?: Omit<InputFieldProps, "onChange">;
58
+ };
59
+
60
+ // Multiple states
61
+ interface States<T extends object> {
62
+ open: boolean;
63
+ options: T[];
64
+ value?: T | string | null | undefined;
65
+ loading?: boolean;
66
+ }
67
+
68
+ /**
69
+ * TiplistPro
70
+ * @param props Props
71
+ * @returns Component
72
+ */
73
+ export function TiplistPro<T extends ListType2 = ListType2>(
74
+ props: TiplistProProps<T>
75
+ ) {
76
+ // Labels
77
+ const {
78
+ noOptions,
79
+ loading,
80
+ more,
81
+ open: openDefault
82
+ } = globalApp?.getLabels("noOptions", "loading", "more", "open") ?? {};
83
+
84
+ // Destruct
85
+ const {
86
+ label,
87
+ loadData,
88
+ defaultValue,
89
+ value,
90
+ idValue,
91
+ maxItems = 16,
92
+ width,
93
+ name,
94
+ inputOnChange,
95
+ inputProps,
96
+ sx,
97
+ openOnFocus = true,
98
+ noOptionsText = noOptions,
99
+ loadingText = loading,
100
+ openText = openDefault,
101
+ getOptionDisabled,
102
+ getOptionLabel,
103
+ onChange,
104
+ ...rest
105
+ } = props;
106
+
107
+ if (width && sx) Object.assign(sx, { width: `${width}px` });
108
+
109
+ // Value input ref
110
+ const inputRef = React.createRef<HTMLInputElement>();
111
+
112
+ // Local value
113
+ let localValue = value ?? defaultValue;
114
+
115
+ // One time calculation for input's default value (uncontrolled)
116
+ const localIdValue =
117
+ idValue ??
118
+ (localValue != null && typeof localValue === "object"
119
+ ? localValue.id
120
+ : null);
121
+
122
+ // Changable states
123
+ const [states, stateUpdate] = React.useReducer(
124
+ (currentState: States<T>, newState: Partial<States<T>>) => {
125
+ return { ...currentState, ...newState };
126
+ },
127
+ {
128
+ // Loading unknown
129
+ open: false,
130
+ options: [],
131
+ value: null
132
+ }
133
+ );
134
+
135
+ React.useEffect(() => {
136
+ if (localValue != value) stateUpdate({ value: localValue });
137
+ }, [localValue]);
138
+
139
+ // Input value
140
+ const inputValue = React.useMemo(
141
+ () =>
142
+ states.value && typeof states.value === "object"
143
+ ? states.value.id
144
+ : undefined,
145
+ [states.value]
146
+ );
147
+
148
+ // State
149
+ const [state] = React.useState<{
150
+ idLoaded?: boolean;
151
+ idSet?: boolean;
152
+ }>({});
153
+ const isMounted = React.useRef(true);
154
+
155
+ // Change handler
156
+ const changeHandle = (event: React.ChangeEvent<HTMLInputElement>) => {
157
+ // Stop processing with auto trigger event
158
+ if (event.nativeEvent.cancelable && !event.nativeEvent.composed) {
159
+ stateUpdate({ options: [] });
160
+ return;
161
+ }
162
+
163
+ // Stop bubble
164
+ event.stopPropagation();
165
+
166
+ // Call with delay
167
+ delayed.call(undefined, event.currentTarget.value);
168
+ };
169
+
170
+ // Directly load data
171
+ const loadDataDirect = (keyword?: string, id?: T["id"]) => {
172
+ // Reset options
173
+ // setOptions([]);
174
+
175
+ if (id == null) {
176
+ // Reset real value
177
+ const input = inputRef.current;
178
+
179
+ if (input && input.value !== "") {
180
+ // Different value, trigger change event
181
+ ReactUtils.triggerChange(input, "", false);
182
+ }
183
+
184
+ if (states.options.length > 0) {
185
+ // Reset options
186
+ stateUpdate({ options: [] });
187
+ }
188
+ }
189
+
190
+ // Loading indicator
191
+ if (!states.loading) stateUpdate({ loading: true });
192
+
193
+ // Load list
194
+ loadData(keyword, id, maxItems).then((options) => {
195
+ if (!isMounted.current) return;
196
+
197
+ if (options != null && options.length >= maxItems) {
198
+ options.push({ id: -1, name: "n/a" } as T);
199
+ }
200
+
201
+ // Indicates loading completed
202
+ stateUpdate({
203
+ loading: false,
204
+ ...(options != null && { options })
205
+ });
206
+ });
207
+ };
208
+
209
+ const delayed = useDelayedExecutor(loadDataDirect, 480);
210
+
211
+ const setInputValue = (value: T | null) => {
212
+ stateUpdate({ value });
213
+
214
+ // Input value
215
+ const input = inputRef.current;
216
+ if (input) {
217
+ // Update value
218
+ const newValue = value?.id.toString() ?? "";
219
+ if (newValue !== input.value) {
220
+ // Different value, trigger change event
221
+ ReactUtils.triggerChange(input, newValue, false);
222
+ }
223
+ }
224
+ };
225
+
226
+ if (localIdValue != null && (localIdValue as any) !== "") {
227
+ if (state.idLoaded) {
228
+ // Set default
229
+ if (!state.idSet && states.options.length == 1) {
230
+ stateUpdate({ value: states.options[0] });
231
+ state.idSet = true;
232
+ }
233
+ } else {
234
+ // Load id data
235
+ loadDataDirect(undefined, localIdValue);
236
+ state.idLoaded = true;
237
+ }
238
+ }
239
+
240
+ React.useEffect(() => {
241
+ return () => {
242
+ isMounted.current = false;
243
+ delayed.clear();
244
+ };
245
+ }, []);
246
+
247
+ // Layout
248
+ return (
249
+ <div>
250
+ <input
251
+ ref={inputRef}
252
+ data-reset="true"
253
+ type="text"
254
+ style={{ display: "none" }}
255
+ name={name}
256
+ value={inputValue ?? ""}
257
+ readOnly
258
+ onChange={inputOnChange}
259
+ />
260
+ {/* Previous input will reset first with "disableClearable = false", next input trigger change works */}
261
+ <Autocomplete<T, false, false, true>
262
+ filterOptions={(options, _state) => options}
263
+ value={states.value}
264
+ options={states.options}
265
+ freeSolo
266
+ clearOnBlur={false}
267
+ onChange={(event, value, reason, details) => {
268
+ if (typeof value === "object") {
269
+ // Set value
270
+ setInputValue(value);
271
+ }
272
+
273
+ // Custom
274
+ if (onChange != null) onChange(event, value, reason, details);
275
+
276
+ // For clear case
277
+ if (reason === "clear") {
278
+ stateUpdate({ options: [] });
279
+ loadDataDirect();
280
+ }
281
+ }}
282
+ open={states.open}
283
+ openOnFocus={openOnFocus}
284
+ onOpen={() => {
285
+ // Should load
286
+ const loading = states.loading ? true : states.options.length === 0;
287
+
288
+ stateUpdate({ open: true, loading });
289
+
290
+ // If not loading
291
+ if (loading)
292
+ loadDataDirect(
293
+ undefined,
294
+ states.value && typeof states.value === "object"
295
+ ? states.value.id
296
+ : undefined
297
+ );
298
+ }}
299
+ onClose={() => {
300
+ stateUpdate({
301
+ open: false,
302
+ ...(!states.value && { options: [] })
303
+ });
304
+ }}
305
+ loading={states.loading}
306
+ renderInput={(params) => (
307
+ <InputField
308
+ {...inputProps}
309
+ {...params}
310
+ onChange={changeHandle}
311
+ label={label}
312
+ name={name + "Input"}
313
+ onBlur={(event) => {
314
+ if (states.value == null && onChange)
315
+ onChange(event, event.target.value, "blur", undefined);
316
+ }}
317
+ />
318
+ )}
319
+ isOptionEqualToValue={(option, value) => option.id === value.id}
320
+ sx={sx}
321
+ noOptionsText={noOptionsText}
322
+ loadingText={loadingText}
323
+ openText={openText}
324
+ getOptionDisabled={(item) => {
325
+ if (item.id === -1) return true;
326
+ return getOptionDisabled ? getOptionDisabled(item) : false;
327
+ }}
328
+ getOptionLabel={(item) => {
329
+ if (typeof item === "string") return item;
330
+ if (item["id"] === -1) return (more ?? "More") + "...";
331
+ if (getOptionLabel == null)
332
+ return "label" in item ? item.label : item.name;
333
+ return getOptionLabel(item);
334
+ }}
335
+ {...rest}
336
+ />
337
+ </div>
338
+ );
339
+ }
package/src/index.ts CHANGED
@@ -92,6 +92,7 @@ export * from "./TabBox";
92
92
  export * from "./TableEx";
93
93
  export * from "./TextFieldEx";
94
94
  export * from "./Tiplist";
95
+ export * from "./TiplistPro";
95
96
  export * from "./TagList";
96
97
  export * from "./TagListPro";
97
98
  export * from "./TwoFieldInput";