@dxos/react-ui-searchlist 0.8.4-main.c4373fc → 0.8.4-main.c85a9c8dae

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 (82) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/browser/index.mjs +716 -408
  3. package/dist/lib/browser/index.mjs.map +4 -4
  4. package/dist/lib/browser/meta.json +1 -1
  5. package/dist/lib/node-esm/index.mjs +716 -408
  6. package/dist/lib/node-esm/index.mjs.map +4 -4
  7. package/dist/lib/node-esm/meta.json +1 -1
  8. package/dist/types/src/components/Combobox/Combobox.d.ts +85 -0
  9. package/dist/types/src/components/Combobox/Combobox.d.ts.map +1 -0
  10. package/dist/types/src/{composites/PopoverCombobox.stories.d.ts → components/Combobox/Combobox.stories.d.ts} +10 -1
  11. package/dist/types/src/components/Combobox/Combobox.stories.d.ts.map +1 -0
  12. package/dist/types/src/components/Combobox/index.d.ts +2 -0
  13. package/dist/types/src/components/Combobox/index.d.ts.map +1 -0
  14. package/dist/types/src/components/{Listbox.d.ts → Listbox/Listbox.d.ts} +6 -6
  15. package/dist/types/src/components/Listbox/Listbox.d.ts.map +1 -0
  16. package/dist/types/src/components/Listbox/Listbox.stories.d.ts +21 -0
  17. package/dist/types/src/components/Listbox/Listbox.stories.d.ts.map +1 -0
  18. package/dist/types/src/components/Listbox/index.d.ts +2 -0
  19. package/dist/types/src/components/Listbox/index.d.ts.map +1 -0
  20. package/dist/types/src/components/SearchList/SearchList.d.ts +90 -0
  21. package/dist/types/src/components/SearchList/SearchList.d.ts.map +1 -0
  22. package/dist/types/src/components/SearchList/SearchList.stories.d.ts +28 -0
  23. package/dist/types/src/components/SearchList/SearchList.stories.d.ts.map +1 -0
  24. package/dist/types/src/components/SearchList/context.d.ts +33 -0
  25. package/dist/types/src/components/SearchList/context.d.ts.map +1 -0
  26. package/dist/types/src/components/SearchList/hooks/index.d.ts +5 -0
  27. package/dist/types/src/components/SearchList/hooks/index.d.ts.map +1 -0
  28. package/dist/types/src/components/SearchList/hooks/useGlobalFilter.d.ts +34 -0
  29. package/dist/types/src/components/SearchList/hooks/useGlobalFilter.d.ts.map +1 -0
  30. package/dist/types/src/components/SearchList/hooks/useSearchListInput.d.ts +12 -0
  31. package/dist/types/src/components/SearchList/hooks/useSearchListInput.d.ts.map +1 -0
  32. package/dist/types/src/components/SearchList/hooks/useSearchListItem.d.ts +10 -0
  33. package/dist/types/src/components/SearchList/hooks/useSearchListItem.d.ts.map +1 -0
  34. package/dist/types/src/components/SearchList/hooks/useSearchListResults.d.ts +36 -0
  35. package/dist/types/src/components/SearchList/hooks/useSearchListResults.d.ts.map +1 -0
  36. package/dist/types/src/components/SearchList/index.d.ts +3 -0
  37. package/dist/types/src/components/SearchList/index.d.ts.map +1 -0
  38. package/dist/types/src/components/index.d.ts +2 -1
  39. package/dist/types/src/components/index.d.ts.map +1 -1
  40. package/dist/types/src/index.d.ts +0 -1
  41. package/dist/types/src/index.d.ts.map +1 -1
  42. package/dist/types/src/translations.d.ts +4 -2
  43. package/dist/types/src/translations.d.ts.map +1 -1
  44. package/dist/types/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +21 -18
  46. package/src/components/Combobox/Combobox.stories.tsx +62 -0
  47. package/src/components/Combobox/Combobox.tsx +343 -0
  48. package/src/components/Combobox/index.ts +5 -0
  49. package/src/components/Listbox/Listbox.stories.tsx +53 -0
  50. package/src/components/{Listbox.tsx → Listbox/Listbox.tsx} +40 -11
  51. package/src/components/Listbox/index.ts +5 -0
  52. package/src/components/SearchList/SearchList.stories.tsx +532 -0
  53. package/src/components/SearchList/SearchList.tsx +554 -0
  54. package/src/components/SearchList/context.ts +43 -0
  55. package/src/components/SearchList/hooks/index.ts +8 -0
  56. package/src/components/SearchList/hooks/useGlobalFilter.tsx +61 -0
  57. package/src/components/SearchList/hooks/useSearchListInput.ts +14 -0
  58. package/src/components/SearchList/hooks/useSearchListItem.ts +14 -0
  59. package/src/components/SearchList/hooks/useSearchListResults.ts +104 -0
  60. package/src/components/SearchList/index.ts +6 -0
  61. package/src/components/index.ts +2 -1
  62. package/src/index.ts +0 -1
  63. package/src/translations.ts +4 -2
  64. package/src/types/command-score.d.ts +16 -0
  65. package/dist/types/src/components/Listbox.d.ts.map +0 -1
  66. package/dist/types/src/components/Listbox.stories.d.ts +0 -16
  67. package/dist/types/src/components/Listbox.stories.d.ts.map +0 -1
  68. package/dist/types/src/components/SearchList.d.ts +0 -47
  69. package/dist/types/src/components/SearchList.d.ts.map +0 -1
  70. package/dist/types/src/components/SearchList.stories.d.ts +0 -16
  71. package/dist/types/src/components/SearchList.stories.d.ts.map +0 -1
  72. package/dist/types/src/composites/PopoverCombobox.d.ts +0 -32
  73. package/dist/types/src/composites/PopoverCombobox.d.ts.map +0 -1
  74. package/dist/types/src/composites/PopoverCombobox.stories.d.ts.map +0 -1
  75. package/dist/types/src/composites/index.d.ts +0 -2
  76. package/dist/types/src/composites/index.d.ts.map +0 -1
  77. package/src/components/Listbox.stories.tsx +0 -73
  78. package/src/components/SearchList.stories.tsx +0 -55
  79. package/src/components/SearchList.tsx +0 -251
  80. package/src/composites/PopoverCombobox.stories.tsx +0 -47
  81. package/src/composites/PopoverCombobox.tsx +0 -209
  82. package/src/composites/index.ts +0 -5
