@sproutsocial/seeds-react-menu 1.7.1 → 1.7.5

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.
Files changed (47) hide show
  1. package/.turbo/turbo-build.log +19 -11
  2. package/BUNDLE_OPTIMIZATION.md +307 -0
  3. package/CHANGELOG.md +51 -0
  4. package/dist/esm/chunk-ROQATIB7.js +357 -0
  5. package/dist/esm/chunk-ROQATIB7.js.map +1 -0
  6. package/dist/esm/index.js +261 -2271
  7. package/dist/esm/index.js.map +1 -1
  8. package/dist/esm/v2/index.js +2000 -0
  9. package/dist/esm/v2/index.js.map +1 -0
  10. package/dist/index.d.mts +1 -0
  11. package/dist/index.d.ts +1 -0
  12. package/dist/index.js +297 -1989
  13. package/dist/index.js.map +1 -1
  14. package/dist/v2/index.d.mts +96 -0
  15. package/dist/v2/index.d.ts +96 -0
  16. package/dist/v2/index.js +2191 -0
  17. package/dist/v2/index.js.map +1 -0
  18. package/package.json +30 -14
  19. package/src/MenuItem/styles.tsx +7 -0
  20. package/src/v2/Autocomplete/Autocomplete.stories.tsx +609 -0
  21. package/src/v2/Autocomplete/MultiAutocomplete.tsx +453 -0
  22. package/src/v2/Autocomplete/SingleAutocomplete.tsx +362 -0
  23. package/src/v2/Autocomplete/index.ts +2 -0
  24. package/src/v2/Common-V2/ComboboxContent.tsx +448 -0
  25. package/src/v2/Common-V2/MenuGroup.tsx +60 -0
  26. package/src/v2/Common-V2/MenuGroupTypes.ts +30 -0
  27. package/src/v2/Common-V2/MenuHeading.tsx +83 -0
  28. package/src/v2/Common-V2/MenuItem.tsx +138 -0
  29. package/src/v2/Common-V2/Popout.tsx +102 -0
  30. package/src/v2/Common-V2/PopoutTypes.tsx +92 -0
  31. package/src/v2/Common-V2/SelectToggleButton.tsx +99 -0
  32. package/src/v2/Common-V2/index.ts +11 -0
  33. package/src/v2/Common-V2/props.ts +74 -0
  34. package/src/v2/Common-V2/styles.tsx +41 -0
  35. package/src/v2/Common-V2/types.ts +16 -0
  36. package/src/v2/Common-V2/useHighlightedIndex.ts +62 -0
  37. package/src/v2/Common-V2/utils.ts +238 -0
  38. package/src/v2/SearchableSelect/AutocompleteContent.tsx +325 -0
  39. package/src/v2/SearchableSelect/SearchableMultiSelect.tsx +521 -0
  40. package/src/v2/SearchableSelect/SearchableSelect.tsx +389 -0
  41. package/src/v2/SearchableSelect/index.ts +12 -0
  42. package/src/v2/Select/MultiSelect.tsx +404 -0
  43. package/src/v2/Select/Select.stories.tsx +593 -0
  44. package/src/v2/Select/SingleSelect.tsx +272 -0
  45. package/src/v2/Select/index.ts +2 -0
  46. package/src/v2/index.ts +2 -0
  47. package/tsup.config.ts +14 -5
