react-core-ts 2.1.3 → 2.1.5
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/AutoCompleteWithTabFilter.js +41 -0
- package/dist/AutoCompleteWithTabFilter.js.map +1 -1
- package/dist/ReactAutoComplete.js +39 -31
- package/dist/ReactAutoComplete.js.map +1 -1
- package/dist/ReactAutoCompleteDropdown.js +38 -34
- package/dist/ReactAutoCompleteDropdown.js.map +1 -1
- package/dist/ReactAutoCompleteSuggections.d.ts +1 -0
- package/dist/ReactAutoCompleteSuggections.js +50 -16
- package/dist/ReactAutoCompleteSuggections.js.map +1 -1
- package/package.json +1 -1
- package/src/AutoCompleteWithTabFilter.tsx +45 -0
- package/src/ReactAutoComplete.tsx +37 -27
- package/src/ReactAutoCompleteDropdown.tsx +37 -33
- package/src/ReactAutoCompleteSuggections.tsx +58 -10
|
@@ -59,6 +59,7 @@ type ModernAutoCompleteSuggectionsProps = {
|
|
|
59
59
|
desc?: string;
|
|
60
60
|
/** Field name that contains the unique identifier (default: 'id'). */
|
|
61
61
|
descId?: string;
|
|
62
|
+
showWarningIcon?: boolean;
|
|
62
63
|
};
|
|
63
64
|
|
|
64
65
|
/**
|
|
@@ -115,8 +116,10 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
115
116
|
labelTitle,
|
|
116
117
|
desc = 'name',
|
|
117
118
|
descId = 'id',
|
|
119
|
+
showWarningIcon = true,
|
|
118
120
|
}) => {
|
|
119
121
|
const [inputValue, setInputValue] = useState(value ?? '');
|
|
122
|
+
const [debouncedInputValue, setDebouncedInputValue] = useState('');
|
|
120
123
|
const [items, setItems] = useState<SuggestionItem[]>(data ?? []);
|
|
121
124
|
const [isLoading, setIsLoading] = useState(false);
|
|
122
125
|
const [showDropdown, setShowDropdown] = useState(false);
|
|
@@ -152,13 +155,26 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
152
155
|
}
|
|
153
156
|
}, [data]);
|
|
154
157
|
|
|
155
|
-
//
|
|
158
|
+
// Debounce inputValue so we don't call API on every keystroke
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
if (!hasTyped) return;
|
|
161
|
+
const handle = window.setTimeout(() => {
|
|
162
|
+
setDebouncedInputValue(inputValue);
|
|
163
|
+
}, 500); // 500ms debounce
|
|
164
|
+
|
|
165
|
+
return () => {
|
|
166
|
+
window.clearTimeout(handle);
|
|
167
|
+
};
|
|
168
|
+
}, [inputValue, hasTyped]);
|
|
169
|
+
|
|
170
|
+
// Load from getData only when user types some text (no initial preload),
|
|
171
|
+
// and only after debounce delay.
|
|
156
172
|
useEffect(() => {
|
|
157
173
|
// Do not call API until the user has actually typed at least once
|
|
158
174
|
if (!hasTyped) return;
|
|
159
175
|
|
|
160
176
|
let cancelled = false;
|
|
161
|
-
const query =
|
|
177
|
+
const query = debouncedInputValue.trim();
|
|
162
178
|
if (!getDataRef.current || query === '') {
|
|
163
179
|
// Clear items when input is cleared so dropdown also clears
|
|
164
180
|
if (!cancelled) {
|
|
@@ -189,7 +205,14 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
189
205
|
return () => {
|
|
190
206
|
cancelled = true;
|
|
191
207
|
};
|
|
192
|
-
}, [
|
|
208
|
+
}, [debouncedInputValue, data]);
|
|
209
|
+
|
|
210
|
+
// Notify parent via onChange when debounced value changes
|
|
211
|
+
useEffect(() => {
|
|
212
|
+
if (!hasTyped) return;
|
|
213
|
+
if (!onChange) return;
|
|
214
|
+
onChange(debouncedInputValue);
|
|
215
|
+
}, [debouncedInputValue, onChange]);
|
|
193
216
|
|
|
194
217
|
// Group by desc field and compute counts
|
|
195
218
|
const grouped = useMemo(() => {
|
|
@@ -232,7 +255,14 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
232
255
|
return grouped.filter((g) => g.name.toLowerCase().includes(term));
|
|
233
256
|
}, [grouped, inputValue, hasTyped]);
|
|
234
257
|
|
|
235
|
-
|
|
258
|
+
const effectiveVisible = useMemo(() => {
|
|
259
|
+
if (!hasTyped && items.length > 0) {
|
|
260
|
+
return grouped;
|
|
261
|
+
}
|
|
262
|
+
return visible;
|
|
263
|
+
}, [hasTyped, items.length, grouped, visible]);
|
|
264
|
+
|
|
265
|
+
// Update dropdown visibility based on visible items from typing
|
|
236
266
|
useEffect(() => {
|
|
237
267
|
setShowDropdown(visible.length > 0);
|
|
238
268
|
}, [visible.length]);
|
|
@@ -317,7 +347,7 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
317
347
|
};
|
|
318
348
|
|
|
319
349
|
const generateClassName = (
|
|
320
|
-
type: 'input' | 'label' | 'message' | 'adorement'
|
|
350
|
+
type: 'input' | 'label' | 'message' | 'adorement' | 'warning'
|
|
321
351
|
): string => {
|
|
322
352
|
let className = propsClassName || '';
|
|
323
353
|
switch (type) {
|
|
@@ -370,6 +400,9 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
370
400
|
case 'message':
|
|
371
401
|
className = ' text-error-icon ';
|
|
372
402
|
break;
|
|
403
|
+
case 'warning':
|
|
404
|
+
className = ' text-warning-icon ';
|
|
405
|
+
break;
|
|
373
406
|
case 'adorement':
|
|
374
407
|
className += ' absolute right-0 adorement gap-1 flex items-center ';
|
|
375
408
|
break;
|
|
@@ -464,11 +497,16 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
464
497
|
value={inputValue ? inputValue : ''}
|
|
465
498
|
ref={inputRef}
|
|
466
499
|
disabled={disabled}
|
|
500
|
+
onFocus={() => {
|
|
501
|
+
// show suggestions when the field gains focus.
|
|
502
|
+
if (!disabled && effectiveVisible.length > 0) {
|
|
503
|
+
setShowDropdown(true);
|
|
504
|
+
}
|
|
505
|
+
}}
|
|
467
506
|
onChange={(e) => {
|
|
468
507
|
const val = e.target.value;
|
|
469
508
|
setInputValue(val);
|
|
470
509
|
setHasTyped(true);
|
|
471
|
-
onChange?.(val);
|
|
472
510
|
}}
|
|
473
511
|
onBlur={() => {}}
|
|
474
512
|
placeholder={placeholder}
|
|
@@ -510,16 +548,26 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
510
548
|
<CustomIcons name="alert" type="medium" />
|
|
511
549
|
</div>
|
|
512
550
|
)}
|
|
551
|
+
|
|
552
|
+
{showWarningIcon && effectiveVisible.length > 0 && (
|
|
553
|
+
<div
|
|
554
|
+
className={`text-warning-label relative mr-1 ${generateClassName(
|
|
555
|
+
'warning'
|
|
556
|
+
)}`}
|
|
557
|
+
>
|
|
558
|
+
<CustomIcons name="alert" type="medium" />
|
|
559
|
+
</div>
|
|
560
|
+
)}
|
|
513
561
|
</div>
|
|
514
562
|
</div>
|
|
515
563
|
</div>
|
|
516
564
|
</div>
|
|
517
|
-
{showDropdown &&
|
|
565
|
+
{showDropdown && effectiveVisible.length > 0 && (
|
|
518
566
|
<>
|
|
519
567
|
{insideOpen ? (
|
|
520
568
|
<div className="suggection-list">
|
|
521
569
|
<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">
|
|
522
|
-
{
|
|
570
|
+
{effectiveVisible.map((g) => (
|
|
523
571
|
<SuggestionItem
|
|
524
572
|
key={g.name}
|
|
525
573
|
name={g.name}
|
|
@@ -536,12 +584,12 @@ const ModernAutoCompleteSuggections: React.FC<
|
|
|
536
584
|
style={dropPosition}
|
|
537
585
|
>
|
|
538
586
|
<div className="h-auto max-h-40 overflow-auto w-full py-1.5">
|
|
539
|
-
{
|
|
587
|
+
{effectiveVisible.map((g) => (
|
|
540
588
|
<div key={g.name} className="px-3.5 text-[11px] text-gray-700">
|
|
541
589
|
<SuggestionItem
|
|
542
590
|
name={g.name}
|
|
543
591
|
count={g.count}
|
|
544
|
-
showCount={g.count >
|
|
592
|
+
showCount={g.count > 0}
|
|
545
593
|
/>
|
|
546
594
|
</div>
|
|
547
595
|
))}
|