react-core-ts 2.0.13 → 2.0.15

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.
@@ -1,12 +1,12 @@
1
- import React, { useCallback, useEffect, useRef, useState } from "react";
2
- import { FieldErrors } from "react-hook-form";
1
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
2
+ import { FieldErrors } from 'react-hook-form';
3
3
 
4
- import CustomIcons from "./components/customIcons";
5
- import Spinner from "./components/loader/Spinner";
6
- import Portal from "./components/portal";
7
- import { debounce } from "./utilities/debounce";
8
- import { applyPositionClass } from "./utilities/getPosition";
9
- import { DropArrow } from "./utilities/icons";
4
+ import CustomIcons from './components/customIcons';
5
+ import Spinner from './components/loader/Spinner';
6
+ import Portal from './components/portal';
7
+ import { debounce } from './utilities/debounce';
8
+ import { applyPositionClass } from './utilities/getPosition';
9
+ import { AllDropArrow, DropArrow } from './utilities/icons';
10
10
 
11
11
  type valueProps = {
12
12
  id?: string | number;
@@ -49,6 +49,7 @@ interface AutoSuggestionInputProps {
49
49
  width?: number;
50
50
  labelTitle?: string;
51
51
  isModern?: boolean;
52
+ autoDropdown?: boolean;
52
53
  size?: "xs" | "sm" | "md" | "lg" | "xxs";
53
54
  tableView?: boolean;
54
55
  dropdownMinWidth?: number; // Minimum additional width in pixels to add to dropdown
@@ -73,11 +74,12 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
73
74
  placeholder,
74
75
  id,
75
76
  className: propsClassName,
76
- type = "custom_select",
77
+ type = 'custom_select',
77
78
  readOnly,
78
79
  disabled = false,
79
80
  value,
80
81
  autoFilter = false,
82
+ autoDropdown = true,
81
83
  insideOpen = false,
82
84
  isClose = true,
83
85
  noLocalFilter = false,
@@ -112,6 +114,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
112
114
  const [selectedIndex, setSelectedIndex] = useState(0);
113
115
  const itemRefs = useRef<(HTMLLIElement | null)[]>([]);
114
116
  const scrollContainerRef = useRef<HTMLUListElement | null>(null);
117
+ const [refetchData, setRefetchData] = useState(false);
115
118
  const [dropPosition, setDropPosition] = useState<any>({
116
119
  top: 0,
117
120
  left: 0,
@@ -132,8 +135,8 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
132
135
  ) => {
133
136
  return substring &&
134
137
  mainString &&
135
- typeof mainString === "string" &&
136
- typeof subString === "string"
138
+ typeof mainString === 'string' &&
139
+ typeof subString === 'string'
137
140
  ? mainString
138
141
  .toString()
139
142
  .toLowerCase()
@@ -148,23 +151,23 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
148
151
  return (
149
152
  checkIncludesIfExists(mainString, subString) ||
150
153
  (!!checkParams &&
151
- ((checkArrayContains(checkParams, "param1") &&
154
+ ((checkArrayContains(checkParams, 'param1') &&
152
155
  checkIncludesIfExists(param1, subString)) ||
153
- (checkArrayContains(checkParams, "param2") &&
156
+ (checkArrayContains(checkParams, 'param2') &&
154
157
  checkIncludesIfExists(param2, subString)) ||
155
- (checkArrayContains(checkParams, "param3") &&
158
+ (checkArrayContains(checkParams, 'param3') &&
156
159
  checkIncludesIfExists(param3, subString)) ||
157
- (checkArrayContains(checkParams, "param4") &&
160
+ (checkArrayContains(checkParams, 'param4') &&
158
161
  checkIncludesIfExists(param4, subString))))
159
162
  );
160
163
  };
161
164
 
162
165
  const getHeight = () => {
163
166
  switch (size) {
164
- case "sm":
165
- return " h-[34px] ";
167
+ case 'sm':
168
+ return ' h-[34px] ';
166
169
  default:
167
- return " ";
170
+ return ' ';
168
171
  }
169
172
  };
170
173
 
@@ -175,8 +178,8 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
175
178
  setInputValue(value);
176
179
  handleValChange(value);
177
180
  if (!value) {
178
- setInputValue("");
179
- onChange({ id: undefined, name: "", from: 2 });
181
+ setInputValue('');
182
+ onChange({ id: undefined, name: '', from: 2 });
180
183
  }
181
184
  };
182
185
 
@@ -184,11 +187,11 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
184
187
  debounce(
185
188
  (value: string) => {
186
189
  setDropOpen(true);
187
- onChange({ id: undefined, name: "", from: 1 });
188
- if (value.trim() === "" && type === "auto_complete") {
190
+ onChange({ id: undefined, name: '', from: 1 });
191
+ if (value.trim() === '' && type === 'auto_complete') {
189
192
  setSuggestions([]);
190
193
  if (autoFilter) {
191
- handleDropData("*");
194
+ handleDropData('*');
192
195
  } else {
193
196
  setDropOpen(false);
194
197
  }
@@ -204,11 +207,11 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
204
207
  []
205
208
  );
206
209
  const handleDropData = (value?: string) => {
207
- if (type === "auto_complete") {
210
+ if (type === 'auto_complete') {
208
211
  if (isStaticList) {
209
212
  loadStaticData();
210
213
  const filteredData =
211
- value && value !== "*"
214
+ value && value !== '*'
212
215
  ? data?.filter((item) =>
213
216
  checkIncludes(
214
217
  item.name,
@@ -220,15 +223,17 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
220
223
  )
221
224
  : data;
222
225
  setSuggestions(filteredData);
223
- } else handlePickSuggestions(value);
226
+ } else {
227
+ handlePickSuggestions(value);
228
+ }
224
229
  } else if (
225
- (type === "custom_select" || type === "custom_search_select") &&
230
+ (type === 'custom_select' || type === 'custom_search_select') &&
226
231
  (!data || data?.length === 0)
227
232
  ) {
228
233
  handlePickSuggestions();
229
- } else if (type === "custom_search_select" && data && data?.length > 0) {
234
+ } else if (type === 'custom_search_select' && data && data?.length > 0) {
230
235
  const filteredData =
231
- value && value !== "*"
236
+ value && value !== '*'
232
237
  ? data.filter((item) =>
233
238
  checkIncludes(
234
239
  item.name,
@@ -249,6 +254,9 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
249
254
  const fetchedSuggestions = await getData?.(value);
250
255
  setSuggestions(fetchedSuggestions);
251
256
  setIsLoading(false);
257
+ if (autoDropdown) {
258
+ setRefetchData(true);
259
+ }
252
260
  } catch (error) {
253
261
  setIsLoading(false);
254
262
  }
@@ -258,10 +266,10 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
258
266
  const onLabelClick = () => {
259
267
  if (!isDisabled) {
260
268
  inputRef?.current?.focus();
261
- if (autoFilter && inputValue === "") {
262
- handleValChange("*");
269
+ if (autoFilter && inputValue === '') {
270
+ handleValChange('*');
263
271
  } else if (
264
- (type === "custom_select" || type === "custom_search_select") &&
272
+ (type === 'custom_select' || type === 'custom_search_select') &&
265
273
  data &&
266
274
  data?.length > 0
267
275
  ) {
@@ -283,17 +291,22 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
283
291
  else return (inputValue?.toString().length ?? 0) <= 0 ? true : false;
284
292
  };
285
293
  const loadStaticData = async () => {
286
- if (!data) {
294
+ if (!data || (refetchData && autoDropdown && !isStaticList)) {
287
295
  data = [];
288
296
  if (getData) {
289
297
  try {
290
298
  setIsLoading(true);
291
- handlePickSuggestions("*");
292
- const fetchedSuggestions = await getData?.("*");
299
+ //handlePickSuggestions('*');
300
+ const fetchedSuggestions = await getData?.('*');
293
301
  fetchedSuggestions?.forEach((element: any) => {
294
302
  data?.push(element);
295
303
  });
304
+ setSuggestions(fetchedSuggestions);
296
305
  setIsLoading(false);
306
+ if (autoDropdown) {
307
+ setRefetchData(false);
308
+ timerRef.current = 1;
309
+ }
297
310
  } catch (error) {
298
311
  setIsLoading(false);
299
312
  }
@@ -301,9 +314,9 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
301
314
  }
302
315
  };
303
316
  useEffect(() => {
304
- document.addEventListener("click", handleClickOutside);
317
+ document.addEventListener('click', handleClickOutside);
305
318
  return () => {
306
- document.removeEventListener("click", handleClickOutside);
319
+ document.removeEventListener('click', handleClickOutside);
307
320
  };
308
321
  }, []);
309
322
 
@@ -314,10 +327,10 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
314
327
  }, [autoFocus]);
315
328
  const onInputFocus = () => {
316
329
  if (!isDisabled) {
317
- if (autoFilter && inputValue === "") {
318
- handleValChange("*");
330
+ if (autoFilter && inputValue === '') {
331
+ handleValChange('*');
319
332
  } else if (
320
- (type === "custom_select" || type === "custom_search_select") &&
333
+ (type === 'custom_select' || type === 'custom_search_select') &&
321
334
  data &&
322
335
  data?.length > 0
323
336
  ) {
@@ -336,18 +349,29 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
336
349
  name: suggestion.name,
337
350
  ...(suggestion?.label ? { label: suggestion?.label } : {}),
338
351
  });
339
- if (type !== "custom_select") setInputValue(suggestion.name);
352
+ if (type !== 'custom_select') setInputValue(suggestion.name);
340
353
  setDropOpen(false);
341
354
  setSelectedIndex(index);
342
355
  };
343
356
  const handleOpen = (e: any) => {
344
- if (!suggestions || suggestions?.length === 0) {
345
- handleDropData();
346
- return;
357
+ if (!suggestions || suggestions?.length === 0) handleDropData();
358
+ if (!isLoading) {
359
+ setDropOpen(!dropOpen);
360
+ if (type !== 'custom_select') setInputValue('');
361
+ }
362
+ };
363
+
364
+ const handleOpenDropdown = (e: any) => {
365
+ if (!suggestions || suggestions?.length === 0 || refetchData) {
366
+ if (autoDropdown && (inputValue === '' || inputValue.trim() === '')) {
367
+ setSuggestions([]);
368
+ loadStaticData();
369
+ } else if (!refetchData) {
370
+ handleDropData();
371
+ }
347
372
  }
348
373
  if (!isLoading) {
349
374
  setDropOpen(!dropOpen);
350
- if (type !== "custom_select") setInputValue("");
351
375
  }
352
376
  };
353
377
 
@@ -358,28 +382,28 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
358
382
  useEffect(() => {
359
383
  if (!insideOpen) {
360
384
  setSelectedIndex(0);
361
- window.addEventListener("scroll", handleScroll);
385
+ window.addEventListener('scroll', handleScroll);
362
386
 
363
- const mainElement = document.querySelector("main");
364
- mainElement?.addEventListener("scroll", handleScroll);
387
+ const mainElement = document.querySelector('main');
388
+ mainElement?.addEventListener('scroll', handleScroll);
365
389
 
366
390
  const gridElements = document.querySelectorAll(
367
- ".k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto"
391
+ '.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto'
368
392
  );
369
393
  gridElements.forEach((gridElement: any) => {
370
- gridElement.addEventListener("scroll", handleScroll);
394
+ gridElement.addEventListener('scroll', handleScroll);
371
395
  });
372
396
 
373
- window.addEventListener("resize", getDropPosition);
397
+ window.addEventListener('resize', getDropPosition);
374
398
  getDropPosition();
375
399
  return () => {
376
- window.removeEventListener("scroll", handleScroll);
377
- const mainElement = document.querySelector("main");
378
- mainElement?.removeEventListener("scroll", handleScroll);
379
- window.addEventListener("resize", getDropPosition);
380
- const gridElements = document.querySelectorAll(".k-grid-content");
400
+ window.removeEventListener('scroll', handleScroll);
401
+ const mainElement = document.querySelector('main');
402
+ mainElement?.removeEventListener('scroll', handleScroll);
403
+ window.addEventListener('resize', getDropPosition);
404
+ const gridElements = document.querySelectorAll('.k-grid-content');
381
405
  gridElements.forEach((gridElement: any) => {
382
- gridElement.removeEventListener("scroll", handleScroll);
406
+ gridElement.removeEventListener('scroll', handleScroll);
383
407
  });
384
408
  };
385
409
  }
@@ -387,13 +411,16 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
387
411
 
388
412
  const handleClear = () => {
389
413
  setDropOpen(false);
390
- setInputValue("");
391
- onChange({ id: undefined, name: "", from: 3 });
414
+ setInputValue('');
415
+ onChange({ id: undefined, name: '', from: 3 });
392
416
  onLabelClick();
417
+ if (autoDropdown) {
418
+ setRefetchData(true);
419
+ }
393
420
  };
394
421
 
395
422
  useEffect(() => {
396
- setInputValue(value?.name ?? "");
423
+ setInputValue(value?.name ?? '');
397
424
  }, [value?.name]);
398
425
 
399
426
  useEffect(() => {
@@ -401,7 +428,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
401
428
  }, [data]);
402
429
 
403
430
  const getErrors = (err: any) => {
404
- let errMsg = "";
431
+ let errMsg = '';
405
432
  if (err.message) {
406
433
  errMsg = err?.message;
407
434
  } else if (err?.id?.message) {
@@ -412,61 +439,61 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
412
439
  return errMsg;
413
440
  };
414
441
  const generateClassName = (
415
- type: "input" | "label" | "message" | "adorement"
442
+ type: 'input' | 'label' | 'message' | 'adorement'
416
443
  ): string => {
417
444
  let className = propsClassName;
418
445
  switch (type) {
419
- case "input":
446
+ case 'input':
420
447
  className += ` block text-common text-input-text font-normal px-3.5 w-full text-sm text-gray-900 bg-transparent border appearance-none peer h-10 rounded-[4px] disabled:text-input-disabled bg-white disabled:bg-disabled ${
421
448
  label && isModern
422
- ? "placeholder-transparent"
423
- : "focus:placeholder-grey-secondary placeholder-input-label"
449
+ ? 'placeholder-transparent'
450
+ : 'focus:placeholder-grey-secondary placeholder-input-label'
424
451
  } focus:placeholder-grey-secondary`;
425
452
 
426
453
  if (errors && errors[name]) {
427
454
  className +=
428
- " border-[#FDA29B] focus:border-error-[#FDA29B] focus:ring-[#FDA29B] focus:ring-3 focus:outline-[#FDA29B] input-outline";
455
+ ' border-[#FDA29B] focus:border-error-[#FDA29B] focus:ring-[#FDA29B] focus:ring-3 focus:outline-[#FDA29B] input-outline';
429
456
  } else {
430
457
  className +=
431
- " text-grey-dark border-input-light focus:border-blue-navy focus:outline-none focus:ring-0";
458
+ ' text-grey-dark border-input-light focus:border-blue-navy focus:outline-none focus:ring-0';
432
459
  }
433
460
 
434
- className += getHeight();
461
+ className += getHeight()
435
462
 
436
463
  break;
437
- case "label":
464
+ case 'label':
438
465
  className += ` flex modern-input-label-truncate peer-focus:modern-input-peer-focus-label-size
439
466
  ${
440
467
  isDisabled
441
- ? "cursor-pointer"
442
- : "cursor-text peer-focus:cursor-pointer"
468
+ ? 'cursor-pointer'
469
+ : 'cursor-text peer-focus:cursor-pointer'
443
470
  } ${
444
471
  isDisabled && !checkIsEmptyField()
445
- ? "disabled-input-label-bg"
472
+ ? 'disabled-input-label-bg'
446
473
  : !isDisabled || !checkIsEmptyField()
447
- ? "active-input-label-bg"
448
- : ""
474
+ ? 'active-input-label-bg'
475
+ : ''
449
476
  } 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 ${
450
477
  isDisabled
451
- ? "cursor-pointer"
452
- : "cursor-text peer-focus:cursor-pointer"
478
+ ? 'cursor-pointer'
479
+ : 'cursor-text peer-focus:cursor-pointer'
453
480
  }
454
481
  ${
455
482
  checkIsEmptyField()
456
- ? "modern-input-label-size"
457
- : "modern-input-peer-focus-label-size"
483
+ ? 'modern-input-label-size'
484
+ : 'modern-input-peer-focus-label-size'
458
485
  }`;
459
486
  if (errors && errors[name]) {
460
- className += " text-error-light ";
487
+ className += ' text-error-light ';
461
488
  } else {
462
- className += " text-grey-dark peer-focus:text-blue-navy";
489
+ className += ' text-grey-dark peer-focus:text-blue-navy';
463
490
  }
464
491
  break;
465
- case "message":
466
- className = " text-error-icon ";
492
+ case 'message':
493
+ className = ' text-error-icon ';
467
494
  break;
468
- case "adorement":
469
- className += " absolute right-0 adorement gap-1 flex items-center ";
495
+ case 'adorement':
496
+ className += ' absolute right-0 adorement gap-1 flex items-center ';
470
497
  break;
471
498
  default:
472
499
  break;
@@ -491,36 +518,37 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
491
518
  // return 'bottom'
492
519
  // }
493
520
  const filteredData =
494
- inputValue !== "*" &&
495
- inputValue !== "" &&
496
- type !== "custom_select" &&
521
+ inputValue !== '*' &&
522
+ inputValue !== '' &&
523
+ type !== 'custom_select' &&
497
524
  !noLocalFilter
498
525
  ? suggestions?.filter((item: valueProps) =>
499
526
  checkIncludes(
500
527
  item.name,
501
528
  inputValue,
502
- item.param1 ?? "",
503
- item.param2 ?? "",
504
- item.param3 ?? "",
505
- item.param4 ?? ""
529
+ item.param1 ?? '',
530
+ item.param2 ?? '',
531
+ item.param3 ?? '',
532
+ item.param4 ?? ''
506
533
  )
507
534
  )
508
535
  : suggestions;
509
536
 
510
537
  const handleError = (data: any) => {
511
538
  if (
512
- getErrors(data[name]) === "required" ||
513
- getErrors(data[name]) === "Required"
539
+ getErrors(data[name]) === 'required' ||
540
+ getErrors(data[name]) === 'Required'
514
541
  ) {
515
542
  return `${label ?? labelTitle} is ${getErrors(data[name])}`;
516
543
  } else {
517
- return getErrors(data[name]) ?? "";
544
+ return getErrors(data[name]) ?? '';
518
545
  }
519
546
  };
520
547
 
521
548
  const getDropPosition = (): any => {
522
549
  if (!insideOpen && inputRef?.current) {
523
550
  const dropdownHeight = 200; // Assume the height of the dropdown is 200px, adjust as needed
551
+ const isMobile = window.innerWidth < 768; // Mobile breakpoint
524
552
 
525
553
  const inputRect = inputRef.current.getBoundingClientRect();
526
554
  const spaceBelow =
@@ -534,11 +562,65 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
534
562
  } else {
535
563
  top = inputRect.top + window.scrollY + inputRect.height + 2;
536
564
  }
565
+
566
+ let left = inputRect.left + window.scrollX;
567
+ let width = inputRect.width + dropdownMinWidth;
568
+ const viewportWidth = window.innerWidth;
569
+ const viewportRight = window.scrollX + viewportWidth;
570
+ const inputRight = inputRect.right + window.scrollX;
571
+
572
+ // Check if dropdown would overflow on the right side
573
+ const dropdownRight = left + width;
574
+ const wouldOverflowRight = dropdownRight > viewportRight;
575
+
576
+ // If dropdown would overflow on the right (last column scenario), align from right to left
577
+ if (wouldOverflowRight) {
578
+ // Align right edge of dropdown with right edge of input
579
+ // Dropdown extends to the left from the input's right edge
580
+ const padding = isMobile ? 8 : 0;
581
+ left = inputRight - width;
582
+
583
+ // Ensure dropdown doesn't go off the left edge
584
+ const viewportLeft = window.scrollX + (isMobile ? 8 : 0);
585
+ if (left < viewportLeft) {
586
+ left = viewportLeft;
587
+ // Adjust width to fit within viewport
588
+ width = Math.min(width, inputRight - left - padding);
589
+ }
590
+ }
591
+
592
+ // Handle mobile view - additional constraints
593
+ if (isMobile) {
594
+ // On mobile, constrain width to viewport with some padding
595
+ const mobilePadding = 16; // 8px padding on each side
596
+ const maxWidth = viewportWidth - mobilePadding;
597
+
598
+ // Use the smaller of: calculated width or max mobile width
599
+ width = Math.min(width, maxWidth);
600
+
601
+ // Adjust left position to prevent overflow
602
+ const rightEdge = left + width;
603
+ const mobileViewportRight = window.scrollX + viewportWidth - mobilePadding / 2;
604
+
605
+ if (rightEdge > mobileViewportRight) {
606
+ // Align to right edge with padding
607
+ left = mobileViewportRight - width;
608
+ }
609
+
610
+ // Ensure dropdown doesn't go off the left edge
611
+ const viewportLeft = window.scrollX + mobilePadding / 2;
612
+ if (left < viewportLeft) {
613
+ left = viewportLeft;
614
+ // Adjust width if needed to fit
615
+ width = Math.min(width, mobileViewportRight - left);
616
+ }
617
+ }
618
+
537
619
  setDropPosition({
538
- left: inputRect.left + window.scrollX,
620
+ left,
539
621
  top,
540
622
  bottom,
541
- width: inputRect.width + dropdownMinWidth,
623
+ width,
542
624
  });
543
625
  }
544
626
 
@@ -549,7 +631,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
549
631
 
550
632
  useEffect(() => {
551
633
  if (
552
- inputValue &&
634
+ (inputValue || autoDropdown) &&
553
635
  filteredData?.length === 0 &&
554
636
  !isLoading &&
555
637
  timerRef.current === 1
@@ -565,34 +647,34 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
565
647
  // Handle keyboard navigation
566
648
  const handleKeyDown = (e: KeyboardEvent) => {
567
649
  if (!dropOpen) return;
568
-
650
+
569
651
  const nextIndex =
570
- e.key === "ArrowDown"
652
+ e.key === 'ArrowDown'
571
653
  ? (selectedIndex + 1) % filteredData.length
572
- : e.key === "ArrowUp"
654
+ : e.key === 'ArrowUp'
573
655
  ? (selectedIndex - 1 + filteredData.length) % filteredData.length
574
656
  : selectedIndex;
575
-
657
+
576
658
  switch (e.key) {
577
- case "ArrowDown":
578
- case "ArrowUp":
659
+ case 'ArrowDown':
660
+ case 'ArrowUp':
579
661
  e.preventDefault();
580
-
662
+
581
663
  // Update index first
582
664
  setSelectedIndex(nextIndex);
583
-
665
+
584
666
  // Wait for DOM update before scrolling
585
667
  requestAnimationFrame(() => {
586
668
  const el = itemRefs.current[nextIndex];
587
669
  const container = scrollContainerRef.current;
588
-
670
+
589
671
  if (el && container) {
590
672
  const elTop = el.offsetTop;
591
673
  const elBottom = elTop + el.offsetHeight;
592
-
674
+
593
675
  const containerTop = container.scrollTop;
594
676
  const containerBottom = containerTop + container.clientHeight;
595
-
677
+
596
678
  if (elBottom > containerBottom) {
597
679
  container.scrollTop = elBottom - container.clientHeight;
598
680
  } else if (elTop < containerTop) {
@@ -601,26 +683,26 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
601
683
  }
602
684
  });
603
685
  break;
604
-
605
- case "Enter":
686
+
687
+ case 'Enter':
606
688
  e.preventDefault();
607
689
  handleSuggestionClick(filteredData[selectedIndex], selectedIndex);
608
690
  break;
609
-
610
- case "Escape":
691
+
692
+ case 'Escape':
611
693
  e.preventDefault();
612
694
  setDropOpen(false);
613
695
  break;
614
-
696
+
615
697
  default:
616
698
  break;
617
699
  }
618
- };
700
+ };
619
701
 
620
702
  if (filteredData?.length > 0 && !isLoading) {
621
- window.addEventListener("keydown", handleKeyDown);
703
+ window.addEventListener('keydown', handleKeyDown);
622
704
  return () => {
623
- window.removeEventListener("keydown", handleKeyDown);
705
+ window.removeEventListener('keydown', handleKeyDown);
624
706
  };
625
707
  }
626
708
  }, [
@@ -636,8 +718,8 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
636
718
  return (
637
719
  (filteredData?.length > 0 || showNoResults) && (
638
720
  <div
639
- className="autocomplete-suggections absolute bg-white shadow-gray-300 shadow-md border border-grey-light z-50 mt-9"
640
721
  style={dropPosition}
722
+ className="autocomplete-suggections autocomplete-suggections-tableview absolute bg-white shadow-gray-300 shadow-md border border-grey-light z-50 mt-9"
641
723
  >
642
724
  <ul
643
725
  className={`h-auto max-h-40 overflow-auto w-full ${tableView ? '' : 'py-1.5'}`}
@@ -649,9 +731,9 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
649
731
  <li
650
732
  className={`${
651
733
  value?.id === suggestion?.id
652
- ? "bg-blue-navy text-white"
734
+ ? 'bg-blue-navy text-white'
653
735
  : `${
654
- index === selectedIndex ? "is-selected" : ""
736
+ index === selectedIndex ? 'is-selected' : ''
655
737
  } hover:bg-table-hover`
656
738
  } cursor-pointer text-xxs qbs-autocomplete-suggections-items ${
657
739
  tableView
@@ -681,14 +763,13 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
681
763
 
682
764
  // Determine if first column needs a separator
683
765
  const hasColumnsAfter = columnsAfter.length > 0;
684
- const hasColumnsBefore = columnsBefore.length > 0;
685
766
 
686
767
  return (
687
768
  <>
688
769
  {/* Columns before first column */}
689
770
  {columnsBefore.map((column, colIndex) => {
690
771
  const hasValue = suggestion?.[column.key];
691
- const isLastBefore = colIndex === columnsBefore.length - 1 && !hasColumnsAfter;
772
+ const isLastBefore = false;
692
773
  return hasValue ? (
693
774
  <li
694
775
  key={column.key}
@@ -771,7 +852,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
771
852
  useEffect(() => {
772
853
  const shouldShowClose =
773
854
  value?.name &&
774
- (value?.id || String(value?.id) === "0") &&
855
+ (value?.id || String(value?.id) === '0') &&
775
856
  !disabled &&
776
857
  !readOnly &&
777
858
  isClose;
@@ -785,7 +866,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
785
866
  if (inputRef.current) {
786
867
  const { scrollWidth, clientWidth, value } = inputRef.current;
787
868
  // Check for overflow only when there's content
788
- if (value.trim() !== "") {
869
+ if (value.trim() !== '') {
789
870
  setShowTooltip(scrollWidth > clientWidth + 2);
790
871
  } else {
791
872
  setShowTooltip(false); // No tooltip for empty input
@@ -794,13 +875,13 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
794
875
  };
795
876
 
796
877
  if (inputRef.current) {
797
- inputRef.current.addEventListener("input", checkOverflow);
878
+ inputRef.current.addEventListener('input', checkOverflow);
798
879
  checkOverflow(); // Initial check
799
880
  }
800
881
 
801
882
  return () => {
802
883
  if (inputRef.current) {
803
- inputRef.current.removeEventListener("input", checkOverflow);
884
+ inputRef.current.removeEventListener('input', checkOverflow);
804
885
  }
805
886
  };
806
887
  }, [inputValue]);
@@ -818,7 +899,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
818
899
  id={
819
900
  id ? `autocomplete-container-${id}` : `autocomplete-container-${name}`
820
901
  }
821
- className={` flex-grow ${fullWidth ? "w-full" : "w-auto"}`}
902
+ className={` flex-grow ${fullWidth ? 'w-full' : 'w-auto'}`}
822
903
  ref={dropdownref}
823
904
  >
824
905
  {label && !isModern && (
@@ -838,7 +919,7 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
838
919
  )}
839
920
 
840
921
  <div
841
- className={`flex relative ${fullWidth ? "w-full" : "w-auto"}`}
922
+ className={`flex relative ${fullWidth ? 'w-full' : 'w-auto'}`}
842
923
  style={{ width: width }}
843
924
  >
844
925
  <div
@@ -848,8 +929,8 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
848
929
  >
849
930
  <input
850
931
  type="text"
851
- readOnly={readOnly ?? type === "custom_select"}
852
- value={inputValue ? inputValue : ""}
932
+ readOnly={readOnly ?? type === 'custom_select'}
933
+ value={inputValue ? inputValue : ''}
853
934
  onBlur={handleClearInputValue}
854
935
  autoComplete="off"
855
936
  disabled={disabled}
@@ -872,22 +953,23 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
872
953
  }
873
954
  : {}),
874
955
  }}
875
- className={` ${generateClassName("input")}`}
956
+ className={` ${generateClassName('input')}`}
876
957
  onChange={handleChange}
877
958
  placeholder={
878
- type === "auto_complete"
959
+ type === 'auto_complete'
879
960
  ? placeholder && isCustomPlaceholder
880
961
  ? placeholder
881
- : "Type to search"
882
- : placeholder ?? "--Select--"
962
+ : 'Type to search'
963
+ : placeholder ?? '--Select--'
883
964
  }
884
965
  onFocus={onInputFocus}
885
966
  onClick={(e) => {
886
- if (type === "custom_select") {
967
+ if (type === 'custom_select') {
887
968
  setDropOpen(!dropOpen);
888
969
  handleOpen(e);
889
970
  } else {
890
- setDropOpen(!dropOpen);
971
+ if (dropOpen || filteredData?.length > 0)
972
+ setDropOpen(!dropOpen);
891
973
  }
892
974
  }}
893
975
  />
@@ -895,20 +977,20 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
895
977
  <label
896
978
  htmlFor={id}
897
979
  onClick={() => onLabelClick()}
898
- className={generateClassName("label")}
980
+ className={generateClassName('label')}
899
981
  >
900
- {label ? <span className="truncate">{label}</span> : ""}
982
+ {label ? <span className="truncate">{label}</span> : ''}
901
983
  {required ? <span className="text-error"> *</span> : <></>}
902
984
  </label>
903
985
  )}
904
986
  </div>
905
- <div className="flex items-center justify-center ">
987
+ <div className="flex items-center justify-center autocomplete-adorement-wrapper">
906
988
  <div
907
989
  ref={adorementRef}
908
990
  className={`${generateClassName(
909
- "adorement"
910
- )} qbs-autocomplete-adorement custom-dorpdown-adorement mr-[1px] ${
911
- isLoading ? "bg-white" : ""
991
+ 'adorement'
992
+ )} qbs-autocomplete-adorement auto-dorpdown-adorement mr-[1px] ${
993
+ isLoading ? 'bg-white' : ''
912
994
  }`}
913
995
  >
914
996
  {showClose && (
@@ -923,31 +1005,47 @@ const ReactAutoCompleteTableView: React.FC<AutoSuggestionInputProps> = ({
923
1005
  </button>
924
1006
  )}
925
1007
  {isLoading && <Spinner />}
926
- {type !== "auto_complete" && !disabled && !readOnly && (
927
- <button
928
- disabled={disabled ?? readOnly}
929
- onClick={(e) => handleOpen(e)}
930
- onBlur={handleClose}
931
- className=" text-[#667085] focus-visible:outline-slate-100"
932
- data-testid="drop-arrow"
933
- type="button"
934
- id="autocomplete-drop-icon"
935
- ref={dropBtnRef}
936
- >
937
- {!dropOpen ? (
938
- <DropArrow uniqueDropArrowId="drop-arrow-icon" />
939
- ) : (
940
- <DropArrow
941
- className="rotate-180"
942
- uniqueDropArrowId="drop-arrow-icon"
943
- />
944
- )}
945
- </button>
946
- )}
1008
+ {(type !== 'auto_complete' || autoDropdown) &&
1009
+ !disabled &&
1010
+ !readOnly && (
1011
+ <button
1012
+ disabled={disabled ?? readOnly}
1013
+ onClick={(e) => handleOpenDropdown(e)}
1014
+ onBlur={handleClose}
1015
+ className=" text-[#667085] focus-visible:outline-slate-100"
1016
+ data-testid="drop-arrow"
1017
+ type="button"
1018
+ id="autocomplete-drop-icon"
1019
+ ref={dropBtnRef}
1020
+ >
1021
+ {!dropOpen ? (
1022
+ autoDropdown ? (
1023
+ <AllDropArrow
1024
+ type="down"
1025
+ uniqueId="all-dropdow-arrow-icon"
1026
+ className="all-dropdow-arrow-icon"
1027
+ />
1028
+ ) : (
1029
+ <DropArrow uniqueDropArrowId="drop-arrow-icon" />
1030
+ )
1031
+ ) : autoDropdown ? (
1032
+ <AllDropArrow
1033
+ type="up"
1034
+ uniqueId="all-dropdow-arrow-icon"
1035
+ className="all-dropdow-arrow-icon"
1036
+ />
1037
+ ) : (
1038
+ <DropArrow
1039
+ className="rotate-180"
1040
+ uniqueDropArrowId="drop-arrow-icon"
1041
+ />
1042
+ )}
1043
+ </button>
1044
+ )}
947
1045
  {errors && errors[name] && (
948
1046
  <div
949
- className={` text-error-label relative cursor-pointer ${generateClassName(
950
- "message"
1047
+ className={` text-error-label relative cursor-pointer ${generateClassName(
1048
+ 'message'
951
1049
  )}`}
952
1050
  onMouseEnter={() => setIsHovered(true)}
953
1051
  onMouseLeave={() => setIsHovered(false)}