11<script setup lang="ts">
2+ import { onKeyDown } from ' @vueuse/core'
3+ import { UseFocusTrap } from ' @vueuse/integrations/useFocusTrap/component'
4+
25defineProps <{
36 /** Dependency path from root to vulnerable package (readonly from VulnerabilityTreeResult) */
47 path: readonly string []
@@ -17,13 +20,16 @@ onClickOutside(popupEl, () => {
1720 if (isOpen .value ) closePopup ()
1821})
1922
20- // Close popup on ESC or scroll
21- function handleKeydown(e : KeyboardEvent ) {
22- if (e .key === ' Escape' ) closePopup ()
23- }
23+ onKeyDown (
24+ ' Escape' ,
25+ e => {
26+ e .preventDefault ()
27+ closePopup ()
28+ },
29+ { dedupe: true , target: popupEl },
30+ )
2431
25- useEventListener (document , ' keydown' , handleKeydown )
26- useEventListener (' scroll' , closePopup , true )
32+ useEventListener (' scroll' , closePopup , { passive: true })
2733
2834function togglePopup(event : MouseEvent ) {
2935 if (isOpen .value ) {
@@ -77,34 +83,36 @@ function parsePackageString(pkg: string): { name: string; version: string } {
7783 class =" fixed z-[100] bg-bg-elevated border border-border rounded-lg shadow-xl p-3 min-w-64 max-w-sm"
7884 :style =" getPopupStyle()"
7985 >
80- <ul class =" list-none m-0 p-0 space-y-0.5" >
81- <li
82- v-for =" (pathItem, idx) in path"
83- :key =" idx"
84- class =" font-mono text-xs"
85- :style =" { paddingLeft: `${idx * 12}px` }"
86- >
87- <span v-if =" idx > 0" class =" text-fg-subtle me-1" >└─</span >
88- <NuxtLink
89- :to =" {
90- name: 'package',
91- params: {
92- package: [
93- ...parsePackageString(pathItem).name.split('/'),
94- 'v',
95- parsePackageString(pathItem).version,
96- ],
97- },
98- }"
99- class =" hover:underline"
100- :class =" idx === path.length - 1 ? 'text-fg font-medium' : 'text-fg-muted'"
101- @click =" closePopup"
86+ <UseFocusTrap :options =" { immediate: true }" >
87+ <ul class =" list-none m-0 p-0 space-y-0.5" >
88+ <li
89+ v-for =" (pathItem, idx) in path"
90+ :key =" idx"
91+ class =" font-mono text-xs"
92+ :style =" { paddingLeft: `${idx * 12}px` }"
10293 >
103- {{ pathItem }}
104- </NuxtLink >
105- <span v-if =" idx === path.length - 1" class =" ms-1 text-amber-500" >⚠</span >
106- </li >
107- </ul >
94+ <span v-if =" idx > 0" class =" text-fg-subtle me-1" >└─</span >
95+ <NuxtLink
96+ :to =" {
97+ name: 'package',
98+ params: {
99+ package: [
100+ ...parsePackageString(pathItem).name.split('/'),
101+ 'v',
102+ parsePackageString(pathItem).version,
103+ ],
104+ },
105+ }"
106+ class =" hover:underline"
107+ :class =" idx === path.length - 1 ? 'text-fg font-medium' : 'text-fg-muted'"
108+ @click =" closePopup"
109+ >
110+ {{ pathItem }}
111+ </NuxtLink >
112+ <span v-if =" idx === path.length - 1" class =" ms-1 text-amber-500" >⚠</span >
113+ </li >
114+ </ul >
115+ </UseFocusTrap >
108116 </div >
109117 </div >
110118</template >
0 commit comments