@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.
- package/.turbo/turbo-build.log +14 -22
- package/CHANGELOG.md +51 -0
- package/dist/esm/index.js +542 -229
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/v3/index.js +870 -1081
- package/dist/esm/v3/index.js.map +1 -1
- package/dist/v3/index.d.mts +82 -38
- package/dist/v3/index.d.ts +82 -38
- package/dist/v3/index.js +887 -1098
- package/dist/v3/index.js.map +1 -1
- package/dist/v3/menu.css +947 -0
- package/package.json +20 -21
- package/src/ActionMenu/ActionMenu.stories.tsx +1 -1
- package/src/Autocomplete/Autocomplete.stories.tsx +1 -1
- package/src/MenuContent/MenuContent.stories.tsx +1 -1
- package/src/MenuFooter/MenuFooter.stories.tsx +1 -1
- package/src/MenuGroup/MenuGroup.stories.tsx +1 -1
- package/src/MenuHeader/MenuHeader.stories.tsx +1 -1
- package/src/MenuItem/MenuItem.stories.tsx +1 -1
- package/src/MenuToggleButton/MenuToggleButton.stories.tsx +1 -1
- package/src/MultiSelectMenu/MultiSelectMenu.stories.tsx +1 -1
- package/src/NestedMenu/NestedMenu.stories.tsx +1 -1
- package/src/SingleSelectMenu/SingleSelectMenu.stories.tsx +1 -1
- package/src/SubmenuItem/SubmenuItem.stories.tsx +1 -1
- package/src/v3/ActionMenu.stories.tsx +1 -1
- package/src/v3/ActionMenuStyles.tsx +169 -149
- package/src/v3/Common/ComboboxStyles.tsx +396 -511
- package/src/v3/Common/SelectIcons.tsx +17 -8
- package/src/v3/Common/SelectItem.tsx +25 -38
- package/src/v3/Common/SelectStyles.tsx +146 -144
- package/src/v3/Common/cn.ts +38 -0
- package/src/v3/MenuButton.stories.tsx +1 -1
- package/src/v3/MenuButtonStyles.tsx +55 -34
- package/src/v3/ModalStories.stories.tsx +1 -1
- package/src/v3/MultiCombobox.stories.tsx +1 -1
- package/src/v3/MultiCombobox.tsx +7 -0
- package/src/v3/MultiSearchableSelect.stories.tsx +1 -1
- package/src/v3/MultiSearchableSelect.tsx +15 -8
- package/src/v3/MultiSelect.stories.tsx +1 -1
- package/src/v3/MultiSelect.tsx +20 -17
- package/src/v3/SingleCombobox.stories.tsx +1 -1
- package/src/v3/SingleCombobox.tsx +7 -0
- package/src/v3/SingleSearchableSelect.stories.tsx +1 -1
- package/src/v3/SingleSearchableSelect.tsx +7 -0
- package/src/v3/SingleSelect.stories.tsx +1 -1
- package/src/v3/SingleSelect.tsx +22 -14
- package/src/v3/__tests__/ariaLabels.test.tsx +133 -0
- package/src/v3/menu.css +947 -0
- package/tsup.config.ts +0 -1
- package/dist/esm/chunk-ROQATIB7.js +0 -357
- package/dist/esm/chunk-ROQATIB7.js.map +0 -1
- package/dist/esm/v2/index.js +0 -2089
- package/dist/esm/v2/index.js.map +0 -1
- package/dist/v2/index.d.mts +0 -108
- package/dist/v2/index.d.ts +0 -108
- package/dist/v2/index.js +0 -2280
- package/dist/v2/index.js.map +0 -1
- package/src/v2/Autocomplete/Autocomplete.stories.tsx +0 -645
- package/src/v2/Autocomplete/MultiAutocomplete.tsx +0 -487
- package/src/v2/Autocomplete/SingleAutocomplete.tsx +0 -366
- package/src/v2/Autocomplete/index.ts +0 -2
- package/src/v2/Common-V2/ComboboxContent.tsx +0 -457
- package/src/v2/Common-V2/MenuGroup.tsx +0 -60
- package/src/v2/Common-V2/MenuGroupTypes.ts +0 -30
- package/src/v2/Common-V2/MenuHeading.tsx +0 -83
- package/src/v2/Common-V2/MenuItem.tsx +0 -138
- package/src/v2/Common-V2/Popout.tsx +0 -124
- package/src/v2/Common-V2/PopoutTypes.tsx +0 -109
- package/src/v2/Common-V2/SelectToggleButton.tsx +0 -99
- package/src/v2/Common-V2/index.ts +0 -11
- package/src/v2/Common-V2/props.ts +0 -84
- package/src/v2/Common-V2/styles.tsx +0 -41
- package/src/v2/Common-V2/types.ts +0 -16
- package/src/v2/Common-V2/useHighlightedIndex.ts +0 -62
- package/src/v2/Common-V2/utils.ts +0 -238
- package/src/v2/SearchableSelect/AutocompleteContent.tsx +0 -325
- package/src/v2/SearchableSelect/SearchableMultiSelect.tsx +0 -527
- package/src/v2/SearchableSelect/SearchableSelect.tsx +0 -395
- package/src/v2/SearchableSelect/index.ts +0 -12
- package/src/v2/Select/MultiSelect.tsx +0 -417
- package/src/v2/Select/Select.stories.tsx +0 -593
- package/src/v2/Select/SingleSelect.tsx +0 -285
- package/src/v2/Select/index.ts +0 -2
- package/src/v2/index.ts +0 -2
|
@@ -1,645 +0,0 @@
|
|
|
1
|
-
/* eslint-disable react-hooks/rules-of-hooks */
|
|
2
|
-
import React from "react";
|
|
3
|
-
import type { Meta, StoryObj } from "@storybook/react";
|
|
4
|
-
import { action } from "@storybook/addon-actions";
|
|
5
|
-
|
|
6
|
-
import { Box } from "@sproutsocial/seeds-react-box";
|
|
7
|
-
import { FormField } from "@sproutsocial/seeds-react-form-field";
|
|
8
|
-
import { Icon } from "@sproutsocial/seeds-react-icon";
|
|
9
|
-
|
|
10
|
-
import { MultiAutocomplete } from "./MultiAutocomplete";
|
|
11
|
-
import { SingleAutocomplete } from "./SingleAutocomplete";
|
|
12
|
-
import Button from "@sproutsocial/seeds-react-button";
|
|
13
|
-
import type { ToggleItem, GroupHeading } from "../Common-V2";
|
|
14
|
-
|
|
15
|
-
type CustomAutocompleteArgs = React.ComponentProps<typeof MultiAutocomplete>;
|
|
16
|
-
|
|
17
|
-
const meta: Meta<CustomAutocompleteArgs> = {
|
|
18
|
-
title: "Really Under Development/Autocomplete",
|
|
19
|
-
component: MultiAutocomplete,
|
|
20
|
-
parameters: {
|
|
21
|
-
controls: {
|
|
22
|
-
expanded: true,
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
decorators: [
|
|
26
|
-
(Story) => (
|
|
27
|
-
<Box display="flex" flexDirection="column" gap="16px" maxWidth={350}>
|
|
28
|
-
<Story />
|
|
29
|
-
</Box>
|
|
30
|
-
),
|
|
31
|
-
],
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export default meta;
|
|
35
|
-
|
|
36
|
-
type Story = StoryObj<CustomAutocompleteArgs>;
|
|
37
|
-
|
|
38
|
-
interface Book {
|
|
39
|
-
id: string;
|
|
40
|
-
author: string;
|
|
41
|
-
title: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const books: Book[] = [
|
|
45
|
-
{ id: "book-1", author: "Harper Lee", title: "To Kill a Mockingbird" },
|
|
46
|
-
{ id: "book-2", author: "Lev Tolstoy", title: "War and Peace" },
|
|
47
|
-
{ id: "book-3", author: "Fyodor Dostoyevsy", title: "The Idiot" },
|
|
48
|
-
{ id: "book-4", author: "Oscar Wilde", title: "A Picture of Dorian Gray" },
|
|
49
|
-
{ id: "book-5", author: "George Orwell", title: "1984" },
|
|
50
|
-
{ id: "book-6", author: "Jane Austen", title: "Pride and Prejudice" },
|
|
51
|
-
{ id: "book-7", author: "Marcus Aurelius", title: "Meditations" },
|
|
52
|
-
{
|
|
53
|
-
id: "book-8",
|
|
54
|
-
author: "Fyodor Dostoevsky",
|
|
55
|
-
title: "The Brothers Karamazov",
|
|
56
|
-
},
|
|
57
|
-
{ id: "book-9", author: "Lev Tolstoy", title: "Anna Karenina" },
|
|
58
|
-
{ id: "book-10", author: "Fyodor Dostoevsky", title: "Crime and Punishment" },
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
// Generate 1000 books for virtualization testing
|
|
62
|
-
const generateBooks = (count: number): Book[] => {
|
|
63
|
-
const authors = [
|
|
64
|
-
"Harper Lee",
|
|
65
|
-
"Lev Tolstoy",
|
|
66
|
-
"Fyodor Dostoevsky",
|
|
67
|
-
"Oscar Wilde",
|
|
68
|
-
"George Orwell",
|
|
69
|
-
"Jane Austen",
|
|
70
|
-
"Marcus Aurelius",
|
|
71
|
-
"Ernest Hemingway",
|
|
72
|
-
"Virginia Woolf",
|
|
73
|
-
"James Joyce",
|
|
74
|
-
"Charles Dickens",
|
|
75
|
-
"Mark Twain",
|
|
76
|
-
"J.R.R. Tolkien",
|
|
77
|
-
"C.S. Lewis",
|
|
78
|
-
"Agatha Christie",
|
|
79
|
-
"Arthur Conan Doyle",
|
|
80
|
-
"J.K. Rowling",
|
|
81
|
-
"Stephen King",
|
|
82
|
-
"Isaac Asimov",
|
|
83
|
-
"Ray Bradbury",
|
|
84
|
-
"Aldous Huxley",
|
|
85
|
-
"Kurt Vonnegut",
|
|
86
|
-
"J.D. Salinger",
|
|
87
|
-
"Maya Angelou",
|
|
88
|
-
"Toni Morrison",
|
|
89
|
-
"Gabriel García Márquez",
|
|
90
|
-
"Milan Kundera",
|
|
91
|
-
"Umberto Eco",
|
|
92
|
-
"Haruki Murakami",
|
|
93
|
-
"Chimamanda Ngozi Adichie",
|
|
94
|
-
];
|
|
95
|
-
|
|
96
|
-
const titleWords = [
|
|
97
|
-
"Adventures",
|
|
98
|
-
"Chronicles",
|
|
99
|
-
"Memories",
|
|
100
|
-
"Journey",
|
|
101
|
-
"Quest",
|
|
102
|
-
"Tales",
|
|
103
|
-
"Stories",
|
|
104
|
-
"Legends",
|
|
105
|
-
"Myths",
|
|
106
|
-
"Dreams",
|
|
107
|
-
"Visions",
|
|
108
|
-
"Revelations",
|
|
109
|
-
"Secrets",
|
|
110
|
-
"Mysteries",
|
|
111
|
-
"Shadows",
|
|
112
|
-
"Light",
|
|
113
|
-
"Darkness",
|
|
114
|
-
"Echoes",
|
|
115
|
-
"Whispers",
|
|
116
|
-
"Voices",
|
|
117
|
-
"Songs",
|
|
118
|
-
"Poems",
|
|
119
|
-
];
|
|
120
|
-
|
|
121
|
-
const books: Book[] = [];
|
|
122
|
-
for (let i = 0; i < count; i++) {
|
|
123
|
-
const author = authors[i % authors.length];
|
|
124
|
-
const titleWord1 =
|
|
125
|
-
titleWords[Math.floor(Math.random() * titleWords.length)];
|
|
126
|
-
const titleWord2 =
|
|
127
|
-
titleWords[Math.floor(Math.random() * titleWords.length)];
|
|
128
|
-
const number = Math.floor(i / authors.length) + 1;
|
|
129
|
-
const title = `${titleWord1} of ${titleWord2} ${number}`;
|
|
130
|
-
|
|
131
|
-
books.push({
|
|
132
|
-
id: `book-${i + 1}`,
|
|
133
|
-
author,
|
|
134
|
-
title,
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return books;
|
|
139
|
-
};
|
|
140
|
-
const largeBookSet = generateBooks(100);
|
|
141
|
-
|
|
142
|
-
const renderItem = (item: Book) => (
|
|
143
|
-
<>
|
|
144
|
-
<span style={{ fontWeight: "bold" }}>{item.title}</span>
|
|
145
|
-
{item.author && (
|
|
146
|
-
<span style={{ fontSize: "12px", color: "#666", marginLeft: "8px" }}>
|
|
147
|
-
by {item.author}
|
|
148
|
-
</span>
|
|
149
|
-
)}
|
|
150
|
-
</>
|
|
151
|
-
);
|
|
152
|
-
|
|
153
|
-
const itemToString = (item: Book | null): string => {
|
|
154
|
-
if (!item) return "";
|
|
155
|
-
return item.title;
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
const itemToSearchString = (item: Book) => `${item.author}|${item.title}`;
|
|
159
|
-
|
|
160
|
-
const defaultEmptyState = (
|
|
161
|
-
<div style={{ padding: "16px", textAlign: "center", color: "#666" }}>
|
|
162
|
-
No books found
|
|
163
|
-
</div>
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
// 1. Single
|
|
167
|
-
export const Single: Story = {
|
|
168
|
-
name: "Single",
|
|
169
|
-
render: () => {
|
|
170
|
-
return (
|
|
171
|
-
<FormField label="Pick a book">
|
|
172
|
-
{({ id }) => (
|
|
173
|
-
<SingleAutocomplete
|
|
174
|
-
id={id}
|
|
175
|
-
data={books}
|
|
176
|
-
itemToString={itemToString}
|
|
177
|
-
renderItem={renderItem}
|
|
178
|
-
onSelectedItemIdChange={(itemId) => console.log(itemId)}
|
|
179
|
-
EmptyState={defaultEmptyState}
|
|
180
|
-
placeholder="Search for a book"
|
|
181
|
-
/>
|
|
182
|
-
)}
|
|
183
|
-
</FormField>
|
|
184
|
-
);
|
|
185
|
-
},
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
// 3. Multi
|
|
189
|
-
export const Multi: Story = {
|
|
190
|
-
name: "Multi",
|
|
191
|
-
render: () => {
|
|
192
|
-
return (
|
|
193
|
-
<div>
|
|
194
|
-
<FormField label="Pick some books">
|
|
195
|
-
{({ id }) => (
|
|
196
|
-
<MultiAutocomplete
|
|
197
|
-
id={id}
|
|
198
|
-
data={books}
|
|
199
|
-
itemToString={itemToString}
|
|
200
|
-
itemToSearchString={itemToSearchString}
|
|
201
|
-
renderItem={renderItem}
|
|
202
|
-
onSelectedItemIdsChange={(itemIds) => console.log(itemIds)}
|
|
203
|
-
EmptyState={defaultEmptyState}
|
|
204
|
-
showSelectedItems={true}
|
|
205
|
-
placeholder="Search for books"
|
|
206
|
-
/>
|
|
207
|
-
)}
|
|
208
|
-
</FormField>
|
|
209
|
-
<Button
|
|
210
|
-
style={{ marginTop: "16px" }}
|
|
211
|
-
onClick={action("Button Clicked")}
|
|
212
|
-
>
|
|
213
|
-
Example Button
|
|
214
|
-
</Button>
|
|
215
|
-
</div>
|
|
216
|
-
);
|
|
217
|
-
},
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
// 4. Multi Grouped by Author
|
|
221
|
-
const TestMultiGroupedByAuthor = () => {
|
|
222
|
-
return (
|
|
223
|
-
<FormField label="Pick some books">
|
|
224
|
-
{({ id }) => (
|
|
225
|
-
<MultiAutocomplete
|
|
226
|
-
id={id}
|
|
227
|
-
data={books}
|
|
228
|
-
itemToString={itemToString}
|
|
229
|
-
itemToSearchString={itemToSearchString}
|
|
230
|
-
renderItem={renderItem}
|
|
231
|
-
groupBy={(book) => book.author}
|
|
232
|
-
EmptyState={defaultEmptyState}
|
|
233
|
-
placeholder="Search for books"
|
|
234
|
-
/>
|
|
235
|
-
)}
|
|
236
|
-
</FormField>
|
|
237
|
-
);
|
|
238
|
-
};
|
|
239
|
-
|
|
240
|
-
export const MultiGroupedByAuthor: Story = {
|
|
241
|
-
name: "Multi Grouped by Author",
|
|
242
|
-
render: () => {
|
|
243
|
-
return <TestMultiGroupedByAuthor />;
|
|
244
|
-
},
|
|
245
|
-
};
|
|
246
|
-
|
|
247
|
-
// 5. Multi Grouped by First Letter
|
|
248
|
-
const TestMultiGroupedByFirstLetter = () => {
|
|
249
|
-
return (
|
|
250
|
-
<FormField label="Pick some books">
|
|
251
|
-
{({ id }) => (
|
|
252
|
-
<MultiAutocomplete
|
|
253
|
-
id={id}
|
|
254
|
-
data={books}
|
|
255
|
-
itemToString={itemToString}
|
|
256
|
-
itemToSearchString={itemToSearchString}
|
|
257
|
-
renderItem={renderItem}
|
|
258
|
-
groupBy={(book) => book.title.charAt(0).toUpperCase()}
|
|
259
|
-
EmptyState={defaultEmptyState}
|
|
260
|
-
placeholder="Search for books"
|
|
261
|
-
/>
|
|
262
|
-
)}
|
|
263
|
-
</FormField>
|
|
264
|
-
);
|
|
265
|
-
};
|
|
266
|
-
|
|
267
|
-
export const MultiGroupedByFirstLetter: Story = {
|
|
268
|
-
name: "Multi Grouped by First Letter",
|
|
269
|
-
render: () => {
|
|
270
|
-
return <TestMultiGroupedByFirstLetter />;
|
|
271
|
-
},
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
// 6. Multi Grouped by Author with Custom Heading
|
|
275
|
-
const TestMultiGroupedByAuthorWithCustomHeading = () => {
|
|
276
|
-
return (
|
|
277
|
-
<FormField label="Pick some books">
|
|
278
|
-
{({ id }) => (
|
|
279
|
-
<MultiAutocomplete
|
|
280
|
-
id={id}
|
|
281
|
-
data={books}
|
|
282
|
-
itemToString={itemToString}
|
|
283
|
-
itemToSearchString={itemToSearchString}
|
|
284
|
-
renderItem={renderItem}
|
|
285
|
-
groupBy={(book) => book.author}
|
|
286
|
-
renderGroupHeading={(label) => `📚 ${label.toUpperCase()}`}
|
|
287
|
-
EmptyState={defaultEmptyState}
|
|
288
|
-
placeholder="Search for books"
|
|
289
|
-
/>
|
|
290
|
-
)}
|
|
291
|
-
</FormField>
|
|
292
|
-
);
|
|
293
|
-
};
|
|
294
|
-
|
|
295
|
-
export const MultiGroupedByAuthorWithCustomHeading: Story = {
|
|
296
|
-
name: "Multi Grouped by Author with Custom Heading",
|
|
297
|
-
render: () => {
|
|
298
|
-
return <TestMultiGroupedByAuthorWithCustomHeading />;
|
|
299
|
-
},
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
// 7. Multi with Select All
|
|
303
|
-
const selectAllItem: ToggleItem = {
|
|
304
|
-
id: "select-all",
|
|
305
|
-
label: "Select All",
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
const TestMultiWithSelectAll = () => {
|
|
309
|
-
return (
|
|
310
|
-
<FormField label="Pick some books">
|
|
311
|
-
{({ id }) => (
|
|
312
|
-
<MultiAutocomplete
|
|
313
|
-
id={id}
|
|
314
|
-
data={books}
|
|
315
|
-
itemToString={itemToString}
|
|
316
|
-
itemToSearchString={itemToSearchString}
|
|
317
|
-
renderItem={renderItem}
|
|
318
|
-
selectAllItem={selectAllItem}
|
|
319
|
-
onSelectedItemIdsChange={(itemIds) => console.log(itemIds)}
|
|
320
|
-
EmptyState={defaultEmptyState}
|
|
321
|
-
showSelectedItems={true}
|
|
322
|
-
placeholder="Search for books"
|
|
323
|
-
/>
|
|
324
|
-
)}
|
|
325
|
-
</FormField>
|
|
326
|
-
);
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
export const MultiWithSelectAll: Story = {
|
|
330
|
-
name: "Multi with Select All",
|
|
331
|
-
render: () => {
|
|
332
|
-
return <TestMultiWithSelectAll />;
|
|
333
|
-
},
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
// 8. Virtualized Multi (with 1000 items)
|
|
337
|
-
const TestVirtualizedMulti = () => {
|
|
338
|
-
return (
|
|
339
|
-
<FormField label="Pick some books">
|
|
340
|
-
{({ id }) => (
|
|
341
|
-
<MultiAutocomplete
|
|
342
|
-
id={id}
|
|
343
|
-
data={largeBookSet}
|
|
344
|
-
itemToString={itemToString}
|
|
345
|
-
itemToSearchString={itemToSearchString}
|
|
346
|
-
renderItem={renderItem}
|
|
347
|
-
isVirtualized={true}
|
|
348
|
-
groupBy={(book) => book.author}
|
|
349
|
-
selectHeadings={true}
|
|
350
|
-
EmptyState={defaultEmptyState}
|
|
351
|
-
placeholder="Search for books"
|
|
352
|
-
menuProps={{
|
|
353
|
-
style: {
|
|
354
|
-
maxHeight: "400px",
|
|
355
|
-
overflow: "auto",
|
|
356
|
-
},
|
|
357
|
-
}}
|
|
358
|
-
/>
|
|
359
|
-
)}
|
|
360
|
-
</FormField>
|
|
361
|
-
);
|
|
362
|
-
};
|
|
363
|
-
|
|
364
|
-
export const VirtualizedMulti: Story = {
|
|
365
|
-
name: "Virtualized Multi (with 1000 items)",
|
|
366
|
-
render: () => {
|
|
367
|
-
return <TestVirtualizedMulti />;
|
|
368
|
-
},
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
// 9. Virtualized Multi (with 1000 items), With Select All, Grouped by Author, with Selectable Headings
|
|
372
|
-
const TestVirtualizedMultiWithSelectAllGrouped = () => {
|
|
373
|
-
return (
|
|
374
|
-
<FormField label="Pick some books">
|
|
375
|
-
{({ id }) => (
|
|
376
|
-
<MultiAutocomplete
|
|
377
|
-
id={id}
|
|
378
|
-
data={largeBookSet}
|
|
379
|
-
itemToString={itemToString}
|
|
380
|
-
itemToSearchString={itemToSearchString}
|
|
381
|
-
renderItem={renderItem}
|
|
382
|
-
groupBy={(book) => book.author}
|
|
383
|
-
selectAllItem={selectAllItem}
|
|
384
|
-
selectHeadings={true}
|
|
385
|
-
isVirtualized={true}
|
|
386
|
-
renderGroupHeading={(label) => `📚 ${label.toUpperCase()}`}
|
|
387
|
-
onSelectedItemIdsChange={(itemIds) => console.log(itemIds)}
|
|
388
|
-
EmptyState={defaultEmptyState}
|
|
389
|
-
showSelectedItems={true}
|
|
390
|
-
placeholder="Search for books"
|
|
391
|
-
menuProps={{
|
|
392
|
-
style: {
|
|
393
|
-
maxHeight: "400px",
|
|
394
|
-
overflow: "auto",
|
|
395
|
-
},
|
|
396
|
-
}}
|
|
397
|
-
/>
|
|
398
|
-
)}
|
|
399
|
-
</FormField>
|
|
400
|
-
);
|
|
401
|
-
};
|
|
402
|
-
|
|
403
|
-
export const VirtualizedMultiWithSelectAllGrouped: Story = {
|
|
404
|
-
name: "Virtualized Multi (with 1000 items), With Select All, Grouped by Author, with Selectable Headings",
|
|
405
|
-
render: () => {
|
|
406
|
-
return <TestVirtualizedMultiWithSelectAllGrouped />;
|
|
407
|
-
},
|
|
408
|
-
};
|
|
409
|
-
|
|
410
|
-
// 10. FullyControlled Single
|
|
411
|
-
const TestFullyControlledSingle = () => {
|
|
412
|
-
const [inputValue, setInputValue] = React.useState("");
|
|
413
|
-
const [selectedItemId, setSelectedItemId] = React.useState<string | null>(
|
|
414
|
-
books[0].id
|
|
415
|
-
);
|
|
416
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
|
417
|
-
|
|
418
|
-
const selectedItem = books.find((book) => book.id === selectedItemId) ?? null;
|
|
419
|
-
|
|
420
|
-
return (
|
|
421
|
-
<>
|
|
422
|
-
<FormField label="Pick a book">
|
|
423
|
-
{({ id }) => (
|
|
424
|
-
<SingleAutocomplete
|
|
425
|
-
id={id}
|
|
426
|
-
data={books}
|
|
427
|
-
inputValue={inputValue}
|
|
428
|
-
itemToString={itemToString}
|
|
429
|
-
itemToSearchString={itemToSearchString}
|
|
430
|
-
onInputValueChange={(newInputValue) => {
|
|
431
|
-
console.log("Input value changed:", newInputValue);
|
|
432
|
-
setInputValue(newInputValue);
|
|
433
|
-
}}
|
|
434
|
-
selectedItemId={selectedItemId}
|
|
435
|
-
onSelectedItemIdChange={(newItemId) => {
|
|
436
|
-
console.log("Selected item changed:", newItemId);
|
|
437
|
-
setSelectedItemId(newItemId);
|
|
438
|
-
}}
|
|
439
|
-
isOpen={isOpen}
|
|
440
|
-
onIsOpenChange={(newIsOpen) => {
|
|
441
|
-
console.log("isOpen changed:", newIsOpen);
|
|
442
|
-
setIsOpen(newIsOpen);
|
|
443
|
-
}}
|
|
444
|
-
renderItem={renderItem}
|
|
445
|
-
EmptyState={defaultEmptyState}
|
|
446
|
-
placeholder="Search for a book"
|
|
447
|
-
/>
|
|
448
|
-
)}
|
|
449
|
-
</FormField>
|
|
450
|
-
<div
|
|
451
|
-
style={{
|
|
452
|
-
marginTop: "16px",
|
|
453
|
-
display: "flex",
|
|
454
|
-
flexDirection: "column",
|
|
455
|
-
gap: "8px",
|
|
456
|
-
}}
|
|
457
|
-
>
|
|
458
|
-
<div>
|
|
459
|
-
<Button onClick={() => setIsOpen(!isOpen)}>Toggle Menu</Button>
|
|
460
|
-
<Button
|
|
461
|
-
onClick={() => setInputValue("War")}
|
|
462
|
-
style={{ marginLeft: "8px" }}
|
|
463
|
-
>
|
|
464
|
-
Set Input to "War"
|
|
465
|
-
</Button>
|
|
466
|
-
<Button
|
|
467
|
-
onClick={() => {
|
|
468
|
-
const randomBook =
|
|
469
|
-
books[Math.floor(Math.random() * books.length)];
|
|
470
|
-
setSelectedItemId(randomBook.id);
|
|
471
|
-
}}
|
|
472
|
-
style={{ marginLeft: "8px" }}
|
|
473
|
-
>
|
|
474
|
-
Select Random Book
|
|
475
|
-
</Button>
|
|
476
|
-
</div>
|
|
477
|
-
<div style={{ fontSize: "12px", color: "#666" }}>
|
|
478
|
-
Input: "{inputValue}" | Menu: {isOpen ? "OPEN" : "CLOSED"} | Selected:{" "}
|
|
479
|
-
{selectedItem ? selectedItem.title : "None"}
|
|
480
|
-
</div>
|
|
481
|
-
</div>
|
|
482
|
-
</>
|
|
483
|
-
);
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
export const FullyControlledSingle: Story = {
|
|
487
|
-
name: "FullyControlled Single",
|
|
488
|
-
render: () => {
|
|
489
|
-
return <TestFullyControlledSingle />;
|
|
490
|
-
},
|
|
491
|
-
};
|
|
492
|
-
|
|
493
|
-
// 11. FullyControlled Multi
|
|
494
|
-
const TestFullyControlledMulti = () => {
|
|
495
|
-
const [inputValue, setInputValue] = React.useState("");
|
|
496
|
-
const [selectedItemIds, setSelectedItemIds] = React.useState<string[]>([
|
|
497
|
-
books[0].id,
|
|
498
|
-
]);
|
|
499
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
|
500
|
-
|
|
501
|
-
const selectedItems = books.filter((book) =>
|
|
502
|
-
selectedItemIds.includes(book.id)
|
|
503
|
-
);
|
|
504
|
-
|
|
505
|
-
return (
|
|
506
|
-
<>
|
|
507
|
-
<FormField label="Pick some books">
|
|
508
|
-
{({ id }) => (
|
|
509
|
-
<MultiAutocomplete
|
|
510
|
-
id={id}
|
|
511
|
-
data={books}
|
|
512
|
-
inputValue={inputValue}
|
|
513
|
-
itemToString={itemToString}
|
|
514
|
-
itemToSearchString={itemToSearchString}
|
|
515
|
-
onInputValueChange={(newInputValue) => {
|
|
516
|
-
console.log("Input value changed:", newInputValue);
|
|
517
|
-
setInputValue(newInputValue);
|
|
518
|
-
}}
|
|
519
|
-
selectedItemIds={selectedItemIds}
|
|
520
|
-
onSelectedItemIdsChange={(newItemIds) => {
|
|
521
|
-
console.log("Selected items changed:", newItemIds);
|
|
522
|
-
setSelectedItemIds(newItemIds);
|
|
523
|
-
}}
|
|
524
|
-
isOpen={isOpen}
|
|
525
|
-
onIsOpenChange={(newIsOpen) => {
|
|
526
|
-
console.log("isOpen changed:", newIsOpen);
|
|
527
|
-
setIsOpen(newIsOpen);
|
|
528
|
-
}}
|
|
529
|
-
renderItem={renderItem}
|
|
530
|
-
EmptyState={defaultEmptyState}
|
|
531
|
-
placeholder="Search for books"
|
|
532
|
-
/>
|
|
533
|
-
)}
|
|
534
|
-
</FormField>
|
|
535
|
-
<div
|
|
536
|
-
style={{
|
|
537
|
-
marginTop: "16px",
|
|
538
|
-
display: "flex",
|
|
539
|
-
flexDirection: "column",
|
|
540
|
-
gap: "8px",
|
|
541
|
-
}}
|
|
542
|
-
>
|
|
543
|
-
<div>
|
|
544
|
-
<Button onClick={() => setIsOpen(!isOpen)}>Toggle Menu</Button>
|
|
545
|
-
<Button
|
|
546
|
-
onClick={() => setInputValue("War")}
|
|
547
|
-
style={{ marginLeft: "8px" }}
|
|
548
|
-
>
|
|
549
|
-
Set Input to "War"
|
|
550
|
-
</Button>
|
|
551
|
-
<Button
|
|
552
|
-
onClick={() => {
|
|
553
|
-
const randomBook =
|
|
554
|
-
books[Math.floor(Math.random() * books.length)];
|
|
555
|
-
setSelectedItemIds((prev) => {
|
|
556
|
-
if (!prev.includes(randomBook.id)) {
|
|
557
|
-
return [...prev, randomBook.id];
|
|
558
|
-
}
|
|
559
|
-
return prev;
|
|
560
|
-
});
|
|
561
|
-
}}
|
|
562
|
-
style={{ marginLeft: "8px" }}
|
|
563
|
-
>
|
|
564
|
-
Add Random Book
|
|
565
|
-
</Button>
|
|
566
|
-
</div>
|
|
567
|
-
<div style={{ fontSize: "12px", color: "#666" }}>
|
|
568
|
-
Input: "{inputValue}" | Menu: {isOpen ? "OPEN" : "CLOSED"} | Selected:{" "}
|
|
569
|
-
{selectedItems.map((item) => item.title).join(", ") || "None"}
|
|
570
|
-
</div>
|
|
571
|
-
</div>
|
|
572
|
-
</>
|
|
573
|
-
);
|
|
574
|
-
};
|
|
575
|
-
|
|
576
|
-
export const FullyControlledMulti: Story = {
|
|
577
|
-
name: "FullyControlled Multi",
|
|
578
|
-
render: () => {
|
|
579
|
-
return <TestFullyControlledMulti />;
|
|
580
|
-
},
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
// Single Custom Search string
|
|
584
|
-
const TestCustomSearchString = () => {
|
|
585
|
-
const customItemToSearchString = (item: Book) =>
|
|
586
|
-
`${item.author}|${item.title}`;
|
|
587
|
-
|
|
588
|
-
return (
|
|
589
|
-
<FormField label="Pick a book">
|
|
590
|
-
{({ id }) => (
|
|
591
|
-
<SingleAutocomplete
|
|
592
|
-
id={id}
|
|
593
|
-
data={books}
|
|
594
|
-
itemToString={itemToString}
|
|
595
|
-
itemToSearchString={customItemToSearchString}
|
|
596
|
-
renderItem={renderItem}
|
|
597
|
-
onSelectedItemIdChange={(itemId) => console.log(itemId)}
|
|
598
|
-
EmptyState={defaultEmptyState}
|
|
599
|
-
placeholder="Search for a book"
|
|
600
|
-
/>
|
|
601
|
-
)}
|
|
602
|
-
</FormField>
|
|
603
|
-
);
|
|
604
|
-
};
|
|
605
|
-
|
|
606
|
-
export const CustomSearchString: Story = {
|
|
607
|
-
name: "Custom Search String",
|
|
608
|
-
render: () => {
|
|
609
|
-
return <TestCustomSearchString />;
|
|
610
|
-
},
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
// Popout Placement Top
|
|
614
|
-
// Positioned at the bottom of the viewport to demonstrate that the popout
|
|
615
|
-
// opens upward rather than downward when popoutPlacement="top" is set.
|
|
616
|
-
const TestPopoutPlacementTop = () => {
|
|
617
|
-
return (
|
|
618
|
-
<FormField label="Pick some books" width="100%">
|
|
619
|
-
{({ id }) => (
|
|
620
|
-
<MultiAutocomplete
|
|
621
|
-
id={id}
|
|
622
|
-
data={books}
|
|
623
|
-
itemToString={itemToString}
|
|
624
|
-
renderItem={renderItem}
|
|
625
|
-
onSelectedItemIdsChange={(itemIds) => console.log(itemIds)}
|
|
626
|
-
EmptyState={defaultEmptyState}
|
|
627
|
-
placeholder="Search for books"
|
|
628
|
-
popoutPlacement="top"
|
|
629
|
-
/>
|
|
630
|
-
)}
|
|
631
|
-
</FormField>
|
|
632
|
-
);
|
|
633
|
-
};
|
|
634
|
-
|
|
635
|
-
export const PopoutPlacementTop: Story = {
|
|
636
|
-
name: "Popout Placement Top",
|
|
637
|
-
decorators: [
|
|
638
|
-
(Story) => (
|
|
639
|
-
<Box display="flex" height="100vh" alignItems="flex-end">
|
|
640
|
-
<Story />
|
|
641
|
-
</Box>
|
|
642
|
-
),
|
|
643
|
-
],
|
|
644
|
-
render: () => <TestPopoutPlacementTop />,
|
|
645
|
-
};
|