@aleph-alpha/ui-library 1.11.0 → 1.12.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 (104) hide show
  1. package/README.md +0 -2
  2. package/dist/system/index.d.ts +860 -179
  3. package/dist/system/lib.js +33936 -9729
  4. package/package.json +1 -2
  5. package/src/compositions/UiDataTable/UiDataTable.stories.ts +6 -7
  6. package/src/compositions/UiDataTable/UiDataTableColumnHeader.vue +22 -8
  7. package/src/compositions/UiDataTable/UiDataTablePagination.vue +5 -5
  8. package/src/compositions/UiDatePicker/UiDatePicker.vue +2 -2
  9. package/src/primitives/UiAlert/UiAlert.stories.ts +8 -8
  10. package/src/primitives/UiBadge/UiBadge.stories.ts +9 -9
  11. package/src/primitives/UiButton/UiButton.stories.ts +12 -12
  12. package/src/primitives/UiCalendar/UiCalendar.stories.ts +4 -4
  13. package/src/primitives/UiDropdownMenu/UiDropdownMenu.stories.ts +2 -2
  14. package/src/primitives/UiIcon/UiIcon.stories.ts +59 -13
  15. package/src/primitives/UiIcon/UiIcon.vue +41 -3
  16. package/src/primitives/UiIcon/__tests__/UiIcon.test.ts +33 -4
  17. package/src/primitives/UiIcon/index.ts +1 -0
  18. package/src/primitives/UiIcon/types.ts +24 -5
  19. package/src/primitives/UiIconButton/UiIconButton.stories.ts +36 -36
  20. package/src/primitives/UiKbd/UiKbd.stories.ts +551 -0
  21. package/src/primitives/UiKbd/UiKbd.vue +62 -0
  22. package/src/primitives/UiKbd/UiKbdGroup.vue +16 -0
  23. package/src/primitives/UiKbd/__tests__/UiKbd.test.ts +46 -0
  24. package/src/primitives/UiKbd/index.ts +3 -0
  25. package/src/primitives/UiKbd/types.ts +32 -0
  26. package/src/primitives/UiLabel/UiLabel.stories.ts +192 -0
  27. package/src/primitives/UiLabel/UiLabel.vue +16 -0
  28. package/src/primitives/UiLabel/__tests__/UiLabel.test.ts +43 -0
  29. package/src/primitives/UiLabel/index.ts +2 -0
  30. package/src/primitives/UiLabel/types.ts +16 -0
  31. package/src/primitives/UiListbox/UiListbox.stories.ts +607 -0
  32. package/src/primitives/UiListbox/UiListbox.vue +30 -0
  33. package/src/primitives/UiListbox/UiListboxContent.vue +16 -0
  34. package/src/primitives/UiListbox/UiListboxFilter.vue +16 -0
  35. package/src/primitives/UiListbox/UiListboxGroup.vue +16 -0
  36. package/src/primitives/UiListbox/UiListboxGroupLabel.vue +16 -0
  37. package/src/primitives/UiListbox/UiListboxItem.vue +20 -0
  38. package/src/primitives/UiListbox/UiListboxItemIndicator.vue +16 -0
  39. package/src/primitives/UiListbox/__tests__/UiListbox.test.ts +42 -0
  40. package/src/primitives/UiListbox/index.ts +8 -0
  41. package/src/primitives/UiListbox/types.ts +119 -0
  42. package/src/primitives/UiPopover/index.ts +1 -0
  43. package/src/primitives/UiSeparator/UiSeparator.stories.ts +177 -0
  44. package/src/primitives/UiSeparator/UiSeparator.vue +17 -0
  45. package/src/primitives/UiSeparator/__tests__/UiSeparator.test.ts +34 -0
  46. package/src/primitives/UiSeparator/index.ts +2 -0
  47. package/src/primitives/UiSeparator/types.ts +23 -0
  48. package/src/primitives/UiSkeleton/UiSkeleton.stories.ts +247 -0
  49. package/src/primitives/UiSkeleton/UiSkeleton.vue +24 -0
  50. package/src/primitives/UiSkeleton/__tests__/UiSkeleton.test.ts +47 -0
  51. package/src/primitives/UiSkeleton/index.ts +2 -0
  52. package/src/primitives/UiSkeleton/types.ts +26 -0
  53. package/src/primitives/UiTable/UiTable.stories.ts +2 -2
  54. package/src/primitives/UiTagsInput/UiTagsInput.stories.ts +538 -0
  55. package/src/primitives/UiTagsInput/UiTagsInput.vue +27 -0
  56. package/src/primitives/UiTagsInput/UiTagsInputInput.vue +14 -0
  57. package/src/primitives/UiTagsInput/UiTagsInputItem.vue +16 -0
  58. package/src/primitives/UiTagsInput/UiTagsInputItemDelete.vue +16 -0
  59. package/src/primitives/UiTagsInput/UiTagsInputItemText.vue +14 -0
  60. package/src/primitives/UiTagsInput/__tests__/UiTagsInput.test.ts +44 -0
  61. package/src/primitives/UiTagsInput/index.ts +6 -0
  62. package/src/primitives/UiTagsInput/types.ts +60 -0
  63. package/src/primitives/UiToggle/UiToggle.stories.ts +370 -0
  64. package/src/primitives/UiToggle/UiToggle.vue +28 -0
  65. package/src/primitives/UiToggle/__tests__/UiToggle.test.ts +62 -0
  66. package/src/primitives/UiToggle/index.ts +2 -0
  67. package/src/primitives/UiToggle/types.ts +35 -0
  68. package/src/primitives/UiTooltip/UiTooltip.stories.ts +8 -8
  69. package/src/primitives/index.ts +7 -0
  70. package/src/primitives/shadcn/accordion/AccordionTrigger.vue +5 -4
  71. package/src/primitives/shadcn/calendar/CalendarNextButton.vue +2 -2
  72. package/src/primitives/shadcn/calendar/CalendarPrevButton.vue +2 -2
  73. package/src/primitives/shadcn/checkbox/Checkbox.vue +2 -2
  74. package/src/primitives/shadcn/dropdown-menu/DropdownMenuCheckboxItem.vue +2 -2
  75. package/src/primitives/shadcn/dropdown-menu/DropdownMenuSubTrigger.vue +2 -2
  76. package/src/primitives/shadcn/kbd/Kbd.vue +20 -0
  77. package/src/primitives/shadcn/kbd/KbdGroup.vue +12 -0
  78. package/src/primitives/shadcn/kbd/index.ts +2 -0
  79. package/src/primitives/shadcn/listbox/Listbox.vue +23 -0
  80. package/src/primitives/shadcn/listbox/ListboxContent.vue +26 -0
  81. package/src/primitives/shadcn/listbox/ListboxFilter.vue +30 -0
  82. package/src/primitives/shadcn/listbox/ListboxGroup.vue +26 -0
  83. package/src/primitives/shadcn/listbox/ListboxGroupLabel.vue +26 -0
  84. package/src/primitives/shadcn/listbox/ListboxItem.vue +32 -0
  85. package/src/primitives/shadcn/listbox/ListboxItemIndicator.vue +40 -0
  86. package/src/primitives/shadcn/listbox/index.ts +7 -0
  87. package/src/primitives/shadcn/native-select/NativeSelect.vue +5 -4
  88. package/src/primitives/shadcn/range-calendar/RangeCalendarNextButton.vue +2 -2
  89. package/src/primitives/shadcn/range-calendar/RangeCalendarPrevButton.vue +2 -2
  90. package/src/primitives/shadcn/select/SelectItem.vue +2 -2
  91. package/src/primitives/shadcn/select/SelectScrollDownButton.vue +2 -2
  92. package/src/primitives/shadcn/select/SelectScrollUpButton.vue +2 -2
  93. package/src/primitives/shadcn/select/SelectTrigger.vue +2 -2
  94. package/src/primitives/shadcn/skeleton/Skeleton.vue +10 -0
  95. package/src/primitives/shadcn/skeleton/index.ts +1 -0
  96. package/src/primitives/shadcn/spinner/Spinner.vue +5 -4
  97. package/src/primitives/shadcn/tags-input/TagsInput.vue +33 -0
  98. package/src/primitives/shadcn/tags-input/TagsInputInput.vue +24 -0
  99. package/src/primitives/shadcn/tags-input/TagsInputItem.vue +31 -0
  100. package/src/primitives/shadcn/tags-input/TagsInputItemDelete.vue +46 -0
  101. package/src/primitives/shadcn/tags-input/TagsInputItemText.vue +24 -0
  102. package/src/primitives/shadcn/tags-input/index.ts +5 -0
  103. package/src/primitives/shadcn/toggle/Toggle.vue +34 -0
  104. package/src/primitives/shadcn/toggle/index.ts +27 -0
