63 lines
1.9 KiB
Vue
63 lines
1.9 KiB
Vue
<script setup>
|
|
import { onBeforeUnmount, watch } from 'vue';
|
|
|
|
const props = defineProps({
|
|
open: { type: Boolean, default: false },
|
|
title: { type: String, default: 'Are you sure?' },
|
|
message: { type: String, default: '' },
|
|
confirmLabel: { type: String, default: 'Confirm' },
|
|
});
|
|
|
|
const emit = defineEmits(['confirm', 'cancel']);
|
|
|
|
const onKeydown = (event) => {
|
|
if (event.key === 'Escape') {
|
|
emit('cancel');
|
|
}
|
|
};
|
|
|
|
watch(
|
|
() => props.open,
|
|
(open) => {
|
|
if (open) {
|
|
document.addEventListener('keydown', onKeydown);
|
|
} else {
|
|
document.removeEventListener('keydown', onKeydown);
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
onBeforeUnmount(() => document.removeEventListener('keydown', onKeydown));
|
|
</script>
|
|
|
|
<template>
|
|
<div
|
|
v-if="open"
|
|
role="dialog"
|
|
aria-modal="true"
|
|
class="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/40 p-4"
|
|
>
|
|
<div class="w-full max-w-sm rounded-lg bg-white p-5 shadow-xl">
|
|
<h2 class="text-base font-semibold text-slate-900">{{ title }}</h2>
|
|
<p v-if="message" class="mt-1 text-sm text-slate-600">{{ message }}</p>
|
|
<div class="mt-4 flex justify-end gap-2">
|
|
<button
|
|
type="button"
|
|
class="rounded-md border border-slate-300 px-3 py-1.5 text-sm text-slate-700 hover:bg-slate-50"
|
|
@click="emit('cancel')"
|
|
>
|
|
Cancel
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="rounded-md bg-red-600 px-3 py-1.5 text-sm font-medium text-white hover:bg-red-500"
|
|
@click="emit('confirm')"
|
|
>
|
|
{{ confirmLabel }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|