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.
@@ -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
+ }
@@ -0,0 +1,8 @@
1
+ @tailwind base;
2
+ @tailwind components;
3
+ @tailwind utilities;
4
+
5
+ @import './components/autocomplete.css';
6
+ @import './components/treedropdown.css';
7
+ @import './components/selectedautocomplete.css';
8
+ @import './components/tooltip.css';
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-core-ts",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "React Components",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -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', 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;
@@ -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
  >
@@ -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;