xingyu4j 2026-06-08 10:39:47 +08:00
commit b37657a92d
15 changed files with 1440 additions and 1309 deletions

View File

@ -61,7 +61,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
@ -89,6 +89,6 @@ jobs:
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
uses: github/codeql-action/analyze@v4
with:
category: '/language:${{matrix.language}}'

View File

@ -19,7 +19,7 @@ jobs:
steps:
# 关闭未活动的 Issues
- name: Close Inactive Issues
uses: actions/stale@v9
uses: actions/stale@v10
with:
days-before-stale: -1 # Issues and PR will never be flagged stale automatically.
stale-issue-label: needs-reproduction # Label that flags an issue as stale.

View File

@ -14,7 +14,7 @@ jobs:
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5
- uses: dessant/lock-threads@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
issue-inactive-days: '14'

View File

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Validate PR title
uses: amannn/action-semantic-pull-request@v5
uses: amannn/action-semantic-pull-request@v6
with:
wip: true
subjectPattern: ^(?![A-Z]).+$

View File

@ -9,7 +9,7 @@ jobs:
if: github.repository == 'vbenjs/vue-vben-admin'
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
- uses: actions/stale@v10
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days'

View File

@ -1 +1 @@
22.22.0
24.16.0

View File

@ -36,13 +36,16 @@ import type { Component, Ref } from 'vue';
import type {
ApiComponentSharedProps,
BaseFormComponentType,
CollapsibleParamsProps,
IconPickerProps,
} from '@vben/common-ui';
import type { Sortable } from '@vben/hooks';
import type { TipTapProps } from '@vben/plugins/tiptap';
import type { Recordable } from '@vben/types';
import {
computed,
defineAsyncComponent,
defineComponent,
h,
nextTick,
@ -58,44 +61,18 @@ import {
ApiComponent,
globalShareState,
IconPicker,
VbenCollapsibleParams,
VCropper,
} from '@vben/common-ui';
import { useSortable } from '@vben/hooks';
import { IconifyIcon } from '@vben/icons';
import { $t } from '@vben/locales';
import { VbenTiptap } from '@vben/plugins/tiptap';
import { isEmpty } from '@vben/utils';
import {
AutoComplete as AutoCompleteComponent,
Button,
Cascader as CascaderComponent,
Checkbox as CheckboxComponent,
CheckboxGroup as CheckboxGroupComponent,
DatePicker as DatePickerComponent,
Divider as DividerComponent,
Image as ImageComponent,
ImagePreviewGroup,
Input as InputComponent,
InputNumber as InputNumberComponent,
InputPassword,
Mentions as MentionsComponent,
message,
Modal,
notification,
Radio as RadioComponent,
RadioGroup as RadioGroupComponent,
DateRangePicker as RangePickerComponent,
Rate as RateComponent,
Select as SelectComponent,
Space as SpaceComponent,
Switch as SwitchComponent,
TextArea as TextareaComponent,
TimePicker as TimePickerComponent,
TimeRangePicker as TimeRangePickerComponent,
TreeSelect as TreeSelectComponent,
Upload as UploadComponent,
} from 'antdv-next';
import { message, Modal, notification } from 'antdv-next';
import { uploadFile as uploadFileApi } from '#/api/infra/file';
import { Tinymce as RichTextarea } from '#/components/tinymce';
import { FileUpload, ImageUpload } from '#/components/upload';
type AdapterUploadProps = UploadProps & {
@ -108,29 +85,70 @@ type AdapterUploadProps = UploadProps & {
onHandleChange?: (event: UploadChangeParam) => void;
};
const AutoComplete = AutoCompleteComponent;
const Checkbox = CheckboxComponent;
const CheckboxGroup = CheckboxGroupComponent;
const DatePicker = DatePickerComponent;
const Divider = DividerComponent;
const Input = InputComponent;
const InputNumber = InputNumberComponent;
const Mentions = MentionsComponent;
const Radio = RadioComponent;
const RadioGroup = RadioGroupComponent;
const RangePicker = RangePickerComponent;
const Rate = RateComponent;
const Select = SelectComponent;
const Space = SpaceComponent;
const Switch = SwitchComponent;
const TextArea = TextareaComponent;
const TimePicker = TimePickerComponent;
const TimeRangePicker = TimeRangePickerComponent;
const TreeSelect = TreeSelectComponent;
const Cascader = CascaderComponent;
const Upload = UploadComponent;
const Image = ImageComponent;
const PreviewGroup = ImagePreviewGroup;
const AutoComplete = defineAsyncComponent(
() => import('antdv-next/dist/auto-complete/index'),
);
const Button = defineAsyncComponent(
() => import('antdv-next/dist/button/index'),
);
const Checkbox = defineAsyncComponent(
() => import('antdv-next/dist/checkbox/index'),
);
const CheckboxGroup = defineAsyncComponent(() =>
import('antdv-next/dist/checkbox/index').then((res) => res.CheckboxGroup),
);
const DatePicker = defineAsyncComponent(
() => import('antdv-next/dist/date-picker/index'),
);
const Divider = defineAsyncComponent(
() => import('antdv-next/dist/divider/index'),
);
const Input = defineAsyncComponent(() => import('antdv-next/dist/input/index'));
const InputNumber = defineAsyncComponent(
() => import('antdv-next/dist/input-number/index'),
);
const InputPassword = defineAsyncComponent(() =>
import('antdv-next/dist/input/index').then((res) => res.InputPassword),
);
const Mentions = defineAsyncComponent(
() => import('antdv-next/dist/mentions/index'),
);
const Radio = defineAsyncComponent(() => import('antdv-next/dist/radio/index'));
const RadioGroup = defineAsyncComponent(() =>
import('antdv-next/dist/radio/index').then((res) => res.RadioGroup),
);
const RangePicker = defineAsyncComponent(() =>
import('antdv-next/dist/date-picker/index').then(
(res) => res.DateRangePicker,
),
);
const Rate = defineAsyncComponent(() => import('antdv-next/dist/rate/index'));
const Select = defineAsyncComponent(
() => import('antdv-next/dist/select/index'),
);
const Space = defineAsyncComponent(() => import('antdv-next/dist/space/index'));
const Switch = defineAsyncComponent(
() => import('antdv-next/dist/switch/index'),
);
const Textarea = defineAsyncComponent(
() => import('antdv-next/dist/input/TextArea'),
);
const TimePicker = defineAsyncComponent(
() => import('antdv-next/dist/time-picker/index'),
);
const TreeSelect = defineAsyncComponent(
() => import('antdv-next/dist/tree-select/index'),
);
const Cascader = defineAsyncComponent(
() => import('antdv-next/dist/cascader/index'),
);
const Upload = defineAsyncComponent(
() => import('antdv-next/dist/upload/index'),
);
const Image = defineAsyncComponent(() => import('antdv-next/dist/image/index'));
const PreviewGroup = defineAsyncComponent(() =>
import('antdv-next/dist/image/index').then((res) => res.ImagePreviewGroup),
);
const withDefaultPlaceholder = (
component: Component,
@ -236,7 +254,7 @@ function getBase64(file: File): Promise<string> {
*/
async function previewImage(
file: UploadFile,
visible: Ref<boolean>,
open: Ref<boolean>,
fileList: Ref<UploadProps['fileList']>,
) {
// 非图片文件直接打开链接
@ -244,6 +262,8 @@ async function previewImage(
const url = file.url || file.preview;
if (url) {
window.open(url, '_blank');
} else if (file.preview) {
window.open(file.preview, '_blank');
} else {
message.error($t('ui.formRules.previewWarning'));
}
@ -279,10 +299,10 @@ async function previewImage(
{
class: 'hidden',
preview: {
open: visible.value,
open: open.value,
current: currentIndex,
onOpenChange: (value: boolean) => {
visible.value = value;
open.value = value;
if (!value) {
setTimeout(() => {
if (!isUnmounted && container) {
@ -324,7 +344,7 @@ function cropImage(file: File, aspectRatio: string | undefined) {
const open = ref<boolean>(true);
const cropperRef = ref<InstanceType<typeof VCropper> | null>(null);
const closeModal = () => {
function closeModal() {
open.value = false;
setTimeout(() => {
if (!isUnmounted && container) {
@ -336,7 +356,7 @@ function cropImage(file: File, aspectRatio: string | undefined) {
container.remove();
}
}, 300);
};
}
const CropperWrapper = {
setup() {
@ -366,7 +386,7 @@ function cropImage(file: File, aspectRatio: string | undefined) {
closable: false,
cancelText: $t('common.cancel'),
okText: $t('ui.crop.confirm'),
destroyOnClose: true,
destroyOnHidden: true,
onOk: async () => {
const cropper = cropperRef.value;
if (!cropper) {
@ -410,7 +430,7 @@ function cropImage(file: File, aspectRatio: string | undefined) {
/**
*
*/
const withPreviewUpload = () => {
function withPreviewUpload() {
return defineComponent({
name: Upload.name,
emits: ['update:modelValue'],
@ -430,10 +450,10 @@ const withPreviewUpload = () => {
() => attrs?.aspectRatio ?? attrs?.['aspect-ratio'],
);
const handleBeforeUpload = async (
async function handleBeforeUpload(
file: UploadFile,
originFileList: Array<File>,
) => {
) {
// 文件大小限制
if (maxSize.value && (file.size || 0) / 1024 / 1024 > maxSize.value) {
message.error($t('ui.formRules.sizeLimit', [maxSize.value]));
@ -457,9 +477,9 @@ const withPreviewUpload = () => {
}
return attrs.beforeUpload?.(file) ?? true;
};
}
const handleChange = (event: UploadChangeParam) => {
function handleChange(event: UploadChangeParam) {
try {
attrs.handleChange?.(event);
attrs.onHandleChange?.(event);
@ -473,19 +493,19 @@ const withPreviewUpload = () => {
'update:modelValue',
event.fileList?.length ? fileList.value : undefined,
);
};
}
const handlePreview = async (file: UploadFile) => {
function handlePreview(file: UploadFile) {
previewVisible.value = true;
await previewImage(file, previewVisible, fileList);
};
return previewImage(file, previewVisible, fileList);
}
const renderUploadButton = () => {
function renderUploadButton() {
if (attrs.disabled) return null;
return isEmpty(slots)
? createDefaultUploadSlots(listType, placeholder)
: slots;
};
}
// 拖拽排序
const draggable = computed(
@ -594,7 +614,7 @@ const withPreviewUpload = () => {
);
},
});
};
}
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type ComponentType =
@ -605,6 +625,7 @@ export type ComponentType =
| 'Cascader'
| 'Checkbox'
| 'CheckboxGroup'
| 'CollapsibleParams'
| 'DatePicker'
| 'DefaultButton'
| 'Divider'
@ -620,13 +641,13 @@ export type ComponentType =
| 'RadioGroup'
| 'RangePicker'
| 'Rate'
| 'RichEditor'
| 'RichTextarea'
| 'Select'
| 'Space'
| 'Switch'
| 'TextArea'
| 'TimePicker'
| 'TimeRangePicker'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
@ -642,6 +663,7 @@ export interface ComponentPropsMap {
Cascader: CascaderProps;
Checkbox: CheckboxProps;
CheckboxGroup: CheckboxGroupProps;
CollapsibleParams: CollapsibleParamsProps;
DatePicker: DatePickerProps;
DefaultButton: ButtonProps;
Divider: DividerProps;
@ -655,6 +677,7 @@ export interface ComponentPropsMap {
RadioGroup: RadioGroupProps;
RangePicker: RangePickerProps;
Rate: RateProps;
RichEditor: TipTapProps;
Select: SelectProps;
Space: SpaceProps;
Switch: SwitchProps;
@ -720,18 +743,39 @@ async function initComponentAdapter() {
RadioGroup,
RangePicker,
Rate,
RichEditor: withDefaultPlaceholder(VbenTiptap, 'input', {
imageUpload: {
upload: (file: any, onProgress: any) => {
return new Promise((resolve, reject) => {
uploadFileApi({
file,
onProgress({ percent }) {
onProgress?.(percent);
},
onSuccess(response) {
// 从响应中提取图片URL
resolve(response?.data?.url ?? response?.url ?? '');
},
onError() {
reject(new Error($t('ui.tiptap.upload.uploadFailed')));
},
});
});
},
},
}),
Select: withDefaultPlaceholder(Select, 'select'),
Space,
Switch,
TextArea: withDefaultPlaceholder(TextArea, 'input'),
TextArea: withDefaultPlaceholder(Textarea, 'input'),
RichTextarea,
TimePicker,
TimeRangePicker,
TreeSelect: withDefaultPlaceholder(TreeSelect, 'select'),
Upload,
PreviewUpload: withPreviewUpload(),
FileUpload,
ImageUpload,
Upload: withPreviewUpload(),
CollapsibleParams: VbenCollapsibleParams,
};
// 将组件注册到全局共享状态中

View File

@ -105,5 +105,5 @@
"node": "^22.18.0 || ^24.0.0",
"pnpm": ">=11.0.0"
},
"packageManager": "pnpm@11.5.0"
"packageManager": "pnpm@11.5.2"
}

View File

@ -67,7 +67,7 @@ const props = withDefaults(defineProps<Props>(), {
const emit = defineEmits<{
sideMouseLeave: [];
toggleSidebar: [];
'update:sidebar-width': [value: number];
'update:sidebarWidth': [value: number];
}>();
const sidebarDraggable = defineModel<boolean>('sidebarDraggable', {
default: true,
@ -520,7 +520,7 @@ const idMainContent = ELEMENT_ID_MAIN_CONTENT;
:width="getSidebarWidth"
:z-index="sidebarZIndex"
@leave="() => emit('sideMouseLeave')"
@update:width="(val) => emit('update:sidebar-width', val)"
@update:width="(val) => emit('update:sidebarWidth', val)"
>
<template v-if="isSideMode && !isMixedNav" #logo>
<slot name="logo"></slot>

View File

@ -1,7 +1,16 @@
<script lang="ts" setup>
import type { ExtendedModalApi, ModalProps } from './modal';
import { computed, nextTick, onDeactivated, ref, unref, watch } from 'vue';
import {
computed,
nextTick,
onDeactivated,
provide,
ref,
unref,
useId,
watch,
} from 'vue';
import { usePriorityValues, useSimpleLocale } from '@vben-core/composables';
import { Expand, Shrink } from '@vben-core/icons';
@ -47,6 +56,10 @@ const footerRef = ref();
const { $t } = useSimpleLocale();
const state = props.modalApi?.useStore?.();
const id = useId();
// id Modal
provide('DISMISSABLE_MODAL_ID', id);
const {
appendToMain,
bordered,
@ -181,8 +194,15 @@ function handleOpenAutoFocus(e: Event) {
// pointer-down-outside
function pointerDownOutside(e: Event) {
if (!closeOnClickModal.value || submitting.value) {
const target = e.target as HTMLElement;
const isDismissableModal = target?.dataset.dismissableModal;
if (
!closeOnClickModal.value ||
isDismissableModal !== id ||
submitting.value
) {
e.preventDefault();
e.stopPropagation();
}
}
@ -212,7 +232,7 @@ function handleClosed() {
</script>
<template>
<Dialog
:modal="modal"
:modal="false"
:open="state?.isOpen"
@update:open="() => (!submitting ? modalApi?.close() : undefined)"
>
@ -240,7 +260,7 @@ function handleClosed() {
:force-mount="getForceMount"
:modal="modal"
:open="state?.isOpen"
:show-close="closable"
:show-close-button="closable"
:animation-type="animationType"
:z-index="zIndex"
:overlay-blur="overlayBlur"

View File

@ -1,33 +1,39 @@
<script setup lang="ts">
import type { DialogContentEmits, DialogContentProps } from 'reka-ui';
import type { HTMLAttributes } from 'vue';
import type { ClassType } from '@vben-core/typings';
import { computed, ref } from 'vue';
import { computed, inject, ref } from 'vue';
import { useScrollLock } from '@vben-core/composables';
import { cn } from '@vben-core/shared/utils';
import { X } from '@lucide/vue';
import {
DialogClose,
DialogContent,
DialogOverlay,
DialogPortal,
useForwardPropsEmits,
} from 'reka-ui';
defineOptions({
inheritAttrs: false,
});
const props = withDefaults(
defineProps<
DialogContentProps & {
animationType?: 'scale' | 'slide';
appendTo?: HTMLElement | string;
class?: ClassType;
class?: HTMLAttributes['class'];
closeClass?: ClassType;
closeDisabled?: boolean;
modal?: boolean;
open?: boolean;
overlayBlur?: number;
showClose?: boolean;
showCloseButton?: boolean;
zIndex?: number;
}
>(),
@ -35,7 +41,7 @@ const props = withDefaults(
appendTo: 'body',
animationType: 'slide',
closeDisabled: false,
showClose: true,
showCloseButton: true,
},
);
const emits = defineEmits<
@ -47,7 +53,7 @@ const delegatedProps = computed(() => {
class: _,
modal: _modal,
open: _open,
showClose: __,
showCloseButton: __,
animationType: ___,
...delegated
} = props;
@ -67,6 +73,12 @@ const position = computed(() => {
return isAppendToBody() ? 'fixed' : 'absolute';
});
// reka-ui Dialog modal=false
// / modal=true body pointer-events:none
// Select
useScrollLock();
const dismissableModalId = inject('DISMISSABLE_MODAL_ID', undefined);
const forwarded = useForwardPropsEmits(delegatedProps, emits);
const contentRef = ref<InstanceType<typeof DialogContent> | null>(null);
@ -87,23 +99,24 @@ defineExpose({
<template>
<DialogPortal :to="appendTo">
<DialogOverlay
v-if="open && modal"
:style="{
...(zIndex ? { zIndex } : {}),
position,
backdropFilter:
overlayBlur && overlayBlur > 0 ? `blur(${overlayBlur}px)` : 'none',
}"
:class="
cn(
'z-popup bg-overlay inset-0 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed',
)
"
/>
<Transition name="fade">
<div
v-if="open && modal"
:data-dismissable-modal="dismissableModalId"
:style="{
...(zIndex ? { zIndex } : {}),
position,
backdropFilter:
overlayBlur && overlayBlur > 0 ? `blur(${overlayBlur}px)` : 'none',
}"
:class="cn('z-popup bg-overlay inset-0 fixed')"
@click="() => emits('close')"
></div>
</Transition>
<DialogContent
ref="contentRef"
:style="{ ...(zIndex ? { zIndex } : {}), position }"
data-slot="dialog-content"
@animationend="onAnimationEnd"
v-bind="forwarded"
:class="
@ -120,8 +133,9 @@ defineExpose({
<slot></slot>
<DialogClose
v-if="showClose"
v-if="showCloseButton"
:disabled="closeDisabled"
data-slot="dialog-close"
:class="
cn(
'flex-center text-foreground/80 hover:bg-accent hover:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-3 right-3 h-6 w-6 rounded-full px-1 text-lg opacity-70 transition-opacity hover:opacity-100 focus:outline-hidden disabled:pointer-events-none',
@ -130,7 +144,7 @@ defineExpose({
"
@click="() => emits('close')"
>
<X class="h-4 w-4" />
<X class="size-4" />
</DialogClose>
</DialogContent>
</DialogPortal>

View File

@ -1,13 +1,31 @@
<script setup lang="ts">
import type { DialogOverlayProps } from 'reka-ui';
import type { HTMLAttributes } from 'vue';
import { cn } from '@vben-core/shared/utils';
import { reactiveOmit } from '@vueuse/core';
import { DialogOverlay } from 'reka-ui';
const props = defineProps<DialogOverlayProps>();
const props = defineProps<
DialogOverlayProps & { class?: HTMLAttributes['class'] }
>();
const delegatedProps = reactiveOmit(props, 'class');
</script>
<template>
<DialogOverlay data-slot="dialog-overlay" v-bind="props">
<DialogOverlay
data-slot="dialog-overlay"
v-bind="delegatedProps"
:class="
cn(
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
props.class,
)
"
>
<slot></slot>
</DialogOverlay>
</template>

View File

@ -60,7 +60,7 @@ const forwarded = useForwardPropsEmits(delegatedProps, emits);
<DialogClose
class="absolute top-4 right-4 p-0.5 transition-colors rounded-md hover:bg-secondary"
>
<X class="w-4 h-4" />
<X class="size-4" />
<span class="sr-only">Close</span>
</DialogClose>
</DialogContent>

File diff suppressed because it is too large Load Diff

View File

@ -40,7 +40,7 @@ catalog:
'@changesets/changelog-github': ^0.7.0
'@changesets/cli': ^2.31.0
'@changesets/git': ^3.0.4
'@clack/prompts': ^1.5.0
'@clack/prompts': ^1.5.1
'@commitlint/cli': ^21.0.2
'@commitlint/config-conventional': ^21.0.2
'@ctrl/tinycolor': ^4.2.0
@ -52,7 +52,7 @@ catalog:
'@form-create/designer': ^3.5.0
'@form-create/element-ui': ^3.3.1
'@form-create/naive-ui': ^3.3.1
'@iconify/json': ^2.2.481
'@iconify/json': ^2.2.483
'@iconify/tailwind4': ^1.2.3
'@iconify/vue': ^5.0.1
'@intlify/core-base': ^11.4.4
@ -69,19 +69,19 @@ catalog:
'@tanstack/vue-store': ^0.11.0
'@tinyflow-ai/vue': ^1.3.6
'@tinymce/tinymce-vue': ^6.3.0
'@tiptap/core': ^3.24.0
'@tiptap/extension-document': ^3.24.0
'@tiptap/extension-highlight': ^3.24.0
'@tiptap/extension-image': ^3.24.0
'@tiptap/extension-link': ^3.24.0
'@tiptap/extension-placeholder': ^3.24.0
'@tiptap/extension-text-align': ^3.24.0
'@tiptap/extension-text-style': ^3.24.0
'@tiptap/extension-underline': ^3.24.0
'@tiptap/pm': ^3.24.0
'@tiptap/starter-kit': ^3.24.0
'@tiptap/vue-3': ^3.24.0
'@tsdown/css': ^0.22.1
'@tiptap/core': ^3.26.0
'@tiptap/extension-document': ^3.26.0
'@tiptap/extension-highlight': ^3.26.0
'@tiptap/extension-image': ^3.26.0
'@tiptap/extension-link': ^3.26.0
'@tiptap/extension-placeholder': ^3.26.0
'@tiptap/extension-text-align': ^3.26.0
'@tiptap/extension-text-style': ^3.26.0
'@tiptap/extension-underline': ^3.26.0
'@tiptap/pm': ^3.26.0
'@tiptap/starter-kit': ^3.26.0
'@tiptap/vue-3': ^3.26.0
'@tsdown/css': ^0.22.2
'@types/archiver': ^7.0.0
'@types/codemirror': ^5.60.17
'@types/crypto-js': ^4.2.2
@ -89,7 +89,7 @@ catalog:
'@types/json-bigint': ^1.0.4
'@types/lodash.clonedeep': ^4.5.9
'@types/markdown-it': ^14.1.2
'@types/node': ^25.9.1
'@types/node': ^25.9.2
'@types/nprogress': ^0.2.3
'@types/qrcode': ^1.5.6
'@types/qs': ^6.15.1
@ -102,14 +102,14 @@ catalog:
'@vitejs/plugin-vue': ^6.0.7
'@vitejs/plugin-vue-jsx': ^5.1.5
'@vue/shared': ^3.5.35
'@vue/test-utils': ^2.4.10
'@vue/test-utils': ^2.4.11
'@vueuse/core': ^14.3.0
'@vueuse/integrations': ^14.3.0
'@vueuse/motion': ^3.0.3
ant-design-vue: ^4.2.6
antdv-next: ^1.3.1
antdv-next: ^1.3.3
archiver: ^7.0.1
axios: ^1.16.1
axios: ^1.17.0
axios-mock-adapter: ^2.1.0
benz-amr-recorder: ^1.1.5
bpmn-js: ^17.11.1
@ -148,14 +148,14 @@ catalog:
eslint-plugin-pnpm: ^1.6.1
eslint-plugin-unicorn: ^64.0.0
eslint-plugin-unused-imports: ^4.4.1
eslint-plugin-vue: ^10.9.1
eslint-plugin-vue: ^10.9.2
eslint-plugin-yml: ^3.4.0
execa: ^9.6.1
fast-xml-parser: ^4.5.6
find-up: ^8.0.0
get-port: ^7.2.0
globals: ^17.6.0
happy-dom: ^20.9.0
happy-dom: ^20.10.2
highlight.js: ^11.11.1
html-minifier-terser: ^7.2.0
is-ci: ^4.1.0
@ -188,7 +188,7 @@ catalog:
publint: ^0.3.21
qrcode: ^1.5.4
qs: ^6.15.2
reka-ui: ^2.9.8
reka-ui: ^2.9.9
resolve.exports: ^2.0.3
rimraf: ^6.1.3
rollup-plugin-visualizer: ^7.0.1
@ -204,14 +204,14 @@ catalog:
stylelint-config-recommended-vue: ^1.6.1
stylelint-config-standard: ^40.0.0
stylelint-order: ^8.1.1
stylelint-scss: ^7.1.1
stylelint-scss: ^7.2.0
tailwind-merge: ^3.6.0
tailwindcss: ^4.3.0
tdesign-vue-next: ^1.20.0
tdesign-vue-next: ^1.20.1
theme-colors: ^0.1.0
tinymce: ^7.9.3
tippy.js: ^6.3.7
tsdown: ^0.22.1
tsdown: ^0.22.2
turbo: ^2.9.16
tw-animate-css: ^1.4.0
tyme4ts: ^1.5.1
@ -231,7 +231,7 @@ catalog:
vitest: ^4.1.8
vue: ^3.5.35
vue-dompurify-html: ^5.3.0
vue-eslint-parser: ^10.4.0
vue-eslint-parser: ^10.4.1
vue-i18n: ^11.4.4
vue-json-pretty: ^2.6.0
vue-router: ^5.1.0
@ -240,15 +240,15 @@ catalog:
vue3-print-nb: ^0.1.4
vue3-signature: ^0.4.4
vuedraggable: ^4.1.0
vxe-pc-ui: ^4.14.26
vxe-table: ^4.19.6
vxe-pc-ui: ^4.14.30
vxe-table: ^4.19.7
watermark-js-plus: ^1.6.3
yaml-eslint-parser: ^2.0.0
zod: ^3.25.76
zod-defaults: 0.1.3
allowBuilds:
'@carbon/icons': true
'@carbon/icons': false
'@parcel/watcher': true
core-js: true
core-js-pure: true