You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and dots ('.'), can be up to 35 characters long. Letters must be lowercase.
84 lines
2.2 KiB
84 lines
2.2 KiB
<script setup> |
|
import { computed, onMounted, onUnmounted, ref } from 'vue'; |
|
|
|
const props = defineProps({ |
|
align: { |
|
type: String, |
|
default: 'right', |
|
}, |
|
width: { |
|
type: String, |
|
default: '48', |
|
}, |
|
contentClasses: { |
|
type: String, |
|
default: 'py-1 bg-white', |
|
}, |
|
}); |
|
|
|
const closeOnEscape = (e) => { |
|
if (open.value && e.key === 'Escape') { |
|
open.value = false; |
|
} |
|
}; |
|
|
|
onMounted(() => document.addEventListener('keydown', closeOnEscape)); |
|
onUnmounted(() => document.removeEventListener('keydown', closeOnEscape)); |
|
|
|
const widthClass = computed(() => { |
|
return { |
|
48: 'w-48', |
|
}[props.width.toString()]; |
|
}); |
|
|
|
const alignmentClasses = computed(() => { |
|
if (props.align === 'left') { |
|
return 'ltr:origin-top-left rtl:origin-top-right start-0'; |
|
} else if (props.align === 'right') { |
|
return 'ltr:origin-top-right rtl:origin-top-left end-0'; |
|
} else { |
|
return 'origin-top'; |
|
} |
|
}); |
|
|
|
const open = ref(false); |
|
</script> |
|
|
|
<template> |
|
<div class="relative"> |
|
<div @click="open = !open"> |
|
<slot name="trigger" /> |
|
</div> |
|
|
|
<!-- Full Screen Dropdown Overlay --> |
|
<div |
|
v-show="open" |
|
class="fixed inset-0 z-40" |
|
@click="open = false" |
|
></div> |
|
|
|
<Transition |
|
enter-active-class="transition ease-out duration-200" |
|
enter-from-class="opacity-0 scale-95" |
|
enter-to-class="opacity-100 scale-100" |
|
leave-active-class="transition ease-in duration-75" |
|
leave-from-class="opacity-100 scale-100" |
|
leave-to-class="opacity-0 scale-95" |
|
> |
|
<div |
|
v-show="open" |
|
class="absolute z-50 mt-2 rounded-md shadow-lg" |
|
:class="[widthClass, alignmentClasses]" |
|
style="display: none" |
|
@click="open = false" |
|
> |
|
<div |
|
class="rounded-md ring-1 ring-black ring-opacity-5" |
|
:class="contentClasses" |
|
> |
|
<slot name="content" /> |
|
</div> |
|
</div> |
|
</Transition> |
|
</div> |
|
</template>
|
|
|