Skip to content

Commit

Permalink
fix(VOverlay): close on scrim click in Shadow DOM without activator (#…
Browse files Browse the repository at this point in the history
…20291)

Co-authored-by: Kael <kaelwd@gmail.com>
  • Loading branch information
cgodo and KaelWD authored Aug 13, 2024
1 parent d25879a commit 2c36fff
Show file tree
Hide file tree
Showing 3 changed files with 8 additions and 3 deletions.
6 changes: 4 additions & 2 deletions packages/vuetify/src/components/VOverlay/VOverlay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import {
animate,
convertToUnit,
genericComponent,
getCurrentInstance,
getScrollParent,
IN_BROWSER,
propsFactory,
Expand Down Expand Up @@ -133,6 +134,7 @@ export const VOverlay = genericComponent<OverlaySlots>()({
},

setup (props, { slots, attrs, emit }) {
const vm = getCurrentInstance('VOverlay')
const model = useProxiedModel(props, 'modelValue')
const isActive = computed({
get: () => model.value,
Expand All @@ -157,7 +159,7 @@ export const VOverlay = genericComponent<OverlaySlots>()({
const { teleportTarget } = useTeleport(() => {
const target = props.attach || props.contained
if (target) return target
const rootNode = activatorEl?.value?.getRootNode()
const rootNode = activatorEl?.value?.getRootNode() || vm.proxy?.$el?.getRootNode()
if (rootNode instanceof ShadowRoot) return rootNode
return false
})
Expand Down Expand Up @@ -196,7 +198,7 @@ export const VOverlay = genericComponent<OverlaySlots>()({
function closeConditional (e: Event) {
return isActive.value && globalTop.value && (
// If using scrim, only close if clicking on it rather than anything opened on top
!props.scrim || e.target === scrimEl.value
!props.scrim || e.target === scrimEl.value || (e instanceof MouseEvent && e.shadowTarget === scrimEl.value)
)
}

Expand Down
4 changes: 3 additions & 1 deletion packages/vuetify/src/directives/click-outside/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ function checkIsActive (e: MouseEvent, binding: ClickOutsideDirectiveBinding): b
function directive (e: MouseEvent, el: HTMLElement, binding: ClickOutsideDirectiveBinding) {
const handler = typeof binding.value === 'function' ? binding.value : binding.value.handler

// Clicks in the Shadow DOM change their target while using setTimeout, so the original target is saved here
e.shadowTarget = e.target

el._clickOutside!.lastMousedownWasOutside && checkEvent(e, el, binding) && setTimeout(() => {
checkIsActive(e, binding) && handler && handler(e)
}, 0)
Expand Down Expand Up @@ -89,7 +92,6 @@ export const ClickOutside = {
app.addEventListener('click', onClick, true)
app.addEventListener('mousedown', onMousedown, true)
})

if (!el._clickOutside) {
el._clickOutside = {
lastMousedownWasOutside: false,
Expand Down
1 change: 1 addition & 0 deletions packages/vuetify/src/globals.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ declare global {

interface MouseEvent {
sourceCapabilities?: { firesTouchEvents: boolean }
shadowTarget?: EventTarget | null
}

interface ColorSelectionOptions {
Expand Down

0 comments on commit 2c36fff

Please sign in to comment.