This commit is contained in:
xingyu4j
2026-02-11 11:01:44 +08:00
170 changed files with 7055 additions and 2142 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/form-ui",
"version": "5.5.9",
"version": "5.6.0",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -6,12 +6,30 @@ import type {
import { computed, ref, watch } from 'vue';
import { isBoolean, isFunction } from '@vben-core/shared/utils';
import { get, isBoolean, isFunction } from '@vben-core/shared/utils';
import { useFormValues } from 'vee-validate';
import { injectRenderFormProps } from './context';
/**
* 解析Nested Objects对应的字段值
* @param values 表单值
* @param fieldName 字段名
*/
function resolveValueByFieldName(
values: Record<string, any>,
fieldName: string,
) {
// vee-validate[] 表示禁用嵌套
if (fieldName.startsWith('[') && fieldName.endsWith(']')) {
const rawKey = fieldName.slice(1, -1);
return values[rawKey];
}
return get(values, fieldName);
}
export default function useDependencies(
getDependencies: () => FormItemDependencies | undefined,
) {
@@ -37,7 +55,7 @@ export default function useDependencies(
// 该字段可能会被多个字段触发
const triggerFields = getDependencies()?.triggerFields ?? [];
return triggerFields.map((dep) => {
return values.value[dep];
return resolveValueByFieldName(values.value, dep);
});
});
@@ -82,10 +100,8 @@ export default function useDependencies(
// 2. 判断show如果show为false则隐藏
if (isFunction(show)) {
isShow.value = !!(await show(formValues, formApi));
if (!isShow.value) return;
} else if (isBoolean(show)) {
isShow.value = show;
if (!isShow.value) return;
}
if (isFunction(componentProps)) {

View File

@@ -53,11 +53,8 @@ const wrapperClass = computed(() => {
provideFormRenderProps(props);
const {
isCalculated,
keepFormItemIndex,
wrapperRef: _wrapperRef,
} = useExpandable(props);
// @ts-expect-error unused
const { isCalculated, keepFormItemIndex, wrapperRef } = useExpandable(props);
const shapes = computed(() => {
const resultShapes: FormShape[] = [];
@@ -174,7 +171,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

@@ -1,6 +1,6 @@
{
"name": "@vben-core/layout-ui",
"version": "5.5.9",
"version": "5.6.0",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -26,8 +26,8 @@ interface Props {
const props = withDefaults(defineProps<Props>(), {});
const { contentElement: _contentElement, overlayStyle } =
useLayoutContentStyle();
// @ts-expect-error unused
const { contentElement, overlayStyle } = useLayoutContentStyle();
const style = computed((): CSSProperties => {
const {
@@ -56,11 +56,7 @@ 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, useSlots, watchEffect } from 'vue';
import { computed, shallowRef, useSlots, watchEffect } from 'vue';
import { VbenScrollbar } from '@vben-core/shadcn-ui';
@@ -114,7 +114,8 @@ const extraVisible = defineModel<boolean>('extraVisible');
const isLocked = useScrollLock(document.body);
const slots = useSlots();
// const asideRef = shallowRef<HTMLDivElement | null>();
// @ts-expect-error unused
const asideRef = shallowRef<HTMLDivElement | null>();
const hiddenSideStyle = computed((): CSSProperties => calcMenuWidthStyle(true));
@@ -290,6 +291,7 @@ function handleMouseleave() {
/>
<div
v-if="isSidebarMixed"
ref="asideRef"
:class="{
'border-l': extraVisible,
}"

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/menu-ui",
"version": "5.5.9",
"version": "5.6.0",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -463,33 +463,33 @@ $namespace: vben;
&.is-dark {
--menu-background-color: hsl(var(--menu));
// --menu-submenu-opened-background-color: hsl(var(--menu-opened-dark));
--menu-item-background-color: var(--menu-background-color);
--menu-item-color: hsl(var(--foreground) / 80%);
--menu-item-background-color: var(--menu-background-color);
--menu-item-hover-color: hsl(var(--accent-foreground));
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-active-color: hsl(var(--accent-foreground));
--menu-item-active-background-color: hsl(var(--accent));
--menu-submenu-hover-color: hsl(var(--foreground));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--foreground));
--menu-submenu-active-background-color: transparent;
--menu-submenu-background-color: var(--menu-background-color);
--menu-submenu-hover-color: hsl(var(--accent-foreground));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--accent-foreground));
--menu-submenu-active-background-color: transparent;
}
&.is-light {
--menu-background-color: hsl(var(--menu));
// --menu-submenu-opened-background-color: hsl(var(--menu-opened));
--menu-item-color: hsl(var(--accent-foreground));
--menu-item-background-color: var(--menu-background-color);
--menu-item-color: hsl(var(--foreground));
--menu-item-hover-color: var(--menu-item-color);
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-active-color: hsl(var(--primary));
--menu-item-active-background-color: hsl(var(--primary) / 15%);
--menu-submenu-background-color: var(--menu-background-color);
--menu-submenu-hover-color: hsl(var(--primary));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--primary));
--menu-submenu-active-background-color: transparent;
--menu-submenu-background-color: var(--menu-background-color);
}
&.is-rounded {
@@ -518,25 +518,33 @@ $namespace: vben;
--menu-background-color: transparent;
&.is-dark {
--menu-background-color: hsl(var(--menu));
--menu-item-color: hsl(var(--foreground) / 80%);
--menu-item-background-color: var(--menu-background-color);
--menu-item-hover-color: hsl(var(--accent-foreground));
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-active-color: hsl(var(--accent-foreground));
--menu-item-active-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--foreground));
--menu-submenu-active-background-color: hsl(var(--accent));
--menu-submenu-background-color: var(--menu-background-color);
--menu-submenu-hover-color: hsl(var(--accent-foreground));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--accent-foreground));
--menu-submenu-active-background-color: hsl(var(--accent));
}
&.is-light {
--menu-background-color: hsl(var(--menu));
--menu-item-color: hsl(var(--accent-foreground));
--menu-item-background-color: var(--menu-background-color);
--menu-item-hover-color: hsl(var(--menu-item-color));
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-active-color: hsl(var(--primary));
--menu-item-active-background-color: hsl(var(--primary) / 15%);
--menu-item-hover-background-color: hsl(var(--accent));
--menu-item-hover-color: hsl(var(--primary));
--menu-submenu-active-color: hsl(var(--primary));
--menu-submenu-active-background-color: hsl(var(--primary) / 15%);
--menu-submenu-background-color: var(--menu-background-color);
--menu-submenu-hover-color: hsl(var(--primary));
--menu-submenu-hover-background-color: hsl(var(--accent));
--menu-submenu-active-color: hsl(var(--primary));
--menu-submenu-active-background-color: hsl(var(--primary) / 15%);
}
}
}
@@ -862,16 +870,17 @@ $namespace: vben;
padding-right: 12px !important;
}
// &:not(.is-active):hover {
&:hover {
color: var(--menu-submenu-hover-color);
text-decoration: none;
cursor: pointer;
background: var(--menu-submenu-hover-background-color) !important;
&:not(.is-active):hover {
&:hover {
//color: var(--menu-submenu-hover-color);
text-decoration: none;
cursor: pointer;
background: var(--menu-submenu-hover-background-color) !important;
// svg {
// fill: var(--menu-submenu-hover-color);
// }
// svg {
// fill: var(--menu-submenu-hover-color);
// }
}
}
}
</style>

