Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into dev
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vben-core/design",
|
||||
"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": {
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
html {
|
||||
@apply text-foreground bg-background font-sans;
|
||||
|
||||
scroll-behavior: smooth;
|
||||
font-size: var(--font-size-base, 16px);
|
||||
font-variation-settings: normal;
|
||||
font-synthesis-weight: none;
|
||||
line-height: 1.15;
|
||||
text-size-adjust: 100%;
|
||||
scroll-behavior: smooth;
|
||||
text-rendering: optimizelegibility;
|
||||
text-size-adjust: 100%;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
/* -webkit-font-smoothing: antialiased;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vben-core/icons",
|
||||
"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": {
|
||||
|
||||
@@ -31,6 +31,7 @@ export {
|
||||
FoldHorizontal,
|
||||
Fullscreen,
|
||||
Github,
|
||||
Grid,
|
||||
Grip,
|
||||
GripVertical,
|
||||
History,
|
||||
@@ -39,6 +40,7 @@ export {
|
||||
Info,
|
||||
InspectionPanel,
|
||||
Languages,
|
||||
LayoutGrid,
|
||||
LoaderCircle,
|
||||
LockKeyhole,
|
||||
LogOut,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vben-core/shared",
|
||||
"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": {
|
||||
|
||||
@@ -22,6 +22,8 @@ export const VBEN_LOGO_URL =
|
||||
*/
|
||||
export const VBEN_PREVIEW_URL = 'https://www.vben.pro';
|
||||
|
||||
export const VBEN_ANTDV_NEXT_PREVIEW_URL = 'https://antdv-next.vben.pro';
|
||||
|
||||
export const VBEN_ELE_PREVIEW_URL = 'https://ele.vben.pro';
|
||||
|
||||
export const VBEN_NAIVE_PREVIEW_URL = 'https://naive.vben.pro';
|
||||
|
||||
107
packages/@core/base/shared/src/utils/__tests__/stack.test.ts
Normal file
107
packages/@core/base/shared/src/utils/__tests__/stack.test.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
import { beforeEach, describe, expect, it } from 'vitest';
|
||||
|
||||
import { createStack, Stack } from '../stack';
|
||||
|
||||
describe('stack', () => {
|
||||
let stack: Stack<number>;
|
||||
|
||||
beforeEach(() => {
|
||||
stack = new Stack<number>();
|
||||
});
|
||||
|
||||
it('push & size should work', () => {
|
||||
stack.push(1, 2);
|
||||
|
||||
expect(stack.size).toBe(2);
|
||||
});
|
||||
|
||||
it('peek should return top element without removing it', () => {
|
||||
stack.push(1, 2);
|
||||
|
||||
expect(stack.peek()).toBe(2);
|
||||
expect(stack.size).toBe(2);
|
||||
});
|
||||
|
||||
it('pop should remove and return top element', () => {
|
||||
stack.push(1, 2);
|
||||
|
||||
expect(stack.pop()).toBe(2);
|
||||
expect(stack.size).toBe(1);
|
||||
expect(stack.peek()).toBe(1);
|
||||
});
|
||||
|
||||
it('pop on empty stack should return undefined', () => {
|
||||
expect(stack.pop()).toBeUndefined();
|
||||
expect(stack.peek()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('clear should remove all elements', () => {
|
||||
stack.push(1, 2);
|
||||
|
||||
stack.clear();
|
||||
|
||||
expect(stack.size).toBe(0);
|
||||
expect(stack.peek()).toBeUndefined();
|
||||
});
|
||||
|
||||
it('toArray should return a shallow copy', () => {
|
||||
stack.push(1, 2);
|
||||
|
||||
const arr = stack.toArray();
|
||||
arr.push(3);
|
||||
|
||||
expect(stack.size).toBe(2);
|
||||
expect(stack.toArray()).toEqual([1, 2]);
|
||||
});
|
||||
|
||||
it('dedup should remove existing item before push', () => {
|
||||
stack.push(1, 2, 1);
|
||||
|
||||
expect(stack.toArray()).toEqual([2, 1]);
|
||||
expect(stack.size).toBe(2);
|
||||
});
|
||||
|
||||
it('dedup = false should allow duplicate items', () => {
|
||||
const s = new Stack<number>(false);
|
||||
|
||||
s.push(1, 1, 1);
|
||||
|
||||
expect(s.toArray()).toEqual([1, 1, 1]);
|
||||
expect(s.size).toBe(3);
|
||||
});
|
||||
|
||||
it('remove should delete all matching items', () => {
|
||||
stack.push(1, 2, 1);
|
||||
|
||||
stack.remove(1);
|
||||
|
||||
expect(stack.toArray()).toEqual([2]);
|
||||
expect(stack.size).toBe(1);
|
||||
});
|
||||
|
||||
it('maxSize should limit stack capacity', () => {
|
||||
const s = new Stack<number>(true, 3);
|
||||
|
||||
s.push(1, 2, 3, 4);
|
||||
|
||||
expect(s.toArray()).toEqual([2, 3, 4]);
|
||||
expect(s.size).toBe(3);
|
||||
});
|
||||
|
||||
it('dedup + maxSize should work together', () => {
|
||||
const s = new Stack<number>(true, 3);
|
||||
|
||||
s.push(1, 2, 3, 2); // 去重并重新入栈
|
||||
|
||||
expect(s.toArray()).toEqual([1, 3, 2]);
|
||||
expect(s.size).toBe(3);
|
||||
});
|
||||
|
||||
it('createStack should create a stack instance', () => {
|
||||
const s = createStack<number>(true, 2);
|
||||
|
||||
s.push(1, 2, 3);
|
||||
|
||||
expect(s.toArray()).toEqual([2, 3]);
|
||||
});
|
||||
});
|
||||
@@ -10,6 +10,7 @@ export * from './letter';
|
||||
export * from './merge';
|
||||
export * from './nprogress';
|
||||
export * from './resources';
|
||||
export * from './stack';
|
||||
export * from './state-handler';
|
||||
export * from './time';
|
||||
export * from './to';
|
||||
|
||||
103
packages/@core/base/shared/src/utils/stack.ts
Normal file
103
packages/@core/base/shared/src/utils/stack.ts
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* @zh_CN 栈数据结构
|
||||
*/
|
||||
export class Stack<T> {
|
||||
/**
|
||||
* @zh_CN 栈内元素数量
|
||||
*/
|
||||
get size() {
|
||||
return this.items.length;
|
||||
}
|
||||
/**
|
||||
* @zh_CN 是否去重
|
||||
*/
|
||||
private readonly dedup: boolean;
|
||||
/**
|
||||
* @zh_CN 栈内元素
|
||||
*/
|
||||
private items: T[] = [];
|
||||
|
||||
/**
|
||||
* @zh_CN 栈的最大容量
|
||||
*/
|
||||
private readonly maxSize?: number;
|
||||
|
||||
constructor(dedup = true, maxSize?: number) {
|
||||
this.maxSize = maxSize;
|
||||
this.dedup = dedup;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh_CN 清空栈内元素
|
||||
*/
|
||||
clear() {
|
||||
this.items.length = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh_CN 查看栈顶元素
|
||||
* @returns 栈顶元素
|
||||
*/
|
||||
peek(): T | undefined {
|
||||
return this.items[this.items.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh_CN 出栈
|
||||
* @returns 栈顶元素
|
||||
*/
|
||||
pop(): T | undefined {
|
||||
return this.items.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh_CN 入栈
|
||||
* @param items 要入栈的元素
|
||||
*/
|
||||
push(...items: T[]) {
|
||||
items.forEach((item) => {
|
||||
// 去重
|
||||
if (this.dedup) {
|
||||
const index = this.items.indexOf(item);
|
||||
if (index !== -1) {
|
||||
this.items.splice(index, 1);
|
||||
}
|
||||
}
|
||||
this.items.push(item);
|
||||
if (this.maxSize && this.items.length > this.maxSize) {
|
||||
this.items.splice(0, this.items.length - this.maxSize);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* @zh_CN 移除栈内元素
|
||||
* @param itemList 要移除的元素列表
|
||||
*/
|
||||
remove(...itemList: T[]) {
|
||||
this.items = this.items.filter((i) => !itemList.includes(i));
|
||||
}
|
||||
/**
|
||||
* @zh_CN 保留栈内元素
|
||||
* @param itemList 要保留的元素列表
|
||||
*/
|
||||
retain(itemList: T[]) {
|
||||
this.items = this.items.filter((i) => itemList.includes(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh_CN 转换为数组
|
||||
* @returns 栈内元素数组
|
||||
*/
|
||||
toArray(): T[] {
|
||||
return [...this.items];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @zh_CN 创建一个栈实例
|
||||
* @param dedup 是否去重
|
||||
* @param maxSize 栈的最大容量
|
||||
* @returns 栈实例
|
||||
*/
|
||||
export const createStack = <T>(dedup = true, maxSize?: number) =>
|
||||
new Stack<T>(dedup, maxSize);
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vben-core/typings",
|
||||
"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": {
|
||||
|
||||
34
packages/@core/base/typings/src/helper.d.ts
vendored
34
packages/@core/base/typings/src/helper.d.ts
vendored
@@ -1,20 +1,38 @@
|
||||
import type { ComputedRef, MaybeRef } from 'vue';
|
||||
|
||||
/**
|
||||
* 类型级递归中增加深度计数
|
||||
*/
|
||||
type Increment<A extends unknown[]> = [...A, unknown];
|
||||
/**
|
||||
* 深层递归所有属性为可选
|
||||
*/
|
||||
type DeepPartial<T> = T extends object
|
||||
? {
|
||||
[P in keyof T]?: DeepPartial<T[P]>;
|
||||
}
|
||||
: T;
|
||||
type DeepPartial<
|
||||
T,
|
||||
D extends number = 10,
|
||||
C extends unknown[] = [],
|
||||
> = C['length'] extends D
|
||||
? T
|
||||
: T extends object
|
||||
? {
|
||||
[P in keyof T]?: DeepPartial<T[P], D, Increment<C>>;
|
||||
}
|
||||
: T;
|
||||
|
||||
/**
|
||||
* 深层递归所有属性为只读
|
||||
*/
|
||||
type DeepReadonly<T> = {
|
||||
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
|
||||
};
|
||||
type DeepReadonly<
|
||||
T,
|
||||
D extends number = 10,
|
||||
C extends unknown[] = [],
|
||||
> = C['length'] extends D
|
||||
? T
|
||||
: T extends object
|
||||
? {
|
||||
readonly [P in keyof T]: DeepReadonly<T[P], D, Increment<C>>;
|
||||
}
|
||||
: T;
|
||||
|
||||
/**
|
||||
* 任意类型的异步函数
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vben-core/composables",
|
||||
"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": {
|
||||
|
||||
@@ -104,7 +104,9 @@ exports[`defaultPreferences immutability test > should not modify the config obj
|
||||
"showIcon": true,
|
||||
"showMaximize": true,
|
||||
"showMore": true,
|
||||
"showRefresh": true,
|
||||
"styleType": "chrome",
|
||||
"visitHistory": true,
|
||||
"wheelable": true,
|
||||
},
|
||||
"theme": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vben-core/preferences",
|
||||
"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": {
|
||||
|
||||
@@ -105,7 +105,9 @@ const defaultPreferences: Preferences = {
|
||||
showIcon: true,
|
||||
showMaximize: true,
|
||||
showMore: true,
|
||||
showRefresh: true,
|
||||
styleType: 'chrome',
|
||||
visitHistory: true,
|
||||
wheelable: true,
|
||||
},
|
||||
theme: {
|
||||
|
||||
@@ -38,12 +38,10 @@ const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
|
||||
primaryColor: 'hsl(240 5.9% 10%)',
|
||||
type: 'zinc',
|
||||
},
|
||||
|
||||
{
|
||||
color: 'hsl(181 84% 32%)',
|
||||
type: 'deep-green',
|
||||
},
|
||||
|
||||
{
|
||||
color: 'hsl(211 91% 39%)',
|
||||
type: 'deep-blue',
|
||||
@@ -56,7 +54,6 @@ const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
|
||||
color: 'hsl(0 75% 42%)',
|
||||
type: 'rose',
|
||||
},
|
||||
|
||||
{
|
||||
color: 'hsl(0 0% 25%)',
|
||||
darkPrimaryColor: 'hsl(0 0% 98%)',
|
||||
|
||||
@@ -222,8 +222,12 @@ interface TabbarPreferences {
|
||||
showMaximize: boolean;
|
||||
/** 显示更多按钮 */
|
||||
showMore: boolean;
|
||||
/** 显示刷新按钮 */
|
||||
showRefresh: boolean;
|
||||
/** 标签页风格 */
|
||||
styleType: TabsStyleType;
|
||||
/** 是否开启访问历史记录 */
|
||||
visitHistory: boolean;
|
||||
/** 是否开启鼠标滚轮响应 */
|
||||
wheelable: boolean;
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
}"
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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
|
||||
/>
|
||||
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user