@sproutsocial/seeds-react-menu 1.10.8 → 1.11.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 (50) hide show
  1. package/.turbo/turbo-build.log +21 -15
  2. package/CHANGELOG.md +22 -0
  3. package/dist/esm/index.js +45 -24
  4. package/dist/esm/index.js.map +1 -1
  5. package/dist/esm/v2/index.js +1 -1
  6. package/dist/esm/v2/index.js.map +1 -1
  7. package/dist/esm/v3/index.js +800 -0
  8. package/dist/esm/v3/index.js.map +1 -0
  9. package/dist/index.d.mts +22 -22
  10. package/dist/index.d.ts +22 -22
  11. package/dist/index.js +35 -14
  12. package/dist/index.js.map +1 -1
  13. package/dist/v2/index.js +1 -1
  14. package/dist/v2/index.js.map +1 -1
  15. package/dist/v3/index.d.mts +295 -0
  16. package/dist/v3/index.d.ts +295 -0
  17. package/dist/v3/index.js +868 -0
  18. package/dist/v3/index.js.map +1 -0
  19. package/package.json +7 -1
  20. package/src/MenuGroup/MenuGroup.tsx +16 -3
  21. package/src/MenuGroup/__tests__/MenuGroup.test.tsx +19 -0
  22. package/src/MenuItem/MenuItem.tsx +21 -10
  23. package/src/MenuItem/__tests__/MenuItem.test.tsx +19 -0
  24. package/src/v2/Common-V2/ComboboxContent.tsx +1 -1
  25. package/src/v3/Common/ComboboxItem.tsx +82 -0
  26. package/src/v3/Common/ComboboxStyles.tsx +475 -0
  27. package/src/v3/Common/SelectGroup.tsx +28 -0
  28. package/src/v3/Common/SelectIcons.tsx +26 -0
  29. package/src/v3/Common/SelectItem.tsx +108 -0
  30. package/src/v3/Common/SelectStyles.tsx +126 -0
  31. package/src/v3/Common/VirtualizedComboboxList.tsx +200 -0
  32. package/src/v3/Common/groupItems.ts +12 -0
  33. package/src/v3/Common/types.ts +3 -0
  34. package/src/v3/ModalStories.stories.tsx +181 -0
  35. package/src/v3/MultiCombobox.stories.tsx +322 -0
  36. package/src/v3/MultiCombobox.tsx +562 -0
  37. package/src/v3/MultiSearchableSelect.stories.tsx +389 -0
  38. package/src/v3/MultiSearchableSelect.tsx +545 -0
  39. package/src/v3/MultiSelect.stories.tsx +300 -0
  40. package/src/v3/MultiSelect.tsx +498 -0
  41. package/src/v3/SeedsPortal.tsx +35 -0
  42. package/src/v3/SingleCombobox.stories.tsx +169 -0
  43. package/src/v3/SingleCombobox.tsx +304 -0
  44. package/src/v3/SingleSearchableSelect.stories.tsx +239 -0
  45. package/src/v3/SingleSearchableSelect.tsx +319 -0
  46. package/src/v3/SingleSelect.stories.tsx +227 -0
  47. package/src/v3/SingleSelect.tsx +245 -0
  48. package/src/v3/index.ts +7 -0
  49. package/src/v3/storyData.tsx +117 -0
  50. package/tsup.config.ts +1 -0
