react-core-ts 2.0.2 → 2.0.4
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 +20 -2
- package/dist/AutoCompleteWithSelectedList.js.map +1 -1
- package/dist/AutoCompleteWithTabFilter.js +199 -41
- package/dist/AutoCompleteWithTabFilter.js.map +1 -1
- package/dist/ReactAutoComplete.d.ts +4 -4
- package/dist/ReactAutoComplete.js +98 -99
- package/dist/ReactAutoComplete.js.map +1 -1
- package/dist/commontypes.d.ts +1 -0
- package/dist/dropdownFilterTabs.d.ts +2 -0
- package/dist/dropdownFilterTabs.js +94 -22
- package/dist/dropdownFilterTabs.js.map +1 -1
- package/dist/dummyAutoCompleteWithSelectedList.js +0 -1
- package/dist/dummyAutoCompleteWithSelectedList.js.map +1 -1
- package/dist/styles/components/autocomplete.css +27 -0
- package/dist/styles/styles/components/autocomplete.css +27 -0
- package/dist/utilities/tooltip.js +0 -1
- package/dist/utilities/tooltip.js.map +1 -1
- package/docs/App.tsx +183 -123
- package/package.json +1 -1
- package/src/AutoCompleteWithSelectedList.tsx +42 -1
- package/src/AutoCompleteWithTabFilter.tsx +222 -24
- package/src/ReactAutoComplete.tsx +135 -135
- package/src/commontypes.ts +1 -0
- package/src/dropdownFilterTabs.tsx +106 -19
- package/src/dummyAutoCompleteWithSelectedList.tsx +0 -1
- package/src/styles/components/autocomplete.css +27 -0
- package/src/utilities/tooltip.tsx +0 -1
|
@@ -24,6 +24,9 @@ const DropdownFilterTabs = forwardRef<
|
|
|
24
24
|
AutoSuggestionInputProps & {
|
|
25
25
|
dropdownRef?: React.RefObject<HTMLDivElement>;
|
|
26
26
|
open?: boolean;
|
|
27
|
+
applyTabFilter?: () => void;
|
|
28
|
+
onToolClose?: () => void;
|
|
29
|
+
|
|
27
30
|
}
|
|
28
31
|
>(
|
|
29
32
|
(
|
|
@@ -81,6 +84,8 @@ const DropdownFilterTabs = forwardRef<
|
|
|
81
84
|
enableSelectAll = false,
|
|
82
85
|
dropdownRef,
|
|
83
86
|
open = false,
|
|
87
|
+
applyTabFilter,
|
|
88
|
+
onToolClose
|
|
84
89
|
},
|
|
85
90
|
ref
|
|
86
91
|
) => {
|
|
@@ -121,6 +126,7 @@ const DropdownFilterTabs = forwardRef<
|
|
|
121
126
|
const [selectAll, setSelectAll] = useState(false);
|
|
122
127
|
const [refetchData, setRefetchData] = useState(false);
|
|
123
128
|
const [allDataLoaded, setAllDataLoaded] = useState(false);
|
|
129
|
+
const [isKeyboardOpen, setIsKeyboardOpen] = useState(false);
|
|
124
130
|
|
|
125
131
|
// Filter selected items based on current active tab
|
|
126
132
|
const currentTabId = tab.length > 0 ? tab[activeTab].id : undefined;
|
|
@@ -128,8 +134,6 @@ const DropdownFilterTabs = forwardRef<
|
|
|
128
134
|
return selectedItems.filter(item => item.tabId === currentTabId);
|
|
129
135
|
}, [selectedItems, currentTabId]);
|
|
130
136
|
|
|
131
|
-
let originalOverflow = '';
|
|
132
|
-
let hasScrollbar = false;
|
|
133
137
|
|
|
134
138
|
useEffect(() => {
|
|
135
139
|
setDropOpen(open);
|
|
@@ -347,10 +351,6 @@ const DropdownFilterTabs = forwardRef<
|
|
|
347
351
|
if (async && type === 'auto_suggestion' && tabInlineSearch) resetSuggections?.();
|
|
348
352
|
};
|
|
349
353
|
|
|
350
|
-
const generateClassName = useCallback(() => {
|
|
351
|
-
return `qbs-textfield-default ${className} ${errors && errors?.message ? 'textfield-error' : 'textfield'
|
|
352
|
-
} ${expandable ? 'expandable' : ''}`;
|
|
353
|
-
}, [errors, name]);
|
|
354
354
|
const handleRemoveSelectedItem = useCallback((index: number) => {
|
|
355
355
|
const itemToRemove = filteredSelectedItems[index];
|
|
356
356
|
setSelectedItems((prev) => {
|
|
@@ -361,48 +361,130 @@ const DropdownFilterTabs = forwardRef<
|
|
|
361
361
|
}, [filteredSelectedItems, descId]);
|
|
362
362
|
|
|
363
363
|
const uniqueDropArrowId = `${name}-drop-arrow-selected-list-icon`;
|
|
364
|
+
const isKeyboardOpenRef = useRef(false);
|
|
365
|
+
|
|
366
|
+
// Keep ref in sync with state for use in event handlers
|
|
367
|
+
useEffect(() => {
|
|
368
|
+
isKeyboardOpenRef.current = isKeyboardOpen;
|
|
369
|
+
}, [isKeyboardOpen]);
|
|
370
|
+
|
|
371
|
+
// Detect keyboard open on mobile using Visual Viewport API
|
|
364
372
|
useEffect(() => {
|
|
373
|
+
const vv = (window as any).visualViewport;
|
|
374
|
+
if (!vv) return;
|
|
375
|
+
const onResize = () => {
|
|
376
|
+
// Heuristic: if visual viewport height shrinks a lot, keyboard is likely open
|
|
377
|
+
const open = vv.height < window.innerHeight - 100;
|
|
378
|
+
setIsKeyboardOpen(open);
|
|
379
|
+
};
|
|
380
|
+
vv.addEventListener("resize", onResize);
|
|
381
|
+
vv.addEventListener("scroll", onResize); // iOS sometimes fires scroll instead
|
|
382
|
+
onResize();
|
|
383
|
+
return () => {
|
|
384
|
+
vv.removeEventListener("resize", onResize);
|
|
385
|
+
vv.removeEventListener("scroll", onResize);
|
|
386
|
+
};
|
|
387
|
+
}, []);
|
|
388
|
+
|
|
389
|
+
useEffect(() => {
|
|
390
|
+
const handleScroll = (event: any) => {
|
|
391
|
+
// On mobile: Don't close dropdown on scroll when keyboard is open
|
|
392
|
+
// On desktop: Always allow closing on scroll
|
|
393
|
+
if (isKeyboardOpenRef.current) {
|
|
394
|
+
// Only prevent closing if keyboard is actually open (mobile scenario)
|
|
395
|
+
// Also check if input is focused to avoid closing while typing
|
|
396
|
+
const activeElement = document.activeElement;
|
|
397
|
+
if (activeElement && (
|
|
398
|
+
activeElement === inputRef.current ||
|
|
399
|
+
activeElement === inputSearchRef.current ||
|
|
400
|
+
(dropRef.current && dropRef.current.contains(activeElement))
|
|
401
|
+
)) {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// Check if scroll is happening within the dropdown itself - if so, don't close
|
|
407
|
+
const scrollTarget = event.target;
|
|
408
|
+
if (dropRef.current && scrollTarget instanceof Node && dropRef.current.contains(scrollTarget)) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// On desktop (keyboard not open), close on scroll
|
|
413
|
+
if (dropRef.current && dropOpen) {
|
|
414
|
+
setTimeout(() => {
|
|
415
|
+
setDropOpen(false);
|
|
416
|
+
onToolClose?.();
|
|
417
|
+
if (!typeOnlyFetch) setSearchValue('');
|
|
418
|
+
}, 200);
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
|
|
365
422
|
const handleClickOutside = (event: any) => {
|
|
423
|
+
const target = event.target as HTMLElement;
|
|
424
|
+
|
|
425
|
+
// When keyboard is open, be more lenient - only close on clear outside clicks
|
|
426
|
+
if (isKeyboardOpenRef.current) {
|
|
427
|
+
// Only close if it's a clear click outside, not on input/textarea elements
|
|
428
|
+
if (
|
|
429
|
+
dropRef.current &&
|
|
430
|
+
target instanceof Node &&
|
|
431
|
+
!dropRef.current.contains(target) &&
|
|
432
|
+
target?.id !== uniqueDropArrowId &&
|
|
433
|
+
event.type === 'mousedown' &&
|
|
434
|
+
target.closest &&
|
|
435
|
+
!target.closest('input') &&
|
|
436
|
+
!target.closest('textarea')
|
|
437
|
+
) {
|
|
438
|
+
setTimeout(() => {
|
|
439
|
+
setDropOpen(false);
|
|
440
|
+
onToolClose?.();
|
|
441
|
+
if (!typeOnlyFetch) setSearchValue('');
|
|
442
|
+
}, 200);
|
|
443
|
+
}
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// Normal behavior when keyboard is not open
|
|
366
448
|
if (
|
|
367
449
|
dropRef.current &&
|
|
368
|
-
|
|
369
|
-
!dropRef.current.contains(
|
|
370
|
-
|
|
450
|
+
target instanceof Node &&
|
|
451
|
+
!dropRef.current.contains(target) &&
|
|
452
|
+
target?.id !== uniqueDropArrowId
|
|
371
453
|
) {
|
|
372
454
|
setTimeout(() => {
|
|
373
455
|
setDropOpen(false);
|
|
456
|
+
onToolClose?.();
|
|
374
457
|
if (!typeOnlyFetch) setSearchValue('');
|
|
375
458
|
}, 200);
|
|
376
|
-
//setSearchValue("");
|
|
377
459
|
}
|
|
378
460
|
};
|
|
379
461
|
|
|
380
462
|
document.addEventListener('mousedown', handleClickOutside as any);
|
|
381
|
-
window.addEventListener('scroll',
|
|
463
|
+
window.addEventListener('scroll', handleScroll as any);
|
|
382
464
|
|
|
383
465
|
const scrollableDivs = document.querySelectorAll(
|
|
384
466
|
'div[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto'
|
|
385
467
|
);
|
|
386
468
|
scrollableDivs.forEach((div) =>
|
|
387
|
-
div.addEventListener('scroll',
|
|
469
|
+
div.addEventListener('scroll', handleScroll as any)
|
|
388
470
|
);
|
|
389
471
|
if (scrollRef && scrollRef.current && scrollRef.current !== null) {
|
|
390
|
-
scrollRef.current.addEventListener('scroll',
|
|
472
|
+
scrollRef.current.addEventListener('scroll', handleScroll as any);
|
|
391
473
|
}
|
|
392
474
|
return () => {
|
|
393
475
|
document.removeEventListener('mousedown', handleClickOutside as any);
|
|
394
|
-
window.removeEventListener('scroll',
|
|
476
|
+
window.removeEventListener('scroll', handleScroll as any);
|
|
395
477
|
scrollableDivs.forEach((div) =>
|
|
396
|
-
div.removeEventListener('scroll',
|
|
478
|
+
div.removeEventListener('scroll', handleScroll as any)
|
|
397
479
|
);
|
|
398
480
|
if (scrollRef && scrollRef.current && scrollRef.current !== null) {
|
|
399
481
|
scrollRef.current.removeEventListener(
|
|
400
482
|
'scroll',
|
|
401
|
-
|
|
483
|
+
handleScroll as any
|
|
402
484
|
);
|
|
403
485
|
}
|
|
404
486
|
};
|
|
405
|
-
}, []);
|
|
487
|
+
}, [dropOpen, typeOnlyFetch, uniqueDropArrowId, onToolClose]);
|
|
406
488
|
|
|
407
489
|
// Filtering suggestions based on type and search value
|
|
408
490
|
const selected: any = isMultiple ? selectedItems : inputValue;
|
|
@@ -745,6 +827,11 @@ const DropdownFilterTabs = forwardRef<
|
|
|
745
827
|
}
|
|
746
828
|
};
|
|
747
829
|
|
|
830
|
+
const handleApplySelected = () => {
|
|
831
|
+
setDropOpen(false);
|
|
832
|
+
applyTabFilter?.();
|
|
833
|
+
};
|
|
834
|
+
|
|
748
835
|
useEffect(() => {
|
|
749
836
|
const allSelected =
|
|
750
837
|
filteredData?.length > 0 && filteredSelectedItems?.length > 0 &&
|
|
@@ -959,10 +1046,10 @@ const DropdownFilterTabs = forwardRef<
|
|
|
959
1046
|
className={`qbs-done-link qbs-text-right qbs-cursor-pointer ${viewMode ? 'hidden' : ''
|
|
960
1047
|
}`}
|
|
961
1048
|
onClick={() => {
|
|
962
|
-
|
|
1049
|
+
handleApplySelected();
|
|
963
1050
|
}}
|
|
964
1051
|
>
|
|
965
|
-
|
|
1052
|
+
Apply
|
|
966
1053
|
</div>
|
|
967
1054
|
</div>
|
|
968
1055
|
|
|
@@ -113,7 +113,6 @@ const AutoCompleteWithSelectedList = forwardRef<
|
|
|
113
113
|
if (tab.length > 0) {
|
|
114
114
|
if (tabRef?.current) dropdownHeight += tabRef?.current?.clientHeight;
|
|
115
115
|
}
|
|
116
|
-
console.log(dropdownHeight);
|
|
117
116
|
if (spaceBelow >= dropdownHeight) {
|
|
118
117
|
dropdownPosition.top =
|
|
119
118
|
inputRect.top + window.scrollY + inputRect.height;
|
|
@@ -382,6 +382,21 @@ ul {
|
|
|
382
382
|
color: #e76458;
|
|
383
383
|
}
|
|
384
384
|
|
|
385
|
+
.qbs-inline-all-dropdown-btn {
|
|
386
|
+
display: flex;
|
|
387
|
+
gap: 12px;
|
|
388
|
+
align-items: center;
|
|
389
|
+
position: absolute;
|
|
390
|
+
right: 25px;
|
|
391
|
+
z-index: 99;
|
|
392
|
+
top: 18px;
|
|
393
|
+
flex-wrap: wrap;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.qbs-inline-all-direct-dropdown-btn {
|
|
397
|
+
right: 0px;
|
|
398
|
+
}
|
|
399
|
+
|
|
385
400
|
.selected-items-container {
|
|
386
401
|
display: flex;
|
|
387
402
|
gap: 12px;
|
|
@@ -416,6 +431,18 @@ ul {
|
|
|
416
431
|
color: #fff;
|
|
417
432
|
}
|
|
418
433
|
|
|
434
|
+
.selected-item-inline-counter {
|
|
435
|
+
right: 30px;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
.selected-item-tool-direct-counter {
|
|
439
|
+
right: 60px;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
.selected-item-nontool-direct-counter {
|
|
443
|
+
right: 35px;
|
|
444
|
+
}
|
|
445
|
+
|
|
419
446
|
.selected-item-more {
|
|
420
447
|
display: flex;
|
|
421
448
|
align-items: center;
|
|
@@ -11,7 +11,6 @@ const ToolTip: React.FC<any> = ({ title, children }) => {
|
|
|
11
11
|
|
|
12
12
|
const spaceAbove = inputBoxRect.top;
|
|
13
13
|
const spaceBelow = viewportHeight - inputBoxRect.bottom;
|
|
14
|
-
console.log(spaceAbove, spaceBelow);
|
|
15
14
|
if (spaceAbove > spaceBelow) {
|
|
16
15
|
if (spaceAbove > 90 && spaceBelow < 120) {
|
|
17
16
|
setDropdownPosition('top-position');
|