react-core-ts 2.0.0 → 2.0.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/AutoCompleteWithSelectedList.js +81 -18
- package/dist/AutoCompleteWithSelectedList.js.map +1 -1
- package/dist/AutoCompleteWithTreeStructure.js +3 -3
- package/dist/AutoCompleteWithTreeStructure.js.map +1 -1
- package/dist/commontypes.d.ts +1 -0
- package/dist/styles/styles/components/autocomplete.css +717 -0
- package/dist/styles/styles/components/selectedautocomplete.css +179 -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/docs/App.tsx +5 -4
- package/package.json +1 -1
- package/src/AutoCompleteWithSelectedList.tsx +88 -19
- package/src/AutoCompleteWithTreeStructure.tsx +4 -8
- package/src/commontypes.ts +1 -0
|
@@ -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/docs/App.tsx
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from '../src/index';
|
|
13
13
|
import ModernTextArea from '../src/ReactTextArea';
|
|
14
14
|
import TextField from '../src/ReactTextField';
|
|
15
|
+
import { ValueProps } from '../src/commontypes';
|
|
15
16
|
import { treeDropData } from './store';
|
|
16
17
|
|
|
17
18
|
import '../src/styles/global.css';
|
|
@@ -20,8 +21,8 @@ export default function App() {
|
|
|
20
21
|
const [dropData, setDropData] = useState();
|
|
21
22
|
const [nexBlock, setNexBlock] = useState(1);
|
|
22
23
|
const [prev, setPrev] = useState(1);
|
|
23
|
-
const [selectedTabItems, setSelectedTabItems] = useState([]);
|
|
24
|
-
const [selectedItems, setSelectedItems] = useState([]);
|
|
24
|
+
const [selectedTabItems, setSelectedTabItems] = useState<ValueProps[]>([]);
|
|
25
|
+
const [selectedItems, setSelectedItems] = useState<ValueProps[]>([]);
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
const getData = (keyName?: string, next?: number) => {
|
|
@@ -117,10 +118,10 @@ export default function App() {
|
|
|
117
118
|
itemCount={3}
|
|
118
119
|
placeholder="Auto Suggestion"
|
|
119
120
|
selectedItems={selectedItems}
|
|
120
|
-
onChange={(e) => setSelectedItems(e)}
|
|
121
|
+
onChange={(e) => setSelectedItems(Array.isArray(e) ? e : e ? [e] : [])}
|
|
121
122
|
tabSelectedItems={selectedTabItems}
|
|
122
123
|
getTabData={getDataWithTab}
|
|
123
|
-
onToolTabChange={(value) => setSelectedTabItems(value)}
|
|
124
|
+
onToolTabChange={(value) => setSelectedTabItems(Array.isArray(value) ? value : value ? [value] : [])}
|
|
124
125
|
countOnly={true}
|
|
125
126
|
toolTabClearSwitch={false}
|
|
126
127
|
enableToolsTab={true}
|
package/package.json
CHANGED
|
@@ -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
|
|
366
388
|
useEffect(() => {
|
|
389
|
+
isKeyboardOpenRef.current = isKeyboardOpen;
|
|
390
|
+
}, [isKeyboardOpen]);
|
|
391
|
+
|
|
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',
|
|
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',
|
|
468
|
+
div.addEventListener('scroll', handleScroll as any)
|
|
400
469
|
);
|
|
401
470
|
if (scrollRef && scrollRef.current && scrollRef.current !== null) {
|
|
402
|
-
scrollRef.current.addEventListener('scroll',
|
|
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',
|
|
475
|
+
window.removeEventListener('scroll', handleScroll as any);
|
|
407
476
|
scrollableDivs.forEach((div) =>
|
|
408
|
-
div.removeEventListener('scroll',
|
|
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
|
-
|
|
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;
|
|
@@ -1,11 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
2
|
-
forwardRef,
|
|
3
|
-
useCallback,
|
|
4
|
-
useEffect,
|
|
5
|
-
useImperativeHandle,
|
|
6
|
-
useRef,
|
|
7
|
-
useState,
|
|
8
|
-
} from 'react';
|
|
1
|
+
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
|
|
9
2
|
import ReactDOM from 'react-dom';
|
|
10
3
|
|
|
11
4
|
import { AutoSuggestionInputProps } from './commontypes';
|
|
@@ -73,6 +66,7 @@ const AutoCompleteWithTreeStructure = forwardRef<
|
|
|
73
66
|
inputType = 'text',
|
|
74
67
|
onFocusTreeDropdown,
|
|
75
68
|
filterCondition,
|
|
69
|
+
singleSelectIcon,
|
|
76
70
|
},
|
|
77
71
|
ref
|
|
78
72
|
) => {
|
|
@@ -454,6 +448,7 @@ const AutoCompleteWithTreeStructure = forwardRef<
|
|
|
454
448
|
updateNode={updateNode}
|
|
455
449
|
desc={desc}
|
|
456
450
|
descId={descId}
|
|
451
|
+
singleSelectIcon={singleSelectIcon}
|
|
457
452
|
toggleExpand={toggleExpand}
|
|
458
453
|
>
|
|
459
454
|
{node.expanded &&
|
|
@@ -769,6 +764,7 @@ const AutoCompleteWithTreeStructure = forwardRef<
|
|
|
769
764
|
hasDisableSelection={hasDisableSelection?.(suggestion)}
|
|
770
765
|
updateNode={updateNode}
|
|
771
766
|
desc={desc}
|
|
767
|
+
singleSelectIcon={singleSelectIcon}
|
|
772
768
|
descId={descId}
|
|
773
769
|
toggleExpand={toggleExpand}
|
|
774
770
|
>
|
package/src/commontypes.ts
CHANGED
|
@@ -97,6 +97,7 @@ export interface AutoSuggestionInputProps {
|
|
|
97
97
|
toolTabClearSwitch?: boolean;
|
|
98
98
|
onToolTabChange?: (value?: ValueProps | ValueProps[]) => void;
|
|
99
99
|
autoRefreshMainDropdown?: boolean;
|
|
100
|
+
singleSelectIcon?: any;
|
|
100
101
|
}
|
|
101
102
|
export interface IconsProps {
|
|
102
103
|
name: any;
|