react-core-ts 1.2.30 → 1.2.32
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/dist/AutoCompleteWithSelectedList.js +24 -38
- package/dist/AutoCompleteWithSelectedList.js.map +1 -1
- package/dist/AutoCompleteWithTreeStructure.js +1 -1
- package/dist/AutoCompleteWithTreeStructure.js.map +1 -1
- package/dist/ExpandableAutoComplete.js +1 -1
- package/dist/ExpandableAutoComplete.js.map +1 -1
- package/dist/dummyAutoCompleteWithSelectedList.d.ts +4 -0
- package/dist/dummyAutoCompleteWithSelectedList.js +456 -0
- package/dist/dummyAutoCompleteWithSelectedList.js.map +1 -0
- package/dist/index.d.ts +15 -15
- package/dist/styles/components/autocomplete.css +1 -1
- package/package.json +1 -1
- package/src/AutoCompleteWithSelectedList.tsx +43 -63
- package/src/AutoCompleteWithTreeStructure.tsx +1 -1
- package/src/ExpandableAutoComplete.tsx +1 -1
- package/src/dummyAutoCompleteWithSelectedList.tsx +778 -0
- package/src/index.tsx +15 -15
- package/src/styles/components/autocomplete.css +1 -1
- package/dist/styles/styles/components/autocomplete.css +0 -616
- package/dist/styles/styles/components/selectedautocomplete.css +0 -128
- package/dist/styles/styles/components/tooltip.css +0 -496
- package/dist/styles/styles/components/treedropdown.css +0 -63
- package/dist/styles/styles/global.css +0 -8
|
@@ -0,0 +1,778 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react';
|
|
9
|
+
import ReactDOM from 'react-dom';
|
|
10
|
+
|
|
11
|
+
import { AutoSuggestionInputProps, TabPops, ValueProps } from './commontypes';
|
|
12
|
+
import DropdownList from './components/DropdownList';
|
|
13
|
+
import InputActions from './components/InputActions';
|
|
14
|
+
import { useSuggestions } from './utilities/autosuggestions';
|
|
15
|
+
import { debounce } from './utilities/debounce';
|
|
16
|
+
import { deepEqual } from './utilities/deepEqual';
|
|
17
|
+
import { default as Tooltip } from './utilities/expandableTootltip';
|
|
18
|
+
import { filterSuggestions } from './utilities/filterSuggestions';
|
|
19
|
+
import { DropArrow, Search, Spinner } from './utilities/icons';
|
|
20
|
+
|
|
21
|
+
const AutoCompleteWithSelectedList = forwardRef<
|
|
22
|
+
HTMLInputElement,
|
|
23
|
+
AutoSuggestionInputProps
|
|
24
|
+
>(
|
|
25
|
+
(
|
|
26
|
+
{
|
|
27
|
+
label,
|
|
28
|
+
onChange,
|
|
29
|
+
getData = async () => [],
|
|
30
|
+
data = [],
|
|
31
|
+
errors,
|
|
32
|
+
required = false,
|
|
33
|
+
name,
|
|
34
|
+
fullWidth = false,
|
|
35
|
+
placeholder,
|
|
36
|
+
id,
|
|
37
|
+
type = 'custom_select',
|
|
38
|
+
selectedItems: propsSeelctedItems = [],
|
|
39
|
+
readOnly = false,
|
|
40
|
+
disabled = false,
|
|
41
|
+
value,
|
|
42
|
+
isMultiple = false,
|
|
43
|
+
desc = 'name',
|
|
44
|
+
descId = 'id',
|
|
45
|
+
singleSelect,
|
|
46
|
+
className,
|
|
47
|
+
async = false,
|
|
48
|
+
paginationEnabled,
|
|
49
|
+
initialLoad = false,
|
|
50
|
+
actionLabel,
|
|
51
|
+
handleAction,
|
|
52
|
+
nextBlock,
|
|
53
|
+
notDataMessage,
|
|
54
|
+
initialDataMessage,
|
|
55
|
+
onFocus,
|
|
56
|
+
expandable = false,
|
|
57
|
+
textCount = 10,
|
|
58
|
+
itemCount = 1,
|
|
59
|
+
scrollRef,
|
|
60
|
+
countOnly = true,
|
|
61
|
+
typeOnlyFetch = false,
|
|
62
|
+
tab = [],
|
|
63
|
+
clearTabSwitch = false,
|
|
64
|
+
selectedRowLimit = 2,
|
|
65
|
+
topMargin = 0,
|
|
66
|
+
currentTab = 0,
|
|
67
|
+
selectedLabel = '',
|
|
68
|
+
viewMode = false,
|
|
69
|
+
},
|
|
70
|
+
ref
|
|
71
|
+
) => {
|
|
72
|
+
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
73
|
+
const dropdownSelectedRef = useRef<HTMLDivElement>(null);
|
|
74
|
+
const tabRef = useRef<HTMLUListElement>(null);
|
|
75
|
+
// State Hooks Section
|
|
76
|
+
const [isInitialRender, setIsInitialRender] = useState(true);
|
|
77
|
+
|
|
78
|
+
const [inputValue, setInputValue] = useState<string>(value);
|
|
79
|
+
const [searchValue, setSearchValue] = useState<string>('');
|
|
80
|
+
const [searchOldValue, setSearchOldValue] = useState<string>('');
|
|
81
|
+
const [nextPage, setNextPage] = useState<number | undefined>(1);
|
|
82
|
+
const [dropOpen, setDropOpen] = useState<boolean>(false);
|
|
83
|
+
const [selectedItems, setSelectedItems] = useState<ValueProps[]>([]);
|
|
84
|
+
|
|
85
|
+
const [showAllSelected, setShowAllSelected] = useState<boolean>(false);
|
|
86
|
+
const [expandArrowClick, setExpandArrowClick] = useState<
|
|
87
|
+
number | undefined
|
|
88
|
+
>(1);
|
|
89
|
+
const [activeTab, setActiveTab] = useState<number>(currentTab);
|
|
90
|
+
// API call for suggestions through a custom hook
|
|
91
|
+
const inputRef = useRef(null);
|
|
92
|
+
const dropRef = useRef(null);
|
|
93
|
+
const inputSearchRef = useRef(null);
|
|
94
|
+
useImperativeHandle(ref, () => inputRef.current);
|
|
95
|
+
const [dropdownStyle, setDropdownStyle] = useState<any>({
|
|
96
|
+
top: undefined,
|
|
97
|
+
left: 0,
|
|
98
|
+
width: 200,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const adjustDropdownPosition = () => {
|
|
102
|
+
if (dropdownRef.current) {
|
|
103
|
+
const inputRect = dropdownRef.current.getBoundingClientRect();
|
|
104
|
+
const dropdownPosition = {
|
|
105
|
+
left: inputRect.left + window.scrollX,
|
|
106
|
+
width: inputRect.width,
|
|
107
|
+
top: 0,
|
|
108
|
+
};
|
|
109
|
+
// Check if there's enough space below the input for the dropdown
|
|
110
|
+
const spaceBelow = window.innerHeight - inputRect.bottom;
|
|
111
|
+
let dropdownHeight = viewMode ? 160 : 380; // Assume a fixed height or calculate based on content
|
|
112
|
+
|
|
113
|
+
if (countOnly && !viewMode) {
|
|
114
|
+
// if (dropdownSelectedRef?.current) {
|
|
115
|
+
// dropdownHeight += dropdownSelectedRef?.current?.clientHeight;
|
|
116
|
+
// }
|
|
117
|
+
dropdownHeight += type === 'auto_suggestion' ? 220 : 192;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (tab.length > 0) {
|
|
121
|
+
if (tabRef?.current) dropdownHeight += tabRef?.current?.clientHeight;
|
|
122
|
+
}
|
|
123
|
+
console.log(dropdownHeight);
|
|
124
|
+
if (spaceBelow >= dropdownHeight) {
|
|
125
|
+
dropdownPosition.top =
|
|
126
|
+
inputRect.top + window.scrollY + inputRect.height;
|
|
127
|
+
} else {
|
|
128
|
+
dropdownPosition.top = viewMode
|
|
129
|
+
? inputRect.top + window.scrollY - dropdownHeight + 18 + topMargin
|
|
130
|
+
: inputRect.top + window.scrollY - dropdownHeight + 73 + topMargin;
|
|
131
|
+
}
|
|
132
|
+
setTimeout(() => {
|
|
133
|
+
setDropdownStyle({
|
|
134
|
+
...dropdownPosition,
|
|
135
|
+
});
|
|
136
|
+
}, 100);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
useEffect(() => {
|
|
141
|
+
window.addEventListener('resize', adjustDropdownPosition);
|
|
142
|
+
adjustDropdownPosition();
|
|
143
|
+
|
|
144
|
+
return () => {
|
|
145
|
+
window.removeEventListener('resize', adjustDropdownPosition);
|
|
146
|
+
};
|
|
147
|
+
}, [selectedItems, expandArrowClick, dropOpen]);
|
|
148
|
+
|
|
149
|
+
const { suggestions, isLoading, handlePickSuggestions } = useSuggestions(
|
|
150
|
+
getData,
|
|
151
|
+
data,
|
|
152
|
+
dropOpen,
|
|
153
|
+
async,
|
|
154
|
+
paginationEnabled,
|
|
155
|
+
initialLoad,
|
|
156
|
+
inputValue,
|
|
157
|
+
isMultiple,
|
|
158
|
+
setNextPage,
|
|
159
|
+
selectedItems,
|
|
160
|
+
typeOnlyFetch
|
|
161
|
+
// nextBlock
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
// Handling the selection of a suggestion
|
|
165
|
+
const handleSuggestionClick = useCallback((suggestion: ValueProps) => {
|
|
166
|
+
if (isMultiple) {
|
|
167
|
+
setSelectedItems((prev) => {
|
|
168
|
+
const isAdded =
|
|
169
|
+
prev && prev.length > 0
|
|
170
|
+
? prev.some((item) => item[descId] === suggestion[descId])
|
|
171
|
+
: false;
|
|
172
|
+
if (isAdded) {
|
|
173
|
+
return prev.filter((item) => item[descId] !== suggestion[descId]);
|
|
174
|
+
} else {
|
|
175
|
+
return [...prev, suggestion];
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
} else {
|
|
179
|
+
setInputValue(suggestion[desc]);
|
|
180
|
+
setSearchValue('');
|
|
181
|
+
onChange(suggestion);
|
|
182
|
+
setDropOpen(false);
|
|
183
|
+
}
|
|
184
|
+
}, []);
|
|
185
|
+
|
|
186
|
+
// Adding debounce to avoid making API calls on every keystroke
|
|
187
|
+
const debouncedUpdate = useCallback(
|
|
188
|
+
debounce((value: string, tabVal?: number | string) => {
|
|
189
|
+
setSearchOldValue(value);
|
|
190
|
+
handlePickSuggestions(value, 1, false, tabVal);
|
|
191
|
+
}, 500),
|
|
192
|
+
[]
|
|
193
|
+
);
|
|
194
|
+
|
|
195
|
+
const handleChangeWithDebounce = (value: string) => {
|
|
196
|
+
if ((type === 'auto_complete' || type === 'auto_suggestion') && async) {
|
|
197
|
+
const activeTabVal = tab.length > 0 ? tab?.[activeTab].id : undefined;
|
|
198
|
+
debouncedUpdate(value, activeTabVal);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
const handleMultiSelect = (e: any, suggestion: ValueProps) => {
|
|
203
|
+
const { checked } = e.target;
|
|
204
|
+
if (isMultiple) {
|
|
205
|
+
if (checked) {
|
|
206
|
+
setSelectedItems((prev) => [...prev, suggestion]);
|
|
207
|
+
} else {
|
|
208
|
+
setSelectedItems((prev) => {
|
|
209
|
+
return prev.filter(
|
|
210
|
+
(item, i) => item[descId] !== suggestion[descId]
|
|
211
|
+
);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
if (checked) {
|
|
216
|
+
setInputValue(suggestion[desc]);
|
|
217
|
+
onChange(suggestion);
|
|
218
|
+
} else {
|
|
219
|
+
setInputValue('');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
useEffect(() => {
|
|
224
|
+
if (!deepEqual(selectedItems, propsSeelctedItems))
|
|
225
|
+
setSelectedItems(propsSeelctedItems);
|
|
226
|
+
}, [propsSeelctedItems]);
|
|
227
|
+
// Effect to set the input value whenever `value` prop changes
|
|
228
|
+
useEffect(() => {
|
|
229
|
+
setInputValue(value ?? '');
|
|
230
|
+
}, [value]);
|
|
231
|
+
|
|
232
|
+
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
233
|
+
const { value } = e.target;
|
|
234
|
+
// setDropOpen(true);
|
|
235
|
+
setSearchValue(value);
|
|
236
|
+
handleChangeWithDebounce(value);
|
|
237
|
+
if (!value) {
|
|
238
|
+
setInputValue('');
|
|
239
|
+
// onChange({ [descId]: '', [desc]: '' });
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
const handleSuggestionChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
243
|
+
const { value } = e.target;
|
|
244
|
+
setDropOpen(true);
|
|
245
|
+
setSearchValue(value);
|
|
246
|
+
handleChangeWithDebounce(value);
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
const handleClear = () => {
|
|
250
|
+
if (searchValue) {
|
|
251
|
+
setSearchValue('');
|
|
252
|
+
setDropOpen(false);
|
|
253
|
+
} else {
|
|
254
|
+
setInputValue('');
|
|
255
|
+
if (isMultiple) onChange([]);
|
|
256
|
+
else onChange({ [descId]: '', [desc]: '' });
|
|
257
|
+
setDropOpen(false);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
const handleClearSelected = () => {
|
|
262
|
+
setSelectedItems([]);
|
|
263
|
+
if (isMultiple) onChange([]);
|
|
264
|
+
else onChange({ [descId]: '', [desc]: '' });
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
const generateClassName = useCallback(() => {
|
|
268
|
+
return `qbs-textfield-default ${className} ${
|
|
269
|
+
errors && errors?.message ? 'textfield-error' : 'textfield'
|
|
270
|
+
} ${expandable ? 'expandable' : ''}`;
|
|
271
|
+
}, [errors, name]);
|
|
272
|
+
const handleRemoveSelectedItem = (index: number) => {
|
|
273
|
+
setSelectedItems((prev) => {
|
|
274
|
+
return prev.filter((_, i) => i !== index);
|
|
275
|
+
});
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
useEffect(() => {
|
|
279
|
+
if (isInitialRender) {
|
|
280
|
+
setIsInitialRender(false);
|
|
281
|
+
} else {
|
|
282
|
+
onChange(selectedItems);
|
|
283
|
+
}
|
|
284
|
+
}, [selectedItems]);
|
|
285
|
+
|
|
286
|
+
useEffect(() => {
|
|
287
|
+
const handleClickOutside = (event: any) => {
|
|
288
|
+
if (
|
|
289
|
+
dropRef.current &&
|
|
290
|
+
event.target instanceof Node &&
|
|
291
|
+
!dropRef.current.contains(event.target) &&
|
|
292
|
+
event.target.nodeName !== 'svg'
|
|
293
|
+
) {
|
|
294
|
+
setTimeout(() => {
|
|
295
|
+
setDropOpen(false);
|
|
296
|
+
}, 200);
|
|
297
|
+
//setSearchValue("");
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
document.addEventListener('mousedown', handleClickOutside as any);
|
|
301
|
+
window.addEventListener('scroll', handleClickOutside as any);
|
|
302
|
+
|
|
303
|
+
const scrollableDivs = document.querySelectorAll(
|
|
304
|
+
'div[style*="overflow"], .overflow-auto '
|
|
305
|
+
);
|
|
306
|
+
scrollableDivs.forEach((div) =>
|
|
307
|
+
div.addEventListener('scroll', handleClickOutside as any)
|
|
308
|
+
);
|
|
309
|
+
if (scrollRef && scrollRef.current && scrollRef.current !== null) {
|
|
310
|
+
scrollRef.current.addEventListener('scroll', handleClickOutside as any);
|
|
311
|
+
}
|
|
312
|
+
return () => {
|
|
313
|
+
document.removeEventListener('mousedown', handleClickOutside as any);
|
|
314
|
+
window.removeEventListener('scroll', handleClickOutside as any);
|
|
315
|
+
scrollableDivs.forEach((div) =>
|
|
316
|
+
div.removeEventListener('scroll', handleClickOutside as any)
|
|
317
|
+
);
|
|
318
|
+
if (scrollRef && scrollRef.current && scrollRef.current !== null) {
|
|
319
|
+
scrollRef.current.removeEventListener(
|
|
320
|
+
'scroll',
|
|
321
|
+
handleClickOutside as any
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
};
|
|
325
|
+
}, []);
|
|
326
|
+
|
|
327
|
+
// Filtering suggestions based on type and search value
|
|
328
|
+
const selected: any = isMultiple ? selectedItems : inputValue;
|
|
329
|
+
const filteredData: ValueProps[] = filterSuggestions(
|
|
330
|
+
suggestions,
|
|
331
|
+
searchValue,
|
|
332
|
+
type,
|
|
333
|
+
desc,
|
|
334
|
+
selected,
|
|
335
|
+
async,
|
|
336
|
+
false,
|
|
337
|
+
true
|
|
338
|
+
);
|
|
339
|
+
const isSelected = (
|
|
340
|
+
item: ValueProps,
|
|
341
|
+
selectedItems: ValueProps[] | string
|
|
342
|
+
): boolean => {
|
|
343
|
+
if (Array.isArray(selectedItems)) {
|
|
344
|
+
return selectedItems.some(
|
|
345
|
+
(selectedItem) => selectedItem[desc] === item[desc]
|
|
346
|
+
);
|
|
347
|
+
} else {
|
|
348
|
+
return item[desc] === selectedItems;
|
|
349
|
+
}
|
|
350
|
+
};
|
|
351
|
+
|
|
352
|
+
const handleLoadMore = () => {
|
|
353
|
+
if (paginationEnabled) {
|
|
354
|
+
handlePickSuggestions(searchValue, nextPage + 1, true);
|
|
355
|
+
setNextPage(nextPage + 1);
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
const handleOnClick = () => {
|
|
360
|
+
(!disabled && !readOnly && !expandable && !dropOpen) || viewMode
|
|
361
|
+
? setDropOpen(true)
|
|
362
|
+
: '';
|
|
363
|
+
};
|
|
364
|
+
const onInputFocus = () => {
|
|
365
|
+
if (!dropOpen) {
|
|
366
|
+
if (countOnly) {
|
|
367
|
+
setTimeout(() => {
|
|
368
|
+
if (inputSearchRef.current) inputSearchRef.current.focus();
|
|
369
|
+
}, 100);
|
|
370
|
+
} else {
|
|
371
|
+
if (inputRef.current) inputRef.current.focus();
|
|
372
|
+
}
|
|
373
|
+
handleOnClick();
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
const handleShowAllSelected = (enabled: boolean) => {
|
|
378
|
+
setExpandArrowClick(expandArrowClick + 1);
|
|
379
|
+
if (enabled) {
|
|
380
|
+
setShowAllSelected(true);
|
|
381
|
+
} else {
|
|
382
|
+
setShowAllSelected(false);
|
|
383
|
+
}
|
|
384
|
+
};
|
|
385
|
+
|
|
386
|
+
const handleCollapseArrowClick = () => {
|
|
387
|
+
setExpandArrowClick(expandArrowClick + 1);
|
|
388
|
+
setShowAllSelected(false);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
const tooltipContent =
|
|
392
|
+
selectedItems?.length > itemCount
|
|
393
|
+
? selectedItems
|
|
394
|
+
?.slice(itemCount)
|
|
395
|
+
.map((item) => item[desc])
|
|
396
|
+
.join(', ')
|
|
397
|
+
: '';
|
|
398
|
+
|
|
399
|
+
const handleDropOpen = async (e: any) => {
|
|
400
|
+
e.stopPropagation();
|
|
401
|
+
if (!dropOpen) setDropOpen(true);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
const handleDropClose = (e: any) => {
|
|
405
|
+
e.stopPropagation();
|
|
406
|
+
if (dropOpen) setDropOpen(false);
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const handleTabClick = (index: number) => {
|
|
410
|
+
if (activeTab !== index) {
|
|
411
|
+
if (clearTabSwitch) {
|
|
412
|
+
handleClearSelected();
|
|
413
|
+
setSearchValue('');
|
|
414
|
+
setInputValue('');
|
|
415
|
+
handlePickSuggestions('', 1);
|
|
416
|
+
}
|
|
417
|
+
setActiveTab(index);
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
const getSelectedRowLimit = () => {
|
|
422
|
+
return selectedRowLimit * 33 + 5;
|
|
423
|
+
};
|
|
424
|
+
|
|
425
|
+
const getSelectedItems = (dropdown: boolean) => {
|
|
426
|
+
return (
|
|
427
|
+
<div
|
|
428
|
+
className="selected-items-outer-container"
|
|
429
|
+
style={{ maxHeight: `${getSelectedRowLimit()}px` }}
|
|
430
|
+
>
|
|
431
|
+
{selectedItems
|
|
432
|
+
.slice(
|
|
433
|
+
0,
|
|
434
|
+
selectedItems?.length > itemCount
|
|
435
|
+
? showAllSelected
|
|
436
|
+
? selectedItems?.length
|
|
437
|
+
: itemCount
|
|
438
|
+
: selectedItems?.length
|
|
439
|
+
)
|
|
440
|
+
.map((item, index) => (
|
|
441
|
+
<div key={index} className="selected-items-container">
|
|
442
|
+
<Tooltip
|
|
443
|
+
title={item?.[desc]}
|
|
444
|
+
enabled={item?.[desc]?.length > textCount}
|
|
445
|
+
>
|
|
446
|
+
<div key={item.id} className="selected-item">
|
|
447
|
+
{item?.[desc]?.length > textCount
|
|
448
|
+
? `${item?.[desc].substring(0, textCount)}...`
|
|
449
|
+
: item?.[desc]}
|
|
450
|
+
{!viewMode && (
|
|
451
|
+
<button
|
|
452
|
+
onClick={() => handleRemoveSelectedItem(index)}
|
|
453
|
+
className="remove-item-btn"
|
|
454
|
+
aria-label={`Remove ${item?.[desc]}`}
|
|
455
|
+
>
|
|
456
|
+
X
|
|
457
|
+
</button>
|
|
458
|
+
)}
|
|
459
|
+
</div>
|
|
460
|
+
</Tooltip>
|
|
461
|
+
</div>
|
|
462
|
+
))}
|
|
463
|
+
{selectedItems?.length > itemCount && !showAllSelected && (
|
|
464
|
+
<div className="selected-items-container">
|
|
465
|
+
<Tooltip title={tooltipContent} enabled={true}>
|
|
466
|
+
<div
|
|
467
|
+
className={`selected-item-more qbs-rounded-full qbs-min-h-6 qbs-min-w-6 qbs-p-1 ${
|
|
468
|
+
dropdown ? 'qbs-cursor-pointer' : ''
|
|
469
|
+
}`}
|
|
470
|
+
onClick={() => {
|
|
471
|
+
handleShowAllSelected(dropdown);
|
|
472
|
+
}}
|
|
473
|
+
>
|
|
474
|
+
+{selectedItems?.length - itemCount}{' '}
|
|
475
|
+
<span className="qbs-hidden">more</span>
|
|
476
|
+
</div>
|
|
477
|
+
</Tooltip>
|
|
478
|
+
</div>
|
|
479
|
+
)}
|
|
480
|
+
</div>
|
|
481
|
+
);
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
const getTabItems = () => {
|
|
485
|
+
return (
|
|
486
|
+
<ul
|
|
487
|
+
className="qbs-flex qbs-flex-wrap qbs-w-full qbs-tab qbs-mb-2 -qbs-mt-2"
|
|
488
|
+
ref={tabRef}
|
|
489
|
+
>
|
|
490
|
+
{tab.map((item: TabPops, idx: number) => (
|
|
491
|
+
<li className="qbs-flex-1 qbs-tab-items" key={`tab-${idx}`}>
|
|
492
|
+
<span
|
|
493
|
+
className={`qbs-inline-block qbs-tab-item qbs-text-sm qbs-cursor-pointer qbs-w-full qbs-text-center qbs-p-1 qbs-border-b-2 ${
|
|
494
|
+
activeTab === idx ? 'qbs-tab-active-item' : ''
|
|
495
|
+
}`}
|
|
496
|
+
onClick={() => {
|
|
497
|
+
handleTabClick(idx);
|
|
498
|
+
}}
|
|
499
|
+
>
|
|
500
|
+
{item.label}
|
|
501
|
+
</span>
|
|
502
|
+
</li>
|
|
503
|
+
))}
|
|
504
|
+
</ul>
|
|
505
|
+
);
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
return (
|
|
509
|
+
<div className={fullWidth ? 'fullWidth' : 'autoWidth'} ref={dropdownRef}>
|
|
510
|
+
{label && (
|
|
511
|
+
<div
|
|
512
|
+
style={{
|
|
513
|
+
marginBottom: 5,
|
|
514
|
+
display: 'flex',
|
|
515
|
+
justifyContent: 'space-between',
|
|
516
|
+
}}
|
|
517
|
+
>
|
|
518
|
+
<label className={`labels label-text`}>
|
|
519
|
+
{label}
|
|
520
|
+
{required && <span className="text-error"> *</span>}
|
|
521
|
+
</label>
|
|
522
|
+
<span onClick={() => handleAction?.()} className={`action_label`}>
|
|
523
|
+
{actionLabel}
|
|
524
|
+
</span>
|
|
525
|
+
</div>
|
|
526
|
+
)}
|
|
527
|
+
{/* Displaying selected items for multi-select */}
|
|
528
|
+
|
|
529
|
+
<div
|
|
530
|
+
className={`qbs-relative qbs-autocomplete-selected-comp ${
|
|
531
|
+
expandable ? 'qbs-expandable-container' : 'qbs-container'
|
|
532
|
+
}`}
|
|
533
|
+
>
|
|
534
|
+
{selectedItems?.length > 0 && (
|
|
535
|
+
<>
|
|
536
|
+
{!countOnly ? (
|
|
537
|
+
getSelectedItems(false)
|
|
538
|
+
) : (
|
|
539
|
+
<div
|
|
540
|
+
className="selected-items-container qbs-text-sm qbs-gap-1"
|
|
541
|
+
onClick={() => onInputFocus()}
|
|
542
|
+
>
|
|
543
|
+
<span className="badge qbs-rounded-full qbs-text-xs qbs-inline-flex qbs-items-center qbs-justify-center qbs-px-2 qbs-py-1 qbs-leading-none qbs-min-w-6 qbs-min-h-6">
|
|
544
|
+
{selectedItems?.length}
|
|
545
|
+
</span>
|
|
546
|
+
<span className="selected-label-text">
|
|
547
|
+
{selectedLabel && selectedLabel !== '' ? (
|
|
548
|
+
selectedLabel
|
|
549
|
+
) : (
|
|
550
|
+
<>Item{selectedItems?.length > 1 && 's'} Selected</>
|
|
551
|
+
)}
|
|
552
|
+
</span>
|
|
553
|
+
</div>
|
|
554
|
+
)}
|
|
555
|
+
</>
|
|
556
|
+
)}
|
|
557
|
+
|
|
558
|
+
<div
|
|
559
|
+
className={`qbs-textfield-expandable ${
|
|
560
|
+
!expandable ? 'qbs-normal' : ''
|
|
561
|
+
}`}
|
|
562
|
+
data-value={
|
|
563
|
+
selectedItems?.length > 0 || searchValue
|
|
564
|
+
? searchValue
|
|
565
|
+
: placeholder ?? ''
|
|
566
|
+
}
|
|
567
|
+
onClick={() => onInputFocus()}
|
|
568
|
+
>
|
|
569
|
+
<input
|
|
570
|
+
id={id}
|
|
571
|
+
ref={inputRef}
|
|
572
|
+
type="text"
|
|
573
|
+
value={
|
|
574
|
+
type === 'auto_suggestion' && !expandable
|
|
575
|
+
? inputValue
|
|
576
|
+
: searchValue || inputValue
|
|
577
|
+
}
|
|
578
|
+
onChange={handleChange}
|
|
579
|
+
// onBlur={handleBlur}
|
|
580
|
+
onFocus={onFocus}
|
|
581
|
+
onClick={() => handleOnClick()}
|
|
582
|
+
className={generateClassName()}
|
|
583
|
+
placeholder={selectedItems?.length > 0 ? '' : placeholder ?? ''}
|
|
584
|
+
readOnly={
|
|
585
|
+
readOnly ||
|
|
586
|
+
type === 'custom_select' ||
|
|
587
|
+
(type == 'auto_suggestion' && !expandable)
|
|
588
|
+
}
|
|
589
|
+
disabled={disabled}
|
|
590
|
+
data-testid="custom-autocomplete"
|
|
591
|
+
/>
|
|
592
|
+
</div>
|
|
593
|
+
|
|
594
|
+
{/* Icons for Clearing Input or Toggling Dropdown */}
|
|
595
|
+
|
|
596
|
+
<InputActions
|
|
597
|
+
inputValue={inputValue}
|
|
598
|
+
searchValue={searchValue}
|
|
599
|
+
dropOpen={dropOpen}
|
|
600
|
+
handleDropOpen={handleDropOpen}
|
|
601
|
+
handleDropClose={handleDropClose}
|
|
602
|
+
disabled={disabled}
|
|
603
|
+
readOnly={readOnly}
|
|
604
|
+
expandable={expandable}
|
|
605
|
+
handleClear={handleClear}
|
|
606
|
+
countOnly={countOnly}
|
|
607
|
+
viewMode={viewMode}
|
|
608
|
+
/>
|
|
609
|
+
{/* Displaying Loading Spinner */}
|
|
610
|
+
|
|
611
|
+
{/* Suggestions Dropdown */}
|
|
612
|
+
|
|
613
|
+
{dropOpen &&
|
|
614
|
+
ReactDOM.createPortal(
|
|
615
|
+
<div
|
|
616
|
+
ref={dropRef}
|
|
617
|
+
style={{
|
|
618
|
+
...dropdownStyle,
|
|
619
|
+
minHeight: viewMode
|
|
620
|
+
? 160
|
|
621
|
+
: type === 'auto_suggestion'
|
|
622
|
+
? 164
|
|
623
|
+
: 192,
|
|
624
|
+
}}
|
|
625
|
+
className={`qbs-autocomplete-suggestions qbs-autocomplete-selected-suggestions ${
|
|
626
|
+
viewMode ? 'qbs-dropdown-selected-preview' : ''
|
|
627
|
+
} ${viewMode && selectedItems?.length === 0 ? 'hidden' : ''}`}
|
|
628
|
+
>
|
|
629
|
+
{!viewMode && (
|
|
630
|
+
<>
|
|
631
|
+
<>{tab.length > 0 && getTabItems()}</>
|
|
632
|
+
{type == 'auto_suggestion' && !expandable && (
|
|
633
|
+
<div
|
|
634
|
+
style={{ position: 'relative' }}
|
|
635
|
+
className="react-core-ts-search-container"
|
|
636
|
+
>
|
|
637
|
+
<span className="dropdown-search-icon">
|
|
638
|
+
<Search />
|
|
639
|
+
</span>
|
|
640
|
+
<input
|
|
641
|
+
className="dropdown-search-input"
|
|
642
|
+
onChange={handleSuggestionChange}
|
|
643
|
+
value={searchValue}
|
|
644
|
+
placeholder="Search"
|
|
645
|
+
ref={inputSearchRef}
|
|
646
|
+
/>
|
|
647
|
+
</div>
|
|
648
|
+
)}
|
|
649
|
+
</>
|
|
650
|
+
)}
|
|
651
|
+
|
|
652
|
+
<div
|
|
653
|
+
className={`qbs-autocomplete-suggestions-sub ${
|
|
654
|
+
viewMode ? 'hidden' : ''
|
|
655
|
+
}`}
|
|
656
|
+
>
|
|
657
|
+
{filteredData?.length > 0 ? (
|
|
658
|
+
filteredData.map((suggestion: ValueProps, idx: number) => (
|
|
659
|
+
<DropdownList
|
|
660
|
+
idx={idx}
|
|
661
|
+
suggestion={suggestion}
|
|
662
|
+
isSelected={isSelected}
|
|
663
|
+
handleSuggestionClick={handleSuggestionClick}
|
|
664
|
+
handleMultiSelect={handleMultiSelect}
|
|
665
|
+
selected={selected}
|
|
666
|
+
isMultiple={isMultiple}
|
|
667
|
+
singleSelect={singleSelect}
|
|
668
|
+
desc={desc}
|
|
669
|
+
key={suggestion[descId]}
|
|
670
|
+
/>
|
|
671
|
+
))
|
|
672
|
+
) : (
|
|
673
|
+
<>
|
|
674
|
+
{isLoading ||
|
|
675
|
+
(searchValue !== searchOldValue &&
|
|
676
|
+
searchValue !== '' &&
|
|
677
|
+
async) ? (
|
|
678
|
+
<div className="qbs-flex qbs-align-middle qbs-justify-center qbs-min-emp-h">
|
|
679
|
+
<div className="qbs-pt-16">
|
|
680
|
+
<Spinner />
|
|
681
|
+
</div>
|
|
682
|
+
</div>
|
|
683
|
+
) : (
|
|
684
|
+
<div className="qbs-autocomplete-notfound qbs-text-center qbs-justify-center qbs-align-middle qbs-min-emp-h">
|
|
685
|
+
{searchValue !== ''
|
|
686
|
+
? notDataMessage ?? 'No Results Found'
|
|
687
|
+
: initialDataMessage ?? 'Type to search'}
|
|
688
|
+
</div>
|
|
689
|
+
)}
|
|
690
|
+
</>
|
|
691
|
+
)}
|
|
692
|
+
{paginationEnabled &&
|
|
693
|
+
nextBlock !== 0 &&
|
|
694
|
+
nextBlock !== undefined &&
|
|
695
|
+
filteredData?.length > 0 && (
|
|
696
|
+
<div
|
|
697
|
+
className="loadMoreSection"
|
|
698
|
+
onClick={() => handleLoadMore()}
|
|
699
|
+
>
|
|
700
|
+
<p style={{ margin: 2 }}>Load More</p>
|
|
701
|
+
</div>
|
|
702
|
+
)}
|
|
703
|
+
</div>
|
|
704
|
+
<>
|
|
705
|
+
{/* {countOnly && selectedItems?.length > 0 && ( */}
|
|
706
|
+
<>
|
|
707
|
+
<div
|
|
708
|
+
style={{
|
|
709
|
+
minHeight: viewMode ? 160 : 192,
|
|
710
|
+
maxHeight: viewMode ? 160 : 192,
|
|
711
|
+
}}
|
|
712
|
+
className={`qbs-expandable-container qbs-dropdown-selected-container`}
|
|
713
|
+
ref={dropdownSelectedRef}
|
|
714
|
+
>
|
|
715
|
+
{selectedItems?.length > 0 ? (
|
|
716
|
+
<div
|
|
717
|
+
className={`qbs-flex qbs-w-full qbs-text-xs items-center`}
|
|
718
|
+
>
|
|
719
|
+
<div className="qbs-selected-lbs qbs-flex-grow">
|
|
720
|
+
Selected Items
|
|
721
|
+
</div>
|
|
722
|
+
<div
|
|
723
|
+
className={`qbs-clear-link qbs-text-right qbs-cursor-pointer ${
|
|
724
|
+
viewMode ? 'hidden' : ''
|
|
725
|
+
}`}
|
|
726
|
+
onClick={handleClearSelected}
|
|
727
|
+
>
|
|
728
|
+
Clear all
|
|
729
|
+
</div>
|
|
730
|
+
</div>
|
|
731
|
+
) : (
|
|
732
|
+
<div className="w-full flex items-center justify-center">
|
|
733
|
+
{' '}
|
|
734
|
+
No Items Selected
|
|
735
|
+
</div>
|
|
736
|
+
)}
|
|
737
|
+
|
|
738
|
+
{getSelectedItems(true)}
|
|
739
|
+
|
|
740
|
+
<>
|
|
741
|
+
{selectedItems?.length > itemCount &&
|
|
742
|
+
showAllSelected && (
|
|
743
|
+
<div className="qbs-readmore-collapse">
|
|
744
|
+
<div
|
|
745
|
+
className="qbs-more-collapse"
|
|
746
|
+
onClick={() => {
|
|
747
|
+
handleCollapseArrowClick();
|
|
748
|
+
}}
|
|
749
|
+
>
|
|
750
|
+
<DropArrow className={`icon-button-rotate`} />
|
|
751
|
+
</div>
|
|
752
|
+
</div>
|
|
753
|
+
)}
|
|
754
|
+
</>
|
|
755
|
+
</div>
|
|
756
|
+
</>
|
|
757
|
+
{/* )} */}
|
|
758
|
+
</>
|
|
759
|
+
</div>,
|
|
760
|
+
document.body
|
|
761
|
+
)}
|
|
762
|
+
</div>
|
|
763
|
+
|
|
764
|
+
{/* Displaying Validation Error */}
|
|
765
|
+
{errors && (
|
|
766
|
+
<div
|
|
767
|
+
className="text-error text-error-label mt-[1px]"
|
|
768
|
+
data-testid="autocomplete-error"
|
|
769
|
+
>
|
|
770
|
+
{errors.message}
|
|
771
|
+
</div>
|
|
772
|
+
)}
|
|
773
|
+
</div>
|
|
774
|
+
);
|
|
775
|
+
}
|
|
776
|
+
);
|
|
777
|
+
|
|
778
|
+
export default React.memo(AutoCompleteWithSelectedList);
|