src/components/data-display/VueTooltip/VueTooltip.vue
<template>
<component
:is="as"
:class="[
$style.vueTooltip,
show && $style.show,
$style[direction],
!disabled && $slots.default && $slots.default()[0].el !== null && $style.highlight,
]"
:data-tip="tip"
@mouseenter.stop.prevent="onEnter"
@mouseleave.stop.prevent="onLeave"
@touchend.stop.prevent="onTouchEnd"
>
<slot />
</component>
</template>
<script setup lang="ts">
import { ref, useCssModule } from 'vue';
import { VerticalDirection } from '~/components/prop-types';
// Interface
interface TooltipProps {
as?: string;
tip: string;
direction?: VerticalDirection;
disabled?: boolean;
}
const props = withDefaults(defineProps<TooltipProps>(), {
as: 'span',
direction: 'top',
disabled: false,
});
// Deps
const $style = useCssModule();
// Data
const show = ref(false);
// Event Handlers
const onEnter = () => {
if (props.disabled === false) {
show.value = true;
}
};
const onLeave = () => {
show.value = false;
};
const onTouchEnd = () => {
if (props.disabled === false) {
show.value = !show.value;
}
};
</script>
<style lang="scss" module>
@import 'assets/_design-system.scss';
.vueTooltip {
display: inline-flex;
align-items: flex-end;
position: relative;
border-bottom: 1px dashed transparent;
&:before {
display: block;
opacity: 0;
pointer-events: none;
position: absolute;
transition-property: opacity;
transition-duration: $tooltip-transition-duration;
transition-timing-function: ease-in-out;
background: $tooltip-bg;
color: $tooltip-color;
font-size: $tooltip-font-size;
line-height: $tooltip-line-height;
font-weight: $tooltip-font-weight;
content: attr(data-tip);
padding: $tooltip-padding;
white-space: nowrap;
box-shadow: $tooltip-elevation;
border-radius: $tooltip-border-radius;
left: 50%;
transform: translateX(-50%);
}
&.top {
&:before {
bottom: calc(100% + #{$space-4});
}
}
&.bottom {
&:before {
top: calc(100% + #{$space-4});
}
}
&.show {
&:before {
opacity: 1;
}
}
&.highlight {
border-bottom: 1px dashed $tooltip-highlight-color;
}
}
</style>