54 lines
1.6 KiB
Vue
54 lines
1.6 KiB
Vue
<script setup>
|
|
import { inject, watch } from "vue";
|
|
|
|
defineOptions({ name: "TooltipContent" });
|
|
|
|
const props = defineProps({
|
|
side: {
|
|
type: String,
|
|
default: "top",
|
|
validator: (value) => ["top", "right", "bottom", "left"].includes(value),
|
|
},
|
|
sideOffset: {
|
|
type: Number,
|
|
default: 4,
|
|
},
|
|
});
|
|
|
|
const { floating, isOpen, floatingStyles, arrowRef, arrowStyles, placement } =
|
|
inject("tooltip");
|
|
</script>
|
|
|
|
<template>
|
|
<Transition
|
|
enter-active-class="transition-opacity duration-200"
|
|
enter-from-class="opacity-0"
|
|
enter-to-class="opacity-100"
|
|
leave-active-class="transition-opacity duration-200"
|
|
leave-from-class="opacity-100"
|
|
leave-to-class="opacity-0"
|
|
>
|
|
<div
|
|
v-if="isOpen"
|
|
ref="floating"
|
|
:style="floatingStyles"
|
|
class="z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2"
|
|
:data-side="placement?.split('-')[0]"
|
|
role="tooltip"
|
|
>
|
|
<slot />
|
|
<div
|
|
ref="arrowRef"
|
|
:style="arrowStyles"
|
|
class="absolute z-[-1] h-2 w-2 rotate-45 bg-popover border"
|
|
:class="{
|
|
'-top-1 border-b border-r': placement?.includes('bottom'),
|
|
'-bottom-1 border-t border-l': placement?.includes('top'),
|
|
'-right-1 border-b border-l': placement?.includes('left'),
|
|
'-left-1 border-t border-r': placement?.includes('right')
|
|
}"
|
|
/>
|
|
</div>
|
|
</Transition>
|
|
</template>
|