@engagebay/engagebay-form-module 1.0.1 → 1.0.2-beta.1
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/link.sh +1 -1
- package/package.json +17 -1
- package/src/api/AxiosConfigProvider.tsx +53 -0
- package/src/api/index.ts +15 -1
- package/src/form/Form.tsx +6 -0
- package/src/form/context/FormContext.tsx +2 -0
- package/src/form/formfields/BusinessHoursField.tsx +293 -181
- package/src/form/formfields/ColorPickerField.tsx +43 -42
- package/src/form/formfields/DatePickerField.tsx +66 -69
- package/src/form/formfields/DynamicMultiSelect.tsx +166 -166
- package/src/form/formfields/DynamicSelect.tsx +4 -5
- package/src/form/formfields/MultipleSelectField.tsx +70 -74
- package/src/form/formfields/RadioField.tsx +73 -86
- package/src/form/formfields/Typeahead.tsx +6 -7
- package/src/form/formfields/TypeaheadMultiSelect.tsx +189 -175
- package/src/form/schema/FormFieldSchema.ts +17 -0
- package/src/form/util/RenderFormField.tsx +2 -0
- package/src/form/util/RenderListOptions.tsx +46 -34
- package/src/index.js +116 -0
- package/src/util/svg/HELPER_ICONS.ts +1 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import React, {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
useCallback,
|
|
3
|
+
useContext,
|
|
4
|
+
useEffect,
|
|
5
|
+
useRef,
|
|
6
|
+
useState,
|
|
7
7
|
} from "react";
|
|
8
8
|
|
|
9
9
|
import { Listbox, ListboxButton } from "@headlessui/react";
|
|
@@ -12,192 +12,206 @@ import { RegisterOptions } from "react-hook-form";
|
|
|
12
12
|
import { FormContext } from "../context/FormContext";
|
|
13
13
|
import { getListOption, getListOptions } from "../FormFieldUtils";
|
|
14
14
|
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
FieldOptionsSchema,
|
|
16
|
+
FormFieldComponentPropSchema,
|
|
17
|
+
FormFieldType,
|
|
18
18
|
} from "../schema/FormFieldSchema";
|
|
19
19
|
import { handleChange, registerFormField } from "../util";
|
|
20
20
|
import RenderFormField from "../util/RenderFormField";
|
|
21
21
|
import RenderListOptions, {
|
|
22
|
-
|
|
22
|
+
renderListBoxValue,
|
|
23
23
|
} from "../util/RenderListOptions";
|
|
24
24
|
// import _ from "lodash";
|
|
25
25
|
import axios from "axios";
|
|
26
|
-
import {
|
|
26
|
+
import { getAxiosInstance } from "src/api";
|
|
27
27
|
|
|
28
28
|
const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
|
|
29
|
-
|
|
29
|
+
props: FormFieldComponentPropSchema,
|
|
30
30
|
) => {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const dynamicSelectRef = useRef<HTMLUListElement>(null);
|
|
32
|
+
const formContext = useContext(FormContext);
|
|
33
|
+
let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
|
|
34
|
+
let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
|
|
35
|
+
const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
|
|
36
|
+
const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
|
|
37
|
+
[],
|
|
38
|
+
);
|
|
39
|
+
const [loading, setLoading] = useState<boolean>(true);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (
|
|
43
|
+
!formContext.getValues(props.fieldConfig.name) &&
|
|
44
|
+
props.fieldConfig.defaultValue
|
|
45
|
+
) {
|
|
46
|
+
formContext.setValue(
|
|
35
47
|
props.fieldConfig.name,
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
props.fieldConfig.defaultValue
|
|
52
|
-
);
|
|
48
|
+
props.fieldConfig.defaultValue,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
fetchData(undefined);
|
|
52
|
+
}, []);
|
|
53
|
+
|
|
54
|
+
const fetchData = useCallback(
|
|
55
|
+
async (_query: string | undefined) => {
|
|
56
|
+
setLoading(true);
|
|
57
|
+
try {
|
|
58
|
+
if (!props.fieldConfig.fetchUrl) return;
|
|
59
|
+
|
|
60
|
+
let url = props.fieldConfig.fetchUrl;
|
|
61
|
+
if (_query) {
|
|
62
|
+
url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
|
|
53
63
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
async (_query: string | undefined) => {
|
|
59
|
-
setLoading(true);
|
|
60
|
-
try {
|
|
61
|
-
if (!props.fieldConfig.fetchUrl) return;
|
|
62
|
-
|
|
63
|
-
let url = props.fieldConfig.fetchUrl;
|
|
64
|
-
if (_query) {
|
|
65
|
-
url = url.includes("?")
|
|
66
|
-
? url + "&q=" + _query
|
|
67
|
-
: url + "?q=" + _query;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
let response = await (props.fieldConfig.disableHeaderInFetch
|
|
71
|
-
? axios.get(url)
|
|
72
|
-
: reachoAPI.get(url));
|
|
73
|
-
if (response.data) {
|
|
74
|
-
const data: FieldOptionsSchema[] = getListOptions(
|
|
75
|
-
response.data,
|
|
76
|
-
props.fieldConfig.optionsConfig
|
|
77
|
-
);
|
|
78
|
-
setListOptions([...data]);
|
|
79
|
-
let values = formContext.getValues(props.fieldConfig.name) || [];
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
values.length > 0 && // Ensure 'values' is not empty
|
|
83
|
-
(data.length === 0 || // If 'data' is empty
|
|
84
|
-
!values.every((v: string) => data.some(i => i.value === v)) && // Ensure none of 'values' match 'data'
|
|
85
|
-
!values.every((v: string) => selectedValues.some(i => i.value === v)) // Ensure none of 'values' match 'selectedValues'
|
|
86
|
-
)) {
|
|
87
|
-
fetchValue(values); // Call 'fetchValue()' if all conditions are met
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (props.fieldConfig.fetchCallback) {
|
|
91
|
-
props.fieldConfig.fetchCallback(response);
|
|
92
|
-
}
|
|
93
|
-
} else {
|
|
94
|
-
console.error(response.statusText);
|
|
95
|
-
}
|
|
96
|
-
} catch (err) {
|
|
97
|
-
} finally {
|
|
98
|
-
setLoading(false);
|
|
99
|
-
}
|
|
100
|
-
},
|
|
101
|
-
[props.fieldConfig.fetchUrl]
|
|
102
|
-
);
|
|
64
|
+
const axiosInstance = getAxiosInstance(
|
|
65
|
+
formContext.axiosInstance,
|
|
66
|
+
props.fieldConfig,
|
|
67
|
+
);
|
|
103
68
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
:
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
69
|
+
let response = await axiosInstance.get(url);
|
|
70
|
+
if (response?.data) {
|
|
71
|
+
const data: FieldOptionsSchema[] = getListOptions(
|
|
72
|
+
response?.data,
|
|
73
|
+
props.fieldConfig.optionsConfig,
|
|
74
|
+
);
|
|
75
|
+
setListOptions([...data]);
|
|
76
|
+
let values = formContext.getValues(props.fieldConfig.name) || [];
|
|
77
|
+
|
|
78
|
+
if (
|
|
79
|
+
values.length > 0 && // Ensure 'values' is not empty
|
|
80
|
+
(data.length === 0 || // If 'data' is empty
|
|
81
|
+
(!values.every((v: string) => data.some((i) => i.value === v)) && // Ensure none of 'values' match 'data'
|
|
82
|
+
!values.every((v: string) =>
|
|
83
|
+
selectedValues.some((i) => i.value === v),
|
|
84
|
+
))) // Ensure none of 'values' match 'selectedValues'
|
|
85
|
+
) {
|
|
86
|
+
fetchValue(values); // Call 'fetchValue()' if all conditions are met
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (props.fieldConfig.fetchCallback) {
|
|
90
|
+
props.fieldConfig.fetchCallback(response);
|
|
91
|
+
}
|
|
92
|
+
} else {
|
|
93
|
+
console.error(response?.statusText);
|
|
94
|
+
}
|
|
95
|
+
} catch (err) {
|
|
96
|
+
} finally {
|
|
97
|
+
setLoading(false);
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
[props.fieldConfig.fetchUrl],
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const fetchValue = async (value: string) => {
|
|
104
|
+
try {
|
|
105
|
+
if (props.fieldConfig.ignoreFetchValue || !props.fieldConfig.fetchUrl) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let url = props.fieldConfig.fetchUrl;
|
|
110
|
+
|
|
111
|
+
url = url = url.includes("?")
|
|
112
|
+
? url + "&values=" + value
|
|
113
|
+
: url + "?values=" + value;
|
|
114
|
+
|
|
115
|
+
let response = await (props.fieldConfig.disableHeaderInFetch
|
|
116
|
+
? axios.get(url)
|
|
117
|
+
: formContext.axiosInstance?.get(url));
|
|
118
|
+
if (response?.data) {
|
|
119
|
+
const data: FieldOptionsSchema[] = getListOptions(
|
|
120
|
+
response?.data,
|
|
121
|
+
props.fieldConfig.optionsConfig,
|
|
136
122
|
);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
defaultValue={props.fieldConfig.defaultValue}
|
|
151
|
-
key={props.fieldConfig.name}
|
|
152
|
-
className={"relative form-listbox flex-1"}
|
|
153
|
-
onChange={(selectedOptions) => {
|
|
154
|
-
const chossenOptions = listOptions.filter(op => selectedOptions.includes(op.value));
|
|
155
|
-
setSelectedValues(prev => [...prev, ...chossenOptions])
|
|
156
|
-
handleChange(
|
|
157
|
-
selectedOptions,
|
|
158
|
-
formContext,
|
|
159
|
-
props.fieldConfig,
|
|
160
|
-
props.onChange
|
|
161
|
-
)
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
multiple>
|
|
165
|
-
<ListboxButton
|
|
166
|
-
className={
|
|
167
|
-
props.fieldConfig.customClassNames?.fieldClassName
|
|
168
|
-
? "form-listbox-select " +
|
|
169
|
-
props.fieldConfig.customClassNames?.fieldClassName
|
|
170
|
-
: "form-listbox-select"
|
|
171
|
-
}>
|
|
172
|
-
{renderListBoxValue(
|
|
173
|
-
formContext,
|
|
174
|
-
props.fieldConfig,
|
|
175
|
-
[...selectedValues, ...listOptions],
|
|
176
|
-
props.onChange
|
|
177
|
-
)}
|
|
178
|
-
</ListboxButton>
|
|
179
|
-
<RenderListOptions
|
|
180
|
-
formContext={formContext}
|
|
181
|
-
onChange={props.onChange}
|
|
182
|
-
formField={FormFieldType.TYPEAHEAD_MULTI_SELECT}
|
|
183
|
-
ref={dynamicSelectRef}
|
|
184
|
-
fieldConfig={props.fieldConfig}
|
|
185
|
-
listOptions={[...selectedValues, ...listOptions]}
|
|
186
|
-
setListOptions={setListOptions}
|
|
187
|
-
loading={loading}
|
|
188
|
-
setLoading={setLoading}
|
|
189
|
-
createCallback={(data) => updateListOptions(data)}
|
|
190
|
-
queryCallback={(query) => fetchData(query)}
|
|
191
|
-
/>
|
|
192
|
-
</Listbox>
|
|
123
|
+
let values: any[] = formContext.getValues(props.fieldConfig.name) || [];
|
|
124
|
+
setSelectedValues(
|
|
125
|
+
[
|
|
126
|
+
...data,
|
|
127
|
+
props.fieldConfig.dropdownFieldConfig?.isSuggestionBox && values
|
|
128
|
+
? values
|
|
129
|
+
.filter(
|
|
130
|
+
(value) =>
|
|
131
|
+
data.some((d) => d.value !== value) || data.length == 0,
|
|
132
|
+
)
|
|
133
|
+
.map((val) => ({ label: val, value: val }))
|
|
134
|
+
: [],
|
|
135
|
+
].flat(),
|
|
193
136
|
);
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
137
|
+
}
|
|
138
|
+
} catch (err) {}
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const updateListOptions = (data: any) => {
|
|
142
|
+
const resData: FieldOptionsSchema = getListOption(
|
|
143
|
+
data,
|
|
144
|
+
props.fieldConfig.optionsConfig,
|
|
145
|
+
);
|
|
146
|
+
setSelectedValues((prev) => [...prev, resData]);
|
|
147
|
+
let result = formContext.getValues(props.fieldConfig.name) || [];
|
|
148
|
+
result = result.includes(resData.value)
|
|
149
|
+
? result.filter((v: string) => v != resData.value)
|
|
150
|
+
: [...result, resData.value];
|
|
151
|
+
formContext.setValue(props.fieldConfig.name, result);
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const getInput = () => {
|
|
199
155
|
return (
|
|
200
|
-
|
|
156
|
+
<Listbox
|
|
157
|
+
as={"div"}
|
|
158
|
+
{...hookProps}
|
|
159
|
+
value={formContext.getValues(props.fieldConfig.name) || []}
|
|
160
|
+
name={props.fieldConfig.name}
|
|
161
|
+
defaultValue={props.fieldConfig.defaultValue}
|
|
162
|
+
key={props.fieldConfig.name}
|
|
163
|
+
className={"relative form-listbox flex-1 overflow-hidden"}
|
|
164
|
+
onChange={(selectedOptions) => {
|
|
165
|
+
const chossenOptions = listOptions.filter((op) =>
|
|
166
|
+
selectedOptions.includes(op.value),
|
|
167
|
+
);
|
|
168
|
+
setSelectedValues((prev) => [...prev, ...chossenOptions]);
|
|
169
|
+
handleChange(
|
|
170
|
+
selectedOptions,
|
|
171
|
+
formContext,
|
|
172
|
+
props.fieldConfig,
|
|
173
|
+
props.onChange,
|
|
174
|
+
);
|
|
175
|
+
}}
|
|
176
|
+
multiple
|
|
177
|
+
>
|
|
178
|
+
<ListboxButton
|
|
179
|
+
className={
|
|
180
|
+
props.fieldConfig.customClassNames?.fieldClassName
|
|
181
|
+
? "form-listbox-select " +
|
|
182
|
+
props.fieldConfig.customClassNames?.fieldClassName
|
|
183
|
+
: "form-listbox-select"
|
|
184
|
+
}
|
|
185
|
+
>
|
|
186
|
+
{renderListBoxValue(
|
|
187
|
+
formContext,
|
|
188
|
+
props.fieldConfig,
|
|
189
|
+
[...selectedValues, ...listOptions],
|
|
190
|
+
props.onChange,
|
|
191
|
+
)}
|
|
192
|
+
</ListboxButton>
|
|
193
|
+
<RenderListOptions
|
|
194
|
+
formContext={formContext}
|
|
195
|
+
onChange={props.onChange}
|
|
196
|
+
formField={FormFieldType.TYPEAHEAD_MULTI_SELECT}
|
|
197
|
+
ref={dynamicSelectRef}
|
|
198
|
+
fieldConfig={props.fieldConfig}
|
|
199
|
+
listOptions={[...selectedValues, ...listOptions]}
|
|
200
|
+
setListOptions={setListOptions}
|
|
201
|
+
loading={loading}
|
|
202
|
+
setLoading={setLoading}
|
|
203
|
+
createCallback={(data) => updateListOptions(data)}
|
|
204
|
+
queryCallback={(query) => fetchData(query)}
|
|
205
|
+
/>
|
|
206
|
+
</Listbox>
|
|
201
207
|
);
|
|
208
|
+
};
|
|
209
|
+
if (props.fieldConfig.hideWhenNoResults && listOptions.length == 0) {
|
|
210
|
+
return <></>;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return (
|
|
214
|
+
<RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
|
|
215
|
+
);
|
|
202
216
|
};
|
|
203
217
|
export default TypeaheadMultiSelect;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
} from "react-hook-form";
|
|
11
11
|
import { Saga } from "redux-saga";
|
|
12
12
|
import { emailIdsValidator, queryValidator } from "./CustomValidators";
|
|
13
|
+
import { AxiosInstance } from 'axios';
|
|
13
14
|
|
|
14
15
|
export enum FormFieldType {
|
|
15
16
|
INPUT = "INPUT",
|
|
@@ -75,6 +76,9 @@ export type DropdownFieldConfig = {
|
|
|
75
76
|
showDeleteOption: boolean;
|
|
76
77
|
showCreateOption: boolean;
|
|
77
78
|
showSearchBox: boolean;
|
|
79
|
+
placeHolder?: string;
|
|
80
|
+
hideIcon?: boolean;
|
|
81
|
+
isSuggestionBox?: boolean;
|
|
78
82
|
createLabelText?: string;
|
|
79
83
|
isCaseSensitive?: boolean;
|
|
80
84
|
};
|
|
@@ -136,6 +140,7 @@ export type FormFieldSchema = {
|
|
|
136
140
|
forceUpdate?: boolean;
|
|
137
141
|
disableHeaderInFetch?: boolean;
|
|
138
142
|
dropdownFieldConfig?: DropdownFieldConfig;
|
|
143
|
+
axiosInstance?: AxiosInstance
|
|
139
144
|
|
|
140
145
|
/**
|
|
141
146
|
* Redux configuration attribute
|
|
@@ -301,6 +306,18 @@ export class FormFieldPatternsImpl implements FormFieldPatterns {
|
|
|
301
306
|
/^[a-z][a-z0-9_]*$/
|
|
302
307
|
);
|
|
303
308
|
|
|
309
|
+
static readonly NO_SPECIAL_CHAR_LOWERCASE_WITH_SPACES = new FormFieldPatternsImpl(
|
|
310
|
+
"NO_SPECIAL_CHAR_LOWERCASE_WITH_SPACES",
|
|
311
|
+
"Please enter only letters, numbers, and spaces.",
|
|
312
|
+
/^[A-Za-z0-9 ]+$/
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
static readonly VALID_SUBDOMAIN_NAME = new FormFieldPatternsImpl(
|
|
316
|
+
"VALID_SUBDOMAIN_NAME",
|
|
317
|
+
"Name should be between 3-30 characters. Cannot contain special characters.",
|
|
318
|
+
/^[a-z]+$/
|
|
319
|
+
);
|
|
320
|
+
|
|
304
321
|
private constructor(
|
|
305
322
|
private readonly patternName: string,
|
|
306
323
|
private readonly message: string,
|
|
@@ -3,6 +3,7 @@ import React from "react";
|
|
|
3
3
|
import { FieldAlignType, FormFieldSchema } from "../schema/FormFieldSchema";
|
|
4
4
|
import ErrorContextHandler from "../formfields/ErrorContextHandler";
|
|
5
5
|
import SVGIcon from "../../util/svg/SVGIcon";
|
|
6
|
+
import { useFormState } from "react-hook-form";
|
|
6
7
|
/**
|
|
7
8
|
* RenderFormField Component
|
|
8
9
|
*
|
|
@@ -54,6 +55,7 @@ const RenderFormField = ({
|
|
|
54
55
|
fieldConfig: FormFieldSchema;
|
|
55
56
|
getInput: Function;
|
|
56
57
|
}): JSX.Element => {
|
|
58
|
+
|
|
57
59
|
function formTypeHorizontal() {
|
|
58
60
|
return (
|
|
59
61
|
<Field
|
|
@@ -85,7 +85,14 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
85
85
|
}
|
|
86
86
|
};
|
|
87
87
|
let resultList = [...createdListItems, ...listOptions];
|
|
88
|
-
resultList = [
|
|
88
|
+
resultList = [
|
|
89
|
+
...resultList
|
|
90
|
+
.filter((result) => result.label)
|
|
91
|
+
.filter(
|
|
92
|
+
(option, index, self) =>
|
|
93
|
+
index === self.findIndex((obj) => obj.value === option.value)
|
|
94
|
+
),
|
|
95
|
+
]; // removing duplicate values
|
|
89
96
|
|
|
90
97
|
const caseSensitive =
|
|
91
98
|
query && fieldConfig.dropdownFieldConfig?.isCaseSensitive
|
|
@@ -159,7 +166,9 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
159
166
|
disabled={option.isDisabled}
|
|
160
167
|
onClick={() => setTimeout(resetToDefault, 300)}
|
|
161
168
|
className={`form-listbox-option ${
|
|
162
|
-
selected
|
|
169
|
+
selected
|
|
170
|
+
? " bg-gray-100 text-gray-900"
|
|
171
|
+
: "hover:bg-gray-100 text-gray-700"
|
|
163
172
|
}`}
|
|
164
173
|
value={option.value}
|
|
165
174
|
>
|
|
@@ -178,7 +187,8 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
178
187
|
)}
|
|
179
188
|
{option.label}
|
|
180
189
|
</span>
|
|
181
|
-
{isTypeahead
|
|
190
|
+
{isTypeahead &&
|
|
191
|
+
!fieldConfig.dropdownFieldConfig?.isSuggestionBox ? (
|
|
182
192
|
<input
|
|
183
193
|
type="checkbox"
|
|
184
194
|
className="form-checkbox"
|
|
@@ -195,7 +205,7 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
195
205
|
)}
|
|
196
206
|
</div>
|
|
197
207
|
{option.helpText && (
|
|
198
|
-
<div className="mt-0 text-
|
|
208
|
+
<div className="mt-0 text-xs text-gray-500 font-normal truncate w-full !max-w-[150px]">
|
|
199
209
|
{option.helpText}
|
|
200
210
|
</div>
|
|
201
211
|
)}
|
|
@@ -259,51 +269,53 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
259
269
|
}
|
|
260
270
|
}}
|
|
261
271
|
className="form-input !pr-[36px] Search-field"
|
|
262
|
-
placeholder=
|
|
272
|
+
placeholder={
|
|
273
|
+
fieldConfig.dropdownFieldConfig?.placeHolder || "Search"
|
|
274
|
+
}
|
|
263
275
|
value={query}
|
|
264
276
|
autoFocus
|
|
265
277
|
type="text"
|
|
266
278
|
/>
|
|
267
|
-
|
|
268
|
-
<
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
279
|
+
{!fieldConfig.dropdownFieldConfig?.hideIcon && (
|
|
280
|
+
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center mr-3">
|
|
281
|
+
<svg
|
|
282
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
283
|
+
viewBox="0 0 16 16"
|
|
284
|
+
fill="currentColor"
|
|
285
|
+
aria-hidden="true"
|
|
286
|
+
data-slot="icon"
|
|
287
|
+
className="h-5 w-5 text-gray-400"
|
|
288
|
+
>
|
|
289
|
+
<path
|
|
290
|
+
fillRule="evenodd"
|
|
291
|
+
d="M9.965 11.026a5 5 0 1 1 1.06-1.06l2.755 2.754a.75.75 0 1 1-1.06 1.06l-2.755-2.754ZM10.5 7a3.5 3.5 0 1 1-7 0 3.5 3.5 0 0 1 7 0Z"
|
|
292
|
+
clipRule="evenodd"
|
|
293
|
+
></path>
|
|
294
|
+
</svg>
|
|
295
|
+
</div>
|
|
296
|
+
)}
|
|
283
297
|
</div>
|
|
284
298
|
)}
|
|
285
299
|
|
|
286
|
-
<div className="form-listbox-options-container">
|
|
287
|
-
|
|
300
|
+
<div className="form-listbox-options-container">
|
|
301
|
+
{loading ? (
|
|
288
302
|
<div className="form-listbox-option">
|
|
289
303
|
<div className="flex items-center justify-center p-3">
|
|
290
304
|
<LoaderWithText />
|
|
291
305
|
</div>
|
|
292
306
|
</div>
|
|
293
|
-
|
|
307
|
+
) : (
|
|
294
308
|
renderList
|
|
295
|
-
|
|
309
|
+
)}
|
|
296
310
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
311
|
+
{Object.keys(groupedOptions).length > 0 &&
|
|
312
|
+
Object.keys(groupedOptions).map((groupName) => (
|
|
313
|
+
<div key={groupName}>
|
|
314
|
+
<h2 className="pb-1 pt-2 font-bold">{groupName}</h2>
|
|
315
|
+
{groupedOptions[groupName].map(renderOption)}
|
|
316
|
+
</div>
|
|
317
|
+
))}
|
|
304
318
|
</div>
|
|
305
|
-
|
|
306
|
-
|
|
307
319
|
</ListboxOptions>
|
|
308
320
|
);
|
|
309
321
|
}
|