react-core-ts 2.1.19 → 2.1.21

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.
@@ -101,6 +101,7 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
101
101
  const inputRef = useRef<HTMLInputElement>(null);
102
102
  const adorementRef = useRef<HTMLDivElement>(null);
103
103
  const dropdownref = useRef<HTMLDivElement>(null);
104
+ const dropdownContentRef = useRef<HTMLDivElement | null>(null);
104
105
  const dropBtnRef = useRef<HTMLButtonElement>(null);
105
106
  const timerRef = useRef<number>(0); // To fix the no results found issue on second type
106
107
  const [selectedIndex, setSelectedIndex] = useState(0);
@@ -359,39 +360,57 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
359
360
  }
360
361
  };
361
362
 
362
- const handleScroll = () => {
363
- setDropOpen(false);
363
+ const handleScroll = (event: any) => {
364
+ const scrollTarget = event.target as Node | null;
365
+
366
+ // Ignore scrolls inside the main autocomplete container or dropdown content
367
+ if (
368
+ scrollTarget &&
369
+ ((dropdownref.current && dropdownref.current.contains(scrollTarget)) ||
370
+ (dropdownContentRef.current &&
371
+ dropdownContentRef.current.contains(scrollTarget)))
372
+ ) {
373
+ return;
374
+ }
375
+
376
+ if (dropOpen) {
377
+ setDropOpen(false);
378
+ }
364
379
  };
365
380
 
366
381
  useEffect(() => {
367
- if (!insideOpen) {
368
- setSelectedIndex(0);
369
- window.addEventListener('scroll', handleScroll);
370
-
371
- const mainElement = document.querySelector('main');
372
- mainElement?.addEventListener('scroll', handleScroll);
373
-
374
- const gridElements = document.querySelectorAll(
375
- '.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto',
376
- );
377
- gridElements.forEach((gridElement: any) => {
378
- gridElement.addEventListener('scroll', handleScroll);
382
+ // Only attach scroll listeners when dropdown is open and rendered in portal
383
+ if (insideOpen || !dropOpen) {
384
+ return;
385
+ }
386
+
387
+ setSelectedIndex(0);
388
+
389
+ const scrollableDivs = document.querySelectorAll(
390
+ 'div[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto',
391
+ );
392
+
393
+ window.addEventListener('scroll', handleScroll);
394
+ document.addEventListener('scroll', handleScroll, true);
395
+
396
+ scrollableDivs.forEach((div) => {
397
+ div.addEventListener('scroll', handleScroll as any);
398
+ });
399
+
400
+ window.addEventListener('resize', getDropPosition);
401
+ getDropPosition();
402
+
403
+ return () => {
404
+ window.removeEventListener('scroll', handleScroll);
405
+ document.removeEventListener('scroll', handleScroll, true);
406
+
407
+ scrollableDivs.forEach((div) => {
408
+ div.removeEventListener('scroll', handleScroll as any);
379
409
  });
380
410
 
381
- window.addEventListener('resize', getDropPosition);
382
- getDropPosition();
383
- return () => {
384
- window.removeEventListener('scroll', handleScroll);
385
- const mainElement = document.querySelector('main');
386
- mainElement?.removeEventListener('scroll', handleScroll);
387
- window.addEventListener('resize', getDropPosition);
388
- const gridElements = document.querySelectorAll('.k-grid-content');
389
- gridElements.forEach((gridElement: any) => {
390
- gridElement.removeEventListener('scroll', handleScroll);
391
- });
392
- };
393
- }
394
- }, [dropOpen]);
411
+ window.removeEventListener('resize', getDropPosition);
412
+ };
413
+ }, [dropOpen, insideOpen]);
395
414
 
396
415
  const handleClear = () => {
397
416
  setDropOpen(false);
@@ -732,6 +751,7 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
732
751
  return (
733
752
  (filteredData?.length > 0 || showNoResults) && (
734
753
  <div
754
+ ref={dropdownContentRef}
735
755
  className="autocomplete-suggections absolute bg-white shadow-gray-300 shadow-md border border-grey-light z-50 mt-9"
736
756
  style={dropPosition}
737
757
  >
@@ -103,6 +103,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
103
103
  const inputRef = useRef<HTMLInputElement>(null);
104
104
  const adorementRef = useRef<HTMLDivElement>(null);
105
105
  const dropdownref = useRef<HTMLDivElement>(null);
106
+ const dropdownContentRef = useRef<HTMLDivElement | null>(null);
106
107
  const dropBtnRef = useRef<HTMLButtonElement>(null);
107
108
  const timerRef = useRef<number>(0); // To fix the no results found issue on second type
108
109
  const [selectedIndex, setSelectedIndex] = useState(0);
@@ -379,39 +380,59 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
379
380
  }
380
381
  };
381
382
 
382
- const handleScroll = () => {
383
- setDropOpen(false);
383
+ const handleScroll = (event: any) => {
384
+ const scrollTarget = event.target as Node | null;
385
+
386
+ // Don't close if the user is scrolling inside the main autocomplete container
387
+ // or inside the dropdown content itself (portal list).
388
+ if (
389
+ scrollTarget &&
390
+ ((dropdownref.current && dropdownref.current.contains(scrollTarget)) ||
391
+ (dropdownContentRef.current &&
392
+ dropdownContentRef.current.contains(scrollTarget)))
393
+ ) {
394
+ return;
395
+ }
396
+
397
+ if (dropOpen) {
398
+ setDropOpen(false);
399
+ }
384
400
  };
385
401
 
386
402
  useEffect(() => {
387
- if (!insideOpen) {
388
- setSelectedIndex(0);
389
- window.addEventListener('scroll', handleScroll);
390
-
391
- const mainElement = document.querySelector('main');
392
- mainElement?.addEventListener('scroll', handleScroll);
393
-
394
- const gridElements = document.querySelectorAll(
395
- '.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto',
396
- );
397
- gridElements.forEach((gridElement: any) => {
398
- gridElement.addEventListener('scroll', handleScroll);
403
+ // Only attach scroll listeners when dropdown is open and rendered in portal
404
+ if (insideOpen || !dropOpen) {
405
+ return;
406
+ }
407
+
408
+ setSelectedIndex(0);
409
+
410
+ const scrollableDivs = document.querySelectorAll(
411
+ 'div[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto',
412
+ );
413
+
414
+ // Listen to window/document scrolls, plus any scrollable divs
415
+ window.addEventListener('scroll', handleScroll);
416
+ document.addEventListener('scroll', handleScroll, true);
417
+
418
+ scrollableDivs.forEach((div) => {
419
+ div.addEventListener('scroll', handleScroll as any);
420
+ });
421
+
422
+ window.addEventListener('resize', getDropPosition);
423
+ getDropPosition();
424
+
425
+ return () => {
426
+ window.removeEventListener('scroll', handleScroll);
427
+ document.removeEventListener('scroll', handleScroll, true);
428
+
429
+ scrollableDivs.forEach((div) => {
430
+ div.removeEventListener('scroll', handleScroll as any);
399
431
  });
400
432
 
401
- window.addEventListener('resize', getDropPosition);
402
- getDropPosition();
403
- return () => {
404
- window.removeEventListener('scroll', handleScroll);
405
- const mainElement = document.querySelector('main');
406
- mainElement?.removeEventListener('scroll', handleScroll);
407
- window.addEventListener('resize', getDropPosition);
408
- const gridElements = document.querySelectorAll('.k-grid-content');
409
- gridElements.forEach((gridElement: any) => {
410
- gridElement.removeEventListener('scroll', handleScroll);
411
- });
412
- };
413
- }
414
- }, [dropOpen]);
433
+ window.removeEventListener('resize', getDropPosition);
434
+ };
435
+ }, [dropOpen, insideOpen]);
415
436
 
416
437
  const handleClear = () => {
417
438
  setDropOpen(false);
@@ -749,6 +770,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
749
770
  return (
750
771
  (filteredData?.length > 0 || showNoResults) && (
751
772
  <div
773
+ ref={dropdownContentRef}
752
774
  style={dropPosition}
753
775
  className="autocomplete-suggections absolute bg-white shadow-gray-300 shadow-md border border-grey-light z-50 mt-9"
754
776
  >
@@ -137,6 +137,7 @@ const ModernAutoCompleteSuggections: React.FC<
137
137
  const inputRef = useRef<HTMLInputElement>(null);
138
138
  const adorementRef = useRef<HTMLDivElement>(null);
139
139
  const containerRef = useRef<HTMLDivElement>(null);
140
+ const dropdownContentRef = useRef<HTMLDivElement | null>(null);
140
141
  const isExternalUpdateRef = useRef(false);
141
142
  const previousDebouncedValueRef = useRef<string>('');
142
143
 
@@ -332,36 +333,52 @@ const ModernAutoCompleteSuggections: React.FC<
332
333
  }
333
334
  };
334
335
 
335
- // Handle scroll to close dropdown
336
- const handleScroll = () => {
336
+ // Handle scroll to close dropdown (only for scrolls outside the component/dropdown)
337
+ const handleScroll = (event: any) => {
338
+ const scrollTarget = event.target as Node | null;
339
+
340
+ if (
341
+ scrollTarget &&
342
+ ((containerRef.current &&
343
+ containerRef.current.contains(scrollTarget)) ||
344
+ (dropdownContentRef.current &&
345
+ dropdownContentRef.current.contains(scrollTarget)))
346
+ ) {
347
+ // Ignore scrolls inside the autocomplete container or the dropdown content
348
+ return;
349
+ }
350
+
337
351
  setShowDropdown(false);
338
352
  };
339
353
 
340
354
  // Attach event listeners for click outside and scroll
341
355
  useEffect(() => {
342
- if (showDropdown) {
343
- document.addEventListener('click', handleClickOutside);
344
- window.addEventListener('scroll', handleScroll);
345
-
346
- const mainElement = document.querySelector('main');
347
- mainElement?.addEventListener('scroll', handleScroll);
348
-
349
- const gridElements = document.querySelectorAll(
350
- '.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto'
351
- );
352
- gridElements.forEach((gridElement: any) => {
353
- gridElement.addEventListener('scroll', handleScroll);
354
- });
355
-
356
- return () => {
357
- document.removeEventListener('click', handleClickOutside);
358
- window.removeEventListener('scroll', handleScroll);
359
- mainElement?.removeEventListener('scroll', handleScroll);
360
- gridElements.forEach((gridElement: any) => {
361
- gridElement.removeEventListener('scroll', handleScroll);
362
- });
363
- };
356
+ if (!showDropdown) {
357
+ return;
364
358
  }
359
+
360
+ document.addEventListener('click', handleClickOutside);
361
+
362
+ const scrollableDivs = document.querySelectorAll(
363
+ 'div[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto'
364
+ );
365
+
366
+ window.addEventListener('scroll', handleScroll);
367
+ document.addEventListener('scroll', handleScroll, true);
368
+
369
+ scrollableDivs.forEach((div) => {
370
+ div.addEventListener('scroll', handleScroll as any);
371
+ });
372
+
373
+ return () => {
374
+ document.removeEventListener('click', handleClickOutside);
375
+ window.removeEventListener('scroll', handleScroll);
376
+ document.removeEventListener('scroll', handleScroll, true);
377
+
378
+ scrollableDivs.forEach((div) => {
379
+ div.removeEventListener('scroll', handleScroll as any);
380
+ });
381
+ };
365
382
  }, [showDropdown]);
366
383
 
367
384
  const checkIsEmptyField = (): boolean => {
@@ -643,7 +660,10 @@ const ModernAutoCompleteSuggections: React.FC<
643
660
  <>
644
661
  {insideOpen ? (
645
662
  <div className="suggection-list">
646
- <div className="bg-white border border-grey-light shadow-gray-300 shadow-md rounded-sm max-h-40 overflow-auto text-[11px] text-gray-700 px-3.5 py-1.5">
663
+ <div
664
+ ref={dropdownContentRef}
665
+ className="bg-white border border-grey-light shadow-gray-300 shadow-md rounded-sm max-h-40 overflow-auto text-[11px] text-gray-700 px-3.5 py-1.5"
666
+ >
647
667
  {effectiveVisible.map((g) => (
648
668
  <SuggestionItem
649
669
  key={g.name}
@@ -657,6 +677,7 @@ const ModernAutoCompleteSuggections: React.FC<
657
677
  ) : (
658
678
  <Portal>
659
679
  <div
680
+ ref={dropdownContentRef}
660
681
  className="autocomplete-suggections autosuggection-list suggection-list bg-white shadow-gray-300 shadow-md border border-grey-light z-50"
661
682
  style={dropPosition}
662
683
  >
@@ -114,6 +114,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
114
114
  const inputRef = useRef<HTMLInputElement>(null);
115
115
  const adorementRef = useRef<HTMLDivElement>(null);
116
116
  const dropdownref = useRef<HTMLDivElement>(null);
117
+ const dropdownContentRef = useRef<HTMLDivElement | null>(null);
117
118
  const dropBtnRef = useRef<HTMLButtonElement>(null);
118
119
  const timerRef = useRef<number>(0); // To fix the no results found issue on second type
119
120
  const [selectedIndex, setSelectedIndex] = useState(0);
@@ -381,39 +382,59 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
381
382
  }
382
383
  };
383
384
 
384
- const handleScroll = () => {
385
- setDropOpen(false);
385
+ const handleScroll = (event: any) => {
386
+ const scrollTarget = event.target as Node | null;
387
+
388
+ // Ignore scrolls that originate from inside the autocomplete container
389
+ // or inside the dropdown content itself.
390
+ if (
391
+ scrollTarget &&
392
+ ((dropdownref.current && dropdownref.current.contains(scrollTarget)) ||
393
+ (dropdownContentRef.current &&
394
+ dropdownContentRef.current.contains(scrollTarget)))
395
+ ) {
396
+ return;
397
+ }
398
+
399
+ if (dropOpen) {
400
+ setDropOpen(false);
401
+ }
386
402
  };
387
403
 
388
404
  useEffect(() => {
389
- if (!insideOpen) {
390
- setSelectedIndex(0);
391
- window.addEventListener('scroll', handleScroll);
405
+ // Only attach scroll listeners when dropdown is open and rendered in portal
406
+ if (insideOpen || !dropOpen) {
407
+ return;
408
+ }
392
409
 
393
- const mainElement = document.querySelector('main');
394
- mainElement?.addEventListener('scroll', handleScroll);
410
+ setSelectedIndex(0);
411
+
412
+ const scrollableDivs = document.querySelectorAll(
413
+ 'div[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto'
414
+ );
395
415
 
396
- const gridElements = document.querySelectorAll(
397
- '.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto'
398
- );
399
- gridElements.forEach((gridElement: any) => {
400
- gridElement.addEventListener('scroll', handleScroll);
416
+ // Listen to window/document scrolls, plus any scrollable divs
417
+ window.addEventListener('scroll', handleScroll);
418
+ document.addEventListener('scroll', handleScroll, true);
419
+
420
+ scrollableDivs.forEach((div) => {
421
+ div.addEventListener('scroll', handleScroll as any);
422
+ });
423
+
424
+ window.addEventListener('resize', getDropPosition);
425
+ getDropPosition();
426
+
427
+ return () => {
428
+ window.removeEventListener('scroll', handleScroll);
429
+ document.removeEventListener('scroll', handleScroll, true);
430
+
431
+ scrollableDivs.forEach((div) => {
432
+ div.removeEventListener('scroll', handleScroll as any);
401
433
  });
402
434
 
403
- window.addEventListener('resize', getDropPosition);
404
- getDropPosition();
405
- return () => {
406
- window.removeEventListener('scroll', handleScroll);
407
- const mainElement = document.querySelector('main');
408
- mainElement?.removeEventListener('scroll', handleScroll);
409
- window.addEventListener('resize', getDropPosition);
410
- const gridElements = document.querySelectorAll('.k-grid-content');
411
- gridElements.forEach((gridElement: any) => {
412
- gridElement.removeEventListener('scroll', handleScroll);
413
- });
414
- };
415
- }
416
- }, [dropOpen]);
435
+ window.removeEventListener('resize', getDropPosition);
436
+ };
437
+ }, [dropOpen, insideOpen]);
417
438
 
418
439
  const handleClear = () => {
419
440
  setDropOpen(false);
@@ -731,6 +752,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
731
752
  return (
732
753
  (filteredData?.length > 0 || showNoResults) && (
733
754
  <div
755
+ ref={dropdownContentRef}
734
756
  style={{ ...dropPosition, overflow: 'hidden' }}
735
757
  className="autocomplete-suggections autocomplete-suggections-tableview absolute bg-white shadow-gray-300 shadow-md border border-grey-light z-50 mt-9"
736
758
  >