<script setup lang="ts">
|
import type { AlertDialogContentEmits, AlertDialogContentProps } from 'reka-ui';
|
|
import type { ClassType } from '..\..\..\..\..\base\typings\src';
|
|
import { ref } from 'vue';
|
|
import { useScrollLock } from '..\..\..\..\..\composables\src';
|
import { cn } from '..\..\..\..\..\base\shared\src\utils';
|
|
import { reactiveOmit } from '@vueuse/core';
|
import {
|
AlertDialogContent,
|
AlertDialogOverlay,
|
AlertDialogPortal,
|
useForwardPropsEmits,
|
} from 'reka-ui';
|
|
defineOptions({
|
inheritAttrs: false,
|
});
|
|
const props = withDefaults(
|
defineProps<
|
AlertDialogContentProps & {
|
centered?: boolean;
|
class?: ClassType;
|
modal?: boolean;
|
open?: boolean;
|
overlayBlur?: number;
|
zIndex?: number;
|
}
|
>(),
|
{ modal: true },
|
);
|
const emits = defineEmits<
|
AlertDialogContentEmits & { close: []; closed: []; opened: [] }
|
>();
|
|
useScrollLock();
|
|
const delegatedProps = reactiveOmit(props, 'class');
|
|
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
|
const contentRef = ref<InstanceType<typeof AlertDialogContent> | null>(null);
|
function onAnimationEnd(event: AnimationEvent) {
|
// 只有在 contentRef 的动画结束时才触发 opened/closed 事件
|
if (event.target === contentRef.value?.$el) {
|
if (props.open) {
|
emits('opened');
|
} else {
|
emits('closed');
|
}
|
}
|
}
|
defineExpose({
|
getContentRef: () => contentRef.value,
|
});
|
</script>
|
|
<template>
|
<AlertDialogPortal>
|
<Transition name="fade" appear>
|
<AlertDialogOverlay
|
data-slot="alert-dialog-overlay"
|
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-popup bg-overlay"
|
v-if="open && modal"
|
:style="{
|
...(zIndex ? { zIndex } : {}),
|
position: 'fixed',
|
backdropFilter:
|
overlayBlur && overlayBlur > 0 ? `blur(${overlayBlur}px)` : 'none',
|
}"
|
@click="() => emits('close')"
|
/>
|
</Transition>
|
<AlertDialogContent
|
data-slot="alert-dialog-content"
|
ref="contentRef"
|
:style="{ ...(zIndex ? { zIndex } : {}), position: 'fixed' }"
|
@animationend="onAnimationEnd"
|
v-bind="{ ...$attrs, ...forwarded }"
|
:class="
|
cn(
|
'z-popup bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed left-[50%] w-full max-w-[calc(100%-2rem)] translate-x-[-50%] rounded-lg border p-6 shadow-lg duration-200 sm:max-w-lg',
|
{
|
'data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%]':
|
!centered,
|
'data-[state=closed]:slide-out-to-top-[148%] data-[state=open]:slide-in-from-top-[98%]':
|
centered,
|
'top-[10vh]': !centered,
|
'top-1/2 -translate-y-1/2': centered,
|
},
|
props.class,
|
)
|
"
|
>
|
<slot></slot>
|
</AlertDialogContent>
|
</AlertDialogPortal>
|
</template>
|