react-core-ts 1.9.17 → 2.0.0
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.d.ts +4 -0
- package/dist/AutoCompleteWithTabFilter.js +743 -0
- package/dist/AutoCompleteWithTabFilter.js.map +1 -0
- package/dist/ReactTextField.js +13 -8
- package/dist/ReactTextField.js.map +1 -1
- package/dist/commontypes.d.ts +14 -1
- package/dist/dropdownFilterTabs.d.ts +7 -0
- package/dist/dropdownFilterTabs.js +647 -0
- package/dist/dropdownFilterTabs.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/styles/components/autocomplete.css +18 -0
- package/dist/styles/components/selectedautocomplete.css +11 -0
- package/dist/utilities/icons.d.ts +1 -0
- package/dist/utilities/icons.js +6 -1
- package/dist/utilities/icons.js.map +1 -1
- package/docs/App.tsx +109 -8
- package/package.json +1 -1
- package/src/AutoCompleteWithTabFilter.tsx +1244 -0
- package/src/ReactTextField.tsx +23 -4
- package/src/commontypes.ts +15 -1
- package/src/dropdownFilterTabs.tsx +1002 -0
- package/src/index.tsx +1 -0
- package/src/styles/components/autocomplete.css +18 -0
- package/src/styles/components/selectedautocomplete.css +11 -0
- package/src/utilities/icons.tsx +10 -0
- package/dist/styles/styles/components/autocomplete.css +0 -699
- package/dist/styles/styles/components/selectedautocomplete.css +0 -168
- package/dist/styles/styles/components/tooltip.css +0 -497
- package/dist/styles/styles/components/treedropdown.css +0 -97
- package/dist/styles/styles/global.css +0 -8
|
@@ -0,0 +1,1002 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
forwardRef,
|
|
3
|
+
useCallback,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
10
|
+
import ReactDOM from 'react-dom';
|
|
11
|
+
|
|
12
|
+
import { AutoSuggestionInputProps, TabPops, ValueProps } from './commontypes';
|
|
13
|
+
import DropdownList from './components/DropdownList';
|
|
14
|
+
import { useSuggestions } from './utilities/autosuggestions';
|
|
15
|
+
import { debounce } from './utilities/debounce';
|
|
16
|
+
import { deepEqual } from './utilities/deepEqual';
|
|
17
|
+
import { filterSuggestions } from './utilities/filterSuggestions';
|
|
18
|
+
import { AllDropArrow, DropArrow, Search, Spinner } from './utilities/icons';
|
|
19
|
+
import { default as Tooltip } from './utilities/NewTooltip';
|
|
20
|
+
import { getKeyValue, safeToLowerString } from './utilities/getKeyValue';
|
|
21
|
+
|
|
22
|
+
const DropdownFilterTabs = forwardRef<
|
|
23
|
+
HTMLInputElement,
|
|
24
|
+
AutoSuggestionInputProps & {
|
|
25
|
+
dropdownRef?: React.RefObject<HTMLDivElement>;
|
|
26
|
+
open?: boolean;
|
|
27
|
+
}
|
|
28
|
+
>(
|
|
29
|
+
(
|
|
30
|
+
{
|
|
31
|
+
label,
|
|
32
|
+
onChange,
|
|
33
|
+
getData = async () => [],
|
|
34
|
+
data = [],
|
|
35
|
+
errors,
|
|
36
|
+
required = false,
|
|
37
|
+
name,
|
|
38
|
+
fullWidth = false,
|
|
39
|
+
placeholder,
|
|
40
|
+
id,
|
|
41
|
+
type = 'custom_select',
|
|
42
|
+
selectedItems: propsSeelctedItems = [],
|
|
43
|
+
readOnly = false,
|
|
44
|
+
disabled = false,
|
|
45
|
+
value,
|
|
46
|
+
searchValue: propsSearchValue = '',
|
|
47
|
+
isMultiple = false,
|
|
48
|
+
desc = 'name',
|
|
49
|
+
descId = 'id',
|
|
50
|
+
singleSelect,
|
|
51
|
+
className,
|
|
52
|
+
async = false,
|
|
53
|
+
paginationEnabled,
|
|
54
|
+
initialLoad = false,
|
|
55
|
+
actionLabel,
|
|
56
|
+
handleAction,
|
|
57
|
+
nextBlock,
|
|
58
|
+
notDataMessage,
|
|
59
|
+
initialDataMessage,
|
|
60
|
+
onFocus,
|
|
61
|
+
onSearchValueChange,
|
|
62
|
+
expandable = false,
|
|
63
|
+
textCount = 10,
|
|
64
|
+
itemCount = 1,
|
|
65
|
+
scrollRef,
|
|
66
|
+
countOnly = true,
|
|
67
|
+
typeOnlyFetch = false,
|
|
68
|
+
tab = [],
|
|
69
|
+
clearTabSwitch = false,
|
|
70
|
+
selectedRowLimit = 2,
|
|
71
|
+
topMargin = 0,
|
|
72
|
+
currentTab = 0,
|
|
73
|
+
selectedLabel = '',
|
|
74
|
+
viewMode = false,
|
|
75
|
+
handleUpdateParent,
|
|
76
|
+
shortCode = '',
|
|
77
|
+
labelCode = '',
|
|
78
|
+
tabInlineSearch = true,
|
|
79
|
+
matchFromStart = false,
|
|
80
|
+
autoDropdown = false,
|
|
81
|
+
enableSelectAll = false,
|
|
82
|
+
dropdownRef,
|
|
83
|
+
open = false,
|
|
84
|
+
},
|
|
85
|
+
ref
|
|
86
|
+
) => {
|
|
87
|
+
const selItemRef = useRef<HTMLDivElement>(null);
|
|
88
|
+
const itemsRef = useRef<HTMLDivElement>(null);
|
|
89
|
+
const dropdownSelectedRef = useRef<HTMLDivElement>(null);
|
|
90
|
+
const tabRef = useRef<HTMLUListElement>(null);
|
|
91
|
+
const dropLevelRef = useRef<string>('bottom');
|
|
92
|
+
// State Hooks Section
|
|
93
|
+
const [isInitialRender, setIsInitialRender] = useState(true);
|
|
94
|
+
const [inputValue, setInputValue] = useState<string>(value);
|
|
95
|
+
const [searchValue, setSearchValue] = useState<string>(propsSearchValue);
|
|
96
|
+
const [searchOldValue, setSearchOldValue] = useState<string>('');
|
|
97
|
+
const [nextPage, setNextPage] = useState<number | undefined>(1);
|
|
98
|
+
const [dropOpen, setDropOpen] = useState<boolean>(open);
|
|
99
|
+
const [selectedItems, setSelectedItems] = useState<ValueProps[]>([]);
|
|
100
|
+
const [showAllSelected, setShowAllSelected] = useState<boolean>(false);
|
|
101
|
+
const [selHeight, setSelHeight] = useState<number>(184);
|
|
102
|
+
const [expandArrowClick, setExpandArrowClick] = useState<
|
|
103
|
+
number | undefined
|
|
104
|
+
>(1);
|
|
105
|
+
const [visible, setVisible] = useState<boolean>(true);
|
|
106
|
+
const [activeTab, setActiveTab] = useState<number>(currentTab);
|
|
107
|
+
const [focusedIndex, setFocusedIndex] = useState(0);
|
|
108
|
+
const itemRefs = useRef<(HTMLDivElement | null)[]>([]);
|
|
109
|
+
// API call for suggestions through a custom hook
|
|
110
|
+
const inputRef = useRef(null);
|
|
111
|
+
const dropRef = useRef(null);
|
|
112
|
+
const inputSearchRef = useRef(null);
|
|
113
|
+
const dropBtnRef = useRef<HTMLButtonElement>(null);
|
|
114
|
+
useImperativeHandle(ref, () => inputRef.current);
|
|
115
|
+
const [dropdownStyle, setDropdownStyle] = useState({
|
|
116
|
+
top: 0,
|
|
117
|
+
left: 0,
|
|
118
|
+
width: 200,
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
const [selectAll, setSelectAll] = useState(false);
|
|
122
|
+
const [refetchData, setRefetchData] = useState(false);
|
|
123
|
+
const [allDataLoaded, setAllDataLoaded] = useState(false);
|
|
124
|
+
|
|
125
|
+
// Filter selected items based on current active tab
|
|
126
|
+
const currentTabId = tab.length > 0 ? tab[activeTab].id : undefined;
|
|
127
|
+
const filteredSelectedItems = useMemo(() => {
|
|
128
|
+
return selectedItems.filter(item => item.tabId === currentTabId);
|
|
129
|
+
}, [selectedItems, currentTabId]);
|
|
130
|
+
|
|
131
|
+
let originalOverflow = '';
|
|
132
|
+
let hasScrollbar = false;
|
|
133
|
+
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
setDropOpen(open);
|
|
136
|
+
}, [open]);
|
|
137
|
+
|
|
138
|
+
const adjustDropdownPosition = () => {
|
|
139
|
+
if (dropdownRef?.current) {
|
|
140
|
+
const inputRect = dropdownRef?.current?.getBoundingClientRect();
|
|
141
|
+
const dropdownPosition = {
|
|
142
|
+
left: inputRect.left + window.scrollX,
|
|
143
|
+
width: inputRect.width,
|
|
144
|
+
top: 0,
|
|
145
|
+
};
|
|
146
|
+
// Check if there's enough space below the input for the dropdown
|
|
147
|
+
const spaceBelow = window.innerHeight - inputRect.bottom;
|
|
148
|
+
const spaceAbove = inputRect.top + window.scrollY;
|
|
149
|
+
|
|
150
|
+
let dropdownHeight = viewMode ? 160 : 300; // Assume a fixed height or calculate based on content
|
|
151
|
+
const defaultHeight = 184;
|
|
152
|
+
|
|
153
|
+
if (countOnly) {
|
|
154
|
+
if (dropdownSelectedRef?.current)
|
|
155
|
+
dropdownHeight += dropdownSelectedRef?.current?.clientHeight;
|
|
156
|
+
}
|
|
157
|
+
if (tab.length > 0) {
|
|
158
|
+
if (tabRef?.current) dropdownHeight += tabRef?.current?.clientHeight;
|
|
159
|
+
}
|
|
160
|
+
if (spaceBelow >= dropdownHeight) {
|
|
161
|
+
dropLevelRef.current = 'bottom';
|
|
162
|
+
dropdownPosition.top =
|
|
163
|
+
inputRect.top + window.scrollY + inputRect.height;
|
|
164
|
+
|
|
165
|
+
setSelHeight(defaultHeight);
|
|
166
|
+
} else if (spaceAbove >= dropdownHeight) {
|
|
167
|
+
let sHeight = tabInlineSearch ? 73 : 113;
|
|
168
|
+
sHeight =
|
|
169
|
+
sHeight -
|
|
170
|
+
(filteredData?.length > 0 && enableSelectAll && isMultiple
|
|
171
|
+
? 32
|
|
172
|
+
: 0);
|
|
173
|
+
dropLevelRef.current = 'top';
|
|
174
|
+
dropdownPosition.top =
|
|
175
|
+
inputRect.top +
|
|
176
|
+
window.scrollY -
|
|
177
|
+
dropdownHeight +
|
|
178
|
+
sHeight +
|
|
179
|
+
topMargin;
|
|
180
|
+
|
|
181
|
+
setSelHeight(defaultHeight);
|
|
182
|
+
} else {
|
|
183
|
+
dropLevelRef.current = 'bottom';
|
|
184
|
+
dropdownPosition.top =
|
|
185
|
+
inputRect.top + window.scrollY + inputRect.height;
|
|
186
|
+
|
|
187
|
+
if (itemsRef?.current) {
|
|
188
|
+
const totalH = showAllSelected ? 148 : defaultHeight;
|
|
189
|
+
const selH = totalH - (dropdownHeight - spaceBelow);
|
|
190
|
+
setSelHeight(selH < 50 ? 50 : selH);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
// setDropdownStyle({
|
|
194
|
+
// ...dropdownPosition,
|
|
195
|
+
// });
|
|
196
|
+
setDropdownStyle((prevStyle) => ({
|
|
197
|
+
...prevStyle,
|
|
198
|
+
transform: `translateY(${dropdownPosition.top}px)`,
|
|
199
|
+
left: inputRect.left + window.scrollX,
|
|
200
|
+
width: inputRect.width,
|
|
201
|
+
}));
|
|
202
|
+
|
|
203
|
+
}
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
useEffect(() => {
|
|
207
|
+
window.addEventListener('resize', adjustDropdownPosition);
|
|
208
|
+
adjustDropdownPosition();
|
|
209
|
+
|
|
210
|
+
return () => {
|
|
211
|
+
window.removeEventListener('resize', adjustDropdownPosition);
|
|
212
|
+
};
|
|
213
|
+
}, [dropOpen, expandArrowClick]);
|
|
214
|
+
|
|
215
|
+
const { suggestions, isLoading, handlePickSuggestions, resetSuggections } =
|
|
216
|
+
useSuggestions(
|
|
217
|
+
getData,
|
|
218
|
+
data,
|
|
219
|
+
dropOpen,
|
|
220
|
+
async,
|
|
221
|
+
paginationEnabled,
|
|
222
|
+
initialLoad,
|
|
223
|
+
inputValue,
|
|
224
|
+
isMultiple,
|
|
225
|
+
setNextPage,
|
|
226
|
+
selectedItems,
|
|
227
|
+
typeOnlyFetch
|
|
228
|
+
// nextBlock
|
|
229
|
+
);
|
|
230
|
+
|
|
231
|
+
// Handling the selection of a suggestion
|
|
232
|
+
const handleSuggestionClick = useCallback(
|
|
233
|
+
(suggestion: ValueProps, idx: number) => {
|
|
234
|
+
if (isMultiple) {
|
|
235
|
+
setFocusedIndex(idx);
|
|
236
|
+
setSelectedItems((prev) => {
|
|
237
|
+
const isAdded =
|
|
238
|
+
prev && prev.length > 0
|
|
239
|
+
? prev.some(
|
|
240
|
+
(item) =>
|
|
241
|
+
getKeyValue(item, descId, 'id') ===
|
|
242
|
+
getKeyValue(suggestion, descId, 'id')
|
|
243
|
+
)
|
|
244
|
+
: false;
|
|
245
|
+
if (isAdded) {
|
|
246
|
+
return prev.filter(
|
|
247
|
+
(item) =>
|
|
248
|
+
getKeyValue(item, descId, 'id') !==
|
|
249
|
+
getKeyValue(suggestion, descId, 'id')
|
|
250
|
+
);
|
|
251
|
+
} else {
|
|
252
|
+
// Include tab ID when adding suggestion
|
|
253
|
+
const suggestionWithTabId = {
|
|
254
|
+
...suggestion,
|
|
255
|
+
tabId: tab.length > 0 ? tab[activeTab].id : undefined
|
|
256
|
+
};
|
|
257
|
+
return [...prev, suggestionWithTabId];
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
} else {
|
|
261
|
+
setFocusedIndex(idx);
|
|
262
|
+
setInputValue(String(suggestion[desc]));
|
|
263
|
+
setSearchValue('');
|
|
264
|
+
onChange(suggestion);
|
|
265
|
+
setDropOpen(false);
|
|
266
|
+
}
|
|
267
|
+
},
|
|
268
|
+
[activeTab, tab, descId, desc, onChange, isMultiple]
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
// Adding debounce to avoid making API calls on every keystroke
|
|
272
|
+
const debouncedUpdate = useCallback(
|
|
273
|
+
debounce((value: string, tabVal?: number | string) => {
|
|
274
|
+
setSearchOldValue(value);
|
|
275
|
+
handlePickSuggestions(value, 1, false, tabVal);
|
|
276
|
+
}, 500),
|
|
277
|
+
[]
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
const handleChangeWithDebounce = (value: string) => {
|
|
281
|
+
if ((type === 'auto_complete' || type === 'auto_suggestion') && async) {
|
|
282
|
+
const activeTabVal = tab.length > 0 ? tab?.[activeTab].id : undefined;
|
|
283
|
+
debouncedUpdate(value, activeTabVal);
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const handleMultiSelect = (e: any, suggestion: ValueProps) => {
|
|
288
|
+
const { checked } = e.target;
|
|
289
|
+
if (isMultiple) {
|
|
290
|
+
if (checked) {
|
|
291
|
+
// Include tab ID when adding suggestion
|
|
292
|
+
const suggestionWithTabId = {
|
|
293
|
+
...suggestion,
|
|
294
|
+
tabId: tab.length > 0 ? tab[activeTab].id : undefined
|
|
295
|
+
};
|
|
296
|
+
setSelectedItems((prev) => [...prev, suggestionWithTabId]);
|
|
297
|
+
} else {
|
|
298
|
+
setSelectedItems((prev) => {
|
|
299
|
+
return prev.filter(
|
|
300
|
+
(item, i) =>
|
|
301
|
+
getKeyValue(item, descId, 'id') !==
|
|
302
|
+
getKeyValue(suggestion, descId, 'id')
|
|
303
|
+
);
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
} else {
|
|
307
|
+
if (checked) {
|
|
308
|
+
setInputValue(String(suggestion[desc]));
|
|
309
|
+
onChange(suggestion);
|
|
310
|
+
} else {
|
|
311
|
+
setInputValue('');
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
useEffect(() => {
|
|
316
|
+
// Only update if different
|
|
317
|
+
if (!deepEqual(selectedItems, propsSeelctedItems)) {
|
|
318
|
+
setSelectedItems(propsSeelctedItems);
|
|
319
|
+
}
|
|
320
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
321
|
+
}, [propsSeelctedItems]);
|
|
322
|
+
// Effect to set the input value whenever `value` prop changes
|
|
323
|
+
useEffect(() => {
|
|
324
|
+
setInputValue(value ?? '');
|
|
325
|
+
}, [value]);
|
|
326
|
+
|
|
327
|
+
const handleSuggestionChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
328
|
+
const { value } = e.target;
|
|
329
|
+
//setVisibleDrop();
|
|
330
|
+
const trimStart = value.trimStart();
|
|
331
|
+
setSearchValue(trimStart);
|
|
332
|
+
handleChangeWithDebounce(trimStart);
|
|
333
|
+
setAllDataLoaded(false);
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
|
|
337
|
+
const handleClearSelected = () => {
|
|
338
|
+
// Only clear items from current tab
|
|
339
|
+
setSelectedItems((prev) => {
|
|
340
|
+
const remainingItems = prev.filter(item => item.tabId !== currentTabId);
|
|
341
|
+
return remainingItems;
|
|
342
|
+
});
|
|
343
|
+
setShowAllSelected(false);
|
|
344
|
+
if (searchValue && type === 'auto_suggestion' && tabInlineSearch) {
|
|
345
|
+
setSearchValue('');
|
|
346
|
+
}
|
|
347
|
+
if (async && type === 'auto_suggestion' && tabInlineSearch) resetSuggections?.();
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
const generateClassName = useCallback(() => {
|
|
351
|
+
return `qbs-textfield-default ${className} ${errors && errors?.message ? 'textfield-error' : 'textfield'
|
|
352
|
+
} ${expandable ? 'expandable' : ''}`;
|
|
353
|
+
}, [errors, name]);
|
|
354
|
+
const handleRemoveSelectedItem = useCallback((index: number) => {
|
|
355
|
+
const itemToRemove = filteredSelectedItems[index];
|
|
356
|
+
setSelectedItems((prev) => {
|
|
357
|
+
return prev.filter((item) =>
|
|
358
|
+
getKeyValue(item, descId, 'id') !== getKeyValue(itemToRemove, descId, 'id')
|
|
359
|
+
);
|
|
360
|
+
});
|
|
361
|
+
}, [filteredSelectedItems, descId]);
|
|
362
|
+
|
|
363
|
+
const uniqueDropArrowId = `${name}-drop-arrow-selected-list-icon`;
|
|
364
|
+
useEffect(() => {
|
|
365
|
+
const handleClickOutside = (event: any) => {
|
|
366
|
+
if (
|
|
367
|
+
dropRef.current &&
|
|
368
|
+
event.target instanceof Node &&
|
|
369
|
+
!dropRef.current.contains(event.target) &&
|
|
370
|
+
event.target?.id !== uniqueDropArrowId
|
|
371
|
+
) {
|
|
372
|
+
setTimeout(() => {
|
|
373
|
+
setDropOpen(false);
|
|
374
|
+
if (!typeOnlyFetch) setSearchValue('');
|
|
375
|
+
}, 200);
|
|
376
|
+
//setSearchValue("");
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
document.addEventListener('mousedown', handleClickOutside as any);
|
|
381
|
+
window.addEventListener('scroll', handleClickOutside as any);
|
|
382
|
+
|
|
383
|
+
const scrollableDivs = document.querySelectorAll(
|
|
384
|
+
'div[style*="overflow"], .overflow-auto, .overflow-y-auto, .overflow-x-auto'
|
|
385
|
+
);
|
|
386
|
+
scrollableDivs.forEach((div) =>
|
|
387
|
+
div.addEventListener('scroll', handleClickOutside as any)
|
|
388
|
+
);
|
|
389
|
+
if (scrollRef && scrollRef.current && scrollRef.current !== null) {
|
|
390
|
+
scrollRef.current.addEventListener('scroll', handleClickOutside as any);
|
|
391
|
+
}
|
|
392
|
+
return () => {
|
|
393
|
+
document.removeEventListener('mousedown', handleClickOutside as any);
|
|
394
|
+
window.removeEventListener('scroll', handleClickOutside as any);
|
|
395
|
+
scrollableDivs.forEach((div) =>
|
|
396
|
+
div.removeEventListener('scroll', handleClickOutside as any)
|
|
397
|
+
);
|
|
398
|
+
if (scrollRef && scrollRef.current && scrollRef.current !== null) {
|
|
399
|
+
scrollRef.current.removeEventListener(
|
|
400
|
+
'scroll',
|
|
401
|
+
handleClickOutside as any
|
|
402
|
+
);
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
}, []);
|
|
406
|
+
|
|
407
|
+
// Filtering suggestions based on type and search value
|
|
408
|
+
const selected: any = isMultiple ? selectedItems : inputValue;
|
|
409
|
+
const filteredData: ValueProps[] = filterSuggestions(
|
|
410
|
+
suggestions,
|
|
411
|
+
searchValue,
|
|
412
|
+
type,
|
|
413
|
+
desc,
|
|
414
|
+
selected,
|
|
415
|
+
async,
|
|
416
|
+
false,
|
|
417
|
+
true,
|
|
418
|
+
matchFromStart
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
const prevSelectedItemsRef = useRef<ValueProps[]>([]);
|
|
422
|
+
|
|
423
|
+
useEffect(() => {
|
|
424
|
+
if (isInitialRender) {
|
|
425
|
+
setIsInitialRender(false);
|
|
426
|
+
} else {
|
|
427
|
+
// Only call onChange if selectedItems actually changed
|
|
428
|
+
if (!deepEqual(selectedItems, prevSelectedItemsRef.current)) {
|
|
429
|
+
onChange(selectedItems);
|
|
430
|
+
prevSelectedItemsRef.current = selectedItems;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
adjustDropdownPosition();
|
|
434
|
+
setTimeout(() => {
|
|
435
|
+
adjustDropdownPosition();
|
|
436
|
+
}, 200);
|
|
437
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
438
|
+
}, [selectedItems]);
|
|
439
|
+
|
|
440
|
+
useEffect(() => {
|
|
441
|
+
adjustDropdownPosition();
|
|
442
|
+
setTimeout(() => {
|
|
443
|
+
adjustDropdownPosition();
|
|
444
|
+
}, 200);
|
|
445
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
446
|
+
}, [filteredData]);
|
|
447
|
+
|
|
448
|
+
useEffect(() => {
|
|
449
|
+
// Handle keyboard navigation
|
|
450
|
+
const handleKeyDown = (e: any) => {
|
|
451
|
+
if (!dropOpen) return;
|
|
452
|
+
|
|
453
|
+
const atBottom = focusedIndex === filteredData.length - 1;
|
|
454
|
+
const atTop = focusedIndex === 0;
|
|
455
|
+
switch (e.key) {
|
|
456
|
+
case 'ArrowDown':
|
|
457
|
+
e.preventDefault();
|
|
458
|
+
if (itemsRef.current) {
|
|
459
|
+
if (!atBottom) {
|
|
460
|
+
itemsRef.current.scrollTop +=
|
|
461
|
+
itemRefs.current[focusedIndex]?.offsetHeight || 50;
|
|
462
|
+
} else {
|
|
463
|
+
itemsRef.current.scrollTop = 0;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
setFocusedIndex((prev) => (prev + 1) % filteredData?.length);
|
|
467
|
+
break;
|
|
468
|
+
|
|
469
|
+
case 'ArrowUp':
|
|
470
|
+
e.preventDefault();
|
|
471
|
+
if (itemsRef.current) {
|
|
472
|
+
if (!atTop) {
|
|
473
|
+
itemsRef.current.scrollTop -=
|
|
474
|
+
itemRefs.current[focusedIndex]?.offsetHeight || 50;
|
|
475
|
+
} else {
|
|
476
|
+
itemsRef.current.scrollTop = 0;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
setFocusedIndex(
|
|
480
|
+
(prev) => (prev - 1 + filteredData?.length) % filteredData?.length
|
|
481
|
+
);
|
|
482
|
+
break;
|
|
483
|
+
|
|
484
|
+
case 'Enter':
|
|
485
|
+
e.preventDefault();
|
|
486
|
+
if (filteredData && filteredData.length > 0)
|
|
487
|
+
handleSuggestionClick(filteredData[focusedIndex], focusedIndex);
|
|
488
|
+
break;
|
|
489
|
+
|
|
490
|
+
case 'Escape':
|
|
491
|
+
e.preventDefault();
|
|
492
|
+
setDropOpen(false);
|
|
493
|
+
break;
|
|
494
|
+
|
|
495
|
+
default:
|
|
496
|
+
break;
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
window.addEventListener('keydown', handleKeyDown);
|
|
501
|
+
|
|
502
|
+
return () => {
|
|
503
|
+
window.removeEventListener('keydown', handleKeyDown);
|
|
504
|
+
};
|
|
505
|
+
}, [filteredData, dropOpen, isLoading, focusedIndex]);
|
|
506
|
+
|
|
507
|
+
const isSelected = (
|
|
508
|
+
item: ValueProps,
|
|
509
|
+
selectedItems: ValueProps[] | string
|
|
510
|
+
): boolean => {
|
|
511
|
+
if (Array.isArray(selectedItems)) {
|
|
512
|
+
return selectedItems.some(
|
|
513
|
+
(selectedItem) =>
|
|
514
|
+
getKeyValue(selectedItem, desc, 'name') === getKeyValue(item, desc, 'name') ||
|
|
515
|
+
getKeyValue(selectedItem, descId, 'id') === getKeyValue(item, descId, 'id')
|
|
516
|
+
);
|
|
517
|
+
} else {
|
|
518
|
+
return (
|
|
519
|
+
getKeyValue(item, desc, 'name') === safeToLowerString(selectedItems) ||
|
|
520
|
+
getKeyValue(item, descId, 'id') === safeToLowerString(selectedItems)
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
|
|
525
|
+
const handleLoadMore = () => {
|
|
526
|
+
if (paginationEnabled) {
|
|
527
|
+
handlePickSuggestions(searchValue, nextPage + 1, true);
|
|
528
|
+
setNextPage(nextPage + 1);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
const handleShowAllSelected = useCallback((enabled: boolean) => {
|
|
533
|
+
setExpandArrowClick(expandArrowClick + 1);
|
|
534
|
+
if (enabled) {
|
|
535
|
+
setShowAllSelected(true);
|
|
536
|
+
} else {
|
|
537
|
+
setShowAllSelected(false);
|
|
538
|
+
}
|
|
539
|
+
}, [expandArrowClick]);
|
|
540
|
+
|
|
541
|
+
const handleCollapseArrowClick = useCallback(() => {
|
|
542
|
+
setExpandArrowClick(expandArrowClick + 1);
|
|
543
|
+
setShowAllSelected(false);
|
|
544
|
+
}, [expandArrowClick]);
|
|
545
|
+
|
|
546
|
+
const tooltipContent =
|
|
547
|
+
filteredSelectedItems?.length > itemCount
|
|
548
|
+
? filteredSelectedItems
|
|
549
|
+
?.slice(itemCount)
|
|
550
|
+
.map((item) => item[desc])
|
|
551
|
+
.join(', ')
|
|
552
|
+
: '';
|
|
553
|
+
|
|
554
|
+
const handleTabClick = useCallback((index: number) => {
|
|
555
|
+
if (activeTab !== index) {
|
|
556
|
+
if (clearTabSwitch) {
|
|
557
|
+
handleClearSelected();
|
|
558
|
+
if (tabInlineSearch) {
|
|
559
|
+
setSearchValue('');
|
|
560
|
+
setInputValue('');
|
|
561
|
+
handlePickSuggestions('', 1);
|
|
562
|
+
} else {
|
|
563
|
+
resetSuggections?.();
|
|
564
|
+
const activeTabVal =
|
|
565
|
+
tab.length > 0 ? tab?.[index].id : undefined;
|
|
566
|
+
handlePickSuggestions(searchValue, 1, false, activeTabVal);
|
|
567
|
+
}
|
|
568
|
+
setAllDataLoaded(false);
|
|
569
|
+
} else {
|
|
570
|
+
resetSuggections?.();
|
|
571
|
+
const activeTabVal = tab.length > 0 ? tab?.[index].id : undefined;
|
|
572
|
+
handlePickSuggestions(searchValue, 1, false, activeTabVal);
|
|
573
|
+
}
|
|
574
|
+
setActiveTab(index);
|
|
575
|
+
}
|
|
576
|
+
}, [activeTab, clearTabSwitch, handleClearSelected, tabInlineSearch, tab, searchValue, handlePickSuggestions, resetSuggections]);
|
|
577
|
+
|
|
578
|
+
const getSelectedRowLimit = useCallback(() => {
|
|
579
|
+
let maxHeight = 36;
|
|
580
|
+
if (selItemRef?.current && selItemRef?.current.clientWidth < 300) {
|
|
581
|
+
maxHeight = 24;
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
return selectedRowLimit * maxHeight + 5;
|
|
585
|
+
}, [selectedRowLimit]);
|
|
586
|
+
const getSelectedItems = useCallback((dropdown: boolean) => {
|
|
587
|
+
return (
|
|
588
|
+
<div
|
|
589
|
+
ref={selItemRef}
|
|
590
|
+
className="selected-items-outer-container"
|
|
591
|
+
style={{ maxHeight: `${getSelectedRowLimit()}px` }}
|
|
592
|
+
>
|
|
593
|
+
{filteredSelectedItems
|
|
594
|
+
.slice(
|
|
595
|
+
0,
|
|
596
|
+
filteredSelectedItems?.length > itemCount
|
|
597
|
+
? showAllSelected
|
|
598
|
+
? filteredSelectedItems?.length
|
|
599
|
+
: itemCount
|
|
600
|
+
: filteredSelectedItems?.length
|
|
601
|
+
)
|
|
602
|
+
.map((item, index) => (
|
|
603
|
+
<div key={index} className="selected-items-container">
|
|
604
|
+
<Tooltip
|
|
605
|
+
title={item?.[desc]}
|
|
606
|
+
enabled={String(item?.[desc])?.length > textCount}
|
|
607
|
+
>
|
|
608
|
+
<div key={item.id} className="selected-item">
|
|
609
|
+
{String(item?.[desc])?.length > textCount
|
|
610
|
+
? `${String(item?.[desc]).substring(0, textCount)}...`
|
|
611
|
+
: item?.[desc]}
|
|
612
|
+
{!viewMode && (
|
|
613
|
+
<button
|
|
614
|
+
onClick={() => handleRemoveSelectedItem(index)}
|
|
615
|
+
className="remove-item-btn"
|
|
616
|
+
aria-label={`Remove ${item?.[desc]}`}
|
|
617
|
+
>
|
|
618
|
+
X
|
|
619
|
+
</button>
|
|
620
|
+
)}
|
|
621
|
+
</div>
|
|
622
|
+
</Tooltip>
|
|
623
|
+
</div>
|
|
624
|
+
))}
|
|
625
|
+
{filteredSelectedItems?.length > itemCount && !showAllSelected && (
|
|
626
|
+
<div className="selected-items-container">
|
|
627
|
+
<Tooltip title={tooltipContent} enabled={true}>
|
|
628
|
+
<div
|
|
629
|
+
className={`selected-item-more qbs-rounded-full qbs-min-h-6 qbs-min-w-6 qbs-p-1 ${dropdown ? 'qbs-cursor-pointer' : ''
|
|
630
|
+
}`}
|
|
631
|
+
onClick={() => {
|
|
632
|
+
handleShowAllSelected(dropdown);
|
|
633
|
+
}}
|
|
634
|
+
>
|
|
635
|
+
+{filteredSelectedItems?.length - itemCount}{' '}
|
|
636
|
+
<span className="qbs-hidden">more</span>
|
|
637
|
+
</div>
|
|
638
|
+
</Tooltip>
|
|
639
|
+
</div>
|
|
640
|
+
)}
|
|
641
|
+
</div>
|
|
642
|
+
);
|
|
643
|
+
}, [filteredSelectedItems, getSelectedRowLimit, itemCount, showAllSelected, desc, textCount, viewMode, handleRemoveSelectedItem, tooltipContent, handleShowAllSelected]);
|
|
644
|
+
|
|
645
|
+
// Check if any items are selected under a specific tab
|
|
646
|
+
const hasSelectedItemsInTab = useCallback((tabIndex: number) => {
|
|
647
|
+
const tabId = tab.length > 0 ? tab[tabIndex].id : undefined;
|
|
648
|
+
return selectedItems.some(item => item.tabId === tabId);
|
|
649
|
+
}, [selectedItems, tab]);
|
|
650
|
+
|
|
651
|
+
const getTabItems = useCallback(() => {
|
|
652
|
+
return (
|
|
653
|
+
<ul
|
|
654
|
+
className="qbs-flex qbs-flex-wrap qbs-w-full qbs-tab qbs-mb-2 -qbs-mt-2"
|
|
655
|
+
ref={tabRef}
|
|
656
|
+
>
|
|
657
|
+
{tab.map((item: TabPops, idx: number) => {
|
|
658
|
+
const hasSelectedItems = hasSelectedItemsInTab(idx);
|
|
659
|
+
return (
|
|
660
|
+
<li
|
|
661
|
+
className={`qbs-flex-1 qbs-tab-items ${hasSelectedItems ? 'qbs-tab-has-selected-items' : ''}`}
|
|
662
|
+
key={`tab-${idx}`}
|
|
663
|
+
>
|
|
664
|
+
<span
|
|
665
|
+
className={`qbs-inline-block qbs-tab-item qbs-text-sm qbs-cursor-pointer qbs-w-full qbs-text-center qbs-p-1 qbs-border-b-2 ${activeTab === idx ? 'qbs-tab-active-item' : ''
|
|
666
|
+
}`}
|
|
667
|
+
onClick={() => {
|
|
668
|
+
handleTabClick(idx);
|
|
669
|
+
}}
|
|
670
|
+
>
|
|
671
|
+
{item.label}
|
|
672
|
+
</span>
|
|
673
|
+
</li>
|
|
674
|
+
);
|
|
675
|
+
})}
|
|
676
|
+
</ul>
|
|
677
|
+
);
|
|
678
|
+
}, [tab, hasSelectedItemsInTab, activeTab, handleTabClick]);
|
|
679
|
+
|
|
680
|
+
const handleSelectAll = useCallback(() => {
|
|
681
|
+
if (isMultiple) {
|
|
682
|
+
if (selectAll) {
|
|
683
|
+
// Remove only items from current tab
|
|
684
|
+
setSelectedItems((prev) =>
|
|
685
|
+
prev.filter(
|
|
686
|
+
(item) =>
|
|
687
|
+
item.tabId !== currentTabId ||
|
|
688
|
+
!filteredData.some(
|
|
689
|
+
(f) =>
|
|
690
|
+
getKeyValue(f, descId, 'id') === getKeyValue(item, descId, 'id')
|
|
691
|
+
)
|
|
692
|
+
)
|
|
693
|
+
);
|
|
694
|
+
} else {
|
|
695
|
+
// Add only items from current tab - batch all updates in single setState
|
|
696
|
+
setSelectedItems((prev) => {
|
|
697
|
+
const newItems: ValueProps[] = [];
|
|
698
|
+
const currentTabId = tab.length > 0 ? tab[activeTab].id : undefined;
|
|
699
|
+
|
|
700
|
+
filteredData.forEach((suggestion: ValueProps) => {
|
|
701
|
+
const isAdded = prev.some(
|
|
702
|
+
(item) =>
|
|
703
|
+
getKeyValue(item, descId, 'id') ===
|
|
704
|
+
getKeyValue(suggestion, descId, 'id')
|
|
705
|
+
);
|
|
706
|
+
if (!isAdded) {
|
|
707
|
+
// Include tab ID when adding suggestion
|
|
708
|
+
const suggestionWithTabId = {
|
|
709
|
+
...suggestion,
|
|
710
|
+
tabId: currentTabId
|
|
711
|
+
};
|
|
712
|
+
newItems.push(suggestionWithTabId);
|
|
713
|
+
}
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
return [...prev, ...newItems];
|
|
717
|
+
});
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}, [isMultiple, selectAll, currentTabId, filteredData, descId, tab, activeTab]);
|
|
721
|
+
|
|
722
|
+
const handleOpenDropdown = (e: any) => {
|
|
723
|
+
if (!suggestions || suggestions?.length === 0 || refetchData) {
|
|
724
|
+
if (autoDropdown && (inputValue === '' || inputValue.trim() === '')) {
|
|
725
|
+
if (tabInlineSearch && tab.length > 0) {
|
|
726
|
+
const activeTabVal =
|
|
727
|
+
tab.length > 0 ? tab?.[activeTab].id : undefined;
|
|
728
|
+
handlePickSuggestions('*', 1, false, activeTabVal);
|
|
729
|
+
} else {
|
|
730
|
+
handlePickSuggestions('*', 1);
|
|
731
|
+
}
|
|
732
|
+
setRefetchData(false);
|
|
733
|
+
setAllDataLoaded(true);
|
|
734
|
+
} else if (!refetchData && inputValue !== '') {
|
|
735
|
+
if (tabInlineSearch && tab.length > 0) {
|
|
736
|
+
const activeTabVal =
|
|
737
|
+
tab.length > 0 ? tab?.[activeTab].id : undefined;
|
|
738
|
+
handlePickSuggestions(inputValue, 1, false, activeTabVal);
|
|
739
|
+
} else {
|
|
740
|
+
handlePickSuggestions(inputValue, 1);
|
|
741
|
+
}
|
|
742
|
+
setRefetchData(true);
|
|
743
|
+
setAllDataLoaded(false);
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
useEffect(() => {
|
|
749
|
+
const allSelected =
|
|
750
|
+
filteredData?.length > 0 && filteredSelectedItems?.length > 0 &&
|
|
751
|
+
filteredData.every((item) =>
|
|
752
|
+
filteredSelectedItems?.some(
|
|
753
|
+
(s) =>
|
|
754
|
+
getKeyValue(s, descId, 'id') === getKeyValue(item, descId, 'id')
|
|
755
|
+
)
|
|
756
|
+
);
|
|
757
|
+
|
|
758
|
+
setSelectAll(allSelected);
|
|
759
|
+
}, [filteredData, filteredSelectedItems, descId]);
|
|
760
|
+
|
|
761
|
+
useEffect(() => {
|
|
762
|
+
handleUpdateParent?.(dropOpen, dropLevelRef.current);
|
|
763
|
+
}, [dropOpen, dropLevelRef.current]);
|
|
764
|
+
|
|
765
|
+
// Auto-focus search input when dropdown opens with tabInlineSearch
|
|
766
|
+
useEffect(() => {
|
|
767
|
+
if (dropOpen && visible && tabInlineSearch && type === 'auto_suggestion' && !expandable) {
|
|
768
|
+
// Small delay to ensure the dropdown is fully rendered
|
|
769
|
+
setTimeout(() => {
|
|
770
|
+
if (inputSearchRef.current) {
|
|
771
|
+
inputSearchRef.current.focus();
|
|
772
|
+
}
|
|
773
|
+
}, 50);
|
|
774
|
+
}
|
|
775
|
+
}, [dropOpen, visible, tabInlineSearch, type, expandable]);
|
|
776
|
+
|
|
777
|
+
return (
|
|
778
|
+
<>
|
|
779
|
+
{dropOpen &&
|
|
780
|
+
ReactDOM.createPortal(
|
|
781
|
+
<div
|
|
782
|
+
ref={dropRef}
|
|
783
|
+
style={{
|
|
784
|
+
...dropdownStyle,
|
|
785
|
+
minHeight: viewMode ? 100 : 192,
|
|
786
|
+
visibility: visible ? 'visible' : 'hidden',
|
|
787
|
+
opacity: visible ? 1 : 0,
|
|
788
|
+
transition: 'opacity 0.2s ease-in-out',
|
|
789
|
+
}}
|
|
790
|
+
className={`qbs-autocomplete-suggestions qbs-autocomplete-selected-suggestions ${viewMode ? 'qbs-dropdown-selected-preview' : ''
|
|
791
|
+
} ${viewMode && filteredSelectedItems?.length === 0 ? 'hidden' : ''}`}
|
|
792
|
+
>
|
|
793
|
+
{!viewMode && (
|
|
794
|
+
<>
|
|
795
|
+
<>{tab.length > 0 && getTabItems()}</>
|
|
796
|
+
{type === 'auto_suggestion' &&
|
|
797
|
+
!expandable &&
|
|
798
|
+
tabInlineSearch && (
|
|
799
|
+
<div
|
|
800
|
+
style={{ position: 'relative' }}
|
|
801
|
+
className="react-core-ts-search-container qbs-autocomplete-selected-suggestions-outer"
|
|
802
|
+
>
|
|
803
|
+
<span className="dropdown-search-icon">
|
|
804
|
+
<Search />
|
|
805
|
+
</span>
|
|
806
|
+
<input
|
|
807
|
+
className="dropdown-search-input"
|
|
808
|
+
onChange={handleSuggestionChange}
|
|
809
|
+
value={searchValue}
|
|
810
|
+
placeholder="Type to search"
|
|
811
|
+
autoComplete="off"
|
|
812
|
+
ref={inputSearchRef}
|
|
813
|
+
/>
|
|
814
|
+
|
|
815
|
+
<>
|
|
816
|
+
{autoDropdown && !disabled && !readOnly && (
|
|
817
|
+
<button
|
|
818
|
+
disabled={disabled ?? readOnly}
|
|
819
|
+
onClick={(e) => handleOpenDropdown(e)}
|
|
820
|
+
className="text-[#667085] focus-visible:outline-slate-100 absolute right-2 qbs-all-dropdown-btn"
|
|
821
|
+
data-testid="drop-arrow"
|
|
822
|
+
type="button"
|
|
823
|
+
id="autocomplete-drop-icon"
|
|
824
|
+
ref={dropBtnRef}
|
|
825
|
+
>
|
|
826
|
+
<AllDropArrow
|
|
827
|
+
type={!allDataLoaded ? 'down' : 'up'}
|
|
828
|
+
uniqueId="all-dropdow-arrow-icon"
|
|
829
|
+
className="all-dropdow-arrow-icon"
|
|
830
|
+
/>
|
|
831
|
+
</button>
|
|
832
|
+
)}
|
|
833
|
+
</>
|
|
834
|
+
</div>
|
|
835
|
+
)}
|
|
836
|
+
</>
|
|
837
|
+
)}
|
|
838
|
+
|
|
839
|
+
{filteredData?.length > 0 && enableSelectAll && isMultiple && (
|
|
840
|
+
<div
|
|
841
|
+
id="select-all"
|
|
842
|
+
className={`qbs-select-all-link qbs-cursor-pointer qbs-text-xs`}
|
|
843
|
+
onClick={handleSelectAll}
|
|
844
|
+
>
|
|
845
|
+
<div
|
|
846
|
+
className={`qbs-autocomplete-listitem-container qbs-autocomplete-checkbox-container`}
|
|
847
|
+
>
|
|
848
|
+
<div className="qbs-autocomplete-checkbox">
|
|
849
|
+
<input
|
|
850
|
+
type="checkbox"
|
|
851
|
+
checked={selectAll}
|
|
852
|
+
id={`qbs-checkbox-all`}
|
|
853
|
+
/>
|
|
854
|
+
<label htmlFor={`qbs-checkbox-all`}>
|
|
855
|
+
<svg
|
|
856
|
+
width="8"
|
|
857
|
+
height="6"
|
|
858
|
+
viewBox="0 0 8 6"
|
|
859
|
+
fill="none"
|
|
860
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
861
|
+
>
|
|
862
|
+
<path
|
|
863
|
+
d="M0 3.21739L2.89883 6L8 1.06994L6.89494 0L2.89883 3.86768L1.09728 2.14745L0 3.21739Z"
|
|
864
|
+
fill="white"
|
|
865
|
+
/>
|
|
866
|
+
</svg>
|
|
867
|
+
</label>
|
|
868
|
+
</div>
|
|
869
|
+
<div className={`qbs-autocomplete-suggestions-item`}>
|
|
870
|
+
Select All
|
|
871
|
+
</div>
|
|
872
|
+
</div>
|
|
873
|
+
</div>
|
|
874
|
+
)}
|
|
875
|
+
|
|
876
|
+
<div
|
|
877
|
+
className={`qbs-autocomplete-suggestions-sub qbs-autocomplete-selected-suggestions-outer ${viewMode ? 'hidden' : ''
|
|
878
|
+
}`}
|
|
879
|
+
ref={itemsRef}
|
|
880
|
+
style={{
|
|
881
|
+
maxHeight: `${selHeight}px`,
|
|
882
|
+
minHeight: `${selHeight}px`,
|
|
883
|
+
}}
|
|
884
|
+
>
|
|
885
|
+
{filteredData?.length > 0 ? (
|
|
886
|
+
filteredData.map((suggestion: ValueProps, idx: number) => (
|
|
887
|
+
<DropdownList
|
|
888
|
+
idx={idx}
|
|
889
|
+
suggestion={suggestion}
|
|
890
|
+
isSelected={isSelected}
|
|
891
|
+
handleSuggestionClick={() =>
|
|
892
|
+
handleSuggestionClick(suggestion, idx)
|
|
893
|
+
}
|
|
894
|
+
handleMultiSelect={handleMultiSelect}
|
|
895
|
+
selected={selected}
|
|
896
|
+
isMultiple={isMultiple}
|
|
897
|
+
singleSelect={singleSelect}
|
|
898
|
+
desc={desc}
|
|
899
|
+
key={suggestion[descId]}
|
|
900
|
+
shortCode={shortCode}
|
|
901
|
+
labelCode={labelCode}
|
|
902
|
+
focusedIndex={focusedIndex}
|
|
903
|
+
setItemRef={(index, ref) => {
|
|
904
|
+
itemRefs.current[index] = ref; // Store each ref properly
|
|
905
|
+
}}
|
|
906
|
+
/>
|
|
907
|
+
))
|
|
908
|
+
) : (
|
|
909
|
+
<>
|
|
910
|
+
{isLoading ||
|
|
911
|
+
(searchValue !== searchOldValue &&
|
|
912
|
+
searchValue !== '' &&
|
|
913
|
+
async) ? (
|
|
914
|
+
<div className="qbs-flex qbs-align-middle qbs-justify-center qbs-min-emp-h">
|
|
915
|
+
<div className="qbs-pt-16 qbs-autocomplete-loader">
|
|
916
|
+
<Spinner />
|
|
917
|
+
</div>
|
|
918
|
+
</div>
|
|
919
|
+
) : (
|
|
920
|
+
<div className="qbs-autocomplete-notfound qbs-text-center qbs-justify-center qbs-align-middle qbs-min-emp-h">
|
|
921
|
+
{searchValue !== ''
|
|
922
|
+
? notDataMessage ?? 'No Results Found'
|
|
923
|
+
: initialDataMessage ?? 'Type to search'}
|
|
924
|
+
</div>
|
|
925
|
+
)}
|
|
926
|
+
</>
|
|
927
|
+
)}
|
|
928
|
+
{paginationEnabled &&
|
|
929
|
+
nextBlock !== 0 &&
|
|
930
|
+
nextBlock !== undefined &&
|
|
931
|
+
filteredData?.length > 0 && (
|
|
932
|
+
<div
|
|
933
|
+
className="loadMoreSection"
|
|
934
|
+
onClick={() => handleLoadMore()}
|
|
935
|
+
>
|
|
936
|
+
<p style={{ margin: 2 }}>Load More</p>
|
|
937
|
+
</div>
|
|
938
|
+
)}
|
|
939
|
+
</div>
|
|
940
|
+
<>
|
|
941
|
+
{countOnly && filteredSelectedItems?.length > 0 && (
|
|
942
|
+
<>
|
|
943
|
+
<div
|
|
944
|
+
className={`qbs-expandable-container qbs-dropdown-selected-container`}
|
|
945
|
+
ref={dropdownSelectedRef}
|
|
946
|
+
>
|
|
947
|
+
<div className={`qbs-flex qbs-w-full qbs-text-xs`}>
|
|
948
|
+
<div className="qbs-selected-lbs qbs-flex-grow">
|
|
949
|
+
Selected Items
|
|
950
|
+
</div>
|
|
951
|
+
<div
|
|
952
|
+
className={`qbs-clear-link qbs-text-right qbs-cursor-pointer ${viewMode ? 'hidden' : ''
|
|
953
|
+
}`}
|
|
954
|
+
onClick={handleClearSelected}
|
|
955
|
+
>
|
|
956
|
+
Clear all
|
|
957
|
+
</div>
|
|
958
|
+
<div
|
|
959
|
+
className={`qbs-done-link qbs-text-right qbs-cursor-pointer ${viewMode ? 'hidden' : ''
|
|
960
|
+
}`}
|
|
961
|
+
onClick={() => {
|
|
962
|
+
setDropOpen(false);
|
|
963
|
+
}}
|
|
964
|
+
>
|
|
965
|
+
Done
|
|
966
|
+
</div>
|
|
967
|
+
</div>
|
|
968
|
+
|
|
969
|
+
{getSelectedItems(true)}
|
|
970
|
+
|
|
971
|
+
<>
|
|
972
|
+
{filteredSelectedItems?.length > itemCount &&
|
|
973
|
+
showAllSelected && (
|
|
974
|
+
<div className="qbs-readmore-collapse">
|
|
975
|
+
<div
|
|
976
|
+
className="qbs-more-collapse"
|
|
977
|
+
onClick={() => {
|
|
978
|
+
handleCollapseArrowClick();
|
|
979
|
+
}}
|
|
980
|
+
>
|
|
981
|
+
<DropArrow
|
|
982
|
+
className={`icon-button-rotate`}
|
|
983
|
+
uniqueDropArrowId={uniqueDropArrowId}
|
|
984
|
+
/>
|
|
985
|
+
</div>
|
|
986
|
+
</div>
|
|
987
|
+
)}
|
|
988
|
+
</>
|
|
989
|
+
</div>
|
|
990
|
+
</>
|
|
991
|
+
)}
|
|
992
|
+
</>
|
|
993
|
+
</div>,
|
|
994
|
+
document.body
|
|
995
|
+
)}
|
|
996
|
+
</>
|
|
997
|
+
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
);
|
|
1001
|
+
|
|
1002
|
+
export default React.memo(DropdownFilterTabs);
|