@aleph-alpha/ui-library 1.13.0 → 1.14.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 (120) hide show
  1. package/README.md +1 -1
  2. package/config.js +34 -1
  3. package/dist/system/index.d.ts +1728 -234
  4. package/dist/system/lib.js +19804 -16600
  5. package/package.json +1 -1
  6. package/src/components/UiKbd/UiKbd.stories.ts +1 -1
  7. package/src/components/UiNavigationMenu/UiNavigationMenu.stories.ts +1196 -0
  8. package/src/components/UiNavigationMenu/UiNavigationMenu.vue +39 -0
  9. package/src/components/UiNavigationMenu/UiNavigationMenuContent.vue +25 -0
  10. package/src/components/UiNavigationMenu/UiNavigationMenuIndicator.vue +14 -0
  11. package/src/components/UiNavigationMenu/UiNavigationMenuItem.vue +16 -0
  12. package/src/components/UiNavigationMenu/UiNavigationMenuLink.vue +27 -0
  13. package/src/components/UiNavigationMenu/UiNavigationMenuList.vue +16 -0
  14. package/src/components/UiNavigationMenu/UiNavigationMenuTrigger.vue +16 -0
  15. package/src/components/UiNavigationMenu/__tests__/UiNavigationMenu.test.ts +428 -0
  16. package/src/components/UiNavigationMenu/index.ts +11 -0
  17. package/src/components/UiNavigationMenu/types.ts +185 -0
  18. package/src/components/UiSheet/UiSheet.stories.ts +715 -0
  19. package/src/components/UiSheet/__tests__/UiSheet.test.ts +229 -0
  20. package/src/components/UiSheet/index.ts +12 -0
  21. package/src/components/UiSheet/types.ts +83 -0
  22. package/src/components/UiSidebar/UiSidebar.stories.ts +1010 -0
  23. package/src/components/UiSidebar/UiSidebar.vue +20 -0
  24. package/src/components/UiSidebar/UiSidebarGroupAction.vue +18 -0
  25. package/src/components/UiSidebar/UiSidebarGroupLabel.vue +18 -0
  26. package/src/components/UiSidebar/UiSidebarHeaderTrigger.vue +53 -0
  27. package/src/components/UiSidebar/UiSidebarInput.vue +14 -0
  28. package/src/components/UiSidebar/UiSidebarMenuAction.vue +19 -0
  29. package/src/components/UiSidebar/UiSidebarMenuButton.vue +27 -0
  30. package/src/components/UiSidebar/UiSidebarMenuSkeleton.vue +16 -0
  31. package/src/components/UiSidebar/UiSidebarMenuSubButton.vue +24 -0
  32. package/src/components/UiSidebar/UiSidebarProvider.vue +18 -0
  33. package/src/components/UiSidebar/UiSidebarSeparator.vue +13 -0
  34. package/src/components/UiSidebar/__tests__/UiSidebar.test.ts +221 -0
  35. package/src/components/UiSidebar/index.ts +34 -0
  36. package/src/components/UiSidebar/types.ts +168 -0
  37. package/src/components/UiStepper/UiStepper.stories.ts +425 -0
  38. package/src/components/UiStepper/UiStepper.vue +27 -0
  39. package/src/components/UiStepper/UiStepperDescription.vue +20 -0
  40. package/src/components/UiStepper/UiStepperIndicator.vue +13 -0
  41. package/src/components/UiStepper/UiStepperItem.vue +25 -0
  42. package/src/components/UiStepper/UiStepperSeparator.vue +17 -0
  43. package/src/components/UiStepper/UiStepperTitle.vue +19 -0
  44. package/src/components/UiStepper/UiStepperTrigger.vue +18 -0
  45. package/src/components/UiStepper/__tests__/UiStepper.test.ts +167 -0
  46. package/src/components/UiStepper/index.ts +9 -0
  47. package/src/components/UiStepper/types.ts +65 -0
  48. package/src/components/core/alert/index.ts +2 -2
  49. package/src/components/core/alert-dialog/AlertDialogContent.vue +1 -1
  50. package/src/components/core/card/Card.vue +1 -1
  51. package/src/components/core/drawer/DrawerContent.vue +1 -1
  52. package/src/components/core/dropdown-menu/DropdownMenuContent.vue +1 -1
  53. package/src/components/core/dropdown-menu/DropdownMenuSubContent.vue +1 -1
  54. package/src/components/core/input/Input.vue +1 -1
  55. package/src/components/core/native-select/NativeSelect.vue +1 -1
  56. package/src/components/core/native-select/NativeSelectOptGroup.vue +1 -1
  57. package/src/components/core/native-select/NativeSelectOption.vue +1 -1
  58. package/src/components/core/navigation-menu/NavigationMenu.vue +40 -0
  59. package/src/components/core/navigation-menu/NavigationMenuContent.vue +28 -0
  60. package/src/components/core/navigation-menu/NavigationMenuIndicator.vue +26 -0
  61. package/src/components/core/navigation-menu/NavigationMenuItem.vue +19 -0
  62. package/src/components/core/navigation-menu/NavigationMenuLink.vue +27 -0
  63. package/src/components/core/navigation-menu/NavigationMenuList.vue +21 -0
  64. package/src/components/core/navigation-menu/NavigationMenuTrigger.vue +27 -0
  65. package/src/components/core/navigation-menu/NavigationMenuViewport.vue +26 -0
  66. package/src/components/core/navigation-menu/index.ts +14 -0
  67. package/src/components/core/popover/PopoverContent.vue +1 -1
  68. package/src/components/core/select/SelectContent.vue +1 -1
  69. package/src/components/core/select/SelectTrigger.vue +1 -1
  70. package/src/components/core/sheet/Sheet.vue +15 -0
  71. package/src/components/core/sheet/SheetClose.vue +12 -0
  72. package/src/components/core/sheet/SheetContent.vue +56 -0
  73. package/src/components/core/sheet/SheetDescription.vue +19 -0
  74. package/src/components/core/sheet/SheetFooter.vue +9 -0
  75. package/src/components/core/sheet/SheetHeader.vue +9 -0
  76. package/src/components/core/sheet/SheetOverlay.vue +24 -0
  77. package/src/components/core/sheet/SheetTitle.vue +19 -0
  78. package/src/components/core/sheet/SheetTrigger.vue +12 -0
  79. package/src/components/core/sheet/index.ts +8 -0
  80. package/src/components/core/sidebar/Sidebar.vue +105 -0
  81. package/src/components/core/sidebar/SidebarContent.vue +21 -0
  82. package/src/components/core/sidebar/SidebarFooter.vue +16 -0
  83. package/src/components/core/sidebar/SidebarGroup.vue +16 -0
  84. package/src/components/core/sidebar/SidebarGroupAction.vue +25 -0
  85. package/src/components/core/sidebar/SidebarGroupContent.vue +16 -0
  86. package/src/components/core/sidebar/SidebarGroupLabel.vue +23 -0
  87. package/src/components/core/sidebar/SidebarHeader.vue +16 -0
  88. package/src/components/core/sidebar/SidebarInput.vue +17 -0
  89. package/src/components/core/sidebar/SidebarInset.vue +21 -0
  90. package/src/components/core/sidebar/SidebarMenu.vue +16 -0
  91. package/src/components/core/sidebar/SidebarMenuAction.vue +33 -0
  92. package/src/components/core/sidebar/SidebarMenuBadge.vue +26 -0
  93. package/src/components/core/sidebar/SidebarMenuButton.vue +49 -0
  94. package/src/components/core/sidebar/SidebarMenuButtonChild.vue +36 -0
  95. package/src/components/core/sidebar/SidebarMenuItem.vue +16 -0
  96. package/src/components/core/sidebar/SidebarMenuSkeleton.vue +32 -0
  97. package/src/components/core/sidebar/SidebarMenuSub.vue +22 -0
  98. package/src/components/core/sidebar/SidebarMenuSubButton.vue +38 -0
  99. package/src/components/core/sidebar/SidebarMenuSubItem.vue +16 -0
  100. package/src/components/core/sidebar/SidebarProvider.vue +102 -0
  101. package/src/components/core/sidebar/SidebarRail.vue +33 -0
  102. package/src/components/core/sidebar/SidebarSeparator.vue +17 -0
  103. package/src/components/core/sidebar/SidebarTrigger.vue +25 -0
  104. package/src/components/core/sidebar/index.ts +58 -0
  105. package/src/components/core/sidebar/utils.ts +19 -0
  106. package/src/components/core/stepper/Stepper.vue +20 -0
  107. package/src/components/core/stepper/StepperDescription.vue +23 -0
  108. package/src/components/core/stepper/StepperIndicator.vue +34 -0
  109. package/src/components/core/stepper/StepperItem.vue +23 -0
  110. package/src/components/core/stepper/StepperSeparator.vue +29 -0
  111. package/src/components/core/stepper/StepperTitle.vue +24 -0
  112. package/src/components/core/stepper/StepperTrigger.vue +22 -0
  113. package/src/components/core/stepper/index.ts +7 -0
  114. package/src/components/core/tabs/TabsTrigger.vue +1 -1
  115. package/src/components/core/tags-input/TagsInput.vue +1 -1
  116. package/src/components/core/textarea/Textarea.vue +1 -1
  117. package/src/components/index.ts +4 -0
  118. package/src/theme/Background.stories.ts +84 -35
  119. package/src/theme/Extended.stories.ts +4 -4
  120. package/tokens.json +145 -8
