@engagebay/engagebay-form-module 1.0.5 → 1.0.6
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/package.json +1 -1
- package/src/form/FormFieldUtils.ts +4 -0
- package/src/form/formfields/DatePickerField.tsx +21 -13
- package/src/form/formfields/NumberField.tsx +55 -50
- package/src/form/formfields/Typeahead2.tsx +284 -0
- package/src/form/schema/FormFieldSchema.ts +4 -0
- package/src/form/util/RenderListOptions.tsx +8 -2
package/package.json
CHANGED
|
@@ -28,6 +28,7 @@ import TimeField from "./formfields/TimeField";
|
|
|
28
28
|
import Typeahead from "./formfields/Typeahead";
|
|
29
29
|
import TypeaheadMultiSelect from "./formfields/TypeaheadMultiSelect";
|
|
30
30
|
import UrlField from "./formfields/UrlField";
|
|
31
|
+
import Typeahead2 from "./formfields/Typeahead2";
|
|
31
32
|
import {
|
|
32
33
|
FieldOptionsSchema,
|
|
33
34
|
FormFieldComponentPropSchema,
|
|
@@ -136,6 +137,9 @@ const formFieldComponents: FormComponentSchema = {
|
|
|
136
137
|
[FormFieldType[FormFieldType.TYPEAHEAD]]: {
|
|
137
138
|
component: Typeahead,
|
|
138
139
|
},
|
|
140
|
+
[FormFieldType[FormFieldType.TYPEAHEAD_2]]: {
|
|
141
|
+
component: Typeahead2,
|
|
142
|
+
},
|
|
139
143
|
[FormFieldType[FormFieldType.TYPEAHEAD_MULTI_SELECT]]: {
|
|
140
144
|
component: TypeaheadMultiSelect,
|
|
141
145
|
},
|
|
@@ -35,14 +35,28 @@ const DatePicker: React.FC<FormFieldComponentPropSchema> = (
|
|
|
35
35
|
let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
|
|
36
36
|
|
|
37
37
|
function getInput() {
|
|
38
|
+
const rawStart =
|
|
39
|
+
initialDate?.startDate ||
|
|
40
|
+
props.fieldConfig.defaultValue ||
|
|
41
|
+
"";
|
|
42
|
+
const rawEnd =
|
|
43
|
+
initialDate?.endDate ||
|
|
44
|
+
props.fieldConfig.defaultValue ||
|
|
45
|
+
"";
|
|
46
|
+
const toDate = (v: string | Date | null | undefined): Date | null => {
|
|
47
|
+
if (v == null || v === "") return null;
|
|
48
|
+
return moment(v).isValid() ? moment(v).toDate() : null;
|
|
49
|
+
};
|
|
50
|
+
const value = {
|
|
51
|
+
startDate: toDate(rawStart),
|
|
52
|
+
endDate: toDate(rawEnd),
|
|
53
|
+
};
|
|
54
|
+
// Calendar opens on selected date's month/year (must be a Date instance)
|
|
55
|
+
const startFrom = value.startDate instanceof Date ? value.startDate : new Date();
|
|
38
56
|
return (
|
|
39
57
|
<Datepicker
|
|
40
|
-
value={
|
|
41
|
-
|
|
42
|
-
startDate: props.fieldConfig.defaultValue,
|
|
43
|
-
endDate: props.fieldConfig.defaultValue,
|
|
44
|
-
}
|
|
45
|
-
}
|
|
58
|
+
value={value}
|
|
59
|
+
startFrom={startFrom}
|
|
46
60
|
{...hookProps}
|
|
47
61
|
placeholder={
|
|
48
62
|
props.fieldConfig.placeholder
|
|
@@ -53,13 +67,7 @@ const DatePicker: React.FC<FormFieldComponentPropSchema> = (
|
|
|
53
67
|
popoverDirection="down"
|
|
54
68
|
useRange={false}
|
|
55
69
|
inputName={props.fieldConfig.name}
|
|
56
|
-
key={
|
|
57
|
-
props.fieldConfig.name +
|
|
58
|
-
"_" +
|
|
59
|
-
initialDate.startDate +
|
|
60
|
-
"_" +
|
|
61
|
-
initialDate.endDate
|
|
62
|
-
}
|
|
70
|
+
key={props.fieldConfig.name + "_" + rawStart + "_" + rawEnd}
|
|
63
71
|
containerClassName={"relative"}
|
|
64
72
|
minDate={props.fieldConfig.minDate}
|
|
65
73
|
maxDate={props.fieldConfig.maxDate}
|
|
@@ -1,61 +1,66 @@
|
|
|
1
|
-
import React, {useContext} from "react";
|
|
2
|
-
import {RegisterOptions} from "react-hook-form";
|
|
3
|
-
import {FormContext} from "../context/FormContext";
|
|
4
|
-
import {FormFieldComponentPropSchema} from "../schema/FormFieldSchema";
|
|
5
|
-
import {handleChange, registerFormField} from "../util";
|
|
1
|
+
import React, { useContext } from "react";
|
|
2
|
+
import { RegisterOptions } from "react-hook-form";
|
|
3
|
+
import { FormContext } from "../context/FormContext";
|
|
4
|
+
import { FormFieldComponentPropSchema } from "../schema/FormFieldSchema";
|
|
5
|
+
import { handleChange, registerFormField } from "../util";
|
|
6
6
|
import RenderFormField from "../util/RenderFormField";
|
|
7
7
|
|
|
8
8
|
const NumberField: React.FC<FormFieldComponentPropSchema> = (
|
|
9
|
-
|
|
9
|
+
props: FormFieldComponentPropSchema,
|
|
10
10
|
) => {
|
|
11
|
-
|
|
11
|
+
const formContext = useContext(FormContext);
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
function getInput() {
|
|
18
|
-
return (
|
|
19
|
-
<input
|
|
20
|
-
type="number"
|
|
21
|
-
{...hookProps}
|
|
22
|
-
placeholder={props.fieldConfig?.placeholder}
|
|
23
|
-
readOnly={props.fieldConfig?.readOnly}
|
|
24
|
-
disabled={props.fieldConfig?.disabled}
|
|
25
|
-
autoComplete={props.fieldConfig?.autoComplete}
|
|
26
|
-
min={props.fieldConfig?.min}
|
|
27
|
-
max={props.fieldConfig?.max}
|
|
28
|
-
step={props.fieldConfig.decimalAllowed ? 0.01 : 1}
|
|
29
|
-
defaultValue={props.fieldConfig.defaultValue as string}
|
|
30
|
-
className={`form-input ${
|
|
31
|
-
props.fieldConfig.customClassNames?.fieldClassName || "flex-1 !w-60"
|
|
32
|
-
}`}
|
|
33
|
-
onKeyDown={(e) => {
|
|
34
|
-
props.fieldConfig.onKeyDown && props.fieldConfig.onKeyDown(e);
|
|
35
|
-
}}
|
|
36
|
-
onChange={(e) => {
|
|
37
|
-
let value = e.target.value;
|
|
38
|
-
let numericValue = parseFloat(value);
|
|
39
|
-
if (props.fieldConfig.max !== undefined && numericValue > props.fieldConfig.max) {
|
|
40
|
-
numericValue = props.fieldConfig.max;
|
|
41
|
-
}
|
|
42
|
-
if (props.fieldConfig.min !== undefined && numericValue < props.fieldConfig.min) {
|
|
43
|
-
numericValue = props.fieldConfig.min;
|
|
44
|
-
}
|
|
45
|
-
value = numericValue.toString();
|
|
46
|
-
handleChange(
|
|
47
|
-
value,
|
|
48
|
-
formContext,
|
|
49
|
-
props.fieldConfig,
|
|
50
|
-
props.onChange
|
|
51
|
-
);
|
|
52
|
-
}}
|
|
53
|
-
/>
|
|
54
|
-
);
|
|
55
|
-
}
|
|
15
|
+
let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
|
|
56
16
|
|
|
17
|
+
function getInput() {
|
|
57
18
|
return (
|
|
58
|
-
|
|
19
|
+
<input
|
|
20
|
+
type="number"
|
|
21
|
+
{...hookProps}
|
|
22
|
+
placeholder={props.fieldConfig?.placeholder}
|
|
23
|
+
readOnly={props.fieldConfig?.readOnly}
|
|
24
|
+
disabled={props.fieldConfig?.disabled}
|
|
25
|
+
autoComplete={props.fieldConfig?.autoComplete}
|
|
26
|
+
min={props.fieldConfig?.min}
|
|
27
|
+
max={props.fieldConfig?.max}
|
|
28
|
+
step={props.fieldConfig.decimalAllowed ? 0.01 : 1}
|
|
29
|
+
defaultValue={props.fieldConfig.defaultValue as string}
|
|
30
|
+
className={`form-input ${
|
|
31
|
+
props.fieldConfig.customClassNames?.fieldClassName || "flex-1 !w-60"
|
|
32
|
+
}`}
|
|
33
|
+
onKeyDown={(e) => {
|
|
34
|
+
props.fieldConfig.onKeyDown && props.fieldConfig.onKeyDown(e);
|
|
35
|
+
}}
|
|
36
|
+
onChange={(e) => {
|
|
37
|
+
let value = e.target.value;
|
|
38
|
+
let numericValue = parseFloat(value);
|
|
39
|
+
if (
|
|
40
|
+
props.fieldConfig.max !== undefined &&
|
|
41
|
+
numericValue > props.fieldConfig.max
|
|
42
|
+
) {
|
|
43
|
+
numericValue = props.fieldConfig.max;
|
|
44
|
+
}
|
|
45
|
+
if (
|
|
46
|
+
props.fieldConfig.min !== undefined &&
|
|
47
|
+
numericValue < props.fieldConfig.min
|
|
48
|
+
) {
|
|
49
|
+
numericValue = props.fieldConfig.min;
|
|
50
|
+
}
|
|
51
|
+
handleChange(
|
|
52
|
+
numericValue,
|
|
53
|
+
formContext,
|
|
54
|
+
props.fieldConfig,
|
|
55
|
+
props.onChange,
|
|
56
|
+
);
|
|
57
|
+
}}
|
|
58
|
+
/>
|
|
59
59
|
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
|
|
64
|
+
);
|
|
60
65
|
};
|
|
61
66
|
export default NumberField;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useCallback,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useMemo,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from "react";
|
|
9
|
+
|
|
10
|
+
import { Listbox, ListboxButton } from "@headlessui/react";
|
|
11
|
+
import { RegisterOptions } from "react-hook-form";
|
|
12
|
+
|
|
13
|
+
import { FormContext } from "../context/FormContext";
|
|
14
|
+
import { getListOption, getListOptions } from "../FormFieldUtils";
|
|
15
|
+
import {
|
|
16
|
+
FieldOptionsSchema,
|
|
17
|
+
FormFieldComponentPropSchema,
|
|
18
|
+
FormFieldType,
|
|
19
|
+
} from "../schema/FormFieldSchema";
|
|
20
|
+
import { handleChange, registerFormField } from "../util";
|
|
21
|
+
import RenderFormField from "../util/RenderFormField";
|
|
22
|
+
import RenderListOptions, {
|
|
23
|
+
renderListBoxValue,
|
|
24
|
+
} from "../util/RenderListOptions";
|
|
25
|
+
import axios from "axios";
|
|
26
|
+
import { getAxiosInstance } from "../../api";
|
|
27
|
+
|
|
28
|
+
const Typeahead2: React.FC<FormFieldComponentPropSchema> = (
|
|
29
|
+
props: FormFieldComponentPropSchema,
|
|
30
|
+
) => {
|
|
31
|
+
const dynamicSelectRef = useRef<HTMLUListElement>(null);
|
|
32
|
+
const abortControllerRef = useRef<AbortController | null>(null);
|
|
33
|
+
const formContext = useContext(FormContext);
|
|
34
|
+
let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
|
|
35
|
+
let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
|
|
36
|
+
const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
|
|
37
|
+
const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
|
|
38
|
+
[],
|
|
39
|
+
);
|
|
40
|
+
const [loading, setLoading] = useState<boolean>(false);
|
|
41
|
+
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (
|
|
44
|
+
!formContext.getValues(props.fieldConfig.name) &&
|
|
45
|
+
props.fieldConfig.defaultValue
|
|
46
|
+
) {
|
|
47
|
+
formContext.setValue(
|
|
48
|
+
props.fieldConfig.name,
|
|
49
|
+
props.fieldConfig.defaultValue,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
let values: any | any[] | undefined =
|
|
53
|
+
formContext.getValues(props.fieldConfig.name) ||
|
|
54
|
+
props.fieldConfig.defaultValue;
|
|
55
|
+
|
|
56
|
+
if (values && selectedValues.length < 1) {
|
|
57
|
+
if (props.fieldConfig.fetchSavedDataUrl) {
|
|
58
|
+
fetchValue(values);
|
|
59
|
+
} else {
|
|
60
|
+
setSelectedValues(
|
|
61
|
+
Array.isArray(values)
|
|
62
|
+
? values.map((val: any) => ({ label: val, value: val }))
|
|
63
|
+
: [values],
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}, []);
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
const fetchData = useMemo(() => {
|
|
72
|
+
let timeoutId: ReturnType<typeof setTimeout>;
|
|
73
|
+
|
|
74
|
+
return (_query: string | undefined) => {
|
|
75
|
+
// Clear the previous timer
|
|
76
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
77
|
+
|
|
78
|
+
// Set a new timer
|
|
79
|
+
timeoutId = setTimeout(async () => {
|
|
80
|
+
// 1. Cancel the previous request if it's still pending
|
|
81
|
+
if (abortControllerRef.current) {
|
|
82
|
+
abortControllerRef.current.abort();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// 2. Create a new controller for the current request
|
|
86
|
+
const controller = new AbortController();
|
|
87
|
+
abortControllerRef.current = controller;
|
|
88
|
+
const minLength = props.fieldConfig?.allowedMinQueryLength ?? 3;
|
|
89
|
+
|
|
90
|
+
if (!_query || _query.length < minLength) {
|
|
91
|
+
setListOptions([]);
|
|
92
|
+
setLoading(false);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
setLoading(true);
|
|
96
|
+
try {
|
|
97
|
+
if (!props.fieldConfig.fetchUrl) return;
|
|
98
|
+
|
|
99
|
+
let url = props.fieldConfig.fetchUrl;
|
|
100
|
+
|
|
101
|
+
url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
|
|
102
|
+
|
|
103
|
+
const axiosInstance = getAxiosInstance(
|
|
104
|
+
formContext.axiosInstance,
|
|
105
|
+
props.fieldConfig,
|
|
106
|
+
);
|
|
107
|
+
const response = await axiosInstance.get(url);
|
|
108
|
+
|
|
109
|
+
if (controller === abortControllerRef.current) {
|
|
110
|
+
if (response?.data) {
|
|
111
|
+
const data: FieldOptionsSchema[] = getListOptions(
|
|
112
|
+
response?.data,
|
|
113
|
+
props.fieldConfig.optionsConfig,
|
|
114
|
+
);
|
|
115
|
+
setListOptions([...data]);
|
|
116
|
+
|
|
117
|
+
if (props.fieldConfig.fetchCallback) {
|
|
118
|
+
props.fieldConfig.fetchCallback(response);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch (err) {
|
|
123
|
+
console.error("Fetch error:", err);
|
|
124
|
+
} finally {
|
|
125
|
+
// Only stop loading if this was the "active" request
|
|
126
|
+
if (controller === abortControllerRef.current) {
|
|
127
|
+
setLoading(false);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}, 250);
|
|
131
|
+
};
|
|
132
|
+
}, []);
|
|
133
|
+
|
|
134
|
+
// Cleanup on unmount
|
|
135
|
+
useEffect(() => {
|
|
136
|
+
return () => {
|
|
137
|
+
abortControllerRef.current?.abort();
|
|
138
|
+
};
|
|
139
|
+
}, []);
|
|
140
|
+
|
|
141
|
+
const fetchValue = async (value: string | any | any[]) => {
|
|
142
|
+
try {
|
|
143
|
+
if (
|
|
144
|
+
props.fieldConfig.ignoreFetchValue ||
|
|
145
|
+
!props.fieldConfig.fetchSavedDataUrl
|
|
146
|
+
) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let url = props.fieldConfig.fetchSavedDataUrl;
|
|
151
|
+
|
|
152
|
+
// url = url.includes("?")
|
|
153
|
+
// ? url + "&values=" + value
|
|
154
|
+
// : url + "?values=" + value;
|
|
155
|
+
|
|
156
|
+
let response = await (props.fieldConfig.disableHeaderInFetch
|
|
157
|
+
? axios.post(url, Array.isArray(value) ? value : [value])
|
|
158
|
+
: formContext.axiosInstance?.post(
|
|
159
|
+
url,
|
|
160
|
+
Array.isArray(value) ? value : [value],
|
|
161
|
+
));
|
|
162
|
+
if (response?.data) {
|
|
163
|
+
const data: FieldOptionsSchema[] = getListOptions(
|
|
164
|
+
response?.data,
|
|
165
|
+
props.fieldConfig.optionsConfig,
|
|
166
|
+
);
|
|
167
|
+
let values: any[] = formContext.getValues(props.fieldConfig.name) || [];
|
|
168
|
+
setSelectedValues(
|
|
169
|
+
[
|
|
170
|
+
...data,
|
|
171
|
+
props.fieldConfig.dropdownFieldConfig?.isSuggestionBox &&
|
|
172
|
+
values &&
|
|
173
|
+
Array.isArray(values)
|
|
174
|
+
? values
|
|
175
|
+
.filter(
|
|
176
|
+
(value) =>
|
|
177
|
+
data.some((d) => d.value !== value) || data.length == 0,
|
|
178
|
+
)
|
|
179
|
+
.map((val) => ({ label: val, value: val }))
|
|
180
|
+
: [],
|
|
181
|
+
].flat(),
|
|
182
|
+
);
|
|
183
|
+
}
|
|
184
|
+
} catch (err) { }
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
const updateListOptions = (data: any) => {
|
|
188
|
+
const resData: FieldOptionsSchema = getListOption(
|
|
189
|
+
data,
|
|
190
|
+
props.fieldConfig.optionsConfig,
|
|
191
|
+
);
|
|
192
|
+
setListOptions([]);
|
|
193
|
+
setSelectedValues((prev) =>
|
|
194
|
+
props.fieldConfig.isMultiple ? [...prev, resData] : [resData],
|
|
195
|
+
);
|
|
196
|
+
let result = formContext.getValues(props.fieldConfig.name) || [];
|
|
197
|
+
result = !props.fieldConfig.isMultiple
|
|
198
|
+
? resData.value
|
|
199
|
+
: result.includes(resData.value)
|
|
200
|
+
? [...result.filter((v: string) => v != resData.value), resData.value]
|
|
201
|
+
: [...result, resData.value];
|
|
202
|
+
formContext.setValue(props.fieldConfig.name, result);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const getInput = () => {
|
|
206
|
+
return (
|
|
207
|
+
<Listbox
|
|
208
|
+
as={"div"}
|
|
209
|
+
{...hookProps}
|
|
210
|
+
value={
|
|
211
|
+
props.fieldConfig.isMultiple
|
|
212
|
+
? formContext.getValues(props.fieldConfig.name)
|
|
213
|
+
? formContext.getValues(props.fieldConfig.name)
|
|
214
|
+
: []
|
|
215
|
+
: formContext.getValues(props.fieldConfig.name)
|
|
216
|
+
}
|
|
217
|
+
name={props.fieldConfig.name}
|
|
218
|
+
defaultValue={props.fieldConfig.defaultValue}
|
|
219
|
+
key={props.fieldConfig.name}
|
|
220
|
+
className={"relative form-listbox flex-1 overflow-hidden"}
|
|
221
|
+
onChange={(selectedOptions) => {
|
|
222
|
+
let currentValue = formContext.getValues(props.fieldConfig.name);
|
|
223
|
+
const newValue =
|
|
224
|
+
currentValue === selectedOptions ? null : selectedOptions;
|
|
225
|
+
|
|
226
|
+
if (props.fieldConfig.isMultiple) {
|
|
227
|
+
currentValue = listOptions.filter((op) =>
|
|
228
|
+
selectedOptions.includes(op.value),
|
|
229
|
+
);
|
|
230
|
+
setSelectedValues((prev) => [...prev, ...currentValue]);
|
|
231
|
+
} else {
|
|
232
|
+
const selected = listOptions.find((o) => o.value == newValue);
|
|
233
|
+
selected && setSelectedValues([selected]);
|
|
234
|
+
}
|
|
235
|
+
setListOptions([]);
|
|
236
|
+
handleChange(
|
|
237
|
+
newValue,
|
|
238
|
+
formContext,
|
|
239
|
+
props.fieldConfig,
|
|
240
|
+
props.onChange,
|
|
241
|
+
);
|
|
242
|
+
}}
|
|
243
|
+
multiple={props.fieldConfig.isMultiple}
|
|
244
|
+
>
|
|
245
|
+
<ListboxButton
|
|
246
|
+
className={
|
|
247
|
+
props.fieldConfig.customClassNames?.fieldClassName
|
|
248
|
+
? "form-listbox-select " +
|
|
249
|
+
props.fieldConfig.customClassNames?.fieldClassName
|
|
250
|
+
: "form-listbox-select"
|
|
251
|
+
}
|
|
252
|
+
>
|
|
253
|
+
{renderListBoxValue(
|
|
254
|
+
formContext,
|
|
255
|
+
props.fieldConfig,
|
|
256
|
+
[...selectedValues, ...listOptions],
|
|
257
|
+
props.onChange,
|
|
258
|
+
)}
|
|
259
|
+
</ListboxButton>
|
|
260
|
+
<RenderListOptions
|
|
261
|
+
formContext={formContext}
|
|
262
|
+
onChange={props.onChange}
|
|
263
|
+
formField={FormFieldType.TYPEAHEAD_2}
|
|
264
|
+
ref={dynamicSelectRef}
|
|
265
|
+
fieldConfig={props.fieldConfig}
|
|
266
|
+
listOptions={listOptions}
|
|
267
|
+
setListOptions={setListOptions}
|
|
268
|
+
loading={loading}
|
|
269
|
+
setLoading={setLoading}
|
|
270
|
+
createCallback={(data) => updateListOptions(data)}
|
|
271
|
+
queryCallback={(query) => fetchData(query)}
|
|
272
|
+
/>
|
|
273
|
+
</Listbox>
|
|
274
|
+
);
|
|
275
|
+
};
|
|
276
|
+
if (props.fieldConfig.hideWhenNoResults && listOptions.length == 0) {
|
|
277
|
+
return <></>;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
return (
|
|
281
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
|
|
282
|
+
);
|
|
283
|
+
};
|
|
284
|
+
export default Typeahead2;
|
|
@@ -37,6 +37,7 @@ export enum FormFieldType {
|
|
|
37
37
|
DYNAMIC_MULTI_SELECT = "DYNAMIC_MULTI_SELECT",
|
|
38
38
|
|
|
39
39
|
TYPEAHEAD = "TYPEAHEAD",
|
|
40
|
+
TYPEAHEAD_2 = "TYPEAHEAD_2",
|
|
40
41
|
TYPEAHEAD_MULTI_SELECT = "TYPEAHEAD_MULTI_SELECT",
|
|
41
42
|
PHONE_NUMBER_INPUT = "PHONE_NUMBER_INPUT",
|
|
42
43
|
SWITCH = "SWITCH",
|
|
@@ -105,6 +106,7 @@ export type FormFieldSchema = {
|
|
|
105
106
|
max?: number;
|
|
106
107
|
min?: number;
|
|
107
108
|
rows?: number;
|
|
109
|
+
allowedMinQueryLength?: number;
|
|
108
110
|
defaultValue?: string | string[] | {} | boolean;
|
|
109
111
|
options?: FieldOptionsSchema[];
|
|
110
112
|
minDate?: Date | null | undefined;
|
|
@@ -127,9 +129,11 @@ export type FormFieldSchema = {
|
|
|
127
129
|
decimalAllowed?: boolean;
|
|
128
130
|
errorMessage?: string;
|
|
129
131
|
submitOnChange?: boolean;
|
|
132
|
+
isMultiple?: boolean;
|
|
130
133
|
formFieldPattern?: FormFieldPatternsImpl[];
|
|
131
134
|
fetchUrl?: string;
|
|
132
135
|
postUrl?: string;
|
|
136
|
+
fetchSavedDataUrl?: string;
|
|
133
137
|
fileAccept?: string;
|
|
134
138
|
icon?: ReactNode;
|
|
135
139
|
outputFormat?: OutputFormatType;
|
|
@@ -133,7 +133,9 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
133
133
|
}, [filteredList]);
|
|
134
134
|
|
|
135
135
|
useEffect(() => {
|
|
136
|
-
|
|
136
|
+
if (formField == FormFieldType.TYPEAHEAD_2)
|
|
137
|
+
queryCallback && queryCallback(query);
|
|
138
|
+
else handleQueryCallback();
|
|
137
139
|
}, [query]);
|
|
138
140
|
|
|
139
141
|
let enableCreateFlag =
|
|
@@ -143,6 +145,7 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
143
145
|
|
|
144
146
|
let validTypeaheadFields = [
|
|
145
147
|
FormFieldType.TYPEAHEAD,
|
|
148
|
+
FormFieldType.TYPEAHEAD_2,
|
|
146
149
|
FormFieldType.TYPEAHEAD_MULTI_SELECT,
|
|
147
150
|
];
|
|
148
151
|
let isTypeahead: boolean = validTypeaheadFields.indexOf(formField) > -1;
|
|
@@ -217,7 +220,9 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
217
220
|
};
|
|
218
221
|
|
|
219
222
|
const renderList = useMemo(() => {
|
|
220
|
-
if (filteredList.length === 0 && (!enableCreateFlag || query === ""))
|
|
223
|
+
if (filteredList.length === 0 && (!enableCreateFlag || query === "")) {
|
|
224
|
+
if (formField == FormFieldType.TYPEAHEAD_2 && query === "")
|
|
225
|
+
return <></>;
|
|
221
226
|
return (
|
|
222
227
|
<div className="form-listbox-option text-center">
|
|
223
228
|
<span className="empty-content text-gray-600 font-normal">
|
|
@@ -225,6 +230,7 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
225
230
|
</span>
|
|
226
231
|
</div>
|
|
227
232
|
);
|
|
233
|
+
}
|
|
228
234
|
|
|
229
235
|
return (
|
|
230
236
|
<>
|