@sproutsocial/seeds-react-menu 1.17.0 → 1.18.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/.turbo/turbo-build.log +14 -22
- package/CHANGELOG.md +30 -0
- package/dist/esm/index.js +542 -229
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v3/index.js +793 -1038
- package/dist/esm/v3/index.js.map +1 -1
- package/dist/v3/index.d.mts +64 -38
- package/dist/v3/index.d.ts +64 -38
- package/dist/v3/index.js +813 -1058
- package/dist/v3/index.js.map +1 -1
- package/dist/v3/menu.css +947 -0
- package/package.json +20 -21
- package/src/v3/ActionMenuStyles.tsx +169 -149
- package/src/v3/Common/ComboboxStyles.tsx +396 -511
- package/src/v3/Common/SelectIcons.tsx +17 -8
- package/src/v3/Common/SelectItem.tsx +25 -38
- package/src/v3/Common/SelectStyles.tsx +146 -144
- package/src/v3/Common/cn.ts +38 -0
- package/src/v3/MenuButtonStyles.tsx +55 -34
- package/src/v3/MultiSearchableSelect.tsx +8 -8
- package/src/v3/MultiSelect.tsx +11 -16
- package/src/v3/SingleSelect.tsx +13 -13
- package/src/v3/menu.css +947 -0
- package/tsup.config.ts +0 -1
- package/dist/esm/chunk-ROQATIB7.js +0 -357
- package/dist/esm/chunk-ROQATIB7.js.map +0 -1
- package/dist/esm/v2/index.js +0 -2089
- package/dist/esm/v2/index.js.map +0 -1
- package/dist/v2/index.d.mts +0 -108
- package/dist/v2/index.d.ts +0 -108
- package/dist/v2/index.js +0 -2280
- package/dist/v2/index.js.map +0 -1
- package/src/v2/Autocomplete/Autocomplete.stories.tsx +0 -645
- package/src/v2/Autocomplete/MultiAutocomplete.tsx +0 -487
- package/src/v2/Autocomplete/SingleAutocomplete.tsx +0 -366
- package/src/v2/Autocomplete/index.ts +0 -2
- package/src/v2/Common-V2/ComboboxContent.tsx +0 -457
- package/src/v2/Common-V2/MenuGroup.tsx +0 -60
- package/src/v2/Common-V2/MenuGroupTypes.ts +0 -30
- package/src/v2/Common-V2/MenuHeading.tsx +0 -83
- package/src/v2/Common-V2/MenuItem.tsx +0 -138
- package/src/v2/Common-V2/Popout.tsx +0 -124
- package/src/v2/Common-V2/PopoutTypes.tsx +0 -109
- package/src/v2/Common-V2/SelectToggleButton.tsx +0 -99
- package/src/v2/Common-V2/index.ts +0 -11
- package/src/v2/Common-V2/props.ts +0 -84
- package/src/v2/Common-V2/styles.tsx +0 -41
- package/src/v2/Common-V2/types.ts +0 -16
- package/src/v2/Common-V2/useHighlightedIndex.ts +0 -62
- package/src/v2/Common-V2/utils.ts +0 -238
- package/src/v2/SearchableSelect/AutocompleteContent.tsx +0 -325
- package/src/v2/SearchableSelect/SearchableMultiSelect.tsx +0 -527
- package/src/v2/SearchableSelect/SearchableSelect.tsx +0 -395
- package/src/v2/SearchableSelect/index.ts +0 -12
- package/src/v2/Select/MultiSelect.tsx +0 -417
- package/src/v2/Select/Select.stories.tsx +0 -593
- package/src/v2/Select/SingleSelect.tsx +0 -285
- package/src/v2/Select/index.ts +0 -2
- package/src/v2/index.ts +0 -2
|
@@ -1,527 +0,0 @@
|
|
|
1
|
-
import { useState, useMemo } from "react";
|
|
2
|
-
import { useCombobox, useMultipleSelection } from "downshift";
|
|
3
|
-
import type { ReactNode } from "react";
|
|
4
|
-
import { Label } from "@sproutsocial/seeds-react-label";
|
|
5
|
-
import { Input } from "@sproutsocial/seeds-react-input";
|
|
6
|
-
// This will eventually be imported from seeds-react-popout
|
|
7
|
-
import { Popout, SelectToggleButton } from "../Common-V2";
|
|
8
|
-
import {
|
|
9
|
-
VirtualizedAutocompleteContent,
|
|
10
|
-
NonVirtualizedAutocompleteContent,
|
|
11
|
-
} from "./AutocompleteContent";
|
|
12
|
-
import {
|
|
13
|
-
isGroupHeading,
|
|
14
|
-
isToggleItem,
|
|
15
|
-
menuAnimationConfig,
|
|
16
|
-
getFilteredItems,
|
|
17
|
-
groupItemsWithHeadings,
|
|
18
|
-
useHighlightedIndex,
|
|
19
|
-
createItemToStringForDownshift,
|
|
20
|
-
} from "../Common-V2";
|
|
21
|
-
import {
|
|
22
|
-
type DataWithId,
|
|
23
|
-
type GroupedItem,
|
|
24
|
-
type ToggleItem,
|
|
25
|
-
type GroupHeading,
|
|
26
|
-
type BaseMultiAutocompleteProps,
|
|
27
|
-
} from "../Common-V2";
|
|
28
|
-
|
|
29
|
-
function defaultReducer(state, actionAndChanges) {
|
|
30
|
-
const { changes, type } = actionAndChanges;
|
|
31
|
-
|
|
32
|
-
switch (type) {
|
|
33
|
-
case useCombobox.stateChangeTypes.InputKeyDownEnter:
|
|
34
|
-
case useCombobox.stateChangeTypes.ItemClick:
|
|
35
|
-
// If the item is already selected, don't set highlighted index to 0
|
|
36
|
-
// We don't have access to selectedItems in the reducer
|
|
37
|
-
return {
|
|
38
|
-
...changes,
|
|
39
|
-
isOpen: true, // keep the menu open after selection.
|
|
40
|
-
highlightedIndex: 0, // with the first option highlighted.
|
|
41
|
-
};
|
|
42
|
-
default:
|
|
43
|
-
return changes;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
export interface SearchableMultiSelectProps<T extends DataWithId>
|
|
48
|
-
extends BaseMultiAutocompleteProps<T> {
|
|
49
|
-
renderSelections?: (items: T[]) => ReactNode;
|
|
50
|
-
name: string;
|
|
51
|
-
triggerButtonProps?: any;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function SearchableMultiSelect<T extends DataWithId>({
|
|
55
|
-
id,
|
|
56
|
-
data,
|
|
57
|
-
selectedItemIds: controlledSelectedItemIds,
|
|
58
|
-
inputValue: controlledInputValue,
|
|
59
|
-
isOpen: controlledIsOpen,
|
|
60
|
-
itemToKey = (item: T) => item?.id,
|
|
61
|
-
itemToString,
|
|
62
|
-
itemToSearchString,
|
|
63
|
-
renderSelections,
|
|
64
|
-
renderItem,
|
|
65
|
-
groupBy,
|
|
66
|
-
renderGroupHeading,
|
|
67
|
-
isVirtualized = false,
|
|
68
|
-
showSelectedItems = false,
|
|
69
|
-
selectHeadings = false,
|
|
70
|
-
selectAllItem,
|
|
71
|
-
EmptyState,
|
|
72
|
-
name,
|
|
73
|
-
placeholder,
|
|
74
|
-
onSelectedItemIdsChange,
|
|
75
|
-
onInputValueChange,
|
|
76
|
-
onIsOpenChange,
|
|
77
|
-
stateReducer = defaultReducer,
|
|
78
|
-
triggerButtonProps,
|
|
79
|
-
onPointerDownOutside,
|
|
80
|
-
onInteractOutside,
|
|
81
|
-
popoutPlacement,
|
|
82
|
-
}: SearchableMultiSelectProps<T>) {
|
|
83
|
-
const [uncontrolledInputValue, setUncontrolledInputValue] =
|
|
84
|
-
useState<string>("");
|
|
85
|
-
const [uncontrolledSelectedItemIds, setUncontrolledSelectedItemIds] =
|
|
86
|
-
useState<T["id"][]>([]);
|
|
87
|
-
const [uncontrolledIsOpen, setUncontrolledIsOpen] = useState<boolean>(false);
|
|
88
|
-
|
|
89
|
-
// Use controlled selectedItemIds if provided, otherwise use internal state
|
|
90
|
-
const isSelectedItemIdsControlled = controlledSelectedItemIds !== undefined;
|
|
91
|
-
const selectedItemIds = isSelectedItemIdsControlled
|
|
92
|
-
? controlledSelectedItemIds
|
|
93
|
-
: uncontrolledSelectedItemIds;
|
|
94
|
-
|
|
95
|
-
// Convert selectedItemIds to selectedItems for internal use
|
|
96
|
-
const selectedItems = useMemo<T[]>(() => {
|
|
97
|
-
return data.filter((item) => selectedItemIds.includes(itemToKey(item)));
|
|
98
|
-
}, [selectedItemIds, data, itemToKey]);
|
|
99
|
-
|
|
100
|
-
// Use controlled inputValue if provided, otherwise use internal state
|
|
101
|
-
const isInputValueControlled = controlledInputValue !== undefined;
|
|
102
|
-
const inputValue = isInputValueControlled
|
|
103
|
-
? controlledInputValue
|
|
104
|
-
: uncontrolledInputValue;
|
|
105
|
-
|
|
106
|
-
// Use controlled isOpen if provided, otherwise use internal state
|
|
107
|
-
const isIsOpenControlled = controlledIsOpen !== undefined;
|
|
108
|
-
const isOpen = isIsOpenControlled ? controlledIsOpen : uncontrolledIsOpen;
|
|
109
|
-
|
|
110
|
-
const updateSelectedItems = (newSelectedItems: T[]) => {
|
|
111
|
-
const newSelectedItemIds = newSelectedItems.map((item) => itemToKey(item));
|
|
112
|
-
if (!isSelectedItemIdsControlled) {
|
|
113
|
-
setUncontrolledSelectedItemIds(newSelectedItemIds);
|
|
114
|
-
}
|
|
115
|
-
onSelectedItemIdsChange?.(newSelectedItemIds);
|
|
116
|
-
};
|
|
117
|
-
|
|
118
|
-
const updateInputValue = (newInputValue: string) => {
|
|
119
|
-
if (!isInputValueControlled) {
|
|
120
|
-
setUncontrolledInputValue(newInputValue);
|
|
121
|
-
}
|
|
122
|
-
onInputValueChange?.(newInputValue);
|
|
123
|
-
};
|
|
124
|
-
|
|
125
|
-
const updateIsOpen = (newIsOpen: boolean) => {
|
|
126
|
-
if (!isIsOpenControlled) {
|
|
127
|
-
setUncontrolledIsOpen(newIsOpen);
|
|
128
|
-
}
|
|
129
|
-
onIsOpenChange?.(newIsOpen);
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
// Use itemToSearchString if provided, otherwise fallback to itemToString
|
|
133
|
-
const searchStringFn =
|
|
134
|
-
itemToSearchString ?? ((item: T) => itemToString(item));
|
|
135
|
-
|
|
136
|
-
const filteredItems = useMemo<T[]>(
|
|
137
|
-
() =>
|
|
138
|
-
getFilteredItems(data, inputValue, searchStringFn, itemToString, {
|
|
139
|
-
selectedItems,
|
|
140
|
-
showSelectedItems,
|
|
141
|
-
}),
|
|
142
|
-
[
|
|
143
|
-
data,
|
|
144
|
-
selectedItems,
|
|
145
|
-
inputValue,
|
|
146
|
-
searchStringFn,
|
|
147
|
-
showSelectedItems,
|
|
148
|
-
itemToString,
|
|
149
|
-
]
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
const items = useMemo<GroupedItem<T>[]>(() => {
|
|
153
|
-
let groupedItems: GroupedItem<T>[];
|
|
154
|
-
|
|
155
|
-
if (groupBy) {
|
|
156
|
-
// Group first, then add selectAllItem at the beginning
|
|
157
|
-
groupedItems = groupItemsWithHeadings(filteredItems, groupBy, data);
|
|
158
|
-
} else {
|
|
159
|
-
groupedItems = filteredItems;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Add selectAllItem at the beginning if provided
|
|
163
|
-
if (selectAllItem) {
|
|
164
|
-
return [selectAllItem, ...groupedItems];
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
return groupedItems;
|
|
168
|
-
}, [filteredItems, groupBy, selectAllItem, data]);
|
|
169
|
-
|
|
170
|
-
// Handler for heading clicks - selects/deselects all items in a group
|
|
171
|
-
const handleHeadingClick = useMemo(() => {
|
|
172
|
-
if (!selectHeadings || !groupBy) {
|
|
173
|
-
return undefined;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return (groupLabel: string, allSelected: boolean) => {
|
|
177
|
-
// Find all items in this group from the full data array
|
|
178
|
-
const groupItems = data.filter((item) => groupBy(item) === groupLabel);
|
|
179
|
-
|
|
180
|
-
if (allSelected) {
|
|
181
|
-
// Deselect all items in the group
|
|
182
|
-
const newSelectedItems = selectedItems.filter(
|
|
183
|
-
(item) => !groupItems.includes(item)
|
|
184
|
-
);
|
|
185
|
-
updateSelectedItems(newSelectedItems);
|
|
186
|
-
} else {
|
|
187
|
-
// Select all items in the group (add them if not already selected)
|
|
188
|
-
const newSelectedItems = [...selectedItems];
|
|
189
|
-
for (const groupItem of groupItems) {
|
|
190
|
-
if (!newSelectedItems.includes(groupItem)) {
|
|
191
|
-
newSelectedItems.push(groupItem);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
updateSelectedItems(newSelectedItems);
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
}, [selectHeadings, groupBy, data, selectedItems, updateSelectedItems]);
|
|
198
|
-
|
|
199
|
-
const { getSelectedItemProps, getDropdownProps, removeSelectedItem } =
|
|
200
|
-
useMultipleSelection<T>({
|
|
201
|
-
selectedItems,
|
|
202
|
-
onStateChange({ selectedItems: newSelectedItems, type }) {
|
|
203
|
-
switch (type) {
|
|
204
|
-
case useMultipleSelection.stateChangeTypes
|
|
205
|
-
.SelectedItemKeyDownBackspace:
|
|
206
|
-
case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete:
|
|
207
|
-
case useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace:
|
|
208
|
-
case useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem:
|
|
209
|
-
if (newSelectedItems !== undefined) {
|
|
210
|
-
updateSelectedItems(newSelectedItems);
|
|
211
|
-
}
|
|
212
|
-
break;
|
|
213
|
-
default:
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
},
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
// Filter out headings for downshift unless selectHeadings is true
|
|
220
|
-
const itemsForCombobox = useMemo<(T | ToggleItem | GroupHeading)[]>(() => {
|
|
221
|
-
if (selectHeadings) {
|
|
222
|
-
// Include all items (headings, toggle items, and data items)
|
|
223
|
-
return items;
|
|
224
|
-
}
|
|
225
|
-
return items.filter(
|
|
226
|
-
(item): item is T | ToggleItem => !isGroupHeading(item)
|
|
227
|
-
);
|
|
228
|
-
}, [items, selectHeadings]);
|
|
229
|
-
|
|
230
|
-
// Wrapper function to handle ToggleItem and GroupHeading separately
|
|
231
|
-
const itemToStringForDownshift = useMemo(
|
|
232
|
-
() => createItemToStringForDownshift(itemToString),
|
|
233
|
-
[itemToString]
|
|
234
|
-
);
|
|
235
|
-
|
|
236
|
-
const comboboxProps = useCombobox<T | ToggleItem | GroupHeading>({
|
|
237
|
-
inputId: id,
|
|
238
|
-
items: itemsForCombobox,
|
|
239
|
-
itemToString: itemToStringForDownshift,
|
|
240
|
-
defaultHighlightedIndex: 0,
|
|
241
|
-
selectedItem: null,
|
|
242
|
-
inputValue,
|
|
243
|
-
isOpen,
|
|
244
|
-
stateReducer,
|
|
245
|
-
onStateChange({
|
|
246
|
-
inputValue: newInputValue,
|
|
247
|
-
type,
|
|
248
|
-
selectedItem: newSelectedItem,
|
|
249
|
-
isOpen: newIsOpen,
|
|
250
|
-
}) {
|
|
251
|
-
// Handle isOpen changes for any state change type
|
|
252
|
-
if (
|
|
253
|
-
newIsOpen !== undefined &&
|
|
254
|
-
type !== useCombobox.stateChangeTypes.InputBlur
|
|
255
|
-
) {
|
|
256
|
-
updateIsOpen(newIsOpen);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
switch (type) {
|
|
260
|
-
case useCombobox.stateChangeTypes.InputKeyDownEnter:
|
|
261
|
-
case useCombobox.stateChangeTypes.ItemClick:
|
|
262
|
-
if (newSelectedItem) {
|
|
263
|
-
// Handle selectAllItem selection
|
|
264
|
-
if (
|
|
265
|
-
selectAllItem &&
|
|
266
|
-
isToggleItem(newSelectedItem) &&
|
|
267
|
-
newSelectedItem.id === selectAllItem.id
|
|
268
|
-
) {
|
|
269
|
-
// Check if all items are selected (excluding selectAllItem itself)
|
|
270
|
-
const allSelected =
|
|
271
|
-
data.length > 0 &&
|
|
272
|
-
data.every((item) => selectedItems.includes(item));
|
|
273
|
-
if (allSelected) {
|
|
274
|
-
// Deselect all items
|
|
275
|
-
updateSelectedItems([]);
|
|
276
|
-
} else {
|
|
277
|
-
// Select all items
|
|
278
|
-
updateSelectedItems([...data]);
|
|
279
|
-
}
|
|
280
|
-
updateInputValue("");
|
|
281
|
-
} else if (
|
|
282
|
-
selectHeadings &&
|
|
283
|
-
groupBy &&
|
|
284
|
-
isGroupHeading(newSelectedItem)
|
|
285
|
-
) {
|
|
286
|
-
// Handle heading selection - select/deselect all items in the group
|
|
287
|
-
const groupLabel = newSelectedItem.label;
|
|
288
|
-
const groupItems = data.filter(
|
|
289
|
-
(item) => groupBy(item) === groupLabel
|
|
290
|
-
);
|
|
291
|
-
const allSelected =
|
|
292
|
-
groupItems.length > 0 &&
|
|
293
|
-
groupItems.every((item) => selectedItems.includes(item));
|
|
294
|
-
|
|
295
|
-
if (allSelected) {
|
|
296
|
-
// Deselect all items in the group
|
|
297
|
-
updateSelectedItems(
|
|
298
|
-
selectedItems.filter((item) => !groupItems.includes(item))
|
|
299
|
-
);
|
|
300
|
-
} else {
|
|
301
|
-
// Select all items in the group
|
|
302
|
-
const newItems = [
|
|
303
|
-
...selectedItems.filter((item) => !groupItems.includes(item)),
|
|
304
|
-
...groupItems,
|
|
305
|
-
];
|
|
306
|
-
updateSelectedItems(newItems);
|
|
307
|
-
}
|
|
308
|
-
updateInputValue("");
|
|
309
|
-
} else if (
|
|
310
|
-
!isGroupHeading(newSelectedItem) &&
|
|
311
|
-
!isToggleItem(newSelectedItem)
|
|
312
|
-
) {
|
|
313
|
-
// Only handle regular data items
|
|
314
|
-
const itemIndex = selectedItems.findIndex(
|
|
315
|
-
(item) => itemToKey(item) === itemToKey(newSelectedItem as T)
|
|
316
|
-
);
|
|
317
|
-
if (itemIndex >= 0) {
|
|
318
|
-
updateSelectedItems(
|
|
319
|
-
selectedItems.filter((_, index) => index !== itemIndex)
|
|
320
|
-
);
|
|
321
|
-
} else {
|
|
322
|
-
updateSelectedItems([...selectedItems, newSelectedItem as T]);
|
|
323
|
-
}
|
|
324
|
-
updateInputValue("");
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
break;
|
|
328
|
-
|
|
329
|
-
case useCombobox.stateChangeTypes.InputChange:
|
|
330
|
-
updateInputValue(newInputValue ?? "");
|
|
331
|
-
break;
|
|
332
|
-
|
|
333
|
-
default:
|
|
334
|
-
break;
|
|
335
|
-
}
|
|
336
|
-
},
|
|
337
|
-
});
|
|
338
|
-
const {
|
|
339
|
-
isOpen: comboboxIsOpen,
|
|
340
|
-
getLabelProps,
|
|
341
|
-
getMenuProps,
|
|
342
|
-
getInputProps,
|
|
343
|
-
highlightedIndex: comboboxHighlightedIndex,
|
|
344
|
-
getItemProps,
|
|
345
|
-
} = comboboxProps;
|
|
346
|
-
|
|
347
|
-
// Map the highlighted index from combobox (which only knows about items) to the full items array (which includes headings)
|
|
348
|
-
const highlightedIndex = useHighlightedIndex(
|
|
349
|
-
items,
|
|
350
|
-
itemsForCombobox,
|
|
351
|
-
comboboxHighlightedIndex,
|
|
352
|
-
!!groupBy,
|
|
353
|
-
selectHeadings ?? false
|
|
354
|
-
);
|
|
355
|
-
|
|
356
|
-
const buttonContent = renderSelections
|
|
357
|
-
? renderSelections(selectedItems)
|
|
358
|
-
: selectedItems.length > 0
|
|
359
|
-
? selectedItems.map((item) => itemToString(item)).join(", ")
|
|
360
|
-
: placeholder;
|
|
361
|
-
|
|
362
|
-
// Handle button click to toggle popout
|
|
363
|
-
const handleButtonClick = () => {
|
|
364
|
-
updateIsOpen(!comboboxIsOpen);
|
|
365
|
-
};
|
|
366
|
-
|
|
367
|
-
return (
|
|
368
|
-
<Popout
|
|
369
|
-
open={comboboxIsOpen}
|
|
370
|
-
onOpenChange={updateIsOpen}
|
|
371
|
-
side={popoutPlacement}
|
|
372
|
-
animationConfig={menuAnimationConfig}
|
|
373
|
-
onOpenAutoFocus={(e) => {
|
|
374
|
-
// Prevent default auto-focus behavior - we'll focus the input manually
|
|
375
|
-
e.preventDefault();
|
|
376
|
-
// Focus the input when popout opens
|
|
377
|
-
const inputElement = document.querySelector(
|
|
378
|
-
`input[name="${name}"]`
|
|
379
|
-
) as HTMLInputElement;
|
|
380
|
-
if (inputElement) {
|
|
381
|
-
setTimeout(() => {
|
|
382
|
-
inputElement.focus();
|
|
383
|
-
}, 0);
|
|
384
|
-
}
|
|
385
|
-
}}
|
|
386
|
-
onCloseAutoFocus={(e) => {
|
|
387
|
-
// Prevent default auto-focus behavior
|
|
388
|
-
e.preventDefault();
|
|
389
|
-
}}
|
|
390
|
-
onPointerDownOutside={onPointerDownOutside}
|
|
391
|
-
onInteractOutside={onInteractOutside}
|
|
392
|
-
content={
|
|
393
|
-
<div>
|
|
394
|
-
{/* Input inside the Popout */}
|
|
395
|
-
<div style={{ marginBottom: "8px" }}>
|
|
396
|
-
{(() => {
|
|
397
|
-
const inputProps = getInputProps(
|
|
398
|
-
getDropdownProps({ preventKeyAction: isOpen })
|
|
399
|
-
);
|
|
400
|
-
const { ref, id, ...restProps } = inputProps as any;
|
|
401
|
-
return (
|
|
402
|
-
<Input
|
|
403
|
-
id={id}
|
|
404
|
-
name={name}
|
|
405
|
-
inputProps={{
|
|
406
|
-
...restProps,
|
|
407
|
-
autoComplete: "off", // Override with "off" to prevent browser autocomplete
|
|
408
|
-
}}
|
|
409
|
-
innerRef={ref}
|
|
410
|
-
placeholder={placeholder}
|
|
411
|
-
/>
|
|
412
|
-
);
|
|
413
|
-
})()}
|
|
414
|
-
</div>
|
|
415
|
-
{/* Menu inside the Popout */}
|
|
416
|
-
{isVirtualized ? (
|
|
417
|
-
<VirtualizedAutocompleteContent
|
|
418
|
-
items={items}
|
|
419
|
-
getMenuProps={getMenuProps}
|
|
420
|
-
getItemProps={(props: { index: number }) => {
|
|
421
|
-
// Only apply getItemProps to actual items, not headings or ToggleItems
|
|
422
|
-
const item = items[props.index];
|
|
423
|
-
if (isGroupHeading(item) && !selectHeadings) {
|
|
424
|
-
return {};
|
|
425
|
-
}
|
|
426
|
-
if (isToggleItem(item)) {
|
|
427
|
-
// Handle ToggleItem clicks manually
|
|
428
|
-
return {
|
|
429
|
-
onClick: () => {
|
|
430
|
-
const allSelected =
|
|
431
|
-
data.length > 0 &&
|
|
432
|
-
data.every((item) => selectedItems.includes(item));
|
|
433
|
-
if (allSelected) {
|
|
434
|
-
updateSelectedItems([]);
|
|
435
|
-
} else {
|
|
436
|
-
updateSelectedItems([...data]);
|
|
437
|
-
}
|
|
438
|
-
},
|
|
439
|
-
};
|
|
440
|
-
}
|
|
441
|
-
const dataItem = item as T;
|
|
442
|
-
// Find the index in itemsForCombobox
|
|
443
|
-
const itemIndex = itemsForCombobox.indexOf(dataItem);
|
|
444
|
-
if (itemIndex === -1) {
|
|
445
|
-
return {};
|
|
446
|
-
}
|
|
447
|
-
return getItemProps({ item: dataItem, index: itemIndex });
|
|
448
|
-
}}
|
|
449
|
-
selectedItems={selectedItems}
|
|
450
|
-
highlightedIndex={highlightedIndex ?? -1}
|
|
451
|
-
renderItem={renderItem}
|
|
452
|
-
renderGroupHeading={renderGroupHeading}
|
|
453
|
-
EmptyState={EmptyState}
|
|
454
|
-
itemToKey={itemToKey}
|
|
455
|
-
itemToString={itemToString}
|
|
456
|
-
inputType="checkbox"
|
|
457
|
-
selectHeadings={selectHeadings}
|
|
458
|
-
onHeadingClick={handleHeadingClick}
|
|
459
|
-
groupBy={groupBy}
|
|
460
|
-
allData={data}
|
|
461
|
-
selectAllItem={selectAllItem}
|
|
462
|
-
/>
|
|
463
|
-
) : (
|
|
464
|
-
<NonVirtualizedAutocompleteContent
|
|
465
|
-
items={items}
|
|
466
|
-
getMenuProps={getMenuProps}
|
|
467
|
-
getItemProps={(props: { index: number }) => {
|
|
468
|
-
// Only apply getItemProps to actual items, not headings or ToggleItems
|
|
469
|
-
const item = items[props.index];
|
|
470
|
-
if (isGroupHeading(item) && !selectHeadings) {
|
|
471
|
-
return {};
|
|
472
|
-
}
|
|
473
|
-
if (isToggleItem(item)) {
|
|
474
|
-
// Handle ToggleItem clicks manually
|
|
475
|
-
return {
|
|
476
|
-
onClick: () => {
|
|
477
|
-
const allSelected =
|
|
478
|
-
data.length > 0 &&
|
|
479
|
-
data.every((item) => selectedItems.includes(item));
|
|
480
|
-
if (allSelected) {
|
|
481
|
-
updateSelectedItems([]);
|
|
482
|
-
} else {
|
|
483
|
-
updateSelectedItems([...data]);
|
|
484
|
-
}
|
|
485
|
-
},
|
|
486
|
-
};
|
|
487
|
-
}
|
|
488
|
-
const dataItem = item as T;
|
|
489
|
-
// Find the index in itemsForCombobox
|
|
490
|
-
const itemIndex = itemsForCombobox.indexOf(dataItem);
|
|
491
|
-
if (itemIndex === -1) {
|
|
492
|
-
return {};
|
|
493
|
-
}
|
|
494
|
-
return getItemProps({ item: dataItem, index: itemIndex });
|
|
495
|
-
}}
|
|
496
|
-
selectedItems={selectedItems}
|
|
497
|
-
highlightedIndex={highlightedIndex ?? -1}
|
|
498
|
-
renderItem={renderItem}
|
|
499
|
-
renderGroupHeading={renderGroupHeading}
|
|
500
|
-
EmptyState={EmptyState}
|
|
501
|
-
itemToKey={itemToKey}
|
|
502
|
-
itemToString={itemToString}
|
|
503
|
-
inputType="checkbox"
|
|
504
|
-
selectHeadings={selectHeadings}
|
|
505
|
-
onHeadingClick={handleHeadingClick}
|
|
506
|
-
groupBy={groupBy}
|
|
507
|
-
allData={data}
|
|
508
|
-
selectAllItem={selectAllItem}
|
|
509
|
-
/>
|
|
510
|
-
)}
|
|
511
|
-
</div>
|
|
512
|
-
}
|
|
513
|
-
>
|
|
514
|
-
<div>
|
|
515
|
-
<SelectToggleButton
|
|
516
|
-
onClick={handleButtonClick}
|
|
517
|
-
{...triggerButtonProps}
|
|
518
|
-
name={name}
|
|
519
|
-
isOpen={comboboxIsOpen}
|
|
520
|
-
type="button"
|
|
521
|
-
>
|
|
522
|
-
{buttonContent}
|
|
523
|
-
</SelectToggleButton>
|
|
524
|
-
</div>
|
|
525
|
-
</Popout>
|
|
526
|
-
);
|
|
527
|
-
}
|