react-core-ts 2.0.24 → 2.1.1

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.
@@ -489,6 +489,33 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
489
489
  // const getPosition = () => {
490
490
  // return 'bottom'
491
491
  // }
492
+ const selectExactMatchFromSuggestions = () => {
493
+ if (!inputValue) {
494
+ return;
495
+ }
496
+
497
+ if (!filteredData || filteredData.length === 0) {
498
+ // No suggestions to match against – notify parent with raw value
499
+ onChange({ id: undefined, name: inputValue, from: 4 });
500
+ return;
501
+ }
502
+
503
+ const normalizedInput = inputValue.toString().trim().toLowerCase();
504
+ const matchIndex = filteredData.findIndex((item: valueProps) => {
505
+ const name = item?.name?.toString().trim().toLowerCase();
506
+ const label = item?.label?.toString().trim().toLowerCase();
507
+ return name === normalizedInput || label === normalizedInput;
508
+ });
509
+
510
+ if (matchIndex >= 0) {
511
+ const match = filteredData[matchIndex];
512
+ handleSuggestionClick(match, matchIndex);
513
+ } else {
514
+ // No exact match – notify parent with typed value
515
+ onChange({ id: undefined, name: inputValue, from: 4 });
516
+ setInputValue('');
517
+ }
518
+ };
492
519
  const filteredData =
493
520
  inputValue !== '*' &&
494
521
  inputValue !== '' &&
@@ -794,7 +821,10 @@ const ModernAutoComplete: React.FC<AutoSuggestionInputProps> = ({
794
821
  type="text"
795
822
  readOnly={readOnly ?? type === 'custom_select'}
796
823
  value={inputValue ? inputValue : ''}
797
- onBlur={handleClearInputValue}
824
+ onBlur={() => {
825
+ handleClearInputValue();
826
+ selectExactMatchFromSuggestions();
827
+ }}
798
828
  autoComplete="off"
799
829
  disabled={disabled}
800
830
  ref={inputRef}
@@ -88,7 +88,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
88
88
  fromPrefix,
89
89
  labelTitle,
90
90
  isModern = true,
91
- size = 'md'
91
+ size = 'md',
92
92
  }) => {
93
93
  const [inputValue, setInputValue] = useState<any>(value?.name ?? '');
94
94
  const [isHovered, setIsHovered] = useState<boolean>(false);
@@ -121,11 +121,11 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
121
121
  param1?: string | number,
122
122
  param2?: string | number,
123
123
  param3?: string | number,
124
- param4?: string | number
124
+ param4?: string | number,
125
125
  ): boolean => {
126
126
  const checkIncludesIfExists = (
127
127
  mainString?: string | number,
128
- substring?: string
128
+ substring?: string,
129
129
  ) => {
130
130
  return substring &&
131
131
  mainString &&
@@ -139,7 +139,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
139
139
  };
140
140
  const checkArrayContains = (
141
141
  strArray: string[] | undefined,
142
- param: string
142
+ param: string,
143
143
  ): boolean => strArray?.includes(param) ?? false;
144
144
 
145
145
  return (
@@ -196,9 +196,9 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
196
196
  timerRef.current = 1;
197
197
  }, 200);
198
198
  },
199
- isStaticList ? 0 : 1000
199
+ isStaticList ? 0 : 1000,
200
200
  ),
201
- []
201
+ [],
202
202
  );
203
203
  const handleDropData = (value?: string) => {
204
204
  if (type === 'auto_complete') {
@@ -212,8 +212,8 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
212
212
  value,
213
213
  item.param1,
214
214
  item.param2,
215
- item.param3
216
- )
215
+ item.param3,
216
+ ),
217
217
  )
218
218
  : data;
219
219
  setSuggestions(filteredData);
@@ -234,8 +234,8 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
234
234
  value,
235
235
  item.param1,
236
236
  item.param2,
237
- item.param3
238
- )
237
+ item.param3,
238
+ ),
239
239
  )
240
240
  : data;
241
241
  setSuggestions(filteredData);
@@ -382,7 +382,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
382
382
  mainElement?.addEventListener('scroll', handleScroll);
