[READ-ONLY] a fast, modern browser for the npm registry
at main 71 lines 2.4 kB view raw
1<script setup lang="ts"> 2import type { HTMLAttributes } from 'vue' 3import type { Placement, Strategy } from '@floating-ui/vue' 4import { autoUpdate, flip, offset, shift, useFloating } from '@floating-ui/vue' 5 6const props = withDefaults( 7 defineProps<{ 8 /** Tooltip text (optional when using content slot) */ 9 text?: string 10 /** Position: 'top' | 'bottom' | 'left' | 'right' */ 11 position?: 'top' | 'bottom' | 'left' | 'right' 12 /** is tooltip visible */ 13 isVisible: boolean 14 /** Allow pointer events on tooltip (for interactive content like links) */ 15 interactive?: boolean 16 /** attributes for tooltip element */ 17 tooltipAttr?: HTMLAttributes 18 /** Teleport target for the tooltip content (defaults to 'body') */ 19 to?: string | HTMLElement 20 /** Whether to defer teleport rendering until after the component is mounted */ 21 defer?: boolean 22 /** Offset distance in pixels (default: 4) */ 23 offset?: number 24 /** Strategy for the tooltip - prefer fixed for sticky containers (defaults to 'absolute') */ 25 strategy?: Strategy 26 }>(), 27 { 28 to: 'body', 29 offset: 4, 30 strategy: 'absolute', 31 }, 32) 33 34const triggerRef = useTemplateRef('triggerRef') 35const tooltipRef = useTemplateRef('tooltipRef') 36 37const placement = computed<Placement>(() => props.position || 'bottom') 38 39const { floatingStyles } = useFloating(triggerRef, tooltipRef, { 40 placement, 41 whileElementsMounted: autoUpdate, 42 strategy: props.strategy, 43 middleware: [offset(props.offset), flip(), shift({ padding: 8 })], 44}) 45</script> 46 47<template> 48 <div ref="triggerRef" class="inline-flex"> 49 <slot /> 50 51 <Teleport :to="props.to" :defer> 52 <Transition 53 enter-active-class="transition-opacity duration-150 motion-reduce:transition-none" 54 leave-active-class="transition-opacity duration-100 motion-reduce:transition-none" 55 enter-from-class="opacity-0" 56 leave-to-class="opacity-0" 57 > 58 <div 59 v-if="props.isVisible" 60 ref="tooltipRef" 61 class="px-2 py-1 font-mono text-xs text-fg bg-bg-elevated border border-border rounded shadow-lg whitespace-pre-line break-words max-w-xs z-[100]" 62 :class="{ 'pointer-events-none': !interactive }" 63 :style="floatingStyles" 64 v-bind="tooltipAttr" 65 > 66 <slot name="content">{{ text }}</slot> 67 </div> 68 </Transition> 69 </Teleport> 70 </div> 71</template>