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.
- package/dist/AutoCompleteWithTabFilter.js +4 -3
- package/dist/AutoCompleteWithTabFilter.js.map +1 -1
- package/dist/ReactAutoCompleteTableView.d.ts +3 -2
- package/dist/ReactAutoCompleteTableView.js +192 -121
- package/dist/ReactAutoCompleteTableView.js.map +1 -1
- package/dist/commontypes.d.ts +5 -1
- package/dist/dropdownFilterTabs.d.ts +5 -1
- package/dist/dropdownFilterTabs.js +65 -47
- package/dist/dropdownFilterTabs.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/styles/styles/components/autocomplete.css +744 -0
- package/dist/styles/styles/components/selectedautocomplete.css +179 -0
- package/dist/styles/styles/components/tooltip.css +497 -0
- package/dist/styles/styles/components/treedropdown.css +97 -0
- package/dist/styles/styles/global.css +8 -0
- package/docs/App.tsx +44 -2
- package/package.json +1 -1
- package/src/AutoCompleteWithTabFilter.tsx +11 -2
- package/src/ReactAutoCompleteTableView.tsx +262 -164
- package/src/commontypes.ts +5 -0
- package/src/dropdownFilterTabs.tsx +100 -56
- package/src/index.tsx +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import React, { useCallback, useEffect, useRef, useState } from
|
|
2
|
-
import { FieldErrors } from
|
|
1
|
+
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
|
+
import { FieldErrors } from 'react-hook-form';
|
|
3
3
|
|
|
4
|
-
import CustomIcons from
|
|
5
|
-
import Spinner from
|
|
6
|
-
import Portal from
|
|
7
|
-
import { debounce } from
|
|
8
|
-
import { applyPositionClass } from
|
|
9
|
-
import { DropArrow } from
|
|
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 =
|
|
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 ===
|
|
136
|
-
typeof subString ===
|
|
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,
|
|
154
|
+
((checkArrayContains(checkParams, 'param1') &&
|
|
152
155
|
checkIncludesIfExists(param1, subString)) ||
|
|
153
|
-
(checkArrayContains(checkParams,
|
|
156
|
+
(checkArrayContains(checkParams, 'param2') &&
|
|
154
157
|
checkIncludesIfExists(param2, subString)) ||
|
|
155
|
-
(checkArrayContains(checkParams,
|
|
158
|
+
(checkArrayContains(checkParams, 'param3') &&
|
|
156
159
|
checkIncludesIfExists(param3, subString)) ||
|
|
157
|
-
(checkArrayContains(checkParams,
|
|
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
|
|
165
|
-
return
|
|
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:
|
|
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:
|
|
188
|
-
if (value.trim() ===
|
|
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 ===
|
|
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
|
|
226
|
+
} else {
|
|
227
|
+
handlePickSuggestions(value);
|
|
228
|
+
}
|
|
224
229
|
} else if (
|
|
225
|
-
(type ===
|
|
230
|
+
(type === 'custom_select' || type === 'custom_search_select') &&
|
|
226
231
|
(!data || data?.length === 0)
|
|
227
232
|
) {
|
|
228
233
|
handlePickSuggestions();
|
|
229
|
-
} else if (type ===
|
|
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 ===
|
|
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(
|
|
317
|
+
document.addEventListener('click', handleClickOutside);
|
|
305
318
|
return () => {
|
|
306
|
-
document.removeEventListener(
|
|
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 ===
|
|
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 !==
|
|
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
|
-
|
|
346
|
-
|
|
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(
|
|
385
|
+
window.addEventListener('scroll', handleScroll);
|
|
362
386
|
|
|
363
|
-
const mainElement = document.querySelector(
|
|
364
|
-
mainElement?.addEventListener(
|
|
387
|
+
const mainElement = document.querySelector('main');
|
|
388
|
+
mainElement?.addEventListener('scroll', handleScroll);
|
|
365
389
|
|
|
366
390
|
const gridElements = document.querySelectorAll(
|
|
367
|
-
|
|
391
|
+
'.k-grid-content, .overflow-auto, .overflow-y-auto, .overflow-x-auto'
|
|
368
392
|
);
|
|
369
393
|
gridElements.forEach((gridElement: any) => {
|
|
370
|
-
gridElement.addEventListener(
|
|
394
|
+
gridElement.addEventListener('scroll', handleScroll);
|
|
371
395
|
});
|
|
372
396
|
|
|
373
|
-
window.addEventListener(
|
|
397
|
+
window.addEventListener('resize', getDropPosition);
|
|
374
398
|
getDropPosition();
|
|
375
399
|
return () => {
|
|
376
|
-
window.removeEventListener(
|
|
377
|
-
const mainElement = document.querySelector(
|
|
378
|
-
mainElement?.removeEventListener(
|
|
379
|
-
window.addEventListener(
|
|
380
|
-
const gridElements = document.querySelectorAll(
|
|
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(
|
|
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:
|
|
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:
|
|
442
|
+
type: 'input' | 'label' | 'message' | 'adorement'
|
|
416
443
|
): string => {
|
|
417
444
|
let className = propsClassName;
|
|
418
445
|
switch (type) {
|
|
419
|
-
case
|
|
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
|
-
?
|
|
423
|
-
:
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
?
|
|
442
|
-
:
|
|
468
|
+
? 'cursor-pointer'
|
|
469
|
+
: 'cursor-text peer-focus:cursor-pointer'
|
|
443
470
|
} ${
|
|
444
471
|
isDisabled && !checkIsEmptyField()
|
|
445
|
-
?
|
|
472
|
+
? 'disabled-input-label-bg'
|
|
446
473
|
: !isDisabled || !checkIsEmptyField()
|
|
447
|
-
?
|
|
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
|
-
?
|
|
452
|
-
:
|
|
478
|
+
? 'cursor-pointer'
|
|
479
|
+
: 'cursor-text peer-focus:cursor-pointer'
|
|
453
480
|
}
|
|
454
481
|
${
|
|
455
482
|
checkIsEmptyField()
|
|
456
|
-
?
|
|
457
|
-
:
|
|
483
|
+
? 'modern-input-label-size'
|
|
484
|
+
: 'modern-input-peer-focus-label-size'
|
|
458
485
|
}`;
|
|
459
486
|
if (errors && errors[name]) {
|
|
460
|
-
className +=
|
|
487
|
+
className += ' text-error-light ';
|
|
461
488
|
} else {
|
|
462
|
-
className +=
|
|
489
|
+
className += ' text-grey-dark peer-focus:text-blue-navy';
|
|
463
490
|
}
|
|
464
491
|
break;
|
|
465
|
-
case
|
|
466
|
-
className =
|
|
492
|
+
case 'message':
|
|
493
|
+
className = ' text-error-icon ';
|
|
467
494
|
break;
|
|
468
|
-
case
|
|
469
|
-
className +=
|
|
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 !==
|
|
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]) ===
|
|
513
|
-
getErrors(data[name]) ===
|
|
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
|
|
620
|
+
left,
|
|
539
621
|
top,
|
|
540
622
|
bottom,
|
|
541
|
-
width
|
|
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 ===
|
|
652
|
+
e.key === 'ArrowDown'
|
|
571
653
|
? (selectedIndex + 1) % filteredData.length
|
|
572
|
-
: e.key ===
|
|
654
|
+
: e.key === 'ArrowUp'
|
|
573
655
|
? (selectedIndex - 1 + filteredData.length) % filteredData.length
|
|
574
656
|
: selectedIndex;
|
|
575
|
-
|
|
657
|
+
|
|
576
658
|
switch (e.key) {
|
|
577
|
-
case
|
|
578
|
-
case
|
|
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
|
|
686
|
+
|
|
687
|
+
case 'Enter':
|
|
606
688
|
e.preventDefault();
|
|
607
689
|
handleSuggestionClick(filteredData[selectedIndex], selectedIndex);
|
|
608
690
|
break;
|
|
609
|
-
|
|
610
|
-
case
|
|
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(
|
|
703
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
622
704
|
return () => {
|
|
623
|
-
window.removeEventListener(
|
|
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
|
-
?
|
|
734
|
+
? 'bg-blue-navy text-white'
|
|
653
735
|
: `${
|
|
654
|
-
index === selectedIndex ?
|
|
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 =
|
|
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) ===
|
|
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(
|
|
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(
|
|
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 ?
|
|
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 ?
|
|
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 ===
|
|
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(
|
|
956
|
+
className={` ${generateClassName('input')}`}
|
|
876
957
|
onChange={handleChange}
|
|
877
958
|
placeholder={
|
|
878
|
-
type ===
|
|
959
|
+
type === 'auto_complete'
|
|
879
960
|
? placeholder && isCustomPlaceholder
|
|
880
961
|
? placeholder
|
|
881
|
-
:
|
|
882
|
-
: placeholder ??
|
|
962
|
+
: 'Type to search'
|
|
963
|
+
: placeholder ?? '--Select--'
|
|
883
964
|
}
|
|
884
965
|
onFocus={onInputFocus}
|
|
885
966
|
onClick={(e) => {
|
|
886
|
-
if (type ===
|
|
967
|
+
if (type === 'custom_select') {
|
|
887
968
|
setDropOpen(!dropOpen);
|
|
888
969
|
handleOpen(e);
|
|
889
970
|
} else {
|
|
890
|
-
|
|
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(
|
|
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
|
-
|
|
910
|
-
)} qbs-autocomplete-adorement
|
|
911
|
-
isLoading ?
|
|
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 !==
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
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
|
|
950
|
-
|
|
1047
|
+
className={` text-error-label relative cursor-pointer ${generateClassName(
|
|
1048
|
+
'message'
|
|
951
1049
|
)}`}
|
|
952
1050
|
onMouseEnter={() => setIsHovered(true)}
|
|
953
1051
|
onMouseLeave={() => setIsHovered(false)}
|