Files
pikasTech-HWLAB/web/hwlab-cloud-web/src/components/common/BaseDialog.vue
T

64 lines
2.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- SPEC: PJ2026-010405 云端控制台. -->
<!-- Implementation reference: draft-2026-07-13-p0-cloud-console. -->
<script setup lang="ts">
import { computed, ref, toRef } from "vue";
import { nextOverlayId, useOverlaySurface } from "@/composables/useOverlaySurface";
const props = withDefaults(defineProps<{
open: boolean;
title: string;
description?: string;
wide?: boolean;
closeOnBackdrop?: boolean;
busy?: boolean;
initialFocus?: string;
}>(), {
description: "",
wide: false,
closeOnBackdrop: true,
busy: false,
initialFocus: ""
});
const emit = defineEmits<{ close: [] }>();
const surface = ref<HTMLElement | null>(null);
const titleId = nextOverlayId("console-dialog-title");
const descriptionId = nextOverlayId("console-dialog-description");
const describedBy = computed(() => props.description ? descriptionId : undefined);
useOverlaySurface(toRef(props, "open"), surface, close, { initialFocusSelector: props.initialFocus || undefined });
function close(): void {
if (!props.busy) emit("close");
}
</script>
<template>
<Teleport to="body">
<div v-if="open" class="console-overlay-backdrop" role="presentation" @mousedown.self="closeOnBackdrop ? close() : undefined">
<section
ref="surface"
class="console-overlay-surface"
:data-wide="wide ? 'true' : 'false'"
role="dialog"
aria-modal="true"
:aria-labelledby="titleId"
:aria-describedby="describedBy"
:aria-busy="busy ? 'true' : 'false'"
tabindex="-1"
>
<header class="console-overlay-header">
<div class="console-overlay-title-stack">
<h2 :id="titleId">{{ title }}</h2>
<p v-if="description" :id="descriptionId">{{ description }}</p>
</div>
<button type="button" class="console-overlay-close" :disabled="busy" aria-label="关闭" @click="close">×</button>
</header>
<div class="console-overlay-body"><slot /></div>
<footer v-if="$slots.footer" class="console-overlay-footer"><slot name="footer" /></footer>
</section>
</div>
</Teleport>
</template>