<template> <div class="tooltip-container"> <div ref="handle" class="tooltip-handle" @click.stop="toggle" > <slot /> </div> <div v-show="opened" class="tooltip-layer" > <div ref="tooltip" class="tooltip-wrapper" :style="{ transform: `translate(${position.x}px, ${position.y}px)` }" > <div class="tooltip" @click="close" > <slot name="tooltip" @click.stop /> </div> </div> </div> </div> </template> <script setup> import { ref, onMounted, onBeforeUnmount, nextTick, } from 'vue'; // import { useFloating } from '@floating-ui/vue'; import { computePosition, shift } from '@floating-ui/dom'; import events from '#/src/events.js'; const handle = ref(null); const tooltip = ref(null); const opened = ref(false); const position = ref({ x: 0, y: 0, }); const props = defineProps({ placement: { type: String, default: 'top', }, }); async function open() { events.emit('blur'); opened.value = true; await nextTick(); console.log(handle.value); /* const { floatingStyles } = useFloating(handle, tooltip, { placement: props.placement, }); styles.value = floatingStyles.value; */ const { x, y } = await computePosition(handle.value, tooltip.value, { placement: props.placement, middleware: [shift()], }); position.value.x = x; position.value.y = y; console.log(x, y); console.log('open!'); } function close() { console.log('close!'); opened.value = false; } function toggle() { if (opened.value) { close(); } else { open(); } } onMounted(() => { events.on('blur', close); }); onBeforeUnmount(() => { events.off('blur', close); }); </script> <style> .tooltip-layer { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10000; } .tooltip-wrapper { width: max-content; overflow: hidden; box-sizing: border-box; padding: .25rem; } .tooltip { max-height: calc(100vh - .5rem); background: var(--background); box-shadow: 0 0 3px var(--shadow); overflow: hidden; } </style>