11<script setup lang="ts">
22import type { HTMLAttributes } from ' vue'
3+ import type { Placement } from ' @floating-ui/vue'
4+ import { autoUpdate , flip , offset , shift , useFloating } from ' @floating-ui/vue'
35
46const props = defineProps <{
57 /** Tooltip text */
@@ -12,34 +14,39 @@ const props = defineProps<{
1214 tooltipAttr? : HTMLAttributes
1315}>()
1416
15- const positionClasses: Record <string , string > = {
16- top: ' bottom-full inset-is-1/2 -translate-x-1/2 mb-1' ,
17- bottom: ' top-full inset-is-0 mt-1' ,
18- left: ' inset-ie-full top-1/2 -translate-y-1/2 me-2' ,
19- right: ' inset-is-full top-1/2 -translate-y-1/2 ms-2' ,
20- }
17+ const triggerRef = useTemplateRef (' triggerRef' )
18+ const tooltipRef = useTemplateRef (' tooltipRef' )
2119
22- const tooltipPosition = computed (() => positionClasses [props .position || ' bottom' ])
20+ const placement = computed <Placement >(() => props .position || ' bottom' )
21+
22+ const { floatingStyles } = useFloating (triggerRef , tooltipRef , {
23+ placement ,
24+ whileElementsMounted: autoUpdate ,
25+ middleware: [offset (4 ), flip (), shift ({ padding: 8 })],
26+ })
2327 </script >
2428
2529<template >
26- <div class = " relative inline-flex" >
30+ <div ref = " triggerRef " class = " inline-flex" >
2731 <slot />
2832
29- <Transition
30- enter-active-class =" transition-opacity duration-150 motion-reduce:transition-none"
31- leave-active-class =" transition-opacity duration-100 motion-reduce:transition-none"
32- enter-from-class =" opacity-0"
33- leave-to-class =" opacity-0"
34- >
35- <div
36- v-if =" props.isVisible"
37- class =" absolute px-2 py-1 font-mono text-xs text-fg bg-bg-elevated border border-border rounded shadow-lg whitespace-nowrap z-[100] pointer-events-none"
38- :class =" tooltipPosition"
39- v-bind =" tooltipAttr"
33+ <Teleport to =" body" >
34+ <Transition
35+ enter-active-class =" transition-opacity duration-150 motion-reduce:transition-none"
36+ leave-active-class =" transition-opacity duration-100 motion-reduce:transition-none"
37+ enter-from-class =" opacity-0"
38+ leave-to-class =" opacity-0"
4039 >
41- {{ text }}
42- </div >
43- </Transition >
40+ <div
41+ v-if =" props.isVisible"
42+ ref =" tooltipRef"
43+ class =" px-2 py-1 font-mono text-xs text-fg bg-bg-elevated border border-border rounded shadow-lg whitespace-nowrap z-[100] pointer-events-none"
44+ :style =" floatingStyles"
45+ v-bind =" tooltipAttr"
46+ >
47+ {{ text }}
48+ </div >
49+ </Transition >
50+ </Teleport >
4451 </div >
4552</template >
0 commit comments