Skip to content

Commit 6a41d10

Browse files
hyobandanielroe
andauthored
fix(ui): prevent the tooltip from clipping in overflow containers (#756)
Co-authored-by: Daniel Roe <daniel@roe.dev>
1 parent 7fbf046 commit 6a41d10

File tree

3 files changed

+33
-22
lines changed

3 files changed

+33
-22
lines changed

app/components/Tooltip/Base.vue

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<script setup lang="ts">
22
import type { HTMLAttributes } from 'vue'
3+
import type { Placement } from '@floating-ui/vue'
4+
import { autoUpdate, flip, offset, shift, useFloating } from '@floating-ui/vue'
35
46
const props = defineProps<{
57
/** Tooltip text */
@@ -12,34 +14,39 @@ const props = defineProps<{
1214
tooltipAttr?: HTMLAttributes
1315
}>()
1416
15-
const positionClasses: Record<string, string> = {
16-
top: 'bottom-full inset-is-1/2 -translate-x-1/2 mb-1',
17-
bottom: 'top-full inset-is-0 mt-1',
18-
left: 'inset-ie-full top-1/2 -translate-y-1/2 me-2',
19-
right: 'inset-is-full top-1/2 -translate-y-1/2 ms-2',
20-
}
17+
const triggerRef = useTemplateRef('triggerRef')
18+
const tooltipRef = useTemplateRef('tooltipRef')
2119
22-
const tooltipPosition = computed(() => positionClasses[props.position || 'bottom'])
20+
const placement = computed<Placement>(() => props.position || 'bottom')
21+
22+
const { floatingStyles } = useFloating(triggerRef, tooltipRef, {
23+
placement,
24+
whileElementsMounted: autoUpdate,
25+
middleware: [offset(4), flip(), shift({ padding: 8 })],
26+
})
2327
</script>
2428

2529
<template>
26-
<div class="relative inline-flex">
30+
<div ref="triggerRef" class="inline-flex">
2731
<slot />
2832

29-
<Transition
30-
enter-active-class="transition-opacity duration-150 motion-reduce:transition-none"
31-
leave-active-class="transition-opacity duration-100 motion-reduce:transition-none"
32-
enter-from-class="opacity-0"
33-
leave-to-class="opacity-0"
34-
>
35-
<div
36-
v-if="props.isVisible"
37-
class="absolute px-2 py-1 font-mono text-xs text-fg bg-bg-elevated border border-border rounded shadow-lg whitespace-nowrap z-[100] pointer-events-none"
38-
:class="tooltipPosition"
39-
v-bind="tooltipAttr"
33+
<Teleport to="body">
34+
<Transition
35+
enter-active-class="transition-opacity duration-150 motion-reduce:transition-none"
36+
leave-active-class="transition-opacity duration-100 motion-reduce:transition-none"
37+
enter-from-class="opacity-0"
38+
leave-to-class="opacity-0"
4039
>
41-
{{ text }}
42-
</div>
43-
</Transition>
40+
<div
41+
v-if="props.isVisible"
42+
ref="tooltipRef"
43+
class="px-2 py-1 font-mono text-xs text-fg bg-bg-elevated border border-border rounded shadow-lg whitespace-nowrap z-[100] pointer-events-none"
44+
:style="floatingStyles"
45+
v-bind="tooltipAttr"
46+
>
47+
{{ text }}
48+
</div>
49+
</Transition>
50+
</Teleport>
4451
</div>
4552
</template>

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"@atproto/lex": "0.0.13",
4141
"@atproto/oauth-client-node": "^0.3.15",
4242
"@deno/doc": "jsr:^0.189.1",
43+
"@floating-ui/vue": "1.1.10",
4344
"@iconify-json/carbon": "1.2.18",
4445
"@iconify-json/lucide": "1.2.87",
4546
"@iconify-json/simple-icons": "1.2.68",

pnpm-lock.yaml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)