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:
Netfan
2024-12-10 17:37:06 +08:00
committed by GitHub
parent 018ddc75c6
commit e419b03cab
22 changed files with 271 additions and 31 deletions

View File

@@ -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,
)
"

View File

@@ -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>

View File

@@ -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) => {

View File

@@ -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>

View File

@@ -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>

View File

@@ -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',
},
},