fix: improve the display of modal and drawer on mobile (#4237)
This commit is contained in:
@@ -3,7 +3,7 @@ import type { ExtendedModalApi, ModalProps } from './modal';
|
||||
|
||||
import { computed, nextTick, ref, watch } from 'vue';
|
||||
|
||||
import { usePriorityValue } from '@vben-core/composables';
|
||||
import { useIsMobile, usePriorityValue } from '@vben-core/composables';
|
||||
import { Expand, Info, Shrink } from '@vben-core/icons';
|
||||
import {
|
||||
Dialog,
|
||||
@@ -46,6 +46,7 @@ const dialogRef = ref();
|
||||
const headerRef = ref();
|
||||
const footerRef = ref();
|
||||
|
||||
const { isMobile } = useIsMobile();
|
||||
// const { height: headerHeight } = useElementSize(headerRef);
|
||||
// const { height: footerHeight } = useElementSize(footerRef);
|
||||
const state = props.modalApi?.useStore?.();
|
||||
@@ -66,7 +67,11 @@ const draggable = usePriorityValue('draggable', props, state);
|
||||
const fullscreenButton = usePriorityValue('fullscreenButton', props, state);
|
||||
const closeOnClickModal = usePriorityValue('closeOnClickModal', props, state);
|
||||
const closeOnPressEscape = usePriorityValue('closeOnPressEscape', props, state);
|
||||
const shouldDraggable = computed(() => draggable.value && !fullscreen.value);
|
||||
|
||||
const shouldFullscreen = computed(() => fullscreen.value || isMobile.value);
|
||||
const shouldDraggable = computed(
|
||||
() => draggable.value && !shouldFullscreen.value,
|
||||
);
|
||||
|
||||
const { dragging } = useModalDraggable(dialogRef, headerRef, shouldDraggable);
|
||||
|
||||
@@ -114,6 +119,14 @@ function escapeKeyDown(e: KeyboardEvent) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
// pointer-down-outside
|
||||
function pointerDownOutside(e: Event) {
|
||||
const target = e.target as HTMLElement;
|
||||
const isDismissableModal = !!target?.dataset.dismissableModal;
|
||||
if (!closeOnClickModal.value || !isDismissableModal) {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<Dialog
|
||||
@@ -133,8 +146,8 @@ function escapeKeyDown(e: KeyboardEvent) {
|
||||
props.class,
|
||||
{
|
||||
'left-0 top-0 size-full max-h-full !translate-x-0 !translate-y-0':
|
||||
fullscreen,
|
||||
'top-1/2 -translate-y-1/2': centered && !fullscreen,
|
||||
shouldFullscreen,
|
||||
'top-1/2 -translate-y-1/2': centered && !shouldFullscreen,
|
||||
'duration-300': !dragging,
|
||||
},
|
||||
)
|
||||
@@ -143,6 +156,7 @@ function escapeKeyDown(e: KeyboardEvent) {
|
||||
close-class="top-4"
|
||||
@escape-key-down="escapeKeyDown"
|
||||
@interact-outside="interactOutside"
|
||||
@pointer-down-outside="pointerDownOutside"
|
||||
>
|
||||
<DialogHeader
|
||||
ref="headerRef"
|
||||
@@ -156,7 +170,7 @@ function escapeKeyDown(e: KeyboardEvent) {
|
||||
)
|
||||
"
|
||||
>
|
||||
<DialogTitle v-if="title">
|
||||
<DialogTitle v-if="title" class="text-left">
|
||||
<slot name="title">
|
||||
{{ title }}
|
||||
|
||||
@@ -191,7 +205,7 @@ function escapeKeyDown(e: KeyboardEvent) {
|
||||
|
||||
<VbenIconButton
|
||||
v-if="fullscreenButton"
|
||||
class="hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-10 top-4 size-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none"
|
||||
class="hover:bg-accent hover:text-accent-foreground text-foreground/80 flex-center absolute right-10 top-4 hidden size-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-none disabled:pointer-events-none sm:block"
|
||||
@click="handleFullscreen"
|
||||
>
|
||||
<Shrink v-if="fullscreen" class="size-3.5" />
|
||||
@@ -201,22 +215,22 @@ function escapeKeyDown(e: KeyboardEvent) {
|
||||
<DialogFooter
|
||||
v-if="showFooter"
|
||||
ref="footerRef"
|
||||
:class="cn('items-center border-t p-2', props.footerClass)"
|
||||
:class="
|
||||
cn(
|
||||
'flex-row items-center justify-end border-t p-2',
|
||||
props.footerClass,
|
||||
)
|
||||
"
|
||||
>
|
||||
<slot name="prepend-footer"></slot>
|
||||
<slot name="footer">
|
||||
<VbenButton
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
@click="() => modalApi?.onCancel()"
|
||||
>
|
||||
<VbenButton variant="ghost" @click="() => modalApi?.onCancel()">
|
||||
<slot name="cancelText">
|
||||
{{ cancelText }}
|
||||
</slot>
|
||||
</VbenButton>
|
||||
<VbenButton
|
||||
:loading="confirmLoading"
|
||||
size="sm"
|
||||
@click="() => modalApi?.onConfirm()"
|
||||
>
|
||||
<slot name="confirmText">
|
||||
|
@@ -94,7 +94,7 @@ async function checkProps(api: ExtendedModalApi, attrs: Record<string, any>) {
|
||||
if (stateKeys.has(attr)) {
|
||||
// connectedComponent存在时,不要传入Modal的props,会造成复杂度提升,如果你需要修改Modal的props,请使用 useModal 或者api
|
||||
console.warn(
|
||||
`[Vben Modal]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Modal, please use useModal or api.`,
|
||||
`[Vben Modal]: When 'connectedComponent' exists, do not set props or slots '${attr}', which will increase complexity. If you need to modify the props of Modal, please use useVbenModal or api.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user