@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,457 +0,0 @@
|
|
|
1
|
-
import { useRef, useEffect } from "react";
|
|
2
|
-
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
3
|
-
import type { ReactNode, MouseEvent } from "react";
|
|
4
|
-
import { StyledMenuContent } from "../../MenuContent/styles";
|
|
5
|
-
import { MenuItem } from "./MenuItem";
|
|
6
|
-
import { MenuHeading } from "./MenuHeading";
|
|
7
|
-
import { MenuGroup } from "./MenuGroup";
|
|
8
|
-
import { groupItems, isGroupHeading, isToggleItem } from "./utils";
|
|
9
|
-
import type { DataWithId, GroupedItem, ToggleItem } from "./types";
|
|
10
|
-
import type { InputType } from "../../MenuItem/MenuItemTypes";
|
|
11
|
-
|
|
12
|
-
// These types could use some cleanup
|
|
13
|
-
// The normal, virutalized, and grouped content all have slightly different props
|
|
14
|
-
interface ComboboxContentProps<T extends DataWithId>
|
|
15
|
-
extends React.HTMLAttributes<HTMLDivElement> {
|
|
16
|
-
items: GroupedItem<T>[];
|
|
17
|
-
getMenuProps: any;
|
|
18
|
-
getItemProps: any;
|
|
19
|
-
selectedItems: T[];
|
|
20
|
-
highlightedIndex: number;
|
|
21
|
-
renderItem: (item: T) => ReactNode;
|
|
22
|
-
renderGroupHeading?: (label: string) => string;
|
|
23
|
-
EmptyState?: ReactNode;
|
|
24
|
-
itemToKey: (item: T) => string | number;
|
|
25
|
-
itemToString: (item: T | null) => string;
|
|
26
|
-
inputType: InputType;
|
|
27
|
-
selectHeadings?: boolean;
|
|
28
|
-
onHeadingClick?: (groupLabel: string, allSelected: boolean) => void;
|
|
29
|
-
groupBy?: (item: T) => string;
|
|
30
|
-
allData?: T[];
|
|
31
|
-
selectAllItem?: ToggleItem;
|
|
32
|
-
placeholderItem?: ToggleItem;
|
|
33
|
-
estimatedItemHeight?: number;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export const VirtualizedComboboxContent = <T extends DataWithId>({
|
|
37
|
-
items,
|
|
38
|
-
getMenuProps,
|
|
39
|
-
getItemProps,
|
|
40
|
-
selectedItems,
|
|
41
|
-
highlightedIndex,
|
|
42
|
-
renderItem,
|
|
43
|
-
renderGroupHeading,
|
|
44
|
-
EmptyState,
|
|
45
|
-
itemToKey,
|
|
46
|
-
inputType,
|
|
47
|
-
selectHeadings = false,
|
|
48
|
-
onHeadingClick,
|
|
49
|
-
groupBy,
|
|
50
|
-
allData,
|
|
51
|
-
selectAllItem,
|
|
52
|
-
estimatedItemHeight = 35,
|
|
53
|
-
...rest
|
|
54
|
-
}: ComboboxContentProps<T>) => {
|
|
55
|
-
const containerRef = useRef(null);
|
|
56
|
-
|
|
57
|
-
// Check if there are any actual items (not just headings)
|
|
58
|
-
const hasItems = items.some((item) => !isGroupHeading(item));
|
|
59
|
-
|
|
60
|
-
const rowVirtualizer = useVirtualizer({
|
|
61
|
-
count: items.length,
|
|
62
|
-
getScrollElement: () => containerRef.current,
|
|
63
|
-
estimateSize: (index) => {
|
|
64
|
-
const item = items[index];
|
|
65
|
-
return isGroupHeading(item) ? 40 : estimatedItemHeight;
|
|
66
|
-
},
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
useEffect(() => {
|
|
70
|
-
if (
|
|
71
|
-
highlightedIndex !== undefined &&
|
|
72
|
-
highlightedIndex !== null &&
|
|
73
|
-
highlightedIndex >= 0
|
|
74
|
-
) {
|
|
75
|
-
rowVirtualizer.scrollToIndex(highlightedIndex);
|
|
76
|
-
}
|
|
77
|
-
}, [highlightedIndex, rowVirtualizer]);
|
|
78
|
-
|
|
79
|
-
const virtualItems = rowVirtualizer.getVirtualItems();
|
|
80
|
-
|
|
81
|
-
const menuProps = getMenuProps(
|
|
82
|
-
{ ref: containerRef },
|
|
83
|
-
{ suppressRefError: true }
|
|
84
|
-
);
|
|
85
|
-
return (
|
|
86
|
-
<div {...menuProps} {...rest} style={{ overflowY: "auto", ...rest.style }}>
|
|
87
|
-
{!hasItems && EmptyState ? (
|
|
88
|
-
<div style={{ padding: "16px" }}>{EmptyState}</div>
|
|
89
|
-
) : (
|
|
90
|
-
<StyledMenuContent
|
|
91
|
-
style={{
|
|
92
|
-
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
93
|
-
position: "relative",
|
|
94
|
-
overflow: "hidden",
|
|
95
|
-
}}
|
|
96
|
-
>
|
|
97
|
-
<div
|
|
98
|
-
style={{
|
|
99
|
-
position: "absolute",
|
|
100
|
-
top: 0,
|
|
101
|
-
left: 0,
|
|
102
|
-
width: "100%",
|
|
103
|
-
transform: `translateY(${virtualItems[0]?.start ?? 0}px)`,
|
|
104
|
-
}}
|
|
105
|
-
>
|
|
106
|
-
{virtualItems.map((virtualItem) => {
|
|
107
|
-
const item = items[virtualItem.index];
|
|
108
|
-
|
|
109
|
-
if (isGroupHeading(item)) {
|
|
110
|
-
// Find all items in this group from the full data array (if groupBy is provided)
|
|
111
|
-
const groupItems =
|
|
112
|
-
groupBy && allData
|
|
113
|
-
? allData.filter(
|
|
114
|
-
(dataItem) => groupBy(dataItem) === item.label
|
|
115
|
-
)
|
|
116
|
-
: [];
|
|
117
|
-
|
|
118
|
-
// Check if all items in the group are selected
|
|
119
|
-
const allSelected =
|
|
120
|
-
groupItems.length > 0 &&
|
|
121
|
-
groupItems.every((groupItem) =>
|
|
122
|
-
selectedItems.includes(groupItem)
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
const headingItemProps = selectHeadings
|
|
126
|
-
? getItemProps({ index: virtualItem.index })
|
|
127
|
-
: {};
|
|
128
|
-
const handleHeadingClick = (e: MouseEvent) => {
|
|
129
|
-
// Call Downshift's onClick if it exists
|
|
130
|
-
headingItemProps.onClick?.(e);
|
|
131
|
-
// Then call our custom handler
|
|
132
|
-
if (onHeadingClick) {
|
|
133
|
-
onHeadingClick(item.label, allSelected);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
return (
|
|
138
|
-
<MenuHeading
|
|
139
|
-
ref={rowVirtualizer.measureElement}
|
|
140
|
-
key={virtualItem.key}
|
|
141
|
-
{...headingItemProps}
|
|
142
|
-
$highlighted={highlightedIndex === virtualItem.index}
|
|
143
|
-
label={item.label}
|
|
144
|
-
renderGroupHeading={renderGroupHeading}
|
|
145
|
-
selectable={selectHeadings}
|
|
146
|
-
selected={allSelected}
|
|
147
|
-
id={item.id}
|
|
148
|
-
onClick={selectHeadings ? handleHeadingClick : undefined}
|
|
149
|
-
style={{
|
|
150
|
-
width: "100%",
|
|
151
|
-
}}
|
|
152
|
-
/>
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Handle ToggleItem separately
|
|
157
|
-
if (isToggleItem(item)) {
|
|
158
|
-
const toggleItem = item as ToggleItem;
|
|
159
|
-
const isItemSelected =
|
|
160
|
-
selectAllItem && toggleItem.id === selectAllItem.id
|
|
161
|
-
? allData &&
|
|
162
|
-
allData.length > 0 &&
|
|
163
|
-
allData.every((item) => selectedItems.includes(item))
|
|
164
|
-
: false;
|
|
165
|
-
return (
|
|
166
|
-
<MenuItem
|
|
167
|
-
ref={rowVirtualizer.measureElement}
|
|
168
|
-
key={virtualItem.key}
|
|
169
|
-
inputType={inputType}
|
|
170
|
-
selected={isItemSelected}
|
|
171
|
-
id={toggleItem.id}
|
|
172
|
-
{...getItemProps({ index: virtualItem.index })}
|
|
173
|
-
style={{
|
|
174
|
-
width: "100%",
|
|
175
|
-
}}
|
|
176
|
-
$highlighted={highlightedIndex === virtualItem.index}
|
|
177
|
-
$active={false}
|
|
178
|
-
>
|
|
179
|
-
{toggleItem.label}
|
|
180
|
-
</MenuItem>
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const dataItem = item as T;
|
|
185
|
-
const isItemSelected = selectedItems.includes(dataItem);
|
|
186
|
-
return (
|
|
187
|
-
<MenuItem
|
|
188
|
-
key={virtualItem.key}
|
|
189
|
-
inputType={inputType}
|
|
190
|
-
selected={isItemSelected}
|
|
191
|
-
id={itemToKey(dataItem)}
|
|
192
|
-
{...getItemProps({ index: virtualItem.index })}
|
|
193
|
-
style={{
|
|
194
|
-
width: "100%",
|
|
195
|
-
}}
|
|
196
|
-
$highlighted={highlightedIndex === virtualItem.index}
|
|
197
|
-
$active={false}
|
|
198
|
-
ref={rowVirtualizer.measureElement}
|
|
199
|
-
>
|
|
200
|
-
{renderItem(dataItem)}
|
|
201
|
-
</MenuItem>
|
|
202
|
-
);
|
|
203
|
-
})}
|
|
204
|
-
</div>
|
|
205
|
-
</StyledMenuContent>
|
|
206
|
-
)}
|
|
207
|
-
</div>
|
|
208
|
-
);
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
export const NormalComboboxContent = <T extends DataWithId>({
|
|
212
|
-
items,
|
|
213
|
-
getMenuProps,
|
|
214
|
-
getItemProps,
|
|
215
|
-
selectedItems,
|
|
216
|
-
highlightedIndex,
|
|
217
|
-
renderItem,
|
|
218
|
-
renderGroupHeading,
|
|
219
|
-
EmptyState,
|
|
220
|
-
itemToKey,
|
|
221
|
-
inputType,
|
|
222
|
-
selectHeadings = false,
|
|
223
|
-
onHeadingClick,
|
|
224
|
-
groupBy,
|
|
225
|
-
allData,
|
|
226
|
-
selectAllItem,
|
|
227
|
-
...rest
|
|
228
|
-
}: ComboboxContentProps<T>) => {
|
|
229
|
-
// Check if there are any actual items (not just headings)
|
|
230
|
-
const hasItems = items.some((item) => !isGroupHeading(item));
|
|
231
|
-
|
|
232
|
-
const menuProps = getMenuProps({}, { suppressRefError: true });
|
|
233
|
-
|
|
234
|
-
return (
|
|
235
|
-
<div {...menuProps} {...rest}>
|
|
236
|
-
{!hasItems && EmptyState ? (
|
|
237
|
-
<div style={{ padding: "16px" }}>{EmptyState}</div>
|
|
238
|
-
) : (
|
|
239
|
-
<StyledMenuContent
|
|
240
|
-
style={{
|
|
241
|
-
position: "relative",
|
|
242
|
-
}}
|
|
243
|
-
>
|
|
244
|
-
{items.map((item, index) => {
|
|
245
|
-
if (isGroupHeading(item)) {
|
|
246
|
-
// Find all items in this group from the full data array (if groupBy is provided)
|
|
247
|
-
const groupItems =
|
|
248
|
-
groupBy && allData
|
|
249
|
-
? allData.filter(
|
|
250
|
-
(dataItem) => groupBy(dataItem) === item.label
|
|
251
|
-
)
|
|
252
|
-
: [];
|
|
253
|
-
|
|
254
|
-
// Check if all items in the group are selected
|
|
255
|
-
const allSelected =
|
|
256
|
-
groupItems.length > 0 &&
|
|
257
|
-
groupItems.every((groupItem) =>
|
|
258
|
-
selectedItems.includes(groupItem)
|
|
259
|
-
);
|
|
260
|
-
|
|
261
|
-
const headingItemProps = selectHeadings
|
|
262
|
-
? getItemProps({ index })
|
|
263
|
-
: {};
|
|
264
|
-
const handleHeadingClick = (e: MouseEvent) => {
|
|
265
|
-
// Call Downshift's onClick if it exists
|
|
266
|
-
headingItemProps.onClick?.(e);
|
|
267
|
-
// Then call our custom handler
|
|
268
|
-
if (onHeadingClick) {
|
|
269
|
-
onHeadingClick(item.label, allSelected);
|
|
270
|
-
}
|
|
271
|
-
};
|
|
272
|
-
|
|
273
|
-
// This should be renamed MenuHeadingItem, it is always selectable
|
|
274
|
-
return (
|
|
275
|
-
<MenuHeading
|
|
276
|
-
key={index}
|
|
277
|
-
{...headingItemProps}
|
|
278
|
-
$highlighted={highlightedIndex === index}
|
|
279
|
-
label={item.label}
|
|
280
|
-
renderGroupHeading={renderGroupHeading}
|
|
281
|
-
selectable={selectHeadings}
|
|
282
|
-
selected={allSelected}
|
|
283
|
-
id={item.id}
|
|
284
|
-
onClick={selectHeadings ? handleHeadingClick : undefined}
|
|
285
|
-
/>
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
// Handle ToggleItem separately
|
|
290
|
-
if (isToggleItem(item)) {
|
|
291
|
-
const toggleItem = item as ToggleItem;
|
|
292
|
-
const isItemSelected =
|
|
293
|
-
selectAllItem && toggleItem.id === selectAllItem.id
|
|
294
|
-
? allData &&
|
|
295
|
-
allData.length > 0 &&
|
|
296
|
-
allData.every((item) => selectedItems.includes(item))
|
|
297
|
-
: false;
|
|
298
|
-
|
|
299
|
-
return (
|
|
300
|
-
<MenuItem
|
|
301
|
-
key={index}
|
|
302
|
-
{...getItemProps({ index })}
|
|
303
|
-
$highlighted={highlightedIndex === index}
|
|
304
|
-
$active={false}
|
|
305
|
-
inputType={inputType}
|
|
306
|
-
selected={isItemSelected}
|
|
307
|
-
id={toggleItem.id}
|
|
308
|
-
>
|
|
309
|
-
{toggleItem.label}
|
|
310
|
-
</MenuItem>
|
|
311
|
-
);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const dataItem = item as T;
|
|
315
|
-
const isItemSelected = selectedItems.includes(dataItem);
|
|
316
|
-
return (
|
|
317
|
-
<MenuItem
|
|
318
|
-
key={index}
|
|
319
|
-
{...getItemProps({ index })}
|
|
320
|
-
$highlighted={highlightedIndex === index}
|
|
321
|
-
$active={false}
|
|
322
|
-
inputType={inputType}
|
|
323
|
-
selected={isItemSelected}
|
|
324
|
-
id={itemToKey(dataItem)}
|
|
325
|
-
>
|
|
326
|
-
{renderItem(dataItem)}
|
|
327
|
-
</MenuItem>
|
|
328
|
-
);
|
|
329
|
-
})}
|
|
330
|
-
</StyledMenuContent>
|
|
331
|
-
)}
|
|
332
|
-
</div>
|
|
333
|
-
);
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
export const GroupedComboboxContent = <T extends DataWithId>({
|
|
337
|
-
items,
|
|
338
|
-
getMenuProps,
|
|
339
|
-
getItemProps,
|
|
340
|
-
highlightedIndex,
|
|
341
|
-
selectedItems,
|
|
342
|
-
renderItem,
|
|
343
|
-
renderGroupHeading,
|
|
344
|
-
EmptyState,
|
|
345
|
-
itemToKey,
|
|
346
|
-
itemToString,
|
|
347
|
-
inputType,
|
|
348
|
-
onHeadingClick,
|
|
349
|
-
groupBy,
|
|
350
|
-
allData,
|
|
351
|
-
selectAllItem,
|
|
352
|
-
placeholderItem,
|
|
353
|
-
...rest
|
|
354
|
-
}: ComboboxContentProps<T>) => {
|
|
355
|
-
// Check if there are any actual items (not just headings)
|
|
356
|
-
const hasItems = items.some((item) => !isGroupHeading(item));
|
|
357
|
-
|
|
358
|
-
const menuProps = getMenuProps({}, { suppressRefError: true });
|
|
359
|
-
|
|
360
|
-
const groupedItems = groupItems(
|
|
361
|
-
items as T[],
|
|
362
|
-
groupBy as (item: T) => string,
|
|
363
|
-
allData
|
|
364
|
-
);
|
|
365
|
-
// If we have a placeholder item, we need to account for it in the item indexing
|
|
366
|
-
let actualItemIndex = placeholderItem ? 1 : 0;
|
|
367
|
-
return (
|
|
368
|
-
<div {...menuProps} {...rest}>
|
|
369
|
-
{!hasItems && EmptyState ? (
|
|
370
|
-
<div style={{ padding: "16px" }}>{EmptyState}</div>
|
|
371
|
-
) : (
|
|
372
|
-
<StyledMenuContent style={{ position: "relative" }}>
|
|
373
|
-
{placeholderItem && (
|
|
374
|
-
<MenuItem
|
|
375
|
-
key="placeholder-item"
|
|
376
|
-
{...getItemProps({ index: 0 })}
|
|
377
|
-
$highlighted={highlightedIndex === 0}
|
|
378
|
-
$active={false}
|
|
379
|
-
inputType={inputType}
|
|
380
|
-
selected={selectedItems.length === 0}
|
|
381
|
-
id={placeholderItem.id}
|
|
382
|
-
data-item-index={0}
|
|
383
|
-
>
|
|
384
|
-
{placeholderItem.label}
|
|
385
|
-
</MenuItem>
|
|
386
|
-
)}
|
|
387
|
-
{Array.from(groupedItems.keys()).map((group, groupIndex) => {
|
|
388
|
-
return (
|
|
389
|
-
<MenuGroup
|
|
390
|
-
id={`menu-group-${group}`}
|
|
391
|
-
key={groupIndex}
|
|
392
|
-
title={renderGroupHeading ? renderGroupHeading(group) : group}
|
|
393
|
-
>
|
|
394
|
-
{groupedItems.get(group)?.map((item) => {
|
|
395
|
-
const isItemSelected = selectedItems.includes(item);
|
|
396
|
-
const itemIndex = actualItemIndex;
|
|
397
|
-
actualItemIndex += 1;
|
|
398
|
-
return (
|
|
399
|
-
<MenuItem
|
|
400
|
-
key={itemIndex}
|
|
401
|
-
{...getItemProps({ index: itemIndex })}
|
|
402
|
-
$highlighted={highlightedIndex === itemIndex}
|
|
403
|
-
$active={false}
|
|
404
|
-
inputType={inputType}
|
|
405
|
-
selected={isItemSelected}
|
|
406
|
-
id={itemToKey(item)}
|
|
407
|
-
data-item-index={itemIndex}
|
|
408
|
-
>
|
|
409
|
-
{renderItem(item)}
|
|
410
|
-
</MenuItem>
|
|
411
|
-
);
|
|
412
|
-
})}
|
|
413
|
-
</MenuGroup>
|
|
414
|
-
);
|
|
415
|
-
})}
|
|
416
|
-
</StyledMenuContent>
|
|
417
|
-
)}
|
|
418
|
-
</div>
|
|
419
|
-
);
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
// Combobox content is not rendered until the menu is open
|
|
423
|
-
// The menus should be updated to only add aria-controls to the menu when it is open
|
|
424
|
-
// Otherwise they should override it to undefined
|
|
425
|
-
export const ComboboxContent = <T extends DataWithId>({
|
|
426
|
-
isVirtualized = false,
|
|
427
|
-
groupBy,
|
|
428
|
-
selectHeadings = false,
|
|
429
|
-
...props
|
|
430
|
-
}: ComboboxContentProps<T> & { isVirtualized?: boolean }) => {
|
|
431
|
-
if (isVirtualized) {
|
|
432
|
-
return (
|
|
433
|
-
<VirtualizedComboboxContent
|
|
434
|
-
groupBy={groupBy}
|
|
435
|
-
selectHeadings={selectHeadings}
|
|
436
|
-
{...props}
|
|
437
|
-
/>
|
|
438
|
-
);
|
|
439
|
-
}
|
|
440
|
-
if (groupBy && !selectHeadings) {
|
|
441
|
-
return (
|
|
442
|
-
<GroupedComboboxContent
|
|
443
|
-
groupBy={groupBy}
|
|
444
|
-
selectHeadings={selectHeadings}
|
|
445
|
-
{...props}
|
|
446
|
-
/>
|
|
447
|
-
);
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
return (
|
|
451
|
-
<NormalComboboxContent
|
|
452
|
-
selectHeadings={selectHeadings}
|
|
453
|
-
groupBy={groupBy}
|
|
454
|
-
{...props}
|
|
455
|
-
/>
|
|
456
|
-
);
|
|
457
|
-
};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import type { MenuItemProps } from "./MenuItem";
|
|
3
|
-
import type { TypeMenuGroupProps } from "./MenuGroupTypes";
|
|
4
|
-
import { StyledMenuGroup, StyledTitle, StyledMenuGroupUl } from "./styles";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* @link https://seeds.sproutsocial.com/components/seeds-react-menu/#menugroup
|
|
8
|
-
*
|
|
9
|
-
* @description MenuGroup is used to group lists of {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuitem MenuItems}.
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* <ActionMenu>
|
|
13
|
-
* <MenuContent>
|
|
14
|
-
* <MenuGroup title="Group 1" id="1">
|
|
15
|
-
* <MenuItem>Item 1</MenuItem>
|
|
16
|
-
* </MenuGroup>
|
|
17
|
-
* <MenuGroup title="Group 2" id="2">
|
|
18
|
-
* <MenuItem>Item 2</MenuItem>
|
|
19
|
-
* </MenuGroup>
|
|
20
|
-
* </MenuContent>
|
|
21
|
-
* </ActionMenu>
|
|
22
|
-
*
|
|
23
|
-
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menuitem MenuItem}
|
|
24
|
-
* @see {@link https://seeds.sproutsocial.com/components/seeds-react-menu/#menucontent MenuContent}
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
const MenuGroup = ({
|
|
28
|
-
titleAs = "h3",
|
|
29
|
-
children,
|
|
30
|
-
title,
|
|
31
|
-
color,
|
|
32
|
-
id,
|
|
33
|
-
...rest
|
|
34
|
-
}: TypeMenuGroupProps) => {
|
|
35
|
-
// Generate a unique ID for the title
|
|
36
|
-
const titleId = `menu-group-title-${Math.random().toString(36).slice(2, 11)}`;
|
|
37
|
-
|
|
38
|
-
return (
|
|
39
|
-
<StyledMenuGroup
|
|
40
|
-
role="group"
|
|
41
|
-
id={id}
|
|
42
|
-
aria-labelledby={title ? titleId : undefined}
|
|
43
|
-
// TODO: fix this type since `color` should be valid here. TS can't resolve the correct type.
|
|
44
|
-
// @ts-expect-error Copy Pasted from original MenuGroup
|
|
45
|
-
color={color}
|
|
46
|
-
{...rest}
|
|
47
|
-
>
|
|
48
|
-
{title && (
|
|
49
|
-
<StyledTitle role="heading" as={titleAs} id={titleId}>
|
|
50
|
-
{title}
|
|
51
|
-
</StyledTitle>
|
|
52
|
-
)}
|
|
53
|
-
<StyledMenuGroupUl>{children}</StyledMenuGroupUl>
|
|
54
|
-
</StyledMenuGroup>
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
MenuGroup.__MENU_PRIMITIVE_TYPE = "MenuGroup";
|
|
59
|
-
|
|
60
|
-
export { MenuGroup };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
TypeBorderSystemProps,
|
|
3
|
-
TypeColorSystemProps,
|
|
4
|
-
TypeFlexboxSystemProps,
|
|
5
|
-
TypeGridSystemProps,
|
|
6
|
-
TypeLayoutSystemProps,
|
|
7
|
-
TypePositionSystemProps,
|
|
8
|
-
TypeSpaceSystemProps,
|
|
9
|
-
TypeTypographySystemProps,
|
|
10
|
-
} from "@sproutsocial/seeds-react-system-props";
|
|
11
|
-
|
|
12
|
-
export interface TypeMenuGroupStyledProps
|
|
13
|
-
extends TypeBorderSystemProps,
|
|
14
|
-
TypeColorSystemProps,
|
|
15
|
-
TypeFlexboxSystemProps,
|
|
16
|
-
TypeGridSystemProps,
|
|
17
|
-
TypeLayoutSystemProps,
|
|
18
|
-
TypePositionSystemProps,
|
|
19
|
-
TypeSpaceSystemProps,
|
|
20
|
-
TypeTypographySystemProps {}
|
|
21
|
-
|
|
22
|
-
export interface TypeStyledMenuGroupProps extends TypeMenuGroupStyledProps {}
|
|
23
|
-
export interface TypeMenuGroupProps
|
|
24
|
-
extends TypeStyledMenuGroupProps,
|
|
25
|
-
Omit<React.ComponentPropsWithoutRef<"ul">, "color"> {
|
|
26
|
-
id: string;
|
|
27
|
-
title?: string;
|
|
28
|
-
titleAs?: string | React.ComponentType<any>;
|
|
29
|
-
children: React.ReactNode;
|
|
30
|
-
}
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
import type { ReactNode, CSSProperties } from "react";
|
|
2
|
-
import { MenuItem } from "./MenuItem";
|
|
3
|
-
import styled from "styled-components";
|
|
4
|
-
import Box from "@sproutsocial/seeds-react-box";
|
|
5
|
-
|
|
6
|
-
export interface MenuHeadingProps {
|
|
7
|
-
label: string;
|
|
8
|
-
renderGroupHeading?: (label: string) => string;
|
|
9
|
-
virtualizedStyles?: {
|
|
10
|
-
position: "absolute";
|
|
11
|
-
top: number;
|
|
12
|
-
left: number;
|
|
13
|
-
width: string;
|
|
14
|
-
height: string;
|
|
15
|
-
transform: string;
|
|
16
|
-
};
|
|
17
|
-
style?: CSSProperties;
|
|
18
|
-
selectable?: boolean;
|
|
19
|
-
$highlighted?: boolean;
|
|
20
|
-
selected?: boolean;
|
|
21
|
-
id?: string | number;
|
|
22
|
-
onClick?: () => void;
|
|
23
|
-
[key: string]: any; // For spreading getItemProps and other props
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
interface TypeMenuHeaderContainerProps {
|
|
27
|
-
$leftAction?: boolean;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export const MenuHeaderContainer = styled(Box)<TypeMenuHeaderContainerProps>`
|
|
31
|
-
border-color: ${({ theme }) => theme.colors.container.border.base};
|
|
32
|
-
border-bottom-width: 1px;
|
|
33
|
-
border-bottom-style: solid;
|
|
34
|
-
font-size: ${({ theme }) => theme.typography[200].fontSize};
|
|
35
|
-
display: flex;
|
|
36
|
-
flex-direction: column;
|
|
37
|
-
padding: ${({ theme }) => theme.space[350]} ${({ theme }) => theme.space[400]};
|
|
38
|
-
`;
|
|
39
|
-
|
|
40
|
-
export const MenuHeading = ({
|
|
41
|
-
label,
|
|
42
|
-
renderGroupHeading,
|
|
43
|
-
style,
|
|
44
|
-
selectable = false,
|
|
45
|
-
$highlighted = false,
|
|
46
|
-
selected = false,
|
|
47
|
-
id,
|
|
48
|
-
onClick,
|
|
49
|
-
...props
|
|
50
|
-
}: MenuHeadingProps) => {
|
|
51
|
-
const combinedStyle: CSSProperties = {
|
|
52
|
-
fontWeight: "bold",
|
|
53
|
-
...style,
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
if (selectable) {
|
|
57
|
-
return (
|
|
58
|
-
<MenuItem
|
|
59
|
-
style={combinedStyle}
|
|
60
|
-
$highlighted={$highlighted}
|
|
61
|
-
$active={false}
|
|
62
|
-
inputType="checkbox"
|
|
63
|
-
selected={selected}
|
|
64
|
-
id={id}
|
|
65
|
-
onClick={onClick}
|
|
66
|
-
{...props}
|
|
67
|
-
>
|
|
68
|
-
{renderGroupHeading ? renderGroupHeading(label) : label}
|
|
69
|
-
</MenuItem>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
return (
|
|
74
|
-
<MenuHeaderContainer
|
|
75
|
-
style={combinedStyle}
|
|
76
|
-
role="option"
|
|
77
|
-
aria-disabled={true}
|
|
78
|
-
aria-selected={false}
|
|
79
|
-
>
|
|
80
|
-
{renderGroupHeading ? renderGroupHeading(label) : label}
|
|
81
|
-
</MenuHeaderContainer>
|
|
82
|
-
);
|
|
83
|
-
};
|