mirror of
https://github.com/vbenjs/vue-vben-admin.git
synced 2025-08-26 08:36:19 +08:00
feat: modal&drawer support appendToMain and zIndex (#5092)
* feat: modal/drawer support append to main content * feat: modal zIndex support * fix: drawer prop define * chore: type * fix: modal/drawer position fixed while append to body * docs: typo * chore: add full-width drawer in content area * chore: remove unnecessary class
This commit is contained in:
@@ -20,14 +20,16 @@ import DialogOverlay from './DialogOverlay.vue';
|
||||
const props = withDefaults(
|
||||
defineProps<
|
||||
{
|
||||
appendTo?: HTMLElement | string;
|
||||
class?: ClassType;
|
||||
closeClass?: ClassType;
|
||||
modal?: boolean;
|
||||
open?: boolean;
|
||||
showClose?: boolean;
|
||||
zIndex?: number;
|
||||
} & DialogContentProps
|
||||
>(),
|
||||
{ showClose: true },
|
||||
{ appendTo: 'body', showClose: true, zIndex: 1000 },
|
||||
);
|
||||
const emits = defineEmits<
|
||||
{ close: []; closed: []; opened: [] } & DialogContentEmits
|
||||
@@ -45,6 +47,18 @@ const delegatedProps = computed(() => {
|
||||
return delegated;
|
||||
});
|
||||
|
||||
function isAppendToBody() {
|
||||
return (
|
||||
props.appendTo === 'body' ||
|
||||
props.appendTo === document.body ||
|
||||
!props.appendTo
|
||||
);
|
||||
}
|
||||
|
||||
const position = computed(() => {
|
||||
return isAppendToBody() ? 'fixed' : 'absolute';
|
||||
});
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
|
||||
const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
|
||||
@@ -64,17 +78,22 @@ defineExpose({
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogPortal>
|
||||
<DialogPortal :to="appendTo">
|
||||
<Transition name="fade">
|
||||
<DialogOverlay v-if="open && modal" @click="() => emits('close')" />
|
||||
<DialogOverlay
|
||||
v-if="open && modal"
|
||||
:style="{ zIndex, position }"
|
||||
@click="() => emits('close')"
|
||||
/>
|
||||
</Transition>
|
||||
<DialogContent
|
||||
ref="contentRef"
|
||||
:style="{ zIndex, position }"
|
||||
@animationend="onAnimationEnd"
|
||||
v-bind="forwarded"
|
||||
:class="
|
||||
cn(
|
||||
'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 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%] fixed z-[1000] w-full p-6 shadow-lg outline-none sm:rounded-xl',
|
||||
'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 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-top-[48%] w-full p-6 shadow-lg outline-none sm:rounded-xl',
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
|
@@ -7,8 +7,5 @@ useScrollLock();
|
||||
const id = inject('DISMISSABLE_MODAL_ID');
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
:data-dismissable-modal="id"
|
||||
class="bg-overlay fixed inset-0 z-[1000]"
|
||||
></div>
|
||||
<div :data-dismissable-modal="id" class="bg-overlay inset-0"></div>
|
||||
</template>
|
||||
|
@@ -14,7 +14,10 @@ import {
|
||||
useForwardPropsEmits,
|
||||
} from 'radix-vue';
|
||||
|
||||
const props = defineProps<{ class?: any } & DialogContentProps>();
|
||||
const props = withDefaults(
|
||||
defineProps<{ class?: any; zIndex?: number } & DialogContentProps>(),
|
||||
{ zIndex: 1000 },
|
||||
);
|
||||
const emits = defineEmits<DialogContentEmits>();
|
||||
|
||||
const delegatedProps = computed(() => {
|
||||
@@ -29,7 +32,8 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
<template>
|
||||
<DialogPortal>
|
||||
<DialogOverlay
|
||||
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 border-border fixed inset-0 z-[1000] grid place-items-center overflow-y-auto border bg-black/80"
|
||||
:style="{ zIndex }"
|
||||
class="data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 border-border absolute inset-0 grid place-items-center overflow-y-auto border bg-black/80"
|
||||
>
|
||||
<DialogContent
|
||||
:class="
|
||||
@@ -38,6 +42,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
props.class,
|
||||
)
|
||||
"
|
||||
:style="{ zIndex }"
|
||||
v-bind="forwarded"
|
||||
@pointer-down-outside="
|
||||
(event) => {
|
||||
|
@@ -15,17 +15,22 @@ import { type SheetVariants, sheetVariants } from './sheet';
|
||||
import SheetOverlay from './SheetOverlay.vue';
|
||||
|
||||
interface SheetContentProps extends DialogContentProps {
|
||||
appendTo?: HTMLElement | string;
|
||||
class?: any;
|
||||
modal?: boolean;
|
||||
open?: boolean;
|
||||
side?: SheetVariants['side'];
|
||||
zIndex?: number;
|
||||
}
|
||||
|
||||
defineOptions({
|
||||
inheritAttrs: false,
|
||||
});
|
||||
|
||||
const props = defineProps<SheetContentProps>();
|
||||
const props = withDefaults(defineProps<SheetContentProps>(), {
|
||||
appendTo: 'body',
|
||||
zIndex: 1000,
|
||||
});
|
||||
|
||||
const emits = defineEmits<DialogContentEmits>();
|
||||
|
||||
@@ -41,16 +46,29 @@ const delegatedProps = computed(() => {
|
||||
return delegated;
|
||||
});
|
||||
|
||||
function isAppendToBody() {
|
||||
return (
|
||||
props.appendTo === 'body' ||
|
||||
props.appendTo === document.body ||
|
||||
!props.appendTo
|
||||
);
|
||||
}
|
||||
|
||||
const position = computed(() => {
|
||||
return isAppendToBody() ? 'fixed' : 'absolute';
|
||||
});
|
||||
|
||||
const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<DialogPortal>
|
||||
<DialogPortal :to="appendTo">
|
||||
<Transition name="fade">
|
||||
<SheetOverlay v-if="open && modal" />
|
||||
<SheetOverlay v-if="open && modal" :style="{ zIndex, position }" />
|
||||
</Transition>
|
||||
<DialogContent
|
||||
:class="cn(sheetVariants({ side }), 'z-[1000]', props.class)"
|
||||
:class="cn(sheetVariants({ side }), props.class)"
|
||||
:style="{ zIndex, position }"
|
||||
v-bind="{ ...forwarded, ...$attrs }"
|
||||
>
|
||||
<slot></slot>
|
||||
|
@@ -7,8 +7,5 @@ useScrollLock();
|
||||
const id = inject('DISMISSABLE_DRAWER_ID');
|
||||
</script>
|
||||
<template>
|
||||
<div
|
||||
:data-dismissable-drawer="id"
|
||||
class="bg-overlay fixed inset-0 z-[1000]"
|
||||
></div>
|
||||
<div :data-dismissable-drawer="id" class="bg-overlay inset-0"></div>
|
||||
</template>
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
export const sheetVariants = cva(
|
||||
'fixed z-[1000] bg-background shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 border-border',
|
||||
'bg-background shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 border-border',
|
||||
{
|
||||
defaultVariants: {
|
||||
side: 'right',
|
||||
@@ -12,7 +12,7 @@ export const sheetVariants = cva(
|
||||
'inset-x-0 bottom-0 border-t border-border data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
|
||||
left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left ',
|
||||
right:
|
||||
'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right',
|
||||
'inset-y-0 right-0 w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right',
|
||||
top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
|
||||
},
|
||||
},
|
||||
|
Reference in New Issue
Block a user