@adyen/bento-mcp 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/README.md +41 -9
- package/dist/assets/components/drawer/drawer.docs.mdx +68 -0
- package/dist/assets/components/drawer/drawer.stories.ts +1 -0
- package/dist/assets/components/drawer/drawer.types.ts +1 -0
- package/dist/assets/components/drawer/drawer.vue +1 -0
- package/dist/assets/components/input-field/input-field.types.ts +1 -1
- package/dist/assets/components/input-field/input-field.vue +1 -1
- package/dist/assets/components/modal/modal.vue +1 -1
- package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.stories.ts +1 -0
- package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.types.ts +1 -0
- package/dist/assets/components/navigation-menu/components/navigation-menu-group/navigation-menu-group.vue +1 -0
- package/dist/assets/components/navigation-menu/components/navigation-menu-item/navigation-menu-item.stories.ts +1 -0
- package/dist/assets/components/navigation-menu/components/navigation-menu-item/navigation-menu-item.types.ts +1 -0
- package/dist/assets/components/navigation-menu/components/navigation-menu-item/navigation-menu-item.vue +1 -0
- package/dist/assets/components/navigation-menu/navigation-menu.docs.mdx +321 -0
- package/dist/assets/components/navigation-menu/navigation-menu.stories.ts +1 -0
- package/dist/assets/components/navigation-menu/navigation-menu.types.ts +1 -0
- package/dist/assets/components/navigation-menu/navigation-menu.vue +1 -0
- package/dist/assets/components.json +4 -0
- package/dist/assets/index.ts +1 -1
- package/dist/assets/usage.json +10 -6
- package/dist/assets/variables.css +3 -0
- package/dist/main.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { Canvas, Meta, Source } from '@storybook/blocks';
|
|
2
|
+
import * as NavigationMenuStories from './navigation-menu.stories';
|
|
3
|
+
|
|
4
|
+
<Meta of={NavigationMenuStories} />
|
|
5
|
+
|
|
6
|
+
# Navigation Menu
|
|
7
|
+
|
|
8
|
+
The Navigation Menu provides a structured way to organize and navigate through different sections of an application. It
|
|
9
|
+
supports simple lists, collapsible groups, and nested items, making it ideal for complex navigation hierarchies.
|
|
10
|
+
|
|
11
|
+
<Canvas of={NavigationMenuStories.EverythingBagel} />
|
|
12
|
+
|
|
13
|
+
## Use Cases
|
|
14
|
+
|
|
15
|
+
Use a Navigation Menu when:
|
|
16
|
+
|
|
17
|
+
- You need to organize multiple navigation items in a vertical sidebar
|
|
18
|
+
- Your application has a hierarchical structure with sections and subsections
|
|
19
|
+
- You want to provide quick access to different pages or views within your application
|
|
20
|
+
- You need collapsible groups to reduce visual clutter while maintaining discoverability
|
|
21
|
+
|
|
22
|
+
### Do not use
|
|
23
|
+
|
|
24
|
+
Do not use a Navigation Menu:
|
|
25
|
+
|
|
26
|
+
- For horizontal navigation - use `bento-tabs` or a horizontal navbar instead
|
|
27
|
+
- For secondary navigation within a content area - use `bento-secondary-nav` instead
|
|
28
|
+
- For switching between different views of the same content - use `bento-tabs` instead
|
|
29
|
+
|
|
30
|
+
**Navigation Menu vs Secondary Nav**: Navigation Menu is designed for primary app-level navigation in sidebars, while
|
|
31
|
+
Secondary Nav is better suited for content-level navigation within pages (e.g., settings sections).
|
|
32
|
+
|
|
33
|
+
**Navigation Menu vs Tabs**: Tabs are for switching between related content views on the same page, while Navigation
|
|
34
|
+
Menu is for navigating to different pages or major sections of the app.
|
|
35
|
+
|
|
36
|
+
## Variations
|
|
37
|
+
|
|
38
|
+
### Simple list
|
|
39
|
+
|
|
40
|
+
The most basic usage is a flat list of navigation items without any grouping.
|
|
41
|
+
|
|
42
|
+
<Canvas of={NavigationMenuStories.SimpleList} />
|
|
43
|
+
|
|
44
|
+
### With groups
|
|
45
|
+
|
|
46
|
+
Use `bento-navigation-menu-group` to organize items into collapsible sections. This is useful when you have many
|
|
47
|
+
navigation items that can be logically grouped.
|
|
48
|
+
|
|
49
|
+
<Source
|
|
50
|
+
dark
|
|
51
|
+
language="html"
|
|
52
|
+
code={`<bento-navigation-menu>
|
|
53
|
+
<bento-navigation-menu-group label="Settings" :is-expanded="true">
|
|
54
|
+
<template #icon><folder-icon /></template>
|
|
55
|
+
<bento-navigation-menu-item nested value="general" label="General" />
|
|
56
|
+
<bento-navigation-menu-item nested value="security" label="Security" />
|
|
57
|
+
</bento-navigation-menu-group>
|
|
58
|
+
</bento-navigation-menu>`}
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
> **Note**: When using items inside a group, set the `nested` prop to `true` on each `bento-navigation-menu-item` to
|
|
62
|
+
> apply proper indentation and styling.
|
|
63
|
+
|
|
64
|
+
### With header actions
|
|
65
|
+
|
|
66
|
+
Use the `headerActions` slot to add interactive elements like search or filters to the navigation header.
|
|
67
|
+
|
|
68
|
+
<Source
|
|
69
|
+
dark
|
|
70
|
+
language="html"
|
|
71
|
+
code={`<bento-navigation-menu label="Pages">
|
|
72
|
+
<template #headerActions>
|
|
73
|
+
<bento-button variant="tertiary-with-background">
|
|
74
|
+
<template #iconLeft><search-icon /></template>
|
|
75
|
+
</bento-button>
|
|
76
|
+
</template>
|
|
77
|
+
<!-- menu items -->
|
|
78
|
+
</bento-navigation-menu>`}
|
|
79
|
+
/>
|
|
80
|
+
|
|
81
|
+
### With expand/collapse all button
|
|
82
|
+
|
|
83
|
+
Set `showExpandAllButton` to `true` to display a button that expands or collapses all groups at once. This is helpful
|
|
84
|
+
when you have multiple collapsible groups.
|
|
85
|
+
|
|
86
|
+
> **Note**: The expand/collapse all button only appears when there is at least one `bento-navigation-menu-group` in the
|
|
87
|
+
> menu.
|
|
88
|
+
|
|
89
|
+
### Action visibility
|
|
90
|
+
|
|
91
|
+
By default, content in the `action` slot of a menu item is only visible on hover. Set `alwaysShowActions` to `true` to
|
|
92
|
+
keep the action visible at all times.
|
|
93
|
+
|
|
94
|
+
## Behavior
|
|
95
|
+
|
|
96
|
+
### Navigation patterns
|
|
97
|
+
|
|
98
|
+
> **⚠️ Important**: Every `bento-navigation-menu-item` **must** be rendered as (or wrapped in) a real link. Without a
|
|
99
|
+
> link, the item is not keyboard-accessible, cannot be opened in a new tab, does not expose a URL to screen readers, and
|
|
100
|
+
> fails core navigation accessibility requirements. Use **one** of the two patterns below.
|
|
101
|
+
|
|
102
|
+
#### 1. Controlled navigation with the `link` prop
|
|
103
|
+
|
|
104
|
+
Pass a `link` object to `bento-navigation-menu-item` to integrate with routing. The `link` prop accepts the same props
|
|
105
|
+
as `bento-link`, allowing seamless integration with Vue Router or other routing solutions.
|
|
106
|
+
|
|
107
|
+
<Source
|
|
108
|
+
dark
|
|
109
|
+
language="html"
|
|
110
|
+
code={`<bento-navigation-menu-item
|
|
111
|
+
value="home"
|
|
112
|
+
label="Home"
|
|
113
|
+
:link="{ to: '/home' }"
|
|
114
|
+
>
|
|
115
|
+
<template #icon><home-icon /></template>
|
|
116
|
+
</bento-navigation-menu-item>`}
|
|
117
|
+
/>
|
|
118
|
+
|
|
119
|
+
This is the recommended approach as it provides the best accessibility, SEO, and user experience (right-click to open in
|
|
120
|
+
new tab, copy link, etc.) out of the box.
|
|
121
|
+
|
|
122
|
+
#### 2. Wrapping with a custom link component
|
|
123
|
+
|
|
124
|
+
If you need full control over the link behavior, wrap the item with any link component (such as `router-link`,
|
|
125
|
+
`bento-link`, or a custom link component). The wrapping element **must** be a real, focusable link.
|
|
126
|
+
|
|
127
|
+
<Source
|
|
128
|
+
dark
|
|
129
|
+
language="html"
|
|
130
|
+
code={`<router-link to="/profile">
|
|
131
|
+
<bento-navigation-menu-item
|
|
132
|
+
value="profile"
|
|
133
|
+
label="Profile"
|
|
134
|
+
>
|
|
135
|
+
<template #icon><profile-icon /></template>
|
|
136
|
+
</bento-navigation-menu-item>
|
|
137
|
+
</router-link>`}
|
|
138
|
+
/>
|
|
139
|
+
|
|
140
|
+
> **Note**: When wrapping with a custom link component, `aria-current` is **not** applied automatically by the menu item
|
|
141
|
+
> — you must set `aria-current="page"` on the wrapping element yourself (many routers, like Vue Router, handle this
|
|
142
|
+
> automatically via `router-link-active` / `router-link-exact-active`). `aria-current` is only applied automatically
|
|
143
|
+
> when you use the `link` prop.
|
|
144
|
+
|
|
145
|
+
#### Tracking navigation with the `update:active-page` event
|
|
146
|
+
|
|
147
|
+
The `bento-navigation-menu` emits `update:active-page` whenever an item is clicked. This is useful for side effects such
|
|
148
|
+
as analytics tracking, syncing state to a store, or triggering other UI updates — **in addition to** one of the two link
|
|
149
|
+
patterns above.
|
|
150
|
+
|
|
151
|
+
> **⚠️ Do not** use `update:active-page` as the **only** navigation mechanism. The event does not provide a focusable,
|
|
152
|
+
> keyboard-accessible link — items without a `link` prop or link wrapper are inaccessible to keyboard and screen reader
|
|
153
|
+
> users. Always pair it with one of the patterns above.
|
|
154
|
+
|
|
155
|
+
### Group expansion state
|
|
156
|
+
|
|
157
|
+
Groups can be controlled or uncontrolled. To control a group's expansion state, bind to `is-expanded`:
|
|
158
|
+
|
|
159
|
+
<Source
|
|
160
|
+
dark
|
|
161
|
+
language="html"
|
|
162
|
+
code={`<bento-navigation-menu-group
|
|
163
|
+
:is-expanded="paymentsExpanded"
|
|
164
|
+
@update:is-expanded="paymentsExpanded = $event"
|
|
165
|
+
>
|
|
166
|
+
<!-- items -->
|
|
167
|
+
</bento-navigation-menu-group>`}
|
|
168
|
+
/>
|
|
169
|
+
|
|
170
|
+
### Semi-collapsed groups
|
|
171
|
+
|
|
172
|
+
When a group contains the currently active item, collapsing the group will enter a "semi-collapsed" state where only the
|
|
173
|
+
active item remains visible. This provides context about the current location while saving space. The group will close
|
|
174
|
+
fully as soon as a different page is selected.
|
|
175
|
+
|
|
176
|
+
### Truncated labels
|
|
177
|
+
|
|
178
|
+
Item and group labels are truncated with an ellipsis when they overflow the available width. In that case, the full
|
|
179
|
+
label is automatically shown in a tooltip on hover and focus, so it remains discoverable without extra configuration.
|
|
180
|
+
When the label fits, no tooltip is rendered.
|
|
181
|
+
|
|
182
|
+
## Accessibility
|
|
183
|
+
|
|
184
|
+
The Navigation Menu follows WCAG guidelines for accessible navigation patterns.
|
|
185
|
+
|
|
186
|
+
### Nav landmark
|
|
187
|
+
|
|
188
|
+
The component uses the `<nav>` element, which creates a navigation landmark region. This helps screen reader users
|
|
189
|
+
quickly locate and navigate to the primary navigation area of your application.
|
|
190
|
+
|
|
191
|
+
#### Labeling the landmark
|
|
192
|
+
|
|
193
|
+
When a page has more than one navigation landmark (for example, a primary sidebar and a secondary nav, breadcrumbs, or a
|
|
194
|
+
footer nav), each landmark needs an accessible name so screen reader users can tell them apart.
|
|
195
|
+
|
|
196
|
+
- If a `label` prop is provided, the `<nav>` is automatically labeled via `aria-labelledby` pointing to the rendered
|
|
197
|
+
label — no extra work needed.
|
|
198
|
+
- If no `label` prop is provided, you **should** add an `aria-label` attribute to the component to give the landmark an
|
|
199
|
+
accessible name:
|
|
200
|
+
|
|
201
|
+
> **Note**: Omitting both `label` and `aria-label` is only acceptable when the page contains a single navigation
|
|
202
|
+
> landmark. When in doubt, provide one.
|
|
203
|
+
|
|
204
|
+
### Keyboard interaction
|
|
205
|
+
|
|
206
|
+
| Keyboard interaction | Action |
|
|
207
|
+
| -------------------- | ------------------------------------------------------------------ |
|
|
208
|
+
| `Tab` | Moves focus to the next interactive element (item or group header) |
|
|
209
|
+
| `Shift + Tab` | Moves focus to the previous interactive element |
|
|
210
|
+
| `Space` | Activates the focused item or toggles the focused group |
|
|
211
|
+
| `Enter` | Activates the focused item or toggles the focused group |
|
|
212
|
+
|
|
213
|
+
### Roles, states and properties
|
|
214
|
+
|
|
215
|
+
#### Navigation Menu (container)
|
|
216
|
+
|
|
217
|
+
| Role | Attribute | Element | Usage |
|
|
218
|
+
| ----- | -------------------------------- | ------- | --------------------------------------------------------------------------------------------- |
|
|
219
|
+
| `nav` | | `nav` | Identifies the element as a navigation landmark region |
|
|
220
|
+
| | `aria-labelledby="ID_REFERENCE"` | `nav` | Applied automatically when `label` is set; points to the rendered label |
|
|
221
|
+
| | `aria-label` | `nav` | Should be provided by the consumer when no `label` is set, to give the landmark a unique name |
|
|
222
|
+
|
|
223
|
+
#### Navigation Menu Item
|
|
224
|
+
|
|
225
|
+
| Role | Attribute | Element | Usage |
|
|
226
|
+
| ------ | --------------------- | ------- | ------------------------------------------------------------------------------- |
|
|
227
|
+
| | `aria-current="page"` | `a` | Applied automatically when the item is selected **and** the `link` prop is used |
|
|
228
|
+
| `link` | | `a` | Applied automatically when using the `link` prop (via `bento-link`) |
|
|
229
|
+
|
|
230
|
+
> When wrapping the item with a custom link component, set `aria-current="page"` on the wrapping element yourself.
|
|
231
|
+
|
|
232
|
+
#### Navigation Menu Group
|
|
233
|
+
|
|
234
|
+
| Role | Attribute | Element | Usage |
|
|
235
|
+
| -------- | -------------------------------- | -------- | ---------------------------------------------------------------------------- |
|
|
236
|
+
| `button` | | `button` | The group header is a button that controls expansion/collapse |
|
|
237
|
+
| | `aria-expanded="true"` | `button` | Indicates the group is expanded and its content is visible |
|
|
238
|
+
| | `aria-expanded="false"` | `button` | Indicates the group is collapsed and its content is hidden |
|
|
239
|
+
| | `aria-controls="ID_REFERENCE"` | `button` | Refers to the content region controlled by this button |
|
|
240
|
+
| `region` | | `div` | The expandable content area |
|
|
241
|
+
| | `aria-labelledby="ID_REFERENCE"` | `div` | Refers to the button that controls this region, providing an accessible name |
|
|
242
|
+
|
|
243
|
+
## Component API
|
|
244
|
+
|
|
245
|
+
### BentoNavigationMenu
|
|
246
|
+
|
|
247
|
+
The main container component.
|
|
248
|
+
|
|
249
|
+
#### Props
|
|
250
|
+
|
|
251
|
+
| Prop | Type | Default | Description |
|
|
252
|
+
| --------------------- | --------- | ----------- | ------------------------------------------------- |
|
|
253
|
+
| `label` | `string` | `undefined` | Label text for the navigation menu header |
|
|
254
|
+
| `showExpandAllButton` | `boolean` | `false` | Whether to show the expand/collapse all button |
|
|
255
|
+
| `activePage` | `string` | `undefined` | The value of the currently active navigation item |
|
|
256
|
+
|
|
257
|
+
#### Slots
|
|
258
|
+
|
|
259
|
+
| Slot | Description |
|
|
260
|
+
| --------------- | -------------------------------------- |
|
|
261
|
+
| `default` | Navigation items and groups |
|
|
262
|
+
| `headerActions` | Action buttons displayed in the header |
|
|
263
|
+
|
|
264
|
+
#### Events
|
|
265
|
+
|
|
266
|
+
| Event | Payload | Description |
|
|
267
|
+
| -------------------- | -------- | ------------------------------------ |
|
|
268
|
+
| `update:active-page` | `string` | Emitted when the active page changes |
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
### BentoNavigationMenuItem
|
|
273
|
+
|
|
274
|
+
Individual navigation item component.
|
|
275
|
+
|
|
276
|
+
#### Props
|
|
277
|
+
|
|
278
|
+
| Prop | Type | Default | Description |
|
|
279
|
+
| ------------------- | ---------------- | ----------- | ---------------------------------------------------------------------------- |
|
|
280
|
+
| `value` | `string` | (required) | Unique identifier for this navigation item |
|
|
281
|
+
| `label` | `string` | (required) | Label text for the item |
|
|
282
|
+
| `nested` | `boolean` | `false` | Whether the item is nested within a group (affects styling) |
|
|
283
|
+
| `link` | `BentoLinkProps` | `undefined` | Link properties to make the item a navigable link |
|
|
284
|
+
| `alwaysShowActions` | `boolean` | `false` | Whether the action slot should always be visible (default: visible on hover) |
|
|
285
|
+
|
|
286
|
+
#### Slots
|
|
287
|
+
|
|
288
|
+
| Slot | Description |
|
|
289
|
+
| -------- | ------------------------------------------------------------ |
|
|
290
|
+
| `icon` | Icon displayed before the label (not shown for nested items) |
|
|
291
|
+
| `action` | Action element displayed at the end of the item |
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
### BentoNavigationMenuGroup
|
|
296
|
+
|
|
297
|
+
Collapsible group container for navigation items.
|
|
298
|
+
|
|
299
|
+
#### Props
|
|
300
|
+
|
|
301
|
+
| Prop | Type | Default | Description |
|
|
302
|
+
| ------------ | --------- | ------- | ----------------------------- |
|
|
303
|
+
| `isExpanded` | `boolean` | `false` | Whether the group is expanded |
|
|
304
|
+
| `label` | `string` | — | Label text for the group |
|
|
305
|
+
|
|
306
|
+
#### Slots
|
|
307
|
+
|
|
308
|
+
| Slot | Description |
|
|
309
|
+
| --------- | ------------------------------- |
|
|
310
|
+
| `icon` | Icon displayed before the label |
|
|
311
|
+
| `default` | Nested navigation items |
|
|
312
|
+
|
|
313
|
+
#### Events
|
|
314
|
+
|
|
315
|
+
| Event | Payload | Description |
|
|
316
|
+
| -------------------- | --------- | --------------------------------- |
|
|
317
|
+
| `update:is-expanded` | `boolean` | Emitted when the group is toggled |
|
|
318
|
+
|
|
319
|
+
## Resources
|
|
320
|
+
|
|
321
|
+
- [Figma link](https://www.figma.com/design/IXcB6elA29Qy6waH5afmO9/WIP-navigation?node-id=748-8290&m=dev)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { ref } from 'vue'; import { storybookDocsParameter } from '@/utils/ts/storybook'; import BentoNavigationMenu from './navigation-menu.vue'; import BentoNavigationMenuItem from './components/navigation-menu-item/navigation-menu-item.vue'; import BentoNavigationMenuGroup from './components/navigation-menu-group/navigation-menu-group.vue'; import { BentoButton } from '@/components/button'; import { BentoLink } from '@/components/link'; import type { Meta, StoryObj } from '@storybook/vue'; import StarIcon from '@adyen/ui-assets-icons-16/vue/star'; import StarFilledIcon from '@adyen/ui-assets-icons-16/vue/star-filled'; import SearchIcon from '@adyen/ui-assets-icons-16/vue/search'; import NavHomeIcon from '@adyen/ui-assets-icons-16/vue/nav-home'; import NavPaymentsIcon from '@adyen/ui-assets-icons-16/vue/nav-payments'; import NavReportsIcon from '@adyen/ui-assets-icons-16/vue/nav-reports'; import NavSettingsIcon from '@adyen/ui-assets-icons-16/vue/nav-settings'; import NavAccountHoldersIcon from '@adyen/ui-assets-icons-16/vue/nav-account-holders'; import { isVue2 } from 'vue-demi'; import NavigationMenuEverythingBagelExample from './__tests__/navigation-menu-everything-bagel-example.vue?raw'; import NavigationMenuSimpleListExample from './__tests__/navigation-menu-simple-list-example.vue?raw'; export default { title: 'Navigation Menu', component: BentoNavigationMenu, argTypes: { default: { control: false, table: { type: { summary: 'Navigation items and groups' }, }, }, headerActions: { control: false, table: { type: { summary: 'Action buttons' }, }, }, }, } as Meta; type Story = StoryObj<typeof BentoNavigationMenu>; export const EverythingBagel: Story = { render: (_args, { argTypes }) => ({ components: { BentoNavigationMenu, BentoNavigationMenuItem, BentoNavigationMenuGroup, BentoButton, BentoLink, StarIcon, StarFilledIcon, SearchIcon, NavHomeIcon, NavPaymentsIcon, NavReportsIcon, NavSettingsIcon, NavAccountHoldersIcon, }, props: Object.keys(argTypes), setup(props) { const activePage = ref('home'); const paymentsExpanded = ref(true); const favorites = ref({}); const toggleFavorite = (value: string) => { favorites.value = { ...favorites.value, [value]: !favorites.value[value] }; }; return { activePage, paymentsExpanded, favorites, toggleFavorite, args: isVue2 ? props : _args, }; }, template: ` <div style="width: 248px;"> <bento-navigation-menu v-bind="args" :active-page="activePage" @update:active-page="activePage = $event"> <template #headerActions> <bento-button variant="tertiary-with-background"> <template #iconLeft> <search-icon /> </template> </bento-button> </template> <bento-navigation-menu-item value="home" label="Home" :link="{ to: '#home', isNotRouting: true }" > <template #icon> <nav-home-icon /> </template> </bento-navigation-menu-item> <bento-navigation-menu-group label="Payments" :is-expanded="paymentsExpanded" @update:is-expanded="paymentsExpanded = $event" > <template #icon> <nav-payments-icon /> </template> <bento-navigation-menu-item nested value="payments" label="Payments" :link="{ to: '#payments', isNotRouting: true }" :always-show-actions="!!favorites.payments || activePage === 'payments'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('payments')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.payments" /> <star-icon v-else /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item nested value="preauth" label="Pre-authorized" :link="{ to: '#preauth', isNotRouting: true }" :always-show-actions="!!favorites.preauth || activePage === 'preauth'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('preauth')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.preauth" /> <star-icon v-else /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item nested value="links" label="Payment links" :link="{ to: '#links', isNotRouting: true }" :always-show-actions="!!favorites.links || activePage === 'links'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('links')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.links" /> <star-icon v-else /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item nested value="methods" label="Payment methods" :link="{ to: '#methods', isNotRouting: true }" :always-show-actions="!!favorites.methods || activePage === 'methods'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('methods')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.methods" /> <star-icon v-else /> </template> </bento-button> </template> </bento-navigation-menu-item> </bento-navigation-menu-group> <bento-navigation-menu-group label="Reports" > <template #icon> <nav-reports-icon /> </template> <bento-navigation-menu-item nested value="analytics" label="Analytics" :link="{ to: '#analytics', isNotRouting: true }" :always-show-actions="!!favorites.analytics || activePage === 'analytics'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('analytics')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.analytics" /> <star-icon v-else /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-navigation-menu-item nested value="transactions" label="Transactions" :link="{ to: '#transactions', isNotRouting: true }" :always-show-actions="!!favorites.transactions || activePage === 'transactions'" > <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('transactions')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.transactions" /> <star-icon v-else /> </template> </bento-button> </template> </bento-navigation-menu-item> </bento-navigation-menu-group> <bento-navigation-menu-item value="settings" label="Settings" :link="{ to: '#settings', isNotRouting: true }" :always-show-actions="!!favorites.settings || activePage === 'settings'" > <template #icon> <nav-settings-icon /> </template> <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('settings')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.settings" /> <star-icon v-else /> </template> </bento-button> </template> </bento-navigation-menu-item> <bento-link to="#profile" is-not-routing disable-typography> <bento-navigation-menu-item value="profile" label="Profile" :always-show-actions="!!favorites.profile || activePage === 'profile'" > <template #icon> <nav-account-holders-icon /> </template> <template #action> <bento-button variant="tertiary" @click.stop.prevent="toggleFavorite('profile')" > <template #iconLeft> <star-filled-icon style="color: var(--b-color-decorative-green);" v-if="favorites.profile" /> <star-icon v-else /> </template> </bento-button> </template> </bento-navigation-menu-item> </bento-link> </bento-navigation-menu> </div> `, }), args: { label: 'Pages', showExpandAllButton: true, }, parameters: storybookDocsParameter(NavigationMenuEverythingBagelExample), }; export const SimpleList: Story = { render: (_args, { argTypes }) => ({ components: { BentoNavigationMenu, BentoNavigationMenuItem, StarIcon, }, props: Object.keys(argTypes), setup(props) { const activePage = ref('home'); return { activePage, args: isVue2 ? props : _args }; }, template: ` <div style="width: 248px;"> <bento-navigation-menu v-bind="args" :active-page="activePage" @update:active-page="activePage = $event"> <bento-navigation-menu-item value="home" label="Home" /> <bento-navigation-menu-item value="analytics" label="Analytics" /> <bento-navigation-menu-item value="settings" label="Settings" /> <bento-navigation-menu-item value="profile" label="Profile" /> </bento-navigation-menu> </div> `, }), args: { label: 'Pages', }, parameters: storybookDocsParameter(NavigationMenuSimpleListExample), };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { type Ref } from 'vue'; export interface BentoNavigationMenuProps { /** * Label text for the navigation menu header */ label?: string; /** * Whether to show the expand/collapse all button */ showExpandAllButton?: boolean; /** * The value of the currently active navigation item */ activePage?: string; } /** * @private */ export interface BentoNavigationMenuGroupRegistration { id: string; setOpen: (open: boolean) => void; getIsOpen: () => boolean; } /** * @private */ export interface BentoNavigationMenuState { registerGroup: (groupId: string, setOpen: (open: boolean) => void, getIsOpen: () => boolean) => void; unregisterGroup: (groupId: string) => void; activePage: Ref<string | undefined>; updateActivePage: (value: string) => void; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<template> <nav class="b-navigation-menu" :aria-labelledby="label ? titleId : undefined"> <div v-if="showHeader" class="b-navigation-menu__header"> <bento-typography v-if="label" :id="titleId" el="p" variant="caption" stronger class="b-navigation-menu__title" > {{ label }} </bento-typography> <div class="b-navigation-menu__actions-container"> <div v-if="hasSlot('headerActions')" class="b-navigation-menu__actions"> <slot name="headerActions" /> </div> <bento-button v-if="computedShowExpandAll" v-bento-tooltip-directive="expandButtonLabel" variant="tertiary-with-background" :aria-label="expandButtonLabel" @click="toggleAllGroups" > <template #iconLeft> <menu-collapse-icon v-if="allExpanded" /> <menu-expand-icon v-else /> </template> </bento-button> </div> </div> <ul class="b-navigation-menu__content"> <slot /> </ul> </nav> </template> <script setup lang="ts"> import { computed, provide, ref, toRef, useSlots } from 'vue'; import { BentoTypography } from '@/components/typography'; import { BentoButton } from '@/components/button'; import MenuCollapseIcon from '@adyen/ui-assets-icons-16/vue/menu-collapse'; import MenuExpandIcon from '@adyen/ui-assets-icons-16/vue/menu-expand'; import { useHasSlot } from '@/composables'; import { BentoTooltipDirective as vBentoTooltipDirective } from '@/directives/tooltip'; import { generateUid } from '@/core/utils/ts'; import { useI18n } from '@/utils/ts/i18n'; import type { BentoNavigationMenuGroupRegistration, BentoNavigationMenuProps, BentoNavigationMenuState, } from './navigation-menu.types'; import { NAVIGATION_MENU_STATE_INJECTION_KEY } from './navigation-menu.keys'; import messages from './messages.json'; type MessageSchema = (typeof messages)['en-US']; const props = withDefaults(defineProps<BentoNavigationMenuProps>(), { label: undefined, showExpandAllButton: false, activePage: undefined, }); const emit = defineEmits<{ /** * Emits update event when active page is changed */ (e: 'update:active-page', value: string): void; }>(); const slots = useSlots(); const hasSlot = useHasSlot(slots); const titleId = generateUid('navigation-menu-title'); const { t } = useI18n<{ message: MessageSchema }>({ messages }); const groups = ref<Array<BentoNavigationMenuGroupRegistration>>([]); const registerGroup = (groupId: string, setOpen: (open: boolean) => void, getIsOpen: () => boolean) => { groups.value.push({ id: groupId, setOpen, getIsOpen }); }; const unregisterGroup = (groupId: string) => { groups.value = groups.value.filter(g => g.id !== groupId); }; const allExpanded = computed(() => groups.value.length > 0 && groups.value.every(group => group.getIsOpen())); const computedShowExpandAll = computed(() => groups.value.length > 0 && props.showExpandAllButton); const showHeader = computed(() => props.label || hasSlot('headerActions') || computedShowExpandAll.value); const expandButtonLabel = computed(() => (allExpanded.value ? t('hideAllPages') : t('showAllPages'))); const toggleAllGroups = () => { const shouldExpand = !allExpanded.value; groups.value.forEach(({ setOpen }) => setOpen(shouldExpand)); }; const updateActivePage = (value: string) => { emit('update:active-page', value); }; provide<BentoNavigationMenuState>(NAVIGATION_MENU_STATE_INJECTION_KEY, { registerGroup, unregisterGroup, activePage: toRef(props, 'activePage'), updateActivePage, }); </script> <script lang="ts"> /** * Navigation menu container component with optional header and action buttons. * * @usage * import { BentoNavigationMenu, BentoNavigationMenuItem, BentoNavigationMenuGroup } from '@adyen/bento-vue2'; * * export default { * components: { BentoNavigationMenu, BentoNavigationMenuItem, BentoNavigationMenuGroup }, * template: ` * <bento-navigation-menu label="Pages" active-page="home"> * <template #headerActions> * <button>Search</button> * </template> * <bento-navigation-menu-item value="home" label="Home"> * <template #icon><home-icon /></template> * </bento-navigation-menu-item> * <bento-navigation-menu-group label="Settings"> * <template #icon><folder-icon /></template> * <bento-navigation-menu-item nested value="general" label="General" /> * </bento-navigation-menu-group> * </bento-navigation-menu> * ` * } */ export default { i18n: { messages }, }; </script> <style lang="scss" scoped src="./navigation-menu.scss" />
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"date-range-picker",
|
|
31
31
|
"divider",
|
|
32
32
|
"draggable-handle",
|
|
33
|
+
"drawer",
|
|
33
34
|
"dropdown",
|
|
34
35
|
"dropdown-avatar",
|
|
35
36
|
"dropdown-country",
|
|
@@ -64,6 +65,9 @@
|
|
|
64
65
|
"modal-fullscreen",
|
|
65
66
|
"modal-fullscreen-page",
|
|
66
67
|
"modal-page",
|
|
68
|
+
"navigation-menu",
|
|
69
|
+
"navigation-menu-group",
|
|
70
|
+
"navigation-menu-item",
|
|
67
71
|
"pagination",
|
|
68
72
|
"payment-method",
|
|
69
73
|
"popover",
|
package/dist/assets/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import BentoVue from './install'; export * from './components/accordion'; export * from './components/action-bar'; export * from './components/ai-tag'; export * from './components/alert'; export * from './components/anchor-scroller'; export * from './components/avatar'; export * from './components/button'; export * from './components/dashed-underline'; export * from './components/data-grid'; export * from './components/card'; export * from './components/date-picker'; export * from './components/date-range-picker'; // TODO: Re-introduce when `bento-draggable` is ready export * from './components/draggable/components/draggable-handle'; export * from './components/dropdown'; export * from './components/checkbox'; export * from './components/chip'; export * from './components/click-outside'; export * from './components/code-snippet'; export * from './components/country'; export * from './components/currency'; export * from './components/date'; export * from './components/divider'; export * from './components/empty-state'; export * from './components/file-uploader'; export * from './components/filter-bar'; export * from './components/form-layout'; export * from './components/header-with-views'; export * from './components/image'; export * from './components/info-icon'; export * from './components/input-field'; export * from './components/input-field-password'; export * from './components/input-field-phone-number'; export * from './components/input-time'; export * from './components/inspector'; export * from './components/layout'; export * from './components/list'; export * from './components/loading-indicator'; export * from './components/link'; export * from './components/menu'; export * from './components/modal'; export * from './components/modal-fullscreen'; export * from './components/header'; export * from './components/pagination'; export * from './components/payment-method'; export * from './components/popover'; export * from './components/promo-banner'; export * from './components/radio-group'; export * from './components/rich-text-editor'; export * from './components/search-bar'; export * from './components/secondary-nav'; export * from './components/selection-card'; export * from './components/segmented-control'; export * from './components/sidepanel'; export * from './components/status'; export * from './components/stepper'; export * from './components/structured-list'; export * from './components/summary-grid'; export * from './components/tabs'; export * from './components/tag'; export * from './components/textarea'; export * from './components/timeline'; export * from './components/toast'; export * from './components/toggle'; export * from './components/tutorial'; export * from './components/typography'; // Export Composables export * from './composables/use-bento-base-filter'; export * from './composables/use-bento-currency'; export * from './composables/use-bento-theme'; export * from './composables/use-bento-toast-controller'; export * from './composables/use-click-outside'; export * from './composables/use-form-validate'; // Export Templates export * from './templates/dashboard-template'; export * from './templates/data-grid-template'; // Export Types export * from './types'; // Export Directives export * from './directives'; // AdlVue Plugin export default BentoVue; export { BentoTheme } from './install';
|
|
1
|
+
import BentoVue from './install'; export * from './components/accordion'; export * from './components/action-bar'; export * from './components/ai-tag'; export * from './components/alert'; export * from './components/anchor-scroller'; export * from './components/avatar'; export * from './components/button'; export * from './components/dashed-underline'; export * from './components/data-grid'; export * from './components/card'; export * from './components/date-picker'; export * from './components/date-range-picker'; // TODO: Re-introduce when `bento-draggable` is ready export * from './components/draggable/components/draggable-handle'; export * from './components/drawer'; export * from './components/dropdown'; export * from './components/checkbox'; export * from './components/chip'; export * from './components/click-outside'; export * from './components/code-snippet'; export * from './components/country'; export * from './components/currency'; export * from './components/date'; export * from './components/divider'; export * from './components/empty-state'; export * from './components/file-uploader'; export * from './components/filter-bar'; export * from './components/form-layout'; export * from './components/header-with-views'; export * from './components/image'; export * from './components/info-icon'; export * from './components/input-field'; export * from './components/input-field-password'; export * from './components/input-field-phone-number'; export * from './components/input-time'; export * from './components/inspector'; export * from './components/layout'; export * from './components/list'; export * from './components/loading-indicator'; export * from './components/link'; export * from './components/menu'; export * from './components/modal'; export * from './components/modal-fullscreen'; export * from './components/navigation-menu'; export * from './components/header'; export * from './components/pagination'; export * from './components/payment-method'; export * from './components/popover'; export * from './components/promo-banner'; export * from './components/radio-group'; export * from './components/rich-text-editor'; export * from './components/search-bar'; export * from './components/secondary-nav'; export * from './components/selection-card'; export * from './components/segmented-control'; export * from './components/sidepanel'; export * from './components/status'; export * from './components/stepper'; export * from './components/structured-list'; export * from './components/summary-grid'; export * from './components/tabs'; export * from './components/tag'; export * from './components/textarea'; export * from './components/timeline'; export * from './components/toast'; export * from './components/toggle'; export * from './components/tutorial'; export * from './components/typography'; // Export Composables export * from './composables/use-bento-base-filter'; export * from './composables/use-bento-currency'; export * from './composables/use-bento-theme'; export * from './composables/use-bento-toast-controller'; export * from './composables/use-click-outside'; export * from './composables/use-form-validate'; // Export Templates export * from './templates/dashboard-template'; export * from './templates/data-grid-template'; // Export Types export * from './types'; // Export Directives export * from './directives'; // AdlVue Plugin export default BentoVue; export { BentoTheme } from './install';
|