更新最新代码

This commit is contained in:
luob
2025-12-24 23:48:38 +08:00
parent e728cf2c5e
commit 1fd17ef73a
1320 changed files with 83513 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
import { defineBuildConfig } from 'unbuild';
export default defineBuildConfig({
clean: true,
declaration: true,
entries: [
{
builder: 'mkdist',
input: './src',
loaders: ['vue'],
pattern: ['**/*.vue'],
},
{
builder: 'mkdist',
format: 'esm',
input: './src',
loaders: ['js'],
pattern: ['**/*.ts'],
},
],
});

View File

@@ -0,0 +1 @@
export { default } from '@vben/tailwind-config/postcss';

View File

@@ -0,0 +1,2 @@
export { default as TabsChrome } from './tabs-chrome/tabs.vue';
export { default as Tabs } from './tabs/tabs.vue';

View File

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

View File

@@ -0,0 +1,3 @@
export * from './components/widgets';
export { default as TabsView } from './tabs-view.vue';
export type { IContextMenuItem } from '@vben-core/shadcn-ui';

View File

@@ -0,0 +1,73 @@
import type { IContextMenuItem } from '@vben-core/shadcn-ui';
import type { TabDefinition, TabsStyleType } from '@vben-core/typings';
export type TabsEmits = {
close: [string];
sortTabs: [number, number];
unpin: [TabDefinition];
};
export interface TabsProps {
active?: string;
/**
* @zh_CN content class
* @default tabs-chrome
*/
contentClass?: string;
/**
* @zh_CN 右键菜单
*/
contextMenus?: (data: any) => IContextMenuItem[];
/**
* @zh_CN 是否可以拖拽
*/
draggable?: boolean;
/**
* @zh_CN 间隙
* @default 7
* 仅限 tabs-chrome
*/
gap?: number;
/**
* @zh_CN tab 最大宽度
* 仅限 tabs-chrome
*/
maxWidth?: number;
/**
* @zh_CN 点击中键时关闭Tab
*/
middleClickToClose?: boolean;
/**
* @zh_CN tab最小宽度
* 仅限 tabs-chrome
*/
minWidth?: number;
/**
* @zh_CN 是否显示图标
*/
showIcon?: boolean;
/**
* @zh_CN 标签页风格
*/
styleType?: TabsStyleType;
/**
* @zh_CN 选项卡数据
*/
tabs?: TabDefinition[];
/**
* @zh_CN 是否响应滚轮事件
*/
wheelable?: boolean;
}
export interface TabConfig extends TabDefinition {
affixTab: boolean;
closable: boolean;
icon: string;
key: string;
title: string;
}

View File

@@ -0,0 +1,124 @@
import type { Sortable } from '@vben-core/composables';
import type { EmitType } from '@vben-core/typings';
import type { TabsProps } from './types';
import { nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import { useIsMobile, useSortable } from '@vben-core/composables';
// 可能会找到拖拽的子元素这里需要确保拖拽的dom时tab元素
function findParentElement(element: HTMLElement) {
const parentCls = 'group';
return element.classList.contains(parentCls)
? element
: element.closest(`.${parentCls}`);
}
export function useTabsDrag(props: TabsProps, emit: EmitType) {
const sortableInstance = ref<null | Sortable>(null);
async function initTabsSortable() {
await nextTick();
const el = document.querySelectorAll(
`.${props.contentClass}`,
)?.[0] as HTMLElement;
if (!el) {
console.warn('Element not found for sortable initialization');
return;
}
const resetElState = async () => {
el.style.cursor = 'default';
// el.classList.remove('dragging');
el.querySelector('.draggable')?.classList.remove('dragging');
};
const { initializeSortable } = useSortable(el, {
filter: (_evt, target: HTMLElement) => {
const parent = findParentElement(target);
const draggable = parent?.classList.contains('draggable');
return !draggable || !props.draggable;
},
onEnd(evt) {
const { newIndex, oldIndex } = evt;
// const fromElement = evt.item;
const { srcElement } = (evt as any).originalEvent;
if (!srcElement) {
resetElState();
return;
}
const srcParent = findParentElement(srcElement);
if (!srcParent) {
resetElState();
return;
}
if (!srcParent.classList.contains('draggable')) {
resetElState();
return;
}
if (
oldIndex !== undefined &&
newIndex !== undefined &&
!Number.isNaN(oldIndex) &&
!Number.isNaN(newIndex) &&
oldIndex !== newIndex
) {
emit('sortTabs', oldIndex, newIndex);
}
resetElState();
},
onMove(evt) {
const parent = findParentElement(evt.related);
if (parent?.classList.contains('draggable') && props.draggable) {
const isCurrentAffix = evt.dragged.classList.contains('affix-tab');
const isRelatedAffix = evt.related.classList.contains('affix-tab');
// 不允许在固定的tab和非固定的tab之间互相拖拽
return isCurrentAffix === isRelatedAffix;
} else {
return false;
}
},
onStart: () => {
el.style.cursor = 'grabbing';
el.querySelector('.draggable')?.classList.add('dragging');
// el.classList.add('dragging');
},
});
sortableInstance.value = await initializeSortable();
}
async function init() {
const { isMobile } = useIsMobile();
// 移动端下tab不需要拖拽
if (isMobile.value) {
return;
}
await nextTick();
initTabsSortable();
}
onMounted(init);
watch(
() => props.styleType,
() => {
sortableInstance.value?.destroy();
init();
},
);
onUnmounted(() => {
sortableInstance.value?.destroy();
});
}

View File

@@ -0,0 +1 @@
export { default } from '@vben/tailwind-config';

View File

@@ -0,0 +1,6 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@vben/tsconfig/web.json",
"include": ["src"],
"exclude": ["node_modules"]
}