@engagebay/engagebay-form-module 1.0.6 → 1.0.7-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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@engagebay/engagebay-form-module",
3
- "version": "1.0.6",
3
+ "version": "1.0.7-beta.1",
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",
package/src/api/index.ts CHANGED
@@ -1,10 +1,16 @@
1
1
  import axios, {AxiosInstance, AxiosRequestConfig} from "axios";
2
2
  import {FormFieldSchema} from "../form/schema/FormFieldSchema";
3
3
 
4
+ let baseURL;
5
+ try {
6
+ baseURL = (window as any).DEFAULT_HOST ||
7
+ (window as any).parent.DEFAULT_HOST
8
+ } catch (error) {
9
+
10
+ }
11
+
4
12
  const BASE_API: AxiosRequestConfig = {
5
- baseURL:
6
- (window as any).REACHO_BASE_URL ||
7
- (window as any).parent.REACHO_BASE_URL,
13
+ baseURL: baseURL ?? "",
8
14
  timeout: 30000,
9
15
  headers: {
10
16
  "Content-Type": "application/json",
@@ -28,13 +28,13 @@ 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";
32
31
  import {
33
32
  FieldOptionsSchema,
34
33
  FormFieldComponentPropSchema,
35
34
  FormFieldType,
36
35
  OptionMappingConfig,
37
36
  } from "./schema/FormFieldSchema";
37
+ import Typeahead2 from "./formfields/Typeahead2";
38
38
 
39
39
  /**
40
40
  * @property {React.FC<FormFieldComponentPropSchema>} component - React component for a form field.
@@ -137,12 +137,12 @@ const formFieldComponents: FormComponentSchema = {
137
137
  [FormFieldType[FormFieldType.TYPEAHEAD]]: {
138
138
  component: Typeahead,
139
139
  },
140
- [FormFieldType[FormFieldType.TYPEAHEAD_2]]: {
141
- component: Typeahead2,
142
- },
143
140
  [FormFieldType[FormFieldType.TYPEAHEAD_MULTI_SELECT]]: {
144
141
  component: TypeaheadMultiSelect,
145
142
  },
143
+ [FormFieldType[FormFieldType.TYPEAHEAD_2]]: {
144
+ component: Typeahead2,
145
+ },
146
146
  [FormFieldType[FormFieldType.COMBO_SELECT]]: {
147
147
  component: ComboSelect,
148
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`)?.[
@@ -8,7 +8,7 @@ import { handleChange, registerFormField } from "../util";
8
8
  import moment from "moment";
9
9
 
10
10
  const DatePicker: React.FC<FormFieldComponentPropSchema> = (
11
- props: FormFieldComponentPropSchema
11
+ props: FormFieldComponentPropSchema,
12
12
  ) => {
13
13
  const formContext = useContext(FormContext);
14
14
  const initialDate = formContext.getValues(props.fieldConfig.name)
@@ -25,13 +25,13 @@ const DatePicker: React.FC<FormFieldComponentPropSchema> = (
25
25
  ) {
26
26
  formContext.setValue(
27
27
  props.fieldConfig.name,
28
- props.fieldConfig.defaultValue
28
+ props.fieldConfig.defaultValue,
29
29
  );
30
30
  }
31
31
  }, [props.fieldConfig.forceUpdate]);
32
32
 
33
33
  let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
34
-
34
+ //registerOptions.valueAsDate = true;
35
35
  let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
36
36
 
37
37
  function getInput() {
@@ -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);
@@ -1,9 +1,9 @@
1
1
  import React, {
2
- useCallback,
3
- useContext,
4
- useEffect,
5
- useRef,
6
- useState,
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,199 +12,185 @@ import { RegisterOptions } from "react-hook-form";
12
12
  import { FormContext } from "../context/FormContext";
13
13
  import { getListOption, getListOptions } from "../FormFieldUtils";
14
14
  import {
15
- FieldOptionsSchema,
16
- FormFieldComponentPropSchema,
17
- FormFieldType,
18
- OutputFormatType,
15
+ FieldOptionsSchema,
16
+ FormFieldComponentPropSchema,
17
+ FormFieldType,
18
+ OutputFormatType,
19
19
  } from "../schema/FormFieldSchema";
20
20
  import { handleChange, registerFormField } from "../util";
21
21
  import RenderFormField from "../util/RenderFormField";
22
22
  import RenderListOptions, {
23
- renderListBoxValue,
23
+ renderListBoxValue,
24
24
  } from "../util/RenderListOptions";
25
25
 
26
26
  const Typeahead: React.FC<FormFieldComponentPropSchema> = (
27
- props: FormFieldComponentPropSchema
27
+ props: FormFieldComponentPropSchema,
28
28
  ) => {
29
- const dynamicSelectRef = useRef<HTMLUListElement>(null);
30
- const formContext = useContext(FormContext);
31
- let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
32
- let hookProps = formContext.register(
33
- props.fieldConfig.name,
34
- registerOptions
35
- );
36
- const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
37
- const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
38
- []
39
- );
40
- const [loading, setLoading] = useState<boolean>(true);
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
- fetchData(undefined);
53
- }, []);
29
+ const dynamicSelectRef = useRef<HTMLUListElement>(null);
30
+ const formContext = useContext(FormContext);
31
+ let registerOptions: RegisterOptions = registerFormField(props.fieldConfig);
32
+ let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
33
+ const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
34
+ const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
35
+ [],
36
+ );
37
+ const [loading, setLoading] = useState<boolean>(true);
54
38
 
55
- const fetchData = useCallback(
56
- async (_query: string | undefined) => {
57
- setLoading(true);
58
- try {
59
- if (!props.fieldConfig.fetchUrl) return;
39
+ useEffect(() => {
40
+ if (
41
+ !formContext.getValues(props.fieldConfig.name) &&
42
+ props.fieldConfig.defaultValue
43
+ ) {
44
+ formContext.setValue(
45
+ props.fieldConfig.name,
46
+ props.fieldConfig.defaultValue,
47
+ );
48
+ }
49
+ fetchData(undefined);
50
+ }, []);
60
51
 
61
- let url = props.fieldConfig.fetchUrl;
62
- if (_query) {
63
- url = url.includes("?")
64
- ? url + "&q=" + _query
65
- : url + "?q=" + _query;
66
- }
52
+ const fetchData = useCallback(
53
+ async (_query: string | undefined) => {
54
+ setLoading(true);
55
+ try {
56
+ if (!props.fieldConfig.fetchUrl) return;
67
57
 
68
- let response = await (props.fieldConfig.disableHeaderInFetch
69
- ? axios.get(url)
70
- : formContext.axiosInstance?.get(url));
71
- if (response?.data) {
72
- const data: FieldOptionsSchema[] = getListOptions(
73
- response.data,
74
- props.fieldConfig.optionsConfig
75
- );
76
- setListOptions([...data]);
77
- let value = formContext.getValues(props.fieldConfig.name);
78
- if (
79
- value &&
80
- data.find((i) => i.value !== value)
81
- ) {
82
- if (selectedValues.find((i) => i.value !== value))
83
- fetchValue(value);
84
- }
85
- if (props.fieldConfig.fetchCallback) {
86
- props.fieldConfig.fetchCallback(response);
87
- }
88
- } else {
89
- console.error(response?.statusText);
90
- }
91
- } catch (err) {
92
- } finally {
93
- setLoading(false);
94
- }
95
- },
96
- [props.fieldConfig.fetchUrl]
97
- );
58
+ let url = props.fieldConfig.fetchUrl;
59
+ if (_query) {
60
+ url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
61
+ }
98
62
 
99
- const fetchValue = async (value: string) => {
100
- try {
101
- if (
102
- props.fieldConfig.ignoreFetchValue ||
103
- !props.fieldConfig.fetchUrl
104
- ) {
105
- return;
106
- }
63
+ let response = await (props.fieldConfig.disableHeaderInFetch
64
+ ? axios.get(url)
65
+ : formContext.axiosInstance?.get(url));
66
+ if (response?.data) {
67
+ const data: FieldOptionsSchema[] = getListOptions(
68
+ response.data,
69
+ props.fieldConfig.optionsConfig,
70
+ );
71
+ setListOptions([...data]);
72
+ let value = formContext.getValues(props.fieldConfig.name);
73
+ if (value && data.find((i) => i.value !== value)) {
74
+ if (selectedValues.find((i) => i.value !== value))
75
+ fetchValue(value);
76
+ }
77
+ if (props.fieldConfig.fetchCallback) {
78
+ props.fieldConfig.fetchCallback(response);
79
+ }
80
+ } else {
81
+ console.error(response?.statusText);
82
+ }
83
+ } catch (err) {
84
+ } finally {
85
+ setLoading(false);
86
+ }
87
+ },
88
+ [props.fieldConfig.fetchUrl],
89
+ );
107
90
 
108
- let url = props.fieldConfig.fetchUrl;
91
+ const fetchValue = async (value: string) => {
92
+ try {
93
+ if (props.fieldConfig.ignoreFetchValue || !props.fieldConfig.fetchUrl) {
94
+ return;
95
+ }
109
96
 
110
- if (value)
111
- url = url.includes("?")
112
- ? url + "&values=" + value
113
- : url + "?values=" + value;
97
+ let url = props.fieldConfig.fetchUrl;
114
98
 
115
- let response = await (
116
- props.fieldConfig.disableHeaderInFetch
117
- ? axios.get(url)
118
- : formContext.axiosInstance?.get(url)
119
- );
120
- if (response?.data) {
121
- const data: FieldOptionsSchema[] = getListOptions(
122
- response?.data,
123
- props.fieldConfig.optionsConfig
124
- );
125
- setSelectedValues([...data]);
126
- }
127
- } catch (err) { }
128
- };
99
+ if (value)
100
+ url = url.includes("?")
101
+ ? url + "&values=" + value
102
+ : url + "?values=" + value;
129
103
 
130
- const updateListOptions = (data: any) => {
131
- const resData: FieldOptionsSchema = getListOption(
132
- data,
133
- props.fieldConfig.optionsConfig
104
+ let response = await (props.fieldConfig.disableHeaderInFetch
105
+ ? axios.get(url)
106
+ : formContext.axiosInstance?.get(url));
107
+ if (response?.data) {
108
+ const data: FieldOptionsSchema[] = getListOptions(
109
+ response?.data,
110
+ props.fieldConfig.optionsConfig,
134
111
  );
135
- setSelectedValues((perv) => [resData]);
136
- formContext.setValue(props.fieldConfig.name, resData.value);
137
- };
112
+ setSelectedValues([...data]);
113
+ }
114
+ } catch (err) {}
115
+ };
138
116
 
139
- function getInput() {
140
- return (
141
- <Listbox
142
- as={"div"}
143
- {...hookProps}
144
- className={`relative form-listbox flex-1`}
145
- value={
146
- formContext.getValues(props.fieldConfig.name)
147
- ? props.fieldConfig.outputFormat ===
148
- OutputFormatType.ARRAY
149
- ? formContext.getValues(props.fieldConfig.name)[0]
150
- : formContext.getValues(props.fieldConfig.name)
151
- : undefined
152
- }
153
- onChange={(val) => {
154
- const currentValue = formContext.getValues(
155
- props.fieldConfig.name
156
- );
117
+ const updateListOptions = (data: any) => {
118
+ const resData: FieldOptionsSchema = getListOption(
119
+ data,
120
+ props.fieldConfig.optionsConfig,
121
+ );
122
+ setSelectedValues((perv) => [resData]);
123
+ formContext.setValue(props.fieldConfig.name, resData.value);
124
+ };
157
125
 
158
- // If the value matches, set it to null, otherwise set it to val
159
- const newValue = currentValue === val ? null : val;
126
+ function getInput() {
127
+ return (
128
+ <Listbox
129
+ as={"div"}
130
+ {...hookProps}
131
+ className={`relative form-listbox flex-1`}
132
+ value={
133
+ formContext.getValues(props.fieldConfig.name)
134
+ ? props.fieldConfig.outputFormat === OutputFormatType.ARRAY
135
+ ? formContext.getValues(props.fieldConfig.name)[0]
136
+ : formContext.getValues(props.fieldConfig.name)
137
+ : undefined
138
+ }
139
+ onChange={(val) => {
140
+ const currentValue = formContext.getValues(props.fieldConfig.name);
160
141
 
161
- const selected = listOptions.find(o => o.value == newValue);
162
- selected && setSelectedValues([selected]);
163
- handleChange(
164
- newValue,
165
- formContext,
166
- props.fieldConfig,
167
- props.onChange
168
- );
169
- }}
170
- name={props.fieldConfig.name}
171
- disabled={props.fieldConfig.disabled}>
172
- <ListboxButton
173
- className={
174
- props.fieldConfig.customClassNames?.fieldClassName
175
- ? "form-listbox-select " +
176
- props.fieldConfig.customClassNames?.fieldClassName
177
- : "form-listbox-select"
178
- }>
179
- {renderListBoxValue(
180
- formContext,
181
- props.fieldConfig,
182
- [...selectedValues, ...listOptions],
183
- props.onChange
184
- )}
185
- </ListboxButton>
186
- <RenderListOptions
187
- formContext={formContext}
188
- onChange={props.onChange}
189
- formField={FormFieldType.TYPEAHEAD}
190
- ref={dynamicSelectRef}
191
- fieldConfig={props.fieldConfig}
192
- listOptions={[...selectedValues, ...listOptions]}
193
- setListOptions={setListOptions}
194
- loading={loading}
195
- setLoading={setLoading}
196
- createCallback={(data) => updateListOptions(data)}
197
- queryCallback={(query) => fetchData(query)}
198
- />
199
- </Listbox>
200
- );
201
- }
202
- if (props.fieldConfig.hideWhenNoResults && listOptions.length == 0) {
203
- return <></>;
204
- }
142
+ // If the value matches, set it to null, otherwise set it to val
143
+ const newValue = currentValue === val ? null : val;
205
144
 
206
- return (
207
- <RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
145
+ const selected = listOptions.find((o) => o.value == newValue);
146
+ selected && setSelectedValues([selected]);
147
+ handleChange(
148
+ newValue,
149
+ formContext,
150
+ props.fieldConfig,
151
+ props.onChange,
152
+ );
153
+ }}
154
+ name={props.fieldConfig.name}
155
+ disabled={props.fieldConfig.disabled}
156
+ >
157
+ <ListboxButton
158
+ className={
159
+ props.fieldConfig.customClassNames?.fieldClassName
160
+ ? "form-listbox-select " +
161
+ props.fieldConfig.customClassNames?.fieldClassName
162
+ : "form-listbox-select"
163
+ }
164
+ >
165
+ {renderListBoxValue(
166
+ formContext,
167
+ props.fieldConfig,
168
+ [...selectedValues, ...listOptions],
169
+ props.onChange,
170
+ )}
171
+ </ListboxButton>
172
+ <RenderListOptions
173
+ formContext={formContext}
174
+ onChange={props.onChange}
175
+ formField={FormFieldType.TYPEAHEAD}
176
+ ref={dynamicSelectRef}
177
+ fieldConfig={props.fieldConfig}
178
+ listOptions={[...selectedValues, ...listOptions]}
179
+ setListOptions={setListOptions}
180
+ loading={loading}
181
+ setLoading={setLoading}
182
+ createCallback={(data) => updateListOptions(data)}
183
+ queryCallback={(query) => fetchData(query)}
184
+ />
185
+ </Listbox>
208
186
  );
187
+ }
188
+ if (props.fieldConfig.hideWhenNoResults && listOptions.length == 0) {
189
+ return <></>;
190
+ }
191
+
192
+ return (
193
+ <RenderFormField fieldConfig={props.fieldConfig} getInput={getInput} />
194
+ );
209
195
  };
210
196
  export default Typeahead;
@@ -23,9 +23,10 @@ import RenderListOptions, {
23
23
  } from "../util/RenderListOptions";
24
24
  // import _ from "lodash";
25
25
  import axios from "axios";
26
+ import { getAxiosInstance } from "../../api";
26
27
 
27
28
  const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
28
- props: FormFieldComponentPropSchema
29
+ props: FormFieldComponentPropSchema,
29
30
  ) => {
30
31
  const dynamicSelectRef = useRef<HTMLUListElement>(null);
31
32
  const formContext = useContext(FormContext);
@@ -33,7 +34,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
33
34
  let hookProps = formContext.register(props.fieldConfig.name, registerOptions);
34
35
  const [listOptions, setListOptions] = useState<FieldOptionsSchema[]>([]);
35
36
  const [selectedValues, setSelectedValues] = useState<FieldOptionsSchema[]>(
36
- []
37
+ [],
37
38
  );
38
39
  const [loading, setLoading] = useState<boolean>(true);
39
40
 
@@ -44,7 +45,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
44
45
  ) {
45
46
  formContext.setValue(
46
47
  props.fieldConfig.name,
47
- props.fieldConfig.defaultValue
48
+ props.fieldConfig.defaultValue,
48
49
  );
49
50
  }
50
51
  fetchData(undefined);
@@ -60,14 +61,16 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
60
61
  if (_query) {
61
62
  url = url.includes("?") ? url + "&q=" + _query : url + "?q=" + _query;
62
63
  }
64
+ const axiosInstance = getAxiosInstance(
65
+ formContext.axiosInstance,
66
+ props.fieldConfig,
67
+ );
63
68
 
64
- let response = await (props.fieldConfig.disableHeaderInFetch
65
- ? axios.get(url)
66
- : formContext.axiosInstance?.get(url));
69
+ let response = await axiosInstance.get(url);
67
70
  if (response?.data) {
68
71
  const data: FieldOptionsSchema[] = getListOptions(
69
72
  response?.data,
70
- props.fieldConfig.optionsConfig
73
+ props.fieldConfig.optionsConfig,
71
74
  );
72
75
  setListOptions([...data]);
73
76
  let values = formContext.getValues(props.fieldConfig.name) || [];
@@ -77,7 +80,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
77
80
  (data.length === 0 || // If 'data' is empty
78
81
  (!values.every((v: string) => data.some((i) => i.value === v)) && // Ensure none of 'values' match 'data'
79
82
  !values.every((v: string) =>
80
- selectedValues.some((i) => i.value === v)
83
+ selectedValues.some((i) => i.value === v),
81
84
  ))) // Ensure none of 'values' match 'selectedValues'
82
85
  ) {
83
86
  fetchValue(values); // Call 'fetchValue()' if all conditions are met
@@ -94,7 +97,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
94
97
  setLoading(false);
95
98
  }
96
99
  },
97
- [props.fieldConfig.fetchUrl]
100
+ [props.fieldConfig.fetchUrl],
98
101
  );
99
102
 
100
103
  const fetchValue = async (value: string) => {
@@ -105,7 +108,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
105
108
 
106
109
  let url = props.fieldConfig.fetchUrl;
107
110
 
108
- url = url = url.includes("?")
111
+ url = url.includes("?")
109
112
  ? url + "&values=" + value
110
113
  : url + "?values=" + value;
111
114
 
@@ -115,7 +118,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
115
118
  if (response?.data) {
116
119
  const data: FieldOptionsSchema[] = getListOptions(
117
120
  response?.data,
118
- props.fieldConfig.optionsConfig
121
+ props.fieldConfig.optionsConfig,
119
122
  );
120
123
  let values: any[] = formContext.getValues(props.fieldConfig.name) || [];
121
124
  setSelectedValues(
@@ -123,22 +126,22 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
123
126
  ...data,
124
127
  props.fieldConfig.dropdownFieldConfig?.isSuggestionBox && values
125
128
  ? values
126
- .filter(
127
- (value) =>
128
- data.some((d) => d.value !== value) || data.length == 0
129
- )
130
- .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 }))
131
134
  : [],
132
- ].flat()
135
+ ].flat(),
133
136
  );
134
137
  }
135
- } catch (err) {}
138
+ } catch (err) { }
136
139
  };
137
140
 
138
141
  const updateListOptions = (data: any) => {
139
142
  const resData: FieldOptionsSchema = getListOption(
140
143
  data,
141
- props.fieldConfig.optionsConfig
144
+ props.fieldConfig.optionsConfig,
142
145
  );
143
146
  setSelectedValues((prev) => [...prev, resData]);
144
147
  let result = formContext.getValues(props.fieldConfig.name) || [];
@@ -160,14 +163,14 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
160
163
  className={"relative form-listbox flex-1 overflow-hidden"}
161
164
  onChange={(selectedOptions) => {
162
165
  const chossenOptions = listOptions.filter((op) =>
163
- selectedOptions.includes(op.value)
166
+ selectedOptions.includes(op.value),
164
167
  );
165
168
  setSelectedValues((prev) => [...prev, ...chossenOptions]);
166
169
  handleChange(
167
170
  selectedOptions,
168
171
  formContext,
169
172
  props.fieldConfig,
170
- props.onChange
173
+ props.onChange,
171
174
  );
172
175
  }}
173
176
  multiple
@@ -176,7 +179,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
176
179
  className={
177
180
  props.fieldConfig.customClassNames?.fieldClassName
178
181
  ? "form-listbox-select " +
179
- props.fieldConfig.customClassNames?.fieldClassName
182
+ props.fieldConfig.customClassNames?.fieldClassName
180
183
  : "form-listbox-select"
181
184
  }
182
185
  >
@@ -184,7 +187,7 @@ const TypeaheadMultiSelect: React.FC<FormFieldComponentPropSchema> = (
184
187
  formContext,
185
188
  props.fieldConfig,
186
189
  [...selectedValues, ...listOptions],
187
- props.onChange
190
+ props.onChange,
188
191
  )}
189
192
  </ListboxButton>
190
193
  <RenderListOptions
@@ -106,7 +106,6 @@ export type FormFieldSchema = {
106
106
  max?: number;
107
107
  min?: number;
108
108
  rows?: number;
109
- allowedMinQueryLength?: number;
110
109
  defaultValue?: string | string[] | {} | boolean;
111
110
  options?: FieldOptionsSchema[];
112
111
  minDate?: Date | null | undefined;
@@ -129,14 +128,15 @@ export type FormFieldSchema = {
129
128
  decimalAllowed?: boolean;
130
129
  errorMessage?: string;
131
130
  submitOnChange?: boolean;
132
- isMultiple?: boolean;
133
131
  formFieldPattern?: FormFieldPatternsImpl[];
134
132
  fetchUrl?: string;
135
- postUrl?: string;
136
133
  fetchSavedDataUrl?: string;
134
+ postUrl?: string;
137
135
  fileAccept?: string;
138
136
  icon?: ReactNode;
139
137
  outputFormat?: OutputFormatType;
138
+ isMultiple?: boolean;
139
+ allowedMinQueryLength?: number;
140
140
  children?: FormFieldSchema[];
141
141
  defaultOptions?: FieldOptionsSchema[];
142
142
  optionsConfig?: OptionMappingConfig;
@@ -205,6 +205,7 @@ export type FieldOptionsSchema = {
205
205
  isDisabled?: boolean;
206
206
  helpText?: string;
207
207
  groupName?: string;
208
+ tooltip?: string;
208
209
  icon?: React.ReactNode;
209
210
  };
210
211
 
@@ -11,13 +11,13 @@ import { handleChange } from ".";
11
11
  import { LoaderWithText } from "../../util/LoaderWithText";
12
12
  import SVGIcon from "../../util/svg/SVGIcon";
13
13
  import { FormContextType } from "../context/FormContext";
14
- import Tippy from "@tippyjs/react";
15
14
  import {
16
15
  FieldOptionsSchema,
17
16
  FormFieldSchema,
18
17
  FormFieldType,
19
18
  OutputFormatType,
20
19
  } from "../schema/FormFieldSchema";
20
+ import Tippy from "@tippyjs/react";
21
21
 
22
22
  type RenderListOptionsProps = {
23
23
  formContext: FormContextType;
@@ -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,7 +127,7 @@ 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]);
@@ -169,11 +169,10 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
169
169
  key={option.value}
170
170
  disabled={option.isDisabled}
171
171
  onClick={() => setTimeout(resetToDefault, 300)}
172
- className={`form-listbox-option ${
173
- selected
174
- ? " bg-gray-100 text-gray-900"
175
- : "hover:bg-gray-100 text-gray-700"
176
- }`}
172
+ className={`form-listbox-option ${selected
173
+ ? " bg-gray-100 text-gray-900"
174
+ : "hover:bg-gray-100 text-gray-700"
175
+ }`}
177
176
  value={option.value}
178
177
  >
179
178
  {fieldConfig.fieldOptionWrapper ? (
@@ -182,17 +181,30 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
182
181
  <>
183
182
  <div className="flex items-center justify-between gap-x-1.5">
184
183
  <span
185
- className={`block truncate w-full ${fieldConfig.customClassNames?.optionClassName} space-x-2 ${
186
- selected ? "font-medium" : "font-normal"
187
- }`}
184
+ className={`block truncate w-full ${fieldConfig.customClassNames?.optionClassName} space-x-2 ${selected ? "font-medium" : "font-normal"
185
+ }`}
188
186
  >
189
187
  {option.icon && (
190
188
  <span className="listbox-svg">{option.icon}</span>
191
189
  )}
192
- {option.label}
190
+ {option.tooltip ? (
191
+ <Tippy
192
+ content={
193
+ <>
194
+ {option.label}
195
+ <br />
196
+ {option.helpText}
197
+ </>
198
+ }
199
+ >
200
+ <div className="truncate">{option.label}</div>
201
+ </Tippy>
202
+ ) : (
203
+ option.label
204
+ )}
193
205
  </span>
194
206
  {isTypeahead &&
195
- !fieldConfig.dropdownFieldConfig?.isSuggestionBox ? (
207
+ !fieldConfig.dropdownFieldConfig?.isSuggestionBox ? (
196
208
  <input
197
209
  type="checkbox"
198
210
  className="form-checkbox"
@@ -208,11 +220,30 @@ const RenderListOptions = forwardRef<HTMLUListElement, RenderListOptionsProps>(
208
220
  )
209
221
  )}
210
222
  </div>
211
- {option.helpText && (
212
- <div className="mt-0 text-xs text-gray-500 font-normal truncate w-full !max-w-[150px]">
213
- {option.helpText}
214
- </div>
215
- )}
223
+ {option.helpText &&
224
+ (option.tooltip ? (
225
+ <Tippy
226
+ content={
227
+ <>
228
+ {option.label}
229
+ <br />
230
+ {option.helpText}
231
+ </>
232
+ }
233
+ >
234
+ <div
235
+ className={`mt-0 text-xs text-gray-500 font-normal truncate w-full ${fieldConfig.customClassNames?.optionClassName}`}
236
+ >
237
+ {option.helpText}
238
+ </div>
239
+ </Tippy>
240
+ ) : (
241
+ <div
242
+ className={`mt-0 text-xs text-gray-500 font-normal truncate w-full ${fieldConfig.customClassNames?.optionClassName}`}
243
+ >
244
+ {option.helpText}
245
+ </div>
246
+ ))}
216
247
  </>
217
248
  )}
218
249
  </ListboxOption>
@@ -372,28 +403,28 @@ export function renderListBoxValue(
372
403
  {values.length > 1
373
404
  ? `${values.length} selected`
374
405
  : listOptions.find((option) => option.value == value[0])?.label ||
375
- values[0]}
406
+ values[0]}
376
407
  </span>
377
408
  {getDeleteButton()}
378
409
  </span>
379
410
  ) : (
380
411
  Array.isArray(values) &&
381
- values.map((opt: any) => {
382
- const option = listOptions.find((option) => option.value == opt);
383
- if (!option && values.length == 0) return getPlaceholder();
412
+ values.map((opt: any) => {
413
+ const option = listOptions.find((option) => option.value == opt);
414
+ if (!option && values.length == 0) return getPlaceholder();
384
415
 
385
- return (
386
- <span key={option?.value} className="form-selected-badge">
387
- <Tippy content={option?.label} delay={500}>
388
- <span className="form-selected-badge-name">
389
- {option?.label}
390
- </span>
391
- </Tippy>
416
+ return (
417
+ <span key={option?.value} className="form-selected-badge">
418
+ <Tippy content={option?.label} delay={500}>
419
+ <span className="form-selected-badge-name">
420
+ {option?.label}
421
+ </span>
422
+ </Tippy>
392
423
 
393
- {getDeleteButton(opt)}
394
- </span>
395
- );
396
- })
424
+ {getDeleteButton(opt)}
425
+ </span>
426
+ );
427
+ })
397
428
  );
398
429
  };
399
430
  const getDeleteButton = (option?: string) => {
@@ -425,9 +456,10 @@ export function renderListBoxValue(
425
456
  )
426
457
  );
427
458
  };
428
- let outputFormat = fieldConfig.outputFormat
429
- ? fieldConfig.outputFormat === OutputFormatType.ARRAY
430
- : false;
459
+ let outputFormat =
460
+ fieldConfig.outputFormat != undefined
461
+ ? fieldConfig.outputFormat === OutputFormatType.STRING
462
+ : false;
431
463
  const getPlaceholder = () => (
432
464
  <span className="form-placeholder">
433
465
  {fieldConfig.placeholder || "Select any option"}