fix(Popover): allow manual mode without blocking normal behaviour

This commit is contained in:
Benjamin Canac
2024-01-03 16:51:20 +01:00
parent 3844714644
commit 3334e2af3d
4 changed files with 49 additions and 36 deletions

View File

@@ -1,5 +1,6 @@
<template>
<HPopover ref="popover" v-slot="{ open: headlessOpen, close }" :class="ui.wrapper" v-bind="attrs" @mouseleave="onMouseLeave">
<!-- eslint-disable-next-line vue/no-template-shadow -->
<HPopover ref="popover" v-slot="{ open, close }" :class="ui.wrapper" v-bind="attrs" @mouseleave="onMouseLeave">
<HPopoverButton
ref="trigger"
as="div"
@@ -8,7 +9,7 @@
role="button"
@mouseover="onMouseOver"
>
<slot :open="(open !== undefined) ? open : headlessOpen" :close="close">
<slot :open="open" :close="close">
<button :disabled="disabled">
Open
</button>
@@ -16,16 +17,16 @@
</HPopoverButton>
<Transition v-if="overlay" appear v-bind="ui.overlay.transition">
<div v-if="(open !== undefined) ? open : headlessOpen" :class="[ui.overlay.base, ui.overlay.background]" @click="$emit('update:open')" />
<div v-if="open" :class="[ui.overlay.base, ui.overlay.background]" />
</Transition>
<div v-if="(open !== undefined) ? open : headlessOpen" ref="container" :class="[ui.container, ui.width]" :style="containerStyle" @mouseover="onMouseOver">
<div v-if="open" ref="container" :class="[ui.container, ui.width]" :style="containerStyle" @mouseover="onMouseOver">
<Transition appear v-bind="ui.transition">
<div>
<div v-if="popper.arrow" data-popper-arrow :class="Object.values(ui.arrow)" />
<HPopoverPanel :class="[ui.base, ui.background, ui.ring, ui.rounded, ui.shadow]" static>
<slot name="panel" :open="(open !== undefined) ? open : headlessOpen" :close="close" />
<slot name="panel" :open="open" :close="close" />
</HPopoverPanel>
</div>
</Transition>
@@ -94,7 +95,7 @@ export default defineComponent({
default: () => ({})
}
},
emits: ['update:open', 'open', 'close'],
emits: ['update:open'],
setup (props, { emit }) {
const { ui, attrs } = useUI('popover', toRef(props, 'ui'), config, toRef(props, 'class'))
@@ -102,8 +103,8 @@ export default defineComponent({
const [trigger, container] = usePopper(popper.value)
// https://github.com/tailwindlabs/headlessui/blob/f66f4926c489fc15289d528294c23a3dc2aee7b1/packages/%40headlessui-vue/src/components/popover/popover.ts#L151
const popover = ref<any>(null)
// https://github.com/tailwindlabs/headlessui/blob/f66f4926c489fc15289d528294c23a3dc2aee7b1/packages/%40headlessui-vue/src/components/popover/popover.ts#L151
const popoverApi = ref<any>(null)
let openTimeout: NodeJS.Timeout | null = null
@@ -116,6 +117,10 @@ export default defineComponent({
}
const popoverProvidesSymbols = Object.getOwnPropertySymbols(popoverProvides)
popoverApi.value = popoverProvidesSymbols.length && popoverProvides[popoverProvidesSymbols[0]]
if (props.open) {
popoverApi.value?.togglePopover()
}
})
const containerStyle = computed(() => {
@@ -170,9 +175,22 @@ export default defineComponent({
}, props.closeDelay)
}
watch(() => props.open, (newValue: boolean, oldValue: boolean) => {
if (!popoverApi.value) return
if (oldValue === undefined || newValue === oldValue) return
if (newValue) {
// No `openPopover` method and `popoverApi.value.togglePopover` won't work because of the `watch` below
popoverApi.value.popoverState = 0
} else {
popoverApi.value.closePopover()
}
})
watch(() => popoverApi.value?.popoverState, (newValue: number, oldValue: number) => {
if (oldValue === undefined) return
emit(newValue === 0 ? 'open' : 'close')
if (oldValue === undefined || newValue === oldValue) return
emit('update:open', newValue === 0)
})
return {