fix(assets): dismiss context menu on scroll and outside click (#8952)

This commit is contained in:
Jin Yi
2026-02-21 13:19:13 +09:00
committed by GitHub
parent 5fe902358c
commit c05644045f
2 changed files with 43 additions and 16 deletions

View File

@@ -199,7 +199,8 @@ import {
useDebounceFn,
useElementHover,
useResizeObserver,
useStorage
useStorage,
useTimeoutFn
} from '@vueuse/core'
import Divider from 'primevue/divider'
import { useToast } from 'primevue/usetoast'
@@ -483,7 +484,16 @@ function handleAssetSelect(asset: AssetItem, assets?: AssetItem[]) {
handleAssetClick(asset, index, assetList)
}
const { start: scheduleCleanup, stop: cancelCleanup } = useTimeoutFn(
() => {
contextMenuAsset.value = null
},
0,
{ immediate: false }
)
function handleAssetContextMenu(event: MouseEvent, asset: AssetItem) {
cancelCleanup()
contextMenuAsset.value = asset
void nextTick(() => {
contextMenuRef.value?.show(event)
@@ -491,10 +501,7 @@ function handleAssetContextMenu(event: MouseEvent, asset: AssetItem) {
}
function handleContextMenuHide() {
// Delay clearing to allow command callbacks to emit before component unmounts
requestAnimationFrame(() => {
contextMenuAsset.value = null
})
scheduleCleanup()
}
const handleBulkDownload = (assets: AssetItem[]) => {

View File

@@ -11,7 +11,7 @@
)
}
}"
@hide="emit('hide')"
@hide="onMenuHide"
>
<template #item="{ item, props }">
<Button
@@ -29,7 +29,7 @@
</template>
<script setup lang="ts">
import { onClickOutside } from '@vueuse/core'
import { useEventListener } from '@vueuse/core'
import ContextMenu from 'primevue/contextmenu'
import type { MenuItem } from 'primevue/menuitem'
import type { ComponentPublicInstance } from 'vue'
@@ -76,19 +76,32 @@ const emit = defineEmits<{
type ContextMenuInstance = ComponentPublicInstance & {
show: (event: MouseEvent) => void
hide: () => void
container?: HTMLElement
$el?: HTMLElement
}
const contextMenu = ref<ContextMenuInstance | null>(null)
const isVisible = ref(false)
const actions = useMediaAssetActions()
const { t } = useI18n()
// Close context menu when clicking outside
onClickOutside(
computed(() => contextMenu.value?.$el),
() => {
hide()
}
)
function getOverlayEl(): HTMLElement | null {
return contextMenu.value?.container ?? contextMenu.value?.$el ?? null
}
function dismissIfOutside(event: Event) {
if (!isVisible.value) return
const overlay = getOverlayEl()
if (!overlay) return
if (overlay.contains(event.target as Node)) return
hide()
}
useEventListener(window, 'pointerdown', dismissIfOutside, { capture: true })
useEventListener(window, 'scroll', dismissIfOutside, {
capture: true,
passive: true
})
const showAddToWorkflow = computed(() => {
// Output assets can always be added
@@ -265,11 +278,18 @@ const contextMenuItems = computed<MenuItem[]>(() => {
return items
})
const show = (event: MouseEvent) => {
function onMenuHide() {
isVisible.value = false
emit('hide')
}
function show(event: MouseEvent) {
isVisible.value = true
contextMenu.value?.show(event)
}
const hide = () => {
function hide() {
isVisible.value = false
contextMenu.value?.hide()
}