Akryum / floating-vue

💬 Easy tooltips, popovers, dropdown, menus... for Vue
https://floating-vue.starpad.dev/
MIT License
3.3k stars 337 forks source link

Close nested VDropdown without closing parent programmatically #874

Open kduvignau opened 2 years ago

kduvignau commented 2 years ago

Hello! I would like to close a nested VDropdown inside another VDropdown.

I tried with the v-close-popper directive on the div node and it works. However, I would like to do some processing (async calls for example) before closing the popper so I can't use the directive as-is.

I also tried to use the hide method exposed by the #popper slot, I got the same result.

I also don't want to use :auto-hide="false" on the parent VDropdown because I want to autoclose when the click is outside

Here is a minimal example, when I click on Hello, the nested AND the parent VDropdown close.

<template>
  <div class="example flex justify-center items-center gap-6">
    <VDropdown placement="bottom-start">
      <button class="border border-gray-300 rounded px-4 py-2">Click me</button>

      <template #popper>
        <VDropdown v-model:shown="open" placement="right-start">
          <button class="rounded hover:bg-green-100 px-4 py-2">Option ></button>

          <template #popper>
            <div class="px-6 py-2" @click="onClick">Hello</div>
          </template>
        </VDropdown>
      </template>
    </VDropdown>
  </div>
</template>

<script setup>
import { ref } from "vue";
const open = ref(false);

function onClick() {
  // Some processing ...
  open.value = false;
}
</script>
or2e commented 1 year ago

bump

Reproduction: https://stackblitz.com/edit/vitejs-vite-t58z89?file=src%2FApp.vue

Expected behavior: only the closest dropdown is closed when calling the hide method Current behavior: the all dropdown hierarchy closes

zhaivoronok commented 1 year ago

Same here, really need to fix it!

or2e commented 1 year ago

zhaivoronok, kduvignau Very dirty hack, nothing seems to be broken (but it's not for sure)

https://github.com/Akryum/floating-vue/blob/main/packages/floating-vue/src/components/Popper.ts#L454

if (this.shownChildren.size > 0) {
-   this.$_pendingHide = true
    return
}

https://github.com/Akryum/floating-vue/blob/main/packages/floating-vue/src/components/Popper.ts#L477

- this.$_scheduleHide(event, skipDelay)
+ setTimeout(() => {
+  this.$_scheduleHide(event, skipDelay)
+ }, 0);
kduvignau commented 1 year ago

Thanks for providing your solution @or2e !

FYI, there is an official package for floating ui for Vue, you can find out here : https://www.npmjs.com/package/@floating-ui/vue

ishaiavrahami commented 9 months ago

Hi was this fixed? @zhaivoronok @kduvignau @or2e

RAIbrahim360 commented 9 months ago

Solution:

<template>
  <Dropdown :shown="open" @show="onShow" @hide="onHide">
    <slot></slot>
    <div slot="popper"></div>
  </Dropdown>
</template>

<script>
import { Dropdown } from 'v-tooltip'

export default {
  name: 'Popover',
  components: {
    Dropdown,
  },
  data() {
    return {
      autoHide_: this.autoHide,
      isOpened: false,
    }
  },
  watch: {
    autoHide(newValue) {
      this.autoHide_ = newValue
    },
  },
  methods: {
    setParentAutoHideToFalse() {
      let parent = this.$parent
      while (parent) {
        if (parent.$el.classList.contains('v-popper') && parent.isOpened) {
          parent.autoHide_ = false
          if (parent.$el.parentNode === document.body) {
            break
          }
        }
        parent = parent.$parent
      }
    },
    setParentAutoHideToTrue() {
      let parent = this.$parent
      while (parent) {
        if (parent.$el.classList.contains('v-popper') && parent.isOpened) {
          parent.autoHide_ = true
          break
        }
        parent = parent.$parent
      }
    },
    onShow() {
      this.isOpened = true
      setTimeout(() => this.setParentAutoHideToFalse(), 200)
    },
    onHide() {
      this.isOpened = false
      setTimeout(() => this.setParentAutoHideToTrue(), 100)
    },
  },
}
</script>
or2e commented 7 months ago

@ishaiavrahami No ( Updated the reproduction: https://stackblitz.com/edit/vitejs-vite-kfcze6?file=src%2FApp.vue

vkolova commented 7 months ago

This is still not resolved after two years?

bendemartin97 commented 1 week ago

Any updates here?