@@ -0,0 +1,2000 @@
1
+ import {
2
+ MenuItemActionLeft,
3
+ MenuItemRow,
4
+ MenuItemText,
5
+ StyledMenuContent,
6
+ StyledMenuItem
7
+ } from "../chunk-ROQATIB7.js";
8
+
9
+ // src/v2/Select/SingleSelect.tsx
10
+ import { useState as useState2, useMemo as useMemo3 } from "react";
11
+ import { useSelect } from "downshift";
12
+ import "@sproutsocial/seeds-react-label";
13
+
14
+ // src/v2/Common-V2/utils.ts
15
+ import "react";
16
+ import { MOTION_DURATION_FAST } from "@sproutsocial/seeds-motion/unitless";
17
+ import "@sproutsocial/seeds-react-popout";
18
+ function isGroupHeading(item) {
19
+ return typeof item === "object" && item !== null && "type" in item && item.type === "heading";
20
+ }
21
+ function isToggleItem(item) {
22
+ return typeof item === "object" && item !== null && "label" in item && !("type" in item) && Object.keys(item).length === 2 && // ToggleItem only has id and label
23
+ "id" in item;
24
+ }
25
+ var menuPlacementOrigin = {
26
+ top: { originX: 0.5, originY: 1 },
27
+ ["top-start"]: { originX: 0, originY: 1 },
28
+ ["top-end"]: { originX: 1, originY: 1 },
29
+ bottom: { originX: 0.5, originY: 0 },
30
+ ["bottom-start"]: { originX: 0, originY: 0 },
31
+ ["bottom-end"]: { originX: 1, originY: 0 },
32
+ left: { originX: 1, originY: 0.5 },
33
+ ["left-start"]: { originX: 1, originY: 0 },
34
+ ["left-end"]: { originX: 1, originY: 1 },
35
+ right: { originX: 0, originY: 0.5 },
36
+ ["right-start"]: { originX: 0, originY: 0 },
37
+ ["right-end"]: { originX: 0, originY: 1 }
38
+ };
39
+ var menuAnimationConfig = {
40
+ // Turning off layout true. This seems to be what causes the crazy animations when searching.
41
+ // layout: true,
42
+ variants: {
43
+ initial: (custom = { placement: "bottom" }) => ({
44
+ ...menuPlacementOrigin[custom.placement],
45
+ scale: 0,
46
+ opacity: 0
47
+ }),
48
+ animate: (custom = { placement: "bottom" }) => ({
49
+ ...menuPlacementOrigin[custom.placement],
50
+ opacity: 1,
51
+ scale: 1,
52
+ transition: {
53
+ type: "tween",
54
+ duration: MOTION_DURATION_FAST,
55
+ ease: "circOut"
56
+ }
57
+ }),
58
+ exit: {
59
+ opacity: 0,
60
+ scale: 1,
61
+ transition: {
62
+ type: "tween",
63
+ duration: MOTION_DURATION_FAST,
64
+ ease: "circIn"
65
+ }
66
+ }
67
+ },
68
+ initial: "initial",
69
+ whileInView: "animate",
70
+ viewport: { once: true },
71
+ exit: "exit"
72
+ };
73
+ function getFilteredItems(data, inputValue, itemToSearchString, itemToString, options) {
74
+ const lowerCasedInputValue = inputValue.toLowerCase();
75
+ if (options?.selectedItem && itemToString(options?.selectedItem).toLowerCase() === lowerCasedInputValue) {
76
+ return data;
77
+ }
78
+ return data.filter(function filterItem(item) {
79
+ if (options?.selectedItems && !options.showSelectedItems && options.selectedItems.includes(item)) {
80
+ return false;
81
+ }
82
+ const searchString = itemToSearchString(item);
83
+ const searchableParts = searchString.split("|").map((part) => part.toLowerCase().trim());
84
+ return searchableParts.some((part) => part.includes(lowerCasedInputValue));
85
+ });
86
+ }
87
+ function groupItems(items, groupBy, allData) {
88
+ if (items.length === 0) {
89
+ return /* @__PURE__ */ new Map();
90
+ }
91
+ const dataForOrder = allData || items;
92
+ const groupOrder = [];
93
+ const seenGroups = /* @__PURE__ */ new Set();
94
+ for (const item of dataForOrder) {
95
+ let groupKey = groupBy(item);
96
+ if (item.id === "clear-selection") {
97
+ continue;
98
+ }
99
+ if (!seenGroups.has(groupKey)) {
100
+ seenGroups.add(groupKey);
101
+ groupOrder.push(groupKey);
102
+ }
103
+ }
104
+ const grouped = /* @__PURE__ */ new Map();
105
+ for (const item of items) {
106
+ let groupKey = groupBy(item);
107
+ if (item.id === "clear-selection") {
108
+ continue;
109
+ }
110
+ if (!grouped.has(groupKey)) {
111
+ grouped.set(groupKey, []);
112
+ }
113
+ grouped.get(groupKey).push(item);
114
+ }
115
+ const sortedGrouped = /* @__PURE__ */ new Map();
116
+ for (const groupKey of groupOrder) {
117
+ const groupItems2 = grouped.get(groupKey);
118
+ if (groupItems2) {
119
+ sortedGrouped.set(groupKey, groupItems2);
120
+ }
121
+ }
122
+ return sortedGrouped;
123
+ }
124
+ function groupItemsWithHeadings(items, groupBy, allData, selectHeadings = false) {
125
+ if (items.length === 0) {
126
+ return [];
127
+ }
128
+ const grouped = groupItems(items, groupBy, allData);
129
+ const result = [];
130
+ for (const groupKey of grouped.keys()) {
131
+ const groupItems2 = grouped.get(groupKey);
132
+ if (groupItems2 && groupItems2.length > 0) {
133
+ if (selectHeadings) {
134
+ result.push({
135
+ id: `heading-${groupKey}`,
136
+ type: "heading",
137
+ label: groupKey
138
+ });
139
+ }
140
+ result.push(...groupItems2);
141
+ }
142
+ }
143
+ return result;
144
+ }
145
+ function createItemToStringForDownshift(itemToString) {
146
+ return (item) => {
147
+ if (!item) return "";
148
+ if (isToggleItem(item)) {
149
+ return item.label;
150
+ }
151
+ if (isGroupHeading(item)) {
152
+ return item.label;
153
+ }
154
+ return itemToString(item);
155
+ };
156
+ }
157
+
158
+ // src/v2/Common-V2/Popout.tsx
159
+ import * as React2 from "react";
160
+ import { motion } from "motion/react";
161
+ import * as Popover from "@radix-ui/react-popover";
162
+ import { MOTION_DURATION_FAST as MOTION_DURATION_FAST2 } from "@sproutsocial/seeds-motion/unitless";
163
+ import styled from "styled-components";
164
+ import { jsx, jsxs } from "react/jsx-runtime";
165
+ var defaultAnimationConfig = {
166
+ initial: { opacity: 0 },
167
+ animate: { opacity: 1 },
168
+ exit: { opacity: 0 },
169
+ transition: {
170
+ ease: "circOut",
171
+ type: "tween",
172
+ duration: MOTION_DURATION_FAST2
173
+ }
174
+ };
175
+ var StyledContent = styled(Popover.Content)`
176
+ width: var(--radix-popover-trigger-width);
177
+ max-height: var(--radix-popover-content-available-height);
178
+ // This should be a prop on the Popout component
179
+ z-index: 7;
180
+ `;
181
+ var StyledMotionDiv = styled(motion.div)`
182
+ background-color: ${({ theme }) => theme.colors.container.background.base};
183
+ border: ${({ theme }) => theme.borders[500]};
184
+ border-color: ${({ theme }) => theme.colors.container.border.base};
185
+ border-radius: ${({ theme }) => theme.radii[500]};
186
+ box-shadow: ${({ theme }) => theme.shadows.medium};
187
+ padding: ${({ theme }) => theme.space[400]};
188
+ `;
189
+ function Popout({
190
+ children,
191
+ content,
192
+ open,
193
+ defaultOpen,
194
+ onOpenChange,
195
+ animationConfig = defaultAnimationConfig,
196
+ side = "bottom",
197
+ sideOffset = 8,
198
+ align = "center",
199
+ alignOffset = 0,
200
+ onOpenAutoFocus,
201
+ onEscapeKeyDown,
202
+ onCloseAutoFocus,
203
+ ...rest
204
+ }) {
205
+ const [isOpen, setIsOpen] = React2.useState(defaultOpen ?? false);
206
+ const handleOpenChange = React2.useCallback(
207
+ (newOpen) => {
208
+ setIsOpen(newOpen);
209
+ onOpenChange?.(newOpen);
210
+ },
211
+ [onOpenChange]
212
+ );
213
+ const isControlled = open !== void 0;
214
+ const popoverOpen = isControlled ? open : isOpen;
215
+ const popoverOnOpenChange = isControlled ? onOpenChange : handleOpenChange;
216
+ const radixRef = React2.useRef(null);
217
+ return /* @__PURE__ */ jsxs(Popover.Root, { open: popoverOpen, onOpenChange: popoverOnOpenChange, children: [
218
+ /* @__PURE__ */ jsx(Popover.Trigger, { ref: radixRef, asChild: true, children }),
219
+ /* @__PURE__ */ jsx(Popover.Anchor, {}),
220
+ /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(
221
+ StyledContent,
222
+ {
223
+ side,
224
+ sideOffset,
225
+ align,
226
+ alignOffset,
227
+ onOpenAutoFocus,
228
+ onEscapeKeyDown,
229
+ onCloseAutoFocus,
230
+ role: "presentation",
231
+ children: /* @__PURE__ */ jsx(StyledMotionDiv, { ...animationConfig, ...rest, children: content })
232
+ }
233
+ ) })
234
+ ] });
235
+ }
236
+
237
+ // src/v2/Common-V2/PopoutTypes.tsx
238
+ import "react";
239
+
240
+ // src/v2/Common-V2/SelectToggleButton.tsx
241
+ import styled2, { css } from "styled-components";
242
+ import { Icon } from "@sproutsocial/seeds-react-icon";
243
+ import Button from "@sproutsocial/seeds-react-button";
244
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
245
+ var StyledSelectToggleButton = styled2(
246
+ Button
247
+ )`
248
+ border-color: ${(props) => props.theme.colors.form.border.base};
249
+ width: 100%;
250
+
251
+ ${(props) => props.invalid && css`
252
+ border-color: ${(props2) => props2.theme.colors.form.border.error};
253
+ `}
254
+ `;
255
+ var StyledChevron = styled2.div`
256
+ margin-left: ${({ theme }) => theme.space[300]};
257
+
258
+ ${({ invalid }) => invalid && css`
259
+ color: ${(props) => props.theme.colors.icon.error};
260
+ `}
261
+ `;
262
+ var RotatingIcon = styled2(Icon)`
263
+ transition: transform 0.15s;
264
+
265
+ ${({ $isOpen }) => $isOpen && `
266
+ transform: rotate(-180deg);
267
+ `}
268
+ `;
269
+ var StyledInnerButton = styled2.div`
270
+ display: flex;
271
+ justify-content: space-between;
272
+ `;
273
+ var EllipsisContent = styled2.div`
274
+ overflow: hidden;
275
+ text-overflow: ellipsis;
276
+ white-space: nowrap;
277
+ `;
278
+ var WrappedContent = styled2.div`
279
+ flex: 1;
280
+ width: 100%;
281
+ text-align: left;
282
+ text-wrap: auto;
283
+ `;
284
+ var SelectToggleButton = ({
285
+ children,
286
+ isOpen,
287
+ shouldOverflow,
288
+ ...buttonProps
289
+ }) => {
290
+ return /* @__PURE__ */ jsx2(StyledSelectToggleButton, { ...buttonProps, children: /* @__PURE__ */ jsxs2(StyledInnerButton, { children: [
291
+ shouldOverflow ? /* @__PURE__ */ jsx2(WrappedContent, { children }) : /* @__PURE__ */ jsx2(EllipsisContent, { children }),
292
+ /* @__PURE__ */ jsx2(StyledChevron, { $isOpen: isOpen, invalid: buttonProps.invalid, children: /* @__PURE__ */ jsx2(
293
+ RotatingIcon,
294
+ {
295
+ name: "chevron-down-outline",
296
+ fixedWidth: true,
297
+ "aria-hidden": true,
298
+ $isOpen: isOpen
299
+ }
300
+ ) })
301
+ ] }) });
302
+ };
303
+
304
+ // src/v2/Common-V2/MenuItem.tsx
305
+ import { useMemo } from "react";
306
+ import { Icon as Icon2 } from "@sproutsocial/seeds-react-icon";
307
+ import { Checkbox } from "@sproutsocial/seeds-react-checkbox";
308
+ import { Switch } from "@sproutsocial/seeds-react-switch";
309
+ import { Radio } from "@sproutsocial/seeds-react-radio";
310
+ import { useTheme } from "styled-components";
311
+ import { Box } from "@sproutsocial/seeds-react-box";
312
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
313
+ var SelectionIndicator = ({
314
+ id,
315
+ inputType = "icon",
316
+ "aria-labelledby": labeledBy,
317
+ selected
318
+ }) => {
319
+ const { space: space2 } = useTheme();
320
+ const inputStub = (e) => {
321
+ e.stopPropagation();
322
+ };
323
+ switch (inputType) {
324
+ case "checkbox":
325
+ return /* @__PURE__ */ jsx3(
326
+ Checkbox,
327
+ {
328
+ tabIndex: -1,
329
+ onChange: () => {
330
+ },
331
+ checked: selected,
332
+ "aria-labelledby": labeledBy,
333
+ id: `MenuItem-${inputType}-${id}`
334
+ }
335
+ );
336
+ case "switch":
337
+ return /* @__PURE__ */ jsx3(
338
+ Switch,
339
+ {
340
+ tabIndex: -1,
341
+ onClick: inputStub,
342
+ checked: !!selected,
343
+ "aria-labelledby": labeledBy,
344
+ id: `MenuItem-${inputType}-${id}`
345
+ }
346
+ );
347
+ case "radio":
348
+ return /* @__PURE__ */ jsx3(
349
+ Radio,
350
+ {
351
+ tabIndex: -1,
352
+ checked: selected,
353
+ id: `MenuItem-${inputType}-${id}`,
354
+ name: `MenuItem-${inputType}`,
355
+ "aria-labelledby": labeledBy
356
+ }
357
+ );
358
+ case "icon":
359
+ if (selected) {
360
+ return /* @__PURE__ */ jsx3(Icon2, { name: "check-solid", "aria-hidden": true, size: "small" });
361
+ } else {
362
+ return /* @__PURE__ */ jsx3(Box, { width: space2["400"] });
363
+ }
364
+ default:
365
+ return null;
366
+ }
367
+ };
368
+ var MenuItem = ({
369
+ children,
370
+ $highlighted = false,
371
+ $active = false,
372
+ inputType,
373
+ selected = false,
374
+ id,
375
+ style,
376
+ ...props
377
+ }) => {
378
+ const labelId = useMemo(
379
+ () => id ? `menu-item-child-${id}` : `menu-item-child-${Math.random().toString(36).substr(2, 9)}`,
380
+ [id]
381
+ );
382
+ const content = inputType ? /* @__PURE__ */ jsxs3(MenuItemRow, { children: [
383
+ /* @__PURE__ */ jsx3(MenuItemActionLeft, { children: /* @__PURE__ */ jsx3(
384
+ SelectionIndicator,
385
+ {
386
+ id: String(id || ""),
387
+ "aria-labelledby": labelId,
388
+ inputType,
389
+ selected
390
+ }
391
+ ) }),
392
+ /* @__PURE__ */ jsx3(MenuItemText, { id: labelId, children })
393
+ ] }) : children;
394
+ return /* @__PURE__ */ jsx3(
395
+ StyledMenuItem,
396
+ {
397
+ $highlighted,
398
+ $active,
399
+ $selected: selected,
400
+ style,
401
+ ...props,
402
+ children: content
403
+ }
404
+ );
405
+ };
406
+
407
+ // src/v2/Common-V2/MenuHeading.tsx
408
+ import styled3 from "styled-components";
409
+ import Box2 from "@sproutsocial/seeds-react-box";
410
+ import { jsx as jsx4 } from "react/jsx-runtime";
411
+ var MenuHeaderContainer = styled3(Box2)`
412
+ border-color: ${({ theme }) => theme.colors.container.border.base};
413
+ border-bottom-width: 1px;
414
+ border-bottom-style: solid;
415
+ font-size: ${({ theme }) => theme.typography[200].fontSize};
416
+ display: flex;
417
+ flex-direction: column;
418
+ padding: ${({ theme }) => theme.space[350]} ${({ theme }) => theme.space[400]};
419
+ `;
420
+ var MenuHeading = ({
421
+ label,
422
+ renderGroupHeading,
423
+ style,
424
+ selectable = false,
425
+ $highlighted = false,
426
+ selected = false,
427
+ id,
428
+ onClick,
429
+ ...props
430
+ }) => {
431
+ const combinedStyle = {
432
+ fontWeight: "bold",
433
+ ...style
434
+ };
435
+ if (selectable) {
436
+ return /* @__PURE__ */ jsx4(
437
+ MenuItem,
438
+ {
439
+ style: combinedStyle,
440
+ $highlighted,
441
+ $active: false,
442
+ inputType: "checkbox",
443
+ selected,
444
+ id,
445
+ onClick,
446
+ ...props,
447
+ children: renderGroupHeading ? renderGroupHeading(label) : label
448
+ }
449
+ );
450
+ }
451
+ return /* @__PURE__ */ jsx4(
452
+ MenuHeaderContainer,
453
+ {
454
+ style: combinedStyle,
455
+ role: "option",
456
+ "aria-disabled": true,
457
+ "aria-selected": false,
458
+ children: renderGroupHeading ? renderGroupHeading(label) : label
459
+ }
460
+ );
461
+ };
462
+
463
+ // src/v2/Common-V2/MenuGroup.tsx
464
+ import "react";
465
+
466
+ // src/v2/Common-V2/styles.tsx
467
+ import styled4 from "styled-components";
468
+ import Text from "@sproutsocial/seeds-react-text";
469
+ import {
470
+ border,
471
+ layout,
472
+ position,
473
+ flexbox,
474
+ grid,
475
+ color,
476
+ space
477
+ } from "styled-system";
478
+ var StyledMenuGroup = styled4.li`
479
+ font-family: ${({ theme }) => theme.fontFamily};
480
+ &:not(:last-child) {
481
+ border-bottom: 1px solid
482
+ ${({ theme }) => theme.colors.container.border.base};
483
+ }
484
+ list-style: none;
485
+ margin: 0;
486
+
487
+ ${border}
488
+ ${position}
489
+ ${color}
490
+ ${flexbox}
491
+ ${grid}
492
+ ${layout}
493
+ ${space}
494
+ `;
495
+ var StyledTitle = styled4(Text.SmallSubHeadline)`
496
+ font-size: ${({ theme }) => theme.typography[100].fontSize};
497
+ margin: ${({ theme }) => theme.space[400]} ${({ theme }) => theme.space[400]}
498
+ 0px ${({ theme }) => theme.space[400]};
499
+ `;
500
+ var StyledMenuGroupUl = styled4.ul`
501
+ margin: 0;
502
+ padding: 0;
503
+ `;
504
+
505
+ // src/v2/Common-V2/MenuGroup.tsx
506
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
507
+ var MenuGroup = ({
508
+ titleAs = "h3",
509
+ children,
510
+ title,
511
+ color: color2,
512
+ id,
513
+ ...rest
514
+ }) => {
515
+ const titleId = `menu-group-title-${Math.random().toString(36).slice(2, 11)}`;
516
+ return /* @__PURE__ */ jsxs4(
517
+ StyledMenuGroup,
518
+ {
519
+ role: "group",
520
+ id,
521
+ "aria-labelledby": title ? titleId : void 0,
522
+ color: color2,
523
+ ...rest,
524
+ children: [
525
+ title && /* @__PURE__ */ jsx5(StyledTitle, { role: "heading", as: titleAs, id: titleId, children: title }),
526
+ /* @__PURE__ */ jsx5(StyledMenuGroupUl, { children })
527
+ ]
528
+ }
529
+ );
530
+ };
531
+ MenuGroup.__MENU_PRIMITIVE_TYPE = "MenuGroup";
532
+
533
+ // src/v2/Common-V2/useHighlightedIndex.ts
534
+ import { useMemo as useMemo2 } from "react";
535
+ function useHighlightedIndex(items, itemsForDownshift, downshiftHighlightedIndex, hasGroups, selectHeadings) {
536
+ return useMemo2(() => {
537
+ if (downshiftHighlightedIndex === null || downshiftHighlightedIndex === void 0 || downshiftHighlightedIndex < 0) {
538
+ return null;
539
+ }
540
+ if (!hasGroups) {
541
+ return downshiftHighlightedIndex;
542
+ }
543
+ const highlightedItem = itemsForDownshift[downshiftHighlightedIndex];
544
+ if (!highlightedItem) {
545
+ return null;
546
+ }
547
+ if (selectHeadings) {
548
+ return items.findIndex((item) => item === highlightedItem);
549
+ } else {
550
+ return items.findIndex(
551
+ (item) => !isGroupHeading(item) && item === highlightedItem
552
+ );
553
+ }
554
+ }, [
555
+ items,
556
+ itemsForDownshift,
557
+ downshiftHighlightedIndex,
558
+ hasGroups,
559
+ selectHeadings
560
+ ]);
561
+ }
562
+
563
+ // src/v2/Common-V2/ComboboxContent.tsx
564
+ import { useRef as useRef2, useEffect } from "react";
565
+ import { useVirtualizer } from "@tanstack/react-virtual";
566
+ import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
567
+ var VirtualizedComboboxContent = ({
568
+ items,
569
+ getMenuProps,
570
+ getItemProps,
571
+ selectedItems,
572
+ highlightedIndex,
573
+ renderItem,
574
+ renderGroupHeading,
575
+ EmptyState,
576
+ itemToKey,
577
+ inputType,
578
+ selectHeadings = false,
579
+ onHeadingClick,
580
+ groupBy,
581
+ allData,
582
+ selectAllItem,
583
+ ...rest
584
+ }) => {
585
+ const containerRef = useRef2(null);
586
+ const hasItems = items.some((item) => !isGroupHeading(item));
587
+ const rowVirtualizer = useVirtualizer({
588
+ count: items.length,
589
+ getScrollElement: () => containerRef.current,
590
+ estimateSize: (index) => {
591
+ const item = items[index];
592
+ return isGroupHeading(item) ? 30 : 35;
593
+ }
594
+ });
595
+ useEffect(() => {
596
+ if (highlightedIndex !== void 0 && highlightedIndex !== null && highlightedIndex >= 0) {
597
+ rowVirtualizer.scrollToIndex(highlightedIndex);
598
+ }
599
+ }, [highlightedIndex, rowVirtualizer]);
600
+ const virtualItems = rowVirtualizer.getVirtualItems();
601
+ const menuProps = getMenuProps({ ref: containerRef });
602
+ return /* @__PURE__ */ jsx6("div", { ...menuProps, ...rest, children: !hasItems && EmptyState ? /* @__PURE__ */ jsx6("div", { style: { padding: "16px" }, children: EmptyState }) : /* @__PURE__ */ jsx6(
603
+ StyledMenuContent,
604
+ {
605
+ style: {
606
+ height: `${rowVirtualizer.getTotalSize()}px`,
607
+ position: "relative"
608
+ },
609
+ children: /* @__PURE__ */ jsx6(
610
+ "div",
611
+ {
612
+ style: {
613
+ position: "absolute",
614
+ top: 0,
615
+ left: 0,
616
+ width: "100%",
617
+ transform: `translateY(${virtualItems[0]?.start ?? 0}px)`
618
+ },
619
+ children: virtualItems.map((virtualItem) => {
620
+ const item = items[virtualItem.index];
621
+ if (isGroupHeading(item)) {
622
+ const groupItems2 = groupBy && allData ? allData.filter(
623
+ (dataItem2) => groupBy(dataItem2) === item.label
624
+ ) : [];
625
+ const allSelected = groupItems2.length > 0 && groupItems2.every(
626
+ (groupItem) => selectedItems.includes(groupItem)
627
+ );
628
+ const headingItemProps = selectHeadings ? getItemProps({ index: virtualItem.index }) : {};
629
+ const handleHeadingClick = (e) => {
630
+ headingItemProps.onClick?.(e);
631
+ if (onHeadingClick) {
632
+ onHeadingClick(item.label, allSelected);
633
+ }
634
+ };
635
+ return /* @__PURE__ */ jsx6(
636
+ MenuHeading,
637
+ {
638
+ ...headingItemProps,
639
+ $highlighted: highlightedIndex === virtualItem.index,
640
+ label: item.label,
641
+ renderGroupHeading,
642
+ selectable: selectHeadings,
643
+ selected: allSelected,
644
+ id: item.id,
645
+ onClick: selectHeadings ? handleHeadingClick : void 0,
646
+ style: {
647
+ width: "100%"
648
+ }
649
+ },
650
+ virtualItem.key
651
+ );
652
+ }
653
+ if (isToggleItem(item)) {
654
+ const toggleItem = item;
655
+ const isItemSelected2 = selectAllItem && toggleItem.id === selectAllItem.id ? allData && allData.length > 0 && allData.every((item2) => selectedItems.includes(item2)) : false;
656
+ return /* @__PURE__ */ jsx6(
657
+ MenuItem,
658
+ {
659
+ inputType,
660
+ selected: isItemSelected2,
661
+ id: toggleItem.id,
662
+ ...getItemProps({ index: virtualItem.index }),
663
+ style: {
664
+ width: "100%"
665
+ },
666
+ $highlighted: highlightedIndex === virtualItem.index,
667
+ $active: false,
668
+ children: toggleItem.label
669
+ },
670
+ virtualItem.key
671
+ );
672
+ }
673
+ const dataItem = item;
674
+ const isItemSelected = selectedItems.includes(dataItem);
675
+ return /* @__PURE__ */ jsx6(
676
+ MenuItem,
677
+ {
678
+ inputType,
679
+ selected: isItemSelected,
680
+ id: itemToKey(dataItem),
681
+ ...getItemProps({ index: virtualItem.index }),
682
+ style: {
683
+ width: "100%"
684
+ },
685
+ $highlighted: highlightedIndex === virtualItem.index,
686
+ $active: false,
687
+ children: renderItem(dataItem)
688
+ },
689
+ virtualItem.key
690
+ );
691
+ })
692
+ }
693
+ )
694
+ }
695
+ ) });
696
+ };
697
+ var NormalComboboxContent = ({
698
+ items,
699
+ getMenuProps,
700
+ getItemProps,
701
+ selectedItems,
702
+ highlightedIndex,
703
+ renderItem,
704
+ renderGroupHeading,
705
+ EmptyState,
706
+ itemToKey,
707
+ inputType,
708
+ selectHeadings = false,
709
+ onHeadingClick,
710
+ groupBy,
711
+ allData,
712
+ selectAllItem,
713
+ ...rest
714
+ }) => {
715
+ const hasItems = items.some((item) => !isGroupHeading(item));
716
+ const menuProps = getMenuProps();
717
+ return /* @__PURE__ */ jsx6("div", { ...menuProps, ...rest, children: !hasItems && EmptyState ? /* @__PURE__ */ jsx6("div", { style: { padding: "16px" }, children: EmptyState }) : /* @__PURE__ */ jsx6(
718
+ StyledMenuContent,
719
+ {
720
+ style: {
721
+ position: "relative"
722
+ },
723
+ children: items.map((item, index) => {
724
+ if (isGroupHeading(item)) {
725
+ const groupItems2 = groupBy && allData ? allData.filter(
726
+ (dataItem2) => groupBy(dataItem2) === item.label
727
+ ) : [];
728
+ const allSelected = groupItems2.length > 0 && groupItems2.every(
729
+ (groupItem) => selectedItems.includes(groupItem)
730
+ );
731
+ const headingItemProps = selectHeadings ? getItemProps({ index }) : {};
732
+ const handleHeadingClick = (e) => {
733
+ headingItemProps.onClick?.(e);
734
+ if (onHeadingClick) {
735
+ onHeadingClick(item.label, allSelected);
736
+ }
737
+ };
738
+ return /* @__PURE__ */ jsx6(
739
+ MenuHeading,
740
+ {
741
+ ...headingItemProps,
742
+ $highlighted: highlightedIndex === index,
743
+ label: item.label,
744
+ renderGroupHeading,
745
+ selectable: selectHeadings,
746
+ selected: allSelected,
747
+ id: item.id,
748
+ onClick: selectHeadings ? handleHeadingClick : void 0
749
+ },
750
+ index
751
+ );
752
+ }
753
+ if (isToggleItem(item)) {
754
+ const toggleItem = item;
755
+ const isItemSelected2 = selectAllItem && toggleItem.id === selectAllItem.id ? allData && allData.length > 0 && allData.every((item2) => selectedItems.includes(item2)) : false;
756
+ return /* @__PURE__ */ jsx6(
757
+ MenuItem,
758
+ {
759
+ ...getItemProps({ index }),
760
+ $highlighted: highlightedIndex === index,
761
+ $active: false,
762
+ inputType,
763
+ selected: isItemSelected2,
764
+ id: toggleItem.id,
765
+ children: toggleItem.label
766
+ },
767
+ index
768
+ );
769
+ }
770
+ const dataItem = item;
771
+ const isItemSelected = selectedItems.includes(dataItem);
772
+ return /* @__PURE__ */ jsx6(
773
+ MenuItem,
774
+ {
775
+ ...getItemProps({ index }),
776
+ $highlighted: highlightedIndex === index,
777
+ $active: false,
778
+ inputType,
779
+ selected: isItemSelected,
780
+ id: itemToKey(dataItem),
781
+ children: renderItem(dataItem)
782
+ },
783
+ index
784
+ );
785
+ })
786
+ }
787
+ ) });
788
+ };
789
+ var GroupedComboboxContent = ({
790
+ items,
791
+ getMenuProps,
792
+ getItemProps,
793
+ highlightedIndex,
794
+ selectedItems,
795
+ renderItem,
796
+ renderGroupHeading,
797
+ EmptyState,
798
+ itemToKey,
799
+ itemToString,
800
+ inputType,
801
+ onHeadingClick,
802
+ groupBy,
803
+ allData,
804
+ selectAllItem,
805
+ placeholderItem,
806
+ ...rest
807
+ }) => {
808
+ const hasItems = items.some((item) => !isGroupHeading(item));
809
+ const menuProps = getMenuProps();
810
+ const groupedItems = groupItems(
811
+ items,
812
+ groupBy,
813
+ allData
814
+ );
815
+ let actualItemIndex = placeholderItem ? 1 : 0;
816
+ return /* @__PURE__ */ jsx6("div", { ...menuProps, ...rest, children: !hasItems && EmptyState ? /* @__PURE__ */ jsx6("div", { style: { padding: "16px" }, children: EmptyState }) : /* @__PURE__ */ jsxs5(StyledMenuContent, { style: { position: "relative" }, children: [
817
+ placeholderItem && /* @__PURE__ */ jsx6(
818
+ MenuItem,
819
+ {
820
+ ...getItemProps({ index: 0 }),
821
+ $highlighted: highlightedIndex === 0,
822
+ $active: false,
823
+ inputType,
824
+ selected: selectedItems.length === 0,
825
+ id: placeholderItem.id,
826
+ "data-item-index": 0,
827
+ children: placeholderItem.label
828
+ },
829
+ "placeholder-item"
830
+ ),
831
+ Array.from(groupedItems.keys()).map((group, groupIndex) => {
832
+ return /* @__PURE__ */ jsx6(
833
+ MenuGroup,
834
+ {
835
+ id: `menu-group-${group}`,
836
+ title: renderGroupHeading ? renderGroupHeading(group) : group,
837
+ children: groupedItems.get(group)?.map((item) => {
838
+ const isItemSelected = selectedItems.includes(item);
839
+ const itemIndex = actualItemIndex;
840
+ actualItemIndex += 1;
841
+ return /* @__PURE__ */ jsx6(
842
+ MenuItem,
843
+ {
844
+ ...getItemProps({ index: itemIndex }),
845
+ $highlighted: highlightedIndex === itemIndex,
846
+ $active: false,
847
+ inputType,
848
+ selected: isItemSelected,
849
+ id: itemToKey(item),
850
+ "data-item-index": itemIndex,
851
+ children: renderItem(item)
852
+ },
853
+ itemIndex
854
+ );
855
+ })
856
+ },
857
+ groupIndex
858
+ );
859
+ })
860
+ ] }) });
861
+ };
862
+ var ComboboxContent = ({
863
+ isVirtualized = false,
864
+ groupBy,
865
+ selectHeadings = false,
866
+ ...props
867
+ }) => {
868
+ if (isVirtualized) {
869
+ return /* @__PURE__ */ jsx6(
870
+ VirtualizedComboboxContent,
871
+ {
872
+ groupBy,
873
+ selectHeadings,
874
+ ...props
875
+ }
876
+ );
877
+ }
878
+ if (groupBy && !selectHeadings) {
879
+ return /* @__PURE__ */ jsx6(
880
+ GroupedComboboxContent,
881
+ {
882
+ groupBy,
883
+ selectHeadings,
884
+ ...props
885
+ }
886
+ );
887
+ }
888
+ return /* @__PURE__ */ jsx6(
889
+ NormalComboboxContent,
890
+ {
891
+ selectHeadings,
892
+ groupBy,
893
+ ...props
894
+ }
895
+ );
896
+ };
897
+
898
+ // src/v2/Select/SingleSelect.tsx
899
+ import { jsx as jsx7 } from "react/jsx-runtime";
900
+ function defaultReducer(state, actionAndChanges) {
901
+ const { changes, type } = actionAndChanges;
902
+ switch (type) {
903
+ case useSelect.stateChangeTypes.ItemClick:
904
+ return {
905
+ ...changes,
906
+ isOpen: false,
907
+ // close the menu after selection for single select
908
+ highlightedIndex: 0
909
+ // reset highlight
910
+ };
911
+ default:
912
+ return changes;
913
+ }
914
+ }
915
+ function SingleSelect({
916
+ id,
917
+ data,
918
+ selectedItemId: controlledSelectedItemId,
919
+ isOpen: controlledIsOpen,
920
+ itemToKey = (item) => item?.id,
921
+ itemToString,
922
+ itemToSelection,
923
+ renderSelection,
924
+ renderItem,
925
+ groupBy,
926
+ renderGroupHeading,
927
+ isVirtualized = false,
928
+ placeholder,
929
+ onSelectedItemIdChange,
930
+ onIsOpenChange,
931
+ stateReducer = defaultReducer,
932
+ triggerButtonProps,
933
+ menuProps,
934
+ inputType = "icon",
935
+ removePlaceholderItem = false
936
+ }) {
937
+ const [uncontrolledSelectedItemId, setUncontrolledSelectedItemId] = useState2(null);
938
+ const [uncontrolledIsOpen, setUncontrolledIsOpen] = useState2(false);
939
+ const isSelectedItemIdControlled = controlledSelectedItemId !== void 0;
940
+ const selectedItemId = isSelectedItemIdControlled ? controlledSelectedItemId : uncontrolledSelectedItemId;
941
+ const selectedItem = useMemo3(() => {
942
+ if (selectedItemId === null || selectedItemId === void 0) {
943
+ return null;
944
+ }
945
+ return data.find((item) => itemToKey(item) === selectedItemId) ?? null;
946
+ }, [selectedItemId, data, itemToKey]);
947
+ const isIsOpenControlled = controlledIsOpen !== void 0;
948
+ const isOpen = isIsOpenControlled ? controlledIsOpen : uncontrolledIsOpen;
949
+ const updateSelectedItem = (newSelectedItem) => {
950
+ const newSelectedItemId = newSelectedItem ? itemToKey(newSelectedItem) : null;
951
+ if (!isSelectedItemIdControlled) {
952
+ setUncontrolledSelectedItemId(newSelectedItemId);
953
+ }
954
+ onSelectedItemIdChange?.(newSelectedItemId);
955
+ };
956
+ const updateIsOpen = (newIsOpen) => {
957
+ if (!isIsOpenControlled) {
958
+ setUncontrolledIsOpen(newIsOpen);
959
+ }
960
+ onIsOpenChange?.(newIsOpen);
961
+ };
962
+ const items = useMemo3(() => {
963
+ let groupedItems;
964
+ const placeholderItem = {
965
+ id: "clear-selection",
966
+ label: placeholder
967
+ };
968
+ if (groupBy) {
969
+ groupedItems = groupItemsWithHeadings(data, groupBy, data, true);
970
+ } else {
971
+ groupedItems = data;
972
+ }
973
+ if (!removePlaceholderItem) {
974
+ groupedItems = [placeholderItem, ...groupedItems];
975
+ }
976
+ return groupedItems;
977
+ }, [data, groupBy, placeholder]);
978
+ const itemsForSelect = useMemo3(() => {
979
+ return items.filter((item) => !isGroupHeading(item));
980
+ }, [items]);
981
+ const itemToStringForDownshift = useMemo3(
982
+ () => createItemToStringForDownshift(itemToString),
983
+ [itemToString]
984
+ );
985
+ const selectProps = useSelect({
986
+ toggleButtonId: id,
987
+ items: itemsForSelect,
988
+ itemToString: itemToStringForDownshift,
989
+ // defaultHighlightedIndex: 0,
990
+ selectedItem,
991
+ isOpen,
992
+ stateReducer,
993
+ onStateChange({ type, selectedItem: newSelectedItem, isOpen: newIsOpen }) {
994
+ if (newIsOpen !== void 0) {
995
+ updateIsOpen(newIsOpen);
996
+ }
997
+ const isSelectionEvent = type === useSelect.stateChangeTypes.ItemClick || type === useSelect.stateChangeTypes.ToggleButtonKeyDownEnter;
998
+ if (isSelectionEvent && newSelectedItem && newSelectedItem !== null) {
999
+ if (newSelectedItem.id === "clear-selection") {
1000
+ updateSelectedItem(null);
1001
+ } else {
1002
+ updateSelectedItem(newSelectedItem);
1003
+ }
1004
+ }
1005
+ }
1006
+ });
1007
+ const {
1008
+ isOpen: selectIsOpen,
1009
+ getToggleButtonProps,
1010
+ getLabelProps,
1011
+ getMenuProps,
1012
+ highlightedIndex: selectHighlightedIndex,
1013
+ getItemProps
1014
+ } = selectProps;
1015
+ const highlightedIndex = useHighlightedIndex(
1016
+ items,
1017
+ itemsForSelect,
1018
+ selectHighlightedIndex,
1019
+ !!groupBy,
1020
+ false
1021
+ // Single select components hardcode selectHeadings to false
1022
+ );
1023
+ const buttonContent = renderSelection ? renderSelection(selectedItem) : selectedItem ? itemToSelection ? itemToSelection(selectedItem) : itemToString(selectedItem) : placeholder;
1024
+ const toggleButtonProps = getToggleButtonProps();
1025
+ toggleButtonProps["aria-labelledby"] = void 0;
1026
+ if (!selectIsOpen) {
1027
+ toggleButtonProps["aria-controls"] = void 0;
1028
+ }
1029
+ return /* @__PURE__ */ jsx7(
1030
+ Popout,
1031
+ {
1032
+ open: selectIsOpen,
1033
+ onOpenChange: updateIsOpen,
1034
+ animationConfig: menuAnimationConfig,
1035
+ onOpenAutoFocus: (e) => {
1036
+ e.preventDefault();
1037
+ },
1038
+ onCloseAutoFocus: (e) => {
1039
+ e.preventDefault();
1040
+ },
1041
+ content: /* @__PURE__ */ jsx7(
1042
+ ComboboxContent,
1043
+ {
1044
+ items,
1045
+ getMenuProps,
1046
+ getItemProps: (props) => {
1047
+ const item = items[props.index];
1048
+ if (isToggleItem(item)) {
1049
+ return {
1050
+ onClick: () => {
1051
+ if (item.id === "clear-selection") {
1052
+ updateSelectedItem(null);
1053
+ }
1054
+ }
1055
+ };
1056
+ }
1057
+ const dataItem = item;
1058
+ const itemIndex = itemsForSelect.indexOf(dataItem);
1059
+ if (itemIndex === -1) {
1060
+ return {};
1061
+ }
1062
+ return getItemProps({ item: dataItem, index: itemIndex });
1063
+ },
1064
+ selectedItems: selectedItem ? [selectedItem] : [],
1065
+ highlightedIndex: highlightedIndex ?? -1,
1066
+ renderItem,
1067
+ renderGroupHeading,
1068
+ itemToKey,
1069
+ itemToString,
1070
+ inputType,
1071
+ isVirtualized,
1072
+ groupBy,
1073
+ selectHeadings: false,
1074
+ ...menuProps
1075
+ }
1076
+ ),
1077
+ children: /* @__PURE__ */ jsx7(
1078
+ SelectToggleButton,
1079
+ {
1080
+ ...toggleButtonProps,
1081
+ ...triggerButtonProps,
1082
+ isOpen: selectIsOpen,
1083
+ children: buttonContent
1084
+ }
1085
+ )
1086
+ }
1087
+ );
1088
+ }
1089
+
1090
+ // src/v2/Select/MultiSelect.tsx
1091
+ import { useState as useState3, useMemo as useMemo4 } from "react";
1092
+ import { useSelect as useSelect2, useMultipleSelection } from "downshift";
1093
+ import "@sproutsocial/seeds-react-label";
1094
+ import { jsx as jsx8 } from "react/jsx-runtime";
1095
+ function defaultReducer2(state, actionAndChanges) {
1096
+ const { changes, type } = actionAndChanges;
1097
+ switch (type) {
1098
+ case useSelect2.stateChangeTypes.ItemClick:
1099
+ return {
1100
+ ...changes,
1101
+ isOpen: true,
1102
+ // keep the menu open after selection.
1103
+ highlightedIndex: 0
1104
+ // with the first option highlighted.
1105
+ };
1106
+ default:
1107
+ if (changes.selectedItem && changes.isOpen === false) {
1108
+ return {
1109
+ ...changes,
1110
+ isOpen: true,
1111
+ // keep the menu open after keyboard selection.
1112
+ highlightedIndex: 0
1113
+ // with the first option highlighted.
1114
+ };
1115
+ }
1116
+ return changes;
1117
+ }
1118
+ }
1119
+ function MultiSelect({
1120
+ id,
1121
+ data,
1122
+ selectedItemIds: controlledSelectedItemIds,
1123
+ isOpen: controlledIsOpen,
1124
+ itemToKey = (item) => item?.id,
1125
+ itemToString,
1126
+ renderSelections,
1127
+ renderItem,
1128
+ groupBy,
1129
+ renderGroupHeading,
1130
+ isVirtualized = false,
1131
+ showSelectedItems = false,
1132
+ selectHeadings = false,
1133
+ selectAllItem,
1134
+ placeholder,
1135
+ onSelectedItemIdsChange,
1136
+ onIsOpenChange,
1137
+ stateReducer = defaultReducer2,
1138
+ triggerButtonProps,
1139
+ menuProps,
1140
+ inputType = "checkbox",
1141
+ shouldOverflow
1142
+ }) {
1143
+ const [uncontrolledSelectedItemIds, setUncontrolledSelectedItemIds] = useState3([]);
1144
+ const [uncontrolledIsOpen, setUncontrolledIsOpen] = useState3(false);
1145
+ const isSelectedItemIdsControlled = controlledSelectedItemIds !== void 0;
1146
+ const selectedItemIds = isSelectedItemIdsControlled ? controlledSelectedItemIds : uncontrolledSelectedItemIds;
1147
+ const selectedItems = useMemo4(() => {
1148
+ return data.filter((item) => selectedItemIds.includes(itemToKey(item)));
1149
+ }, [selectedItemIds, data, itemToKey]);
1150
+ const isIsOpenControlled = controlledIsOpen !== void 0;
1151
+ const isOpen = isIsOpenControlled ? controlledIsOpen : uncontrolledIsOpen;
1152
+ const updateSelectedItems = (newSelectedItems) => {
1153
+ const newSelectedItemIds = newSelectedItems.map((item) => itemToKey(item));
1154
+ if (!isSelectedItemIdsControlled) {
1155
+ setUncontrolledSelectedItemIds(newSelectedItemIds);
1156
+ }
1157
+ onSelectedItemIdsChange?.(newSelectedItemIds);
1158
+ };
1159
+ const updateIsOpen = (newIsOpen) => {
1160
+ if (!isIsOpenControlled) {
1161
+ setUncontrolledIsOpen(newIsOpen);
1162
+ }
1163
+ onIsOpenChange?.(newIsOpen);
1164
+ };
1165
+ const filteredData = useMemo4(() => {
1166
+ if (showSelectedItems) {
1167
+ return data;
1168
+ }
1169
+ return data.filter((item) => !selectedItems.includes(item));
1170
+ }, [data, selectedItems, showSelectedItems]);
1171
+ const items = useMemo4(() => {
1172
+ let groupedItems;
1173
+ if (groupBy) {
1174
+ groupedItems = groupItemsWithHeadings(filteredData, groupBy, data, true);
1175
+ } else {
1176
+ groupedItems = filteredData;
1177
+ }
1178
+ if (selectAllItem) {
1179
+ return [selectAllItem, ...groupedItems];
1180
+ }
1181
+ return groupedItems;
1182
+ }, [filteredData, groupBy, data, selectAllItem, selectHeadings]);
1183
+ const handleHeadingClick = useMemo4(() => {
1184
+ if (!selectHeadings || !groupBy) {
1185
+ return void 0;
1186
+ }
1187
+ return (groupLabel, allSelected) => {
1188
+ const groupItems2 = data.filter((item) => groupBy(item) === groupLabel);
1189
+ if (allSelected) {
1190
+ const newSelectedItems = selectedItems.filter(
1191
+ (item) => !groupItems2.includes(item)
1192
+ );
1193
+ updateSelectedItems(newSelectedItems);
1194
+ } else {
1195
+ const newSelectedItems = [...selectedItems];
1196
+ for (const groupItem of groupItems2) {
1197
+ if (!newSelectedItems.includes(groupItem)) {
1198
+ newSelectedItems.push(groupItem);
1199
+ }
1200
+ }
1201
+ updateSelectedItems(newSelectedItems);
1202
+ }
1203
+ };
1204
+ }, [selectHeadings, groupBy, data, selectedItems, updateSelectedItems]);
1205
+ const { getSelectedItemProps, getDropdownProps, removeSelectedItem } = useMultipleSelection({
1206
+ selectedItems,
1207
+ onStateChange({ selectedItems: newSelectedItems, type }) {
1208
+ switch (type) {
1209
+ case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownBackspace:
1210
+ case useMultipleSelection.stateChangeTypes.SelectedItemKeyDownDelete:
1211
+ case useMultipleSelection.stateChangeTypes.DropdownKeyDownBackspace:
1212
+ case useMultipleSelection.stateChangeTypes.FunctionRemoveSelectedItem:
1213
+ if (newSelectedItems !== void 0) {
1214
+ updateSelectedItems(newSelectedItems);
1215
+ }
1216
+ break;
1217
+ default:
1218
+ break;
1219
+ }
1220
+ }
1221
+ });
1222
+ const itemsForSelect = useMemo4(() => {
1223
+ if (selectHeadings) {
1224
+ return items;
1225
+ }
1226
+ return items.filter(
1227
+ (item) => !isGroupHeading(item)
1228
+ );
1229
+ }, [items, selectHeadings]);
1230
+ const itemToStringForDownshift = useMemo4(
1231
+ () => createItemToStringForDownshift(itemToString),
1232
+ [itemToString]
1233
+ );
1234
+ const selectProps = useSelect2({
1235
+ toggleButtonId: id,
1236
+ items: itemsForSelect,
1237
+ itemToString: itemToStringForDownshift,
1238
+ // defaultHighlightedIndex: 0, // after selection, highlight the first item.
1239
+ selectedItem: null,
1240
+ isOpen,
1241
+ stateReducer,
1242
+ // Could maybe let devs override this too?
1243
+ onStateChange({ type, selectedItem: newSelectedItem, isOpen: newIsOpen }) {
1244
+ if (newIsOpen !== void 0) {
1245
+ updateIsOpen(newIsOpen);
1246
+ }
1247
+ if (newSelectedItem && newSelectedItem !== null) {
1248
+ const isSelectionEvent = type === useSelect2.stateChangeTypes.ItemClick || type === useSelect2.stateChangeTypes.ToggleButtonKeyDownEnter;
1249
+ if (isSelectionEvent) {
1250
+ if (selectAllItem && isToggleItem(newSelectedItem) && newSelectedItem.id === selectAllItem.id) {
1251
+ const allSelected = data.length > 0 && data.every((item) => selectedItems.includes(item));
1252
+ if (allSelected) {
1253
+ updateSelectedItems([]);
1254
+ } else {
1255
+ updateSelectedItems([...data]);
1256
+ }
1257
+ } else if (selectHeadings && groupBy && isGroupHeading(newSelectedItem)) {
1258
+ const groupLabel = newSelectedItem.label;
1259
+ const groupItems2 = data.filter(
1260
+ (item) => groupBy(item) === groupLabel
1261
+ );
1262
+ const allSelected = groupItems2.length > 0 && groupItems2.every((item) => selectedItems.includes(item));
1263
+ if (allSelected) {
1264
+ updateSelectedItems(
1265
+ selectedItems.filter((item) => !groupItems2.includes(item))
1266
+ );
1267
+ } else {
1268
+ const newItems = [
1269
+ ...selectedItems.filter((item) => !groupItems2.includes(item)),
1270
+ ...groupItems2
1271
+ ];
1272
+ updateSelectedItems(newItems);
1273
+ }
1274
+ } else if (!isGroupHeading(newSelectedItem) && !isToggleItem(newSelectedItem)) {
1275
+ const itemIndex = selectedItems.findIndex(
1276
+ (item) => itemToKey(item) === itemToKey(newSelectedItem)
1277
+ );
1278
+ if (itemIndex >= 0) {
1279
+ updateSelectedItems(
1280
+ selectedItems.filter((_, index) => index !== itemIndex)
1281
+ );
1282
+ } else {
1283
+ updateSelectedItems([...selectedItems, newSelectedItem]);
1284
+ }
1285
+ }
1286
+ }
1287
+ }
1288
+ }
1289
+ });
1290
+ const {
1291
+ isOpen: selectIsOpen,
1292
+ getToggleButtonProps,
1293
+ getLabelProps,
1294
+ getMenuProps,
1295
+ highlightedIndex: selectHighlightedIndex,
1296
+ getItemProps
1297
+ } = selectProps;
1298
+ const highlightedIndex = useHighlightedIndex(
1299
+ items,
1300
+ itemsForSelect,
1301
+ selectHighlightedIndex,
1302
+ !!groupBy,
1303
+ selectHeadings ?? false
1304
+ );
1305
+ const buttonText = renderSelections ? renderSelections(selectedItems) : selectedItems.length > 0 ? selectedItems.map((item) => itemToString(item)).join(", ") : placeholder;
1306
+ const toggleButtonIdProps = getToggleButtonProps();
1307
+ toggleButtonIdProps["aria-labelledby"] = void 0;
1308
+ if (!selectIsOpen) {
1309
+ toggleButtonIdProps["aria-controls"] = void 0;
1310
+ }
1311
+ return /* @__PURE__ */ jsx8(
1312
+ Popout,
1313
+ {
1314
+ open: selectIsOpen,
1315
+ onOpenChange: updateIsOpen,
1316
+ onOpenAutoFocus: (e) => {
1317
+ e.preventDefault();
1318
+ },
1319
+ onCloseAutoFocus: (e) => {
1320
+ e.preventDefault();
1321
+ },
1322
+ animationConfig: menuAnimationConfig,
1323
+ content: /* @__PURE__ */ jsx8(
1324
+ ComboboxContent,
1325
+ {
1326
+ items,
1327
+ getMenuProps,
1328
+ getItemProps: (props) => {
1329
+ const item = items[props.index];
1330
+ if (isToggleItem(item)) {
1331
+ return {
1332
+ onClick: () => {
1333
+ const allSelected = data.length > 0 && data.every((item2) => selectedItems.includes(item2));
1334
+ if (allSelected) {
1335
+ updateSelectedItems([]);
1336
+ } else {
1337
+ updateSelectedItems([...data]);
1338
+ }
1339
+ }
1340
+ };
1341
+ }
1342
+ const dataItem = item;
1343
+ const itemIndex = itemsForSelect.indexOf(dataItem);
1344
+ if (itemIndex === -1) {
1345
+ return {};
1346
+ }
1347
+ return getItemProps({ item: dataItem, index: itemIndex });
1348
+ },
1349
+ selectedItems,
1350
+ highlightedIndex: highlightedIndex ?? -1,
1351
+ renderItem,
1352
+ renderGroupHeading,
1353
+ itemToKey,
1354
+ itemToString,
1355
+ inputType,
1356
+ selectHeadings,
1357
+ onHeadingClick: handleHeadingClick,
1358
+ groupBy,
1359
+ allData: data,
1360
+ selectAllItem,
1361
+ isVirtualized,
1362
+ ...menuProps
1363
+ }
1364
+ ),
1365
+ children: /* @__PURE__ */ jsx8(
1366
+ SelectToggleButton,
1367
+ {
1368
+ ...toggleButtonIdProps,
1369
+ ...triggerButtonProps,
1370
+ isOpen: selectIsOpen,
1371
+ shouldOverflow,
1372
+ children: buttonText
1373
+ }
1374
+ )
1375
+ }
1376
+ );
1377
+ }
1378
+
1379
+ // src/v2/Autocomplete/SingleAutocomplete.tsx
1380
+ import { useState as useState4, useMemo as useMemo5, useEffect as useEffect2 } from "react";
1381
+ import { useCombobox } from "downshift";
1382
+ import "@sproutsocial/seeds-react-label";
1383
+ import { Input } from "@sproutsocial/seeds-react-input";
1384
+ import { jsx as jsx9 } from "react/jsx-runtime";
1385
+ function defaultReducer3(state, actionAndChanges) {
1386
+ const { changes, type } = actionAndChanges;
1387
+ switch (type) {
1388
+ case useCombobox.stateChangeTypes.InputKeyDownEnter:
1389
+ case useCombobox.stateChangeTypes.ItemClick:
1390
+ return {
1391
+ ...changes,
1392
+ isOpen: false,
1393
+ // close the menu after selection for single select
1394
+ highlightedIndex: 0
1395
+ // reset highlight
1396
+ };
1397
+ default:
1398
+ return changes;
1399
+ }
1400
+ }
1401
+ function SingleAutocomplete({
1402
+ id,
1403
+ data,
1404
+ selectedItemId: controlledSelectedItemId,
1405
+ inputValue: controlledInputValue,
1406
+ isOpen: controlledIsOpen,
1407
+ itemToKey = (item) => item?.id,
1408
+ itemToString,
1409
+ itemToSearchString,
1410
+ renderItem,
1411
+ groupBy,
1412
+ renderGroupHeading,
1413
+ isVirtualized = false,
1414
+ EmptyState,
1415
+ placeholder,
1416
+ onSelectedItemIdChange,
1417
+ onInputValueChange,
1418
+ onIsOpenChange,
1419
+ stateReducer = defaultReducer3,
1420
+ menuProps,
1421
+ inputType = "icon",
1422
+ includePlaceholderItem = false
1423
+ }) {
1424
+ const [uncontrolledInputValue, setUncontrolledInputValue] = useState4("");
1425
+ const [uncontrolledSelectedItemId, setUncontrolledSelectedItemId] = useState4(null);
1426
+ const [uncontrolledIsOpen, setUncontrolledIsOpen] = useState4(false);
1427
+ const isSelectedItemIdControlled = controlledSelectedItemId !== void 0;
1428
+ const selectedItemId = isSelectedItemIdControlled ? controlledSelectedItemId : uncontrolledSelectedItemId;
1429
+ const selectedItem = useMemo5(() => {
1430
+ if (selectedItemId === null || selectedItemId === void 0) {
1431
+ return null;
1432
+ }
1433
+ return data.find((item) => itemToKey(item) === selectedItemId) ?? null;
1434
+ }, [selectedItemId, data, itemToKey]);
1435
+ const isInputValueControlled = controlledInputValue !== void 0;
1436
+ const inputValue = isInputValueControlled ? controlledInputValue : uncontrolledInputValue;
1437
+ const isIsOpenControlled = controlledIsOpen !== void 0;
1438
+ const isOpen = isIsOpenControlled ? controlledIsOpen : uncontrolledIsOpen;
1439
+ useEffect2(() => {
1440
+ if (selectedItem && !isOpen) {
1441
+ const selectedItemString = itemToString(selectedItem);
1442
+ if (!isInputValueControlled && uncontrolledInputValue !== selectedItemString) {
1443
+ setUncontrolledInputValue(selectedItemString);
1444
+ } else if (isInputValueControlled && inputValue !== selectedItemString) {
1445
+ updateInputValue(selectedItemString);
1446
+ }
1447
+ }
1448
+ }, [
1449
+ selectedItem,
1450
+ isOpen,
1451
+ isInputValueControlled,
1452
+ itemToString,
1453
+ uncontrolledInputValue
1454
+ ]);
1455
+ const updateSelectedItem = (newSelectedItem) => {
1456
+ const newSelectedItemId = newSelectedItem ? itemToKey(newSelectedItem) : null;
1457
+ if (!isSelectedItemIdControlled) {
1458
+ setUncontrolledSelectedItemId(newSelectedItemId);
1459
+ }
1460
+ onSelectedItemIdChange?.(newSelectedItemId);
1461
+ };
1462
+ const updateInputValue = (newInputValue) => {
1463
+ if (!isInputValueControlled) {
1464
+ setUncontrolledInputValue(newInputValue);
1465
+ }
1466
+ onInputValueChange?.(newInputValue);
1467
+ };
1468
+ const updateIsOpen = (newIsOpen) => {
1469
+ if (!isIsOpenControlled) {
1470
+ setUncontrolledIsOpen(newIsOpen);
1471
+ }
1472
+ onIsOpenChange?.(newIsOpen);
1473
+ };
1474
+ const searchStringFn = itemToSearchString ?? ((item) => itemToString(item));
1475
+ const filteredItems = useMemo5(
1476
+ () => getFilteredItems(data, inputValue, searchStringFn, itemToString, {
1477
+ selectedItem
1478
+ }),
1479
+ [data, selectedItem, inputValue, searchStringFn, itemToString]
1480
+ );
1481
+ const placeholderItem = {
1482
+ id: "clear-selection",
1483
+ label: placeholder
1484
+ };
1485
+ const items = useMemo5(() => {
1486
+ let groupedItems;
1487
+ if (groupBy) {
1488
+ groupedItems = groupItemsWithHeadings(
1489
+ filteredItems,
1490
+ groupBy,
1491
+ data,
1492
+ isVirtualized
1493
+ );
1494
+ } else {
1495
+ groupedItems = filteredItems;
1496
+ }
1497
+ groupedItems = includePlaceholderItem ? [placeholderItem, ...groupedItems] : groupedItems;
1498
+ return groupedItems;
1499
+ }, [
1500
+ filteredItems,
1501
+ placeholder,
1502
+ groupBy,
1503
+ data,
1504
+ includePlaceholderItem,
1505
+ isVirtualized
1506
+ ]);
1507
+ const itemsForCombobox = useMemo5(() => {
1508
+ return items.filter(
1509
+ (item) => !isGroupHeading(item)
1510
+ );
1511
+ }, [items]);
1512
+ const itemToStringForDownshift = useMemo5(
1513
+ () => createItemToStringForDownshift(itemToString),
1514
+ [itemToString]
1515
+ );
1516
+ const comboboxProps = useCombobox({
1517
+ inputId: id,
1518
+ items: itemsForCombobox,
1519
+ itemToString: itemToStringForDownshift,
1520
+ defaultHighlightedIndex: 0,
1521
+ selectedItem,
1522
+ inputValue,
1523
+ isOpen,
1524
+ stateReducer,
1525
+ onStateChange({
1526
+ inputValue: newInputValue,
1527
+ type,
1528
+ selectedItem: newSelectedItem,
1529
+ isOpen: newIsOpen
1530
+ }) {
1531
+ if (newIsOpen !== void 0 && type !== useCombobox.stateChangeTypes.InputBlur) {
1532
+ updateIsOpen(newIsOpen);
1533
+ }
1534
+ switch (type) {
1535
+ case useCombobox.stateChangeTypes.InputKeyDownEnter:
1536
+ case useCombobox.stateChangeTypes.ItemClick:
1537
+ if (newSelectedItem) {
1538
+ updateSelectedItem(newSelectedItem);
1539
+ if (newSelectedItem.id === "clear-selection") {
1540
+ updateInputValue("");
1541
+ return;
1542
+ }
1543
+ updateInputValue(itemToString(newSelectedItem));
1544
+ }
1545
+ break;
1546
+ case useCombobox.stateChangeTypes.InputChange:
1547
+ updateInputValue(newInputValue ?? "");
1548
+ if (newInputValue === "" && selectedItem && !isInputValueControlled) {
1549
+ updateSelectedItem(null);
1550
+ }
1551
+ break;
1552
+ default:
1553
+ break;
1554
+ }
1555
+ }
1556
+ });
1557
+ const {
1558
+ isOpen: comboboxIsOpen,
1559
+ getToggleButtonProps,
1560
+ getLabelProps,
1561
+ getMenuProps,
1562
+ getInputProps,
1563
+ highlightedIndex: comboboxHighlightedIndex,
1564
+ getItemProps,
1565
+ selectedItem: comboboxSelectedItem
1566
+ } = comboboxProps;
1567
+ const highlightedIndex = useHighlightedIndex(
1568
+ items,
1569
+ itemsForCombobox,
1570
+ comboboxHighlightedIndex,
1571
+ !!groupBy,
1572
+ false
1573
+ // Single select components hardcode selectHeadings to false
1574
+ );
1575
+ const inputProps = getInputProps();
1576
+ inputProps["aria-labelledby"] = void 0;
1577
+ if (!comboboxIsOpen) {
1578
+ inputProps["aria-controls"] = void 0;
1579
+ }
1580
+ const { ref, id: inputId, ...restProps } = inputProps;
1581
+ const handleBlur = (e) => {
1582
+ if (inputProps.onBlur) {
1583
+ inputProps.onBlur(e);
1584
+ }
1585
+ updateIsOpen(false);
1586
+ };
1587
+ return /* @__PURE__ */ jsx9(
1588
+ Popout,
1589
+ {
1590
+ open: comboboxIsOpen,
1591
+ onOpenChange: updateIsOpen,
1592
+ animationConfig: menuAnimationConfig,
1593
+ onOpenAutoFocus: (e) => {
1594
+ e.preventDefault();
1595
+ },
1596
+ onCloseAutoFocus: (e) => {
1597
+ e.preventDefault();
1598
+ },
1599
+ content: /* @__PURE__ */ jsx9(
1600
+ ComboboxContent,
1601
+ {
1602
+ items,
1603
+ getMenuProps,
1604
+ getItemProps: (props) => {
1605
+ const item = items[props.index];
1606
+ const dataItem = item;
1607
+ const itemIndex = itemsForCombobox.indexOf(dataItem);
1608
+ if (itemIndex === -1) {
1609
+ return {};
1610
+ }
1611
+ return getItemProps({ item: dataItem, index: itemIndex });
1612
+ },
1613
+ selectedItems: selectedItem ? [selectedItem] : [],
1614
+ highlightedIndex: highlightedIndex ?? -1,
1615
+ renderItem,
1616
+ renderGroupHeading,
1617
+ EmptyState,
1618
+ itemToKey,
1619
+ itemToString,
1620
+ inputType,
1621
+ selectHeadings: false,
1622
+ groupBy,
1623
+ isVirtualized,
1624
+ placeholderItem: includePlaceholderItem ? placeholderItem : void 0,
1625
+ ...menuProps
1626
+ }
1627
+ ),
1628
+ children: /* @__PURE__ */ jsx9(
1629
+ Input,
1630
+ {
1631
+ id,
1632
+ inputProps: {
1633
+ ...restProps,
1634
+ autoComplete: "off",
1635
+ onBlur: handleBlur
1636
+ },
1637
+ innerRef: ref,
1638
+ placeholder,
1639
+ elemAfter: !includePlaceholderItem ? /* @__PURE__ */ jsx9(Input.ClearButton, {}) : void 0,
1640
+ clearButtonLabel: "Clear selection",
1641
+ onClear: () => {
1642
+ updateSelectedItem(null);
1643
+ updateInputValue("");
1644
+ },
1645
+ ...restProps,
1646
+ onBlur: handleBlur
1647
+ }
1648
+ )
1649
+ }
1650
+ );
1651
+ }
1652
+
1653
+ // src/v2/Autocomplete/MultiAutocomplete.tsx
1654
+ import { useState as useState5, useMemo as useMemo6 } from "react";
1655
+ import { useCombobox as useCombobox2, useMultipleSelection as useMultipleSelection2 } from "downshift";
1656
+ import "@sproutsocial/seeds-react-label";
1657
+ import { TokenInput } from "@sproutsocial/seeds-react-token-input";
1658
+ import { jsx as jsx10 } from "react/jsx-runtime";
1659
+ function defaultReducer4(state, actionAndChanges) {
1660
+ const { changes, type } = actionAndChanges;
1661
+ switch (type) {
1662
+ case useCombobox2.stateChangeTypes.InputKeyDownEnter:
1663
+ case useCombobox2.stateChangeTypes.ItemClick:
1664
+ return {
1665
+ ...changes,
1666
+ isOpen: true,
1667
+ // keep the menu open after selection.
1668
+ highlightedIndex: 0
1669
+ // with the first option highlighted.
1670
+ };
1671
+ default:
1672
+ return changes;
1673
+ }
1674
+ }
1675
+ function MultiAutocomplete({
1676
+ id,
1677
+ data,
1678
+ selectedItemIds: controlledSelectedItemIds,
1679
+ inputValue: controlledInputValue,
1680
+ isOpen: controlledIsOpen,
1681
+ itemToKey = (item) => item?.id,
1682
+ itemToString,
1683
+ itemToSearchString,
1684
+ renderItem,
1685
+ groupBy,
1686
+ renderGroupHeading,
1687
+ isVirtualized = false,
1688
+ showSelectedItems = false,
1689
+ selectHeadings = false,
1690
+ selectAllItem,
1691
+ EmptyState,
1692
+ placeholder,
1693
+ onSelectedItemIdsChange,
1694
+ onInputValueChange,
1695
+ onIsOpenChange,
1696
+ stateReducer = defaultReducer4,
1697
+ menuProps,
1698
+ inputType = "checkbox"
1699
+ }) {
1700
+ const [uncontrolledInputValue, setUncontrolledInputValue] = useState5("");
1701
+ const [uncontrolledSelectedItemIds, setUncontrolledSelectedItemIds] = useState5([]);
1702
+ const [uncontrolledIsOpen, setUncontrolledIsOpen] = useState5(false);
1703
+ const isSelectedItemIdsControlled = controlledSelectedItemIds !== void 0;
1704
+ const selectedItemIds = isSelectedItemIdsControlled ? controlledSelectedItemIds : uncontrolledSelectedItemIds;
1705
+ const selectedItems = useMemo6(() => {
1706
+ return data.filter((item) => selectedItemIds.includes(itemToKey(item)));
1707
+ }, [selectedItemIds, data, itemToKey]);
1708
+ const isInputValueControlled = controlledInputValue !== void 0;
1709
+ const inputValue = isInputValueControlled ? controlledInputValue : uncontrolledInputValue;
1710
+ const isIsOpenControlled = controlledIsOpen !== void 0;
1711
+ const isOpen = isIsOpenControlled ? controlledIsOpen : uncontrolledIsOpen;
1712
+ const updateSelectedItems = (newSelectedItems) => {
1713
+ const newSelectedItemIds = newSelectedItems.map((item) => itemToKey(item));
1714
+ if (!isSelectedItemIdsControlled) {
1715
+ setUncontrolledSelectedItemIds(newSelectedItemIds);
1716
+ }
1717
+ onSelectedItemIdsChange?.(newSelectedItemIds);
1718
+ };
1719
+ const updateInputValue = (newInputValue) => {
1720
+ if (!isInputValueControlled) {
1721
+ setUncontrolledInputValue(newInputValue);
1722
+ }
1723
+ onInputValueChange?.(newInputValue);
1724
+ };
1725
+ const updateIsOpen = (newIsOpen) => {
1726
+ if (!isIsOpenControlled) {
1727
+ setUncontrolledIsOpen(newIsOpen);
1728
+ }
1729
+ onIsOpenChange?.(newIsOpen);
1730
+ };
1731
+ const searchStringFn = itemToSearchString ?? ((item) => itemToString(item));
1732
+ const filteredItems = useMemo6(
1733
+ () => getFilteredItems(data, inputValue, searchStringFn, itemToString, {
1734
+ selectedItems,
1735
+ showSelectedItems
1736
+ }),
1737
+ [data, selectedItems, inputValue, searchStringFn, showSelectedItems]
1738
+ );
1739
+ const items = useMemo6(() => {
1740
+ let listItems;
1741
+ if (groupBy) {
1742
+ listItems = groupItemsWithHeadings(
1743
+ filteredItems,
1744
+ groupBy,
1745
+ data,
1746
+ selectHeadings
1747
+ );
1748
+ } else {
1749
+ listItems = filteredItems;
1750
+ }
1751
+ if (selectAllItem) {
1752
+ return [selectAllItem, ...listItems];
1753
+ }
1754
+ return listItems;
1755
+ }, [filteredItems, groupBy, selectAllItem, selectHeadings, data]);
1756
+ const handleHeadingClick = useMemo6(() => {
1757
+ if (!selectHeadings || !groupBy) {
1758
+ return void 0;
1759
+ }
1760
+ return (groupLabel, allSelected) => {
1761
+ const groupItems2 = data.filter((item) => groupBy(item) === groupLabel);
1762
+ if (allSelected) {
1763
+ const newSelectedItems = selectedItems.filter(
1764
+ (item) => !groupItems2.includes(item)
1765
+ );
1766
+ updateSelectedItems(newSelectedItems);
1767
+ } else {
1768
+ const newSelectedItems = [...selectedItems];
1769
+ for (const groupItem of groupItems2) {
1770
+ if (!newSelectedItems.includes(groupItem)) {
1771
+ newSelectedItems.push(groupItem);
1772
+ }
1773
+ }
1774
+ updateSelectedItems(newSelectedItems);
1775
+ }
1776
+ };
1777
+ }, [selectHeadings, groupBy, data, selectedItems, updateSelectedItems]);
1778
+ const { getSelectedItemProps, getDropdownProps, removeSelectedItem } = useMultipleSelection2({
1779
+ selectedItems,
1780
+ onStateChange({ selectedItems: newSelectedItems, type }) {
1781
+ switch (type) {
1782
+ case useMultipleSelection2.stateChangeTypes.SelectedItemKeyDownBackspace:
1783
+ case useMultipleSelection2.stateChangeTypes.SelectedItemKeyDownDelete:
1784
+ case useMultipleSelection2.stateChangeTypes.DropdownKeyDownBackspace:
1785
+ case useMultipleSelection2.stateChangeTypes.FunctionRemoveSelectedItem:
1786
+ if (newSelectedItems !== void 0) {
1787
+ updateSelectedItems(newSelectedItems);
1788
+ }
1789
+ break;
1790
+ default:
1791
+ break;
1792
+ }
1793
+ }
1794
+ });
1795
+ const itemsForCombobox = useMemo6(() => {
1796
+ if (selectHeadings) {
1797
+ return items;
1798
+ }
1799
+ return items.filter(
1800
+ (item) => !isGroupHeading(item)
1801
+ );
1802
+ }, [items, selectHeadings]);
1803
+ const itemToStringForDownshift = useMemo6(
1804
+ () => createItemToStringForDownshift(itemToString),
1805
+ [itemToString]
1806
+ );
1807
+ const comboboxProps = useCombobox2({
1808
+ inputId: id,
1809
+ items: itemsForCombobox,
1810
+ itemToString: itemToStringForDownshift,
1811
+ defaultHighlightedIndex: 0,
1812
+ // after selection, highlight the first item.
1813
+ selectedItem: null,
1814
+ inputValue,
1815
+ isOpen,
1816
+ stateReducer,
1817
+ // Could maybe let devs override this too?
1818
+ onStateChange({
1819
+ inputValue: newInputValue,
1820
+ type,
1821
+ selectedItem: newSelectedItem,
1822
+ isOpen: newIsOpen
1823
+ }) {
1824
+ if (newIsOpen !== void 0) {
1825
+ updateIsOpen(newIsOpen);
1826
+ }
1827
+ switch (type) {
1828
+ case useCombobox2.stateChangeTypes.InputKeyDownEnter:
1829
+ case useCombobox2.stateChangeTypes.ItemClick:
1830
+ if (newSelectedItem) {
1831
+ if (selectAllItem && isToggleItem(newSelectedItem) && newSelectedItem.id === selectAllItem.id) {
1832
+ const allSelected = data.length > 0 && data.every((item) => selectedItems.includes(item));
1833
+ if (allSelected) {
1834
+ updateSelectedItems([]);
1835
+ } else {
1836
+ updateSelectedItems([...data]);
1837
+ }
1838
+ updateInputValue("");
1839
+ } else if (selectHeadings && groupBy && isGroupHeading(newSelectedItem)) {
1840
+ const groupLabel = newSelectedItem.label;
1841
+ const groupItems2 = data.filter(
1842
+ (item) => groupBy(item) === groupLabel
1843
+ );
1844
+ const allSelected = groupItems2.length > 0 && groupItems2.every((item) => selectedItems.includes(item));
1845
+ if (allSelected) {
1846
+ updateSelectedItems(
1847
+ selectedItems.filter((item) => !groupItems2.includes(item))
1848
+ );
1849
+ } else {
1850
+ const newItems = [
1851
+ ...selectedItems.filter((item) => !groupItems2.includes(item)),
1852
+ ...groupItems2
1853
+ ];
1854
+ updateSelectedItems(newItems);
1855
+ }
1856
+ updateInputValue("");
1857
+ } else if (!isGroupHeading(newSelectedItem) && !isToggleItem(newSelectedItem)) {
1858
+ const itemIndex = selectedItems.findIndex(
1859
+ (item) => itemToKey(item) === itemToKey(newSelectedItem)
1860
+ );
1861
+ if (itemIndex >= 0) {
1862
+ updateSelectedItems(
1863
+ selectedItems.filter((_, index) => index !== itemIndex)
1864
+ );
1865
+ } else {
1866
+ updateSelectedItems([...selectedItems, newSelectedItem]);
1867
+ }
1868
+ updateInputValue("");
1869
+ }
1870
+ }
1871
+ break;
1872
+ case useCombobox2.stateChangeTypes.InputChange:
1873
+ updateInputValue(newInputValue ?? "");
1874
+ break;
1875
+ default:
1876
+ break;
1877
+ }
1878
+ }
1879
+ });
1880
+ const {
1881
+ isOpen: comboboxIsOpen,
1882
+ getToggleButtonProps,
1883
+ getLabelProps,
1884
+ getMenuProps,
1885
+ getInputProps,
1886
+ highlightedIndex: comboboxHighlightedIndex,
1887
+ getItemProps,
1888
+ selectedItem
1889
+ } = comboboxProps;
1890
+ const highlightedIndex = useHighlightedIndex(
1891
+ items,
1892
+ itemsForCombobox,
1893
+ comboboxHighlightedIndex,
1894
+ !!groupBy,
1895
+ selectHeadings ?? false
1896
+ );
1897
+ const inputProps = getInputProps({ preventKeyAction: isOpen });
1898
+ inputProps["aria-labelledby"] = void 0;
1899
+ if (!comboboxIsOpen) {
1900
+ inputProps["aria-controls"] = void 0;
1901
+ }
1902
+ const handleBlur = (e) => {
1903
+ if (inputProps.onBlur) {
1904
+ inputProps.onBlur(e);
1905
+ }
1906
+ };
1907
+ const inputPropsToSpread = { ...inputProps };
1908
+ delete inputPropsToSpread.onBlur;
1909
+ return /* @__PURE__ */ jsx10(
1910
+ Popout,
1911
+ {
1912
+ open: comboboxIsOpen,
1913
+ onOpenChange: updateIsOpen,
1914
+ onOpenAutoFocus: (e) => {
1915
+ e.preventDefault();
1916
+ },
1917
+ onCloseAutoFocus: (e) => {
1918
+ e.preventDefault();
1919
+ },
1920
+ animationConfig: menuAnimationConfig,
1921
+ content: /* @__PURE__ */ jsx10(
1922
+ ComboboxContent,
1923
+ {
1924
+ items,
1925
+ getMenuProps,
1926
+ getItemProps: (props) => {
1927
+ const item = items[props.index];
1928
+ if (isToggleItem(item)) {
1929
+ return {
1930
+ onClick: () => {
1931
+ const allSelected = data.length > 0 && data.every((item2) => selectedItems.includes(item2));
1932
+ if (allSelected) {
1933
+ updateSelectedItems([]);
1934
+ } else {
1935
+ updateSelectedItems([...data]);
1936
+ }
1937
+ }
1938
+ };
1939
+ }
1940
+ const dataItem = item;
1941
+ const itemIndex = itemsForCombobox.indexOf(dataItem);
1942
+ if (itemIndex === -1) {
1943
+ return {};
1944
+ }
1945
+ return getItemProps({ item: dataItem, index: itemIndex });
1946
+ },
1947
+ selectedItems,
1948
+ highlightedIndex: highlightedIndex ?? -1,
1949
+ renderItem,
1950
+ renderGroupHeading,
1951
+ EmptyState,
1952
+ itemToKey,
1953
+ itemToString,
1954
+ inputType,
1955
+ selectHeadings,
1956
+ onHeadingClick: handleHeadingClick,
1957
+ groupBy,
1958
+ allData: data,
1959
+ selectAllItem,
1960
+ isVirtualized,
1961
+ ...menuProps
1962
+ }
1963
+ ),
1964
+ children: /* @__PURE__ */ jsx10(
1965
+ TokenInput,
1966
+ {
1967
+ placeholder,
1968
+ inputProps: {
1969
+ ...inputPropsToSpread,
1970
+ autoComplete: "off"
1971
+ // Override with "off" to prevent browser autocomplete
1972
+ },
1973
+ tokens: selectedItems.map((item) => ({
1974
+ id: String(itemToKey(item)),
1975
+ value: itemToString(item)
1976
+ })),
1977
+ onRemoveToken: (tokenId) => {
1978
+ const itemToRemove = selectedItems.find(
1979
+ (item) => String(itemToKey(item)) === tokenId
1980
+ );
1981
+ if (itemToRemove) {
1982
+ removeSelectedItem(itemToRemove);
1983
+ }
1984
+ },
1985
+ onClickToken: (e) => {
1986
+ e.stopPropagation();
1987
+ },
1988
+ onBlur: handleBlur
1989
+ }
1990
+ )
1991
+ }
1992
+ );
1993
+ }
1994
+ export {
1995
+ MultiAutocomplete,
1996
+ MultiSelect,
1997
+ SingleAutocomplete,
1998
+ SingleSelect
1999
+ };
2000
+ //# sourceMappingURL=index.js.map