Skip to content

Commit 5d68252

Browse files
pogrib0km0ksemasvae
authored
Feat#1417/add new menu component (#3637)
Co-authored-by: Maksim Nedoshev <[email protected]> Co-authored-by: Yauheni Prakopchyk <[email protected]>
1 parent a5439fa commit 5d68252

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1354
-39
lines changed

packages/docs/modules/page-config/blocks/api/common-description.ts

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ export default
1515
eventArgument: "The event argument is:"
1616
},
1717
props: {
18+
ariaLabel: "Sets the `aria-label` attribute.",
19+
ariaLabeledby: "Sets the `aria-labelledby` attribute.",
20+
role: "Sets the `role` attribute.",
1821
align: "Customizes horizontal position of component (flex based). Available values are strings: 'left', 'center', 'right', 'between', 'around', 'stretch'.",
1922
id: "Applies `id` to internal input component. Useful for native forms.",
2023
name: "Applies `name` to internal input component. Useful for native forms.",

packages/docs/modules/page-config/blocks/api/index.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import { definePageConfigBlock } from '../../types'
33
import Component from './index.vue'
44
import { VisualOptions, type ManualApiOptions, APIDescriptionOptions } from './types';
55
import { parseComponent } from './component-parser'
6+
import type * as components from 'vuestic-ui/src/services/vue-plugin/components'
7+
import { ExtractComponentProps } from 'vuestic-ui/src/utils/component-options';
8+
import { VuesticComponent } from 'vuestic-ui/src/services/component-config';
69

710
const setup = (
811
componentName: string,
@@ -27,7 +30,20 @@ const setup = (
2730
}
2831

2932
export default definePageConfigBlock({
30-
setup: setup as unknown as (componentName: string, descriptionOptions: APIDescriptionOptions, manual?: ManualApiOptions, visualOptions?: VisualOptions) => ReturnType<typeof setup>,
33+
setup: setup as unknown as <
34+
ComponentName extends keyof typeof components,
35+
Component extends typeof components[ComponentName] = typeof components[ComponentName]
36+
>(
37+
componentName: ComponentName,
38+
descriptionOptions: {
39+
props?: Partial<Record<keyof ExtractComponentProps<Component>, string>>,
40+
events?: Partial<Record<keyof Component['emits'], string>>,
41+
slots?: Record<string, string>,
42+
methods?: Partial<Record<keyof Component['methods'], string>>,
43+
},
44+
manual?: ManualApiOptions,
45+
visualOptions?: VisualOptions
46+
) => ReturnType<typeof setup>,
3147
component: Component,
3248
})
3349

packages/docs/modules/page-config/runtime/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,4 @@ export type UnwrapPageConfigBlock<T extends Record<string, any>> = {
8080
_blockComponent: DefineComponent,
8181
} & T
8282

83-
export const defineApiDescription = (options: APIDescriptionOptions) => options;
83+
export const defineApiDescription = <T extends APIDescriptionOptions>(options: T) => options;

packages/docs/page-config/navigationRoutes.ts

+14-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { navigationBadge } from './../utils/navigation/badge';
21
import { navigationBadge, type NavigationBadge } from "../utils/navigation/badge";
32

43
export type NavigationRoute = {
@@ -389,6 +388,20 @@ export const navigationRoutes: NavigationRoute[] = [
389388
badge : navigationBadge.updated('1.8.3'),
390389
}
391390
},
391+
{
392+
name: 'menu',
393+
displayName: 'Menu',
394+
meta: {
395+
badge : navigationBadge.new('1.8.4'),
396+
}
397+
},
398+
{
399+
name: 'menu-list',
400+
displayName: 'Menu List',
401+
meta: {
402+
badge : navigationBadge.new('1.8.4'),
403+
}
404+
},
392405
{
393406
category: "Utility",
394407
name: "value",

packages/docs/page-config/ui-elements/dropdown/api-description.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { defineApiDescription } from "~/modules/page-config/runtime";
22

33
export default defineApiDescription({
44
props: {
5+
anchor: "Anchor element. Dropdown will be opened when clicked on anchor. Can be `HTMLElement` or `CSS selector`",
6+
closeOnAnchorClick: "Dropdown will be closed when clicked on anchor",
57
closeOnContentClick: "Dropdown will be closed when clicked inside dropdown content",
8+
closeOnFocusOutside: "Dropdown will be closed when focus is outside dropdown content and anchor",
69
hoverOutTimeout: "Time in `ms` after mouse leave dropdown before it will be closed",
710
hoverOverTimeout: "Time in `ms` after mouse enter dropdown before it will be opened",
811
verticalScrollOnOverflow: "If true, dropdown content will adjust its height when the content is larger than available space",
@@ -11,14 +14,17 @@ export default defineApiDescription({
1114
placement: "Dropdown content will be placed on `placement` side of anchor",
1215
trigger: "Action that will triggered when open and close dropdown.",
1316
target: "Dropdown content parent. Dropdown content will be attached to `target` to prevent overflow",
14-
closeOnAnchorClick:"Dropdown will be closed when anchor is clicked",
15-
ariaLabel: "The aria-label of the component",
16-
role: "The `role` attribute applied to the anchor"
17+
role: "The role attribute of the dropdown",
1718
},
1819
events: {
1920
anchorClick: "The event is triggered when anchor is clicked",
20-
clickOutside: "The event is triggered when clicked outside dropdown content and anchor",
21-
contentClick: "The event is triggered when clicked inside dropdown content"
21+
anchorDblclick: "The event is triggered when anchor is double clicked",
22+
anchorRightClick: "The event is triggered when anchor is right clicked",
23+
close: "The event is triggered when dropdown is closed",
24+
open: "The event is triggered when dropdown is opened",
25+
contentClick: "The event is triggered when clicked inside dropdown content",
26+
focusOutside: "The event is triggered when focus is outside dropdown content and anchor",
27+
clickOutside: "The event is triggered when clicked outside dropdown content and anchor"
2228
},
2329
slots: {
2430
anchor: "Slot for anchor. When anchor is clicked, dropdown will be opened",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<template>
2+
<VaMenuList
3+
:options="['Option 1', 'Option 2', 'Option 3']"
4+
@selected="(v) => alert(v)"
5+
/>
6+
</template>
7+
8+
<script setup>
9+
const alert = (...args) => window.alert(...args)
10+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<template>
2+
<VaMenuList
3+
:options="options"
4+
@selected="(v) => alert(v)"
5+
/>
6+
</template>
7+
8+
<script setup>
9+
const alert = (...args) => window.alert(...args)
10+
11+
const options = [
12+
{ id: '0', text: 'one', value: 'one', group: '' },
13+
{ id: '1', text: 'two', value: 'two', group: 'Group 1' },
14+
{ id: '2', text: 'three', value: 'three', group: '' },
15+
{ id: '3', text: 'four', value: 'four', group: 'Group 2' },
16+
{ id: '4', text: 'five', value: 'five', group: 'Group 2' },
17+
]
18+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<template>
2+
<VaMenuList
3+
:options="options"
4+
@selected="(v) => alert(v)"
5+
/>
6+
</template>
7+
8+
<script setup>
9+
const alert = (...args) => window.alert(...args)
10+
11+
const options = [
12+
{ id: '0', text: 'copy', value: 'one', icon: 'content_copy', rightIcon: '' },
13+
{ id: '1', text: 'paste', value: 'two', icon: 'content_paste', rightIcon: '' },
14+
{ id: '2', text: 'cut', value: 'three', icon: 'content_cut', rightIcon: '' },
15+
{ id: '3', text: 'share', value: 'four', icon: '', rightIcon: 'share' },
16+
{ id: '4', text: 'delete', value: 'five', icon: 'delete' },
17+
]
18+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<template>
2+
<VaMenuList>
3+
<VaMenuItem @selected="alert">
4+
Option 1
5+
</VaMenuItem>
6+
<VaMenuItem @selected="alert">
7+
Option 2
8+
</VaMenuItem>
9+
<VaMenuItem @selected="alert">
10+
Option 2
11+
</VaMenuItem>
12+
</VaMenuList>
13+
</template>
14+
15+
<script setup lang="ts">
16+
const alert = (...args) => window.alert(...args)
17+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<template>
2+
<VaMenuList>
3+
<VaMenuItem @selected="alert">
4+
Option 1
5+
</VaMenuItem>
6+
<VaMenuItem @selected="alert">
7+
Option 2
8+
</VaMenuItem>
9+
<VaDivider />
10+
<VaMenuItem @selected="alert">
11+
Option 3
12+
</VaMenuItem>
13+
<VaMenuItem @selected="alert">
14+
Option 4
15+
</VaMenuItem>
16+
<div>
17+
Custom divider
18+
</div>
19+
<VaMenuItem @selected="alert">
20+
Option 5
21+
</VaMenuItem>
22+
</VaMenuList>
23+
</template>
24+
25+
<script setup lang="ts">
26+
const alert = (...args) => window.alert(...args)
27+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
export default definePageConfig({
2+
blocks: [
3+
block.title("Menu List"),
4+
block.paragraph("The `VaMenuList` component is used to display structured information in selectable list format."),
5+
6+
7+
block.link("VaMenu", "/ui-elements/menu", { preText: "See " }),
8+
9+
block.subtitle("Examples"),
10+
11+
block.example("Default", {
12+
title: "Basic usage",
13+
description: "To show menu items you can use `options` prop:",
14+
}),
15+
block.example("MenuItem", {
16+
title: "Slot usage",
17+
description: "You can also use slot and VaMenuItem component to achieve better flexibility.",
18+
}),
19+
20+
block.example("Icon", {
21+
title: "Icon",
22+
description: "You can use `icon `and `rightIcon` properties in options or `left-icon` and `right-icon` slots in `VaMenuItem` component.",
23+
}),
24+
25+
block.example("Group", {
26+
title: "Group",
27+
description: "You can use `group` property in options or `VaMenuGroup` component.",
28+
}),
29+
30+
block.example("WithDivider", {
31+
title: "With divider",
32+
description: "You can use `VaDivider` component in pair with `VaMenuItem` components.",
33+
}),
34+
35+
block.api("VaMenuList", {
36+
props: {
37+
textBy: 'When `options` prop items are an objects, this key will be used as displayed text. Can be string (path to the key) or function of type: `(option) => option.text`',
38+
valueBy: 'When `options` prop items are an objects, this key will be used in `selected` event. Can be string (path to the key) or function of type: `(option) => option.value`',
39+
trackBy: 'When `options` prop items are an objects, this key will be used to track selected `options`. Can be string (path to the key) or function of type: `(option) => option.track`',
40+
groupBy: 'When `options` prop items are an objects, this key will be used to check correct option group',
41+
disabledBy: "Specify the key in the object to be used as item `disabled` prop. Can be string (path to the key) or function of type: `(option) => option.disabled`",
42+
options: "Available options that the user can select from",
43+
},
44+
events: {
45+
selected: 'Emitted when an option is selected. Returns the selected option value as first argument and the selected option as second argument',
46+
}
47+
}),
48+
],
49+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import { defineApiDescription } from "~/modules/page-config/runtime";
2+
3+
export default defineApiDescription({
4+
props: {
5+
anchor: "Anchor element. Dropdown will be opened when clicked on anchor. Can be `HTMLElement` or `CSS selector`",
6+
closeOnAnchorClick: "Dropdown will be closed when clicked on anchor",
7+
closeOnContentClick: "Dropdown will be closed when clicked inside dropdown content",
8+
closeOnFocusOutside: "Dropdown will be closed when focus is outside dropdown content and anchor",
9+
hoverOutTimeout: "Time in `ms` after mouse leave dropdown before it will be closed",
10+
hoverOverTimeout: "Time in `ms` after mouse enter dropdown before it will be opened",
11+
verticalScrollOnOverflow: "If true, dropdown content will adjust its height when the content is larger than available space",
12+
keepAnchorWidth: "If true, dropdown content will have exact same width as anchor",
13+
offset: "Dropdown content will be moved by main and cross axis according to current `placement`",
14+
placement: "Dropdown content will be placed on `placement` side of anchor",
15+
trigger: "Action that will triggered when open and close dropdown.",
16+
target: "Dropdown content parent. Dropdown content will be attached to `target` to prevent overflow",
17+
role: "The role attribute of the dropdown",
18+
19+
textBy: 'When `options` prop items are an objects, this key will be used as displayed text. Can be string (path to the key) or function of type: `(option) => option.text`',
20+
valueBy: 'When `options` prop items are an objects, this key will be used in `selected` event. Can be string (path to the key) or function of type: `(option) => option.value`',
21+
trackBy: 'When `options` prop items are an objects, this key will be used to track selected `options`. Can be string (path to the key) or function of type: `(option) => option.track`',
22+
groupBy: 'When `options` prop items are an objects, this key will be used to check correct option group',
23+
disabledBy: "Specify the key in the object to be used as item `disabled` prop. Can be string (path to the key) or function of type: `(option) => option.disabled`",
24+
options: "Available options that the user can select from",
25+
},
26+
events: {
27+
anchorClick: "The event is triggered when anchor is clicked",
28+
anchorDblclick: "The event is triggered when anchor is double clicked",
29+
anchorRightClick: "The event is triggered when anchor is right clicked",
30+
close: "The event is triggered when dropdown is closed",
31+
open: "The event is triggered when dropdown is opened",
32+
contentClick: "The event is triggered when clicked inside dropdown content",
33+
focusOutside: "The event is triggered when focus is outside dropdown content and anchor",
34+
clickOutside: "The event is triggered when clicked outside dropdown content and anchor",
35+
selected: 'Emitted when an option is selected. Returns the selected option value as first argument and the selected option as second argument',
36+
},
37+
slots: {
38+
anchor: "Slot for anchor. When anchor is clicked, dropdown will be opened",
39+
default: "Dropdown content",
40+
}
41+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<template>
2+
<VaMenu
3+
:options="['Option 1', 'Option 2', 'Option 3']"
4+
preset="context"
5+
@selected="(v) => alert(v)"
6+
>
7+
<template #anchor>
8+
<va-image
9+
class="h-[300px] w-[300px]"
10+
src="https://picsum.photos/1500"
11+
>
12+
<va-badge text="Right click this image" />
13+
</va-image>
14+
</template>
15+
</VaMenu>
16+
</template>
17+
18+
<script setup>
19+
const alert = (...args) => window.alert(...args)
20+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<template>
2+
<VaMenu
3+
:options="['Option 1', 'Option 2', 'Option 3']"
4+
@selected="(v) => alert(v)"
5+
>
6+
<template #anchor>
7+
<VaButton>Open menu</VaButton>
8+
</template>
9+
</VaMenu>
10+
</template>
11+
12+
<script setup>
13+
const alert = (...args) => window.alert(...args)
14+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<template>
2+
<VaMenu
3+
:options="options"
4+
@selected="(v) => alert(v)"
5+
>
6+
<template #anchor>
7+
<VaButton>Open menu</VaButton>
8+
</template>
9+
</VaMenu>
10+
</template>
11+
12+
<script setup>
13+
const alert = (...args) => window.alert(...args)
14+
15+
const options = [
16+
{ id: '0', text: 'one', value: 'one', group: '' },
17+
{ id: '1', text: 'two', value: 'two', group: 'Group 1' },
18+
{ id: '2', text: 'three', value: 'three', group: '' },
19+
{ id: '3', text: 'four', value: 'four', group: 'Group 2' },
20+
{ id: '4', text: 'five', value: 'five', group: 'Group 2' },
21+
]
22+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<template>
2+
<VaMenu
3+
:options="options"
4+
@selected="(v) => alert(v)"
5+
>
6+
<template #anchor>
7+
<VaButton>Open menu</VaButton>
8+
</template>
9+
</VaMenu>
10+
</template>
11+
12+
<script setup>
13+
const alert = (...args) => window.alert(...args)
14+
15+
const options = [
16+
{ text: 'copy', value: 'one', icon: 'content_copy' },
17+
{ text: 'paste', value: 'two', icon: 'content_paste' },
18+
{ text: 'cut', value: 'three', icon: 'content_cut' },
19+
{ text: 'share', value: 'four', rightIcon: 'share' },
20+
{ text: 'delete', value: 'five', icon: 'delete' },
21+
]
22+
</script>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<template>
2+
<VaMenu>
3+
<template #anchor>
4+
<VaButton>Open menu</VaButton>
5+
</template>
6+
7+
<VaMenuItem @selected="alert">
8+
Option 1
9+
</VaMenuItem>
10+
<VaMenuItem @selected="alert">
11+
Option 2
12+
</VaMenuItem>
13+
<VaMenuItem @selected="alert">
14+
Option 2
15+
</VaMenuItem>
16+
</VaMenu>
17+
</template>
18+
19+
<script setup lang="ts">
20+
const alert = (...args) => window.alert(...args)
21+
</script>

0 commit comments

Comments
 (0)