react-core-ts 1.5.7 → 1.6.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.
@@ -0,0 +1,892 @@
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { FieldErrors } from 'react-hook-form';
3
+
4
+ import CustomIcons from './components/customIcons';
5
+ import Spinner from './components/loader/Spinner';
6
+ import Portal from './components/portal';
7
+ import { debounce } from './utilities/debounce';
8
+ import { applyPositionClass } from './utilities/getPosition';
9
+ import { DropArrow } from './utilities/icons';
10
+
11
+ type valueProps = {
12
+ id?: string | number;
13
+ name: string;
14
+ label?: string;
15
+ param1?: string | number | null;
16
+ param2?: string | number | null;
17
+ param3?: string | number | null;
18
+ param4?: string | number | null;
19
+ from?: number;
20
+ };
21
+ interface AutoSuggestionInputProps {
22
+ id?: string;
23
+ label?: string;
24
+ fullWidth?: boolean;
25
+ className?: string;
26
+ autoFocus?: boolean;
27
+ required?: boolean;
28
+ shortCode?: string;
29
+ hideClear?: boolean;
30
+ value?: valueProps;
31
+ onChange: (value?: valueProps) => void;
32
+ data?: any[];
33
+ type?: 'custom_select' | 'auto_complete' | 'custom_search_select';
34
+ placeholder?: string;
35
+ getData?: ((key?: string) => Promise<any>) | ((key?: string) => any);
36
+ errors?: FieldErrors;
37
+ name: string;
38
+ readOnly?: boolean;
39
+ disabled?: boolean;
40
+ autoFilter?: boolean;
41
+
42
+ insideOpen?: boolean;
43
+ isClose?: boolean;
44
+ noLocalFilter?: boolean;
45
+ isStaticList?: boolean;
46
+ isCustomPlaceholder?: boolean;
47
+ checkParams?: string[];
48
+ fromPrefix?: boolean;
49
+ hasParentError?: boolean;
50
+ width?: number;
51
+ labelTitle?: string;
52
+ isModern?: boolean;
53
+ autoDropdown?: boolean;
54
+ }
55
+
56
+ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
57
+ label,
58
+ onChange,
59
+
60
+ getData,
61
+ data,
62
+ errors,
63
+ required = false,
64
+ autoFocus,
65
+ name,
66
+ shortCode = '',
67
+ fullWidth,
68
+ placeholder,
69
+ id,
70
+ className: propsClassName,
71
+ type = 'custom_select',
72
+ readOnly,
73
+ disabled = false,
74
+ value,
75
+ autoFilter = false,
76
+ autoDropdown = true,
77
+ insideOpen = false,
78
+ isClose = true,
79
+ noLocalFilter = false,
80
+ isStaticList = false,
81
+ isCustomPlaceholder = false,
82
+ checkParams,
83
+ width,
84
+ hasParentError,
85
+ fromPrefix,
86
+ labelTitle,
87
+ isModern = true,
88
+ }) => {
89
+ const [inputValue, setInputValue] = useState<any>(value?.name ?? '');
90
+ const [isHovered, setIsHovered] = useState<boolean>(false);
91
+ const [isLoading, setIsLoading] = useState<boolean>(false);
92
+ const [dropOpen, setDropOpen] = useState<boolean>(false);
93
+
94
+ const [isDisabled, setIsDisabled] = useState<boolean>(disabled);
95
+ const [showClose, setShowClose] = useState(false);
96
+ const [showToolTip, setShowTooltip] = useState(false);
97
+ const [tooltipIsHovered, setTooltipIsHovered] = useState(false);
98
+ const [suggestions, setSuggestions] = useState<any>([]);
99
+ const inputRef = useRef<HTMLInputElement>(null);
100
+ const adorementRef = useRef<HTMLDivElement>(null);
101
+ const dropdownref = useRef<HTMLDivElement>(null);
102
+ const dropBtnRef = useRef<HTMLButtonElement>(null);
103
+ const timerRef = useRef<number>(0); // To fix the no results found issue on second type
104
+ const [selectedIndex, setSelectedIndex] = useState(0);
105
+ const itemRefs = useRef<(HTMLLIElement | null)[]>([]);
106
+ const scrollContainerRef = useRef<HTMLUListElement | null>(null);
107
+ const [dropPosition, setDropPosition] = useState<any>({
108
+ top: 0,
109
+ left: 0,
110
+ bottom: 0,
111
+ right: 0,
112
+ });
113
+ const checkIncludes = (
114
+ mainString: string,
115
+ subString: string,
116
+ param1?: string | number,
117
+ param2?: string | number,
118
+ param3?: string | number,
119
+ param4?: string | number
120
+ ): boolean => {
121
+ const checkIncludesIfExists = (
122
+ mainString?: string | number,
123
+ substring?: string
124
+ ) => {
125
+ return substring &&
126
+ mainString &&
127
+ typeof mainString === 'string' &&
128
+ typeof subString === 'string'
129
+ ? mainString
130
+ .toString()
131
+ .toLowerCase()
132
+ .startsWith(substring.toString().toLowerCase())
133
+ : false;
134
+ };
135
+ const checkArrayContains = (
136
+ strArray: string[] | undefined,
137
+ param: string
138
+ ): boolean => strArray?.includes(param) ?? false;
139
+
140
+ return (
141
+ checkIncludesIfExists(mainString, subString) ||
142
+ (!!checkParams &&
143
+ ((checkArrayContains(checkParams, 'param1') &&
144
+ checkIncludesIfExists(param1, subString)) ||
145
+ (checkArrayContains(checkParams, 'param2') &&
146
+ checkIncludesIfExists(param2, subString)) ||
147
+ (checkArrayContains(checkParams, 'param3') &&
148
+ checkIncludesIfExists(param3, subString)) ||
149
+ (checkArrayContains(checkParams, 'param4') &&
150
+ checkIncludesIfExists(param4, subString))))
151
+ );
152
+ };
153
+
154
+ const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
155
+ const { value } = event.target;
156
+ timerRef.current = 0;
157
+
158
+ setInputValue(value);
159
+ handleValChange(value);
160
+ if (!value) {
161
+ setInputValue('');
162
+ onChange({ id: undefined, name: '', from: 2 });
163
+ }
164
+ };
165
+
166
+ const handleValChange = useCallback(
167
+ debounce(
168
+ (value: string) => {
169
+ setDropOpen(true);
170
+ onChange({ id: undefined, name: '', from: 1 });
171
+ if (value.trim() === '' && type === 'auto_complete') {
172
+ setSuggestions([]);
173
+ if (autoFilter) {
174
+ handleDropData('*');
175
+ } else {
176
+ setDropOpen(false);
177
+ }
178
+ } else {
179
+ handleDropData(value);
180
+ }
181
+ setTimeout(() => {
182
+ timerRef.current = 1;
183
+ }, 200);
184
+ },
185
+ isStaticList ? 0 : 1000
186
+ ),
187
+ []
188
+ );
189
+ const handleDropData = (value?: string) => {
190
+ if (type === 'auto_complete') {
191
+ if (isStaticList) {
192
+ loadStaticData();
193
+ const filteredData =
194
+ value && value !== '*'
195
+ ? data?.filter((item) =>
196
+ checkIncludes(
197
+ item.name,
198
+ value,
199
+ item.param1,
200
+ item.param2,
201
+ item.param3
202
+ )
203
+ )
204
+ : data;
205
+ setSuggestions(filteredData);
206
+ } else {
207
+ handlePickSuggestions(value);
208
+ }
209
+ } else if (
210
+ (type === 'custom_select' || type === 'custom_search_select') &&
211
+ (!data || data?.length === 0)
212
+ ) {
213
+ handlePickSuggestions();
214
+ } else if (type === 'custom_search_select' && data && data?.length > 0) {
215
+ const filteredData =
216
+ value && value !== '*'
217
+ ? data.filter((item) =>
218
+ checkIncludes(
219
+ item.name,
220
+ value,
221
+ item.param1,
222
+ item.param2,
223
+ item.param3
224
+ )
225
+ )
226
+ : data;
227
+ setSuggestions(filteredData);
228
+ }
229
+ };
230
+ const handlePickSuggestions = async (value?: string) => {
231
+ if (getData) {
232
+ setIsLoading(true);
233
+ try {
234
+ const fetchedSuggestions = await getData?.(value);
235
+ setSuggestions(fetchedSuggestions);
236
+ setIsLoading(false);
237
+ } catch (error) {
238
+ setIsLoading(false);
239
+ }
240
+ }
241
+ };
242
+
243
+ const onLabelClick = () => {
244
+ if (!isDisabled) {
245
+ inputRef?.current?.focus();
246
+ if (autoFilter && inputValue === '') {
247
+ handleValChange('*');
248
+ } else if (
249
+ (type === 'custom_select' || type === 'custom_search_select') &&
250
+ data &&
251
+ data?.length > 0
252
+ ) {
253
+ handleDropData();
254
+ setDropOpen(true);
255
+ }
256
+ }
257
+ };
258
+ const handleClickOutside = (event: MouseEvent) => {
259
+ if (
260
+ dropdownref.current &&
261
+ !dropdownref.current.contains(event.target as Node)
262
+ ) {
263
+ setDropOpen(false);
264
+ }
265
+ };
266
+ const checkIsEmptyField = (): boolean => {
267
+ if (inputValue === undefined) return true;
268
+ else return (inputValue?.toString().length ?? 0) <= 0 ? true : false;
269
+ };
270
+ const loadStaticData = async () => {
271
+ if (!data) {
272
+ data = [];
273
+ if (getData) {
274
+ try {
275
+ setIsLoading(true);
276
+ //handlePickSuggestions('*');
277
+ const fetchedSuggestions = await getData?.('*');
278
+ setSuggestions(fetchedSuggestions);
279
+ setIsLoading(false);
280
+ } catch (error) {
281
+ setIsLoading(false);
282
+ }
283
+ }
284
+ }
285
+ };
286
+ useEffect(() => {
287
+ document.addEventListener('click', handleClickOutside);
288
+ return () => {
289
+ document.removeEventListener('click', handleClickOutside);
290
+ };
291
+ }, []);
292
+
293
+ useEffect(() => {
294
+ if (autoFocus) {
295
+ onLabelClick();
296
+ }
297
+ }, [autoFocus]);
298
+ const onInputFocus = () => {
299
+ if (!isDisabled) {
300
+ if (autoFilter && inputValue === '') {
301
+ handleValChange('*');
302
+ } else if (
303
+ (type === 'custom_select' || type === 'custom_search_select') &&
304
+ data &&
305
+ data?.length > 0
306
+ ) {
307
+ handleDropData();
308
+ //if (insideOpen) setDropOpen(true) // commeted this code bcoz added onclick function inside
309
+ }
310
+ }
311
+ };
312
+ useEffect(() => {
313
+ setIsDisabled(disabled);
314
+ }, [disabled]);
315
+ const handleSuggestionClick = (suggestion: valueProps, index: number) => {
316
+ onChange({
317
+ ...suggestion,
318
+ id: suggestion?.id,
319
+ name: suggestion.name,
320
+ ...(suggestion?.label ? { label: suggestion?.label } : {}),
321
+ });
322
+ if (type !== 'custom_select') setInputValue(suggestion.name);
323
+ setDropOpen(false);
324
+ setSelectedIndex(index);
325
+ };
326
+ const handleOpen = (e: any) => {
327
+ if (!suggestions || suggestions?.length === 0) handleDropData();
328
+ if (!isLoading) {
329
+ setDropOpen(!dropOpen);
330
+ if (type !== 'custom_select') setInputValue('');
331
+ }
332
+ };
333
+
334
+ const handleOpenDropdown = (e: any) => {
335
+ if (!suggestions || suggestions?.length === 0) {
336
+ if (autoDropdown && (inputValue === '' || inputValue.trim() === '')) {
337
+ loadStaticData();
338
+ } else {
339
+ handleDropData()
340
+ }
341
+ };
342
+ if (!isLoading) {
343
+ setDropOpen(!dropOpen);
344
+ }
345
+ };
346
+
347
+ const handleScroll = () => {
348
+ setDropOpen(false);
349
+ };
350
+
351
+ useEffect(() => {
352
+ if (!insideOpen) {
353
+ setSelectedIndex(0);
354
+ window.addEventListener('scroll', handleScroll);
355
+
356
+ const mainElement = document.querySelector('main');
357
+ mainElement?.addEventListener('scroll', handleScroll);
358
+
359
+ const gridElements = document.querySelectorAll(
360
+ '.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto'
361
+ );
362
+ gridElements.forEach((gridElement: any) => {
363
+ gridElement.addEventListener('scroll', handleScroll);
364
+ });
365
+
366
+ window.addEventListener('resize', getDropPosition);
367
+ getDropPosition();
368
+ return () => {
369
+ window.removeEventListener('scroll', handleScroll);
370
+ const mainElement = document.querySelector('main');
371
+ mainElement?.removeEventListener('scroll', handleScroll);
372
+ window.addEventListener('resize', getDropPosition);
373
+ const gridElements = document.querySelectorAll('.k-grid-content');
374
+ gridElements.forEach((gridElement: any) => {
375
+ gridElement.removeEventListener('scroll', handleScroll);
376
+ });
377
+ };
378
+ }
379
+ }, [dropOpen]);
380
+
381
+ const handleClear = () => {
382
+ setDropOpen(false);
383
+ setInputValue('');
384
+ onChange({ id: undefined, name: '', from: 3 });
385
+ onLabelClick();
386
+ };
387
+
388
+ useEffect(() => {
389
+ setInputValue(value?.name ?? '');
390
+ }, [value?.name]);
391
+
392
+ useEffect(() => {
393
+ setSuggestions(data);
394
+ }, [data]);
395
+
396
+ const getErrors = (err: any) => {
397
+ let errMsg = '';
398
+ if (err.message) {
399
+ errMsg = err?.message;
400
+ } else if (err?.id?.message) {
401
+ errMsg = err?.id?.message;
402
+ } else if (err?.name?.message) {
403
+ errMsg = err?.name?.message;
404
+ }
405
+ return errMsg;
406
+ };
407
+ const generateClassName = (
408
+ type: 'input' | 'label' | 'message' | 'adorement'
409
+ ): string => {
410
+ let className = propsClassName;
411
+ switch (type) {
412
+ case 'input':
413
+ className += `block text-common text-input-text font-normal px-3.5 w-full text-sm text-gray-900 bg-transparent border appearance-none peer h-10 rounded-[4px] disabled:text-input-disabled bg-white disabled:bg-disabled ${
414
+ label && isModern
415
+ ? 'placeholder-transparent'
416
+ : 'focus:placeholder-grey-secondary placeholder-input-label'
417
+ } focus:placeholder-grey-secondary`;
418
+
419
+ if (errors && errors[name]) {
420
+ className +=
421
+ ' border-[#FDA29B] focus:border-error-[#FDA29B] focus:ring-[#FDA29B] focus:ring-3 focus:outline-[#FDA29B] input-outline';
422
+ } else {
423
+ className +=
424
+ ' text-grey-dark border-input-light focus:border-blue-navy focus:outline-none focus:ring-0';
425
+ }
426
+
427
+ break;
428
+ case 'label':
429
+ className += ` flex modern-input-label-truncate peer-focus:modern-input-peer-focus-label-size
430
+ ${
431
+ isDisabled
432
+ ? 'cursor-pointer'
433
+ : 'cursor-text peer-focus:cursor-pointer'
434
+ } ${
435
+ isDisabled && !checkIsEmptyField()
436
+ ? 'disabled-input-label-bg'
437
+ : !isDisabled || !checkIsEmptyField()
438
+ ? 'active-input-label-bg'
439
+ : ''
440
+ } absolute duration-300 transform -translate-y-4 top-2 z-1 origin-[0] px-0 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:-translate-y-4 start-[14px] rtl:peer-focus:translate-x-1/4 rtl:peer-focus:left-auto ${
441
+ isDisabled
442
+ ? 'cursor-pointer'
443
+ : 'cursor-text peer-focus:cursor-pointer'
444
+ }
445
+ ${
446
+ checkIsEmptyField()
447
+ ? 'modern-input-label-size'
448
+ : 'modern-input-peer-focus-label-size'
449
+ }`;
450
+ if (errors && errors[name]) {
451
+ className += ' text-error-light ';
452
+ } else {
453
+ className += ' text-grey-dark peer-focus:text-blue-navy';
454
+ }
455
+ break;
456
+ case 'message':
457
+ className = ' text-error-icon ';
458
+ break;
459
+ case 'adorement':
460
+ className += ' absolute right-0 adorement gap-1 flex items-center ';
461
+ break;
462
+ default:
463
+ break;
464
+ }
465
+ return className;
466
+ };
467
+ const handleClose = () => {
468
+ setTimeout(() => {
469
+ setDropOpen(false);
470
+ }, 500);
471
+ };
472
+ const handleClearInputValue = () => {
473
+ // setInputValue(value?.name ?? '')
474
+ };
475
+ const getInnerWidth = () => {
476
+ const innerwidth = adorementRef.current
477
+ ? adorementRef.current.offsetWidth
478
+ : 0;
479
+ return innerwidth;
480
+ };
481
+ // const getPosition = () => {
482
+ // return 'bottom'
483
+ // }
484
+ const filteredData =
485
+ inputValue !== '*' &&
486
+ inputValue !== '' &&
487
+ type !== 'custom_select' &&
488
+ !noLocalFilter
489
+ ? suggestions?.filter((item: valueProps) =>
490
+ checkIncludes(
491
+ item.name,
492
+ inputValue,
493
+ item.param1 ?? '',
494
+ item.param2 ?? '',
495
+ item.param3 ?? '',
496
+ item.param4 ?? ''
497
+ )
498
+ )
499
+ : suggestions;
500
+
501
+ const handleError = (data: any) => {
502
+ if (
503
+ getErrors(data[name]) === 'required' ||
504
+ getErrors(data[name]) === 'Required'
505
+ ) {
506
+ return `${label ?? labelTitle} is ${getErrors(data[name])}`;
507
+ } else {
508
+ return getErrors(data[name]) ?? '';
509
+ }
510
+ };
511
+
512
+ const getDropPosition = (): any => {
513
+ if (!insideOpen && inputRef?.current) {
514
+ const dropdownHeight = 200; // Assume the height of the dropdown is 200px, adjust as needed
515
+
516
+ const inputRect = inputRef.current.getBoundingClientRect();
517
+ const spaceBelow =
518
+ window.innerHeight - (inputRect.bottom + window.scrollY);
519
+ const spaceAbove = inputRect.top + window.scrollY;
520
+
521
+ let top;
522
+ let bottom;
523
+ if (spaceBelow < dropdownHeight && spaceAbove > dropdownHeight) {
524
+ bottom = spaceBelow + 43;
525
+ } else {
526
+ top = inputRect.top + window.scrollY + inputRect.height + 2;
527
+ }
528
+ setDropPosition({
529
+ left: inputRect.left + window.scrollX,
530
+ top,
531
+ bottom,
532
+ width: inputRect.width,
533
+ });
534
+ }
535
+
536
+ return undefined;
537
+ };
538
+
539
+ const [showNoResults, setShowNoResults] = useState(false);
540
+
541
+ useEffect(() => {
542
+ if (
543
+ inputValue &&
544
+ filteredData?.length === 0 &&
545
+ !isLoading &&
546
+ timerRef.current === 1
547
+ ) {
548
+ const timer = setTimeout(() => {
549
+ setShowNoResults(true);
550
+ }, 500); // Delay in milliseconds
551
+ return () => clearTimeout(timer);
552
+ } else {
553
+ setShowNoResults(false);
554
+ }
555
+
556
+ // Handle keyboard navigation
557
+ const handleKeyDown = (e: any) => {
558
+ if (!dropOpen) return;
559
+
560
+ const atBottom = selectedIndex === filteredData.length - 1;
561
+ const atTop = selectedIndex === 0;
562
+
563
+ switch (e.key) {
564
+ case 'ArrowDown':
565
+ e.preventDefault();
566
+ if (itemRefs.current && scrollContainerRef.current) {
567
+ if (!atBottom) {
568
+ scrollContainerRef.current.scrollTop +=
569
+ itemRefs.current[selectedIndex]?.offsetHeight || 50;
570
+ } else {
571
+ scrollContainerRef.current.scrollTop = 0;
572
+ }
573
+ }
574
+ setSelectedIndex((prev) => (prev + 1) % filteredData?.length);
575
+ break;
576
+
577
+ case 'ArrowUp':
578
+ e.preventDefault();
579
+ if (itemRefs.current && scrollContainerRef.current) {
580
+ if (!atTop) {
581
+ scrollContainerRef.current.scrollTop -=
582
+ itemRefs.current[selectedIndex]?.offsetHeight || 50;
583
+ } else {
584
+ scrollContainerRef.current.scrollTop = 0;
585
+ }
586
+ }
587
+ setSelectedIndex(
588
+ (prev) => (prev - 1 + filteredData?.length) % filteredData?.length
589
+ );
590
+ break;
591
+
592
+ case 'Enter':
593
+ e.preventDefault();
594
+ handleSuggestionClick(filteredData[selectedIndex], selectedIndex);
595
+ break;
596
+
597
+ case 'Escape':
598
+ e.preventDefault();
599
+ setDropOpen(false);
600
+ break;
601
+
602
+ default:
603
+ break;
604
+ }
605
+ };
606
+
607
+ if (filteredData?.length > 0 && !isLoading) {
608
+ window.addEventListener('keydown', handleKeyDown);
609
+ return () => {
610
+ window.removeEventListener('keydown', handleKeyDown);
611
+ };
612
+ }
613
+ }, [
614
+ inputValue,
615
+ filteredData,
616
+ isLoading,
617
+ timerRef.current,
618
+ selectedIndex,
619
+ dropOpen,
620
+ ]);
621
+
622
+ const setDropDown = () => {
623
+ return (
624
+ (filteredData?.length > 0 || showNoResults) && (
625
+ <ul
626
+ className="autocomplete-suggections absolute h-auto max-h-40 overflow-auto w-full bg-white shadow-gray-300 shadow-md border border-grey-light py-1.5 z-50 mt-9"
627
+ style={dropPosition}
628
+ ref={scrollContainerRef}
629
+ >
630
+ {filteredData?.length > 0 ? (
631
+ <>
632
+ {filteredData.map((suggestion: any, index: number) => (
633
+ <li
634
+ className={`${
635
+ value?.id === suggestion?.id
636
+ ? 'bg-blue-navy text-white'
637
+ : `${
638
+ index === selectedIndex ? 'is-selected' : ''
639
+ } hover:bg-table-hover`
640
+ } cursor-pointer p-1 text-xxs ps-3.5 pl-[10px] qbs-autocomplete-suggections-items`}
641
+ key={suggestion?.id}
642
+ data-testid={suggestion.name}
643
+ onClick={() => handleSuggestionClick(suggestion, index)}
644
+ tabIndex={index}
645
+ ref={(el) => (itemRefs.current[index] = el)}
646
+ >
647
+ <span>
648
+ {suggestion?.label ? suggestion?.label : suggestion.name}
649
+ </span>
650
+
651
+ {shortCode && suggestion?.[shortCode] && (
652
+ <span className="short-code">
653
+ {suggestion?.[shortCode]}
654
+ </span>
655
+ )}
656
+ </li>
657
+ ))}
658
+ </>
659
+ ) : (
660
+ showNoResults &&
661
+ !isLoading &&
662
+ timerRef.current === 1 && (
663
+ <li
664
+ className={`$ cursor-pointer p-1 rounded-sm text-xxs`}
665
+ onClick={handleClose}
666
+ >
667
+ No Results Found
668
+ </li>
669
+ )
670
+ )}
671
+ </ul>
672
+ )
673
+ );
674
+ };
675
+ const getBorderRight = () => {
676
+ if (fromPrefix) {
677
+ if (
678
+ (hasParentError && Boolean(errors && errors[name])) ||
679
+ hasParentError
680
+ ) {
681
+ return 0;
682
+ } else if (errors && errors[name]) {
683
+ return undefined;
684
+ }
685
+ }
686
+ return 0;
687
+ };
688
+
689
+ useEffect(() => {
690
+ applyPositionClass(dropdownref, isHovered);
691
+ setDropOpen(false);
692
+ }, [isHovered]);
693
+
694
+ useEffect(() => {
695
+ const shouldShowClose =
696
+ value?.name &&
697
+ (value?.id || String(value?.id) === '0') &&
698
+ !disabled &&
699
+ !readOnly &&
700
+ isClose;
701
+ if (showClose !== shouldShowClose) {
702
+ setShowClose(shouldShowClose);
703
+ }
704
+ }, [value, disabled, readOnly]);
705
+ useEffect(() => {
706
+ // Check if input content overflows
707
+ const checkOverflow = () => {
708
+ if (inputRef.current) {
709
+ const { scrollWidth, clientWidth, value } = inputRef.current;
710
+ // Check for overflow only when there's content
711
+ if (value.trim() !== '') {
712
+ setShowTooltip(scrollWidth > clientWidth + 2);
713
+ } else {
714
+ setShowTooltip(false); // No tooltip for empty input
715
+ }
716
+ }
717
+ };
718
+
719
+ if (inputRef.current) {
720
+ inputRef.current.addEventListener('input', checkOverflow);
721
+ checkOverflow(); // Initial check
722
+ }
723
+
724
+ return () => {
725
+ if (inputRef.current) {
726
+ inputRef.current.removeEventListener('input', checkOverflow);
727
+ }
728
+ };
729
+ }, [inputValue]);
730
+
731
+ const handleMouseEnter = () => {
732
+ setTooltipIsHovered(true);
733
+ };
734
+
735
+ const handleMouseLeave = () => {
736
+ setTooltipIsHovered(false);
737
+ };
738
+
739
+ return (
740
+ <div
741
+ id={
742
+ id ? `autocomplete-container-${id}` : `autocomplete-container-${name}`
743
+ }
744
+ className={` flex-grow ${fullWidth ? 'w-full' : 'w-auto'}`}
745
+ ref={dropdownref}
746
+ >
747
+ {label && !isModern && (
748
+ <div className="mb-3">
749
+ <label className={`text-xs font-medium`}>
750
+ {label}
751
+ {required ? <span className="text-error"> *</span> : <></>}
752
+ </label>
753
+ </div>
754
+ )}
755
+ <div className="tooltip-container">
756
+ {isHovered && errors && errors[name] && (
757
+ <span className="tooltip">{handleError(errors)} </span>
758
+ )}
759
+ {tooltipIsHovered && showToolTip && !dropOpen && inputValue && (
760
+ <div className={`tooltip-info`}>{inputValue}</div>
761
+ )}
762
+
763
+ <div
764
+ className={`flex relative ${fullWidth ? 'w-full' : 'w-auto'}`}
765
+ style={{ width: width }}
766
+ >
767
+ <div
768
+ className="relative w-full"
769
+ onMouseEnter={() => handleMouseEnter()}
770
+ onMouseLeave={() => handleMouseLeave()}
771
+ >
772
+ <input
773
+ type="text"
774
+ readOnly={readOnly ?? type === 'custom_select'}
775
+ value={inputValue ? inputValue : ''}
776
+ onBlur={handleClearInputValue}
777
+ autoComplete="off"
778
+ disabled={disabled}
779
+ ref={inputRef}
780
+ id={
781
+ id ? `custom-autocomplete-${id}` : `custom-autocomplete-${name}`
782
+ }
783
+ data-testid="custom-autocomplete"
784
+ // onBlur={() => {
785
+ // setInputValue("")
786
+ // }}
787
+ aria-describedby={id}
788
+ style={{
789
+ paddingRight: getInnerWidth(),
790
+ ...(fromPrefix
791
+ ? {
792
+ borderRight: getBorderRight(),
793
+ borderTopRightRadius: 0,
794
+ borderBottomRightRadius: 0,
795
+ }
796
+ : {}),
797
+ }}
798
+ className={` ${generateClassName('input')}`}
799
+ onChange={handleChange}
800
+ placeholder={
801
+ type === 'auto_complete'
802
+ ? placeholder && isCustomPlaceholder
803
+ ? placeholder
804
+ : 'Type to search'
805
+ : placeholder ?? '--Select--'
806
+ }
807
+ onFocus={onInputFocus}
808
+ onClick={(e) => {
809
+ if (type === 'custom_select') {
810
+ setDropOpen(!dropOpen);
811
+ handleOpen(e);
812
+ } else {
813
+ setDropOpen(!dropOpen);
814
+ }
815
+ }}
816
+ />
817
+ {isModern && (
818
+ <label
819
+ htmlFor={id}
820
+ onClick={() => onLabelClick()}
821
+ className={generateClassName('label')}
822
+ >
823
+ {label ? <span className="truncate">{label}</span> : ''}
824
+ {required ? <span className="text-error"> *</span> : <></>}
825
+ </label>
826
+ )}
827
+ </div>
828
+ <div className="flex items-center justify-center ">
829
+ <div
830
+ ref={adorementRef}
831
+ className={`${generateClassName(
832
+ 'adorement'
833
+ )} qbs-autocomplete-adorement mr-[1px] ${
834
+ isLoading ? 'bg-white' : ''
835
+ }`}
836
+ >
837
+ {showClose && (
838
+ <button
839
+ onClick={() => handleClear()}
840
+ className=" text-table-bodyColor text-[#667085]"
841
+ aria-label="close"
842
+ type="button"
843
+ id="autocomplete-close-icon"
844
+ >
845
+ <CustomIcons name="close" type="large-m" />
846
+ </button>
847
+ )}
848
+ {isLoading && <Spinner />}
849
+ {(type !== 'auto_complete' || autoDropdown) && !disabled && !readOnly && (
850
+ <button
851
+ disabled={disabled ?? readOnly}
852
+ onClick={(e) => handleOpenDropdown(e)}
853
+ onBlur={handleClose}
854
+ className=" text-[#667085] focus-visible:outline-slate-100"
855
+ data-testid="drop-arrow"
856
+ type="button"
857
+ id="autocomplete-drop-icon"
858
+ ref={dropBtnRef}
859
+ >
860
+ {!dropOpen ? (
861
+ <DropArrow uniqueDropArrowId="drop-arrow-icon" />
862
+ ) : (
863
+ <DropArrow
864
+ className="rotate-180"
865
+ uniqueDropArrowId="drop-arrow-icon"
866
+ />
867
+ )}
868
+ </button>
869
+ )}
870
+ {errors && errors[name] && (
871
+ <div
872
+ className={` text-error-label relative cursor-pointer ${generateClassName(
873
+ 'message'
874
+ )}`}
875
+ onMouseEnter={() => setIsHovered(true)}
876
+ onMouseLeave={() => setIsHovered(false)}
877
+ >
878
+ <CustomIcons name="alert" type="medium" />
879
+ </div>
880
+ )}
881
+ </div>
882
+ </div>
883
+ {dropOpen && (!isLoading || filteredData?.length > 0) && (
884
+ <>{insideOpen ? setDropDown() : <Portal>{setDropDown()}</Portal>}</>
885
+ )}
886
+ </div>
887
+ </div>
888
+ </div>
889
+ );
890
+ };
891
+
892
+ export default ModernAutoCompleteDropdown;