react-core-ts 2.0.1 → 2.0.3

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.
@@ -118,6 +118,7 @@ const AutoCompleteWithSelectedList = forwardRef<
118
118
  const [selectAll, setSelectAll] = useState(false);
119
119
  const [refetchData, setRefetchData] = useState(false);
120
120
  const [allDataLoaded, setAllDataLoaded] = useState(false);
121
+ const [isKeyboardOpen, setIsKeyboardOpen] = useState(false);
121
122
 
122
123
  let originalOverflow = '';
123
124
  let hasScrollbar = false;
@@ -198,6 +199,24 @@ const AutoCompleteWithSelectedList = forwardRef<
198
199
  };
199
200
  }, [dropOpen, expandArrowClick]);
200
201
 
202
+ // Detect keyboard open on mobile using Visual Viewport API
203
+ useEffect(() => {
204
+ const vv = (window as any).visualViewport;
205
+ if (!vv) return;
206
+ const onResize = () => {
207
+ // Heuristic: if visual viewport height shrinks a lot, keyboard is likely open
208
+ const open = vv.height < window.innerHeight - 100;
209
+ setIsKeyboardOpen(open);
210
+ };
211
+ vv.addEventListener("resize", onResize);
212
+ vv.addEventListener("scroll", onResize); // iOS sometimes fires scroll instead
213
+ onResize();
214
+ return () => {
215
+ vv.removeEventListener("resize", onResize);
216
+ vv.removeEventListener("scroll", onResize);
217
+ };
218
+ }, []);
219
+
201
220
  const { suggestions, isLoading, handlePickSuggestions, resetSuggections } =
202
221
  useSuggestions(
203
222
  getData,
@@ -363,58 +382,108 @@ const AutoCompleteWithSelectedList = forwardRef<
363
382
  };
364
383
 
365
384
  const uniqueDropArrowId = `${name}-drop-arrow-selected-list-icon`;
