/
CommonPopoverMenu.vue
100 lines (86 loc) · 3.15 KB
/
CommonPopoverMenu.vue
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
<!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
<script setup lang="ts">
import { computed, toRefs, useSlots } from 'vue'
import type { ObjectLike } from '#shared/types/utils.ts'
import { usePopoverMenu } from '#desktop/components/CommonPopover/usePopoverMenu.ts'
import type { CommonPopoverInstance, MenuItem, Variant } from './types'
import CommonPopoverMenuItem from './CommonPopoverMenuItem.vue'
export interface Props {
popover: CommonPopoverInstance | undefined
headerLabel?: string
items?: MenuItem[]
entity?: ObjectLike
}
const props = defineProps<Props>()
const { items, entity } = toRefs(props)
const { filteredMenuItems } = usePopoverMenu(items, entity)
const slots = useSlots()
const showHeaderLabel = computed(() => {
if (!filteredMenuItems.value && !slots.default) return false
return slots.header || props.headerLabel
})
const onClickItem = (event: MouseEvent, item: MenuItem) => {
if (item.onClick) {
item.onClick(props.entity)
}
if (!item.noCloseOnClick) {
props.popover?.closePopover()
}
}
const getHoverFocusStyles = (variant?: Variant) => {
if (variant === 'danger') {
return 'focus-within:bg-red-50 hover:bg-red-50 hover:focus-within:bg-red-50 dark:focus-within:bg-red-900 dark:hover:bg-red-900 dark:hover:focus-within:bg-red-900'
}
return 'focus-within:bg-blue-800 focus-within:text-white hover:bg-blue-600 hover:focus-within:bg-blue-800 dark:hover:bg-blue-900 dark:hover:focus-within:bg-blue-800'
}
</script>
<template>
<section class="min-w-58 flex flex-col gap-0.5">
<div
v-if="showHeaderLabel"
role="heading"
aria-level="2"
class="p-2 leading-3"
>
<slot name="header">
<CommonLabel size="small" class="text-stone-200 dark:text-neutral-500"
>{{ i18n.t(headerLabel) }}
</CommonLabel>
</slot>
</div>
<template v-if="filteredMenuItems || $slots.default">
<slot>
<ul role="menu" v-bind="$attrs" class="flex w-full flex-col">
<template v-for="item in filteredMenuItems" :key="item.key">
<li
role="menuitem"
class="group flex items-center justify-between last:rounded-b-[10px]"
:class="[
{
'first:rounded-t-[10px]': !showHeaderLabel,
'border-t border-neutral-100 dark:border-gray-900':
item.separatorTop,
},
getHoverFocusStyles(item.variant),
]"
>
<slot :name="`item-${item.key}`" v-bind="item">
<component
:is="item.component || CommonPopoverMenuItem"
class="flex grow p-2.5"
:label="item.label"
:variant="item.variant"
:link="item.link"
:icon="item.icon"
:label-placeholder="item.labelPlaceholder"
@click="onClickItem($event, item)"
/>
<slot :name="`itemRight-${item.key}`" v-bind="item" />
</slot>
</li>
</template>
</ul>
</slot>
</template>
</section>
</template>