383
383
 
384
384
  const gridElements = document.querySelectorAll(
385
- '.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto'
385
+ '.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto',
386
386
  );
387
387
  gridElements.forEach((gridElement: any) => {
388
388
  gridElement.addEventListener('scroll', handleScroll);
@@ -433,7 +433,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
433
433
  return errMsg;
434
434
  };
435
435
  const generateClassName = (
436
- type: 'input' | 'label' | 'message' | 'adorement'
436
+ type: 'input' | 'label' | 'message' | 'adorement',
437
437
  ): string => {
438
438
  let className = propsClassName;
439
439
  switch (type) {
@@ -452,7 +452,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
452
452
  ' text-grey-dark border-input-light focus:border-blue-navy focus:outline-none focus:ring-0';
453
453
  }
454
454
 
455
- className += getHeight()
455
+ className += getHeight();
456
456
 
457
457
  break;
458
458
  case 'label':
@@ -462,16 +462,16 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
462
462
  ? 'cursor-pointer'
463
463
  : 'cursor-text peer-focus:cursor-pointer'
464
464
  } ${
465
- isDisabled && !checkIsEmptyField()
466
- ? 'disabled-input-label-bg'
467
- : !isDisabled || !checkIsEmptyField()
468
- ? 'active-input-label-bg'
469
- : ''
470
- } absolute duration-300 transform -translate-y-4 top-2 z-1 origin-[0] px-0 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:-translate-y-4 start-[14px] rtl:peer-focus:translate-x-1/4 rtl:peer-focus:left-auto ${
471
- isDisabled
472
- ? 'cursor-pointer'
473
- : 'cursor-text peer-focus:cursor-pointer'
474
- }
465
+ isDisabled && !checkIsEmptyField()
466
+ ? 'disabled-input-label-bg'
467
+ : !isDisabled || !checkIsEmptyField()
468
+ ? 'active-input-label-bg'
469
+ : ''
470
+ } absolute duration-300 transform -translate-y-4 top-2 z-1 origin-[0] px-0 peer-placeholder-shown:-translate-y-1/2 peer-placeholder-shown:top-1/2 peer-focus:top-2 peer-focus:-translate-y-4 start-[14px] rtl:peer-focus:translate-x-1/4 rtl:peer-focus:left-auto ${
471
+ isDisabled
472
+ ? 'cursor-pointer'
473
+ : 'cursor-text peer-focus:cursor-pointer'
474
+ }
475
475
  ${
476
476
  checkIsEmptyField()
477
477
  ? 'modern-input-label-size'
@@ -511,6 +511,33 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
511
511
  // const getPosition = () => {
512
512
  // return 'bottom'
513
513
  // }
514
+ const selectExactMatchFromSuggestions = () => {
515
+ if (!inputValue) {
516
+ return;
517
+ }
518
+
519
+ if (!filteredData || filteredData.length === 0) {
520
+ // No suggestions to match against – notify parent with raw value
521
+ onChange({ id: undefined, name: inputValue, from: 4 });
522
+ return;
523
+ }
524
+
525
+ const normalizedInput = inputValue.toString().trim().toLowerCase();
526
+ const matchIndex = filteredData.findIndex((item: valueProps) => {
527
+ const name = item?.name?.toString().trim().toLowerCase();
528
+ const label = item?.label?.toString().trim().toLowerCase();
529
+ return name === normalizedInput || label === normalizedInput;
530
+ });
531
+
532
+ if (matchIndex >= 0) {
533
+ const match = filteredData[matchIndex];
534
+ handleSuggestionClick(match, matchIndex);
535
+ } else {
536
+ // No exact match – notify parent with typed value
537
+ onChange({ id: undefined, name: inputValue, from: 4 });
538
+ setInputValue('');
539
+ }
540
+ };
514
541
  const filteredData =
515
542
  inputValue !== '*' &&
516
543
  inputValue !== '' &&
@@ -523,8 +550,8 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
523
550
  item.param1 ?? '',
524
551
  item.param2 ?? '',
525
552
  item.param3 ?? '',
526
- item.param4 ?? ''
527
- )
553
+ item.param4 ?? '',
554
+ ),
528
555
  )
