@engagebay/engagebay-form-module 1.0.2-beta.4 → 1.0.2-beta.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/README.md CHANGED
@@ -124,3 +124,22 @@ const fieldSchema: FormFieldSchema = {
124
124
 
125
125
  - **`FormFieldPatternsImpl`**
126
126
  Class providing validation patterns and messages for fields (e.g., `REQUIRED`, `EMAIL`, `URL`).
127
+
128
+ ---
129
+
130
+ ## Context and providers (this package only)
131
+
132
+ These contexts are used **inside this package** (and by other packages in the eb-ui-components repo that depend on it). Consuming applications (other projects) have their own context trees and may wrap this package differently.
133
+
134
+ - **FormContext** — Provided by `<Form>`. Required for all field components used via `FormField` / `FormFields` (they use `useContext(FormContext)`).
135
+ - **AxiosConfigProvider** — Optional. Only needed for components that call APIs (e.g. dynamic options). Use `useAxiosConfig()` or `useAxiosConfigOptional()`.
136
+
137
+ ---
138
+
139
+ ## Implementing base components (this package)
140
+
141
+ When adding or changing form field components **in this package**:
142
+
143
+ - **Form-context components** — Must run inside `<Form>`. Use `useContext(FormContext)` for `register`, `setValue`, `control`, `errors`, etc. Register the component in `FormFieldUtils.ts` and export it from the package’s main entry (`index.js`).
144
+ - **Context-free components** — If a component does not need form or API context, note it in JSDoc (e.g. “Does not require FormContext”).
145
+ - **New contexts** — If you add a new React context in this package, document it in this README and list which components use it.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@engagebay/engagebay-form-module",
3
- "version": "1.0.2-beta.4",
3
+ "version": "1.0.2-beta.6",
4
4
  "description": "Provide base form components to reacho",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -16,7 +16,6 @@
16
16
  "@heroicons/react": ">=2.1.5",
17
17
  "@reduxjs/toolkit": ">=2.2.7",
18
18
  "@tippyjs/react": ">=4.2.6",
19
- "@types/lodash": ">=4.17.7",
20
19
  "@types/react-redux": ">=7.1.33",
21
20
  "axios": ">=1.7.2",
22
21
  "clsx": ">=2.1.1",
@@ -32,7 +31,6 @@
32
31
  "@heroicons/react": ">=2.1.5",
33
32
  "@reduxjs/toolkit": ">=2.2.7",
34
33
  "@tippyjs/react": ">=4.2.6",
35
- "@types/lodash": ">=4.17.7",
36
34
  "@types/react-redux": ">=7.1.33",
37
35
  "axios": ">=1.7.2",
38
36
  "clsx": ">=2.1.1",
@@ -34,6 +34,7 @@ import {
34
34
  FormFieldType,
35
35
  OptionMappingConfig,
36
36
  } from "./schema/FormFieldSchema";
37
+ import Typeahead2 from "./formfields/Typeahead2";
37
38
 
38
39
  /**
39
40
  * @property {React.FC<FormFieldComponentPropSchema>} component - React component for a form field.
@@ -139,6 +140,9 @@ const formFieldComponents: FormComponentSchema = {
139
140
  [FormFieldType[FormFieldType.TYPEAHEAD_MULTI_SELECT]]: {
140
141
  component: TypeaheadMultiSelect,
141
142
  },
143
+ [FormFieldType[FormFieldType.TYPEAHEAD_2]]: {
144
+ component: Typeahead2,
145
+ },
142
146
  [FormFieldType[FormFieldType.COMBO_SELECT]]: {
143
147
  component: ComboSelect,
144
148
  },
@@ -21,7 +21,6 @@ import FormField from "../FormField";
21
21
  import RenderFormField from "../util/RenderFormField";
22
22
  import { TrashIcon, XMarkIcon } from "@heroicons/react/24/outline";
23
23
  import Tippy from "@tippyjs/react";
24
- import { set } from "lodash";
25
24
 
26
25
  const defaultBusinessHours = {
27
26
  MONDAY: {
@@ -124,9 +123,8 @@ export const BusinessHoursField: React.FC<FormFieldComponentPropSchema> = (
124
123
  <div className="w-full sm:w-full text-end mr-[2.3em]">
125
124
  <button
126
125
  type="button"
127
- className={`text-end text-primary cursor-pointer font-[13px] font-medium ${
128
- getValues(`${mappedName}.sessions`)?.length > 1 ? "mr-9" : ""
129
- }`}
126
+ className={`text-end text-primary cursor-pointer font-[13px] font-medium ${getValues(`${mappedName}.sessions`)?.length > 1 ? "mr-9" : ""
127
+ }`}
130
128
  onClick={() => {
131
129
  const lastEndTime =
132
130
  getValues(`${mappedName}.sessions`)?.[
@@ -28,7 +28,7 @@ const NumberField: React.FC<FormFieldComponentPropSchema> = (
28
28
  step={props.fieldConfig.decimalAllowed ? 0.01 : 1}
29
29
  defaultValue={props.fieldConfig.defaultValue as string}
30
30
  className={`form-input ${
31
- props.fieldConfig.customClassNames?.fieldClassName || "flex-1 !w-60"
31
+ props.fieldConfig.customClassNames?.fieldClassName || "flex-1"
32
32
  }`}
33
33
  onKeyDown={(e) => {
34
34
  props.fieldConfig.onKeyDown && props.fieldConfig.onKeyDown(e);
@@ -58,8 +58,6 @@ const Typeahead: React.FC<FormFieldComponentPropSchema> = (
58
58
  let url = props.fieldConfig.fetchUrl;
59
59
  if (_query) {
60
60
  url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
61
- } else {
62
- url = url.includes("?") ? url + "&q=" + null : url + "?q=" + null;
63
61
  }
64
62
 
65
63
  let response = await (props.fieldConfig.disableHeaderInFetch
@@ -99,7 +97,9 @@ const Typeahead: React.FC<FormFieldComponentPropSchema> = (
99
97
  let url = props.fieldConfig.fetchUrl;
100
98
 
101
99
  if (value)
102
- url = url.includes("?") ? url + "&q=" + value : url + "?q=" + value;
100
+ url = url.includes("?")
101
+ ? url + "&values=" + value
102
+ : url + "?values=" + value;
103
103
 
104
104
  let response = await (props.fieldConfig.disableHeaderInFetch
105
105
  ? axios.get(url)
@@ -0,0 +1,283 @@
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
+
89
+ if (!_query || _query.length < 3) {
90
+ setListOptions([]);
91
+ setLoading(false);
92
+ return;
93
+ }
94
+ setLoading(true);
95
+ try {
96
+ if (!props.fieldConfig.fetchUrl) return;
97
+
98
+ let url = props.fieldConfig.fetchUrl;
99
+
100
+ url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
101
+
102
+ const axiosInstance = getAxiosInstance(
103
+ formContext.axiosInstance,
104
+ props.fieldConfig,
105
+ );
106
+ const response = await axiosInstance.get(url);
107
+
108
+ if (controller === abortControllerRef.current) {
109
+ if (response?.data) {
110
+ const data: FieldOptionsSchema[] = getListOptions(
111
+ response?.data,
112
+ props.fieldConfig.optionsConfig,
113
+ );
114
+ setListOptions([...data]);
115
+
116
+ if (props.fieldConfig.fetchCallback) {
117
+ props.fieldConfig.fetchCallback(response);
118
+ }
119
+ }
120
+ }
121
+ } catch (err) {
122
+ console.error("Fetch error:", err);
123
+ } finally {
124
+ // Only stop loading if this was the "active" request
125
+ if (controller === abortControllerRef.current) {
126
+ setLoading(false);
127
+ }
128
+ }
129
+ }, 250);
130
+ };
131
+ }, []);
132
+
133
+ // Cleanup on unmount
134
+ useEffect(() => {
135
+ return () => {
136
+ abortControllerRef.current?.abort();
137
+ };
138
+ }, []);
139
+
140
+ const fetchValue = async (value: string | any | any[]) => {
141
+ try {
142
+ if (
143
+ props.fieldConfig.ignoreFetchValue ||
144
+ !props.fieldConfig.fetchSavedDataUrl
145
+ ) {
146
+ return;
147
+ }
148
+
149
+ let url = props.fieldConfig.fetchSavedDataUrl;
150
+
151
+ // url = url.includes("?")
152
+ // ? url + "&values=" + value
153
+ // : url + "?values=" + value;
154
+
155
+ let response = await (props.fieldConfig.disableHeaderInFetch
156
+ ? axios.post(url, Array.isArray(value) ? value : [value])
157
+ : formContext.axiosInstance?.post(
158
+ url,
159
+ Array.isArray(value) ? value : [value],
160
+ ));
161
+ if (response?.data) {
162
+ const data: FieldOptionsSchema[] = getListOptions(
163
+ response?.data,
164
+ props.fieldConfig.optionsConfig,
165
+ );
166
+ let values: any[] = formContext.getValues(props.fieldConfig.name) || [];
167
+ setSelectedValues(
168
+ [
169
+ ...data,
170
+ props.fieldConfig.dropdownFieldConfig?.isSuggestionBox &&
171
+ values &&
172
+ Array.isArray(values)
173
+ ? values
174
+ .filter(
175
+ (value) =>
176
+ data.some((d) => d.value !== value) || data.length == 0,
177
+ )
178
+ .map((val) => ({ label: val, value: val }))
179
+ : [],
180
+ ].flat(),
181
+ );
182
+ }
183
+ } catch (err) { }
184
+ };
185
+
186
+ const updateListOptions = (data: any) => {
187
+ const resData: FieldOptionsSchema = getListOption(
188
+ data,
189
+ props.fieldConfig.optionsConfig,
190
+ );
191
+ setListOptions([]);
192
+ setSelectedValues((prev) =>
193
+ props.fieldConfig.isMultiple ? [...prev, resData] : [resData],
194
+ );
195
+ let result = formContext.getValues(props.fieldConfig.name) || [];
196
+ result = !props.fieldConfig.isMultiple
197
+ ? resData.value
198
+ : result.includes(resData.value)
199
+ ? [...result.filter((v: string) => v != resData.value), resData.value]
200
+ : [...result, resData.value];
201
+ formContext.setValue(props.fieldConfig.name, result);
202
+ };
203
+
204
+ const getInput = () => {
205
+ return (
206
+ <Listbox
207
+ as={"div"}
208
+ {...hookProps}
209
+ value={
210
+ props.fieldConfig.isMultiple
211
+ ? formContext.getValues(props.fieldConfig.name)
212
+ ? formContext.getValues(props.fieldConfig.name)
213
+ : []
214
+ : formContext.getValues(props.fieldConfig.name)
215
+ }
216
+ name={props.fieldConfig.name}
217
+ defaultValue={props.fieldConfig.defaultValue}
218
+ key={props.fieldConfig.name}
219
+ className={"relative form-listbox flex-1 overflow-hidden"}
220
+ onChange={(selectedOptions) => {
221
+ let currentValue = formContext.getValues(props.fieldConfig.name);
222
+ const newValue =
223
+ currentValue === selectedOptions ? null : selectedOptions;
224
+
225
+ if (props.fieldConfig.isMultiple) {
226
+ currentValue = listOptions.filter((op) =>
227
+ selectedOptions.includes(op.value),
228
+ );
229
+ setSelectedValues((prev) => [...prev, ...currentValue]);
230
+ } else {
231
+ const selected = listOptions.find((o) => o.value == newValue);
232
+ selected && setSelectedValues([selected]);
233
+ }
234
+ setListOptions([]);
235
+ handleChange(
236
+ newValue,
237
+ formContext,
238
+ props.fieldConfig,
239
+ props.onChange,
240
+ );
241
+ }}
242
+ multiple={props.fieldConfig.isMultiple}
243
+ >
244
+ <ListboxButton
245
+ className={
246
+ props.fieldConfig.customClassNames?.fieldClassName
247
+ ? "form-listbox-select " +
248
+ props.fieldConfig.customClassNames?.fieldClassName
249
+ : "form-listbox-select"
250
+ }
251
+ >
252
+ {renderListBoxValue(
253
+ formContext,
254
+ props.fieldConfig,
255
+ [...selectedValues, ...listOptions],
256
+ props.onChange,
257
+ )}
258
+ </ListboxButton>
259
+ <RenderListOptions
260
+ formContext={formContext}
261
+ onChange={props.onChange}
262
+ formField={FormFieldType.TYPEAHEAD_2}
263
+ ref={dynamicSelectRef}
264
+ fieldConfig={props.fieldConfig}
265
+ listOptions={listOptions}
266
+ setListOptions={setListOptions}
267
+ loading={loading}
268
+ setLoading={setLoading}
269
+ createCallback={(data) => updateListOptions(data)}
270
+ queryCallback={(query) => fetchData(query)}
271
+ />
272
+ </Listbox>
273
+ );
274
+ };
275
+ if (props.fieldConfig.hideWhenNoResults && listOptions.length == 0) {
276
+ return <></>;
277
+ }
278
+
279
+ return (
280
+ <RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
281
+ );
282
+ };
283
+ export default Typeahead2;
@@ -60,8 +60,6 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
60
60
  let url = props.fieldConfig.fetchUrl;
61
61
  if (_query) {
62
62
  url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
63
- } else {
64
- url = url.includes("?") ? url + "&q=" + null : url + "?q=" + null;
65
63
  }
66
64
  const axiosInstance = getAxiosInstance(
67
65
  formContext.axiosInstance,
@@ -110,7 +108,9 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
110
108
 
111
109
  let url = props.fieldConfig.fetchUrl;
112
110
 
113
- url = url = url.includes("?") ? url + "&q=" + value : url + "?q=" + value;
111
+ url = url.includes("?")
112
+ ? url + "&values=" + value
113
+ : url + "?values=" + value;
114
114
 
115
115
  let response = await (props.fieldConfig.disableHeaderInFetch
116
116
  ? axios.get(url)
@@ -126,16 +126,16 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
126
126
  ...data,
127
127
  props.fieldConfig.dropdownFieldConfig?.isSuggestionBox && values
128
128
  ? values
129
- .filter(
130
- (value) =>
131
- data.some((d) => d.value !== value) || data.length == 0,
132
- )
133
- .map((val) => ({ label: val, value: val }))
129
+ .filter(
130
+ (value) =>
131
+ data.some((d) => d.value !== value) || data.length == 0,
132
+ )
133
+ .map((val) => ({ label: val, value: val }))
134
134
  : [],
135
135
  ].flat(),
136
136
  );
137
137
  }
138
- } catch (err) {}
138
+ } catch (err) { }
139
139
  };
140
140
 
141
141
  const updateListOptions = (data: any) => {
@@ -179,7 +179,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
179
179
  className={
180
180
  props.fieldConfig.customClassNames?.fieldClassName
181
181
  ? "form-listbox-select " +
182
- props.fieldConfig.customClassNames?.fieldClassName
182
+ props.fieldConfig.customClassNames?.fieldClassName
183
183
  : "form-listbox-select"
184
184
  }
185
185
  >
@@ -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",
@@ -129,10 +130,12 @@ export type FormFieldSchema = {
129
130
  submitOnChange?: boolean;
130
131
  formFieldPattern?: FormFieldPatternsImpl[];
131
132
  fetchUrl?: string;
133
+ fetchSavedDataUrl?: string;
132
134
  postUrl?: string;
133
135
  fileAccept?: string;
134
136
  icon?: ReactNode;
135
137
  outputFormat?: OutputFormatType;
138
+ isMultiple?: boolean;
136
139
  children?: FormFieldSchema[];
137
140
  defaultOptions?: FieldOptionsSchema[];
138
141
  optionsConfig?: OptionMappingConfig;
@@ -102,15 +102,15 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
102
102
 
103
103
  const filteredList = query
104
104
  ? resultList.filter((item) => {
105
- const normalizedLabel = fieldConfig.dropdownFieldConfig
106
- ?.isCaseSensitive
107
- ? item.label
108
- : item.label.toLowerCase();
105
+ const normalizedLabel = fieldConfig.dropdownFieldConfig
106
+ ?.isCaseSensitive
107
+ ? item.label
108
+ : item.label.toLowerCase();
109
109
 
110
- return normalizedLabel
111
- .replace(/\s+/g, "")
112
- .includes(caseSensitive.replace(/\s+/g, ""));
113
- })
110
+ return normalizedLabel
111
+ .replace(/\s+/g, "")
112
+ .includes(caseSensitive.replace(/\s+/g, ""));
113
+ })
114
114
  : resultList;
115
115
 
116
116
  let nullGroupOptions: any[] = [];
@@ -127,13 +127,15 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
127
127
  }, {});
128
128
 
129
129
  const handleQueryCallback = useCallback(() => {
130
- if (filteredList.length == 0 && isTypeahead) {
130
+ if (filteredList.length < 5 && isTypeahead) {
131
131
  queryCallback && queryCallback(query);
132
132
  }
133
133
  }, [filteredList]);
134
134
 
135
135
  useEffect(() => {
136
- handleQueryCallback();
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;
@@ -166,11 +169,10 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
166
169
  key={option.value}
167
170
  disabled={option.isDisabled}
168
171
  onClick={() => setTimeout(resetToDefault, 300)}
169
- className={`form-listbox-option ${
170
- selected
171
- ? " bg-gray-100 text-gray-900"
172
- : "hover:bg-gray-100 text-gray-700"
173
- }`}
172
+ className={`form-listbox-option ${selected
173
+ ? " bg-gray-100 text-gray-900"
174
+ : "hover:bg-gray-100 text-gray-700"
175
+ }`}
174
176
  value={option.value}
175
177
  >
176
178
  {fieldConfig.fieldOptionWrapper ? (
@@ -179,9 +181,8 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
179
181
  <>
180
182
  <div className="flex items-center justify-between gap-x-1.5">
181
183
  <span
182
- className={`block truncate w-full ${fieldConfig.customClassNames?.optionClassName} space-x-2 ${
183
- selected ? "font-medium" : "font-normal"
184
- }`}
184
+ className={`block truncate w-full ${fieldConfig.customClassNames?.optionClassName} space-x-2 ${selected ? "font-medium" : "font-normal"
185
+ }`}
185
186
  >
186
187
  {option.icon && (
187
188
  <span className="listbox-svg">{option.icon}</span>
@@ -203,7 +204,7 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
203
204
  )}
204
205
  </span>
205
206
  {isTypeahead &&
206
- !fieldConfig.dropdownFieldConfig?.isSuggestionBox ? (
207
+ !fieldConfig.dropdownFieldConfig?.isSuggestionBox ? (
207
208
  <input
208
209
  type="checkbox"
209
210
  className="form-checkbox"
@@ -399,28 +400,28 @@ export function renderListBoxValue(
399
400
  {values.length > 1
400
401
  ? `${values.length} selected`
401
402
  : listOptions.find((option) => option.value == value[0])?.label ||
402
- values[0]}
403
+ values[0]}
403
404
  </span>
404
405
  {getDeleteButton()}
405
406
  </span>
406
407
  ) : (
407
408
  Array.isArray(values) &&
408
- values.map((opt: any) => {
409
- const option = listOptions.find((option) => option.value == opt);
410
- if (!option && values.length == 0) return getPlaceholder();
409
+ values.map((opt: any) => {
410
+ const option = listOptions.find((option) => option.value == opt);
411
+ if (!option && values.length == 0) return getPlaceholder();
411
412
 
412
- return (
413
- <span key={option?.value} className="form-selected-badge">
414
- <Tippy content={option?.label} delay={500}>
415
- <span className="form-selected-badge-name">
416
- {option?.label}
417
- </span>
418
- </Tippy>
413
+ return (
414
+ <span key={option?.value} className="form-selected-badge">
415
+ <Tippy content={option?.label} delay={500}>
416
+ <span className="form-selected-badge-name">
417
+ {option?.label}
418
+ </span>
419
+ </Tippy>
419
420
 
420
- {getDeleteButton(opt)}
421
- </span>
422
- );
423
- })
421
+ {getDeleteButton(opt)}
422
+ </span>
423
+ );
424
+ })
424
425
  );
425
426
  };
426
427
  const getDeleteButton = (option?: string) => {
@@ -452,9 +453,10 @@ export function renderListBoxValue(
452
453
  )
453
454
  );
454
455
  };
455
- let outputFormat = fieldConfig.outputFormat
456
- ? fieldConfig.outputFormat === OutputFormatType.ARRAY
457
- : false;
456
+ let outputFormat =
457
+ fieldConfig.outputFormat != undefined
458
+ ? fieldConfig.outputFormat === OutputFormatType.STRING
459
+ : false;
458
460
  const getPlaceholder = () => (
459
461
  <span className="form-placeholder">
460
462
  {fieldConfig.placeholder || "Select any option"}