@@ -0,0 +1,607 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { ref, computed } from 'vue';
3
+ import { useFilter } from 'reka-ui';
4
+ import UiListbox from './UiListbox.vue';
5
+ import UiListboxContent from './UiListboxContent.vue';
6
+ import UiListboxFilter from './UiListboxFilter.vue';
7
+ import UiListboxItem from './UiListboxItem.vue';
8
+ import UiListboxItemIndicator from './UiListboxItemIndicator.vue';
9
+ import UiListboxGroup from './UiListboxGroup.vue';
10
+ import UiListboxGroupLabel from './UiListboxGroupLabel.vue';
11
+
12
+ const meta: Meta<typeof UiListbox> = {
13
+ title: 'Primitives/UiListbox',
14
+ component: UiListbox,
15
+ tags: ['autodocs'],
16
+ argTypes: {
17
+ disabled: {
18
+ control: 'boolean',
19
+ description: 'Disable the listbox',
20
+ },
21
+ multiple: {
22
+ control: 'boolean',
23
+ description: 'Allow multiple selections',
24
+ },
25
+ highlightOnHover: {
26
+ control: 'boolean',
27
+ description: 'Highlight items on hover',
28
+ },
29
+ },
30
+ args: {
31
+ disabled: false,
32
+ multiple: false,
33
+ highlightOnHover: false,
34
+ },
35
+ };
36
+
37
+ export default meta;
38
+
39
+ type Story = StoryObj<typeof UiListbox>;
40
+
41
+ const fruits = [
42
+ { value: 'apple', label: 'Apple' },
43
+ { value: 'banana', label: 'Banana' },
44
+ { value: 'cherry', label: 'Cherry' },
45
+ { value: 'date', label: 'Date' },
46
+ { value: 'elderberry', label: 'Elderberry' },
47
+ ];
48
+
49
+ const defaultTemplateSource = `<script setup lang="ts">
50
+ import { ref } from 'vue'
51
+ import {
52
+ UiListbox,
53
+ UiListboxContent,
54
+ UiListboxItem,
55
+ UiListboxItemIndicator
56
+ } from '@aleph-alpha/ui-library'
57
+
58
+ const selected = ref('apple')
59
+ const fruits = [
60
+ { value: 'apple', label: 'Apple' },
61
+ { value: 'banana', label: 'Banana' },
62
+ { value: 'cherry', label: 'Cherry' },
63
+ ]
64
+ </script>
65
+
66
+ <template>
67
+ <UiListbox v-model="selected" class="w-[200px] rounded-md border p-1">
68
+ <UiListboxContent>
69
+ <UiListboxItem
70
+ v-for="fruit in fruits"
71
+ :key="fruit.value"
72
+ :value="fruit.value"
73
+ >
74
+ <span>{{ fruit.label }}</span>
75
+ <UiListboxItemIndicator />
76
+ </UiListboxItem>
77
+ </UiListboxContent>
78
+ </UiListbox>
79
+ </template>`;
80
+
81
+ /**
82
+ * Default single-selection listbox.
83
+ */
84
+ export const Default: Story = {
85
+ render: (args) => ({
86
+ components: {
87
+ UiListbox,
88
+ UiListboxContent,
89
+ UiListboxItem,
90
+ UiListboxItemIndicator,
91
+ },
92
+ setup() {
93
+ const selected = ref('apple');
94
+ return { args, selected, fruits };
95
+ },
96
+ template: `
97
+ <UiListbox
98
+ v-model="selected"
99
+ class="w-[200px] rounded-md border p-1"
100
+ :disabled="args.disabled"
101
+ :highlight-on-hover="args.highlightOnHover"
102
+ >
103
+ <UiListboxContent>
104
+ <UiListboxItem
105
+ v-for="fruit in fruits"
106
+ :key="fruit.value"
107
+ :value="fruit.value"
108
+ >
109
+ <span>{{ fruit.label }}</span>
110
+ <UiListboxItemIndicator />
111
+ </UiListboxItem>
112
+ </UiListboxContent>
113
+ </UiListbox>
114
+ `,
115
+ }),
116
+ parameters: {
117
+ docs: {
118
+ source: {
119
+ code: defaultTemplateSource,
120
+ },
121
+ },
122
+ },
123
+ };
124
+
125
+ const multipleTemplateSource = `<script setup lang="ts">
126
+ import { ref } from 'vue'
127
+ import {
128
+ UiListbox,
129
+ UiListboxContent,
130
+ UiListboxItem,
131
+ UiListboxItemIndicator
132
+ } from '@aleph-alpha/ui-library'
133
+
134
+ const selected = ref(['apple', 'cherry'])
135
+ const fruits = [
136
+ { value: 'apple', label: 'Apple' },
137
+ { value: 'banana', label: 'Banana' },
138
+ { value: 'cherry', label: 'Cherry' },
139
+ ]
140
+ </script>
141
+
142
+ <template>
143
+ <UiListbox v-model="selected" multiple class="w-[200px] rounded-md border p-1">
144
+ <UiListboxContent>
145
+ <UiListboxItem
146
+ v-for="fruit in fruits"
147
+ :key="fruit.value"
148
+ :value="fruit.value"
149
+ >
150
+ <span>{{ fruit.label }}</span>
151
+ <UiListboxItemIndicator />
152
+ </UiListboxItem>
153
+ </UiListboxContent>
154
+ </UiListbox>
155
+ </template>`;
156
+
157
+ /**
158
+ * Multiple selection listbox.
159
+ */
160
+ export const Multiple: Story = {
161
+ render: () => ({
162
+ components: {
163
+ UiListbox,
164
+ UiListboxContent,
165
+ UiListboxItem,
166
+ UiListboxItemIndicator,
167
+ },
168
+ setup() {
169
+ const selected = ref(['apple', 'cherry']);
170
+ return { selected, fruits };
171
+ },
172
+ template: `
173
+ <UiListbox v-model="selected" multiple class="w-[200px] rounded-md border p-1">
174
+ <UiListboxContent>
175
+ <UiListboxItem
176
+ v-for="fruit in fruits"
177
+ :key="fruit.value"
178
+ :value="fruit.value"
179
+ >
180
+ <span>{{ fruit.label }}</span>
181
+ <UiListboxItemIndicator />
182
+ </UiListboxItem>
183
+ </UiListboxContent>
184
+ </UiListbox>
185
+ `,
186
+ }),
187
+ parameters: {
188
+ docs: {
189
+ source: {
190
+ code: multipleTemplateSource,
191
+ },
192
+ },
193
+ },
194
+ };
195
+
196
+ const withFilterTemplateSource = `<script setup lang="ts">
197
+ import { ref, computed } from 'vue'
198
+ import { useFilter } from 'reka-ui'
199
+ import {
200
+ UiListbox,
201
+ UiListboxContent,
202
+ UiListboxFilter,
203
+ UiListboxItem,
204
+ UiListboxItemIndicator
205
+ } from '@aleph-alpha/ui-library'
206
+
207
+ const selected = ref('apple')
208
+ const searchTerm = ref('')
209
+ const fruits = [
210
+ { value: 'apple', label: 'Apple' },
211
+ { value: 'banana', label: 'Banana' },
212
+ { value: 'cherry', label: 'Cherry' },
213
+ ]
214
+
215
+ const { contains } = useFilter({ sensitivity: 'base' })
216
+ const filteredFruits = computed(() =>
217
+ searchTerm.value === ''
218
+ ? fruits
219
+ : fruits.filter(fruit => contains(fruit.label, searchTerm.value))
220
+ )
221
+ </script>
222
+
223
+ <template>
224
+ <UiListbox v-model="selected" class="w-[200px] rounded-md border">
225
+ <UiListboxFilter v-model="searchTerm" placeholder="Search fruits..." class="border-b" />
226
+ <UiListboxContent class="p-1">
227
+ <UiListboxItem
228
+ v-for="fruit in filteredFruits"
229
+ :key="fruit.value"
230
+ :value="fruit.value"
231
+ >
232
+ <span>{{ fruit.label }}</span>
233
+ <UiListboxItemIndicator />
234
+ </UiListboxItem>
235
+ </UiListboxContent>
236
+ </UiListbox>
237
+ </template>`;
238
+
239
+ /**
240
+ * Listbox with filter/search functionality.
241
+ */
242
+ export const WithFilter: Story = {
243
+ render: () => ({
244
+ components: {
245
+ UiListbox,
246
+ UiListboxContent,
247
+ UiListboxFilter,
248
+ UiListboxItem,
249
+ UiListboxItemIndicator,
250
+ },
251
+ setup() {
252
+ const selected = ref('apple');
253
+ const searchTerm = ref('');
254
+ const { contains } = useFilter({ sensitivity: 'base' });
255
+
256
+ const filteredFruits = computed(() =>
257
+ searchTerm.value === ''
258
+ ? fruits
259
+ : fruits.filter((fruit) => contains(fruit.label, searchTerm.value)),
260
+ );
261
+
262
+ return { selected, searchTerm, filteredFruits };
263
+ },
264
+ template: `
265
+ <UiListbox v-model="selected" class="w-[200px] rounded-md border">
266
+ <UiListboxFilter v-model="searchTerm" placeholder="Search fruits..." class="border-b" />
267
+ <UiListboxContent class="p-1">
268
+ <UiListboxItem
269
+ v-for="fruit in filteredFruits"
270
+ :key="fruit.value"
271
+ :value="fruit.value"
272
+ >
273
+ <span>{{ fruit.label }}</span>
274
+ <UiListboxItemIndicator />
275
+ </UiListboxItem>
276
+ </UiListboxContent>
277
+ </UiListbox>
278
+ `,
279
+ }),
280
+ parameters: {
281
+ docs: {
282
+ source: {
283
+ code: withFilterTemplateSource,
284
+ },
285
+ },
286
+ },
287
+ };
288
+
289
+ const withGroupsTemplateSource = `<script setup lang="ts">
290
+ import { ref } from 'vue'
291
+ import {
292
+ UiListbox,
293
+ UiListboxContent,
294
+ UiListboxItem,
295
+ UiListboxItemIndicator,
296
+ UiListboxGroup,
297
+ UiListboxGroupLabel
298
+ } from '@aleph-alpha/ui-library'
299
+
300
+ const selected = ref('apple')
301
+ </script>
302
+
303
+ <template>
304
+ <UiListbox v-model="selected" class="w-[200px] rounded-md border p-1">
305
+ <UiListboxContent>
306
+ <UiListboxGroup>
307
+ <UiListboxGroupLabel>Fruits</UiListboxGroupLabel>
308
+ <UiListboxItem value="apple">
309
+ <span>Apple</span>
310
+ <UiListboxItemIndicator />
311
+ </UiListboxItem>
312
+ <UiListboxItem value="banana">
313
+ <span>Banana</span>
314
+ <UiListboxItemIndicator />
315
+ </UiListboxItem>
316
+ </UiListboxGroup>
317
+ <UiListboxGroup>
318
+ <UiListboxGroupLabel>Vegetables</UiListboxGroupLabel>
319
+ <UiListboxItem value="carrot">
320
+ <span>Carrot</span>
321
+ <UiListboxItemIndicator />
322
+ </UiListboxItem>
323
+ <UiListboxItem value="broccoli">
324
+ <span>Broccoli</span>
325
+ <UiListboxItemIndicator />
326
+ </UiListboxItem>
327
+ </UiListboxGroup>
328
+ </UiListboxContent>
329
+ </UiListbox>
330
+ </template>`;
331
+
332
+ /**
333
+ * Listbox with grouped items.
334
+ */
335
+ export const WithGroups: Story = {
336
+ render: () => ({
337
+ components: {
338
+ UiListbox,
339
+ UiListboxContent,
340
+ UiListboxItem,
341
+ UiListboxItemIndicator,
342
+ UiListboxGroup,
343
+ UiListboxGroupLabel,
344
+ },
345
+ setup() {
346
+ const selected = ref('apple');
347
+ return { selected };
348
+ },
349
+ template: `
350
+ <UiListbox v-model="selected" class="w-[200px] rounded-md border p-1">
351
+ <UiListboxContent>
352
+ <UiListboxGroup>
353
+ <UiListboxGroupLabel>Fruits</UiListboxGroupLabel>
354
+ <UiListboxItem value="apple">
355
+ <span>Apple</span>
356
+ <UiListboxItemIndicator />
357
+ </UiListboxItem>
358
+ <UiListboxItem value="banana">
359
+ <span>Banana</span>
360
+ <UiListboxItemIndicator />
361
+ </UiListboxItem>
362
+ </UiListboxGroup>
363
+ <UiListboxGroup>
364
+ <UiListboxGroupLabel>Vegetables</UiListboxGroupLabel>
365
+ <UiListboxItem value="carrot">
366
+ <span>Carrot</span>
367
+ <UiListboxItemIndicator />
368
+ </UiListboxItem>
369
+ <UiListboxItem value="broccoli">
370
+ <span>Broccoli</span>
371
+ <UiListboxItemIndicator />
372
+ </UiListboxItem>
373
+ </UiListboxGroup>
374
+ </UiListboxContent>
375
+ </UiListbox>
376
+ `,
377
+ }),
378
+ parameters: {
379
+ docs: {
380
+ source: {
381
+ code: withGroupsTemplateSource,
382
+ },
383
+ },
384
+ },
385
+ };
386
+
387
+ const disabledTemplateSource = `<script setup lang="ts">
388
+ import { ref } from 'vue'
389
+ import {
390
+ UiListbox,
391
+ UiListboxContent,
392
+ UiListboxItem,
393
+ UiListboxItemIndicator
394
+ } from '@aleph-alpha/ui-library'
395
+
396
+ const selected = ref('apple')
397
+ const fruits = [
398
+ { value: 'apple', label: 'Apple' },
399
+ { value: 'banana', label: 'Banana' },
400
+ { value: 'cherry', label: 'Cherry' },
401
+ ]
402
+ </script>
403
+
404
+ <template>
405
+ <UiListbox v-model="selected" disabled class="w-[200px] rounded-md border p-1">
406
+ <UiListboxContent>
407
+ <UiListboxItem
408
+ v-for="fruit in fruits"
409
+ :key="fruit.value"
410
+ :value="fruit.value"
411
+ >
412
+ <span>{{ fruit.label }}</span>
413
+ <UiListboxItemIndicator />
414
+ </UiListboxItem>
415
+ </UiListboxContent>
416
+ </UiListbox>
417
+ </template>`;
418
+
419
+ /**
420
+ * Disabled listbox.
421
+ */
422
+ export const Disabled: Story = {
423
+ args: {
424
+ disabled: true,
425
+ },
426
+ render: () => ({
427
+ components: {
428
+ UiListbox,
429
+ UiListboxContent,
430
+ UiListboxItem,
431
+ UiListboxItemIndicator,
432
+ },
433
+ setup() {
434
+ const selected = ref('apple');
435
+ return { selected, fruits };
436
+ },
437
+ template: `
438
+ <UiListbox v-model="selected" disabled class="w-[200px] rounded-md border p-1 opacity-50">
439
+ <UiListboxContent>
440
+ <UiListboxItem
441
+ v-for="fruit in fruits"
442
+ :key="fruit.value"
443
+ :value="fruit.value"
444
+ >
445
+ <span>{{ fruit.label }}</span>
446
+ <UiListboxItemIndicator />
447
+ </UiListboxItem>
448
+ </UiListboxContent>
449
+ </UiListbox>
450
+ `,
451
+ }),
452
+ parameters: {
453
+ docs: {
454
+ source: {
455
+ code: disabledTemplateSource,
456
+ },
457
+ },
458
+ },
459
+ };
460
+
461
+ const highlightOnHoverTemplateSource = `<script setup lang="ts">
462
+ import { ref } from 'vue'
463
+ import {
464
+ UiListbox,
465
+ UiListboxContent,
466
+ UiListboxItem,
467
+ UiListboxItemIndicator
468
+ } from '@aleph-alpha/ui-library'
469
+
470
+ const selected = ref('apple')
471
+ const fruits = [
472
+ { value: 'apple', label: 'Apple' },
473
+ { value: 'banana', label: 'Banana' },
474
+ { value: 'cherry', label: 'Cherry' },
475
+ ]
476
+ </script>
477
+
478
+ <template>
479
+ <UiListbox v-model="selected" highlight-on-hover class="w-[200px] rounded-md border p-1">
480
+ <UiListboxContent>
481
+ <UiListboxItem
482
+ v-for="fruit in fruits"
483
+ :key="fruit.value"
484
+ :value="fruit.value"
485
+ >
486
+ <span>{{ fruit.label }}</span>
487
+ <UiListboxItemIndicator />
488
+ </UiListboxItem>
489
+ </UiListboxContent>
490
+ </UiListbox>
491
+ </template>`;
492
+
493
+ /**
494
+ * Listbox with highlight on hover enabled.
495
+ */
496
+ export const HighlightOnHover: Story = {
497
+ args: {
498
+ highlightOnHover: true,
499
+ },
500
+ render: () => ({
501
+ components: {
502
+ UiListbox,
503
+ UiListboxContent,
504
+ UiListboxItem,
505
+ UiListboxItemIndicator,
506
+ },
507
+ setup() {
508
+ const selected = ref('apple');
509
+ return { selected, fruits };
510
+ },
511
+ template: `
512
+ <UiListbox v-model="selected" highlight-on-hover class="w-[200px] rounded-md border p-1">
513
+ <UiListboxContent>
514
+ <UiListboxItem
515
+ v-for="fruit in fruits"
516
+ :key="fruit.value"
517
+ :value="fruit.value"
518
+ >
519
+ <span>{{ fruit.label }}</span>
520
+ <UiListboxItemIndicator />
521
+ </UiListboxItem>
522
+ </UiListboxContent>
523
+ </UiListbox>
524
+ `,
525
+ }),
526
+ parameters: {
527
+ docs: {
528
+ source: {
529
+ code: highlightOnHoverTemplateSource,
530
+ },
531
+ },
532
+ },
533
+ };
534
+
535
+ const withDisabledItemsTemplateSource = `<script setup lang="ts">
536
+ import { ref } from 'vue'
537
+ import {
538
+ UiListbox,
539
+ UiListboxContent,
540
+ UiListboxItem,
541
+ UiListboxItemIndicator
542
+ } from '@aleph-alpha/ui-library'
543
+
544
+ const selected = ref('apple')
545
+ </script>
546
+
547
+ <template>
548
+ <UiListbox v-model="selected" class="w-[200px] rounded-md border p-1">
549
+ <UiListboxContent>
550
+ <UiListboxItem value="apple">
551
+ <span>Apple</span>
552
+ <UiListboxItemIndicator />
553
+ </UiListboxItem>
554
+ <UiListboxItem value="banana" disabled>
555
+ <span>Banana (unavailable)</span>
556
+ <UiListboxItemIndicator />
557
+ </UiListboxItem>
558
+ <UiListboxItem value="cherry">
559
+ <span>Cherry</span>
560
+ <UiListboxItemIndicator />
561
+ </UiListboxItem>
562
+ </UiListboxContent>
563
+ </UiListbox>
564
+ </template>`;
565
+
566
+ /**
567
+ * Listbox with some disabled items.
568
+ */
569
+ export const WithDisabledItems: Story = {
570
+ render: () => ({
571
+ components: {
572
+ UiListbox,
573
+ UiListboxContent,
574
+ UiListboxItem,
575
+ UiListboxItemIndicator,
576
+ },
577
+ setup() {
578
+ const selected = ref('apple');
579
+ return { selected };
580
+ },
581
+ template: `
582
+ <UiListbox v-model="selected" class="w-[200px] rounded-md border p-1">
583
+ <UiListboxContent>
584
+ <UiListboxItem value="apple">
585
+ <span>Apple</span>
586
+ <UiListboxItemIndicator />
587
+ </UiListboxItem>
588
+ <UiListboxItem value="banana" disabled>
589
+ <span>Banana (unavailable)</span>
590
+ <UiListboxItemIndicator />
591
+ </UiListboxItem>
592
+ <UiListboxItem value="cherry">
593
+ <span>Cherry</span>
594
+ <UiListboxItemIndicator />
595
+ </UiListboxItem>
596
+ </UiListboxContent>
597
+ </UiListbox>
598
+ `,
599
+ }),
600
+ parameters: {
601
+ docs: {
602
+ source: {
603
+ code: withDisabledItemsTemplateSource,
604
+ },
605
+ },
606
+ },
607
+ };
@@ -0,0 +1,30 @@
1
+ <script setup lang="ts">
2
+ import type { AcceptableValue } from 'reka-ui';
3
+ import { computed } from 'vue';
4
+ import { Listbox as ShadcnListbox } from '@/primitives/shadcn/listbox';
5
+ import { UiListboxProps } from './types';
6
+
7
+ defineOptions({
8
+ name: 'UiListbox',
9
+ });
10
+
11
+ const props = withDefaults(defineProps<UiListboxProps>(), {
12
+ disabled: false,
13
+ multiple: false,
14
+ highlightOnHover: false,
15
+ });
16
+
17
+ const model = defineModel<AcceptableValue | AcceptableValue[]>();
18
+
19
+ const delegatedProps = computed(() => {
20
+ // eslint-disable-next-line sonarjs/no-unused-vars
21
+ const { modelValue: _modelValue, ...rest } = props;
22
+ return rest;
23
+ });
24
+ </script>
25
+
26
+ <template>
27
+ <ShadcnListbox v-model="model" v-bind="delegatedProps">
28
+ <slot />
29
+ </ShadcnListbox>
30
+ </template>
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import { ListboxContent as ShadcnListboxContent } from '@/primitives/shadcn/listbox';
3
+ import { UiListboxContentProps } from './types';
4
+
5
+ defineOptions({
6
+ name: 'UiListboxContent',
7
+ });
8
+
9
+ const props = defineProps<UiListboxContentProps>();
10
+ </script>
11
+
12
+ <template>
13
+ <ShadcnListboxContent v-bind="props">
14
+ <slot />
15
+ </ShadcnListboxContent>
16
+ </template>
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import { ListboxFilter as ShadcnListboxFilter } from '@/primitives/shadcn/listbox';
3
+ import { UiListboxFilterProps } from './types';
4
+
5
+ defineOptions({
6
+ name: 'UiListboxFilter',
7
+ });
8
+
9
+ const props = defineProps<UiListboxFilterProps>();
10
+
11
+ const model = defineModel<string>();
12
+ </script>
13
+
14
+ <template>
15
+ <ShadcnListboxFilter v-model="model" v-bind="props" />
16
+ </template>
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import { ListboxGroup as ShadcnListboxGroup } from '@/primitives/shadcn/listbox';
3
+ import { UiListboxGroupProps } from './types';
4
+
5
+ defineOptions({
6
+ name: 'UiListboxGroup',
7
+ });
8
+
9
+ const props = defineProps<UiListboxGroupProps>();
10
+ </script>
11
+
12
+ <template>
13
+ <ShadcnListboxGroup v-bind="props">
14
+ <slot />
15
+ </ShadcnListboxGroup>
16
+ </template>
@@ -0,0 +1,16 @@
1
+ <script setup lang="ts">
2
+ import { ListboxGroupLabel as ShadcnListboxGroupLabel } from '@/primitives/shadcn/listbox';
3
+ import { UiListboxGroupLabelProps } from './types';
4
+
5
+ defineOptions({
6
+ name: 'UiListboxGroupLabel',
7
+ });
8
+
9
+ const props = defineProps<UiListboxGroupLabelProps>();
10
+ </script>
11
+
12
+ <template>
13
+ <ShadcnListboxGroupLabel v-bind="props">
14
+ <slot />
15
+ </ShadcnListboxGroupLabel>
16
+ </template>