优化FaDrawer/FaModal遮罩层

This commit is contained in:
Hooray
2025-02-05 10:04:33 +08:00
parent 6ed480cc2f
commit 871113e34f
4 changed files with 68 additions and 18 deletions
+11 -3
View File
@@ -73,6 +73,9 @@ const emits = defineEmits<{
'cancel': []
}>()
const id = useId()
provide('DrawerId', id)
const isOpen = ref(props.modelValue)
watch(() => props.modelValue, (newValue) => {
@@ -106,14 +109,16 @@ function handleFocusOutside(e: Event) {
}
function handleClickOutside(e: Event) {
if (!props.closeOnClickOverlay) {
if (!props.closeOnClickOverlay || (e.target as HTMLElement).dataset.drawerId !== id) {
e.preventDefault()
e.stopPropagation()
}
}
function handleEscapeKeyDown(e: KeyboardEvent) {
if (!props.closeOnPressEscape) {
e.preventDefault()
e.stopPropagation()
}
}
@@ -128,12 +133,15 @@ function handleAnimationEnd() {
</script>
<template>
<Sheet :modal="props.overlay" :open="isOpen" @update:open="updateOpen">
<Sheet :modal="false" :open="isOpen" @update:open="updateOpen">
<SheetContent
:closable="props.closable"
:open="isOpen"
:overlay="props.overlay"
:overlay-blur="props.overlayBlur"
class="w-full flex flex-col gap-0 p-0"
:side="props.side"
@open-auto-focus="handleFocusOutside"
@close-auto-focus="handleFocusOutside"
@focus-outside="handleFocusOutside"
@pointer-down-outside="handleClickOutside"
@@ -150,7 +158,7 @@ function handleAnimationEnd() {
<SheetTitle :class="{ 'text-center': props.centered }">
{{ title }}
</SheetTitle>
<SheetDescription v-if="!!description" :class="{ 'text-center': props.centered }">
<SheetDescription class="empty:hidden" :class="{ 'text-center': props.centered }">
{{ description }}
</SheetDescription>
</slot>
@@ -6,7 +6,6 @@ import {
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'radix-vue'
@@ -15,8 +14,10 @@ import { type SheetVariants, sheetVariants } from '.'
interface SheetContentProps extends DialogContentProps {
class?: HTMLAttributes['class']
open?: boolean
side?: SheetVariants['side']
closable?: boolean
overlay?: boolean
overlayBlur?: boolean
}
@@ -37,15 +38,31 @@ const delegatedProps = computed(() => {
})
const forwarded = useForwardPropsEmits(delegatedProps, emits)
const id = inject('DrawerId')
</script>
<template>
<DialogPortal>
<DialogOverlay
:class="cn('fixed inset-0 z-2000 data-[state=closed]:animate-out data-[state=open]:animate-in bg-black/50 data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0', {
'backdrop-blur-sm': props.overlayBlur,
})"
/>
<Transition
v-bind="{
enterActiveClass: 'ease-in-out duration-300',
enterFromClass: 'opacity-0',
enterToClass: 'opacity-100',
leaveActiveClass: 'ease-in-out duration-300',
leaveFromClass: 'opacity-100',
leaveToClass: 'opacity-0',
}"
:appear="true"
>
<div
v-if="props.open && props.overlay"
:data-drawer-id="id"
:class="cn('fixed inset-0 z-2000 data-[state=closed]:animate-out data-[state=open]:animate-in bg-black/50 data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0', {
'backdrop-blur-sm': props.overlayBlur,
})"
/>
</Transition>
<DialogContent
:class="cn(sheetVariants({ side }), props.class)"
v-bind="{ ...forwarded, ...$attrs }"
@@ -6,7 +6,6 @@ import {
DialogContent,
type DialogContentEmits,
type DialogContentProps,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'radix-vue'
@@ -14,9 +13,11 @@ import { computed, type HTMLAttributes } from 'vue'
const props = defineProps<DialogContentProps & {
class?: HTMLAttributes['class']
open?: boolean
maximize?: boolean
maximizable?: boolean
closable?: boolean
overlay?: boolean
overlayBlur?: boolean
}>()
const emits = defineEmits<DialogContentEmits & {
@@ -41,15 +42,31 @@ const dialogContentRef = useTemplateRef('dialogContentRef')
defineExpose({
el: dialogContentRef,
})
const id = inject('ModalId')
</script>
<template>
<DialogPortal>
<DialogOverlay
:class="cn('fixed inset-0 z-2000 data-[state=closed]:animate-out data-[state=open]:animate-in bg-black/50 data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0', {
'backdrop-blur-sm': props.overlayBlur,
})"
/>
<Transition
v-bind="{
enterActiveClass: 'ease-in-out duration-300',
enterFromClass: 'opacity-0',
enterToClass: 'opacity-100',
leaveActiveClass: 'ease-in-out duration-300',
leaveFromClass: 'opacity-100',
leaveToClass: 'opacity-0',
}"
:appear="true"
>
<div
v-if="props.open && props.overlay"
:data-modal-id="id"
:class="cn('fixed inset-0 z-2000 data-[state=closed]:animate-out data-[state=open]:animate-in bg-black/50 data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0', {
'backdrop-blur-sm': props.overlayBlur,
})"
/>
</Transition>
<DialogContent
ref="dialogContentRef"
v-bind="forwarded"
+11 -3
View File
@@ -60,6 +60,9 @@ defineExpose({
areaRef: dialogAreaRef,
})
const id = useId()
provide('ModalId', id)
const isOpen = ref(props.modelValue)
const isMaximize = ref(props.maximize)
@@ -119,14 +122,16 @@ function handleFocusOutside(e: Event) {
}
function handleClickOutside(e: Event) {
if (!props.closeOnClickOverlay) {
if (!props.closeOnClickOverlay || (e.target as HTMLElement).dataset.modalId !== id) {
e.preventDefault()
e.stopPropagation()
}
}
function handleEscapeKeyDown(e: KeyboardEvent) {
if (!props.closeOnPressEscape) {
e.preventDefault()
e.stopPropagation()
}
}
@@ -146,10 +151,12 @@ function handleAnimationEnd() {
</script>
<template>
<Dialog :modal="props.overlay" :open="isOpen" @update:open="updateOpen">
<Dialog :modal="false" :open="isOpen" @update:open="updateOpen">
<DialogContent
ref="dialogContentRef"
:open="isOpen"
:closable="props.closable"
:overlay="props.overlay"
:overlay-blur="props.overlayBlur"
:maximize="isMaximize"
:maximizable="props.maximizable"
@@ -158,6 +165,7 @@ function handleAnimationEnd() {
'md:top-1/2 md:-translate-y-1/2!': props.alignCenter,
'duration-0': isDragging,
})"
@open-auto-focus="handleFocusOutside"
@close-auto-focus="handleFocusOutside"
@focus-outside="handleFocusOutside"
@pointer-down-outside="handleClickOutside"
@@ -193,7 +201,7 @@ function handleAnimationEnd() {
/>
{{ title }}
</DialogTitle>
<DialogDescription v-if="!!description" :class="{ 'text-center': props.center }">
<DialogDescription class="empty:hidden" :class="{ 'text-center': props.center }">
{{ description }}
</DialogDescription>
</slot>