mirror of https://github.com/VERT-sh/VERT.git
156 lines
3.8 KiB
Svelte
156 lines
3.8 KiB
Svelte
<script lang="ts">
|
|
import { fade } from "$lib/animation";
|
|
interface Props {
|
|
children: () => any;
|
|
text: string;
|
|
className?: string;
|
|
position?: "top" | "bottom" | "left" | "right";
|
|
}
|
|
|
|
let { children, text, className, position = "top" }: Props = $props();
|
|
let showTooltip = $state(false);
|
|
let timeout: NodeJS.Timeout | null = null;
|
|
let triggerElement: HTMLElement;
|
|
let tooltipElement = $state<HTMLElement>();
|
|
let tooltipPosition = $state({ x: 0, y: 0 });
|
|
|
|
function show() {
|
|
timeout = setTimeout(() => {
|
|
if (!triggerElement) return;
|
|
const rect = triggerElement.getBoundingClientRect();
|
|
|
|
switch (position) {
|
|
case "top":
|
|
tooltipPosition = {
|
|
x: rect.left + rect.width / 2,
|
|
y: rect.top - 10,
|
|
};
|
|
break;
|
|
case "bottom":
|
|
tooltipPosition = {
|
|
x: rect.left + rect.width / 2,
|
|
y: rect.bottom + 10,
|
|
};
|
|
break;
|
|
case "left":
|
|
tooltipPosition = {
|
|
x: rect.left - 10,
|
|
y: rect.top + rect.height / 2,
|
|
};
|
|
break;
|
|
case "right":
|
|
tooltipPosition = {
|
|
x: rect.right + 10,
|
|
y: rect.top + rect.height / 2,
|
|
};
|
|
break;
|
|
}
|
|
showTooltip = true;
|
|
}, 500);
|
|
}
|
|
|
|
function hide() {
|
|
showTooltip = false;
|
|
if (timeout) clearTimeout(timeout);
|
|
}
|
|
|
|
$effect(() => {
|
|
if (showTooltip && tooltipElement) {
|
|
document.body.appendChild(tooltipElement);
|
|
}
|
|
|
|
return () => {
|
|
if (tooltipElement && tooltipElement.parentNode === document.body) {
|
|
document.body.removeChild(tooltipElement);
|
|
}
|
|
};
|
|
});
|
|
</script>
|
|
|
|
<span
|
|
bind:this={triggerElement}
|
|
class="relative inline-block {className}"
|
|
onmouseenter={show}
|
|
onmouseleave={hide}
|
|
onfocusin={show}
|
|
onfocusout={hide}
|
|
ontouchstart={show}
|
|
ontouchend={hide}
|
|
role="tooltip"
|
|
>
|
|
{@render children()}
|
|
</span>
|
|
|
|
{#if showTooltip}
|
|
<span
|
|
bind:this={tooltipElement}
|
|
class="tooltip tooltip-{position}"
|
|
style="left: {tooltipPosition.x}px; top: {tooltipPosition.y}px;"
|
|
transition:fade={{
|
|
duration: 100,
|
|
}}
|
|
>
|
|
{text}
|
|
</span>
|
|
{/if}
|
|
|
|
<style lang="postcss">
|
|
.tooltip {
|
|
--border-size: 1px;
|
|
@apply fixed bg-panel-alt text-foreground border border-stone-400 dynadark:border-white drop-shadow-lg text-xs rounded-full pointer-events-none z-[999] max-w-xs break-words whitespace-normal;
|
|
@apply px-5 py-2.5;
|
|
}
|
|
|
|
.tooltip-top {
|
|
transform: translate(-50%, -100%);
|
|
}
|
|
|
|
.tooltip-top::after {
|
|
@apply content-[""] absolute top-full left-1/2 -translate-x-1/2 border-8 border-x-transparent border-b-transparent;
|
|
}
|
|
|
|
.tooltip-top::before {
|
|
border-width: calc(var(--border-size) + 8px);
|
|
margin-left: calc(-1 * (var(--border-size) + 8px));
|
|
@apply content-[""] absolute top-full left-1/2 border-x-transparent border-b-transparent border-t-inherit;
|
|
}
|
|
|
|
.tooltip-bottom {
|
|
transform: translate(-50%, 20%);
|
|
}
|
|
|
|
.tooltip-bottom::after {
|
|
@apply content-[""] absolute bottom-full left-1/2 -ml-2 border-8 border-x-transparent border-t-transparent;
|
|
}
|
|
|
|
.tooltip-bottom::before {
|
|
border-width: calc(var(--border-size) + 8px);
|
|
margin-left: calc(-1 * (var(--border-size) + 8px));
|
|
@apply content-[""] absolute bottom-full left-1/2 border-x-transparent border-t-transparent border-b-inherit;
|
|
}
|
|
|
|
.tooltip-left {
|
|
transform: translate(-100%, -50%);
|
|
}
|
|
|
|
.tooltip-left::after {
|
|
@apply content-[""] absolute top-1/2 left-full -mt-2 border-8 border-y-transparent border-r-transparent border-l-inherit;
|
|
}
|
|
|
|
.tooltip-right {
|
|
transform: translate(0%, -50%);
|
|
}
|
|
|
|
.tooltip-right::after {
|
|
margin-right: -2px;
|
|
@apply content-[""] absolute top-1/2 right-full -mt-2 border-8 border-y-transparent border-l-transparent;
|
|
}
|
|
|
|
.tooltip-right::before {
|
|
margin-right: -2px;
|
|
border-width: calc(var(--border-size) + 8px);
|
|
margin-top: calc(-1 * (var(--border-size) + 8px));
|
|
@apply content-[""] absolute top-1/2 right-full border-y-transparent border-l-transparent border-r-inherit;
|
|
}
|
|
</style>
|