First commit

This commit is contained in:
2026-08-10 04:29:24 -06:00
commit 26851fa750
71 changed files with 8333 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
<script setup lang="ts">
import { nextTick, onBeforeUnmount, onMounted, ref, useId, watch } from "vue";
import DsIconButton from "../actions/DsIconButton.vue";
const props = withDefaults(
defineProps<{
title: string;
description?: string;
closeLabel?: string;
closeOnBackdrop?: boolean;
}>(),
{
description: undefined,
closeLabel: "Cerrar diálogo",
closeOnBackdrop: true,
},
);
const model = defineModel<boolean>({ default: false });
const emit = defineEmits<{ close: []; cancel: [] }>();
const dialog = ref<HTMLDialogElement | null>(null);
const titleId = useId();
const descriptionId = useId();
let previousFocus: HTMLElement | null = null;
async function syncDialog(open: boolean) {
await nextTick();
if (open && dialog.value && !dialog.value.open) {
previousFocus = document.activeElement as HTMLElement | null;
dialog.value.showModal();
} else if (!open && dialog.value?.open) {
dialog.value.close();
previousFocus?.focus();
}
}
watch(model, syncDialog);
onMounted(() => syncDialog(model.value));
function requestClose(cancelled = false) {
model.value = false;
if (cancelled) emit("cancel");
emit("close");
}
function onCancel(event: Event) {
event.preventDefault();
requestClose(true);
}
function onBackdrop(event: MouseEvent) {
if (props.closeOnBackdrop && event.target === dialog.value)
requestClose(true);
}
onBeforeUnmount(() => {
if (dialog.value?.open) dialog.value.close();
});
</script>
<template>
<dialog
ref="dialog"
class="ds-dialog"
:aria-labelledby="titleId"
:aria-describedby="description ? descriptionId : undefined"
@cancel="onCancel"
@click="onBackdrop"
>
<div class="ds-dialog__header">
<div>
<h2 :id="titleId" class="ds-dialog__title">{{ title }}</h2>
<p
v-if="description"
:id="descriptionId"
class="ds-dialog__description"
>
{{ description }}
</p>
</div>
<DsIconButton :label="closeLabel" @click="requestClose(true)"
>×</DsIconButton
>
</div>
<div class="ds-dialog__body"><slot /></div>
<footer v-if="$slots.footer" class="ds-dialog__footer">
<slot name="footer" :close="requestClose" />
</footer>
</dialog>
</template>