View File

@@ -210,6 +210,7 @@ onBeforeUnmount(() => {
opened ? '' : 'hidden',
'overflow-auto',
'max-h-[calc(var(--reka-hover-card-content-available-height)-20px)]',
mode === 'horizontal' ? 'is-horizontal' : '',
]"
:content-props="contentProps"
:open="true"

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/popup-ui",
"version": "5.2.1",
"version": "5.6.0",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -54,7 +54,8 @@ const components = globalShareState.getComponents();
const id = useId();
provide('DISMISSABLE_DRAWER_ID', id);
// const wrapperRef = ref<HTMLElement>();
// @ts-expect-error unused
const wrapperRef = ref<HTMLElement>();
const { $t } = useSimpleLocale();
const { isMobile } = useIsMobile();
@@ -281,6 +282,7 @@ 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,12 @@ const props = withDefaults(defineProps<Props>(), {
const components = globalShareState.getComponents();
const contentRef = ref();
// const wrapperRef = ref<HTMLElement>();
// @ts-expect-error unused
const wrapperRef = ref<HTMLElement>();
const dialogRef = ref();
const headerRef = ref();
// const footerRef = ref();
// @ts-expect-error unused
const footerRef = ref();
const id = useId();
@@ -306,6 +308,7 @@ 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,
@@ -325,6 +328,7 @@ function handleClosed() {
</VbenIconButton>
<DialogFooter
ref="footerRef"
v-if="showFooter"
:class="
cn(

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/shadcn-ui",
"version": "5.5.9",
"version": "5.6.0",
"#main": "./dist/index.mjs",
"#module": "./dist/index.mjs",
"homepage": "https://github.com/vbenjs/vue-vben-admin",

View File

@@ -42,14 +42,17 @@ export default defineComponent({
return props.content;
}
}
return h(props.content as never, {
...attrs,
props: {
...props,
return h(
props.content as never,
{
...attrs,
props: {
...props,
...attrs,
},
},
slots,
});
);
};
},
});

View File

@@ -33,5 +33,16 @@ const modelValue = useVModel(props, 'modelValue', emits, {
<style lang="scss" scoped>
input {
--ring: var(--primary);
&::-ms-reveal,
&::-ms-clear {
display: none;
}
&::-webkit-credentials-auto-fill-button,
&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
display: none;
}
}
</style>

View File

@@ -65,16 +65,24 @@ const modelValue = defineModel<Arrayable<number | string>>();
const expanded = ref<Array<number | string>>(props.defaultExpandedKeys ?? []);
const treeValue = ref();
let lastTreeData: any = null;
onMounted(() => {
watchEffect(() => {
flattenData.value = flatten(props.treeData, props.childrenField);
updateTreeValue();
if (
props.defaultExpandedLevel !== undefined &&
props.defaultExpandedLevel > 0
)
expandToLevel(props.defaultExpandedLevel);
// 只在 treeData 变化时执行展开
const currentTreeData = JSON.stringify(props.treeData);
if (lastTreeData !== currentTreeData) {
lastTreeData = currentTreeData;
if (
props.defaultExpandedLevel !== undefined &&
props.defaultExpandedLevel > 0
) {
expandToLevel(props.defaultExpandedLevel);
}
}
});
});
@@ -87,9 +95,11 @@ function getItemByValue(value: number | string) {
function updateTreeValue() {
const val = modelValue.value;
if (val === undefined) {
treeValue.value = undefined;
} else {
if (Array.isArray(val)) {
treeValue.value = props.multiple ? [] : undefined;
} else if (Array.isArray(val)) {
if (val.length === 0) {
treeValue.value = [];
} else {
const filteredValues = val.filter((v) => {
const item = getItemByValue(v);
return item && !get(item, props.disabledField);
@@ -99,14 +109,14 @@ function updateTreeValue() {
if (filteredValues.length !== val.length) {
modelValue.value = filteredValues;
}
}
} else {
const item = getItemByValue(val);
if (item && !get(item, props.disabledField)) {
treeValue.value = item;
} else {
const item = getItemByValue(val);
if (item && !get(item, props.disabledField)) {
treeValue.value = item;
} else {
treeValue.value = undefined;
modelValue.value = undefined;
}
treeValue.value = props.multiple ? [] : undefined;
modelValue.value = props.multiple ? [] : undefined;
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vben-core/tabs-ui",
"version": "5.5.9",
"version": "5.6.0",
"homepage": "https://github.com/vbenjs/vue-vben-admin",
"bugs": "https://github.com/vbenjs/vue-vben-admin/issues",
"repository": {

View File

@@ -3,7 +3,7 @@ import type { TabDefinition } from '@vben-core/typings';
import type { TabConfig, TabsProps } from '../../types';
import { computed } from 'vue';
import { computed, ref } from 'vue';
import { Pin, X } from '@vben-core/icons';
import { VbenContextMenu, VbenIcon } from '@vben-core/shadcn-ui';
@@ -28,8 +28,10 @@ const emit = defineEmits<{
}>();
const active = defineModel<string>('active');
// const contentRef = ref();
// const tabRef = ref();
// @ts-expect-error unused
const contentRef = ref();
// @ts-expect-error unused
const tabRef = ref();
const style = computed(() => {
const { gap } = props;
@@ -73,6 +75,7 @@ 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"
@@ -81,6 +84,7 @@ function onMouseDown(e: MouseEvent, tab: TabConfig) {
<div
v-for="(tab, i) in tabsView"
:key="tab.key"
ref="tabRef"
:class="[
{
'is-active': tab.key === active,
@@ -154,7 +158,7 @@ function onMouseDown(e: MouseEvent, tab: TabConfig) {
<VbenIcon
v-if="showIcon"
:icon="tab.icon"
class="mr-1 flex size-4 items-center overflow-hidden"
class="mr-1 flex size-4 items-center overflow-hidden group-hover:animate-[shrink_0.3s_ease-in-out]"
/>
<span class="flex-1 overflow-hidden whitespace-nowrap text-sm">

View File

@@ -132,7 +132,7 @@ function onMouseDown(e: MouseEvent, tab: TabConfig) {
<VbenIcon
v-if="showIcon"
:icon="tab.icon"
class="mr-2 flex size-4 items-center overflow-hidden"
class="mr-2 flex size-4 items-center overflow-hidden group-hover:animate-[shrink_0.3s_ease-in-out]"
fallback
/>

View File

@@ -1,2 +1,3 @@
export { default as TabsToolMore } from './tool-more.vue';
export { default as TabsToolRefresh } from './tool-refresh.vue';
export { default as TabsToolScreen } from './tool-screen.vue';

View File

@@ -1,7 +1,7 @@
<script lang="ts" setup>
import type { DropdownMenuProps } from '@vben-core/shadcn-ui';
import { ChevronDown } from '@vben-core/icons';
import { LayoutGrid } from '@vben-core/icons';
import { VbenDropdownMenu } from '@vben-core/shadcn-ui';
defineProps<DropdownMenuProps>();
@@ -12,7 +12,7 @@ defineProps<DropdownMenuProps>();
<div
class="flex-center h-full cursor-pointer border-l border-border px-2 text-lg font-semibold text-muted-foreground hover:bg-muted hover:text-foreground"
>
<ChevronDown class="size-4" />
<LayoutGrid class="size-4" />
</div>
</VbenDropdownMenu>
</template>

View File

@@ -0,0 +1,18 @@
<script lang="ts" setup>
import { RotateCw } from '@vben-core/icons';
const emit = defineEmits(['refresh']);
const handleRefresh = () => {
emit('refresh');
};
</script>
<template>
<div
class="flex-center h-full cursor-pointer border-l border-border px-2 text-lg font-semibold text-muted-foreground hover:bg-muted hover:text-foreground"
@click="handleRefresh"
>
<RotateCw class="size-4" />
</div>
</template>

View File

@@ -2,7 +2,7 @@
import type { TabsEmits, TabsProps } from './types';
import { useForwardPropsEmits } from '@vben-core/composables';
import { ChevronLeft, ChevronRight } from '@vben-core/icons';
import { ChevronsLeft, ChevronsRight } from '@vben-core/icons';
import { VbenScrollbar } from '@vben-core/shadcn-ui';
import { Tabs, TabsChrome } from './components';
@@ -29,7 +29,8 @@ const forward = useForwardPropsEmits(props, emit);
const {
handleScrollAt,
handleWheel,
scrollbarRef: _scrollbarRef,
// @ts-expect-error unused
scrollbarRef,
scrollDirection,
scrollIsAtLeft,
scrollIsAtRight,
@@ -59,7 +60,7 @@ useTabsDrag(props, emit);
class="border-r px-2"
@click="scrollDirection('left')"
>
<ChevronLeft class="size-4 h-full" />
<ChevronsLeft class="size-4 h-full" />
</span>
<div
@@ -69,7 +70,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"
@@ -100,7 +101,7 @@ useTabsDrag(props, emit);
class="cursor-pointer border-l px-2 text-muted-foreground hover:bg-muted"
@click="scrollDirection('right')"
>
<ChevronRight class="size-4 h-full" />
<ChevronsRight class="size-4 h-full" />
</span>
</div>
</template>