385
+ const isKeyboardOpenRef = useRef(false);
386
+
387
+ // Keep ref in sync with state for use in event handlers
388
+ useEffect(() => {
389
+ isKeyboardOpenRef.current = isKeyboardOpen;
390
+ }, [isKeyboardOpen]);
391
+
366
392
  useEffect(() => {
393
+ const handleScroll = (event: any) => {
394
+ // On mobile: Don't close dropdown on scroll when keyboard is open
395
+ // On desktop: Always allow closing on scroll
396
+ if (isKeyboardOpenRef.current) {
397
+ // Only prevent closing if keyboard is actually open (mobile scenario)
398
+ // Also check if input is focused to avoid closing while typing
399
+ const activeElement = document.activeElement;
400
+ if (activeElement && (
401
+ activeElement === inputRef.current ||
402
+ activeElement === inputSearchRef.current ||
403
+ (dropRef.current && dropRef.current.contains(activeElement))
404
+ )) {
405
+ return;
406
+ }
407
+ }
408
+
409
+ // Check if scroll is happening within the dropdown itself - if so, don't close
410
+ const scrollTarget = event.target;
411
+ if (dropRef.current && scrollTarget instanceof Node && dropRef.current.contains(scrollTarget)) {
412
+ return;
413
+ }
414
+
415
+ // On desktop (keyboard not open), close on scroll
416
+ if (dropRef.current && dropOpen) {
417
+ setTimeout(() => {
418
+ setDropOpen(false);
419
+ if (!typeOnlyFetch) setSearchValue('');
420
+ }, 200);
421
+ }
422
+ };
423
+
367
424
  const handleClickOutside = (event: any) => {
425
+ // When keyboard is open, be more lenient - only close on clear outside clicks
426
+ if (isKeyboardOpenRef.current) {
427
+ const target = event.target as HTMLElement;
428
+ // Only close if it's a clear click outside, not on input/textarea elements
429
+ if (
430
+ dropRef.current &&
431
+ target instanceof Node &&
432
+ !dropRef.current.contains(target) &&
433
+ target?.id !== uniqueDropArrowId &&
434
+ event.type === 'mousedown' &&
435
+ target.closest &&
436
+ !target.closest('input') &&
437
+ !target.closest('textarea')
438
+ ) {
439
+ setTimeout(() => {
440
+ setDropOpen(false);
441
+ if (!typeOnlyFetch) setSearchValue('');
442
+ }, 200);
443
+ }
444
+ return;
445
+ }
446
+
447
+ // Normal behavior when keyboard is not open
368
448
  if (
369
449
  dropRef.current &&
370
450
  event.target instanceof Node &&
371
451
  !dropRef.current.contains(event.target) &&
372
- event.target?.id !== uniqueDropArrowId
452
+ (event.target as HTMLElement)?.id !== uniqueDropArrowId
373
453
  ) {
374
454
  setTimeout(() => {
375
455
  setDropOpen(false);
376
456
  if (!typeOnlyFetch) setSearchValue('');
377
457
  }, 200);
378
- //setSearchValue("");
379
458
  }
380
459
  };
381
460
 
382
- // const observer = new MutationObserver(() => {
383
- // adjustDropdownPosition();
384
- // });
385
-
386
- // observer.observe(document.body, {
387
- // childList: true,
388
- // subtree: true,
389
- // attributes: true,
390
- // });
391
-
392
461
  document.addEventListener('mousedown', handleClickOutside as any);
393
- window.addEventListener('scroll', handleClickOutside as any);
462
+ window.addEventListener('scroll', handleScroll as any);
394
463
 
395
464
  const scrollableDivs = document.querySelectorAll(
396
465
  'div[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto'
397
466
  );
398
467
  scrollableDivs.forEach((div) =>
399
- div.addEventListener('scroll', handleClickOutside as any)
468
+ div.addEventListener('scroll', handleScroll as any)
400
469
  );
401
470
  if (scrollRef && scrollRef.current && scrollRef.current !== null) {
402
- scrollRef.current.addEventListener('scroll', handleClickOutside as any);
471
+ scrollRef.current.addEventListener('scroll', handleScroll as any);
403
472
  }
404
473
  return () => {
405
474
  document.removeEventListener('mousedown', handleClickOutside as any);
406
- window.removeEventListener('scroll', handleClickOutside as any);
475
+ window.removeEventListener('scroll', handleScroll as any);
407
476
  scrollableDivs.forEach((div) =>
408
- div.removeEventListener('scroll', handleClickOutside as any)
477
+ div.removeEventListener('scroll', handleScroll as any)
409
478
  );
410
479
  if (scrollRef && scrollRef.current && scrollRef.current !== null) {
411
480
  scrollRef.current.removeEventListener(
412
481
  'scroll',
413
- handleClickOutside as any
482
+ handleScroll as any
414
483
  );
415
484
  }
416
485
  };
417
- }, []);
486
+ }, [dropOpen, typeOnlyFetch, uniqueDropArrowId]);
418
487
 
419
488
  // Filtering suggestions based on type and search value
420
489
  const selected: any = isMultiple ? selectedItems : inputValue;
@@ -758,6 +827,24 @@ const AutoCompleteWithSelectedList = forwardRef<
758
827
  };
759
828
 
