<template>
<div>
<slot name="activator" @click="toggleTooltip"></slot>
<div v-if="showTooltip" ref="tooltip" :style="tooltipPosition" class="tooltip">
<slot></slot>
</div>
</div>
</template>
<script>
import { ref, watch, onMounted, onBeforeUnmount } from 'vue';
export default {
name: 'Tooltip',
setup() {
const showTooltip = ref(false);
const toggleTooltip = () => {
showTooltip.value = !showTooltip.value;
};
const closeTooltip = (event) => {
if (!event.target.closest('.tooltip')) {
showTooltip.value = false;
}
};
const handleEscapeKey = (event) => {
if (event.key === 'Escape') {
showTooltip.value = false;
}
};
onMounted(() => {
window.addEventListener('click', closeTooltip);
window.addEventListener('keydown', handleEscapeKey);
});
onBeforeUnmount(() => {
window.removeEventListener('click', closeTooltip);
window.removeEventListener('keydown', handleEscapeKey);
});
const tooltipPosition = ref({});
watch(showTooltip, (newValue) => {
if (newValue) {
const tooltip = document.querySelector('.tooltip');
const activator = document.querySelector('.tooltip-activator');
const tooltipRect = tooltip.getBoundingClientRect();
const activatorRect = activator.getBoundingClientRect();
const viewportWidth = window.innerWidth;
let left, top;
if (activatorRect.left < tooltipRect.width) {
left = `${activatorRect.right}px`;
} else if (activatorRect.left + tooltipRect.width > viewportWidth) {
left = `${activatorRect.left - tooltipRect.width}px`;
} else {
left = `${activatorRect.left}px`;
}
if (activatorRect.top < tooltipRect.height) {
top = `${activatorRect.bottom}px`;
} else {
top = `${activatorRect.top - tooltipRect.height}px`;
}
tooltipPosition.value = { left, top };
}
});
return {
showTooltip,
toggleTooltip,
tooltipPosition,
};
},
};
</script>
<style scoped>
.tooltip {
position: absolute;
z-index: 999;
background-color: #f1f1f1;
padding: 10px;
border-radius: 4px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}
</style>