mirror of
https://github.com/frappe/books.git
synced 2025-02-05 21:48:32 +00:00
147 lines
2.9 KiB
Vue
147 lines
2.9 KiB
Vue
<template>
|
|
<div ref="reference">
|
|
<div class="h-full">
|
|
<slot
|
|
name="target"
|
|
:toggle-popover="togglePopover"
|
|
:handle-blur="handleBlur"
|
|
></slot>
|
|
</div>
|
|
<Transition>
|
|
<div
|
|
v-show="isOpen"
|
|
ref="popover"
|
|
:class="popoverClass"
|
|
class="
|
|
bg-white
|
|
rounded-md
|
|
border
|
|
shadow-lg
|
|
popover-container
|
|
relative
|
|
z-10
|
|
"
|
|
:style="{ 'transition-delay': `${isOpen ? entryDelay : exitDelay}ms` }"
|
|
>
|
|
<slot name="content" :toggle-popover="togglePopover"></slot>
|
|
</div>
|
|
</Transition>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { createPopper } from '@popperjs/core';
|
|
import { nextTick } from 'vue';
|
|
|
|
export default {
|
|
name: 'Popover',
|
|
props: {
|
|
showPopup: {
|
|
type: [Boolean, null],
|
|
default: null,
|
|
},
|
|
right: Boolean,
|
|
entryDelay: { type: Number, default: 0 },
|
|
exitDelay: { type: Number, default: 0 },
|
|
placement: {
|
|
type: String,
|
|
default: 'bottom-start',
|
|
},
|
|
popoverClass: [String, Object, Array],
|
|
},
|
|
emits: ['open', 'close'],
|
|
data() {
|
|
return {
|
|
isOpen: false,
|
|
};
|
|
},
|
|
watch: {
|
|
showPopup(value) {
|
|
if (value === true) {
|
|
this.open();
|
|
}
|
|
if (value === false) {
|
|
this.close();
|
|
}
|
|
},
|
|
},
|
|
mounted() {
|
|
this.listener = (e) => {
|
|
let $els = [this.$refs.reference, this.$refs.popover];
|
|
let insideClick = $els.some(
|
|
($el) => $el && (e.target === $el || $el.contains(e.target))
|
|
);
|
|
if (insideClick) {
|
|
return;
|
|
}
|
|
this.close();
|
|
};
|
|
|
|
if (this.show == null) {
|
|
document.addEventListener('click', this.listener);
|
|
}
|
|
},
|
|
beforeUnmount() {
|
|
this.popper && this.popper.destroy();
|
|
if (this.listener) {
|
|
document.removeEventListener('click', this.listener);
|
|
delete this.listener;
|
|
}
|
|
},
|
|
methods: {
|
|
setupPopper() {
|
|
if (!this.popper) {
|
|
this.popper = createPopper(this.$refs.reference, this.$refs.popover, {
|
|
placement: this.placement,
|
|
modifiers: [{ name: 'offset', options: { offset: [0, 8] } }],
|
|
});
|
|
} else {
|
|
this.popper.update();
|
|
}
|
|
},
|
|
togglePopover(flag) {
|
|
if (flag == null) {
|
|
flag = !this.isOpen;
|
|
}
|
|
flag = Boolean(flag);
|
|
if (flag) {
|
|
this.open();
|
|
} else {
|
|
this.close();
|
|
}
|
|
},
|
|
open() {
|
|
if (this.isOpen) {
|
|
return;
|
|
}
|
|
this.isOpen = true;
|
|
nextTick(() => {
|
|
this.setupPopper();
|
|
});
|
|
this.$emit('open');
|
|
},
|
|
close() {
|
|
if (!this.isOpen) {
|
|
return;
|
|
}
|
|
this.isOpen = false;
|
|
this.$emit('close');
|
|
},
|
|
handleBlur({ relatedTarget }) {
|
|
relatedTarget && this.close();
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
<style scoped>
|
|
.v-enter-active,
|
|
.v-leave-active {
|
|
transition: opacity 150ms ease-out;
|
|
}
|
|
|
|
.v-enter-from,
|
|
.v-leave-to {
|
|
opacity: 0;
|
|
}
|
|
</style>
|