@@ -0,0 +1,532 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
6
+ import React, { useState } from 'react';
7
+
8
+ import { faker } from '@dxos/random';
9
+ import { withLayout, withTheme } from '@dxos/react-ui/testing';
10
+
11
+ import { translations } from '../../translations';
12
+
13
+ import { useSearchListInput, useSearchListItem, useSearchListResults } from './hooks';
14
+ import { SearchList } from './SearchList';
15
+
16
+ faker.seed(1234);
17
+
18
+ type StoryItem = {
19
+ id: string;
20
+ label: string;
21
+ icon?: string;
22
+ };
23
+
24
+ const defaultItems: StoryItem[] = faker.helpers.uniqueArray(faker.commerce.productName, 16).map((label) => ({
25
+ id: faker.string.uuid(),
26
+ label,
27
+ icon: 'ph--file--regular',
28
+ }));
29
+
30
+ //
31
+ // Default Story - Basic composition with SearchList.Item
32
+ //
33
+
34
+ type DefaultStoryProps = {
35
+ items?: StoryItem[];
36
+ };
37
+
38
+ const DefaultStory = ({ items = defaultItems }: DefaultStoryProps) => {
39
+ const { results, handleSearch } = useSearchListResults({ items });
40
+
41
+ return (
42
+ <SearchList.Root onSearch={handleSearch}>
43
+ <SearchList.Content classNames='h-[400px]'>
44
+ <SearchList.Input placeholder='Search items...' autoFocus />
45
+ <SearchList.Viewport>
46
+ {results.length > 0 ? (
47
+ results.map((item) => (
48
+ <SearchList.Item
49
+ key={item.id}
50
+ value={item.id}
51
+ label={item.label}
52
+ icon={item.icon}
53
+ onSelect={() => console.log('[SearchList.Item.onSelect]', item.id, item.label)}
54
+ />
55
+ ))
56
+ ) : (
57
+ <SearchList.Empty>No results found</SearchList.Empty>
58
+ )}
59
+ </SearchList.Viewport>
60
+ </SearchList.Content>
61
+ </SearchList.Root>
62
+ );
63
+ };
64
+
65
+ //
66
+ // Controlled Story - Controlled query state
67
+ //
68
+
69
+ const ControlledStory = ({ items = defaultItems }: DefaultStoryProps) => {
70
+ const [query, setQuery] = useState('');
71
+ const [results, setResults] = useState<StoryItem[]>(items);
72
+
73
+ const handleSearch = (searchQuery: string) => {
74
+ if (!searchQuery) {
75
+ setResults(items);
76
+ return;
77
+ }
78
+ const filtered = items.filter((item) => item.label.toLowerCase().includes(searchQuery.toLowerCase()));
79
+ setResults(filtered);
80
+ };
81
+
82
+ const handleQueryChange = (newQuery: string) => {
83
+ setQuery(newQuery);
84
+ handleSearch(newQuery);
85
+ };
86
+
87
+ return (
88
+ <div className='w-full h-[400px] flex flex-col gap-2'>
89
+ <div className='text-sm text-description'>Controlled query: &quot;{query}&quot;</div>
90
+ <SearchList.Root onSearch={handleSearch} value={query}>
91
+ <SearchList.Input placeholder='Controlled search...' onChange={(e) => handleQueryChange(e.target.value)} />
92
+ <SearchList.Content>
93
+ <SearchList.Viewport>
94
+ {results.map((item) => (
95
+ <SearchList.Item
96
+ key={item.id}
97
+ value={item.id}
98
+ label={item.label}
99
+ icon={item.icon}
100
+ onSelect={() => console.log('[SearchList.Item.onSelect]', item.id)}
101
+ />
102
+ ))}
103
+ </SearchList.Viewport>
104
+ </SearchList.Content>
105
+ </SearchList.Root>
106
+ <button className='px-2 py-1 rounded-sm bg-accent-surface text-accent-text' onClick={() => handleQueryChange('')}>
107
+ Clear Query
108
+ </button>
109
+ </div>
110
+ );
111
+ };
112
+
113
+ //
114
+ // Custom Rendering Story - Custom components in Content using useSearchItem hook
115
+ //
116
+
117
+ type CustomItemProps = {
118
+ value: string;
119
+ label: string;
120
+ description: string;
121
+ onSelect?: () => void;
122
+ };
123
+
124
+ const CustomItem = ({ value, label, description, onSelect }: CustomItemProps) => {
125
+ const { selectedValue, registerItem, unregisterItem } = useSearchListItem();
126
+ const ref = React.useRef<HTMLDivElement>(null);
127
+ const isSelected = selectedValue === value;
128
+
129
+ React.useEffect(() => {
130
+ registerItem(value, ref.current, onSelect);
131
+ return () => unregisterItem(value);
132
+ }, [value, onSelect, registerItem, unregisterItem]);
133
+
134
+ // Scroll into view when selected.
135
+ React.useEffect(() => {
136
+ if (isSelected && ref.current) {
137
+ ref.current.scrollIntoView({ block: 'nearest', behavior: 'smooth' });
138
+ }
139
+ }, [isSelected]);
140
+
141
+ return (
142
+ <div
143
+ ref={ref}
144
+ role='option'
145
+ aria-selected={isSelected}
146
+ data-selected={isSelected}
147
+ className={`p-2 border-b border-separator cursor-pointer ${isSelected ? 'bg-hover-overlay' : 'hover:bg-hover-overlay'}`}
148
+ onClick={onSelect}
149
+ >
150
+ <div className='font-medium'>{label}</div>
151
+ <div className='text-xs text-description'>{description}</div>
152
+ </div>
153
+ );
154
+ };
155
+
156
+ const CustomRenderingStory = ({ items = defaultItems }: DefaultStoryProps) => {
157
+ const { results, handleSearch } = useSearchListResults({ items });
158
+
159
+ return (
160
+ <div className='w-full h-[400px] flex flex-col'>
161
+ <SearchList.Root onSearch={handleSearch}>
162
+ <SearchList.Input placeholder='Search with custom rendering...' autoFocus />
163
+ <SearchList.Content>
164
+ <SearchList.Viewport>
165
+ {results.map((item) => (
166
+ <CustomItem
167
+ key={item.id}
168
+ value={item.id}
169
+ label={item.label}
170
+ description={`ID: ${item.id}`}
171
+ onSelect={() => console.log('[CustomItem.onSelect]', item.id, item.label)}
172
+ />
173
+ ))}
174
+ </SearchList.Viewport>
175
+ </SearchList.Content>
176
+ </SearchList.Root>
177
+ </div>
178
+ );
179
+ };
180
+
181
+ //
182
+ // With Empty Story - Show Empty component when no results
183
+ //
184
+
185
+ const WithEmptyStory = () => {
186
+ const [hasSearched, setHasSearched] = useState(false);
187
+
188
+ const handleSearch = (query: string) => {
189
+ setHasSearched(!!query);
190
+ };
191
+
192
+ return (
193
+ <div className='w-full h-[400px] flex flex-col'>
194
+ <SearchList.Root onSearch={handleSearch}>
195
+ <SearchList.Input placeholder='Try searching for anything...' />
196
+ <SearchList.Content>
197
+ {hasSearched ? (
198
+ <SearchList.Empty classNames='text-center text-description p-4'>
199
+ <div className='text-lg'>🔍</div>
200
+ <div>No results found</div>
201
+ <div className='text-xs'>Try a different search term</div>
202
+ </SearchList.Empty>
203
+ ) : (
204
+ <SearchList.Empty classNames='text-center text-description p-4'>
205
+ <div>Start typing to search</div>
206
+ </SearchList.Empty>
207
+ )}
208
+ </SearchList.Content>
209
+ </SearchList.Root>
210
+ </div>
211
+ );
212
+ };
213
+
214
+ //
215
+ // Without Viewport Story - Content without scrolling
216
+ //
217
+
218
+ const WithoutViewportStory = ({ items = defaultItems }: DefaultStoryProps) => {
219
+ const { results, handleSearch } = useSearchListResults({ items });
220
+
221
+ return (
222
+ <div className='w-full h-[300px] flex flex-col'>
223
+ <SearchList.Root onSearch={handleSearch}>
224
+ <SearchList.Input placeholder='Search without viewport (no scroll)...' classNames='shrink-0' />
225
+ <SearchList.Content>
226
+ {results.map((item) => (
227
+ <SearchList.Item
228
+ key={item.id}
229
+ value={item.id}
230
+ label={item.label}
231
+ icon={item.icon}
232
+ onSelect={() => console.log('[SearchList.Item.onSelect]', item.id)}
233
+ />
234
+ ))}
235
+ </SearchList.Content>
236
+ </SearchList.Root>
237
+ </div>
238
+ );
239
+ };
240
+
241
+ //
242
+ // With Icons Story - Various icon configurations
243
+ //
244
+
245
+ const iconsItems: StoryItem[] = [
246
+ { id: '1', label: 'Document', icon: 'ph--file-text--regular' },
247
+ { id: '2', label: 'Folder', icon: 'ph--folder--regular' },
248
+ { id: '3', label: 'Image', icon: 'ph--image--regular' },
249
+ { id: '4', label: 'Settings', icon: 'ph--gear--regular' },
250
+ { id: '5', label: 'No icon item' },
251
+ ];
252
+
253
+ const WithIconsStory = () => {
254
+ return (
255
+ <div className='w-full flex flex-col'>
256
+ <SearchList.Root>
257
+ <SearchList.Input placeholder='Search items with icons...' />
258
+ <SearchList.Content>
259
+ {iconsItems.map((item) => (
260
+ <SearchList.Item
261
+ key={item.id}
262
+ value={item.id}
263
+ label={item.label}
264
+ icon={item.icon}
265
+ onSelect={() => console.log('[SearchList.Item.onSelect]', item.id)}
266
+ />
267
+ ))}
268
+ </SearchList.Content>
269
+ </SearchList.Root>
270
+ </div>
271
+ );
272
+ };
273
+
274
+ //
275
+ // Custom Input Story - Demonstrate using hooks for custom input
276
+ //
277
+
278
+ const CustomInput = () => {
279
+ const { query, onQueryChange, selectedValue, onSelectedValueChange, getItemValues, triggerSelect } =
280
+ useSearchListInput();
281
+
282
+ const handleKeyDown = (event: React.KeyboardEvent<HTMLInputElement>) => {
283
+ const values = getItemValues();
284
+ if (values.length === 0) {
285
+ if (event.key === 'Escape') {
286
+ onQueryChange('');
287
+ }
288
+ return;
289
+ }
290
+
291
+ const currentIndex = selectedValue !== undefined ? values.indexOf(selectedValue) : -1;
292
+
293
+ switch (event.key) {
294
+ case 'ArrowDown': {
295
+ event.preventDefault();
296
+ const nextIndex = currentIndex === -1 ? 0 : Math.min(currentIndex + 1, values.length - 1);
297
+ const nextValue = values[nextIndex];
298
+ if (nextValue !== undefined) {
299
+ onSelectedValueChange(nextValue);
300
+ }
301
+ break;
302
+ }
303
+ case 'ArrowUp': {
304
+ event.preventDefault();
305
+ const prevIndex = currentIndex === -1 ? values.length - 1 : Math.max(currentIndex - 1, 0);
306
+ const prevValue = values[prevIndex];
307
+ if (prevValue !== undefined) {
308
+ onSelectedValueChange(prevValue);
309
+ }
310
+ break;
311
+ }
312
+ case 'Enter': {
313
+ if (selectedValue !== undefined) {
314
+ event.preventDefault();
315
+ triggerSelect();
316
+ }
317
+ break;
318
+ }
319
+ case 'Escape': {
320
+ event.preventDefault();
321
+ if (selectedValue !== undefined) {
322
+ onSelectedValueChange(undefined);
323
+ } else {
324
+ onQueryChange('');
325
+ }
326
+ break;
327
+ }
328
+ }
329
+ };
330
+
331
+ return (
332
+ <div className='flex gap-2 items-center p-2 bg-input rounded-sm'>
333
+ <input
334
+ type='text'
335
+ value={query}
336
+ onChange={(ev) => onQueryChange(ev.target.value)}
337
+ onKeyDown={handleKeyDown}
338
+ placeholder='Custom input...'
339
+ className='bg-transparent outline-hidden grow'
340
+ />
341
+ {query && (
342
+ <button onClick={() => onQueryChange('')} className='text-description hover:text-base-surface-text'>
343
+
344
+ </button>
345
+ )}
346
+ </div>
347
+ );
348
+ };
349
+
350
+ const CustomInputStory = ({ items = defaultItems }: DefaultStoryProps) => {
351
+ const { results, handleSearch } = useSearchListResults({ items });
352
+
353
+ return (
354
+ <div className='w-full h-[400px] flex flex-col border border-separator'>
355
+ <SearchList.Root onSearch={handleSearch}>
356
+ <CustomInput />
357
+ <SearchList.Content>
358
+ <SearchList.Viewport>
359
+ {results.map((item) => (
360
+ <SearchList.Item
361
+ key={item.id}
362
+ value={item.id}
363
+ label={item.label}
364
+ icon={item.icon}
365
+ onSelect={() => console.log('[SearchList.Item.onSelect]', item.id)}
366
+ />
367
+ ))}
368
+ </SearchList.Viewport>
369
+ </SearchList.Content>
370
+ </SearchList.Root>
371
+ </div>
372
+ );
373
+ };
374
+
375
+ //
376
+ // With Disabled Items Story
377
+ //
378
+
379
+ const disabledItems: StoryItem[] = [
380
+ { id: '1', label: 'Available item 1', icon: 'ph--check--regular' },
381
+ { id: '2', label: 'Disabled item (cannot select)', icon: 'ph--prohibit--regular' },
382
+ { id: '3', label: 'Available item 2', icon: 'ph--check--regular' },
383
+ { id: '4', label: 'Disabled item 2', icon: 'ph--prohibit--regular' },
384
+ { id: '5', label: 'Available item 3', icon: 'ph--check--regular' },
385
+ ];
386
+
387
+ const WithDisabledItemsStory = () => {
388
+ return (
389
+ <div className='w-full flex flex-col'>
390
+ <SearchList.Root>
391
+ <SearchList.Input placeholder='Arrow keys skip disabled items...' autoFocus />
392
+ <SearchList.Content>
393
+ {disabledItems.map((item, index) => (
394
+ <SearchList.Item
395
+ key={item.id}
396
+ value={item.id}
397
+ label={item.label}
398
+ icon={item.icon}
399
+ disabled={index === 1 || index === 3}
400
+ onSelect={() => console.log('[SearchList.Item.onSelect]', item.id)}
401
+ />
402
+ ))}
403
+ </SearchList.Content>
404
+ </SearchList.Root>
405
+ </div>
406
+ );
407
+ };
408
+
409
+ //
410
+ // With Groups Story
411
+ //
412
+
413
+ type GroupedItem = StoryItem & { category: string };
414
+
415
+ const groupedItems: GroupedItem[] = [
416
+ { id: '1', label: 'Document 1', icon: 'ph--file-text--regular', category: 'Documents' },
417
+ { id: '2', label: 'Document 2', icon: 'ph--file-text--regular', category: 'Documents' },
418
+ { id: '3', label: 'Image 1', icon: 'ph--image--regular', category: 'Images' },
419
+ { id: '4', label: 'Image 2', icon: 'ph--image--regular', category: 'Images' },
420
+ { id: '5', label: 'Settings', icon: 'ph--gear--regular', category: 'Other' },
421
+ ];
422
+
423
+ const WithGroupsStory = () => {
424
+ const { results, handleSearch } = useSearchListResults({ items: groupedItems });
425
+
426
+ // Group items by category.
427
+ const grouped = results.reduce(
428
+ (acc, item) => {
429
+ if (!acc[item.category]) {
430
+ acc[item.category] = [];
431
+ }
432
+ acc[item.category].push(item);
433
+ return acc;
434
+ },
435
+ {} as Record<string, GroupedItem[]>,
436
+ );
437
+
438
+ return (
439
+ <div className='w-full h-[400px] flex flex-col'>
440
+ <SearchList.Root onSearch={handleSearch}>
441
+ <SearchList.Input placeholder='Search grouped items...' autoFocus />
442
+ <SearchList.Content>
443
+ <SearchList.Viewport>
444
+ {Object.entries(grouped).map(([category, items]) => (
445
+ <SearchList.Group key={category} heading={category}>
446
+ {items.map((item) => (
447
+ <SearchList.Item
448
+ key={item.id}
449
+ value={item.id}
450
+ label={item.label}
451
+ icon={item.icon}
452
+ onSelect={() => console.log('[SearchList.Item.onSelect]', item.id, item.label)}
453
+ />
454
+ ))}
455
+ </SearchList.Group>
456
+ ))}
457
+ {results.length === 0 && <SearchList.Empty>No results found</SearchList.Empty>}
458
+ </SearchList.Viewport>
459
+ </SearchList.Content>
460
+ </SearchList.Root>
461
+ </div>
462
+ );
463
+ };
464
+
465
+ //
466
+ // Meta
467
+ //
468
+
469
+ const meta = {
470
+ title: 'ui/react-ui-searchlist/SearchList',
471
+ component: SearchList.Root as any,
472
+ decorators: [withTheme(), withLayout({ layout: 'column' })],
473
+ parameters: {
474
+ layout: 'fullscreen',
475
+ translations,
476
+ },
477
+ } satisfies Meta<typeof DefaultStory>;
478
+
479
+ export default meta;
480
+
481
+ type Story = StoryObj<typeof meta>;
482
+
483
+ export const Default: Story = {
484
+ render: DefaultStory,
485
+ args: {
486
+ items: defaultItems,
487
+ },
488
+ };
489
+
490
+ export const Controlled: Story = {
491
+ render: ControlledStory,
492
+ args: {
493
+ items: defaultItems,
494
+ },
495
+ };
496
+
497
+ export const CustomRendering: Story = {
498
+ render: CustomRenderingStory,
499
+ args: {
500
+ items: defaultItems,
501
+ },
502
+ };
503
+
504
+ export const WithEmpty: Story = {
505
+ render: WithEmptyStory,
506
+ };
507
+
508
+ export const WithoutViewport: Story = {
509
+ render: WithoutViewportStory,
510
+ args: {
511
+ items: defaultItems,
512
+ },
513
+ };
514
+
515
+ export const WithIcons: Story = {
516
+ render: WithIconsStory,
517
+ };
518
+
519
+ export const CustomInputExample: Story = {
520
+ render: CustomInputStory,
521
+ args: {
522
+ items: defaultItems,
523
+ },
524
+ };
525
+
526
+ export const WithDisabledItems: Story = {
527
+ render: WithDisabledItemsStory,
528
+ };
529
+
530
+ export const WithGroups: Story = {
531
+ render: WithGroupsStory,
532
+ };