@@ -0,0 +1,389 @@
1
+ import React from "react";
2
+ import type { Meta, StoryObj } from "@storybook/react";
3
+ import { FormField } from "@sproutsocial/seeds-react-form-field";
4
+ import MultiSearchableSelect from "./MultiSearchableSelect";
5
+ import { books, largeBookSet, itemToString, renderItem } from "./storyData";
6
+
7
+ const meta: Meta<typeof MultiSearchableSelect> = {
8
+ title: "Really Under Development/V3/Multi Searchable Select",
9
+ component: MultiSearchableSelect,
10
+ };
11
+
12
+ export default meta;
13
+ type Story = StoryObj<typeof MultiSearchableSelect>;
14
+
15
+ export const Basic: Story = {
16
+ name: "Basic",
17
+ render: () => (
18
+ <div style={{ width: "300px" }}>
19
+ <FormField label="Pick books">
20
+ {({ id }) => (
21
+ <MultiSearchableSelect
22
+ id={id}
23
+ data={books}
24
+ itemToString={itemToString}
25
+ placeholder="Select books"
26
+ searchPlaceholder="Search books..."
27
+ />
28
+ )}
29
+ </FormField>
30
+ </div>
31
+ ),
32
+ };
33
+
34
+ export const CustomRenderItem: Story = {
35
+ name: "Custom render item",
36
+ render: () => (
37
+ <div style={{ width: "300px" }}>
38
+ <FormField label="Pick books">
39
+ {({ id }) => (
40
+ <MultiSearchableSelect
41
+ id={id}
42
+ data={books}
43
+ itemToString={itemToString}
44
+ renderItem={renderItem}
45
+ placeholder="Select books"
46
+ searchPlaceholder="Search books..."
47
+ />
48
+ )}
49
+ </FormField>
50
+ </div>
51
+ ),
52
+ };
53
+
54
+ export const Grouped: Story = {
55
+ name: "Grouped",
56
+ render: () => (
57
+ <div style={{ width: "300px" }}>
58
+ <FormField label="Pick books">
59
+ {({ id }) => (
60
+ <MultiSearchableSelect
61
+ id={id}
62
+ data={books}
63
+ itemToString={itemToString}
64
+ renderItem={renderItem}
65
+ placeholder="Select books"
66
+ searchPlaceholder="Search books..."
67
+ groupBy={(book) => book.author}
68
+ />
69
+ )}
70
+ </FormField>
71
+ </div>
72
+ ),
73
+ };
74
+
75
+ export const DefaultSelected: Story = {
76
+ name: "Default selected",
77
+ render: () => (
78
+ <div style={{ width: "300px" }}>
79
+ <FormField label="Pick books">
80
+ {({ id }) => (
81
+ <MultiSearchableSelect
82
+ id={id}
83
+ data={books}
84
+ itemToString={itemToString}
85
+ renderItem={renderItem}
86
+ placeholder="Select books"
87
+ searchPlaceholder="Search books..."
88
+ defaultSelectedItemIds={["book-1", "book-3"]}
89
+ />
90
+ )}
91
+ </FormField>
92
+ </div>
93
+ ),
94
+ };
95
+
96
+ export const Controlled: Story = {
97
+ name: "Controlled",
98
+ render: () => {
99
+ const [selectedIds, setSelectedIds] = React.useState<string[]>(["book-2"]);
100
+ const selected = books.filter((b) => selectedIds.includes(b.id));
101
+ return (
102
+ <div
103
+ style={{
104
+ width: "300px",
105
+ display: "flex",
106
+ flexDirection: "column",
107
+ gap: 16,
108
+ }}
109
+ >
110
+ <FormField label="Pick books">
111
+ {({ id }) => (
112
+ <MultiSearchableSelect
113
+ id={id}
114
+ data={books}
115
+ itemToString={itemToString}
116
+ renderItem={renderItem}
117
+ placeholder="Select books"
118
+ searchPlaceholder="Search books..."
119
+ selectedItemIds={selectedIds}
120
+ onSelectedItemIdsChange={(ids: string[]) => setSelectedIds(ids)}
121
+ />
122
+ )}
123
+ </FormField>
124
+ <div style={{ fontSize: 13 }}>
125
+ Selected:{" "}
126
+ <strong>
127
+ {selected.length > 0
128
+ ? selected.map((b) => b.title).join(", ")
129
+ : "none"}
130
+ </strong>
131
+ </div>
132
+ <div style={{ display: "flex", gap: 8 }}>
133
+ <button onClick={() => setSelectedIds([])}>Clear all</button>
134
+ <button onClick={() => setSelectedIds(["book-5", "book-7"])}>
135
+ Select 1984 &amp; Meditations
136
+ </button>
137
+ </div>
138
+ </div>
139
+ );
140
+ },
141
+ };
142
+
143
+ export const CustomSelection: Story = {
144
+ name: "Custom renderSelection",
145
+ render: () => (
146
+ <div style={{ width: "300px" }}>
147
+ <FormField label="Pick books">
148
+ {({ id }) => (
149
+ <MultiSearchableSelect
150
+ id={id}
151
+ data={books}
152
+ itemToString={itemToString}
153
+ renderItem={renderItem}
154
+ placeholder="Select books"
155
+ searchPlaceholder="Search books..."
156
+ renderSelection={(selected) => {
157
+ if (selected.length === 0) return "Select books";
158
+ const first = itemToString(selected[0]);
159
+ const extra =
160
+ selected.length > 1 ? ` (+${selected.length - 1})` : "";
161
+ return (
162
+ <span style={{ fontSize: 13 }}>
163
+ {first}
164
+ {extra}
165
+ </span>
166
+ );
167
+ }}
168
+ />
169
+ )}
170
+ </FormField>
171
+ </div>
172
+ ),
173
+ };
174
+
175
+ export const CustomRenderSelections: Story = {
176
+ name: "Custom customRenderSelections",
177
+ render: () => (
178
+ <div style={{ width: "300px" }}>
179
+ <FormField label="Pick books">
180
+ {({ id }) => (
181
+ <MultiSearchableSelect
182
+ id={id}
183
+ data={books}
184
+ itemToString={itemToString}
185
+ renderItem={renderItem}
186
+ placeholder="Select books"
187
+ searchPlaceholder="Search books..."
188
+ customRenderSelections={(item) => `${item.title} (${item.author})`}
189
+ />
190
+ )}
191
+ </FormField>
192
+ </div>
193
+ ),
194
+ };
195
+
196
+ export const SelectableHeadings: Story = {
197
+ name: "Selectable headings",
198
+ render: () => (
199
+ <div style={{ width: "300px" }}>
200
+ <FormField label="Pick books">
201
+ {({ id }) => (
202
+ <MultiSearchableSelect
203
+ id={id}
204
+ data={books}
205
+ itemToString={itemToString}
206
+ renderItem={renderItem}
207
+ placeholder="Select books"
208
+ searchPlaceholder="Search books..."
209
+ groupBy={(book) => book.author}
210
+ selectHeadings
211
+ />
212
+ )}
213
+ </FormField>
214
+ </div>
215
+ ),
216
+ };
217
+
218
+ export const SelectAll: Story = {
219
+ name: "Select all",
220
+ render: () => (
221
+ <div style={{ width: "300px" }}>
222
+ <FormField label="Pick books">
223
+ {({ id }) => (
224
+ <MultiSearchableSelect
225
+ id={id}
226
+ data={books}
227
+ itemToString={itemToString}
228
+ renderItem={renderItem}
229
+ placeholder="Select books"
230
+ searchPlaceholder="Search books..."
231
+ groupBy={(book) => book.author}
232
+ selectHeadings
233
+ selectAll
234
+ />
235
+ )}
236
+ </FormField>
237
+ </div>
238
+ ),
239
+ };
240
+
241
+ export const Virtualized: Story = {
242
+ name: "Virtualized",
243
+ render: () => (
244
+ <div style={{ width: "300px" }}>
245
+ <FormField label="Pick books">
246
+ {({ id }) => (
247
+ <MultiSearchableSelect
248
+ id={id}
249
+ data={largeBookSet}
250
+ itemToString={itemToString}
251
+ renderItem={renderItem}
252
+ placeholder="Select books"
253
+ searchPlaceholder="Search books..."
254
+ groupBy={(book) => book.author}
255
+ selectHeadings
256
+ isVirtualized
257
+ />
258
+ )}
259
+ </FormField>
260
+ </div>
261
+ ),
262
+ };
263
+
264
+ export const MaxSelections: Story = {
265
+ name: "Max selections",
266
+ render: () => (
267
+ <div style={{ width: "300px" }}>
268
+ <FormField label="Pick books">
269
+ {({ id }) => (
270
+ <MultiSearchableSelect
271
+ id={id}
272
+ data={books}
273
+ itemToString={itemToString}
274
+ renderItem={renderItem}
275
+ placeholder="Select books"
276
+ searchPlaceholder="Search books..."
277
+ defaultSelectedItemIds={[
278
+ "book-1",
279
+ "book-2",
280
+ "book-3",
281
+ "book-4",
282
+ "book-5",
283
+ ]}
284
+ maxSelections={2}
285
+ />
286
+ )}
287
+ </FormField>
288
+ </div>
289
+ ),
290
+ };
291
+
292
+ export const RemoveSelectedItems: Story = {
293
+ name: "Remove selected items",
294
+ render: () => (
295
+ <div style={{ width: "300px" }}>
296
+ <FormField label="Pick books">
297
+ {({ id }) => (
298
+ <MultiSearchableSelect
299
+ id={id}
300
+ data={books}
301
+ itemToString={itemToString}
302
+ renderItem={renderItem}
303
+ placeholder="Select books"
304
+ searchPlaceholder="Search books..."
305
+ removeSelectedItems
306
+ />
307
+ )}
308
+ </FormField>
309
+ </div>
310
+ ),
311
+ };
312
+
313
+ export const VirtualizedSelectAll: Story = {
314
+ name: "Virtualized + select all",
315
+ render: () => (
316
+ <div style={{ width: "300px" }}>
317
+ <FormField label="Pick books">
318
+ {({ id }) => (
319
+ <MultiSearchableSelect
320
+ id={id}
321
+ data={largeBookSet}
322
+ itemToString={itemToString}
323
+ renderItem={renderItem}
324
+ placeholder="Select books"
325
+ searchPlaceholder="Search books..."
326
+ groupBy={(book) => book.author}
327
+ selectHeadings
328
+ selectAll
329
+ isVirtualized
330
+ />
331
+ )}
332
+ </FormField>
333
+ </div>
334
+ ),
335
+ };
336
+
337
+ export const Loading: Story = {
338
+ name: "Loading",
339
+ render: () => (
340
+ <div style={{ width: "300px" }}>
341
+ <FormField label="Pick books">
342
+ {({ id }) => (
343
+ <MultiSearchableSelect
344
+ id={id}
345
+ data={[]}
346
+ itemToString={itemToString}
347
+ placeholder="Select books"
348
+ searchPlaceholder="Search books..."
349
+ isLoading
350
+ />
351
+ )}
352
+ </FormField>
353
+ </div>
354
+ ),
355
+ };
356
+
357
+ export const LoadingWithToggle: Story = {
358
+ name: "Loading (toggle)",
359
+ render: () => {
360
+ const [isLoading, setIsLoading] = React.useState(true);
361
+ const data = isLoading ? [] : books;
362
+ return (
363
+ <div
364
+ style={{
365
+ width: "300px",
366
+ display: "flex",
367
+ flexDirection: "column",
368
+ gap: 16,
369
+ }}
370
+ >
371
+ <FormField label="Pick books">
372
+ {({ id }) => (
373
+ <MultiSearchableSelect
374
+ id={id}
375
+ data={data}
376
+ itemToString={itemToString}
377
+ placeholder="Select books"
378
+ searchPlaceholder="Search books..."
379
+ isLoading={isLoading}
380
+ />
381
+ )}
382
+ </FormField>
383
+ <button onClick={() => setIsLoading((v) => !v)}>
384
+ {isLoading ? "Finish loading" : "Set loading"}
385
+ </button>
386
+ </div>
387
+ );
388
+ },
389
+ };