[READ-ONLY] a fast, modern browser for the npm registry
at main 97 lines 2.3 kB view raw
1<script setup lang="ts"> 2const props = defineProps<{ 3 modalTitle: string 4}>() 5 6const dialogRef = useTemplateRef('dialogRef') 7 8const emit = defineEmits<{ 9 (e: 'transitioned'): void 10}>() 11 12const modalTitleId = computed(() => { 13 const id = getCurrentInstance()?.attrs.id 14 return id ? `${id}-title` : undefined 15}) 16 17function handleModalClose() { 18 dialogRef.value?.close() 19} 20 21/** 22 * Emits `transitioned` once the dialog has finished its open opacity transition. 23 * This is used by consumers that need to run layout-sensitive logic (for example 24 * dispatching a resize) only after the modal is fully displayed. 25 */ 26function onDialogTransitionEnd(event: TransitionEvent) { 27 const el = dialogRef.value 28 if (!el) return 29 if (!el.open) return 30 if (event.target !== el) return 31 if (event.propertyName !== 'opacity') return 32 emit('transitioned') 33} 34 35defineExpose({ 36 showModal: () => dialogRef.value?.showModal(), 37 close: () => dialogRef.value?.close(), 38}) 39</script> 40 41<template> 42 <Teleport to="body"> 43 <dialog 44 ref="dialogRef" 45 closedby="any" 46 class="w-[calc(100%-2rem)] bg-bg border border-border rounded-lg shadow-xl max-h-[90vh] overflow-y-auto overscroll-contain m-0 m-auto p-6 text-fg focus-visible:outline focus-visible:outline-accent/70" 47 :aria-labelledby="modalTitleId" 48 v-bind="$attrs" 49 @transitionend="onDialogTransitionEnd" 50 > 51 <!-- Modal top header section --> 52 <div class="flex items-center justify-between mb-6"> 53 <h2 :id="modalTitleId" class="font-mono text-lg font-medium"> 54 {{ modalTitle }} 55 </h2> 56 <ButtonBase 57 type="button" 58 :aria-label="$t('common.close')" 59 @click="handleModalClose" 60 classicon="i-lucide:x" 61 /> 62 </div> 63 <!-- Modal body content --> 64 <slot /> 65 </dialog> 66 </Teleport> 67</template> 68 69<style scoped> 70/* Backdrop styling when any of the modals are open */ 71dialog:modal::backdrop { 72 @apply bg-bg-elevated/70; 73} 74 75dialog::backdrop { 76 pointer-events: none; 77} 78 79/* Modal transition styles */ 80dialog { 81 opacity: 0; 82 transition: opacity 200ms ease; 83 transition-behavior: allow-discrete; 84} 85 86dialog:modal { 87 opacity: 1; 88 transition: opacity 200ms ease; 89 transition-behavior: allow-discrete; 90} 91 92@starting-style { 93 dialog:modal { 94 opacity: 0; 95 } 96} 97</style>