react-core-ts 2.1.1 → 2.1.2
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/AutoComplete.js +26 -8
- package/dist/AutoComplete.js.map +1 -1
- package/dist/ReactAutoComplete.js +42 -5
- package/dist/ReactAutoComplete.js.map +1 -1
- package/dist/ReactAutoCompleteDropdown.js +42 -5
- package/dist/ReactAutoCompleteDropdown.js.map +1 -1
- package/dist/styles/styles/components/autocomplete.css +744 -0
- package/dist/styles/styles/components/selectedautocomplete.css +221 -0
- package/dist/styles/styles/components/tooltip.css +497 -0
- package/dist/styles/styles/components/treedropdown.css +97 -0
- package/dist/styles/styles/global.css +8 -0
- package/package.json +1 -1
- package/src/AutoComplete.tsx +45 -13
- package/src/ReactAutoComplete.tsx +47 -4
- package/src/ReactAutoCompleteDropdown.tsx +48 -4
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
.qbs-tree-list-container {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
}
|
|
5
|
+
.qbs-tree-list-container-sub {
|
|
6
|
+
display: flex;
|
|
7
|
+
flex-direction: row;
|
|
8
|
+
align-items: flex-start;
|
|
9
|
+
gap: 7px;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.qbs-tree-list-container-sub .no-children {
|
|
13
|
+
margin-left: 1.75rem; /* Corresponds to ml-7 in Tailwind */
|
|
14
|
+
}
|
|
15
|
+
.qbs-tree-list-container-sub-icon {
|
|
16
|
+
margin-top: 0.25rem; /* Corresponds to mt-1 in Tailwind */
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
padding-top: 0.5rem; /* Corresponds to py-2 in Tailwind */
|
|
19
|
+
padding-bottom: 0.5rem;
|
|
20
|
+
transition: transform 0.3s ease; /* Smooth rotation transition */
|
|
21
|
+
color: #003c71;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.qbs-tree-list-container-sub-icon.expanded {
|
|
25
|
+
transform: rotate(90deg); /* Corresponds to rotate-90 in Tailwind */
|
|
26
|
+
}
|
|
27
|
+
.qbs-tree-list-container-sub-container {
|
|
28
|
+
display: flex;
|
|
29
|
+
gap: 15px; /* Corresponds to gap-2 in Tailwind */
|
|
30
|
+
padding: 0.5rem; /* Corresponds to p-2 in Tailwind */
|
|
31
|
+
flex-direction: row; /* Corresponds to flex-row in Tailwind */
|
|
32
|
+
width: 100%; /* Corresponds to w-full in Tailwind */
|
|
33
|
+
color: #3d414a;
|
|
34
|
+
}
|
|
35
|
+
.qbs-tree-list-container-sub-container-hideicon {
|
|
36
|
+
display: flex;
|
|
37
|
+
gap: 6px; /* Corresponds to gap-2 in Tailwind */
|
|
38
|
+
padding: 0.5rem; /* Corresponds to p-2 in Tailwind */
|
|
39
|
+
flex-direction: row; /* Corresponds to flex-row in Tailwind */
|
|
40
|
+
width: 100%; /* Corresponds to w-full in Tailwind */
|
|
41
|
+
color: #3d414a;
|
|
42
|
+
}
|
|
43
|
+
.qbs-tree-list-container-sub-container-hideicon:hover {
|
|
44
|
+
color: #003c71;
|
|
45
|
+
background-color: rgba(141, 194, 240, 0.15) !important;
|
|
46
|
+
}
|
|
47
|
+
.qbs-tree-list-container-sub-container:hover {
|
|
48
|
+
color: #003c71;
|
|
49
|
+
background-color: rgba(141, 194, 240, 0.15) !important;
|
|
50
|
+
}
|
|
51
|
+
.qbs-tree-list-container-sub-container.qbs-expanded-child {
|
|
52
|
+
color: #003c71;
|
|
53
|
+
}
|
|
54
|
+
.qbs-tree-list-container-sub-text.qbs-expanded-child {
|
|
55
|
+
color: #003c71;
|
|
56
|
+
}
|
|
57
|
+
.qbs-tree-list-container-sub-text:hover {
|
|
58
|
+
color: #003c71;
|
|
59
|
+
/* background-color: rgba(141, 194, 240, 0.15) !important; */
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.qbs-tree-list-container-sub-container.checked,
|
|
63
|
+
.qbs-tree-list-container-sub-container-hideicon.checked {
|
|
64
|
+
color: #003c71;
|
|
65
|
+
background-color: rgba(
|
|
66
|
+
141,
|
|
67
|
+
194,
|
|
68
|
+
240,
|
|
69
|
+
0.15
|
|
70
|
+
) !important; /* Corresponds to bg-green-200 in Tailwind */
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.marginLeft {
|
|
74
|
+
margin-left: 28px; /* Corresponds to ml-2 in Tailwind */
|
|
75
|
+
}
|
|
76
|
+
.lightmarginLeft {
|
|
77
|
+
margin-left: 19px; /* Corresponds to ml-2 in Tailwind */
|
|
78
|
+
}
|
|
79
|
+
.qbs-tree-list-container-sub- {
|
|
80
|
+
line-height: 18px; /* Corresponds to leading-[18px] in Tailwind */
|
|
81
|
+
font-size: 0.875rem; /* Corresponds to text-sm in Tailwind (14px) */
|
|
82
|
+
}
|
|
83
|
+
.qbs-tree-list-container-child {
|
|
84
|
+
margin-left: 1rem; /* Corresponds to ml-4 in Tailwind */
|
|
85
|
+
margin-top: 0.5rem; /* Corresponds to mt-2 in Tailwind */
|
|
86
|
+
display: flex; /* Corresponds to flex in Tailwind */
|
|
87
|
+
flex-direction: column; /* Corresponds to flex-col in Tailwind */
|
|
88
|
+
gap: 0.5rem; /* Corresponds to gap-2 in Tailwind */
|
|
89
|
+
}
|
|
90
|
+
.qbs-tree-list-container-sub-text {
|
|
91
|
+
line-height: 18px; /* Corresponds to leading-[18px] in Tailwind */
|
|
92
|
+
font-size: 14px; /* Corresponds to text-sm in Tailwind (14px) */
|
|
93
|
+
font-weight: 500;
|
|
94
|
+
letter-spacing: 0.28px;
|
|
95
|
+
font-family: 'Noto Sans';
|
|
96
|
+
/* color: #3d414a; */
|
|
97
|
+
}
|
package/package.json
CHANGED
package/src/AutoComplete.tsx
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useRef,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react';
|
|
2
9
|
|
|
3
10
|
import { AutoSuggestionInputProps } from './commontypes';
|
|
4
11
|
import { useSuggestions } from './utilities/autosuggestions';
|
|
@@ -43,7 +50,7 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoSuggestionInputProps>(
|
|
|
43
50
|
notDataMessage,
|
|
44
51
|
onFocus,
|
|
45
52
|
},
|
|
46
|
-
ref
|
|
53
|
+
ref,
|
|
47
54
|
) => {
|
|
48
55
|
const dropdownRef = useRef<HTMLDivElement>(null);
|
|
49
56
|
// State Hooks Section
|
|
@@ -94,16 +101,17 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoSuggestionInputProps>(
|
|
|
94
101
|
inputValue,
|
|
95
102
|
isMultiple,
|
|
96
103
|
setNextPage,
|
|
97
|
-
selectedItems
|
|
104
|
+
selectedItems,
|
|
98
105
|
// nextBlock
|
|
99
106
|
);
|
|
100
107
|
|
|
101
108
|
// Handling the selection of a suggestion
|
|
102
109
|
const handleSuggestionClick = useCallback((suggestion: ValueProps) => {
|
|
110
|
+
isSelectingRef.current = true;
|
|
103
111
|
if (isMultiple) {
|
|
104
112
|
setSelectedItems((prev) => {
|
|
105
113
|
const isAdded = prev.some(
|
|
106
|
-
(item) => item[descId] === suggestion[descId]
|
|
114
|
+
(item) => item[descId] === suggestion[descId],
|
|
107
115
|
);
|
|
108
116
|
if (isAdded) {
|
|
109
117
|
return prev.filter((item) => item[descId] !== suggestion[descId]);
|
|
@@ -134,7 +142,7 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoSuggestionInputProps>(
|
|
|
134
142
|
} else {
|
|
135
143
|
setSelectedItems((prev) => {
|
|
136
144
|
return prev.filter(
|
|
137
|
-
(item, i) => item[descId] !== suggestion[descId]
|
|
145
|
+
(item, i) => item[descId] !== suggestion[descId],
|
|
138
146
|
);
|
|
139
147
|
});
|
|
140
148
|
}
|
|
@@ -156,7 +164,15 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoSuggestionInputProps>(
|
|
|
156
164
|
setInputValue(value ?? '');
|
|
157
165
|
}, [value]);
|
|
158
166
|
|
|
167
|
+
const isSelectingRef = useRef(false);
|
|
168
|
+
|
|
159
169
|
const selectExactMatchFromSuggestions = () => {
|
|
170
|
+
// If user is clicking on dropdown, don't execute exact match logic
|
|
171
|
+
if (isSelectingRef.current) {
|
|
172
|
+
isSelectingRef.current = false;
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
160
176
|
if (!inputValue) {
|
|
161
177
|
return;
|
|
162
178
|
}
|
|
@@ -260,15 +276,15 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoSuggestionInputProps>(
|
|
|
260
276
|
type,
|
|
261
277
|
desc,
|
|
262
278
|
selected,
|
|
263
|
-
async
|
|
279
|
+
async,
|
|
264
280
|
);
|
|
265
281
|
const isSelected = (
|
|
266
282
|
item: ValueProps,
|
|
267
|
-
selectedItems: ValueProps[] | string
|
|
283
|
+
selectedItems: ValueProps[] | string,
|
|
268
284
|
): boolean => {
|
|
269
285
|
if (Array.isArray(selectedItems)) {
|
|
270
286
|
return selectedItems.some(
|
|
271
|
-
(selectedItem) => selectedItem[desc] === item[desc]
|
|
287
|
+
(selectedItem) => selectedItem[desc] === item[desc],
|
|
272
288
|
);
|
|
273
289
|
} else {
|
|
274
290
|
return item[desc] === selectedItems;
|
|
@@ -353,14 +369,26 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoSuggestionInputProps>(
|
|
|
353
369
|
: searchValue || inputValue
|
|
354
370
|
}
|
|
355
371
|
onChange={handleChange}
|
|
356
|
-
onBlur={() => {
|
|
357
|
-
|
|
358
|
-
|
|
372
|
+
onBlur={(e) => {
|
|
373
|
+
// Delay to allow click events on dropdown to process first
|
|
374
|
+
setTimeout(() => {
|
|
375
|
+
// Check if focus moved to dropdown or if user is selecting
|
|
376
|
+
const relatedTarget = e.relatedTarget as Node;
|
|
377
|
+
if (
|
|
378
|
+
dropdownRef.current &&
|
|
379
|
+
relatedTarget &&
|
|
380
|
+
dropdownRef.current.contains(relatedTarget)
|
|
381
|
+
) {
|
|
382
|
+
return; // Focus moved to dropdown, don't execute exact match
|
|
383
|
+
}
|
|
384
|
+
handleBlur();
|
|
385
|
+
selectExactMatchFromSuggestions();
|
|
386
|
+
}, 200);
|
|
359
387
|
}}
|
|
360
388
|
onFocus={onFocus}
|
|
361
389
|
onClick={() => handleOnClick()}
|
|
362
390
|
className={generateClassName()}
|
|
363
|
-
placeholder={selectedItems?.length > 0 ? '' : placeholder ?? ''}
|
|
391
|
+
placeholder={selectedItems?.length > 0 ? '' : (placeholder ?? '')}
|
|
364
392
|
readOnly={
|
|
365
393
|
readOnly || type === 'custom_select' || type == 'auto_suggestion'
|
|
366
394
|
}
|
|
@@ -469,6 +497,10 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoSuggestionInputProps>(
|
|
|
469
497
|
className={`qbs-autocomplete-suggestions-item ${
|
|
470
498
|
isSelected(suggestion, selected) ? 'is-selected' : ''
|
|
471
499
|
}`}
|
|
500
|
+
onMouseDown={(e) => {
|
|
501
|
+
e.preventDefault(); // Prevent input blur before click
|
|
502
|
+
isSelectingRef.current = true;
|
|
503
|
+
}}
|
|
472
504
|
onClick={() => handleSuggestionClick(suggestion)}
|
|
473
505
|
data-testid={suggestion[desc]}
|
|
474
506
|
>
|
|
@@ -523,7 +555,7 @@ const AutoComplete = forwardRef<HTMLInputElement, AutoSuggestionInputProps>(
|
|
|
523
555
|
)}
|
|
524
556
|
</div>
|
|
525
557
|
);
|
|
526
|
-
}
|
|
558
|
+
},
|
|
527
559
|
);
|
|
528
560
|
|
|
529
561
|
export default React.memo(AutoComplete);
|
|
@@ -106,6 +106,7 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
|
|
|
106
106
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
107
107
|
const itemRefs = useRef<(HTMLLIElement | null)[]>([]);
|
|
108
108
|
const scrollContainerRef = useRef<HTMLUListElement | null>(null);
|
|
109
|
+
const isSelectingRef = useRef(false);
|
|
109
110
|
const [dropPosition, setDropPosition] = useState<any>({
|
|
110
111
|
top: 0,
|
|
111
112
|
left: 0,
|
|
@@ -329,6 +330,7 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
|
|
|
329
330
|
setIsDisabled(disabled);
|
|
330
331
|
}, [disabled]);
|
|
331
332
|
const handleSuggestionClick = (suggestion: valueProps, index: number) => {
|
|
333
|
+
isSelectingRef.current = true;
|
|
332
334
|
onChange({
|
|
333
335
|
...suggestion,
|
|
334
336
|
id: suggestion?.id,
|
|
@@ -338,6 +340,10 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
|
|
|
338
340
|
if (type !== 'custom_select') setInputValue(suggestion.name);
|
|
339
341
|
setDropOpen(false);
|
|
340
342
|
setSelectedIndex(index);
|
|
343
|
+
// Reset flag after a short delay to allow blur handler to check it
|
|
344
|
+
setTimeout(() => {
|
|
345
|
+
isSelectingRef.current = false;
|
|
346
|
+
}, 100);
|
|
341
347
|
};
|
|
342
348
|
const handleOpen = (e: any) => {
|
|
343
349
|
if (!suggestions || suggestions?.length === 0) {
|
|
@@ -490,6 +496,12 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
|
|
|
490
496
|
// return 'bottom'
|
|
491
497
|
// }
|
|
492
498
|
const selectExactMatchFromSuggestions = () => {
|
|
499
|
+
// If user is clicking on dropdown, don't execute exact match logic
|
|
500
|
+
if (isSelectingRef.current) {
|
|
501
|
+
isSelectingRef.current = false;
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
|
|
493
505
|
if (!inputValue) {
|
|
494
506
|
return;
|
|
495
507
|
}
|
|
@@ -630,7 +642,18 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
|
|
|
630
642
|
|
|
631
643
|
case 'Enter':
|
|
632
644
|
e.preventDefault();
|
|
633
|
-
|
|
645
|
+
if (filteredData[selectedIndex]) {
|
|
646
|
+
handleSuggestionClick(filteredData[selectedIndex], selectedIndex);
|
|
647
|
+
}
|
|
648
|
+
break;
|
|
649
|
+
|
|
650
|
+
case 'Tab':
|
|
651
|
+
// Tab should select highlighted item if dropdown is open
|
|
652
|
+
if (filteredData[selectedIndex]) {
|
|
653
|
+
isSelectingRef.current = true;
|
|
654
|
+
handleSuggestionClick(filteredData[selectedIndex], selectedIndex);
|
|
655
|
+
// Don't prevent default - allow Tab to move focus
|
|
656
|
+
}
|
|
634
657
|
break;
|
|
635
658
|
|
|
636
659
|
case 'Escape':
|
|
@@ -682,6 +705,10 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
|
|
|
682
705
|
} cursor-pointer p-1 text-xxs ps-3.5 pl-[10px] qbs-autocomplete-suggections-items`}
|
|
683
706
|
key={suggestion?.id}
|
|
684
707
|
data-testid={suggestion.name}
|
|
708
|
+
onMouseDown={(e) => {
|
|
709
|
+
e.preventDefault(); // Prevent input blur before click
|
|
710
|
+
isSelectingRef.current = true;
|
|
711
|
+
}}
|
|
685
712
|
onClick={() => handleSuggestionClick(suggestion, index)}
|
|
686
713
|
tabIndex={index}
|
|
687
714
|
ref={(el) => (itemRefs.current[index] = el)}
|
|
@@ -821,9 +848,25 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
|
|
|
821
848
|
type="text"
|
|
822
849
|
readOnly={readOnly ?? type === 'custom_select'}
|
|
823
850
|
value={inputValue ? inputValue : ''}
|
|
824
|
-
onBlur={() => {
|
|
825
|
-
|
|
826
|
-
|
|
851
|
+
onBlur={(e) => {
|
|
852
|
+
// Check immediately if user is selecting (Tab or click)
|
|
853
|
+
const wasSelecting = isSelectingRef.current;
|
|
854
|
+
|
|
855
|
+
// Delay to allow click events on dropdown to process first
|
|
856
|
+
setTimeout(() => {
|
|
857
|
+
// Check if focus moved to dropdown or if user is selecting
|
|
858
|
+
const relatedTarget = e.relatedTarget as Node;
|
|
859
|
+
if (
|
|
860
|
+
wasSelecting ||
|
|
861
|
+
(dropdownref.current &&
|
|
862
|
+
relatedTarget &&
|
|
863
|
+
dropdownref.current.contains(relatedTarget))
|
|
864
|
+
) {
|
|
865
|
+
return; // User selected an item or focus moved to dropdown, don't execute exact match
|
|
866
|
+
}
|
|
867
|
+
handleClearInputValue();
|
|
868
|
+
selectExactMatchFromSuggestions();
|
|
869
|
+
}, 200);
|
|
827
870
|
}}
|
|
828
871
|
autoComplete="off"
|
|
829
872
|
disabled={disabled}
|
|
@@ -109,6 +109,8 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
|
|
|
109
109
|
const itemRefs = useRef<(HTMLLIElement | null)[]>([]);
|
|
110
110
|
const scrollContainerRef = useRef<HTMLUListElement | null>(null);
|
|
111
111
|
const [refetchData, setRefetchData] = useState(false);
|
|
112
|
+
|
|
113
|
+
const isSelectingRef = useRef(false);
|
|
112
114
|
const [dropPosition, setDropPosition] = useState<any>({
|
|
113
115
|
top: 0,
|
|
114
116
|
left: 0,
|
|
@@ -337,6 +339,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
|
|
|
337
339
|
setIsDisabled(disabled);
|
|
338
340
|
}, [disabled]);
|
|
339
341
|
const handleSuggestionClick = (suggestion: valueProps, index: number) => {
|
|
342
|
+
isSelectingRef.current = true;
|
|
340
343
|
onChange({
|
|
341
344
|
...suggestion,
|
|
342
345
|
id: suggestion?.id,
|
|
@@ -346,6 +349,10 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
|
|
|
346
349
|
if (type !== 'custom_select') setInputValue(suggestion.name);
|
|
347
350
|
setDropOpen(false);
|
|
348
351
|
setSelectedIndex(index);
|
|
352
|
+
// Reset flag after a short delay to allow blur handler to check it
|
|
353
|
+
setTimeout(() => {
|
|
354
|
+
isSelectingRef.current = false;
|
|
355
|
+
}, 100);
|
|
349
356
|
};
|
|
350
357
|
const handleOpen = (e: any) => {
|
|
351
358
|
if (!suggestions || suggestions?.length === 0) handleDropData();
|
|
@@ -512,6 +519,12 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
|
|
|
512
519
|
// return 'bottom'
|
|
513
520
|
// }
|
|
514
521
|
const selectExactMatchFromSuggestions = () => {
|
|
522
|
+
// If user is clicking on dropdown, don't execute exact match logic
|
|
523
|
+
if (isSelectingRef.current) {
|
|
524
|
+
isSelectingRef.current = false;
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
|
|
515
528
|
if (!inputValue) {
|
|
516
529
|
return;
|
|
517
530
|
}
|
|
@@ -652,7 +665,18 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
|
|
|
652
665
|
|
|
653
666
|
case 'Enter':
|
|
654
667
|
e.preventDefault();
|
|
655
|
-
|
|
668
|
+
if (filteredData[selectedIndex]) {
|
|
669
|
+
handleSuggestionClick(filteredData[selectedIndex], selectedIndex);
|
|
670
|
+
}
|
|
671
|
+
break;
|
|
672
|
+
|
|
673
|
+
case 'Tab':
|
|
674
|
+
// Tab should select highlighted item if dropdown is open
|
|
675
|
+
if (filteredData[selectedIndex]) {
|
|
676
|
+
isSelectingRef.current = true;
|
|
677
|
+
handleSuggestionClick(filteredData[selectedIndex], selectedIndex);
|
|
678
|
+
// Don't prevent default - allow Tab to move focus
|
|
679
|
+
}
|
|
656
680
|
break;
|
|
657
681
|
|
|
658
682
|
case 'Escape':
|
|
@@ -704,6 +728,10 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
|
|
|
704
728
|
} cursor-pointer p-1 text-xxs ps-3.5 pl-[10px] qbs-autocomplete-suggections-items`}
|
|
705
729
|
key={suggestion?.id}
|
|
706
730
|
data-testid={suggestion.name}
|
|
731
|
+
onMouseDown={(e) => {
|
|
732
|
+
e.preventDefault(); // Prevent input blur before click
|
|
733
|
+
isSelectingRef.current = true;
|
|
734
|
+
}}
|
|
707
735
|
onClick={() => handleSuggestionClick(suggestion, index)}
|
|
708
736
|
tabIndex={index}
|
|
709
737
|
ref={(el) => (itemRefs.current[index] = el)}
|
|
@@ -844,9 +872,25 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
|
|
|
844
872
|
type="text"
|
|
845
873
|
readOnly={readOnly ?? type === 'custom_select'}
|
|
846
874
|
value={inputValue ? inputValue : ''}
|
|
847
|
-
onBlur={() => {
|
|
848
|
-
|
|
849
|
-
|
|
875
|
+
onBlur={(e) => {
|
|
876
|
+
// Check immediately if user is selecting (Tab or click)
|
|
877
|
+
const wasSelecting = isSelectingRef.current;
|
|
878
|
+
|
|
879
|
+
// Delay to allow click events on dropdown to process first
|
|
880
|
+
setTimeout(() => {
|
|
881
|
+
// Check if focus moved to dropdown or if user is selecting
|
|
882
|
+
const relatedTarget = e.relatedTarget as Node;
|
|
883
|
+
if (
|
|
884
|
+
wasSelecting ||
|
|
885
|
+
(dropdownref.current &&
|
|
886
|
+
relatedTarget &&
|
|
887
|
+
dropdownref.current.contains(relatedTarget))
|
|
888
|
+
) {
|
|
889
|
+
return; // User selected an item or focus moved to dropdown, don't execute exact match
|
|
890
|
+
}
|
|
891
|
+
handleClearInputValue();
|
|
892
|
+
selectExactMatchFromSuggestions();
|
|
893
|
+
}, 200);
|
|
850
894
|
}}
|
|
851
895
|
autoComplete="off"
|
|
852
896
|
disabled={disabled}
|