Skip to content

Commit 3bdc0e3

Browse files
committed
feat(app): add v-tooltip
1 parent 22d007c commit 3bdc0e3

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed

packages/app/components/VTooltip.vue

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
<script lang="ts">
2+
export default {
3+
name: 'VTooltip',
4+
inheritAttrs: false,
5+
}
6+
</script>
7+
<script setup lang="ts">
8+
import { computed, onUnmounted, ref, watch, onMounted } from 'vue'
9+
import { useVModel } from 'vue-wind/composables/v-model'
10+
11+
import debounce from 'lodash/debounce'
12+
13+
// Props & Emits
14+
const props = defineProps({
15+
modelValue: {
16+
type: Boolean,
17+
default: null,
18+
},
19+
color: {
20+
type: String,
21+
default: 'b-primary',
22+
},
23+
offsetY: {
24+
type: Boolean,
25+
default: false,
26+
},
27+
offsetX: {
28+
type: Boolean,
29+
default: false,
30+
},
31+
x: {
32+
type: Number,
33+
default: null,
34+
},
35+
y: {
36+
type: Number,
37+
default: null,
38+
},
39+
})
40+
41+
const emit = defineEmits(['update:modelValue'])
42+
43+
// Show
44+
45+
const innerModel = ref(false)
46+
const model = useVModel(props, 'modelValue', emit)
47+
48+
const show = computed({
49+
get() {
50+
if (model.value !== null) {
51+
return model.value
52+
}
53+
54+
return innerModel.value
55+
},
56+
set(value) {
57+
if (model.value !== null) {
58+
model.value = value
59+
return
60+
}
61+
62+
innerModel.value = value
63+
},
64+
})
65+
66+
function toggle() {
67+
show.value = !show.value
68+
}
69+
70+
// track mouse position
71+
72+
const mouse = ref({
73+
x: 0,
74+
y: 0,
75+
})
76+
77+
const onMouseover = debounce((event: MouseEvent) => {
78+
const el = event.target as HTMLElement
79+
80+
if (!el || !el.matches(':hover')) {
81+
show.value = false
82+
return
83+
}
84+
85+
mouse.value.y = event.clientY + 20
86+
mouse.value.x = event.clientX
87+
88+
show.value = true
89+
}, 500)
90+
91+
function onMouseleave() {
92+
show.value = false
93+
}
94+
95+
// style
96+
const style = computed(() => {
97+
let y = props.y ?? mouse.value.y
98+
let x = props.x ?? mouse.value.x
99+
100+
const result = {
101+
top: `${y}px`,
102+
left: `${x}px`,
103+
}
104+
105+
return result
106+
})
107+
</script>
108+
109+
<template>
110+
<slot name="activator" :attrs="{ onMouseover, onMouseleave }" :toggle="toggle" />
111+
112+
<teleport to="body">
113+
<div
114+
v-show="show"
115+
:style="style"
116+
class="v-tooltip z-20 fixed transition-all overflow-auto max-h-screen"
117+
v-bind="$attrs"
118+
>
119+
<v-card :color="color" class="text-xs p-2">
120+
<slot />
121+
</v-card>
122+
</div>
123+
</teleport>
124+
</template>

0 commit comments

Comments
 (0)