123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- <!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->
- <script setup lang="ts">
- import { computed, toRefs } from 'vue'
- import type { Sizes } from '#shared/components/CommonIcon/types.ts'
- import CommonPopover from '#shared/components/CommonPopover/CommonPopover.vue'
- import type {
- Orientation,
- Placement,
- } from '#shared/components/CommonPopover/types.ts'
- import { usePopover } from '#shared/components/CommonPopover/usePopover.ts'
- import type { ObjectLike } from '#shared/types/utils.ts'
- import getUuid from '#shared/utils/getUuid.ts'
- import CommonButton from '#desktop/components/CommonButton/CommonButton.vue'
- import type {
- ButtonSize,
- ButtonVariant,
- } from '#desktop/components/CommonButton/types.ts'
- import CommonPopoverMenu from '#desktop/components/CommonPopoverMenu/CommonPopoverMenu.vue'
- import type { MenuItem } from '#desktop/components/CommonPopoverMenu/types.ts'
- import { usePopoverMenu } from '#desktop/components/CommonPopoverMenu/usePopoverMenu.ts'
- export interface Props {
- actions: MenuItem[]
- entity?: ObjectLike
- buttonSize?: ButtonSize
- linkSize?: Sizes
- placement?: Placement
- orientation?: Orientation
- hideArrow?: boolean
- disabled?: boolean
- noSingleActionMode?: boolean
- customMenuButtonLabel?: string
- defaultIcon?: string
- defaultButtonVariant?: ButtonVariant | 'neutral-light' | 'neutral-dark'
- noPaddedDefaultButton?: boolean
- noSmallRoundingDefaultButton?: boolean
- }
- const props = withDefaults(defineProps<Props>(), {
- buttonSize: 'medium',
- placement: 'arrowStart',
- orientation: 'autoVertical',
- defaultButtonVariant: 'neutral',
- defaultIcon: 'three-dots-vertical',
- noPaddedDefaultButton: true,
- })
- const { popover, isOpen: popoverIsOpen, popoverTarget, toggle } = usePopover()
- const { actions, entity } = toRefs(props)
- const { filteredMenuItems, singleMenuItemPresent, singleMenuItem } =
- usePopoverMenu(actions, entity, { provides: true })
- const entityId = computed(() => props.entity?.id || getUuid())
- const menuId = computed(() => `popover-${entityId.value}`)
- const singleActionAriaLabel = computed(() => {
- if (typeof singleMenuItem.value?.ariaLabel === 'function') {
- return singleMenuItem.value.ariaLabel(props.entity)
- }
- return singleMenuItem.value?.ariaLabel || singleMenuItem.value?.label
- })
- const buttonVariantClassExtension = computed(() => {
- if (props.defaultButtonVariant === 'neutral-dark')
- return 'border border-neutral-100 !outline-transparent dark:hover:border-blue-700 hover:border-blue-800 bg-neutral-50 hover:bg-white text-gray-100 dark:border-gray-900 dark:bg-gray-500 dark:text-neutral-400'
- if (props.defaultButtonVariant === 'neutral-light')
- return 'border border-neutral-100 !outline-transparent dark:hover:border-blue-700 hover:border-blue-800 hover:bg-white bg-blue-100 text-gray-100 dark:border-gray-900 dark:bg-stone-500 dark:text-neutral-400'
- return ''
- })
- const singleActionMode = computed(() => {
- if (props.noSingleActionMode) return false
- return singleMenuItemPresent.value
- })
- const variantClasses = computed(() => {
- if (singleMenuItem.value?.variant === 'secondary') return 'text-blue-800'
- if (singleMenuItem.value?.variant === 'danger') return 'text-red-500'
- return 'text-stone-200 dark:text-neutral-500'
- })
- </script>
- <template>
- <div
- v-if="filteredMenuItems && filteredMenuItems.length > 0"
- class="-:inline-block"
- >
- <template v-if="singleActionMode">
- <CommonLink
- v-if="singleMenuItem?.link"
- v-tooltip="$t(singleActionAriaLabel)"
- class="flex focus:outline-none focus-visible:outline-1 focus-visible:outline-offset-1 focus-visible:outline-blue-800"
- :aria-label="$t(singleActionAriaLabel)"
- :disabled="disabled"
- :link="singleMenuItem.link"
- >
- <CommonIcon
- v-if="singleMenuItem?.icon"
- :size="linkSize"
- :class="variantClasses"
- :name="singleMenuItem?.icon"
- />
- </CommonLink>
- <CommonButton
- v-else
- v-tooltip="$t(singleActionAriaLabel)"
- class="rounded-sm p-0"
- :class="[variantClasses]"
- :size="buttonSize"
- :disabled="disabled"
- :aria-label="$t(singleActionAriaLabel)"
- :icon="singleMenuItem?.icon"
- @click="singleMenuItem?.onClick?.(props.entity as ObjectLike)"
- />
- </template>
- <template v-else>
- <CommonButton
- :id="`action-menu-${entityId}`"
- ref="popoverTarget"
- :aria-label="$t(customMenuButtonLabel || 'Action menu button')"
- aria-haspopup="true"
- :aria-controls="popoverIsOpen ? menuId : undefined"
- :disabled="disabled"
- :class="[
- {
- 'outline outline-1 outline-offset-1 outline-blue-800 hover:outline-blue-800 hover:dark:outline-blue-800':
- popoverIsOpen,
- 'p-0': noPaddedDefaultButton,
- 'rounded-sm': !noSmallRoundingDefaultButton,
- },
- buttonVariantClassExtension,
- ]"
- :variant="defaultButtonVariant as ButtonVariant"
- :size="buttonSize"
- :icon="defaultIcon"
- @click="toggle"
- />
- <CommonPopover
- :id="menuId"
- ref="popover"
- :placement="placement"
- :hide-arrow="hideArrow"
- :orientation="orientation"
- :owner="popoverTarget"
- >
- <CommonPopoverMenu :entity="entity" :popover="popover" />
- </CommonPopover>
- </template>
- </div>
- </template>
|