@sproutsocial/seeds-react-menu 1.17.0 → 1.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/.turbo/turbo-build.log +14 -22
  2. package/CHANGELOG.md +30 -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 +793 -1038
  6. package/dist/esm/v3/index.js.map +1 -1
  7. package/dist/v3/index.d.mts +64 -38
  8. package/dist/v3/index.d.ts +64 -38
  9. package/dist/v3/index.js +813 -1058
  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/v3/ActionMenuStyles.tsx +169 -149
  14. package/src/v3/Common/ComboboxStyles.tsx +396 -511
  15. package/src/v3/Common/SelectIcons.tsx +17 -8
  16. package/src/v3/Common/SelectItem.tsx +25 -38
  17. package/src/v3/Common/SelectStyles.tsx +146 -144
  18. package/src/v3/Common/cn.ts +38 -0
  19. package/src/v3/MenuButtonStyles.tsx +55 -34
  20. package/src/v3/MultiSearchableSelect.tsx +8 -8
  21. package/src/v3/MultiSelect.tsx +11 -16
  22. package/src/v3/SingleSelect.tsx +13 -13
  23. package/src/v3/menu.css +947 -0
  24. package/tsup.config.ts +0 -1
  25. package/dist/esm/chunk-ROQATIB7.js +0 -357
  26. package/dist/esm/chunk-ROQATIB7.js.map +0 -1
  27. package/dist/esm/v2/index.js +0 -2089
  28. package/dist/esm/v2/index.js.map +0 -1
  29. package/dist/v2/index.d.mts +0 -108
  30. package/dist/v2/index.d.ts +0 -108
  31. package/dist/v2/index.js +0 -2280
  32. package/dist/v2/index.js.map +0 -1
  33. package/src/v2/Autocomplete/Autocomplete.stories.tsx +0 -645
  34. package/src/v2/Autocomplete/MultiAutocomplete.tsx +0 -487
  35. package/src/v2/Autocomplete/SingleAutocomplete.tsx +0 -366
  36. package/src/v2/Autocomplete/index.ts +0 -2
  37. package/src/v2/Common-V2/ComboboxContent.tsx +0 -457
  38. package/src/v2/Common-V2/MenuGroup.tsx +0 -60
  39. package/src/v2/Common-V2/MenuGroupTypes.ts +0 -30
  40. package/src/v2/Common-V2/MenuHeading.tsx +0 -83
  41. package/src/v2/Common-V2/MenuItem.tsx +0 -138
  42. package/src/v2/Common-V2/Popout.tsx +0 -124
  43. package/src/v2/Common-V2/PopoutTypes.tsx +0 -109
  44. package/src/v2/Common-V2/SelectToggleButton.tsx +0 -99
  45. package/src/v2/Common-V2/index.ts +0 -11
  46. package/src/v2/Common-V2/props.ts +0 -84
  47. package/src/v2/Common-V2/styles.tsx +0 -41
  48. package/src/v2/Common-V2/types.ts +0 -16
  49. package/src/v2/Common-V2/useHighlightedIndex.ts +0 -62
  50. package/src/v2/Common-V2/utils.ts +0 -238
  51. package/src/v2/SearchableSelect/AutocompleteContent.tsx +0 -325
  52. package/src/v2/SearchableSelect/SearchableMultiSelect.tsx +0 -527
  53. package/src/v2/SearchableSelect/SearchableSelect.tsx +0 -395
  54. package/src/v2/SearchableSelect/index.ts +0 -12
  55. package/src/v2/Select/MultiSelect.tsx +0 -417
  56. package/src/v2/Select/Select.stories.tsx +0 -593
  57. package/src/v2/Select/SingleSelect.tsx +0 -285
  58. package/src/v2/Select/index.ts +0 -2
  59. package/src/v2/index.ts +0 -2
