@engagebay/engagebay-form-module 1.0.0 → 1.0.2-beta.0
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 +167 -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 +49 -36
- 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
|
|
@@ -154,12 +161,15 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
154
161
|
selected = option.value == formValue;
|
|
155
162
|
}
|
|
156
163
|
return (
|
|
157
|
-
<
|
|
164
|
+
<Listbox.Option
|
|
165
|
+
static
|
|
158
166
|
key={option.value}
|
|
159
167
|
disabled={option.isDisabled}
|
|
160
168
|
onClick={() => setTimeout(resetToDefault, 300)}
|
|
161
169
|
className={`form-listbox-option ${
|
|
162
|
-
selected
|
|
170
|
+
selected
|
|
171
|
+
? " bg-gray-100 text-gray-900"
|
|
172
|
+
: "hover:bg-gray-100 text-gray-700"
|
|
163
173
|
}`}
|
|
164
174
|
value={option.value}
|
|
165
175
|
>
|
|
@@ -178,7 +188,8 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
178
188
|
)}
|
|
179
189
|
{option.label}
|
|
180
190
|
</span>
|
|
181
|
-
{isTypeahead
|
|
191
|
+
{isTypeahead &&
|
|
192
|
+
!fieldConfig.dropdownFieldConfig?.isSuggestionBox ? (
|
|
182
193
|
<input
|
|
183
194
|
type="checkbox"
|
|
184
195
|
className="form-checkbox"
|
|
@@ -195,7 +206,7 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
195
206
|
)}
|
|
196
207
|
</div>
|
|
197
208
|
{option.helpText && (
|
|
198
|
-
<div className="mt-0 text-
|
|
209
|
+
<div className="mt-0 text-xs text-gray-500 font-normal truncate w-full !max-w-[150px]">
|
|
199
210
|
{option.helpText}
|
|
200
211
|
</div>
|
|
201
212
|
)}
|
|
@@ -259,51 +270,53 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
|
|
|
259
270
|
}
|
|
260
271
|
}}
|
|
261
272
|
className="form-input !pr-[36px] Search-field"
|
|
262
|
-
placeholder=
|
|
273
|
+
placeholder={
|
|
274
|
+
fieldConfig.dropdownFieldConfig?.placeHolder || "Search"
|
|
275
|
+
}
|
|
263
276
|
value={query}
|
|
264
277
|
autoFocus
|
|
265
278
|
type="text"
|
|
266
279
|
/>
|
|
267
|
-
|
|
268
|
-
<
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
280
|
+
{!fieldConfig.dropdownFieldConfig?.hideIcon && (
|
|
281
|
+
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center mr-3">
|
|
282
|
+
<svg
|
|
283
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
284
|
+
viewBox="0 0 16 16"
|
|
285
|
+
fill="currentColor"
|
|
286
|
+
aria-hidden="true"
|
|
287
|
+
data-slot="icon"
|
|
288
|
+
className="h-5 w-5 text-gray-400"
|
|
289
|
+
>
|
|
290
|
+
<path
|
|
291
|
+
fillRule="evenodd"
|
|
292
|
+
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"
|
|
293
|
+
clipRule="evenodd"
|
|
294
|
+
></path>
|
|
295
|
+
</svg>
|
|
296
|
+
</div>
|
|
297
|
+
)}
|
|
283
298
|
</div>
|
|
284
299
|
)}
|
|
285
300
|
|
|
286
|
-
<div className="form-listbox-options-container">
|
|
287
|
-
|
|
301
|
+
<div className="form-listbox-options-container">
|
|
302
|
+
{loading ? (
|
|
288
303
|
<div className="form-listbox-option">
|
|
289
304
|
<div className="flex items-center justify-center p-3">
|
|
290
305
|
<LoaderWithText />
|
|
291
306
|
</div>
|
|
292
307
|
</div>
|
|
293
|
-
|
|
308
|
+
) : (
|
|
294
309
|
renderList
|
|
295
|
-
|
|
310
|
+
)}
|
|
296
311
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
312
|
+
{Object.keys(groupedOptions).length > 0 &&
|
|
313
|
+
Object.keys(groupedOptions).map((groupName) => (
|
|
314
|
+
<div key={groupName}>
|
|
315
|
+
<h2 className="pb-1 pt-2 font-bold">{groupName}</h2>
|
|
316
|
+
{groupedOptions[groupName].map(renderOption)}
|
|
317
|
+
</div>
|
|
318
|
+
))}
|
|
304
319
|
</div>
|
|
305
|
-
|
|
306
|
-
|
|
307
320
|
</ListboxOptions>
|
|
308
321
|
);
|
|
309
322
|
}
|
|
@@ -413,7 +426,7 @@ export function renderListBoxValue(
|
|
|
413
426
|
};
|
|
414
427
|
return (
|
|
415
428
|
<>
|
|
416
|
-
<span className="form-selected-option">{renderValue()}</span>
|
|
429
|
+
<span className="form-selected-option w-full">{renderValue()}</span>
|
|
417
430
|
<SVGIcon
|
|
418
431
|
name="chevronDown"
|
|
419
432
|
className="h-5 w-5 text-gray-400"
|