-
Notifications
You must be signed in to change notification settings - Fork 1
/
Tooltip.svelte
109 lines (95 loc) · 2.44 KB
/
Tooltip.svelte
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<!--
Copyright © 2022 The Radicle Design System Contributors
This file is part of radicle-design-system, distributed under the GPLv3
with Radicle Linking Exception. For full terms see the included
LICENSE file.
-->
<script lang="ts">
type Offset = { top: number; left: number };
import type { Position } from "./Tooltip";
import { debounce } from "lodash-es";
export let style: string | undefined = undefined;
export let value: string | undefined = undefined;
export let position: Position = "right";
export let showDelay = 50; // ms
let container: Element | null = null;
let message: Element | null = null;
let offset: Offset = { top: 0, left: 0 };
let visible: boolean = false;
const setVisible = debounce((value: boolean) => {
visible = value;
}, showDelay);
function calculateOffset(
position: Position,
container: DOMRect,
message: DOMRect
): Offset {
switch (position) {
case "top":
return {
top: container.top - 40,
left: container.left + container.width / 2,
};
case "right":
return {
top: container.top + container.height / 2 - 16,
left: container.right + 8,
};
case "bottom":
return {
top: container.bottom + 8,
left: container.left + container.width / 2,
};
case "left":
return {
top: container.top + container.height / 2 - 16,
left: container.left - message.width - 8,
};
}
}
$: if (container && message) {
offset = calculateOffset(
position,
container.getBoundingClientRect(),
message.getBoundingClientRect()
);
}
</script>
<style>
.tooltip {
white-space: nowrap;
user-select: none;
background-color: var(--color-foreground);
color: var(--color-background);
text-align: center;
border-radius: 0.5rem;
padding: 4px 8px;
position: fixed;
pointer-events: none;
z-index: 100;
}
.tooltip.bottom,
.tooltip.top {
transform: translateX(-50%);
}
</style>
{#if value}
<div
{style}
bind:this={container}
on:mouseenter={() => setVisible(true)}
on:mouseleave={() => setVisible(false)}>
<slot />
{#if visible}
<div
bind:this={message}
class={`typo-text tooltip ${position}`}
style:top={`${offset.top}px`}
style:left={`${offset.left}px`}>
{value}
</div>
{/if}
</div>
{:else}
<slot />
{/if}