This commit is contained in:
xingyu4j
2026-01-26 10:13:23 +08:00
62 changed files with 5078 additions and 3451 deletions

View File

@@ -53,7 +53,11 @@ const wrapperClass = computed(() => {
provideFormRenderProps(props);
const { isCalculated, keepFormItemIndex, wrapperRef } = useExpandable(props);
const {
isCalculated,
keepFormItemIndex,
wrapperRef: _wrapperRef,
} = useExpandable(props);
const shapes = computed(() => {
const resultShapes: FormShape[] = [];
@@ -170,7 +174,7 @@ const computedSchema = computed(
<template>
<component :is="formComponent" v-bind="formComponentProps">
<div ref="wrapperRef" :class="wrapperClass">
<div ref="_wrapperRef" :class="wrapperClass">
<template v-for="cSchema in computedSchema" :key="cSchema.fieldName">
<!-- <div v-if="$slots[cSchema.fieldName]" :class="cSchema.formItemClass">
<slot :definition="cSchema" :name="cSchema.fieldName"> </slot>

View File

@@ -352,9 +352,9 @@ export interface ActionButtonOptions extends VbenButtonProps {
export interface VbenFormProps<
T extends BaseFormComponentType = BaseFormComponentType,
> extends Omit<
FormRenderProps<T>,
'componentBindEventMap' | 'componentMap' | 'form'
> {
FormRenderProps<T>,
'componentBindEventMap' | 'componentMap' | 'form'
> {
/**
* 操作按钮是否反转(提交按钮前置)
*/

View File

@@ -26,7 +26,8 @@ interface Props {
const props = withDefaults(defineProps<Props>(), {});
const { contentElement, overlayStyle } = useLayoutContentStyle();
const { contentElement: _contentElement, overlayStyle } =
useLayoutContentStyle();
const style = computed((): CSSProperties => {
const {
@@ -55,7 +56,11 @@ const style = computed((): CSSProperties => {
</script>
<template>
<main ref="contentElement" :style="style" class="relative bg-background-deep">
<main
ref="_contentElement"
:style="style"
class="relative bg-background-deep"
>
<Slot :style="overlayStyle">
<slot name="overlay"></slot>
</Slot>

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
import type { CSSProperties } from 'vue';
import { computed, shallowRef, useSlots, watchEffect } from 'vue';
import { computed, useSlots, watchEffect } from 'vue';
import { VbenScrollbar } from '@vben-core/shadcn-ui';
@@ -114,7 +114,7 @@ const extraVisible = defineModel<boolean>('extraVisible');
const isLocked = useScrollLock(document.body);
const slots = useSlots();
const asideRef = shallowRef<HTMLDivElement | null>();
// const asideRef = shallowRef<HTMLDivElement | null>();
const hiddenSideStyle = computed((): CSSProperties => calcMenuWidthStyle(true));
@@ -290,7 +290,6 @@ function handleMouseleave() {
/>
<div
v-if="isSidebarMixed"
ref="asideRef"
:class="{
'border-l': extraVisible,
}"

View File

@@ -403,13 +403,10 @@ watch(
);
{
const mouseMove = () => {
mouseY.value > headerWrapperHeight.value
? (headerIsHidden.value = true)
: (headerIsHidden.value = false);
};
const HEADER_TRIGGER_DISTANCE = 12;
watch(
[() => props.headerMode, () => mouseY.value],
[() => props.headerMode, () => mouseY.value, () => headerIsHidden.value],
() => {
if (!isHeaderAutoMode.value || isMixedNav.value || isFullContent.value) {
if (props.headerMode !== 'auto-scroll') {
@@ -417,8 +414,12 @@ watch(
}
return;
}
headerIsHidden.value = true;
mouseMove();
const isInTriggerZone = mouseY.value <= HEADER_TRIGGER_DISTANCE;
const isInHeaderZone =
!headerIsHidden.value && mouseY.value <= headerWrapperHeight.value;
headerIsHidden.value = !(isInTriggerZone || isInHeaderZone);
},
{
immediate: true,

View File

@@ -351,14 +351,14 @@ function getActivePaths() {
role="menu"
>
<template v-if="mode === 'horizontal' && getSlot.showSlotMore">
<template v-for="item in getSlot.slotDefault" :key="item.key">
<template v-for="(item, index) in getSlot.slotDefault" :key="index">
<component :is="item" />
</template>
<SubMenu is-sub-menu-more path="sub-menu-more">
<template #title>
<Ellipsis class="size-4" />
</template>
<template v-for="item in getSlot.slotMore" :key="item.key">
<template v-for="(item, index) in getSlot.slotMore" :key="index">
<component :is="item" />
</template>
</SubMenu>

View File

@@ -54,7 +54,7 @@ const components = globalShareState.getComponents();
const id = useId();
provide('DISMISSABLE_DRAWER_ID', id);
const wrapperRef = ref<HTMLElement>();
// const wrapperRef = ref<HTMLElement>();
const { $t } = useSimpleLocale();
const { isMobile } = useIsMobile();
@@ -281,7 +281,6 @@ const getForceMount = computed(() => {
</VisuallyHidden>
</template>
<div
ref="wrapperRef"
:class="
cn('relative flex-1 overflow-y-auto p-3', contentClass, {
'pointer-events-none': showLoading || submitting,

View File

@@ -50,10 +50,10 @@ const props = withDefaults(defineProps<Props>(), {
const components = globalShareState.getComponents();
const contentRef = ref();
const wrapperRef = ref<HTMLElement>();
// const wrapperRef = ref<HTMLElement>();
const dialogRef = ref();
const headerRef = ref();
const footerRef = ref();
// const footerRef = ref();
const id = useId();
@@ -306,7 +306,6 @@ function handleClosed() {
</VisuallyHidden>
</DialogHeader>
<div
ref="wrapperRef"
:class="
cn('relative min-h-40 flex-1 overflow-y-auto p-3', contentClass, {
'pointer-events-none': showLoading || submitting,
@@ -327,7 +326,6 @@ function handleClosed() {
<DialogFooter
v-if="showFooter"
ref="footerRef"
:class="
cn(
'flex-row items-center justify-end p-2',

View File

@@ -41,6 +41,7 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
// 不能用 Object.assign,会丢失 api 的原型函数
Object.setPrototypeOf(extendedApi, api);
},
consumed: false,
options,
async reCreateModal() {
isModalReady.value = false;
@@ -73,7 +74,13 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
return [Modal, extendedApi as ExtendedModalApi] as const;
}
const injectData = inject<any>(USER_MODAL_INJECT_KEY, {});
let injectData = inject<any>(USER_MODAL_INJECT_KEY, {});
// 这个数据已经被使用了说明这个弹窗是嵌套的弹窗不应该merge上层的配置
if (injectData.consumed) {
injectData = {};
} else {
injectData.consumed = true;
}
const mergedOptions = {
...DEFAULT_MODAL_PROPS,

View File

@@ -27,8 +27,10 @@ export type CustomRenderType = (() => Component | string) | string;
export type ValueType = boolean | number | string;
export interface VbenButtonGroupProps
extends Pick<VbenButtonProps, 'disabled'> {
export interface VbenButtonGroupProps extends Pick<
VbenButtonProps,
'disabled'
> {
/** 单选模式下允许清除选中 */
allowClear?: boolean;
/** 值改变前的回调 */

View File

@@ -73,6 +73,7 @@ function handleClick(menu: IContextMenuItem) {
>
<template v-for="menu in menusView" :key="menu.key">
<ContextMenuItem
v-if="!menu.hidden"
:class="itemClass"
:disabled="menu.disabled"
:inset="menu.inset || !menu.icon"

View File

@@ -10,6 +10,10 @@ interface IContextMenuItem {
* @param data
*/
handler?: (data: any) => void;
/**
* @zh_CN 是否隐藏
*/
hidden?: boolean;
/**
* @zh_CN 图标
*/

View File

@@ -27,7 +27,7 @@ function handleItemClick(value: string) {
</DropdownMenuTrigger>
<DropdownMenuContent align="start">
<DropdownMenuGroup>
<template v-for="menu in menus" :key="menu.key">
<template v-for="menu in menus" :key="menu.value">
<DropdownMenuItem
:class="
menu.value === modelValue

View File

@@ -32,19 +32,19 @@ const props = withDefaults(defineProps<Props>(), {
// const startTime = ref(0);
const showSpinner = ref(false);
const renderSpinner = ref(false);
const timer = ref<ReturnType<typeof setTimeout>>();
let timer: ReturnType<typeof setTimeout> | undefined;
watch(
() => props.spinning,
(show) => {
if (!show) {
showSpinner.value = false;
clearTimeout(timer.value);
timer && clearTimeout(timer);
return;
}
// startTime.value = performance.now();
timer.value = setTimeout(() => {
timer = setTimeout(() => {
// const loadingTime = performance.now() - startTime.value;
showSpinner.value = true;

View File

@@ -3,7 +3,7 @@ import type { TabDefinition } from '@vben-core/typings';
import type { TabConfig, TabsProps } from '../../types';
import { computed, ref } from 'vue';
import { computed } from 'vue';
import { Pin, X } from '@vben-core/icons';
import { VbenContextMenu, VbenIcon } from '@vben-core/shadcn-ui';
@@ -28,8 +28,8 @@ const emit = defineEmits<{
}>();
const active = defineModel<string>('active');
const contentRef = ref();
const tabRef = ref();
// const contentRef = ref();
// const tabRef = ref();
const style = computed(() => {
const { gap } = props;
@@ -73,7 +73,6 @@ function onMouseDown(e: MouseEvent, tab: TabConfig) {
<template>
<div
ref="contentRef"
:class="contentClass"
:style="style"
class="tabs-chrome !flex h-full w-max overflow-y-hidden pr-6"
@@ -82,7 +81,6 @@ function onMouseDown(e: MouseEvent, tab: TabConfig) {
<div
v-for="(tab, i) in tabsView"
:key="tab.key"
ref="tabRef"
:class="[
{
'is-active': tab.key === active,

View File

@@ -29,7 +29,7 @@ const forward = useForwardPropsEmits(props, emit);
const {
handleScrollAt,
handleWheel,
scrollbarRef,
scrollbarRef: _scrollbarRef,
scrollDirection,
scrollIsAtLeft,
scrollIsAtRight,
@@ -69,7 +69,7 @@ useTabsDrag(props, emit);
class="size-full flex-1 overflow-hidden"
>
<VbenScrollbar
ref="scrollbarRef"
ref="_scrollbarRef"
:shadow-bottom="false"
:shadow-top="false"
class="h-full"