529
556
  : suggestions;
530
557
 
@@ -586,34 +613,34 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
586
613
  // Handle keyboard navigation
587
614
  const handleKeyDown = (e: KeyboardEvent) => {
588
615
  if (!dropOpen) return;
589
-
616
+
590
617
  const nextIndex =
591
618
  e.key === 'ArrowDown'
592
619
  ? (selectedIndex + 1) % filteredData.length
593
620
  : e.key === 'ArrowUp'
594
- ? (selectedIndex - 1 + filteredData.length) % filteredData.length
595
- : selectedIndex;
596
-
621
+ ? (selectedIndex - 1 + filteredData.length) % filteredData.length
622
+ : selectedIndex;
623
+
597
624
  switch (e.key) {
598
625
  case 'ArrowDown':
599
626
  case 'ArrowUp':
600
627
  e.preventDefault();
601
-
628
+
602
629
  // Update index first
603
630
  setSelectedIndex(nextIndex);
604
-
631
+
605
632
  // Wait for DOM update before scrolling
606
633
  requestAnimationFrame(() => {
607
634
  const el = itemRefs.current[nextIndex];
608
635
  const container = scrollContainerRef.current;
609
-
636
+
610
637
  if (el && container) {
611
638
  const elTop = el.offsetTop;
612
639
  const elBottom = elTop + el.offsetHeight;
613
-
640
+
614
641
  const containerTop = container.scrollTop;
615
642
  const containerBottom = containerTop + container.clientHeight;
616
-
643
+
617
644
  if (elBottom > containerBottom) {
618
645
  container.scrollTop = elBottom - container.clientHeight;
619
646
  } else if (elTop < containerTop) {
@@ -622,21 +649,21 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
622
649
  }
623
650
  });
624
651
  break;
625
-
652
+
626
653
  case 'Enter':
627
654
  e.preventDefault();
628
655
  handleSuggestionClick(filteredData[selectedIndex], selectedIndex);
629
656
  break;
630
-
657
+
631
658
  case 'Escape':
632
659
  e.preventDefault();
633
660
  setDropOpen(false);
634
661
  break;
635
-
662
+
636
663
  default:
637
664
  break;
638
665
  }
639
- };
666
+ };
640
667
 
641
668
  if (filteredData?.length > 0 && !isLoading) {
642
669
  window.addEventListener('keydown', handleKeyDown);
@@ -817,7 +844,10 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
817
844
  type="text"
818
845
  readOnly={readOnly ?? type === 'custom_select'}
819
846
  value={inputValue ? inputValue : ''}
820
- onBlur={handleClearInputValue}
847
+ onBlur={() => {
848
+ handleClearInputValue();
849
+ selectExactMatchFromSuggestions();
850
+ }}
821
851
  autoComplete="off"
822
852
  disabled={disabled}
823
853
  ref={inputRef}
@@ -846,7 +876,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
846
876
  ? placeholder && isCustomPlaceholder
847
877
  ? placeholder
848
878
  : 'Type to search'
849
- : placeholder ?? '--Select--'
879
+ : (placeholder ?? '--Select--')
850
880
  }
851
881
  onFocus={onInputFocus}
852
882
  onClick={(e) => {
@@ -874,7 +904,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
874
904
  <div
875
905
  ref={adorementRef}
876
906
  className={`${generateClassName(
877
- 'adorement'
907
+ 'adorement',
878
908
  )} qbs-autocomplete-adorement auto-dorpdown-adorement mr-[1px] ${
879
909
  isLoading ? 'bg-white' : ''
880
910
  }`}
@@ -931,7 +961,7 @@ const ModernAutoCompleteDropdown: React.FC<AutoSuggestionInputProps> = ({
931
961
  {errors && errors[name] && (
932
962
  <div
933
963
  className={` text-error-label relative cursor-pointer ${generateClassName(
934
- 'message'
964
+ 'message',
935
965
  )}`}
936
966
  onMouseEnter={() => setIsHovered(true)}
937
967
  onMouseLeave={() => setIsHovered(false)}