@@ -0,0 +1,1196 @@
1
+ import type { Meta, StoryObj } from '@storybook/vue3-vite';
2
+ import { ref, watch } from 'vue';
3
+ import {
4
+ UiNavigationMenu,
5
+ UiNavigationMenuList,
6
+ UiNavigationMenuItem,
7
+ UiNavigationMenuTrigger,
8
+ UiNavigationMenuContent,
9
+ UiNavigationMenuLink,
10
+ UiNavigationMenuIndicator,
11
+ navigationMenuTriggerStyle,
12
+ } from './index';
13
+
14
+ function useStoryModel(args: { modelValue?: string }) {
15
+ const value = ref(args.modelValue);
16
+ watch(
17
+ () => args.modelValue,
18
+ (v) => {
19
+ value.value = v;
20
+ },
21
+ );
22
+ return value;
23
+ }
24
+
25
+ const meta: Meta<typeof UiNavigationMenu> = {
26
+ title: 'Components/UiNavigationMenu',
27
+ component: UiNavigationMenu,
28
+ tags: ['autodocs'],
29
+ argTypes: {
30
+ modelValue: {
31
+ control: 'text',
32
+ description: 'Controlled active menu item value (use with v-model:modelValue)',
33
+ },
34
+ defaultValue: {
35
+ control: 'text',
36
+ description: 'The value of the menu item that should be active when initially rendered',
37
+ },
38
+ orientation: {
39
+ control: 'select',
40
+ options: ['horizontal', 'vertical'],
41
+ description: 'The orientation of the menu',
42
+ },
43
+ dir: {
44
+ control: 'select',
45
+ options: ['ltr', 'rtl'],
46
+ description: 'The reading direction of the menu',
47
+ },
48
+ delayDuration: {
49
+ control: 'number',
50
+ description: 'The duration from when the mouse enters a trigger until the content opens',
51
+ },
52
+ skipDelayDuration: {
53
+ control: 'number',
54
+ description:
55
+ 'How much time a user has to enter another trigger without incurring a delay again',
56
+ },
57
+ disableClickTrigger: {
58
+ control: 'boolean',
59
+ description: 'Whether to disable the click trigger behavior',
60
+ },
61
+ disableHoverTrigger: {
62
+ control: 'boolean',
63
+ description: 'Whether to disable the hover trigger behavior',
64
+ },
65
+ viewport: {
66
+ control: 'boolean',
67
+ description: 'Whether to render the viewport element',
68
+ },
69
+ },
70
+ args: {
71
+ orientation: 'horizontal',
72
+ dir: 'ltr',
73
+ delayDuration: 200,
74
+ skipDelayDuration: 300,
75
+ disableClickTrigger: false,
76
+ disableHoverTrigger: false,
77
+ viewport: true,
78
+ },
79
+ parameters: {
80
+ docs: {
81
+ story: {
82
+ height: '400px',
83
+ inline: false,
84
+ },
85
+ },
86
+ },
87
+ };
88
+
89
+ export default meta;
90
+
91
+ type Story = StoryObj<typeof UiNavigationMenu>;
92
+
93
+ const defaultTemplateSource = `<script setup lang="ts">
94
+ import { ref } from 'vue'
95
+ import {
96
+ UiNavigationMenu,
97
+ UiNavigationMenuList,
98
+ UiNavigationMenuItem,
99
+ UiNavigationMenuTrigger,
100
+ UiNavigationMenuContent,
101
+ UiNavigationMenuLink,
102
+ navigationMenuTriggerStyle,
103
+ } from '@aleph-alpha/ui-library'
104
+
105
+ const value = ref('')
106
+ </script>
107
+
108
+ <template>
109
+ <UiNavigationMenu v-model:modelValue="value">
110
+ <UiNavigationMenuList>
111
+ <UiNavigationMenuItem>
112
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Home</UiNavigationMenuLink>
113
+ </UiNavigationMenuItem>
114
+
115
+ <UiNavigationMenuItem value="products">
116
+ <UiNavigationMenuTrigger>Products</UiNavigationMenuTrigger>
117
+ <UiNavigationMenuContent>
118
+ <ul class="grid w-[400px]">
119
+ <li>
120
+ <UiNavigationMenuLink href="#">
121
+ <div class="font-medium">Analytics</div>
122
+ <p class="text-sm text-muted-foreground">Track your metrics and KPIs</p>
123
+ </UiNavigationMenuLink>
124
+ </li>
125
+ <li>
126
+ <UiNavigationMenuLink href="#">
127
+ <div class="font-medium">Automation</div>
128
+ <p class="text-sm text-muted-foreground">Streamline your workflows</p>
129
+ </UiNavigationMenuLink>
130
+ </li>
131
+ <li>
132
+ <UiNavigationMenuLink href="#">
133
+ <div class="font-medium">Integrations</div>
134
+ <p class="text-sm text-muted-foreground">Connect with your favorite tools</p>
135
+ </UiNavigationMenuLink>
136
+ </li>
137
+ </ul>
138
+ </UiNavigationMenuContent>
139
+ </UiNavigationMenuItem>
140
+
141
+ <UiNavigationMenuItem>
142
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">About</UiNavigationMenuLink>
143
+ </UiNavigationMenuItem>
144
+ </UiNavigationMenuList>
145
+ </UiNavigationMenu>
146
+ </template>`;
147
+
148
+ /**
149
+ * Basic navigation menu with 3 items (Home, Products, About). Products has dropdown content.
150
+ */
151
+ export const Default: Story = {
152
+ render: (args) => ({
153
+ components: {
154
+ UiNavigationMenu,
155
+ UiNavigationMenuList,
156
+ UiNavigationMenuItem,
157
+ UiNavigationMenuTrigger,
158
+ UiNavigationMenuContent,
159
+ UiNavigationMenuLink,
160
+ },
161
+ setup() {
162
+ const value = useStoryModel(args);
163
+ return { args, value, navigationMenuTriggerStyle };
164
+ },
165
+ template: `<UiNavigationMenu
166
+ v-model:modelValue="value"
167
+ :orientation="args.orientation"
168
+ :dir="args.dir"
169
+ :delay-duration="args.delayDuration"
170
+ :skip-delay-duration="args.skipDelayDuration"
171
+ :disable-click-trigger="args.disableClickTrigger"
172
+ :disable-hover-trigger="args.disableHoverTrigger"
173
+ :viewport="args.viewport"
174
+ >
175
+ <UiNavigationMenuList>
176
+ <UiNavigationMenuItem>
177
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Home</UiNavigationMenuLink>
178
+ </UiNavigationMenuItem>
179
+
180
+ <UiNavigationMenuItem value="products">
181
+ <UiNavigationMenuTrigger>Products</UiNavigationMenuTrigger>
182
+ <UiNavigationMenuContent>
183
+ <ul class="grid w-[400px]">
184
+ <li>
185
+ <UiNavigationMenuLink href="#">
186
+ <div class="font-medium">Analytics</div>
187
+ <p class="text-sm text-muted-foreground">Track your metrics and KPIs</p>
188
+ </UiNavigationMenuLink>
189
+ </li>
190
+ <li>
191
+ <UiNavigationMenuLink href="#">
192
+ <div class="font-medium">Automation</div>
193
+ <p class="text-sm text-muted-foreground">Streamline your workflows</p>
194
+ </UiNavigationMenuLink>
195
+ </li>
196
+ <li>
197
+ <UiNavigationMenuLink href="#">
198
+ <div class="font-medium">Integrations</div>
199
+ <p class="text-sm text-muted-foreground">Connect with your favorite tools</p>
200
+ </UiNavigationMenuLink>
201
+ </li>
202
+ </ul>
203
+ </UiNavigationMenuContent>
204
+ </UiNavigationMenuItem>
205
+
206
+ <UiNavigationMenuItem>
207
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">About</UiNavigationMenuLink>
208
+ </UiNavigationMenuItem>
209
+ </UiNavigationMenuList>
210
+ </UiNavigationMenu>`,
211
+ }),
212
+ parameters: {
213
+ docs: {
214
+ source: {
215
+ code: defaultTemplateSource,
216
+ },
217
+ },
218
+ },
219
+ };
220
+
221
+ const withLinksTemplateSource = `<script setup lang="ts">
222
+ import {
223
+ UiNavigationMenu,
224
+ UiNavigationMenuList,
225
+ UiNavigationMenuItem,
226
+ UiNavigationMenuLink,
227
+ navigationMenuTriggerStyle,
228
+ } from '@aleph-alpha/ui-library'
229
+ </script>
230
+
231
+ <template>
232
+ <UiNavigationMenu>
233
+ <UiNavigationMenuList>
234
+ <UiNavigationMenuItem>
235
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Home</UiNavigationMenuLink>
236
+ </UiNavigationMenuItem>
237
+ <UiNavigationMenuItem>
238
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Features</UiNavigationMenuLink>
239
+ </UiNavigationMenuItem>
240
+ <UiNavigationMenuItem>
241
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Pricing</UiNavigationMenuLink>
242
+ </UiNavigationMenuItem>
243
+ <UiNavigationMenuItem>
244
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Contact</UiNavigationMenuLink>
245
+ </UiNavigationMenuItem>
246
+ </UiNavigationMenuList>
247
+ </UiNavigationMenu>
248
+ </template>`;
249
+
250
+ /**
251
+ * Navigation with simple links (no dropdowns).
252
+ */
253
+ export const WithLinks: Story = {
254
+ render: (args) => ({
255
+ components: {
256
+ UiNavigationMenu,
257
+ UiNavigationMenuList,
258
+ UiNavigationMenuItem,
259
+ UiNavigationMenuLink,
260
+ },
261
+ setup() {
262
+ return { args, navigationMenuTriggerStyle };
263
+ },
264
+ template: `<UiNavigationMenu
265
+ :orientation="args.orientation"
266
+ :dir="args.dir"
267
+ >
268
+ <UiNavigationMenuList>
269
+ <UiNavigationMenuItem>
270
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Home</UiNavigationMenuLink>
271
+ </UiNavigationMenuItem>
272
+ <UiNavigationMenuItem>
273
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Features</UiNavigationMenuLink>
274
+ </UiNavigationMenuItem>
275
+ <UiNavigationMenuItem>
276
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Pricing</UiNavigationMenuLink>
277
+ </UiNavigationMenuItem>
278
+ <UiNavigationMenuItem>
279
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Contact</UiNavigationMenuLink>
280
+ </UiNavigationMenuItem>
281
+ </UiNavigationMenuList>
282
+ </UiNavigationMenu>`,
283
+ }),
284
+ parameters: {
285
+ docs: {
286
+ source: {
287
+ code: withLinksTemplateSource,
288
+ },
289
+ },
290
+ },
291
+ };
292
+
293
+ const withIndicatorTemplateSource = `<script setup lang="ts">
294
+ import { ref } from 'vue'
295
+ import {
296
+ UiNavigationMenu,
297
+ UiNavigationMenuList,
298
+ UiNavigationMenuItem,
299
+ UiNavigationMenuTrigger,
300
+ UiNavigationMenuContent,
301
+ UiNavigationMenuLink,
302
+ UiNavigationMenuIndicator,
303
+ } from '@aleph-alpha/ui-library'
304
+
305
+ const value = ref('')
306
+ </script>
307
+
308
+ <template>
309
+ <UiNavigationMenu v-model:modelValue="value">
310
+ <UiNavigationMenuList>
311
+ <UiNavigationMenuItem value="getting-started">
312
+ <UiNavigationMenuTrigger>Getting Started</UiNavigationMenuTrigger>
313
+ <UiNavigationMenuContent>
314
+ <ul class="grid w-[300px]">
315
+ <li>
316
+ <UiNavigationMenuLink href="#">
317
+ <div class="font-medium">Introduction</div>
318
+ <p class="text-sm text-muted-foreground">Learn the basics</p>
319
+ </UiNavigationMenuLink>
320
+ </li>
321
+ <li>
322
+ <UiNavigationMenuLink href="#">
323
+ <div class="font-medium">Installation</div>
324
+ <p class="text-sm text-muted-foreground">Get up and running</p>
325
+ </UiNavigationMenuLink>
326
+ </li>
327
+ </ul>
328
+ </UiNavigationMenuContent>
329
+ </UiNavigationMenuItem>
330
+
331
+ <UiNavigationMenuItem value="components">
332
+ <UiNavigationMenuTrigger>Components</UiNavigationMenuTrigger>
333
+ <UiNavigationMenuContent>
334
+ <ul class="grid w-[300px]">
335
+ <li>
336
+ <UiNavigationMenuLink href="#">
337
+ <div class="font-medium">Buttons</div>
338
+ <p class="text-sm text-muted-foreground">Interactive elements</p>
339
+ </UiNavigationMenuLink>
340
+ </li>
341
+ <li>
342
+ <UiNavigationMenuLink href="#">
343
+ <div class="font-medium">Forms</div>
344
+ <p class="text-sm text-muted-foreground">Input components</p>
345
+ </UiNavigationMenuLink>
346
+ </li>
347
+ </ul>
348
+ </UiNavigationMenuContent>
349
+ </UiNavigationMenuItem>
350
+
351
+ <UiNavigationMenuIndicator />
352
+ </UiNavigationMenuList>
353
+ </UiNavigationMenu>
354
+ </template>`;
355
+
356
+ /**
357
+ * Shows the indicator animation when hovering over menu items.
358
+ */
359
+ export const WithIndicator: Story = {
360
+ render: (args) => ({
361
+ components: {
362
+ UiNavigationMenu,
363
+ UiNavigationMenuList,
364
+ UiNavigationMenuItem,
365
+ UiNavigationMenuTrigger,
366
+ UiNavigationMenuContent,
367
+ UiNavigationMenuLink,
368
+ UiNavigationMenuIndicator,
369
+ },
370
+ setup() {
371
+ const value = useStoryModel(args);
372
+ return { args, value };
373
+ },
374
+ template: `<UiNavigationMenu
375
+ v-model:modelValue="value"
376
+ :orientation="args.orientation"
377
+ :dir="args.dir"
378
+ :delay-duration="args.delayDuration"
379
+ :skip-delay-duration="args.skipDelayDuration"
380
+ >
381
+ <UiNavigationMenuList>
382
+ <UiNavigationMenuItem value="getting-started">
383
+ <UiNavigationMenuTrigger>Getting Started</UiNavigationMenuTrigger>
384
+ <UiNavigationMenuContent>
385
+ <ul class="grid w-[300px]">
386
+ <li>
387
+ <UiNavigationMenuLink href="#">
388
+ <div class="font-medium">Introduction</div>
389
+ <p class="text-sm text-muted-foreground">Learn the basics</p>
390
+ </UiNavigationMenuLink>
391
+ </li>
392
+ <li>
393
+ <UiNavigationMenuLink href="#">
394
+ <div class="font-medium">Installation</div>
395
+ <p class="text-sm text-muted-foreground">Get up and running</p>
396
+ </UiNavigationMenuLink>
397
+ </li>
398
+ </ul>
399
+ </UiNavigationMenuContent>
400
+ </UiNavigationMenuItem>
401
+
402
+ <UiNavigationMenuItem value="components">
403
+ <UiNavigationMenuTrigger>Components</UiNavigationMenuTrigger>
404
+ <UiNavigationMenuContent>
405
+ <ul class="grid w-[300px]">
406
+ <li>
407
+ <UiNavigationMenuLink href="#">
408
+ <div class="font-medium">Buttons</div>
409
+ <p class="text-sm text-muted-foreground">Interactive elements</p>
410
+ </UiNavigationMenuLink>
411
+ </li>
412
+ <li>
413
+ <UiNavigationMenuLink href="#">
414
+ <div class="font-medium">Forms</div>
415
+ <p class="text-sm text-muted-foreground">Input components</p>
416
+ </UiNavigationMenuLink>
417
+ </li>
418
+ </ul>
419
+ </UiNavigationMenuContent>
420
+ </UiNavigationMenuItem>
421
+
422
+ <UiNavigationMenuIndicator />
423
+ </UiNavigationMenuList>
424
+ </UiNavigationMenu>`,
425
+ }),
426
+ parameters: {
427
+ docs: {
428
+ source: {
429
+ code: withIndicatorTemplateSource,
430
+ },
431
+ },
432
+ },
433
+ };
434
+
435
+ const verticalOrientationTemplateSource = `<script setup lang="ts">
436
+ import { ref } from 'vue'
437
+ import {
438
+ UiNavigationMenu,
439
+ UiNavigationMenuList,
440
+ UiNavigationMenuItem,
441
+ UiNavigationMenuTrigger,
442
+ UiNavigationMenuContent,
443
+ UiNavigationMenuLink,
444
+ navigationMenuTriggerStyle,
445
+ } from '@aleph-alpha/ui-library'
446
+
447
+ const value = ref('')
448
+ </script>
449
+
450
+ <template>
451
+ <UiNavigationMenu v-model:modelValue="value" orientation="vertical">
452
+ <UiNavigationMenuList class="flex-col items-start">
453
+ <UiNavigationMenuItem>
454
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Dashboard</UiNavigationMenuLink>
455
+ </UiNavigationMenuItem>
456
+
457
+ <UiNavigationMenuItem value="settings">
458
+ <UiNavigationMenuTrigger>Settings</UiNavigationMenuTrigger>
459
+ <UiNavigationMenuContent>
460
+ <ul class="grid gap-2 p-4 w-[200px]">
461
+ <li>
462
+ <UiNavigationMenuLink href="#" href="#">
463
+ Profile
464
+ </UiNavigationMenuLink>
465
+ </li>
466
+ <li>
467
+ <UiNavigationMenuLink href="#" href="#">
468
+ Account
469
+ </UiNavigationMenuLink>
470
+ </li>
471
+ <li>
472
+ <UiNavigationMenuLink href="#" href="#">
473
+ Security
474
+ </UiNavigationMenuLink>
475
+ </li>
476
+ </ul>
477
+ </UiNavigationMenuContent>
478
+ </UiNavigationMenuItem>
479
+
480
+ <UiNavigationMenuItem>
481
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Help</UiNavigationMenuLink>
482
+ </UiNavigationMenuItem>
483
+ </UiNavigationMenuList>
484
+ </UiNavigationMenu>
485
+ </template>`;
486
+
487
+ /**
488
+ * Vertical menu layout for sidebar navigation.
489
+ */
490
+ export const VerticalOrientation: Story = {
491
+ render: (args) => ({
492
+ components: {
493
+ UiNavigationMenu,
494
+ UiNavigationMenuList,
495
+ UiNavigationMenuItem,
496
+ UiNavigationMenuTrigger,
497
+ UiNavigationMenuContent,
498
+ UiNavigationMenuLink,
499
+ },
500
+ setup() {
501
+ const value = useStoryModel(args);
502
+ return { args, value, navigationMenuTriggerStyle };
503
+ },
504
+ template: `<UiNavigationMenu
505
+ v-model:modelValue="value"
506
+ orientation="vertical"
507
+ :dir="args.dir"
508
+ :delay-duration="args.delayDuration"
509
+ :skip-delay-duration="args.skipDelayDuration"
510
+ >
511
+ <UiNavigationMenuList class="flex-col items-start">
512
+ <UiNavigationMenuItem>
513
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Dashboard</UiNavigationMenuLink>
514
+ </UiNavigationMenuItem>
515
+
516
+ <UiNavigationMenuItem value="settings">
517
+ <UiNavigationMenuTrigger>Settings</UiNavigationMenuTrigger>
518
+ <UiNavigationMenuContent>
519
+ <ul class="grid gap-2 p-4 w-[200px]">
520
+ <li>
521
+ <UiNavigationMenuLink href="#" href="#">
522
+ Profile
523
+ </UiNavigationMenuLink>
524
+ </li>
525
+ <li>
526
+ <UiNavigationMenuLink href="#" href="#">
527
+ Account
528
+ </UiNavigationMenuLink>
529
+ </li>
530
+ <li>
531
+ <UiNavigationMenuLink href="#" href="#">
532
+ Security
533
+ </UiNavigationMenuLink>
534
+ </li>
535
+ </ul>
536
+ </UiNavigationMenuContent>
537
+ </UiNavigationMenuItem>
538
+
539
+ <UiNavigationMenuItem>
540
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Help</UiNavigationMenuLink>
541
+ </UiNavigationMenuItem>
542
+ </UiNavigationMenuList>
543
+ </UiNavigationMenu>`,
544
+ }),
545
+ parameters: {
546
+ docs: {
547
+ source: {
548
+ code: verticalOrientationTemplateSource,
549
+ },
550
+ story: {
551
+ height: '500px',
552
+ },
553
+ },
554
+ },
555
+ };
556
+
557
+ const withCustomContentTemplateSource = `<script setup lang="ts">
558
+ import { ref } from 'vue'
559
+ import {
560
+ UiNavigationMenu,
561
+ UiNavigationMenuList,
562
+ UiNavigationMenuItem,
563
+ UiNavigationMenuTrigger,
564
+ UiNavigationMenuContent,
565
+ UiNavigationMenuLink,
566
+ navigationMenuTriggerStyle,
567
+ } from '@aleph-alpha/ui-library'
568
+
569
+ const value = ref('')
570
+ </script>
571
+
572
+ <template>
573
+ <UiNavigationMenu v-model:modelValue="value">
574
+ <UiNavigationMenuList>
575
+ <UiNavigationMenuItem value="products">
576
+ <UiNavigationMenuTrigger>Products</UiNavigationMenuTrigger>
577
+ <UiNavigationMenuContent>
578
+ <div class="grid gap-3 p-6 w-[600px] grid-cols-[.75fr_1fr]">
579
+ <div class="row-span-3 rounded-md bg-gradient-to-b from-muted/50 to-muted p-6">
580
+ <div class="mb-2 text-lg font-medium">Featured</div>
581
+ <p class="text-sm text-muted-foreground mb-4">
582
+ Our most popular product with advanced features and integrations.
583
+ </p>
584
+ <UiNavigationMenuLink href="#" class="text-sm font-medium text-primary hover:underline">
585
+ Learn more
586
+ </UiNavigationMenuLink>
587
+ </div>
588
+ <ul class="grid gap-3">
589
+ <li>
590
+ <UiNavigationMenuLink href="#">
591
+ <div class="text-sm font-medium">Analytics Platform</div>
592
+ <p class="text-sm text-muted-foreground">Real-time insights and reporting</p>
593
+ </UiNavigationMenuLink>
594
+ </li>
595
+ <li>
596
+ <UiNavigationMenuLink href="#">
597
+ <div class="text-sm font-medium">Automation Suite</div>
598
+ <p class="text-sm text-muted-foreground">Workflow automation tools</p>
599
+ </UiNavigationMenuLink>
600
+ </li>
601
+ <li>
602
+ <UiNavigationMenuLink href="#">
603
+ <div class="text-sm font-medium">Developer API</div>
604
+ <p class="text-sm text-muted-foreground">Build custom integrations</p>
605
+ </UiNavigationMenuLink>
606
+ </li>
607
+ </ul>
608
+ </div>
609
+ </UiNavigationMenuContent>
610
+ </UiNavigationMenuItem>
611
+
612
+ <UiNavigationMenuItem value="resources">
613
+ <UiNavigationMenuTrigger>Resources</UiNavigationMenuTrigger>
614
+ <UiNavigationMenuContent>
615
+ <ul class="grid w-[500px] gap-3 p-4 grid-cols-2">
616
+ <li>
617
+ <UiNavigationMenuLink href="#">
618
+ <div class="text-sm font-medium">Documentation</div>
619
+ <p class="text-sm text-muted-foreground">Guides and API reference</p>
620
+ </UiNavigationMenuLink>
621
+ </li>
622
+ <li>
623
+ <UiNavigationMenuLink href="#">
624
+ <div class="text-sm font-medium">Blog</div>
625
+ <p class="text-sm text-muted-foreground">Latest news and updates</p>
626
+ </UiNavigationMenuLink>
627
+ </li>
628
+ <li>
629
+ <UiNavigationMenuLink href="#">
630
+ <div class="text-sm font-medium">Community</div>
631
+ <p class="text-sm text-muted-foreground">Join the discussion</p>
632
+ </UiNavigationMenuLink>
633
+ </li>
634
+ <li>
635
+ <UiNavigationMenuLink href="#">
636
+ <div class="text-sm font-medium">Support</div>
637
+ <p class="text-sm text-muted-foreground">Get help from our team</p>
638
+ </UiNavigationMenuLink>
639
+ </li>
640
+ </ul>
641
+ </UiNavigationMenuContent>
642
+ </UiNavigationMenuItem>
643
+
644
+ <UiNavigationMenuItem>
645
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Pricing</UiNavigationMenuLink>
646
+ </UiNavigationMenuItem>
647
+ </UiNavigationMenuList>
648
+ </UiNavigationMenu>
649
+ </template>`;
650
+
651
+ /**
652
+ * Rich dropdown content with grid layout (mega menu style).
653
+ */
654
+ export const WithCustomContent: Story = {
655
+ render: (args) => ({
656
+ components: {
657
+ UiNavigationMenu,
658
+ UiNavigationMenuList,
659
+ UiNavigationMenuItem,
660
+ UiNavigationMenuTrigger,
661
+ UiNavigationMenuContent,
662
+ UiNavigationMenuLink,
663
+ },
664
+ setup() {
665
+ const value = useStoryModel(args);
666
+ return { args, value, navigationMenuTriggerStyle };
667
+ },
668
+ template: `<UiNavigationMenu
669
+ v-model:modelValue="value"
670
+ :orientation="args.orientation"
671
+ :dir="args.dir"
672
+ :delay-duration="args.delayDuration"
673
+ :skip-delay-duration="args.skipDelayDuration"
674
+ >
675
+ <UiNavigationMenuList>
676
+ <UiNavigationMenuItem value="products">
677
+ <UiNavigationMenuTrigger>Products</UiNavigationMenuTrigger>
678
+ <UiNavigationMenuContent>
679
+ <div class="grid gap-3 p-6 w-[600px] grid-cols-[.75fr_1fr]">
680
+ <div class="row-span-3 rounded-md bg-gradient-to-b from-muted/50 to-muted p-6">
681
+ <div class="mb-2 text-lg font-medium">Featured</div>
682
+ <p class="text-sm text-muted-foreground mb-4">
683
+ Our most popular product with advanced features and integrations.
684
+ </p>
685
+ <UiNavigationMenuLink href="#" class="text-sm font-medium text-primary hover:underline">
686
+ Learn more
687
+ </UiNavigationMenuLink>
688
+ </div>
689
+ <ul class="grid gap-3">
690
+ <li>
691
+ <UiNavigationMenuLink href="#">
692
+ <div class="text-sm font-medium">Analytics Platform</div>
693
+ <p class="text-sm text-muted-foreground">Real-time insights and reporting</p>
694
+ </UiNavigationMenuLink>
695
+ </li>
696
+ <li>
697
+ <UiNavigationMenuLink href="#">
698
+ <div class="text-sm font-medium">Automation Suite</div>
699
+ <p class="text-sm text-muted-foreground">Workflow automation tools</p>
700
+ </UiNavigationMenuLink>
701
+ </li>
702
+ <li>
703
+ <UiNavigationMenuLink href="#">
704
+ <div class="text-sm font-medium">Developer API</div>
705
+ <p class="text-sm text-muted-foreground">Build custom integrations</p>
706
+ </UiNavigationMenuLink>
707
+ </li>
708
+ </ul>
709
+ </div>
710
+ </UiNavigationMenuContent>
711
+ </UiNavigationMenuItem>
712
+
713
+ <UiNavigationMenuItem value="resources">
714
+ <UiNavigationMenuTrigger>Resources</UiNavigationMenuTrigger>
715
+ <UiNavigationMenuContent>
716
+ <ul class="grid w-[500px] gap-3 p-4 grid-cols-2">
717
+ <li>
718
+ <UiNavigationMenuLink href="#">
719
+ <div class="text-sm font-medium">Documentation</div>
720
+ <p class="text-sm text-muted-foreground">Guides and API reference</p>
721
+ </UiNavigationMenuLink>
722
+ </li>
723
+ <li>
724
+ <UiNavigationMenuLink href="#">
725
+ <div class="text-sm font-medium">Blog</div>
726
+ <p class="text-sm text-muted-foreground">Latest news and updates</p>
727
+ </UiNavigationMenuLink>
728
+ </li>
729
+ <li>
730
+ <UiNavigationMenuLink href="#">
731
+ <div class="text-sm font-medium">Community</div>
732
+ <p class="text-sm text-muted-foreground">Join the discussion</p>
733
+ </UiNavigationMenuLink>
734
+ </li>
735
+ <li>
736
+ <UiNavigationMenuLink href="#">
737
+ <div class="text-sm font-medium">Support</div>
738
+ <p class="text-sm text-muted-foreground">Get help from our team</p>
739
+ </UiNavigationMenuLink>
740
+ </li>
741
+ </ul>
742
+ </UiNavigationMenuContent>
743
+ </UiNavigationMenuItem>
744
+
745
+ <UiNavigationMenuItem>
746
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Pricing</UiNavigationMenuLink>
747
+ </UiNavigationMenuItem>
748
+ </UiNavigationMenuList>
749
+ </UiNavigationMenu>`,
750
+ }),
751
+ parameters: {
752
+ docs: {
753
+ source: {
754
+ code: withCustomContentTemplateSource,
755
+ },
756
+ },
757
+ },
758
+ };
759
+
760
+ const controlledStateTemplateSource = `<script setup lang="ts">
761
+ import { ref } from 'vue'
762
+ import {
763
+ UiNavigationMenu,
764
+ UiNavigationMenuList,
765
+ UiNavigationMenuItem,
766
+ UiNavigationMenuTrigger,
767
+ UiNavigationMenuContent,
768
+ UiNavigationMenuLink,
769
+ } from '@aleph-alpha/ui-library'
770
+
771
+ // Controlled state - menu opens/closes based on this value
772
+ const activeItem = ref('')
773
+
774
+ // You can programmatically control which menu is open
775
+ function openProducts() {
776
+ activeItem.value = 'products'
777
+ }
778
+
779
+ function closeAll() {
780
+ activeItem.value = ''
781
+ }
782
+ </script>
783
+
784
+ <template>
785
+ <div class="space-y-4">
786
+ <div class="flex gap-2">
787
+ <button type="button" @click="openProducts" class="px-3 py-1 text-sm border rounded">
788
+ Open Products
789
+ </button>
790
+ <button type="button" @click="closeAll" class="px-3 py-1 text-sm border rounded">
791
+ Close All
792
+ </button>
793
+ <span class="text-sm text-muted-foreground">
794
+ Current value: "{{ activeItem }}"
795
+ </span>
796
+ </div>
797
+
798
+ <UiNavigationMenu v-model:modelValue="activeItem">
799
+ <UiNavigationMenuList>
800
+ <UiNavigationMenuItem value="products">
801
+ <UiNavigationMenuTrigger>Products</UiNavigationMenuTrigger>
802
+ <UiNavigationMenuContent>
803
+ <ul class="grid w-[300px]">
804
+ <li>
805
+ <UiNavigationMenuLink href="#">
806
+ Product A
807
+ </UiNavigationMenuLink>
808
+ </li>
809
+ <li>
810
+ <UiNavigationMenuLink href="#">
811
+ Product B
812
+ </UiNavigationMenuLink>
813
+ </li>
814
+ </ul>
815
+ </UiNavigationMenuContent>
816
+ </UiNavigationMenuItem>
817
+
818
+ <UiNavigationMenuItem value="services">
819
+ <UiNavigationMenuTrigger>Services</UiNavigationMenuTrigger>
820
+ <UiNavigationMenuContent>
821
+ <ul class="grid w-[300px]">
822
+ <li>
823
+ <UiNavigationMenuLink href="#">
824
+ Service A
825
+ </UiNavigationMenuLink>
826
+ </li>
827
+ <li>
828
+ <UiNavigationMenuLink href="#">
829
+ Service B
830
+ </UiNavigationMenuLink>
831
+ </li>
832
+ </ul>
833
+ </UiNavigationMenuContent>
834
+ </UiNavigationMenuItem>
835
+ </UiNavigationMenuList>
836
+ </UiNavigationMenu>
837
+ </div>
838
+ </template>`;
839
+
840
+ const keyboardNavigationTemplateSource = `<script setup lang="ts">
841
+ import { ref } from 'vue'
842
+ import {
843
+ UiNavigationMenu,
844
+ UiNavigationMenuList,
845
+ UiNavigationMenuItem,
846
+ UiNavigationMenuTrigger,
847
+ UiNavigationMenuContent,
848
+ UiNavigationMenuLink,
849
+ navigationMenuTriggerStyle,
850
+ } from '@aleph-alpha/ui-library'
851
+
852
+ const value = ref('')
853
+ </script>
854
+
855
+ <template>
856
+ <div class="space-y-4">
857
+ <div class="p-4 bg-muted rounded-md text-sm">
858
+ <p class="font-medium mb-2">Keyboard Navigation:</p>
859
+ <ul class="space-y-1 text-muted-foreground">
860
+ <li><kbd class="px-1 bg-background rounded">Tab</kbd> - Move focus to/from navigation</li>
861
+ <li><kbd class="px-1 bg-background rounded">Arrow Left/Right</kbd> - Navigate between menu items</li>
862
+ <li><kbd class="px-1 bg-background rounded">Enter</kbd> or <kbd class="px-1 bg-background rounded">Space</kbd> - Open dropdown / activate link</li>
863
+ <li><kbd class="px-1 bg-background rounded">Escape</kbd> - Close open dropdown</li>
864
+ <li><kbd class="px-1 bg-background rounded">Arrow Down</kbd> - Move focus into dropdown content</li>
865
+ </ul>
866
+ </div>
867
+
868
+ <UiNavigationMenu v-model:modelValue="value" aria-label="Main navigation" :disable-hover-trigger="true">
869
+ <UiNavigationMenuList>
870
+ <UiNavigationMenuItem>
871
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Home</UiNavigationMenuLink>
872
+ </UiNavigationMenuItem>
873
+
874
+ <UiNavigationMenuItem value="products">
875
+ <UiNavigationMenuTrigger>Products</UiNavigationMenuTrigger>
876
+ <UiNavigationMenuContent>
877
+ <ul class="grid w-[300px]">
878
+ <li>
879
+ <UiNavigationMenuLink href="#">
880
+ <div class="font-medium">Analytics</div>
881
+ <p class="text-sm text-muted-foreground">Track your metrics</p>
882
+ </UiNavigationMenuLink>
883
+ </li>
884
+ <li>
885
+ <UiNavigationMenuLink href="#">
886
+ <div class="font-medium">Automation</div>
887
+ <p class="text-sm text-muted-foreground">Streamline workflows</p>
888
+ </UiNavigationMenuLink>
889
+ </li>
890
+ </ul>
891
+ </UiNavigationMenuContent>
892
+ </UiNavigationMenuItem>
893
+
894
+ <UiNavigationMenuItem value="resources">
895
+ <UiNavigationMenuTrigger>Resources</UiNavigationMenuTrigger>
896
+ <UiNavigationMenuContent>
897
+ <ul class="grid w-[300px]">
898
+ <li>
899
+ <UiNavigationMenuLink href="#">
900
+ <div class="font-medium">Documentation</div>
901
+ <p class="text-sm text-muted-foreground">Guides and API reference</p>
902
+ </UiNavigationMenuLink>
903
+ </li>
904
+ <li>
905
+ <UiNavigationMenuLink href="#">
906
+ <div class="font-medium">Support</div>
907
+ <p class="text-sm text-muted-foreground">Get help from our team</p>
908
+ </UiNavigationMenuLink>
909
+ </li>
910
+ </ul>
911
+ </UiNavigationMenuContent>
912
+ </UiNavigationMenuItem>
913
+
914
+ <UiNavigationMenuItem>
915
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Contact</UiNavigationMenuLink>
916
+ </UiNavigationMenuItem>
917
+ </UiNavigationMenuList>
918
+ </UiNavigationMenu>
919
+ </div>
920
+ </template>`;
921
+
922
+ const withActivePageTemplateSource = `<script setup lang="ts">
923
+ import {
924
+ UiNavigationMenu,
925
+ UiNavigationMenuList,
926
+ UiNavigationMenuItem,
927
+ UiNavigationMenuLink,
928
+ navigationMenuTriggerStyle,
929
+ } from '@aleph-alpha/ui-library'
930
+
931
+ // In a real app, you would determine active state based on current route
932
+ const currentPage = 'features'
933
+ </script>
934
+
935
+ <template>
936
+ <UiNavigationMenu aria-label="Main navigation">
937
+ <UiNavigationMenuList>
938
+ <UiNavigationMenuItem>
939
+ <UiNavigationMenuLink href="#" :active="currentPage === 'home'" :class="navigationMenuTriggerStyle()">Home</UiNavigationMenuLink>
940
+ </UiNavigationMenuItem>
941
+ <UiNavigationMenuItem>
942
+ <UiNavigationMenuLink href="#" :active="currentPage === 'features'" :class="navigationMenuTriggerStyle()">Features</UiNavigationMenuLink>
943
+ </UiNavigationMenuItem>
944
+ <UiNavigationMenuItem>
945
+ <UiNavigationMenuLink href="#" :active="currentPage === 'pricing'" :class="navigationMenuTriggerStyle()">Pricing</UiNavigationMenuLink>
946
+ </UiNavigationMenuItem>
947
+ <UiNavigationMenuItem>
948
+ <UiNavigationMenuLink href="#" :active="currentPage === 'contact'" :class="navigationMenuTriggerStyle()">Contact</UiNavigationMenuLink>
949
+ </UiNavigationMenuItem>
950
+ </UiNavigationMenuList>
951
+ </UiNavigationMenu>
952
+ </template>`;
953
+
954
+ /**
955
+ * Demonstrates v-model:modelValue for controlled active state.
956
+ * Use the buttons to programmatically control which menu item is open.
957
+ */
958
+ export const ControlledState: Story = {
959
+ render: (args) => ({
960
+ components: {
961
+ UiNavigationMenu,
962
+ UiNavigationMenuList,
963
+ UiNavigationMenuItem,
964
+ UiNavigationMenuTrigger,
965
+ UiNavigationMenuContent,
966
+ UiNavigationMenuLink,
967
+ },
968
+ setup() {
969
+ const activeItem = ref(args.modelValue || '');
970
+ watch(
971
+ () => args.modelValue,
972
+ (v) => {
973
+ activeItem.value = v || '';
974
+ },
975
+ );
976
+
977
+ function openProducts() {
978
+ activeItem.value = 'products';
979
+ }
980
+
981
+ function closeAll() {
982
+ activeItem.value = '';
983
+ }
984
+
985
+ return { args, activeItem, openProducts, closeAll };
986
+ },
987
+ template: `<div class="space-y-4">
988
+ <div class="flex gap-2 items-center">
989
+ <button type="button" @click="openProducts" class="px-3 py-1 text-sm border rounded hover:bg-muted">
990
+ Open Products
991
+ </button>
992
+ <button type="button" @click="closeAll" class="px-3 py-1 text-sm border rounded hover:bg-muted">
993
+ Close All
994
+ </button>
995
+ <span class="text-sm text-muted-foreground">
996
+ Current value: "{{ activeItem }}"
997
+ </span>
998
+ </div>
999
+
1000
+ <UiNavigationMenu
1001
+ v-model:modelValue="activeItem"
1002
+ :orientation="args.orientation"
1003
+ :dir="args.dir"
1004
+ :delay-duration="args.delayDuration"
1005
+ :skip-delay-duration="args.skipDelayDuration"
1006
+ >
1007
+ <UiNavigationMenuList>
1008
+ <UiNavigationMenuItem value="products">
1009
+ <UiNavigationMenuTrigger>Products</UiNavigationMenuTrigger>
1010
+ <UiNavigationMenuContent>
1011
+ <ul class="grid w-[300px]">
1012
+ <li>
1013
+ <UiNavigationMenuLink href="#">
1014
+ Product A
1015
+ </UiNavigationMenuLink>
1016
+ </li>
1017
+ <li>
1018
+ <UiNavigationMenuLink href="#">
1019
+ Product B
1020
+ </UiNavigationMenuLink>
1021
+ </li>
1022
+ </ul>
1023
+ </UiNavigationMenuContent>
1024
+ </UiNavigationMenuItem>
1025
+
1026
+ <UiNavigationMenuItem value="services">
1027
+ <UiNavigationMenuTrigger>Services</UiNavigationMenuTrigger>
1028
+ <UiNavigationMenuContent>
1029
+ <ul class="grid w-[300px]">
1030
+ <li>
1031
+ <UiNavigationMenuLink href="#">
1032
+ Service A
1033
+ </UiNavigationMenuLink>
1034
+ </li>
1035
+ <li>
1036
+ <UiNavigationMenuLink href="#">
1037
+ Service B
1038
+ </UiNavigationMenuLink>
1039
+ </li>
1040
+ </ul>
1041
+ </UiNavigationMenuContent>
1042
+ </UiNavigationMenuItem>
1043
+ </UiNavigationMenuList>
1044
+ </UiNavigationMenu>
1045
+ </div>`,
1046
+ }),
1047
+ parameters: {
1048
+ docs: {
1049
+ source: {
1050
+ code: controlledStateTemplateSource,
1051
+ },
1052
+ },
1053
+ },
1054
+ };
1055
+
1056
+ /**
1057
+ * Demonstrates keyboard navigation support. Click on a menu item and use
1058
+ * Arrow keys to navigate, Enter/Space to activate, and Escape to close.
1059
+ * Hover is disabled in this example to better demonstrate keyboard interaction.
1060
+ */
1061
+ export const KeyboardNavigation: Story = {
1062
+ render: (args) => ({
1063
+ components: {
1064
+ UiNavigationMenu,
1065
+ UiNavigationMenuList,
1066
+ UiNavigationMenuItem,
1067
+ UiNavigationMenuTrigger,
1068
+ UiNavigationMenuContent,
1069
+ UiNavigationMenuLink,
1070
+ },
1071
+ setup() {
1072
+ const value = useStoryModel(args);
1073
+ return { args, value, navigationMenuTriggerStyle };
1074
+ },
1075
+ template: `<div class="space-y-4">
1076
+ <div class="p-4 bg-muted rounded-md text-sm">
1077
+ <p class="font-medium mb-2">Keyboard Navigation:</p>
1078
+ <ul class="space-y-1 text-muted-foreground">
1079
+ <li><kbd class="px-1 bg-background rounded">Tab</kbd> - Move focus to/from navigation</li>
1080
+ <li><kbd class="px-1 bg-background rounded">Arrow Left/Right</kbd> - Navigate between menu items</li>
1081
+ <li><kbd class="px-1 bg-background rounded">Enter</kbd> or <kbd class="px-1 bg-background rounded">Space</kbd> - Open dropdown / activate link</li>
1082
+ <li><kbd class="px-1 bg-background rounded">Escape</kbd> - Close open dropdown</li>
1083
+ <li><kbd class="px-1 bg-background rounded">Arrow Down</kbd> - Move focus into dropdown content</li>
1084
+ </ul>
1085
+ </div>
1086
+
1087
+ <UiNavigationMenu
1088
+ v-model:modelValue="value"
1089
+ aria-label="Main navigation"
1090
+ :disable-hover-trigger="true"
1091
+ :dir="args.dir"
1092
+ >
1093
+ <UiNavigationMenuList>
1094
+ <UiNavigationMenuItem>
1095
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Home</UiNavigationMenuLink>
1096
+ </UiNavigationMenuItem>
1097
+
1098
+ <UiNavigationMenuItem value="products">
1099
+ <UiNavigationMenuTrigger>Products</UiNavigationMenuTrigger>
1100
+ <UiNavigationMenuContent>
1101
+ <ul class="grid w-[300px]">
1102
+ <li>
1103
+ <UiNavigationMenuLink href="#">
1104
+ <div class="font-medium">Analytics</div>
1105
+ <p class="text-sm text-muted-foreground">Track your metrics</p>
1106
+ </UiNavigationMenuLink>
1107
+ </li>
1108
+ <li>
1109
+ <UiNavigationMenuLink href="#">
1110
+ <div class="font-medium">Automation</div>
1111
+ <p class="text-sm text-muted-foreground">Streamline workflows</p>
1112
+ </UiNavigationMenuLink>
1113
+ </li>
1114
+ </ul>
1115
+ </UiNavigationMenuContent>
1116
+ </UiNavigationMenuItem>
1117
+
1118
+ <UiNavigationMenuItem value="resources">
1119
+ <UiNavigationMenuTrigger>Resources</UiNavigationMenuTrigger>
1120
+ <UiNavigationMenuContent>
1121
+ <ul class="grid w-[300px]">
1122
+ <li>
1123
+ <UiNavigationMenuLink href="#">
1124
+ <div class="font-medium">Documentation</div>
1125
+ <p class="text-sm text-muted-foreground">Guides and API reference</p>
1126
+ </UiNavigationMenuLink>
1127
+ </li>
1128
+ <li>
1129
+ <UiNavigationMenuLink href="#">
1130
+ <div class="font-medium">Support</div>
1131
+ <p class="text-sm text-muted-foreground">Get help from our team</p>
1132
+ </UiNavigationMenuLink>
1133
+ </li>
1134
+ </ul>
1135
+ </UiNavigationMenuContent>
1136
+ </UiNavigationMenuItem>
1137
+
1138
+ <UiNavigationMenuItem>
1139
+ <UiNavigationMenuLink href="#" :class="navigationMenuTriggerStyle()">Contact</UiNavigationMenuLink>
1140
+ </UiNavigationMenuItem>
1141
+ </UiNavigationMenuList>
1142
+ </UiNavigationMenu>
1143
+ </div>`,
1144
+ }),
1145
+ parameters: {
1146
+ docs: {
1147
+ source: {
1148
+ code: keyboardNavigationTemplateSource,
1149
+ },
1150
+ story: {
1151
+ height: '600px',
1152
+ },
1153
+ },
1154
+ },
1155
+ };
1156
+
1157
+ /**
1158
+ * Demonstrates active page indication with aria-current="page".
1159
+ * The active link is visually highlighted and announced to screen readers.
1160
+ */
1161
+ export const WithActivePage: Story = {
1162
+ render: () => ({
1163
+ components: {
1164
+ UiNavigationMenu,
1165
+ UiNavigationMenuList,
1166
+ UiNavigationMenuItem,
1167
+ UiNavigationMenuLink,
1168
+ },
1169
+ setup() {
1170
+ return { navigationMenuTriggerStyle };
1171
+ },
1172
+ template: `<UiNavigationMenu aria-label="Main navigation">
1173
+ <UiNavigationMenuList>
1174
+ <UiNavigationMenuItem>
1175
+ <UiNavigationMenuLink href="#" :active="false" :class="navigationMenuTriggerStyle()">Home</UiNavigationMenuLink>
1176
+ </UiNavigationMenuItem>
1177
+ <UiNavigationMenuItem>
1178
+ <UiNavigationMenuLink href="#" :active="true" :class="navigationMenuTriggerStyle()">Features</UiNavigationMenuLink>
1179
+ </UiNavigationMenuItem>
1180
+ <UiNavigationMenuItem>
1181
+ <UiNavigationMenuLink href="#" :active="false" :class="navigationMenuTriggerStyle()">Pricing</UiNavigationMenuLink>
1182
+ </UiNavigationMenuItem>
1183
+ <UiNavigationMenuItem>
1184
+ <UiNavigationMenuLink href="#" :active="false" :class="navigationMenuTriggerStyle()">Contact</UiNavigationMenuLink>
1185
+ </UiNavigationMenuItem>
1186
+ </UiNavigationMenuList>
1187
+ </UiNavigationMenu>`,
1188
+ }),
1189
+ parameters: {
1190
+ docs: {
1191
+ source: {
1192
+ code: withActivePageTemplateSource,
1193
+ },
1194
+ },
1195
+ },
1196
+ };