[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: show info-tooltips on mobile (#1268)

authored by

Alex Savelyev and committed by
GitHub
d2d893e6 ad0a6458

+93 -25
+4 -4
app/components/Package/Dependencies.vue
··· 95 95 {{ dep }} 96 96 </LinkBase> 97 97 <span class="flex items-center gap-1 max-w-[40%]" dir="ltr"> 98 - <span 98 + <TooltipApp 99 99 v-if="outdatedDeps[dep]" 100 - class="shrink-0" 100 + class="shrink-0 p-2 -m-2" 101 101 :class="getVersionClass(outdatedDeps[dep])" 102 - :title="getOutdatedTooltip(outdatedDeps[dep], $t)" 103 102 aria-hidden="true" 103 + :text="getOutdatedTooltip(outdatedDeps[dep], $t)" 104 104 > 105 105 <span class="i-carbon:warning-alt w-3 h-3" /> 106 - </span> 106 + </TooltipApp> 107 107 <LinkBase 108 108 v-if="getVulnerableDepInfo(dep)" 109 109 :to="packageRoute(dep, getVulnerableDepInfo(dep)!.version)"
+4 -4
app/components/Package/InstallScripts.vue
··· 115 115 {{ dep }} 116 116 </LinkBase> 117 117 <span class="flex items-center gap-1"> 118 - <span 118 + <TooltipApp 119 119 v-if=" 120 120 outdatedNpxDeps[dep] && 121 121 outdatedNpxDeps[dep].resolved !== outdatedNpxDeps[dep].latest 122 122 " 123 - class="shrink-0" 123 + class="shrink-0 p-2 -m-2" 124 124 :class="getVersionClass(outdatedNpxDeps[dep])" 125 - :title="getOutdatedTooltip(outdatedNpxDeps[dep], $t)" 126 125 aria-hidden="true" 126 + :text="getOutdatedTooltip(outdatedNpxDeps[dep], $t)" 127 127 > 128 128 <span class="i-carbon:warning-alt w-3 h-3" /> 129 - </span> 129 + </TooltipApp> 130 130 <span 131 131 class="font-mono text-xs text-end truncate" 132 132 :class="getVersionClass(outdatedNpxDeps[dep])"
+8 -4
app/components/Package/SkillsModal.vue
··· 164 164 aria-hidden="true" 165 165 /> 166 166 <span class="font-mono text-sm text-fg-muted">{{ skill.name }}</span> 167 - <span 167 + <TooltipApp 168 168 v-if="skill.warnings?.length" 169 - class="i-carbon:warning w-3.5 h-3.5 text-amber-500 shrink-0" 170 - :title="getWarningTooltip(skill)" 171 - /> 169 + class="shrink-0 p-2 -m-2" 170 + aria-hidden="true" 171 + :text="getWarningTooltip(skill)" 172 + to="#skills-modal" 173 + > 174 + <span class="i-carbon:warning w-3.5 h-3.5 text-amber-500" /> 175 + </TooltipApp> 172 176 </button> 173 177 174 178 <!-- Expandable details -->
+3
app/components/Tooltip/App.vue
··· 6 6 position?: 'top' | 'bottom' | 'left' | 'right' 7 7 /** Enable interactive tooltip (pointer events + hide delay for clickable content) */ 8 8 interactive?: boolean 9 + /** Teleport target for the tooltip content (defaults to 'body') */ 10 + to?: string | HTMLElement 9 11 }>() 10 12 11 13 const isVisible = shallowRef(false) ··· 48 50 :position 49 51 :interactive 50 52 :tooltip-attr="tooltipAttrs" 53 + :to="props.to" 51 54 @mouseenter="show" 52 55 @mouseleave="hide" 53 56 @focusin="show"
+20 -13
app/components/Tooltip/Base.vue
··· 3 3 import type { Placement } from '@floating-ui/vue' 4 4 import { autoUpdate, flip, offset, shift, useFloating } from '@floating-ui/vue' 5 5 6 - const props = defineProps<{ 7 - /** Tooltip text (optional when using content slot) */ 8 - text?: string 9 - /** Position: 'top' | 'bottom' | 'left' | 'right' */ 10 - position?: 'top' | 'bottom' | 'left' | 'right' 11 - /** is tooltip visible */ 12 - isVisible: boolean 13 - /** Allow pointer events on tooltip (for interactive content like links) */ 14 - interactive?: boolean 15 - /** attributes for tooltip element */ 16 - tooltipAttr?: HTMLAttributes 17 - }>() 6 + const props = withDefaults( 7 + defineProps<{ 8 + /** Tooltip text (optional when using content slot) */ 9 + text?: string 10 + /** Position: 'top' | 'bottom' | 'left' | 'right' */ 11 + position?: 'top' | 'bottom' | 'left' | 'right' 12 + /** is tooltip visible */ 13 + isVisible: boolean 14 + /** Allow pointer events on tooltip (for interactive content like links) */ 15 + interactive?: boolean 16 + /** attributes for tooltip element */ 17 + tooltipAttr?: HTMLAttributes 18 + /** Teleport target for the tooltip content (defaults to 'body') */ 19 + to?: string | HTMLElement 20 + }>(), 21 + { 22 + to: 'body', 23 + }, 24 + ) 18 25 19 26 const triggerRef = useTemplateRef('triggerRef') 20 27 const tooltipRef = useTemplateRef('tooltipRef') ··· 32 39 <div ref="triggerRef" class="inline-flex"> 33 40 <slot /> 34 41 35 - <Teleport to="body"> 42 + <Teleport :to="props.to"> 36 43 <Transition 37 44 enter-active-class="transition-opacity duration-150 motion-reduce:transition-none" 38 45 leave-active-class="transition-opacity duration-100 motion-reduce:transition-none"
+54
test/nuxt/components/Tooltip.spec.ts
··· 1 + import { describe, expect, it } from 'vitest' 2 + import { mountSuspended } from '@nuxt/test-utils/runtime' 3 + import TooltipBase from '~/components/Tooltip/Base.vue' 4 + 5 + describe('TooltipBase to prop', () => { 6 + it('teleports to body by default', async () => { 7 + await mountSuspended(TooltipBase, { 8 + props: { 9 + text: 'Tooltip text', 10 + isVisible: true, 11 + tooltipAttr: { 'aria-label': 'tooltip' }, 12 + }, 13 + slots: { 14 + default: '<button>Trigger</button>', 15 + }, 16 + }) 17 + 18 + const tooltip = document.querySelector<HTMLElement>('[aria-label="tooltip"]') 19 + expect(tooltip).not.toBeNull() 20 + expect(tooltip?.textContent).toContain('Tooltip text') 21 + 22 + const currentContainer = tooltip?.parentElement?.parentElement 23 + expect(currentContainer).toBe(document.body) 24 + }) 25 + 26 + it('teleports into provided container when using selector string', async () => { 27 + const container = document.createElement('div') 28 + container.id = 'tooltip-container' 29 + document.body.appendChild(container) 30 + 31 + try { 32 + await mountSuspended(TooltipBase, { 33 + props: { 34 + text: 'Tooltip text', 35 + isVisible: true, 36 + to: '#tooltip-container', 37 + tooltipAttr: { 'aria-label': 'tooltip' }, 38 + }, 39 + slots: { 40 + default: '<button>Trigger</button>', 41 + }, 42 + }) 43 + 44 + const tooltip = container.querySelector<HTMLElement>('[aria-label="tooltip"]') 45 + expect(tooltip).not.toBeNull() 46 + expect(tooltip?.textContent).toContain('Tooltip text') 47 + 48 + const currentContainer = tooltip?.parentElement?.parentElement 49 + expect(currentContainer).toBe(container) 50 + } finally { 51 + container.remove() 52 + } 53 + }) 54 + })