@@ -1,285 +0,0 @@
1
- import { useState, useMemo } from "react";
2
- import { useSelect } from "downshift";
3
- import type { ReactNode } from "react";
4
- import { Label } from "@sproutsocial/seeds-react-label";
5
- // This will eventually be imported from seeds-react-popout
6
- import { Popout } from "../Common-V2";
7
- import {
8
- isGroupHeading,
9
- isToggleItem,
10
- menuAnimationConfig,
11
- groupItemsWithHeadings,
12
- useHighlightedIndex,
13
- createItemToStringForDownshift,
14
- ComboboxContent,
15
- SelectToggleButton,
16
- } from "../Common-V2";
17
- import {
18
- type DataWithId,
19
- type GroupedItem,
20
- type ToggleItem,
21
- type BaseSingleSelectProps,
22
- } from "../Common-V2";
23
-
24
- function defaultReducer(state, actionAndChanges) {
25
- const { changes, type } = actionAndChanges;
26
-
27
- switch (type) {
28
- case useSelect.stateChangeTypes.ItemClick:
29
- return {
30
- ...changes,
31
- isOpen: false, // close the menu after selection for single select
32
- highlightedIndex: 0, // reset highlight
33
- };
34
- default:
35
- return changes;
36
- }
37
- }
38
-
39
- export interface SingleSelectProps<T extends DataWithId>
40
- extends BaseSingleSelectProps<T> {
41
- itemToSelection?: (item: T) => ReactNode;
42
- renderSelection?: (item: T | null) => ReactNode;
43
- triggerButtonProps?: any;
44
- }
45
-
46
- export function SingleSelect<T extends DataWithId>({
47
- id,
48
- data,
49
- selectedItemId: controlledSelectedItemId,
50
- isOpen: controlledIsOpen,
51
- itemToKey = (item: T) => item?.id,
52
- itemToString,
53
- itemToSelection,
54
- renderSelection,
55
- renderItem,
56
- groupBy,
57
- renderGroupHeading,
58
- isVirtualized = false,
59
- estimatedItemHeight,
60
- placeholder,
61
- onSelectedItemIdChange,
62
- onIsOpenChange,
63
- stateReducer = defaultReducer,
64
- triggerButtonProps,
65
- menuProps,
66
- inputType = "icon",
67
- removePlaceholderItem = false,
68
- onPointerDownOutside,
69
- onInteractOutside,
70
- popoutPlacement,
71
- }: SingleSelectProps<T>) {
72
- const [uncontrolledSelectedItemId, setUncontrolledSelectedItemId] = useState<
73
- T["id"] | null
74
- >(null);
75
- const [uncontrolledIsOpen, setUncontrolledIsOpen] = useState<boolean>(false);
76
-
77
- // Use controlled selectedItemId if provided, otherwise use internal state
78
- const isSelectedItemIdControlled = controlledSelectedItemId !== undefined;
79
- const selectedItemId = isSelectedItemIdControlled
80
- ? controlledSelectedItemId
81
- : uncontrolledSelectedItemId;
82
-
83
- // Convert selectedItemId to selectedItem for internal use
84
- const selectedItem = useMemo<T | null>(() => {
85
- if (selectedItemId === null || selectedItemId === undefined) {
86
- return null;
87
- }
88
- return data.find((item) => itemToKey(item) === selectedItemId) ?? null;
89
- }, [selectedItemId, data, itemToKey]);
90
-
91
- // Use controlled isOpen if provided, otherwise use internal state
92
- const isIsOpenControlled = controlledIsOpen !== undefined;
93
- const isOpen = isIsOpenControlled ? controlledIsOpen : uncontrolledIsOpen;
94
-
95
- const updateSelectedItem = (newSelectedItem: T | null) => {
96
- const newSelectedItemId = newSelectedItem
97
- ? itemToKey(newSelectedItem)
98
- : null;
99
- if (!isSelectedItemIdControlled) {
100
- setUncontrolledSelectedItemId(newSelectedItemId);
101
- }
102
- onSelectedItemIdChange?.(newSelectedItemId);
103
- };
104
-
105
- const updateIsOpen = (newIsOpen: boolean) => {
106
- if (!isIsOpenControlled) {
107
- setUncontrolledIsOpen(newIsOpen);
108
- }
109
- onIsOpenChange?.(newIsOpen);
110
- };
111
-
112
- // TODO: This could be made generic as a hook and used in other components
113
- // For Select, we show all items (no filtering)
114
- const items = useMemo<GroupedItem<T>[]>(() => {
115
- let groupedItems: GroupedItem<T>[];
116
-
117
- const placeholderItem: ToggleItem = {
118
- id: "clear-selection",
119
- label: placeholder,
120
- };
121
-
122
- if (groupBy) {
123
- // Group first, then add placeholderItem at the beginning
124
- groupedItems = groupItemsWithHeadings(data, groupBy, data, true);
125
- } else {
126
- groupedItems = data;
127
- }
128
- if (!removePlaceholderItem) {
129
- groupedItems = [placeholderItem, ...groupedItems];
130
- }
131
-
132
- return groupedItems;
133
- }, [data, groupBy, placeholder]);
134
-
135
- // Filter out headings for downshift
136
- const itemsForSelect = useMemo<(T | ToggleItem)[]>(() => {
137
- // This is unnecessary for single select because we don't have group headings
138
- return items.filter((item): item is T => !isGroupHeading(item));
139
- }, [items]);
140
-
141
- // Wrapper function to handle ToggleItem separately
142
- const itemToStringForDownshift = useMemo(
143
- () => createItemToStringForDownshift(itemToString),
144
- [itemToString]
145
- );
146
-
147
- const selectProps = useSelect<T | ToggleItem>({
148
- toggleButtonId: id,
149
- items: itemsForSelect,
150
- itemToString: itemToStringForDownshift,
151
- // defaultHighlightedIndex: 0,
152
- selectedItem: selectedItem,
153
- isOpen,
154
- stateReducer,
155
- onStateChange({ type, selectedItem: newSelectedItem, isOpen: newIsOpen }) {
156
- // Handle isOpen changes for any state change type
157
- if (newIsOpen !== undefined) {
158
- updateIsOpen(newIsOpen);
159
- }
160
-
161
- // Handle item selection for both click and keyboard (Enter/Space) interactions
162
- // When Enter/Space is pressed on a highlighted item, useSelect sets selectedItem
163
- // We detect selection when selectedItem changes and it's a user interaction
164
- const isSelectionEvent =
165
- type === useSelect.stateChangeTypes.ItemClick ||
166
- type === useSelect.stateChangeTypes.ToggleButtonKeyDownEnter;
167
-
168
- if (isSelectionEvent && newSelectedItem && newSelectedItem !== null) {
169
- // If placeholderItem is selected, set selectedItem to null
170
- // Note: placeholderItem won't be in itemsForSelect, so this check is for safety
171
- if (newSelectedItem.id === "clear-selection") {
172
- updateSelectedItem(null);
173
- } else {
174
- updateSelectedItem(newSelectedItem as T);
175
- }
176
- }
177
- },
178
- });
179
-
180
- const {
181
- isOpen: selectIsOpen,
182
- getToggleButtonProps,
183
- getLabelProps,
184
- getMenuProps,
185
- highlightedIndex: selectHighlightedIndex,
186
- getItemProps,
187
- } = selectProps;
188
-
189
- // Map the highlighted index from select (which only knows about items) to the full items array (which includes headings)
190
- const highlightedIndex = useHighlightedIndex(
191
- items,
192
- itemsForSelect,
193
- selectHighlightedIndex,
194
- !!groupBy,
195
- false // Single select components hardcode selectHeadings to false
196
- );
197
-
198
- const buttonContent = renderSelection
199
- ? renderSelection(selectedItem)
200
- : selectedItem
201
- ? itemToSelection
202
- ? itemToSelection(selectedItem)
203
- : itemToString(selectedItem)
204
- : placeholder;
205
-
206
- const toggleButtonProps = getToggleButtonProps();
207
- // Downshift adds aria-labelledby by default, which can conflict with our Label usage
208
- toggleButtonProps["aria-labelledby"] = undefined;
209
- if (!selectIsOpen) {
210
- // Remove aria-controls when the menu is closed to avoid referencing a non-existent element
211
- // @ts-expect-error downshift types require aria-controls even though it is not required
212
- toggleButtonProps["aria-controls"] = undefined;
213
- }
214
-
215
- return (
216
- <Popout
217
- open={selectIsOpen}
218
- onOpenChange={updateIsOpen}
219
- side={popoutPlacement}
220
- animationConfig={menuAnimationConfig}
221
- onOpenAutoFocus={(e) => {
222
- // Prevent default auto-focus behavior
223
- e.preventDefault();
224
- }}
225
- onCloseAutoFocus={(e) => {
226
- // Prevent default auto-focus behavior
227
- e.preventDefault();
228
- }}
229
- onPointerDownOutside={onPointerDownOutside}
230
- onInteractOutside={onInteractOutside}
231
- content={
232
- <ComboboxContent
233
- items={items}
234
- getMenuProps={getMenuProps}
235
- getItemProps={(props: { index: number }) => {
236
- // Only apply getItemProps to actual items, not headings or ToggleItems
237
- const item = items[props.index];
238
- if (isToggleItem(item)) {
239
- // Handle ToggleItem (placeholderItem) clicks manually
240
- return {
241
- onClick: () => {
242
- if (item.id === "clear-selection") {
243
- updateSelectedItem(null);
244
- }
245
- },
246
- };
247
- }
248
- const dataItem = item as T;
249
- // Find the index in itemsForSelect using itemToKey for safer comparison
250
- const itemIndex = itemsForSelect.findIndex((selectItem) => {
251
- if (isToggleItem(selectItem)) {
252
- return false;
253
- }
254
- return itemToKey(selectItem as T) === itemToKey(dataItem);
255
- });
256
- if (itemIndex === -1) {
257
- return {};
258
- }
259
- return getItemProps({ item: dataItem, index: itemIndex });
260
- }}
261
- selectedItems={selectedItem ? [selectedItem] : []}
262
- highlightedIndex={highlightedIndex ?? -1}
263
- renderItem={renderItem}
264
- renderGroupHeading={renderGroupHeading}
265
- itemToKey={itemToKey}
266
- itemToString={itemToString}
267
- inputType={inputType}
268
- isVirtualized={isVirtualized}
269
- estimatedItemHeight={estimatedItemHeight}
270
- groupBy={groupBy}
271
- selectHeadings={false}
272
- {...menuProps}
273
- />
274
- }
275
- >
276
- <SelectToggleButton
277
- {...toggleButtonProps}
278
- {...triggerButtonProps}
279
- isOpen={selectIsOpen}
280
- >
281
- {buttonContent}
282
- </SelectToggleButton>
283
- </Popout>
284
- );
285
- }
@@ -1,2 +0,0 @@
1
- export * from "./SingleSelect";
2
- export * from "./MultiSelect";
package/src/v2/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from "./Select";
2
- export * from "./Autocomplete";