[READ-ONLY] a fast, modern browser for the npm registry
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(ui): prevent the tooltip from clipping in overflow containers (#756)

Co-authored-by: Daniel Roe <daniel@roe.dev>

authored by

Stephen Zhou
Daniel Roe
and committed by
GitHub
6a41d106 7fbf0469

+33 -22
+29 -22
app/components/Tooltip/Base.vue
··· 1 1 <script setup lang="ts"> 2 2 import type { HTMLAttributes } from 'vue' 3 + import type { Placement } from '@floating-ui/vue' 4 + import { autoUpdate, flip, offset, shift, useFloating } from '@floating-ui/vue' 3 5 4 6 const props = defineProps<{ 5 7 /** Tooltip text */ ··· 12 14 tooltipAttr?: HTMLAttributes 13 15 }>() 14 16 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') 19 + 20 + const placement = computed<Placement>(() => props.position || 'bottom') 21 21 22 - const tooltipPosition = computed(() => positionClasses[props.position || 'bottom']) 22 + const { floatingStyles } = useFloating(triggerRef, tooltipRef, { 23 + placement, 24 + whileElementsMounted: autoUpdate, 25 + middleware: [offset(4), flip(), shift({ padding: 8 })], 26 + }) 23 27 </script> 24 28 25 29 <template> 26 - <div class="relative inline-flex"> 30 + <div ref="triggerRef" class="inline-flex"> 27 31 <slot /> 28 32 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" 40 39 > 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> 44 51 </div> 45 52 </template>
+1
package.json
··· 40 40 "@atproto/lex": "0.0.13", 41 41 "@atproto/oauth-client-node": "^0.3.15", 42 42 "@deno/doc": "jsr:^0.189.1", 43 + "@floating-ui/vue": "1.1.10", 43 44 "@iconify-json/carbon": "1.2.18", 44 45 "@iconify-json/lucide": "1.2.87", 45 46 "@iconify-json/simple-icons": "1.2.68",
+3
pnpm-lock.yaml
··· 32 32 '@deno/doc': 33 33 specifier: jsr:^0.189.1 34 34 version: '@jsr/deno__doc@0.189.1(patch_hash=24f326e123c822a07976329a5afe91a8713e82d53134b5586625b72431c87832)' 35 + '@floating-ui/vue': 36 + specifier: 1.1.10 37 + version: 1.1.10(vue@3.5.27(typescript@5.9.3)) 35 38 '@iconify-json/carbon': 36 39 specifier: 1.2.18 37 40 version: 1.2.18