@sproutsocial/seeds-react-menu 1.16.16 → 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 +51 -0
- package/dist/esm/index.js +542 -229
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v3/index.js +870 -1081
- package/dist/esm/v3/index.js.map +1 -1
- package/dist/v3/index.d.mts +82 -38
- package/dist/v3/index.d.ts +82 -38
- package/dist/v3/index.js +887 -1098
- package/dist/v3/index.js.map +1 -1
- package/dist/v3/menu.css +947 -0
- package/package.json +20 -21
- package/src/ActionMenu/ActionMenu.stories.tsx +1 -1
- package/src/Autocomplete/Autocomplete.stories.tsx +1 -1
- package/src/MenuContent/MenuContent.stories.tsx +1 -1
- package/src/MenuFooter/MenuFooter.stories.tsx +1 -1
- package/src/MenuGroup/MenuGroup.stories.tsx +1 -1
- package/src/MenuHeader/MenuHeader.stories.tsx +1 -1
- package/src/MenuItem/MenuItem.stories.tsx +1 -1
- package/src/MenuToggleButton/MenuToggleButton.stories.tsx +1 -1
- package/src/MultiSelectMenu/MultiSelectMenu.stories.tsx +1 -1
- package/src/NestedMenu/NestedMenu.stories.tsx +1 -1
- package/src/SingleSelectMenu/SingleSelectMenu.stories.tsx +1 -1
- package/src/SubmenuItem/SubmenuItem.stories.tsx +1 -1
- package/src/v3/ActionMenu.stories.tsx +1 -1
- 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/MenuButton.stories.tsx +1 -1
- package/src/v3/MenuButtonStyles.tsx +55 -34
- package/src/v3/ModalStories.stories.tsx +1 -1
- package/src/v3/MultiCombobox.stories.tsx +1 -1
- package/src/v3/MultiCombobox.tsx +7 -0
- package/src/v3/MultiSearchableSelect.stories.tsx +1 -1
- package/src/v3/MultiSearchableSelect.tsx +15 -8
- package/src/v3/MultiSelect.stories.tsx +1 -1
- package/src/v3/MultiSelect.tsx +20 -17
- package/src/v3/SingleCombobox.stories.tsx +1 -1
- package/src/v3/SingleCombobox.tsx +7 -0
- package/src/v3/SingleSearchableSelect.stories.tsx +1 -1
- package/src/v3/SingleSearchableSelect.tsx +7 -0
- package/src/v3/SingleSelect.stories.tsx +1 -1
- package/src/v3/SingleSelect.tsx +22 -14
- package/src/v3/__tests__/ariaLabels.test.tsx +133 -0
- 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,417 +0,0 @@
|
|
|
1
|
-
import { useState, useMemo } from "react";
|
|
2
|
-
import { useSelect, useMultipleSelection } from "downshift";
|
|
3
|
-
import type { ReactNode } from "react";
|
|
4
|
-
import { Label } from "@sproutsocial/seeds-react-label";
|
|
5
|
-
// This will eventually be imported from seeds-react-popout
|
|
6
|
-
import { Popout } from "../Common-V2";
|
|
7
|
-
import {
|
|
8
|
-
isGroupHeading,
|
|
9
|
-
isToggleItem,
|
|
10
|
-
menuAnimationConfig,
|
|
11
|
-
groupItemsWithHeadings,
|
|
12
|
-
useHighlightedIndex,
|
|
13
|
-
createItemToStringForDownshift,
|
|
14
|
-
ComboboxContent,
|
|
15
|
-
SelectToggleButton,
|
|
16
|
-
} from "../Common-V2";
|
|
17
|
-
import {
|
|
18
|
-
type DataWithId,
|
|
19
|
-
type GroupedItem,
|
|
20
|
-
type ToggleItem,
|
|
21
|
-
type GroupHeading,
|
|
22
|
-
type BaseMultiSelectProps,
|
|
23
|
-
} from "../Common-V2";
|
|
24
|
-
|
|
25
|
-
function defaultReducer(state, actionAndChanges) {
|
|
26
|
-
const { changes, type } = actionAndChanges;
|
|
27
|
-
|
|
28
|
-
switch (type) {
|
|
29
|
-
case useSelect.stateChangeTypes.ItemClick:
|
|
30
|
-
// If the item is already selected, don't set highlighted index to 0
|
|
31
|
-
// We don't have access to selectedItems in the reducer
|
|
32
|
-
return {
|
|
33
|
-
...changes,
|
|
34
|
-
isOpen: true, // keep the menu open after selection.
|
|
35
|
-
highlightedIndex: 0, // with the first option highlighted.
|
|
36
|
-
};
|
|
37
|
-
default:
|
|
38
|
-
// For keyboard Enter/Space on menu items, keep menu open if an item is being selected
|
|
39
|
-
if (changes.selectedItem && changes.isOpen === false) {
|
|
40
|
-
return {
|
|
41
|
-
...changes,
|
|
42
|
-
isOpen: true, // keep the menu open after keyboard selection.
|
|
43
|
-
highlightedIndex: 0, // with the first option highlighted.
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
return changes;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export interface MultiSelectProps<T extends DataWithId>
|
|
51
|
-
extends BaseMultiSelectProps<T> {
|
|
52
|
-
renderSelections?: (items: T[]) => ReactNode;
|
|
53
|
-
triggerButtonProps?: any;
|
|
54
|
-
shouldOverflow?: boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function MultiSelect<T extends DataWithId>({
|
|
58
|
-
id,
|
|
59
|
-
data,
|
|
60
|
-
selectedItemIds: controlledSelectedItemIds,
|
|
61
|
-
isOpen: controlledIsOpen,
|
|
62
|
-
itemToKey = (item: T) => item?.id,
|
|
63
|
-
itemToString,
|
|
64
|
-
renderSelections,
|
|
65
|
-
renderItem,
|
|
66
|
-
groupBy,
|
|
67
|
-
renderGroupHeading,
|
|
68
|
-
isVirtualized = false,
|
|
69
|
-
estimatedItemHeight,
|
|
70
|
-
showSelectedItems = false,
|
|
71
|
-
selectHeadings = false,
|
|
72
|
-
selectAllItem,
|
|
73
|
-
placeholder,
|
|
74
|
-
onSelectedItemIdsChange,
|
|
75
|
-
onIsOpenChange,
|
|
76
|
-
stateReducer = defaultReducer,
|
|
77
|
-
triggerButtonProps,
|
|
78
|
-
menuProps,
|
|
79
|
-
inputType = "checkbox",
|
|
80
|
-
shouldOverflow,
|
|
81
|
-
onPointerDownOutside,
|
|
82
|
-
onInteractOutside,
|
|
83
|
-
popoutPlacement,
|
|
84
|
-
}: MultiSelectProps<T>) {
|
|
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 isOpen if provided, otherwise use internal state
|
|
101
|
-
const isIsOpenControlled = controlledIsOpen !== undefined;
|
|
102
|
-
const isOpen = isIsOpenControlled ? controlledIsOpen : uncontrolledIsOpen;
|
|
103
|
-
|
|
104
|
-
const updateSelectedItems = (newSelectedItems: T[]) => {
|
|
105
|
-
const newSelectedItemIds = newSelectedItems.map((item) => itemToKey(item));
|
|
106
|
-
if (!isSelectedItemIdsControlled) {
|
|
107
|
-
setUncontrolledSelectedItemIds(newSelectedItemIds);
|
|
108
|
-
}
|
|
109
|
-
onSelectedItemIdsChange?.(newSelectedItemIds);
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const updateIsOpen = (newIsOpen: boolean) => {
|
|
113
|
-
if (!isIsOpenControlled) {
|
|
114
|
-
setUncontrolledIsOpen(newIsOpen);
|
|
115
|
-
}
|
|
116
|
-
onIsOpenChange?.(newIsOpen);
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
// For Select, we show all items (no filtering)
|
|
120
|
-
// Filter out selected items if showSelectedItems is false
|
|
121
|
-
const filteredData = useMemo<T[]>(() => {
|
|
122
|
-
if (showSelectedItems) {
|
|
123
|
-
return data;
|
|
124
|
-
}
|
|
125
|
-
return data.filter((item) => !selectedItems.includes(item));
|
|
126
|
-
}, [data, selectedItems, showSelectedItems]);
|
|
127
|
-
|
|
128
|
-
const items = useMemo<GroupedItem<T>[]>(() => {
|
|
129
|
-
let groupedItems: GroupedItem<T>[];
|
|
130
|
-
|
|
131
|
-
if (groupBy) {
|
|
132
|
-
// Group first, then add selectAllItem at the beginning
|
|
133
|
-
groupedItems = groupItemsWithHeadings(filteredData, groupBy, data, true);
|
|
134
|
-
} else {
|
|
135
|
-
groupedItems = filteredData;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// Add selectAllItem at the beginning if provided
|
|
139
|
-
if (selectAllItem) {
|
|
140
|
-
return [selectAllItem, ...groupedItems];
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return groupedItems;
|
|
144
|
-
}, [filteredData, groupBy, data, selectAllItem, selectHeadings]);
|
|
145
|
-
|
|
146
|
-
// Handler for heading clicks - selects/deselects all items in a group
|
|
147
|
-
const handleHeadingClick = useMemo(() => {
|
|
148
|
-
if (!selectHeadings || !groupBy) {
|
|
149
|
-
return undefined;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return (groupLabel: string, allSelected: boolean) => {
|
|
153
|
-
// Find all items in this group from the full data array
|
|
154
|
-
const groupItems = data.filter((item) => groupBy(item) === groupLabel);
|
|
155
|
-
|
|
156
|
-
if (allSelected) {
|
|
157
|
-
// Deselect all items in the group
|
|
158
|
-
const newSelectedItems = selectedItems.filter(
|
|
159
|
-
(item) => !groupItems.includes(item)
|
|
160
|
-
);
|
|
161
|
-
updateSelectedItems(newSelectedItems);
|
|
162
|
-
} else {
|
|
163
|
-
// Select all items in the group (add them if not already selected)
|
|
164
|
-
const newSelectedItems = [...selectedItems];
|
|
165
|
-
for (const groupItem of groupItems) {
|
|
166
|
-
if (!newSelectedItems.includes(groupItem)) {
|
|
167
|
-
newSelectedItems.push(groupItem);
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
updateSelectedItems(newSelectedItems);
|
|
171
|
-
}
|
|
172
|
-
};
|
|
173
|
-
}, [selectHeadings, groupBy, data, selectedItems, updateSelectedItems]);
|
|
174
|
-
|
|
175
|
-
const { getSelectedItemProps, getDropdownProps, removeSelectedItem } =
|
|
176
|
-
useMultipleSelection<T>({
|
|
177
|
-
selectedItems,
|
|
178
|
-
onStateChange({ selectedItems: newSelectedItems, type }) {
|
|
179
|
-
switch (type) {
|
|
180
|
-
case useMultipleSelection.stateChangeTypes
|
|
181
|
-
.SelectedItemKeyDownBackspace:
|
|
182
|
-
case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete:
|
|
183
|
-
case useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace:
|
|
184
|
-
case useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem:
|
|
185
|
-
if (newSelectedItems !== undefined) {
|
|
186
|
-
updateSelectedItems(newSelectedItems);
|
|
187
|
-
}
|
|
188
|
-
break;
|
|
189
|
-
default:
|
|
190
|
-
break;
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
// Filter out headings for downshift unless selectHeadings is true
|
|
196
|
-
const itemsForSelect = useMemo<(T | ToggleItem | GroupHeading)[]>(() => {
|
|
197
|
-
if (selectHeadings) {
|
|
198
|
-
// Include all items (headings, toggle items, and data items)
|
|
199
|
-
return items;
|
|
200
|
-
}
|
|
201
|
-
return items.filter(
|
|
202
|
-
(item): item is T | ToggleItem => !isGroupHeading(item)
|
|
203
|
-
);
|
|
204
|
-
}, [items, selectHeadings]);
|
|
205
|
-
|
|
206
|
-
// Wrapper function to handle ToggleItem and GroupHeading separately
|
|
207
|
-
const itemToStringForDownshift = useMemo(
|
|
208
|
-
() => createItemToStringForDownshift(itemToString),
|
|
209
|
-
[itemToString]
|
|
210
|
-
);
|
|
211
|
-
|
|
212
|
-
const selectProps = useSelect<T | ToggleItem | GroupHeading>({
|
|
213
|
-
toggleButtonId: id,
|
|
214
|
-
items: itemsForSelect,
|
|
215
|
-
itemToString: itemToStringForDownshift,
|
|
216
|
-
// defaultHighlightedIndex: 0, // after selection, highlight the first item.
|
|
217
|
-
selectedItem: null,
|
|
218
|
-
isOpen,
|
|
219
|
-
stateReducer,
|
|
220
|
-
// Could maybe let devs override this too?
|
|
221
|
-
onStateChange({ type, selectedItem: newSelectedItem, isOpen: newIsOpen }) {
|
|
222
|
-
// Handle isOpen changes for any state change type
|
|
223
|
-
if (newIsOpen !== undefined) {
|
|
224
|
-
updateIsOpen(newIsOpen);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Handle item selection for both click and keyboard (Enter/Space) interactions
|
|
228
|
-
// When Enter/Space is pressed on a highlighted item, useSelect sets selectedItem
|
|
229
|
-
// We detect selection when selectedItem is set and menu is/was open
|
|
230
|
-
if (newSelectedItem && newSelectedItem !== null) {
|
|
231
|
-
// Check if this is a selection event (click or keyboard) and menu is open
|
|
232
|
-
const isSelectionEvent =
|
|
233
|
-
type === useSelect.stateChangeTypes.ItemClick ||
|
|
234
|
-
type === useSelect.stateChangeTypes.ToggleButtonKeyDownEnter;
|
|
235
|
-
|
|
236
|
-
if (isSelectionEvent) {
|
|
237
|
-
// Handle selectAllItem selection
|
|
238
|
-
if (
|
|
239
|
-
selectAllItem &&
|
|
240
|
-
isToggleItem(newSelectedItem) &&
|
|
241
|
-
newSelectedItem.id === selectAllItem.id
|
|
242
|
-
) {
|
|
243
|
-
// Check if all items are selected (excluding selectAllItem itself)
|
|
244
|
-
const allSelected =
|
|
245
|
-
data.length > 0 &&
|
|
246
|
-
data.every((item) => selectedItems.includes(item));
|
|
247
|
-
if (allSelected) {
|
|
248
|
-
// Deselect all items
|
|
249
|
-
updateSelectedItems([]);
|
|
250
|
-
} else {
|
|
251
|
-
// Select all items
|
|
252
|
-
updateSelectedItems([...data]);
|
|
253
|
-
}
|
|
254
|
-
} else if (
|
|
255
|
-
selectHeadings &&
|
|
256
|
-
groupBy &&
|
|
257
|
-
isGroupHeading(newSelectedItem)
|
|
258
|
-
) {
|
|
259
|
-
// Handle heading selection - select/deselect all items in the group
|
|
260
|
-
const groupLabel = newSelectedItem.label;
|
|
261
|
-
const groupItems = data.filter(
|
|
262
|
-
(item) => groupBy(item) === groupLabel
|
|
263
|
-
);
|
|
264
|
-
const allSelected =
|
|
265
|
-
groupItems.length > 0 &&
|
|
266
|
-
groupItems.every((item) => selectedItems.includes(item));
|
|
267
|
-
|
|
268
|
-
if (allSelected) {
|
|
269
|
-
// Deselect all items in the group
|
|
270
|
-
updateSelectedItems(
|
|
271
|
-
selectedItems.filter((item) => !groupItems.includes(item))
|
|
272
|
-
);
|
|
273
|
-
} else {
|
|
274
|
-
// Select all items in the group
|
|
275
|
-
const newItems = [
|
|
276
|
-
...selectedItems.filter((item) => !groupItems.includes(item)),
|
|
277
|
-
...groupItems,
|
|
278
|
-
];
|
|
279
|
-
updateSelectedItems(newItems);
|
|
280
|
-
}
|
|
281
|
-
} else if (
|
|
282
|
-
!isGroupHeading(newSelectedItem) &&
|
|
283
|
-
!isToggleItem(newSelectedItem)
|
|
284
|
-
) {
|
|
285
|
-
// Only handle regular data items
|
|
286
|
-
const itemIndex = selectedItems.findIndex(
|
|
287
|
-
(item) => itemToKey(item) === itemToKey(newSelectedItem as T)
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
if (itemIndex >= 0) {
|
|
291
|
-
updateSelectedItems(
|
|
292
|
-
selectedItems.filter((_, index) => index !== itemIndex)
|
|
293
|
-
);
|
|
294
|
-
} else {
|
|
295
|
-
updateSelectedItems([...selectedItems, newSelectedItem as T]);
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
},
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
const {
|
|
304
|
-
isOpen: selectIsOpen,
|
|
305
|
-
getToggleButtonProps,
|
|
306
|
-
getLabelProps,
|
|
307
|
-
getMenuProps,
|
|
308
|
-
highlightedIndex: selectHighlightedIndex,
|
|
309
|
-
getItemProps,
|
|
310
|
-
} = selectProps;
|
|
311
|
-
|
|
312
|
-
// Map the highlighted index from select (which only knows about items) to the full items array (which includes headings)
|
|
313
|
-
const highlightedIndex = useHighlightedIndex(
|
|
314
|
-
items,
|
|
315
|
-
itemsForSelect,
|
|
316
|
-
selectHighlightedIndex,
|
|
317
|
-
!!groupBy,
|
|
318
|
-
selectHeadings ?? false
|
|
319
|
-
);
|
|
320
|
-
|
|
321
|
-
const buttonText = renderSelections
|
|
322
|
-
? renderSelections(selectedItems)
|
|
323
|
-
: selectedItems.length > 0
|
|
324
|
-
? selectedItems.map((item) => itemToString(item)).join(", ")
|
|
325
|
-
: placeholder;
|
|
326
|
-
|
|
327
|
-
const toggleButtonIdProps = getToggleButtonProps();
|
|
328
|
-
// Downshift adds aria-labelledby by default, which can conflict with our Label usage
|
|
329
|
-
toggleButtonIdProps["aria-labelledby"] = undefined;
|
|
330
|
-
if (!selectIsOpen) {
|
|
331
|
-
// Remove aria-controls when the menu is closed to avoid referencing a non-existent element
|
|
332
|
-
// @ts-expect-error downshift types require aria-controls even though it is not required
|
|
333
|
-
toggleButtonIdProps["aria-controls"] = undefined;
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return (
|
|
337
|
-
<Popout
|
|
338
|
-
open={selectIsOpen}
|
|
339
|
-
onOpenChange={updateIsOpen}
|
|
340
|
-
side={popoutPlacement}
|
|
341
|
-
onOpenAutoFocus={(e) => {
|
|
342
|
-
// Prevent default auto-focus behavior
|
|
343
|
-
e.preventDefault();
|
|
344
|
-
}}
|
|
345
|
-
onCloseAutoFocus={(e) => {
|
|
346
|
-
// Prevent default auto-focus behavior
|
|
347
|
-
e.preventDefault();
|
|
348
|
-
}}
|
|
349
|
-
onPointerDownOutside={onPointerDownOutside}
|
|
350
|
-
onInteractOutside={onInteractOutside}
|
|
351
|
-
animationConfig={menuAnimationConfig}
|
|
352
|
-
content={
|
|
353
|
-
<ComboboxContent
|
|
354
|
-
items={items}
|
|
355
|
-
getMenuProps={getMenuProps}
|
|
356
|
-
getItemProps={(props: { index: number }) => {
|
|
357
|
-
// Only apply getItemProps to actual items, not headings or ToggleItems
|
|
358
|
-
const item = items[props.index];
|
|
359
|
-
if (isToggleItem(item)) {
|
|
360
|
-
// Handle ToggleItem clicks manually
|
|
361
|
-
return {
|
|
362
|
-
onClick: () => {
|
|
363
|
-
// This will be handled by the selection logic in onStateChange
|
|
364
|
-
// We need to trigger the selection manually
|
|
365
|
-
const allSelected =
|
|
366
|
-
data.length > 0 &&
|
|
367
|
-
data.every((item) => selectedItems.includes(item));
|
|
368
|
-
if (allSelected) {
|
|
369
|
-
updateSelectedItems([]);
|
|
370
|
-
} else {
|
|
371
|
-
updateSelectedItems([...data]);
|
|
372
|
-
}
|
|
373
|
-
},
|
|
374
|
-
};
|
|
375
|
-
}
|
|
376
|
-
const dataItem = item as T;
|
|
377
|
-
// Find the index in itemsForSelect using itemToKey for safer comparison
|
|
378
|
-
const itemIndex = itemsForSelect.findIndex((selectItem) => {
|
|
379
|
-
if (isGroupHeading(selectItem) || isToggleItem(selectItem)) {
|
|
380
|
-
return false;
|
|
381
|
-
}
|
|
382
|
-
return itemToKey(selectItem as T) === itemToKey(dataItem);
|
|
383
|
-
});
|
|
384
|
-
if (itemIndex === -1) {
|
|
385
|
-
return {};
|
|
386
|
-
}
|
|
387
|
-
return getItemProps({ item: dataItem, index: itemIndex });
|
|
388
|
-
}}
|
|
389
|
-
selectedItems={selectedItems}
|
|
390
|
-
highlightedIndex={highlightedIndex ?? -1}
|
|
391
|
-
renderItem={renderItem}
|
|
392
|
-
renderGroupHeading={renderGroupHeading}
|
|
393
|
-
itemToKey={itemToKey}
|
|
394
|
-
itemToString={itemToString}
|
|
395
|
-
inputType={inputType}
|
|
396
|
-
selectHeadings={selectHeadings}
|
|
397
|
-
onHeadingClick={handleHeadingClick}
|
|
398
|
-
groupBy={groupBy}
|
|
399
|
-
allData={data}
|
|
400
|
-
selectAllItem={selectAllItem}
|
|
401
|
-
isVirtualized={isVirtualized}
|
|
402
|
-
estimatedItemHeight={estimatedItemHeight}
|
|
403
|
-
{...menuProps}
|
|
404
|
-
/>
|
|
405
|
-
}
|
|
406
|
-
>
|
|
407
|
-
<SelectToggleButton
|
|
408
|
-
{...toggleButtonIdProps}
|
|
409
|
-
{...triggerButtonProps}
|
|
410
|
-
isOpen={selectIsOpen}
|
|
411
|
-
shouldOverflow={shouldOverflow}
|
|
412
|
-
>
|
|
413
|
-
{buttonText}
|
|
414
|
-
</SelectToggleButton>
|
|
415
|
-
</Popout>
|
|
416
|
-
);
|
|
417
|
-
}
|