diff --git a/packages/vuetify/src/components/VMenu/VMenu.tsx b/packages/vuetify/src/components/VMenu/VMenu.tsx index edfcf781375..08bebfa5458 100644 --- a/packages/vuetify/src/components/VMenu/VMenu.tsx +++ b/packages/vuetify/src/components/VMenu/VMenu.tsx @@ -15,7 +15,17 @@ import { useScopeId } from '@/composables/scopeId' // Utilities import { computed, inject, mergeProps, nextTick, provide, ref, shallowRef, watch } from 'vue' import { VMenuSymbol } from './shared' -import { focusableChildren, focusChild, genericComponent, getNextElement, getUid, omit, propsFactory, useRender } from '@/util' +import { + focusableChildren, + focusChild, + genericComponent, + getNextElement, + getUid, + isClickInsideElement, + omit, + propsFactory, + useRender, +} from '@/util' // Types import type { Component } from 'vue' @@ -64,9 +74,11 @@ export const VMenu = genericComponent()({ unregister () { --openChildren.value }, - closeParents () { + closeParents (e) { setTimeout(() => { - if (!openChildren.value) { + if (!openChildren.value && + (e == null || (e && !isClickInsideElement(e, overlay.value!.contentEl!))) + ) { isActive.value = false parent?.closeParents() } @@ -106,8 +118,8 @@ export const VMenu = genericComponent()({ } }) - function onClickOutside () { - parent?.closeParents() + function onClickOutside (e: MouseEvent) { + parent?.closeParents(e) } function onKeydown (e: KeyboardEvent) { diff --git a/packages/vuetify/src/components/VMenu/shared.ts b/packages/vuetify/src/components/VMenu/shared.ts index 08f15dd12b6..c23b2769808 100644 --- a/packages/vuetify/src/components/VMenu/shared.ts +++ b/packages/vuetify/src/components/VMenu/shared.ts @@ -4,7 +4,7 @@ import type { InjectionKey } from 'vue' interface MenuProvide { register (): void unregister (): void - closeParents (): void + closeParents (e?: MouseEvent): void } export const VMenuSymbol: InjectionKey = Symbol.for('vuetify:v-menu') diff --git a/packages/vuetify/src/util/helpers.ts b/packages/vuetify/src/util/helpers.ts index cd80daec6e6..a374b2ab722 100644 --- a/packages/vuetify/src/util/helpers.ts +++ b/packages/vuetify/src/util/helpers.ts @@ -721,4 +721,15 @@ export function eagerComputed (fn: () => T, options?: WatchOptions): Readonly }) return readonly(result) +export function isClickInsideElement (event: MouseEvent, targetDiv: HTMLElement) { + const mouseX = event.clientX + const mouseY = event.clientY + + const divRect = targetDiv.getBoundingClientRect() + const divLeft = divRect.left + const divTop = divRect.top + const divRight = divRect.right + const divBottom = divRect.bottom + + return mouseX >= divLeft && mouseX <= divRight && mouseY >= divTop && mouseY <= divBottom }