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 classpull/58/MERGE
parent
018ddc75c6
commit
e419b03cab
|
@ -74,6 +74,7 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||||
|
|
||||||
| 属性名 | 描述 | 类型 | 默认值 |
|
| 属性名 | 描述 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
|
| appendToMain | 是否挂载到内容区域(默认挂载到body) | `boolean` | `false` |
|
||||||
| title | 标题 | `string\|slot` | - |
|
| title | 标题 | `string\|slot` | - |
|
||||||
| titleTooltip | 标题提示信息 | `string\|slot` | - |
|
| titleTooltip | 标题提示信息 | `string\|slot` | - |
|
||||||
| description | 描述信息 | `string\|slot` | - |
|
| description | 描述信息 | `string\|slot` | - |
|
||||||
|
@ -95,6 +96,13 @@ const [Drawer, drawerApi] = useVbenDrawer({
|
||||||
| contentClass | modal内容区域的class | `string` | - |
|
| contentClass | modal内容区域的class | `string` | - |
|
||||||
| footerClass | modal底部区域的class | `string` | - |
|
| footerClass | modal底部区域的class | `string` | - |
|
||||||
| headerClass | modal顶部区域的class | `string` | - |
|
| headerClass | modal顶部区域的class | `string` | - |
|
||||||
|
| zIndex | 抽屉的ZIndex层级 | `number` | `1000` |
|
||||||
|
|
||||||
|
::: info appendToMain
|
||||||
|
|
||||||
|
`appendToMain`可以指定将抽屉挂载到内容区域,打开抽屉时,内容区域以外的部分(标签栏、导航菜单等等)不会被遮挡。默认情况下,抽屉会挂载到body上。但是:挂载到内容区域时,作为页面根容器的`Page`组件,需要设置`auto-content-height`属性,以便抽屉能够正确计算高度。
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
### Event
|
### Event
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,7 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
|
|
||||||
| 属性名 | 描述 | 类型 | 默认值 |
|
| 属性名 | 描述 | 类型 | 默认值 |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
|
| appendToMain | 是否挂载到内容区域(默认挂载到body) | `boolean` | `false` |
|
||||||
| title | 标题 | `string\|slot` | - |
|
| title | 标题 | `string\|slot` | - |
|
||||||
| titleTooltip | 标题提示信息 | `string\|slot` | - |
|
| titleTooltip | 标题提示信息 | `string\|slot` | - |
|
||||||
| description | 描述信息 | `string\|slot` | - |
|
| description | 描述信息 | `string\|slot` | - |
|
||||||
|
@ -106,6 +107,13 @@ const [Modal, modalApi] = useVbenModal({
|
||||||
| footerClass | modal底部区域的class | `string` | - |
|
| footerClass | modal底部区域的class | `string` | - |
|
||||||
| headerClass | modal顶部区域的class | `string` | - |
|
| headerClass | modal顶部区域的class | `string` | - |
|
||||||
| bordered | 是否显示border | `boolean` | `false` |
|
| bordered | 是否显示border | `boolean` | `false` |
|
||||||
|
| zIndex | 弹窗的ZIndex层级 | `number` | `1000` |
|
||||||
|
|
||||||
|
::: info appendToMain
|
||||||
|
|
||||||
|
`appendToMain`可以指定将弹窗挂载到内容区域,打开带这招的弹窗时,内容区域以外的部分(标签栏、导航菜单等等)不会被遮挡。默认情况下,弹窗会挂载到body上。但是:挂载到内容区域时,作为页面根容器的`Page`组件,需要设置`auto-content-height`属性,以便弹窗能够正确计算高度。
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
### Event
|
### Event
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ export const CSS_VARIABLE_LAYOUT_HEADER_HEIGHT = `--vben-header-height`;
|
||||||
/** layout footer 组件的高度 */
|
/** layout footer 组件的高度 */
|
||||||
export const CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT = `--vben-footer-height`;
|
export const CSS_VARIABLE_LAYOUT_FOOTER_HEIGHT = `--vben-footer-height`;
|
||||||
|
|
||||||
|
/** 内容区域的组件ID */
|
||||||
|
export const ELEMENT_ID_MAIN_CONTENT = `__vben_main_content`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @zh_CN 默认命名空间
|
* @zh_CN 默认命名空间
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
"@vben-core/composables": "workspace:*",
|
"@vben-core/composables": "workspace:*",
|
||||||
"@vben-core/icons": "workspace:*",
|
"@vben-core/icons": "workspace:*",
|
||||||
"@vben-core/shadcn-ui": "workspace:*",
|
"@vben-core/shadcn-ui": "workspace:*",
|
||||||
|
"@vben-core/shared": "workspace:*",
|
||||||
"@vben-core/typings": "workspace:*",
|
"@vben-core/typings": "workspace:*",
|
||||||
"@vueuse/core": "catalog:",
|
"@vueuse/core": "catalog:",
|
||||||
"vue": "catalog:"
|
"vue": "catalog:"
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
} from '@vben-core/composables';
|
} from '@vben-core/composables';
|
||||||
import { Menu } from '@vben-core/icons';
|
import { Menu } from '@vben-core/icons';
|
||||||
import { VbenIconButton } from '@vben-core/shadcn-ui';
|
import { VbenIconButton } from '@vben-core/shadcn-ui';
|
||||||
|
import { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';
|
||||||
|
|
||||||
import { useMouse, useScroll, useThrottleFn } from '@vueuse/core';
|
import { useMouse, useScroll, useThrottleFn } from '@vueuse/core';
|
||||||
|
|
||||||
|
@ -457,6 +458,8 @@ function handleHeaderToggle() {
|
||||||
emit('toggleSidebar');
|
emit('toggleSidebar');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const idMainContent = ELEMENT_ID_MAIN_CONTENT;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -553,6 +556,7 @@ function handleHeaderToggle() {
|
||||||
|
|
||||||
<!-- </div> -->
|
<!-- </div> -->
|
||||||
<LayoutContent
|
<LayoutContent
|
||||||
|
:id="idMainContent"
|
||||||
:content-compact="contentCompact"
|
:content-compact="contentCompact"
|
||||||
:content-compact-width="contentCompactWidth"
|
:content-compact-width="contentCompactWidth"
|
||||||
:padding="contentPadding"
|
:padding="contentPadding"
|
||||||
|
|
|
@ -7,6 +7,11 @@ import type { Component, Ref } from 'vue';
|
||||||
export type DrawerPlacement = 'bottom' | 'left' | 'right' | 'top';
|
export type DrawerPlacement = 'bottom' | 'left' | 'right' | 'top';
|
||||||
|
|
||||||
export interface DrawerProps {
|
export interface DrawerProps {
|
||||||
|
/**
|
||||||
|
* 是否挂载到内容区域
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
appendToMain?: boolean;
|
||||||
/**
|
/**
|
||||||
* 取消按钮文字
|
* 取消按钮文字
|
||||||
*/
|
*/
|
||||||
|
@ -59,12 +64,12 @@ export interface DrawerProps {
|
||||||
* 弹窗头部样式
|
* 弹窗头部样式
|
||||||
*/
|
*/
|
||||||
headerClass?: ClassType;
|
headerClass?: ClassType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 弹窗是否显示
|
* 弹窗是否显示
|
||||||
* @default false
|
* @default false
|
||||||
*/
|
*/
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否显示遮罩
|
* 是否显示遮罩
|
||||||
* @default true
|
* @default true
|
||||||
|
@ -74,12 +79,12 @@ export interface DrawerProps {
|
||||||
* 是否自动聚焦
|
* 是否自动聚焦
|
||||||
*/
|
*/
|
||||||
openAutoFocus?: boolean;
|
openAutoFocus?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 抽屉位置
|
* 抽屉位置
|
||||||
* @default right
|
* @default right
|
||||||
*/
|
*/
|
||||||
placement?: DrawerPlacement;
|
placement?: DrawerPlacement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否显示取消按钮
|
* 是否显示取消按钮
|
||||||
* @default true
|
* @default true
|
||||||
|
@ -98,6 +103,10 @@ export interface DrawerProps {
|
||||||
* 弹窗标题提示
|
* 弹窗标题提示
|
||||||
*/
|
*/
|
||||||
titleTooltip?: string;
|
titleTooltip?: string;
|
||||||
|
/**
|
||||||
|
* 抽屉层级
|
||||||
|
*/
|
||||||
|
zIndex?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DrawerState extends DrawerProps {
|
export interface DrawerState extends DrawerProps {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { DrawerProps, ExtendedDrawerApi } from './drawer';
|
import type { DrawerProps, ExtendedDrawerApi } from './drawer';
|
||||||
|
|
||||||
import { provide, ref, useId, watch } from 'vue';
|
import { computed, provide, ref, useId, watch } from 'vue';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
useIsMobile,
|
useIsMobile,
|
||||||
|
@ -23,6 +23,7 @@ import {
|
||||||
VbenLoading,
|
VbenLoading,
|
||||||
VisuallyHidden,
|
VisuallyHidden,
|
||||||
} from '@vben-core/shadcn-ui';
|
} from '@vben-core/shadcn-ui';
|
||||||
|
import { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';
|
||||||
import { globalShareState } from '@vben-core/shared/global-state';
|
import { globalShareState } from '@vben-core/shared/global-state';
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
@ -31,7 +32,9 @@ interface Props extends DrawerProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
appendToMain: false,
|
||||||
drawerApi: undefined,
|
drawerApi: undefined,
|
||||||
|
zIndex: 1000,
|
||||||
});
|
});
|
||||||
|
|
||||||
const components = globalShareState.getComponents();
|
const components = globalShareState.getComponents();
|
||||||
|
@ -46,6 +49,7 @@ const { isMobile } = useIsMobile();
|
||||||
const state = props.drawerApi?.useStore?.();
|
const state = props.drawerApi?.useStore?.();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
appendToMain,
|
||||||
cancelText,
|
cancelText,
|
||||||
class: drawerClass,
|
class: drawerClass,
|
||||||
closable,
|
closable,
|
||||||
|
@ -67,6 +71,7 @@ const {
|
||||||
showConfirmButton,
|
showConfirmButton,
|
||||||
title,
|
title,
|
||||||
titleTooltip,
|
titleTooltip,
|
||||||
|
zIndex,
|
||||||
} = usePriorityValues(props, state);
|
} = usePriorityValues(props, state);
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
|
@ -110,6 +115,10 @@ function handleFocusOutside(e: Event) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getAppendTo = computed(() => {
|
||||||
|
return appendToMain.value ? `#${ELEMENT_ID_MAIN_CONTENT}` : undefined;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Sheet
|
<Sheet
|
||||||
|
@ -118,6 +127,7 @@ function handleFocusOutside(e: Event) {
|
||||||
@update:open="() => drawerApi?.close()"
|
@update:open="() => drawerApi?.close()"
|
||||||
>
|
>
|
||||||
<SheetContent
|
<SheetContent
|
||||||
|
:append-to="getAppendTo"
|
||||||
:class="
|
:class="
|
||||||
cn('flex w-[520px] flex-col', drawerClass, {
|
cn('flex w-[520px] flex-col', drawerClass, {
|
||||||
'!w-full': isMobile || placement === 'bottom' || placement === 'top',
|
'!w-full': isMobile || placement === 'bottom' || placement === 'top',
|
||||||
|
@ -127,6 +137,7 @@ function handleFocusOutside(e: Event) {
|
||||||
:modal="modal"
|
:modal="modal"
|
||||||
:open="state?.isOpen"
|
:open="state?.isOpen"
|
||||||
:side="placement"
|
:side="placement"
|
||||||
|
:z-index="zIndex"
|
||||||
@close-auto-focus="handleFocusOutside"
|
@close-auto-focus="handleFocusOutside"
|
||||||
@escape-key-down="escapeKeyDown"
|
@escape-key-down="escapeKeyDown"
|
||||||
@focus-outside="handleFocusOutside"
|
@focus-outside="handleFocusOutside"
|
||||||
|
|
|
@ -3,6 +3,11 @@ import type { ModalApi } from './modal-api';
|
||||||
import type { Component, Ref } from 'vue';
|
import type { Component, Ref } from 'vue';
|
||||||
|
|
||||||
export interface ModalProps {
|
export interface ModalProps {
|
||||||
|
/**
|
||||||
|
* 是否要挂载到内容区域
|
||||||
|
* @default false
|
||||||
|
*/
|
||||||
|
appendToMain?: boolean;
|
||||||
/**
|
/**
|
||||||
* 是否显示边框
|
* 是否显示边框
|
||||||
* @default false
|
* @default false
|
||||||
|
@ -12,7 +17,6 @@ export interface ModalProps {
|
||||||
* 取消按钮文字
|
* 取消按钮文字
|
||||||
*/
|
*/
|
||||||
cancelText?: string;
|
cancelText?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否居中
|
* 是否居中
|
||||||
* @default false
|
* @default false
|
||||||
|
@ -20,6 +24,7 @@ export interface ModalProps {
|
||||||
centered?: boolean;
|
centered?: boolean;
|
||||||
|
|
||||||
class?: string;
|
class?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否显示右上角的关闭按钮
|
* 是否显示右上角的关闭按钮
|
||||||
* @default true
|
* @default true
|
||||||
|
@ -112,6 +117,10 @@ export interface ModalProps {
|
||||||
* 弹窗标题提示
|
* 弹窗标题提示
|
||||||
*/
|
*/
|
||||||
titleTooltip?: string;
|
titleTooltip?: string;
|
||||||
|
/**
|
||||||
|
* 弹窗层级
|
||||||
|
*/
|
||||||
|
zIndex?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModalState extends ModalProps {
|
export interface ModalState extends ModalProps {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import {
|
||||||
VbenLoading,
|
VbenLoading,
|
||||||
VisuallyHidden,
|
VisuallyHidden,
|
||||||
} from '@vben-core/shadcn-ui';
|
} from '@vben-core/shadcn-ui';
|
||||||
|
import { ELEMENT_ID_MAIN_CONTENT } from '@vben-core/shared/constants';
|
||||||
import { globalShareState } from '@vben-core/shared/global-state';
|
import { globalShareState } from '@vben-core/shared/global-state';
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ interface Props extends ModalProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
appendToMain: false,
|
||||||
modalApi: undefined,
|
modalApi: undefined,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -52,6 +54,7 @@ const { isMobile } = useIsMobile();
|
||||||
const state = props.modalApi?.useStore?.();
|
const state = props.modalApi?.useStore?.();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
appendToMain,
|
||||||
bordered,
|
bordered,
|
||||||
cancelText,
|
cancelText,
|
||||||
centered,
|
centered,
|
||||||
|
@ -78,6 +81,7 @@ const {
|
||||||
showConfirmButton,
|
showConfirmButton,
|
||||||
title,
|
title,
|
||||||
titleTooltip,
|
titleTooltip,
|
||||||
|
zIndex,
|
||||||
} = usePriorityValues(props, state);
|
} = usePriorityValues(props, state);
|
||||||
|
|
||||||
const shouldFullscreen = computed(
|
const shouldFullscreen = computed(
|
||||||
|
@ -161,6 +165,9 @@ function handleFocusOutside(e: Event) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
}
|
}
|
||||||
|
const getAppendTo = computed(() => {
|
||||||
|
return appendToMain.value ? `#${ELEMENT_ID_MAIN_CONTENT}` : undefined;
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<Dialog
|
<Dialog
|
||||||
|
@ -170,6 +177,7 @@ function handleFocusOutside(e: Event) {
|
||||||
>
|
>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
ref="contentRef"
|
ref="contentRef"
|
||||||
|
:append-to="getAppendTo"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
cn(
|
||||||
'left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col p-0 sm:rounded-[var(--radius)]',
|
'left-0 right-0 top-[10vh] mx-auto flex max-h-[80%] w-[520px] flex-col p-0 sm:rounded-[var(--radius)]',
|
||||||
|
@ -187,6 +195,7 @@ function handleFocusOutside(e: Event) {
|
||||||
:modal="modal"
|
:modal="modal"
|
||||||
:open="state?.isOpen"
|
:open="state?.isOpen"
|
||||||
:show-close="closable"
|
:show-close="closable"
|
||||||
|
:z-index="zIndex"
|
||||||
close-class="top-3"
|
close-class="top-3"
|
||||||
@close-auto-focus="handleFocusOutside"
|
@close-auto-focus="handleFocusOutside"
|
||||||
@closed="() => modalApi?.onClosed()"
|
@closed="() => modalApi?.onClosed()"
|
||||||
|
|
|
@ -20,14 +20,16 @@ import DialogOverlay from './DialogOverlay.vue';
|
||||||
const props = withDefaults(
|
const props = withDefaults(
|
||||||
defineProps<
|
defineProps<
|
||||||
{
|
{
|
||||||
|
appendTo?: HTMLElement | string;
|
||||||
class?: ClassType;
|
class?: ClassType;
|
||||||
closeClass?: ClassType;
|
closeClass?: ClassType;
|
||||||
modal?: boolean;
|
modal?: boolean;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
showClose?: boolean;
|
showClose?: boolean;
|
||||||
|
zIndex?: number;
|
||||||
} & DialogContentProps
|
} & DialogContentProps
|
||||||
>(),
|
>(),
|
||||||
{ showClose: true },
|
{ appendTo: 'body', showClose: true, zIndex: 1000 },
|
||||||
);
|
);
|
||||||
const emits = defineEmits<
|
const emits = defineEmits<
|
||||||
{ close: []; closed: []; opened: [] } & DialogContentEmits
|
{ close: []; closed: []; opened: [] } & DialogContentEmits
|
||||||
|
@ -45,6 +47,18 @@ const delegatedProps = computed(() => {
|
||||||
return delegated;
|
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 forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
|
|
||||||
const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
|
const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
|
||||||
|
@ -64,17 +78,22 @@ defineExpose({
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DialogPortal>
|
<DialogPortal :to="appendTo">
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<DialogOverlay v-if="open && modal" @click="() => emits('close')" />
|
<DialogOverlay
|
||||||
|
v-if="open && modal"
|
||||||
|
:style="{ zIndex, position }"
|
||||||
|
@click="() => emits('close')"
|
||||||
|
/>
|
||||||
</Transition>
|
</Transition>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
ref="contentRef"
|
ref="contentRef"
|
||||||
|
:style="{ zIndex, position }"
|
||||||
@animationend="onAnimationEnd"
|
@animationend="onAnimationEnd"
|
||||||
v-bind="forwarded"
|
v-bind="forwarded"
|
||||||
:class="
|
:class="
|
||||||
cn(
|
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,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
|
|
@ -7,8 +7,5 @@ useScrollLock();
|
||||||
const id = inject('DISMISSABLE_MODAL_ID');
|
const id = inject('DISMISSABLE_MODAL_ID');
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :data-dismissable-modal="id" class="bg-overlay inset-0"></div>
|
||||||
:data-dismissable-modal="id"
|
|
||||||
class="bg-overlay fixed inset-0 z-[1000]"
|
|
||||||
></div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -14,7 +14,10 @@ import {
|
||||||
useForwardPropsEmits,
|
useForwardPropsEmits,
|
||||||
} from 'radix-vue';
|
} 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 emits = defineEmits<DialogContentEmits>();
|
||||||
|
|
||||||
const delegatedProps = computed(() => {
|
const delegatedProps = computed(() => {
|
||||||
|
@ -29,7 +32,8 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
<template>
|
<template>
|
||||||
<DialogPortal>
|
<DialogPortal>
|
||||||
<DialogOverlay
|
<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
|
<DialogContent
|
||||||
:class="
|
:class="
|
||||||
|
@ -38,6 +42,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
props.class,
|
props.class,
|
||||||
)
|
)
|
||||||
"
|
"
|
||||||
|
:style="{ zIndex }"
|
||||||
v-bind="forwarded"
|
v-bind="forwarded"
|
||||||
@pointer-down-outside="
|
@pointer-down-outside="
|
||||||
(event) => {
|
(event) => {
|
||||||
|
|
|
@ -15,17 +15,22 @@ import { type SheetVariants, sheetVariants } from './sheet';
|
||||||
import SheetOverlay from './SheetOverlay.vue';
|
import SheetOverlay from './SheetOverlay.vue';
|
||||||
|
|
||||||
interface SheetContentProps extends DialogContentProps {
|
interface SheetContentProps extends DialogContentProps {
|
||||||
|
appendTo?: HTMLElement | string;
|
||||||
class?: any;
|
class?: any;
|
||||||
modal?: boolean;
|
modal?: boolean;
|
||||||
open?: boolean;
|
open?: boolean;
|
||||||
side?: SheetVariants['side'];
|
side?: SheetVariants['side'];
|
||||||
|
zIndex?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const props = defineProps<SheetContentProps>();
|
const props = withDefaults(defineProps<SheetContentProps>(), {
|
||||||
|
appendTo: 'body',
|
||||||
|
zIndex: 1000,
|
||||||
|
});
|
||||||
|
|
||||||
const emits = defineEmits<DialogContentEmits>();
|
const emits = defineEmits<DialogContentEmits>();
|
||||||
|
|
||||||
|
@ -41,16 +46,29 @@ const delegatedProps = computed(() => {
|
||||||
return delegated;
|
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 forwarded = useForwardPropsEmits(delegatedProps, emits);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<DialogPortal>
|
<DialogPortal :to="appendTo">
|
||||||
<Transition name="fade">
|
<Transition name="fade">
|
||||||
<SheetOverlay v-if="open && modal" />
|
<SheetOverlay v-if="open && modal" :style="{ zIndex, position }" />
|
||||||
</Transition>
|
</Transition>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
:class="cn(sheetVariants({ side }), 'z-[1000]', props.class)"
|
:class="cn(sheetVariants({ side }), props.class)"
|
||||||
|
:style="{ zIndex, position }"
|
||||||
v-bind="{ ...forwarded, ...$attrs }"
|
v-bind="{ ...forwarded, ...$attrs }"
|
||||||
>
|
>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
|
@ -7,8 +7,5 @@ useScrollLock();
|
||||||
const id = inject('DISMISSABLE_DRAWER_ID');
|
const id = inject('DISMISSABLE_DRAWER_ID');
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div :data-dismissable-drawer="id" class="bg-overlay inset-0"></div>
|
||||||
:data-dismissable-drawer="id"
|
|
||||||
class="bg-overlay fixed inset-0 z-[1000]"
|
|
||||||
></div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { cva, type VariantProps } from 'class-variance-authority';
|
import { cva, type VariantProps } from 'class-variance-authority';
|
||||||
|
|
||||||
export const sheetVariants = cva(
|
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: {
|
defaultVariants: {
|
||||||
side: 'right',
|
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',
|
'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 ',
|
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:
|
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',
|
top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, nextTick, onMounted, ref, useTemplateRef } from 'vue';
|
import {
|
||||||
|
computed,
|
||||||
|
nextTick,
|
||||||
|
onMounted,
|
||||||
|
ref,
|
||||||
|
type StyleValue,
|
||||||
|
useTemplateRef,
|
||||||
|
} from 'vue';
|
||||||
|
|
||||||
import { CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT } from '@vben-core/shared/constants';
|
import { CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT } from '@vben-core/shared/constants';
|
||||||
import { cn } from '@vben-core/shared/utils';
|
import { cn } from '@vben-core/shared/utils';
|
||||||
|
@ -29,13 +36,13 @@ const shouldAutoHeight = ref(false);
|
||||||
const headerRef = useTemplateRef<HTMLDivElement>('headerRef');
|
const headerRef = useTemplateRef<HTMLDivElement>('headerRef');
|
||||||
const footerRef = useTemplateRef<HTMLDivElement>('footerRef');
|
const footerRef = useTemplateRef<HTMLDivElement>('footerRef');
|
||||||
|
|
||||||
const contentStyle = computed(() => {
|
const contentStyle = computed<StyleValue>(() => {
|
||||||
if (autoContentHeight) {
|
if (autoContentHeight) {
|
||||||
return {
|
return {
|
||||||
height: shouldAutoHeight.value
|
height: shouldAutoHeight.value
|
||||||
? `calc(var(${CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT}) - ${headerHeight.value}px)`
|
? `calc(var(${CSS_VARIABLE_LAYOUT_CONTENT_HEIGHT}) - ${headerHeight.value}px)`
|
||||||
: '0',
|
: '0',
|
||||||
// 'overflow-y': shouldAutoHeight.value?'auto':'unset',
|
overflowY: shouldAutoHeight.value ? 'auto' : 'unset',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVbenDrawer } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const [Drawer, drawerApi] = useVbenDrawer({
|
||||||
|
onCancel() {
|
||||||
|
drawerApi.close();
|
||||||
|
},
|
||||||
|
onConfirm() {
|
||||||
|
message.info('onConfirm');
|
||||||
|
// drawerApi.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Drawer append-to-main title="基础抽屉示例" title-tooltip="标题提示内容">
|
||||||
|
<template #extra> extra </template>
|
||||||
|
本抽屉指定在内容区域打开
|
||||||
|
</Drawer>
|
||||||
|
</template>
|
|
@ -8,6 +8,7 @@ import AutoHeightDemo from './auto-height-demo.vue';
|
||||||
import BaseDemo from './base-demo.vue';
|
import BaseDemo from './base-demo.vue';
|
||||||
import DynamicDemo from './dynamic-demo.vue';
|
import DynamicDemo from './dynamic-demo.vue';
|
||||||
import FormDrawerDemo from './form-drawer-demo.vue';
|
import FormDrawerDemo from './form-drawer-demo.vue';
|
||||||
|
import inContentDemo from './in-content-demo.vue';
|
||||||
import SharedDataDemo from './shared-data-demo.vue';
|
import SharedDataDemo from './shared-data-demo.vue';
|
||||||
|
|
||||||
const [BaseDrawer, baseDrawerApi] = useVbenDrawer({
|
const [BaseDrawer, baseDrawerApi] = useVbenDrawer({
|
||||||
|
@ -16,6 +17,12 @@ const [BaseDrawer, baseDrawerApi] = useVbenDrawer({
|
||||||
// placement: 'left',
|
// placement: 'left',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [InContentDrawer, inContentDrawerApi] = useVbenDrawer({
|
||||||
|
// 连接抽离的组件
|
||||||
|
connectedComponent: inContentDemo,
|
||||||
|
// placement: 'left',
|
||||||
|
});
|
||||||
|
|
||||||
const [AutoHeightDrawer, autoHeightDrawerApi] = useVbenDrawer({
|
const [AutoHeightDrawer, autoHeightDrawerApi] = useVbenDrawer({
|
||||||
connectedComponent: AutoHeightDemo,
|
connectedComponent: AutoHeightDemo,
|
||||||
});
|
});
|
||||||
|
@ -37,6 +44,23 @@ function openBaseDrawer(placement: DrawerPlacement = 'right') {
|
||||||
baseDrawerApi.open();
|
baseDrawerApi.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openInContentDrawer(placement: DrawerPlacement = 'right') {
|
||||||
|
inContentDrawerApi.setState({ class: '', placement });
|
||||||
|
if (placement === 'top') {
|
||||||
|
// 页面顶部区域的层级只有200,所以设置一个低于200的值,抽屉从顶部滑出来的时候才比较合适
|
||||||
|
inContentDrawerApi.setState({ zIndex: 199 });
|
||||||
|
} else {
|
||||||
|
inContentDrawerApi.setState({ zIndex: undefined });
|
||||||
|
}
|
||||||
|
inContentDrawerApi.open();
|
||||||
|
}
|
||||||
|
|
||||||
|
function openMaxContentDrawer() {
|
||||||
|
// 这里只是用来演示方便。实际上自己使用的时候可以直接将这些配置卸载Drawer的属性里
|
||||||
|
inContentDrawerApi.setState({ class: 'w-full', placement: 'right' });
|
||||||
|
inContentDrawerApi.open();
|
||||||
|
}
|
||||||
|
|
||||||
function openAutoHeightDrawer() {
|
function openAutoHeightDrawer() {
|
||||||
autoHeightDrawerApi.open();
|
autoHeightDrawerApi.open();
|
||||||
}
|
}
|
||||||
|
@ -69,6 +93,7 @@ function openFormDrawer() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Page
|
<Page
|
||||||
|
auto-content-height
|
||||||
description="抽屉组件通常用于在当前页面上显示一个覆盖层,用以展示重要信息或提供用户交互界面。"
|
description="抽屉组件通常用于在当前页面上显示一个覆盖层,用以展示重要信息或提供用户交互界面。"
|
||||||
title="抽屉组件示例"
|
title="抽屉组件示例"
|
||||||
>
|
>
|
||||||
|
@ -76,6 +101,7 @@ function openFormDrawer() {
|
||||||
<DocButton path="/components/common-ui/vben-drawer" />
|
<DocButton path="/components/common-ui/vben-drawer" />
|
||||||
</template>
|
</template>
|
||||||
<BaseDrawer />
|
<BaseDrawer />
|
||||||
|
<InContentDrawer />
|
||||||
<AutoHeightDrawer />
|
<AutoHeightDrawer />
|
||||||
<DynamicDrawer />
|
<DynamicDrawer />
|
||||||
<SharedDataDrawer />
|
<SharedDataDrawer />
|
||||||
|
@ -83,18 +109,55 @@ function openFormDrawer() {
|
||||||
|
|
||||||
<Card class="mb-4" title="基本使用">
|
<Card class="mb-4" title="基本使用">
|
||||||
<p class="mb-3">一个基础的抽屉示例</p>
|
<p class="mb-3">一个基础的抽屉示例</p>
|
||||||
<Button type="primary" @click="openBaseDrawer('right')">右侧打开</Button>
|
<Button class="mb-2" type="primary" @click="openBaseDrawer('right')">
|
||||||
<Button class="ml-2" type="primary" @click="openBaseDrawer('bottom')">
|
右侧打开
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class="mb-2 ml-2"
|
||||||
|
type="primary"
|
||||||
|
@click="openBaseDrawer('bottom')"
|
||||||
|
>
|
||||||
底部打开
|
底部打开
|
||||||
</Button>
|
</Button>
|
||||||
<Button class="ml-2" type="primary" @click="openBaseDrawer('left')">
|
<Button class="mb-2 ml-2" type="primary" @click="openBaseDrawer('left')">
|
||||||
左侧打开
|
左侧打开
|
||||||
</Button>
|
</Button>
|
||||||
<Button class="ml-2" type="primary" @click="openBaseDrawer('top')">
|
<Button class="mb-2 ml-2" type="primary" @click="openBaseDrawer('top')">
|
||||||
顶部打开
|
顶部打开
|
||||||
</Button>
|
</Button>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Card class="mb-4" title="在内容区域打开">
|
||||||
|
<p class="mb-3">指定抽屉在内容区域打开,不会覆盖顶部和左侧菜单等区域</p>
|
||||||
|
<Button class="mb-2" type="primary" @click="openInContentDrawer('right')">
|
||||||
|
右侧打开
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class="mb-2 ml-2"
|
||||||
|
type="primary"
|
||||||
|
@click="openInContentDrawer('bottom')"
|
||||||
|
>
|
||||||
|
底部打开
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class="mb-2 ml-2"
|
||||||
|
type="primary"
|
||||||
|
@click="openInContentDrawer('left')"
|
||||||
|
>
|
||||||
|
左侧打开
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
class="mb-2 ml-2"
|
||||||
|
type="primary"
|
||||||
|
@click="openInContentDrawer('top')"
|
||||||
|
>
|
||||||
|
顶部打开
|
||||||
|
</Button>
|
||||||
|
<Button class="mb-2 ml-2" type="primary" @click="openMaxContentDrawer">
|
||||||
|
内容区域全屏打开
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<Card class="mb-4" title="内容高度自适应滚动">
|
<Card class="mb-4" title="内容高度自适应滚动">
|
||||||
<p class="mb-3">可根据内容自动计算滚动高度</p>
|
<p class="mb-3">可根据内容自动计算滚动高度</p>
|
||||||
<Button type="primary" @click="openAutoHeightDrawer">打开抽屉</Button>
|
<Button type="primary" @click="openAutoHeightDrawer">打开抽屉</Button>
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
|
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
|
|
||||||
|
const [Modal, modalApi] = useVbenModal({
|
||||||
|
onCancel() {
|
||||||
|
modalApi.close();
|
||||||
|
},
|
||||||
|
onConfirm() {
|
||||||
|
message.info('onConfirm');
|
||||||
|
// modalApi.close();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<Modal
|
||||||
|
append-to-main
|
||||||
|
class="w-[600px]"
|
||||||
|
title="基础弹窗示例"
|
||||||
|
title-tooltip="标题提示内容"
|
||||||
|
>
|
||||||
|
此弹窗指定在内容区域打开
|
||||||
|
</Modal>
|
||||||
|
</template>
|
|
@ -9,6 +9,7 @@ import BaseDemo from './base-demo.vue';
|
||||||
import DragDemo from './drag-demo.vue';
|
import DragDemo from './drag-demo.vue';
|
||||||
import DynamicDemo from './dynamic-demo.vue';
|
import DynamicDemo from './dynamic-demo.vue';
|
||||||
import FormModalDemo from './form-modal-demo.vue';
|
import FormModalDemo from './form-modal-demo.vue';
|
||||||
|
import InContentModalDemo from './in-content-demo.vue';
|
||||||
import SharedDataDemo from './shared-data-demo.vue';
|
import SharedDataDemo from './shared-data-demo.vue';
|
||||||
|
|
||||||
const [BaseModal, baseModalApi] = useVbenModal({
|
const [BaseModal, baseModalApi] = useVbenModal({
|
||||||
|
@ -16,6 +17,11 @@ const [BaseModal, baseModalApi] = useVbenModal({
|
||||||
connectedComponent: BaseDemo,
|
connectedComponent: BaseDemo,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [InContentModal, inContentModalApi] = useVbenModal({
|
||||||
|
// 连接抽离的组件
|
||||||
|
connectedComponent: InContentModalDemo,
|
||||||
|
});
|
||||||
|
|
||||||
const [AutoHeightModal, autoHeightModalApi] = useVbenModal({
|
const [AutoHeightModal, autoHeightModalApi] = useVbenModal({
|
||||||
connectedComponent: AutoHeightDemo,
|
connectedComponent: AutoHeightDemo,
|
||||||
});
|
});
|
||||||
|
@ -40,6 +46,10 @@ function openBaseModal() {
|
||||||
baseModalApi.open();
|
baseModalApi.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openInContentModal() {
|
||||||
|
inContentModalApi.open();
|
||||||
|
}
|
||||||
|
|
||||||
function openAutoHeightModal() {
|
function openAutoHeightModal() {
|
||||||
autoHeightModalApi.open();
|
autoHeightModalApi.open();
|
||||||
}
|
}
|
||||||
|
@ -76,6 +86,7 @@ function openFormModal() {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<Page
|
<Page
|
||||||
|
auto-content-height
|
||||||
description="弹窗组件常用于在不离开当前页面的情况下,显示额外的信息、表单或操作提示,更多api请查看组件文档。"
|
description="弹窗组件常用于在不离开当前页面的情况下,显示额外的信息、表单或操作提示,更多api请查看组件文档。"
|
||||||
title="弹窗组件示例"
|
title="弹窗组件示例"
|
||||||
>
|
>
|
||||||
|
@ -83,6 +94,7 @@ function openFormModal() {
|
||||||
<DocButton path="/components/common-ui/vben-modal" />
|
<DocButton path="/components/common-ui/vben-modal" />
|
||||||
</template>
|
</template>
|
||||||
<BaseModal />
|
<BaseModal />
|
||||||
|
<InContentModal />
|
||||||
<AutoHeightModal />
|
<AutoHeightModal />
|
||||||
<DragModal />
|
<DragModal />
|
||||||
<DynamicModal />
|
<DynamicModal />
|
||||||
|
@ -93,6 +105,11 @@ function openFormModal() {
|
||||||
<Button type="primary" @click="openBaseModal">打开弹窗</Button>
|
<Button type="primary" @click="openBaseModal">打开弹窗</Button>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
<Card class="mb-4" title="指定容器">
|
||||||
|
<p class="mb-3">在内容区域打开弹窗的示例</p>
|
||||||
|
<Button type="primary" @click="openInContentModal">打开弹窗</Button>
|
||||||
|
</Card>
|
||||||
|
|
||||||
<Card class="mb-4" title="内容高度自适应">
|
<Card class="mb-4" title="内容高度自适应">
|
||||||
<p class="mb-3">可根据内容并自动调整高度</p>
|
<p class="mb-3">可根据内容并自动调整高度</p>
|
||||||
<Button type="primary" @click="openAutoHeightModal">打开弹窗</Button>
|
<Button type="primary" @click="openAutoHeightModal">打开弹窗</Button>
|
||||||
|
|
|
@ -76,6 +76,12 @@ function changeLoading() {
|
||||||
<template #extra>
|
<template #extra>
|
||||||
<DocButton path="/components/common-ui/vben-vxe-table" />
|
<DocButton path="/components/common-ui/vben-vxe-table" />
|
||||||
</template>
|
</template>
|
||||||
|
<Modal title="弹窗测试">
|
||||||
|
<p>这是一个弹窗</p>
|
||||||
|
</Modal>
|
||||||
|
<Drawer title="抽屉测试">
|
||||||
|
<p>这是一个抽屉</p>
|
||||||
|
</Drawer>
|
||||||
<Grid table-title="基础列表" table-title-help="提示">
|
<Grid table-title="基础列表" table-title-help="提示">
|
||||||
<!-- <template #toolbar-actions>
|
<!-- <template #toolbar-actions>
|
||||||
<Button class="mr-2" type="primary">左侧插槽</Button>
|
<Button class="mr-2" type="primary">左侧插槽</Button>
|
||||||
|
|
|
@ -1340,6 +1340,9 @@ importers:
|
||||||
'@vben-core/shadcn-ui':
|
'@vben-core/shadcn-ui':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../shadcn-ui
|
version: link:../shadcn-ui
|
||||||
|
'@vben-core/shared':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../../base/shared
|
||||||
'@vben-core/typings':
|
'@vben-core/typings':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../../base/typings
|
version: link:../../base/typings
|
||||||
|
|
Loading…
Reference in New Issue