760
829
  const handleOpenDropdown = (e: any) => {
830
+
831
+ if (!tabInlineSearch) {
832
+ // Toggle the main dropdown when not using inline search
833
+ if (dropOpen && visible && allDataLoaded) {
834
+ // If dropdown is open and visible, close it
835
+ setDropOpen(false);
836
+ setVisible(false);
837
+ setAllDataLoaded(false);
838
+ return
839
+ } else if (!dropOpen) {
840
+ // If dropdown is closed, open it
841
+ setVisibleDrop();
842
+ } else if (dropOpen && !visible) {
843
+ // If dropdown is open but not visible, make it visible
844
+ setVisible(true);
845
+ }
846
+ }
847
+
761
848
  if (!suggestions || suggestions?.length === 0 || refetchData) {
762
849
  if (autoDropdown && (inputValue === '' || inputValue.trim() === '')) {
763
850
  if (tabInlineSearch && tab.length > 0) {
@@ -834,7 +921,7 @@ const AutoCompleteWithSelectedList = forwardRef<
834
921
  {!countOnly ? (
835
922
  getSelectedItems(false)
836
923
  ) : !tabInlineSearch ? (
837
- <div className="selected-items-counter-container qbs-text-sm qbs-gap-1">
924
+ <div className={`selected-items-counter-container qbs-text-sm qbs-gap-1 ${!tabInlineSearch && autoDropdown ? 'selected-item-nontool-direct-counter' : ''}`}>
838
925
  <Tooltip title={allSelectedTooltipContent} enabled={selectedItems?.length > 0 ? true : false}>
839
926
  <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">
840
927
  {selectedItems?.length}
@@ -865,6 +952,28 @@ const AutoCompleteWithSelectedList = forwardRef<
865
952
  </>
866
953
  )}
867
954
 
955
+ <>
956
+ {autoDropdown && !tabInlineSearch && !disabled && !readOnly && (
957
+ <div className={`qbs-inline-all-dropdown-btn ${!tabInlineSearch && autoDropdown ? 'qbs-inline-all-direct-dropdown-btn' : ''}`}>
958
+ <button
959
+ disabled={disabled ?? readOnly}
960
+ onClick={(e) => handleOpenDropdown(e)}
961
+ className="text-[#667085] focus-visible:outline-slate-100 absolute right-2 qbs-all-dropdown-btn"
962
+ data-testid="drop-arrow"
963
+ type="button"
964
+ id="autocomplete-drop-icon"
965
+ ref={dropBtnRef}
966
+ >
967
+ <AllDropArrow
968
+ type={!allDataLoaded ? 'down' : 'up'}
969
+ uniqueId="all-dropdow-arrow-icon"
970
+ className="all-dropdow-arrow-icon"
971
+ />
972
+ </button>
973
+ </div>
974
+ )}
975
+ </>
976
+
868
977
  <div
869
978
  className={`qbs-textfield-expandable ${
870
979
  !expandable ? 'qbs-normal' : ''
@@ -933,6 +1042,7 @@ const AutoCompleteWithSelectedList = forwardRef<
933
1042
  countOnly={countOnly}
934
1043
  uniqueDropArrowId={uniqueDropArrowId}
935
1044
  viewMode={viewMode}
1045
+ autoDropdown={autoDropdown && !tabInlineSearch ? true : false}
936
1046
  />
937
1047
  {/* Displaying Loading Spinner */}
938
1048
 
@@ -89,6 +89,7 @@ const AutoCompleteWithTabFilter = forwardRef<
89
89
  toolTabClearSwitch = false,
90
90
  onToolTabChange,
91
91
  autoRefreshMainDropdown = true,
92
+ autoTabSelectAll = true
92
93
  },
93
94
  ref
94
95
  ) => {
@@ -113,6 +114,7 @@ const AutoCompleteWithTabFilter = forwardRef<
113
114
  number | undefined
114
115
  >(1);
115
116
  const [visible, setVisible] = useState<boolean>(false);
117
+ const lastEmittedSelectedRef = useRef<ValueProps[] | null>(null);
116
118
  const [activeTab, setActiveTab] = useState<number>(currentTab);
117
119
  const [focusedIndex, setFocusedIndex] = useState(0);
118
120
  const itemRefs = useRef<(HTMLDivElement | null)[]>([]);
@@ -132,10 +134,12 @@ const AutoCompleteWithTabFilter = forwardRef<
132
134
  const [selectAll, setSelectAll] = useState(false);
133
135
  const [refetchData, setRefetchData] = useState(false);
134
136
  const [allDataLoaded, setAllDataLoaded] = useState(false);
137
+ const [isKeyboardOpen, setIsKeyboardOpen] = useState(false);
135
138
  const toolsBtnRef = useRef<HTMLButtonElement>(null);
136
139
  const [showToolsTab, setShowToolsTab] = useState(false);
137
140
  // Track previous tabSelectedItems to detect new items
138
141
  const prevTabSelectedItemsRef = useRef<ValueProps[]>([]);
142
+ const [applyTabFilter, setApplyTabFilter] = useState(false);
139
143
 
140
144
  let originalOverflow = '';
141
145
  let hasScrollbar = false;
@@ -187,6 +191,7 @@ const AutoCompleteWithTabFilter = forwardRef<
187
191
  onChange(suggestion);
188
192
  setDropOpen(false);
189
193
  setShowToolsTab(false);
194
+ setAllDataLoaded(false);
190
195
  }
191
196
  },
192
197
  [tab, activeTab, descId, desc, onChange]
@@ -232,6 +237,14 @@ const AutoCompleteWithTabFilter = forwardRef<
232
237
  }
233
238
  }, [isMultiple, descId, desc, onChange]);
234
239
  useEffect(() => {
240
+ // Avoid feedback loops: if props equal last emitted value, skip syncing to state
241
+ if (
242
+ propsSeelctedItems &&
243
+ lastEmittedSelectedRef.current &&
244
+ deepEqual(propsSeelctedItems, lastEmittedSelectedRef.current)
245
+ ) {
246
+ return;
247
+ }
235
248
  // Only update if different
236
249
  if (!deepEqual(selectedItems, propsSeelctedItems)) {
237
250
  setSelectedItems(propsSeelctedItems);
@@ -263,7 +276,7 @@ const AutoCompleteWithTabFilter = forwardRef<
263
276
  setShowToolsTab(false);
264
277
  }
265
278
  }, [handleChangeWithDebounce, tabInlineSearch, onSearchValueChange, typeOnlyFetch]);
266
-
279
+
267
280
  const handleSuggestionChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
268
281
  const { value } = e.target;
269
282
  //setVisibleDrop();
@@ -276,6 +289,7 @@ const AutoCompleteWithTabFilter = forwardRef<
276
289
  const handleClearSelected = useCallback(() => {
277
290
  setSelectedItems([]);
278
291
  setShowAllSelected(false);
292
+ setShowToolsTab(false);
279
293
  if (searchValue && type === 'auto_suggestion' && tabInlineSearch) {
280
294
  setSearchValue('');
281
295
  }
@@ -295,50 +309,124 @@ const AutoCompleteWithTabFilter = forwardRef<
295
309
  }, []);
296
310
 
297
311
  const uniqueDropArrowId = `${name}-drop-arrow-selected-list-icon`;
312
+ const isKeyboardOpenRef = useRef(false);
313
+
314
+ // Keep ref in sync with state for use in event handlers
298
315
  useEffect(() => {
316
+ isKeyboardOpenRef.current = isKeyboardOpen;
317
+ }, [isKeyboardOpen]);
318
+
319
+ useEffect(() => {
320
+ const handleScroll = (event: any) => {
321
+ // On mobile: Don't close dropdown on scroll when keyboard is open
322
+ // On desktop: Always allow closing on scroll
323
+ if (isKeyboardOpenRef.current) {
324
+ // Only prevent closing if keyboard is actually open (mobile scenario)
325
+ // Also check if input is focused to avoid closing while typing
326
+ const activeElement = document.activeElement;
327
+ if (activeElement && (
328
+ activeElement === inputRef.current ||
329
+ activeElement === inputSearchRef.current ||
330
+ (dropRef.current && dropRef.current.contains(activeElement))
331
+ )) {
332
+ return;
333
+ }
334
+ }
335
+
336
+ // Check if scroll is happening within the dropdown itself - if so, don't close
337
+ const scrollTarget = event.target;
338
+ if (dropRef.current && scrollTarget instanceof Node && dropRef.current.contains(scrollTarget)) {
339
+ return;
340
+ }
341
+
342
+ // On desktop (keyboard not open), close on scroll
343
+ if (dropRef.current && dropOpen) {
344
+ setTimeout(() => {
345
+ setDropOpen(false);
346
+ setShowToolsTab(false);
347
+ setAllDataLoaded(false);
348
+ if (!typeOnlyFetch) setSearchValue('');
349
+ }, 200);
350
+ }
351
+ };
352
+
299
353
  const handleClickOutside = (event: any) => {
300
- if (
301
- dropRef.current &&
302
- event.target instanceof Node &&
303
- !dropRef.current.contains(event.target) &&
304
- event.target?.id !== uniqueDropArrowId &&
305
- !event.target?.closest('.tools-drop-btn')
306
- ) {
354
+ const target = event.target as HTMLElement;
355
+
356
+ // Always check if click is inside component container first
357
+ const insideComponent = dropdownRef.current ? dropdownRef.current.contains(target) : false;
358
+
359
+ // If clicking inside component, don't close (let onClick handlers handle it)
360
+ if (insideComponent) {
361
+ return;
362
+ }
363
+
364
+ // When keyboard is open, be more lenient - only close on clear outside clicks
365
+ if (isKeyboardOpenRef.current) {
366
+ // Only close if it's a clear click outside, not on input/textarea elements
367
+ if (
368
+ dropRef.current &&
369
+ target instanceof Node &&
370
+ !dropRef.current.contains(target) &&
371
+ target?.id !== uniqueDropArrowId &&
372
+ !target?.closest('.tools-drop-btn') &&
373
+ event.type === 'mousedown' &&
374
+ target.closest &&
375
+ !target.closest('input') &&
376
+ !target.closest('textarea')
377
+ ) {
378
+ setTimeout(() => {
379
+ setDropOpen(false);
380
+ setShowToolsTab(false);
381
+ setAllDataLoaded(false);
382
+ if (!typeOnlyFetch) setSearchValue('');
383
+ }, 200);
384
+ }
385
+ return;
386
+ }
387
+
388
+ // Normal behavior when keyboard is not open
389
+ const clickedToolsBtn = !!target?.closest?.('.tools-drop-btn');
390
+ const insideMainDropdown = dropRef.current ? dropRef.current.contains(target) : false;
391
+ const insideAnyDropdown = !!target?.closest?.('.qbs-autocomplete-selected-suggestions');
392
+
393
+ // Close only when click is outside both dropdowns and not on tools button
394
+ if (!insideMainDropdown && !insideAnyDropdown && !clickedToolsBtn) {
307
395
  setTimeout(() => {
308
396
  setDropOpen(false);
309
397
  setShowToolsTab(false);
398
+ setAllDataLoaded(false);
310
399
  if (!typeOnlyFetch) setSearchValue('');
311
400
  }, 200);
312
- //setSearchValue("");
313
401
  }
314
402
  };
315
403
 
316
404
  document.addEventListener('mousedown', handleClickOutside as any);
317
- window.addEventListener('scroll', handleClickOutside as any);
405
+ window.addEventListener('scroll', handleScroll as any);
318
406
 
319
407
  const scrollableDivs = document.querySelectorAll(
320
408
  'div[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto'
321
409
  );
322
410
  scrollableDivs.forEach((div) =>
323
- div.addEventListener('scroll', handleClickOutside as any)
411
+ div.addEventListener('scroll', handleScroll as any)
324
412
  );
325
413
  if (scrollRef && scrollRef.current && scrollRef.current !== null) {
326
- scrollRef.current.addEventListener('scroll', handleClickOutside as any);
414
+ scrollRef.current.addEventListener('scroll', handleScroll as any);
327
415
  }
328
416
  return () => {
329
417
  document.removeEventListener('mousedown', handleClickOutside as any);
330
- window.removeEventListener('scroll', handleClickOutside as any);
418
+ window.removeEventListener('scroll', handleScroll as any);
331
419
  scrollableDivs.forEach((div) =>
332
- div.removeEventListener('scroll', handleClickOutside as any)
420
+ div.removeEventListener('scroll', handleScroll as any)
333
421
  );
334
422
  if (scrollRef && scrollRef.current && scrollRef.current !== null) {
335
423
  scrollRef.current.removeEventListener(
336
424
  'scroll',
337
- handleClickOutside as any
425
+ handleScroll as any
338
426
  );
339
427
  }
340
428
  };
341
- }, []);
429
+ }, [dropOpen, typeOnlyFetch, uniqueDropArrowId]);
342
430
 
343
431
  // Filtering suggestions based on type and search value
344
432
  const selected: any = isMultiple ? selectedItems : inputValue;
@@ -440,11 +528,30 @@ const AutoCompleteWithTabFilter = forwardRef<
440
528
  };
441
529
  }, [adjustDropdownPosition]);
442
530
 
531
+ // Detect keyboard open on mobile using Visual Viewport API
532
+ useEffect(() => {
533
+ const vv = (window as any).visualViewport;
534
+ if (!vv) return;
535
+ const onResize = () => {
536
+ // Heuristic: if visual viewport height shrinks a lot, keyboard is likely open
537
+ const open = vv.height < window.innerHeight - 100;
538
+ setIsKeyboardOpen(open);
539
+ };
540
+ vv.addEventListener("resize", onResize);
541
+ vv.addEventListener("scroll", onResize); // iOS sometimes fires scroll instead
542
+ onResize();
543
+ return () => {
544
+ vv.removeEventListener("resize", onResize);
545
+ vv.removeEventListener("scroll", onResize);
546
+ };
547
+ }, []);
548
+
443
549
  useEffect(() => {
444
550
  if (isInitialRender) {
445
551
  setIsInitialRender(false);
446
552
  } else {
447
553
  onChange(selectedItems);
554
+ lastEmittedSelectedRef.current = selectedItems;
448
555
  }
449
556
  adjustDropdownPosition();
450
557
  setTimeout(() => {
@@ -506,6 +613,7 @@ const AutoCompleteWithTabFilter = forwardRef<
506
613
  case 'Escape':
507
614
  e.preventDefault();
508
615
  setDropOpen(false);
616
+ setAllDataLoaded(false);
509
617
  break;
510
618
 
511
619
  default:
@@ -591,13 +699,21 @@ const AutoCompleteWithTabFilter = forwardRef<
591
699
  .join(', ')
592
700
  : '';
593
701
 
594
- const setVisibleDrop = () => {
702
+ const setVisibleDrop = (skipAnimation = false) => {
595
703
  hasScrollbar = document.body.scrollHeight > window.innerHeight;
596
704
  if (!originalOverflow && !hasScrollbar) {
597
705
  originalOverflow = document.body.style.overflow;
598
706
  document.body.style.overflow = 'hidden';
599
707
  }
600
708
 
709
+ // If skipAnimation is true (dropdown already open but not visible), just make it visible
710
+ if (skipAnimation && dropOpen) {
711
+ setVisible(true);
712
+ setFocusedIndex(0);
713
+ return;
714
+ }
715
+
716
+ // Normal opening animation
601
717
  setVisible(false);
602
718
  if (!dropOpen) {
603
719
  setDropOpen(true);
@@ -612,7 +728,7 @@ const AutoCompleteWithTabFilter = forwardRef<
612
728
  document.body.style.overflow = originalOverflow || '';
613
729
  }
614
730
  originalOverflow = '';
615
- }, 200);
731
+ }, 100);
616
732
  };
617
733
 
618
734
  const handleTabClick = useCallback((index: number) => {
@@ -746,7 +862,7 @@ const AutoCompleteWithTabFilter = forwardRef<
746
862
  // Add only items from current tab - batch all updates in single setState
747
863
  setSelectedItems((prev) => {
748
864
  const newItems: ValueProps[] = [];
749
-
865
+
750
866
  filteredData.forEach((suggestion: ValueProps) => {
751
867
  const isAdded = prev.some(
752
868
  (item) =>
@@ -757,7 +873,7 @@ const AutoCompleteWithTabFilter = forwardRef<
757
873
  newItems.push(suggestion);
758
874
  }
759
875
  });
760
-
876
+
761
877
  return [...prev, ...newItems];
762
878
  });
763
879
  }
@@ -765,6 +881,22 @@ const AutoCompleteWithTabFilter = forwardRef<
765
881
  }, [isMultiple, selectAll, filteredData, descId]);
766
882
 
767
883
  const handleOpenDropdown = useCallback((e: any) => {
884
+ if (!tabInlineSearch) {
885
+ // Toggle the main dropdown when not using inline search
886
+ if (dropOpen && visible && allDataLoaded) {
887
+ // If dropdown is open and visible, close it
888
+ setDropOpen(false);
889
+ setVisible(false);
890
+ setAllDataLoaded(false);
891
+ return
892
+ } else if (!dropOpen) {
893
+ // If dropdown is closed, open it
894
+ setVisibleDrop(false);
895
+ } else if (dropOpen && !visible) {
896
+ // If dropdown is open but not visible, make it visible
897
+ setVisible(true);
898
+ }
899
+ }
768
900
  if (!suggestions || suggestions?.length === 0 || refetchData) {
769
901
  if (autoDropdown && (inputValue === '' || inputValue.trim() === '')) {
770
902
  if (tabInlineSearch && tab.length > 0) {
@@ -788,13 +920,53 @@ const AutoCompleteWithTabFilter = forwardRef<
788
920
  setAllDataLoaded(false);
789
921
  }
790
922
  }
791
- }, [suggestions, refetchData, autoDropdown, inputValue, tabInlineSearch, tab, activeTab, handlePickSuggestions]);
923
+ }, [suggestions, refetchData, autoDropdown, inputValue, tabInlineSearch, tab, activeTab, handlePickSuggestions, dropOpen, visible]);
924
+
925
+ useEffect(() => {
926
+ if (applyTabFilter && !isLoading && suggestions) {
927
+ // Auto select all currently loaded suggestions (dedup by descId)
928
+ if (isMultiple && Array.isArray(suggestions) && autoTabSelectAll) {
929
+ setSelectedItems((prev) => {
930
+ const existingIds = new Set(
931
+ (prev || []).map((item) => getKeyValue(item, descId, 'id'))
932
+ );
933
+ const toAdd: ValueProps[] = [];
934
+ suggestions.forEach((s: ValueProps) => {
935
+ const sid = getKeyValue(s, descId, 'id');
936
+ if (!existingIds.has(sid)) {
937
+ toAdd.push(s);
938
+ }
939
+ });
940
+ return toAdd.length > 0 ? [...prev, ...toAdd] : prev;
941
+ });
942
+ }
943
+
944
+ // Clear tabSelectedItems after applying filter and data is loaded
945
+ onToolTabChange?.([]);
946
+ setShowToolsTab(false);
947
+ // Open dropdown immediately when data is ready (tools tab was open so dropdown is closed)
948
+ if (!dropOpen) {
949
+ setVisibleDrop(false); // Full animation for closed dropdown
950
+ } else if (dropOpen && !visible) {
951
+ // If for some reason dropdown is open but not visible, just make it visible
952
+ setVisible(true);
953
+ }
954
+ setApplyTabFilter(false);
955
+ }
956
+ }, [applyTabFilter, isLoading, suggestions, onToolTabChange, isMultiple, descId, dropOpen, visible]);
792
957
 
793
958
  const handleOpenToolsTab = useCallback((e: any) => {
794
959
  setShowToolsTab(showToolsTab ? false : true);
795
960
  setDropOpen(false);
961
+ setAllDataLoaded(false);
796
962
  }, [showToolsTab]);
797
963
 
964
+ const handleApplyTabFilter = useCallback(() => {
965
+ // Set flag to trigger effect when data loads
966
+ setApplyTabFilter(true);
967
+ handlePickSuggestions(searchValue ? searchValue : '*', 1);
968
+ }, [searchValue, handlePickSuggestions]);
969
+
798
970
  useEffect(() => {
799
971
  const allSelected =
800
972
  filteredData?.length > 0 && selectedItems?.length > 0 &&
@@ -830,14 +1002,14 @@ const AutoCompleteWithTabFilter = forwardRef<
830
1002
  // Check if there are changes by comparing with previous state
831
1003
  const hasChanges = tabSelectedItems.length !== prevTabSelectedItemsRef.current.length ||
832
1004
  !deepEqual(tabSelectedItems, prevTabSelectedItemsRef.current);
833
-
1005
+
834
1006
  // Trigger refresh if there are changes (items added, removed, or modified)
835
1007
  if (hasChanges) {
836
1008
  if (tabInlineSearch && toolTabs.length > 0 && searchValue) {
837
1009
  handlePickSuggestions(searchValue, 1);
838
1010
  }
839
1011
  }
840
-
1012
+
841
1013
  // Update the previous state
842
1014
  prevTabSelectedItemsRef.current = tabSelectedItems;
843
1015
  }
@@ -872,12 +1044,13 @@ const AutoCompleteWithTabFilter = forwardRef<
872
1044
  className={`qbs-relative qbs-autocomplete-selected-comp ${expandable ? 'qbs-expandable-container' : 'qbs-container'
873
1045
  }`}
874
1046
  >
1047
+
875
1048
  {(selectedItems?.length > 0 || !tabInlineSearch) && (
876
1049
  <>
877
1050
  {!countOnly ? (
878
1051
  getSelectedItems(false)
879
1052
  ) : !tabInlineSearch ? (
880
- <div className="selected-items-counter-container qbs-text-sm qbs-gap-1">
1053
+ <div className={`selected-items-counter-container selected-item-inline-counter qbs-text-sm qbs-gap-1 ${!tabInlineSearch && autoDropdown ? 'selected-item-tool-direct-counter' : ''}`}>
881
1054
  <Tooltip title={allSelectedTooltipContent} enabled={selectedItems?.length > 0 ? true : false}>
882
1055
  <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">
883
1056
  {selectedItems?.length}
@@ -907,6 +1080,28 @@ const AutoCompleteWithTabFilter = forwardRef<
907
1080
  </>
908
1081
  )}
909
1082
 
1083
+ <>
1084
+ {autoDropdown && !tabInlineSearch && !disabled && !readOnly && (
1085
+ <div className='qbs-inline-all-dropdown-btn'>
1086
+ <button
1087
+ disabled={disabled ?? readOnly}
1088
+ onClick={(e) => handleOpenDropdown(e)}
1089
+ className="text-[#667085] focus-visible:outline-slate-100 absolute right-2 qbs-all-dropdown-btn"
1090
+ data-testid="drop-arrow"
1091
+ type="button"
1092
+ id="autocomplete-drop-icon"
1093
+ ref={dropBtnRef}
1094
+ >
1095
+ <AllDropArrow
1096
+ type={!allDataLoaded ? 'down' : 'up'}
1097
+ uniqueId="all-dropdow-arrow-icon"
1098
+ className="all-dropdow-arrow-icon"
1099
+ />
1100
+ </button>
1101
+ </div>
1102
+ )}
1103
+ </>
1104
+
910
1105
  <div
911
1106
  className={`qbs-textfield-expandable ${!expandable ? 'qbs-normal' : ''
912
1107
  }`}
@@ -1164,6 +1359,7 @@ const AutoCompleteWithTabFilter = forwardRef<
1164
1359
  }`}
1165
1360
  onClick={() => {
1166
1361
  setDropOpen(false);
1362
+ setAllDataLoaded(false);
1167
1363
  }}
1168
1364
  >
1169
1365
  Done
@@ -1223,6 +1419,8 @@ const AutoCompleteWithTabFilter = forwardRef<
1223
1419
  open={showToolsTab}
1224
1420
  data={tabData}
1225
1421
  enableSelectAll={enableSelectAll}
1422
+ applyTabFilter={handleApplyTabFilter}
1423
+ onToolClose={() => setShowToolsTab(false)}
1226
1424
  />)
1227
1425
  }
1228
1426
  </div>