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