Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug Report][3.5.15] v-menu be closed in second time trigger by selecting month or year when used in shadowRoot #19616

Closed
wyhsunflower opened this issue Apr 15, 2024 · 1 comment · Fixed by #20273 · May be fixed by jonathanestefani/crud_vuetify#5, WontonSam/Cachimanstarter.dev#447 or aurelienfvre/sae401#1
Labels
D: click-outside T: bug Functionality that does not work as intended/expected
Milestone

Comments

@wyhsunflower
Copy link

Environment

Vuetify Version: 3.5.15
Last working version: 3.5.15
Vue Version: 3.4.21
Browsers: Chrome 123.0.0.0
OS: Mac OS 10.15.7, Windows

Steps to reproduce

  1. Choose one date from "Second DatePicker" which is using in a shadowRoot. For example, Apr.30, it works!
    2.Let's change the Second DatePicker again, If you click the those icons to switch the month or year, the menu will be quickly closed even if using the :close-on-content-click="false" in v-menu.
Second Picker
  1. The operations of the above 1 and 2 steps can be successfully completed in the first DatePicker

Expected Behavior

v-menu won't be closed in second time popup if it using in the shadowRoot

Actual Behavior

v-menu was be closed when using in shadowRoot even through using close-on-content-click="false"

Reproduction Link

https://play.vuetifyjs.com/#...

Other comments

Hi, Vuetify team, since Front-end micro app more and more popular, this could be a common problem, so I did in-depth research about this issue, and we have a result.
The root cause is that the v-clickout directive using the wrong lifecyle, so, I want to try to fix this issue.

@cgodo
Copy link
Contributor

cgodo commented Aug 2, 2024

This issue actually affects all components that use VOverlay in the Shadow DOM, like VMenu, for example. The following Playground.vue demonstrates the issue.

Whenever a menu is opened and closed for the first time in the Shadow DOM, the next time trying to open the submenu, everything is closed immediately.

<template>
  <v-menu v-bind="$attrs" location="right">
    <template #activator="{ props }">
      <v-btn v-bind="props" class="ma-5">Normal Menu</v-btn>
    </template>
    <v-list>
      <v-menu location="right">
        <template #activator="{ props }">
          <v-list-item v-bind="props" title="Submenu" />
        </template>
        <v-list>
          <v-list-item title="Submenu item" />
          <v-list-item title="Submenu item" />
        </v-list>
      </v-menu>
    </v-list>
  </v-menu>

  <div ref="shadow" />
</template>

<script>
  import { createApp, h } from 'vue'
  import vuetify from './vuetify'
  import { VBtn, VList, VListItem, VMenu } from 'vuetify/src/components'

  export default {
    name: 'Playground',
    setup () {
      return {

      }
    },
    mounted () {
      const shadowRoot = this.$refs.shadow.attachShadow({ mode: 'open' })
      const shadowApp = document.createElement('div')
      shadowApp.id = 'shadow-app'
      shadowRoot.appendChild(shadowApp)
      document.querySelectorAll('style').forEach(styleElement => {
        shadowRoot.appendChild(styleElement.cloneNode(true))
      })

      createApp({
        render: () => h(VMenu, { location: 'right' }, {
          activator: ({ props }) => h(VBtn, { ...props, class: 'ma-5' }, 'Shadow Menu'),
          default: () => [
            h(VList, {}, () => [
              h(VMenu, { location: 'right' }, {
                activator: ({ props }) => h(VListItem, { ...props, title: 'Submenu' }),
                default: () => [
                  h(VList, {}, () => [
                    h(VListItem, { title: 'Submenu item' }),
                    h(VListItem, { title: 'Submenu item' }),
                  ]),
                ],
              }),
            ]),
          ],
        }),
      })
        .use(vuetify)
        .mount(shadowApp)
    },
  }
</script>

cgodo added a commit to cgodo/vuetify that referenced this issue Aug 2, 2024
Use beforeUnmount instead of unmounted to remove event handlers in
click-outside directive, since it's not possible to get element's
shadowRoot when the element is already unmounted.

fixes vuetifyjs#19616
@KaelWD KaelWD added T: bug Functionality that does not work as intended/expected D: click-outside labels Aug 3, 2024
@KaelWD KaelWD added this to the v3.6.x milestone Aug 3, 2024
@github-actions github-actions bot removed the S: triage label Aug 3, 2024
@KaelWD KaelWD closed this as completed in 9b02b0d Aug 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment