CatPtain's picture
Upload 339 files
89ce340 verified
raw
history blame
2.47 kB
<template>
<div class="popover" :class="{ 'center': center }" ref="triggerRef">
<div class="popover-content" :style="contentStyle" ref="contentRef">
<slot name="content" v-if="contentVisible"></slot>
</div>
<slot></slot>
</div>
</template>
<script lang="ts" setup>
import { type CSSProperties, onMounted, onUnmounted, ref, watch, computed } from 'vue'
import tippy, { type Instance, type Placement } from 'tippy.js'
import 'tippy.js/animations/scale.css'
const props = withDefaults(defineProps<{
value?: boolean
trigger?: 'click' | 'mouseenter' | 'manual'
placement?: Placement
appendTo?: HTMLElement | 'parent'
contentStyle?: CSSProperties
center?: boolean
offset?: number
}>(), {
value: false,
trigger: 'click',
placement: 'bottom',
center: false,
offset: 8,
})
const emit = defineEmits<{
(event: 'update:value', payload: boolean): void
(event: 'show'): void
(event: 'hide'): void
}>()
const instance = ref<Instance>()
const triggerRef = ref<HTMLElement>()
const contentRef = ref<HTMLElement>()
const contentVisible = ref(false)
const contentStyle = computed(() => {
return props.contentStyle || {}
})
watch(() => props.value, () => {
if (!instance.value) return
if (props.value) instance.value.show()
else instance.value.hide()
})
onUnmounted(() => {
if (instance.value) instance.value.destroy()
})
onMounted(() => {
instance.value = tippy(triggerRef.value!, {
content: contentRef.value!,
allowHTML: true,
trigger: props.trigger,
placement: props.placement,
interactive: true,
appendTo: props.appendTo || document.body,
maxWidth: 'none',
offset: [0, props.offset],
duration: 200,
animation: 'scale',
theme: 'popover',
onShow() {
contentVisible.value = true
},
onShown() {
if (!props.value) {
emit('update:value', true)
emit('show')
}
},
onHidden() {
if (props.value) {
emit('update:value', false)
emit('hide')
}
contentVisible.value = false
},
})
})
</script>
<style lang="scss" scoped>
.popover.center {
display: flex;
justify-content: center;
align-items: center;
}
.popover-content {
background-color: #fff;
padding: 10px;
border: 1px solid $borderColor;
box-shadow: $boxShadow;
border-radius: $borderRadius;
font-size: 13px;
}
</style>
<style lang="scss">
.tippy-box[data-theme~='popover'] {
border: 0;
outline: 0;
}
</style>