docs: update docs (#4466)

* chore: fixed known issues with form components

* docs: add vben form doc
pull/48/MERGE
Vben 2024-09-22 14:16:06 +08:00 committed by GitHub
parent dac80703d9
commit 5ce3a18785
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 1938 additions and 139 deletions

View File

@ -27,13 +27,13 @@ import {
Select,
Space,
Switch,
Textarea,
TimePicker,
TreeSelect,
Upload,
} from 'ant-design-vue';
// 业务表单组件适配
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type FormComponentType =
| 'AutoComplete'
| 'Checkbox'
@ -51,6 +51,7 @@ export type FormComponentType =
| 'Select'
| 'Space'
| 'Switch'
| 'Textarea'
| 'TimePicker'
| 'TreeSelect'
| 'Upload'
@ -83,12 +84,16 @@ setupVbenForm<FormComponentType>({
Select,
Space,
Switch,
Textarea,
TimePicker,
TreeSelect,
Upload,
},
config: {
// ant design vue组件库默认都是 v-model:value
baseModelPropName: 'value',
// 一些组件是 v-model:checked 或者 v-model:fileList
modelPropNameMap: {
Checkbox: 'checked',
Radio: 'checked',
@ -97,12 +102,14 @@ setupVbenForm<FormComponentType>({
},
},
defineRules: {
// 输入项目必填国际化适配
required: (value, _params, ctx) => {
if ((!value && value !== 0) || value.length === 0) {
if (value === undefined || value === null || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;
},
// 选择项目必填国际化适配
selectRequired: (value, _params, ctx) => {
if (value === undefined || value === null) {
return $t('formRules.selectRequired', [ctx.label]);

View File

@ -73,7 +73,7 @@ setupVbenForm<FormComponentType>({
},
defineRules: {
required: (value, _params, ctx) => {
if ((!value && value !== 0) || value.length === 0) {
if (value === undefined || value === null || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;

View File

@ -82,7 +82,7 @@ setupVbenForm<FormComponentType>({
},
defineRules: {
required: (value, _params, ctx) => {
if ((!value && value !== 0) || value.length === 0) {
if (value === undefined || value === null || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;

View File

@ -24,14 +24,16 @@ const parsedFiles = computed(() => {
class="not-prose relative w-full overflow-x-auto rounded-t-lg px-4 py-6"
>
<div class="flex w-full max-w-[700px] px-2">
<slot v-if="parsedFiles.length > 0"></slot>
<div v-else class="text-destructive text-sm">
<span class="bg-destructive text-foreground rounded-sm px-1 py-1">
ERROR:
</span>
The preview directory does not exist. Please check the 'dir'
parameter.
</div>
<ClientOnly>
<slot v-if="parsedFiles.length > 0"></slot>
<div v-else class="text-destructive text-sm">
<span class="bg-destructive text-foreground rounded-sm px-1 py-1">
ERROR:
</span>
The preview directory does not exist. Please check the 'dir'
parameter.
</div>
</ClientOnly>
</div>
</div>
<PreviewGroup v-if="parsedFiles.length > 0" :files="parsedFiles">

View File

@ -154,15 +154,19 @@ function sidebarComponents(): DefaultTheme.SidebarItem[] {
items: [
{
link: 'common-ui/vben-modal',
text: 'Vben Modal 模态框',
text: 'Modal 模态框',
},
{
link: 'common-ui/vben-drawer',
text: 'Vben Drawer 抽屉',
text: 'Drawer 抽屉',
},
{
link: 'common-ui/vben-form',
text: 'Vben Form 表单',
text: 'Form 表单',
},
{
link: 'common-ui/vben-count-to-animator',
text: 'CountToAnimator 数字动画',
},
],
},

View File

@ -1,30 +1,92 @@
<script lang="ts" setup>
import { nextTick, onMounted, watch } from 'vue';
import {
computed,
nextTick,
onBeforeUnmount,
onMounted,
ref,
watch,
} from 'vue';
// import { useAntdDesignTokens } from '@vben/hooks';
// import { initPreferences } from '@vben/preferences';
import { ConfigProvider, theme } from 'ant-design-vue';
import mediumZoom from 'medium-zoom';
import { useRoute } from 'vitepress';
import DefaultTheme from 'vitepress/theme';
const { Layout } = DefaultTheme;
const route = useRoute();
// const { tokens } = useAntdDesignTokens();
const initZoom = () => {
// mediumZoom('[data-zoomable]', { background: 'var(--vp-c-bg)' });
mediumZoom('.VPContent img', { background: 'var(--vp-c-bg)' });
};
const isDark = ref(true);
watch(
() => route.path,
() => nextTick(() => initZoom()),
);
// initPreferences({
// namespace: 'docs',
// });
onMounted(() => {
initZoom();
});
// 使
const observer = watchDarkModeChange((dark) => {
isDark.value = dark;
});
onBeforeUnmount(() => {
observer?.disconnect();
});
function watchDarkModeChange(callback: (isDark: boolean) => void) {
if (typeof window === 'undefined') {
return;
}
const htmlElement = document.documentElement;
const observer = new MutationObserver(() => {
const isDark = htmlElement.classList.contains('dark');
callback(isDark);
});
observer.observe(htmlElement, {
attributeFilter: ['class'],
attributes: true,
});
const initialIsDark = htmlElement.classList.contains('dark');
callback(initialIsDark);
return observer;
}
const tokenTheme = computed(() => {
const algorithm = isDark.value
? [theme.darkAlgorithm]
: [theme.defaultAlgorithm];
return {
algorithm,
// token: tokens,
};
});
</script>
<template>
<Layout />
<ConfigProvider :theme="tokenTheme">
<Layout />
</ConfigProvider>
</template>
<style>

View File

@ -5,3 +5,7 @@ html.dark {
.dark .VPContent {
/* background-color: #14161a; */
}
.form-valid-error p {
margin: 0;
}

View File

@ -7,10 +7,17 @@
"dev": "vitepress dev",
"docs:preview": "vitepress preview"
},
"imports": {
"#/*": "./src/_env/*"
},
"dependencies": {
"@vben-core/shadcn-ui": "workspace:*",
"@vben/common-ui": "workspace:*",
"@vben/hooks": "workspace:*",
"@vben/locales": "workspace:*",
"@vben/preferences": "workspace:*",
"@vben/styles": "workspace:*",
"ant-design-vue": "catalog:",
"lucide-vue-next": "catalog:",
"medium-zoom": "catalog:",
"radix-vue": "catalog:",

View File

@ -0,0 +1,127 @@
import type {
BaseFormComponentType,
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import { h } from 'vue';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import {
AutoComplete,
Button,
Checkbox,
CheckboxGroup,
DatePicker,
Divider,
Input,
InputNumber,
InputPassword,
Mentions,
Radio,
RadioGroup,
RangePicker,
Rate,
Select,
Space,
Switch,
Textarea,
TimePicker,
TreeSelect,
Upload,
} from 'ant-design-vue';
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type FormComponentType =
| 'AutoComplete'
| 'Checkbox'
| 'CheckboxGroup'
| 'DatePicker'
| 'Divider'
| 'Input'
| 'InputNumber'
| 'InputPassword'
| 'Mentions'
| 'Radio'
| 'RadioGroup'
| 'RangePicker'
| 'Rate'
| 'Select'
| 'Space'
| 'Switch'
| 'Textarea'
| 'TimePicker'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
// 初始化表单组件并注册到form组件内部
setupVbenForm<FormComponentType>({
components: {
AutoComplete,
Checkbox,
CheckboxGroup,
DatePicker,
// 自定义默认的重置按钮
DefaultResetActionButton: (props, { attrs, slots }) => {
return h(Button, { ...props, attrs, type: 'default' }, slots);
},
// 自定义默认的提交按钮
DefaultSubmitActionButton: (props, { attrs, slots }) => {
return h(Button, { ...props, attrs, type: 'primary' }, slots);
},
Divider,
Input,
InputNumber,
InputPassword,
Mentions,
Radio,
RadioGroup,
RangePicker,
Rate,
Select,
Space,
Switch,
Textarea,
TimePicker,
TreeSelect,
Upload,
},
config: {
// ant design vue组件库默认都是 v-model:value
baseModelPropName: 'value',
// 一些组件是 v-model:checked 或者 v-model:fileList
modelPropNameMap: {
Checkbox: 'checked',
Radio: 'checked',
Switch: 'checked',
Upload: 'fileList',
},
},
defineRules: {
// 输入项目必填国际化适配
required: (value, _params, ctx) => {
if (value === undefined || value === null || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;
},
// 选择项目必填国际化适配
selectRequired: (value, _params, ctx) => {
if (value === undefined || value === null) {
return $t('formRules.selectRequired', [ctx.label]);
}
return true;
},
},
});
const useVbenForm = useForm<FormComponentType>;
export { useVbenForm, z };
export type VbenFormSchema = FormSchema<FormComponentType>;
export type { VbenFormProps };

View File

@ -0,0 +1 @@
export * from './form';

View File

@ -0,0 +1,52 @@
---
outline: deep
---
# Vben CountToAnimator 数字动画
框架提供的数字动画组件,支持数字动画效果。
> 如果文档内没有参数说明,可以尝试在在线示例内寻找
::: info 写在前面
如果你觉得现有组件的封装不够理想,或者不完全符合你的需求,大可以直接使用原生组件,亦或亲手封装一个适合的组件。框架提供的组件并非束缚,使用与否,完全取决于你的需求与自由。
:::
## 基础用法
通过 `start-val``end-val`设置数字动画的开始值和结束值, 持续时间`3000`ms。
<DemoPreview dir="demos/vben-count-to-animator/basic" />
## 自定义前缀及分隔符
通过 `prefix``separator` 设置数字动画的前缀和分隔符。
<DemoPreview dir="demos/vben-count-to-animator/custom" />
### Props
| 属性名 | 描述 | 类型 | 默认值 |
| ---------- | -------------- | --------- | -------- |
| startVal | 起始值 | `number` | `0` |
| endVal | 结束值 | `number` | `2021` |
| duration | 动画持续时间 | `number` | `1500` |
| autoplay | 自动执行 | `boolean` | `true` |
| prefix | 前缀 | `string` | - |
| suffix | 后缀 | `string` | - |
| separator | 分隔符 | `string` | `,` |
| color | 字体颜色 | `string` | - |
| useEasing | 是否开启动画 | `boolean` | `true` |
| transition | 动画效果 | `string` | `linear` |
| decimals | 保留小数点位数 | `number` | `0` |
### Methods
以下事件,只有在 `useVbenModal({onCancel:()=>{}})` 中传入才会生效。
| 事件名 | 描述 | 类型 |
| ------ | ------------ | ---------- |
| start | 开始执行动画 | `()=>void` |
| reset | 重置 | `()=>void` |

View File

@ -4,8 +4,441 @@ outline: deep
# Vben Form 表单
框架提供的表单组件,可适配 `Element Plus`、`Ant Design Vue`、`Naive`UI 框架。
框架提供的表单组件,可适配 `Element Plus`、`Ant Design Vue`、`Naive UI` 等框架。
# 使用
> 如果文档内没有参数说明,可以尝试在在线示例内寻找
TODO
::: info 写在前面
如果你觉得现有组件的封装不够理想,或者不完全符合你的需求,大可以直接使用原生组件,亦或亲手封装一个适合的组件。框架提供的组件并非束缚,使用与否,完全取决于你的需求与自由。
:::
## 适配器
表单底层使用 [vee-validate](https://vee-validate.logaretm.com/v4/) 进行表单验证,所以你可以使用 `vee-validate` 的所有功能。对于不同的 UI 框架,我们提供了适配器,以便更好的适配不同的 UI 框架。
### 适配器说明
每个应用都有不同的 UI 框架,所以在应用的 `src/adapter/form` 内部,你可以根据自己的需求,进行组件适配。下面是 `Ant Design Vue` 的适配器示例代码,可根据注释查看说明:
::: details ant design 适配器
```ts
import type {
BaseFormComponentType,
VbenFormSchema as FormSchema,
VbenFormProps,
} from '@vben/common-ui';
import { h } from 'vue';
import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
import {
AutoComplete,
Button,
Checkbox,
CheckboxGroup,
DatePicker,
Divider,
Input,
InputNumber,
InputPassword,
Mentions,
Radio,
RadioGroup,
RangePicker,
Rate,
Select,
Space,
Switch,
Textarea,
TimePicker,
TreeSelect,
Upload,
} from 'ant-design-vue';
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type FormComponentType =
| 'AutoComplete'
| 'Checkbox'
| 'CheckboxGroup'
| 'DatePicker'
| 'Divider'
| 'Input'
| 'InputNumber'
| 'InputPassword'
| 'Mentions'
| 'Radio'
| 'RadioGroup'
| 'RangePicker'
| 'Rate'
| 'Select'
| 'Space'
| 'Switch'
| 'Textarea'
| 'TimePicker'
| 'TreeSelect'
| 'Upload'
| BaseFormComponentType;
// 初始化表单组件并注册到form组件内部
setupVbenForm<FormComponentType>({
components: {
AutoComplete,
Checkbox,
CheckboxGroup,
DatePicker,
// 自定义默认的重置按钮
DefaultResetActionButton: (props, { attrs, slots }) => {
return h(Button, { ...props, attrs, type: 'default' }, slots);
},
// 自定义默认的提交按钮
DefaultSubmitActionButton: (props, { attrs, slots }) => {
return h(Button, { ...props, attrs, type: 'primary' }, slots);
},
Divider,
Input,
InputNumber,
InputPassword,
Mentions,
Radio,
RadioGroup,
RangePicker,
Rate,
Select,
Space,
Switch,
Textarea,
TimePicker,
TreeSelect,
Upload,
},
config: {
// ant design vue组件库默认都是 v-model:value
baseModelPropName: 'value',
// 一些组件是 v-model:checked 或者 v-model:fileList
modelPropNameMap: {
Checkbox: 'checked',
Radio: 'checked',
Switch: 'checked',
Upload: 'fileList',
},
},
defineRules: {
// 输入项目必填国际化适配
required: (value, _params, ctx) => {
if (value === undefined || value === null || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;
},
// 选择项目必填国际化适配
selectRequired: (value, _params, ctx) => {
if (value === undefined || value === null) {
return $t('formRules.selectRequired', [ctx.label]);
}
return true;
},
},
});
const useVbenForm = useForm<FormComponentType>;
export { useVbenForm, z };
export type VbenFormSchema = FormSchema<FormComponentType>;
export type { VbenFormProps };
```
:::
## 基础用法
::: tip README
下方示例代码中的,存在一些国际化、主题色未适配问题,这些问题只在文档内会出现,实际使用并不会有这些问题,可忽略,不必纠结。
:::
使用 `useVbenForm` 创建最基础的表单。
<DemoPreview dir="demos/vben-form/basic" />
## 查询表单
查询表单是一种特殊的表单,用于查询数据。查询表单不会触发表单验证,只会触发查询事件。
<DemoPreview dir="demos/vben-form/query" />
## 表单校验
表单校验是一个非常重要的功能,可以通过 `rules` 属性进行校验。
<DemoPreview dir="demos/vben-form/rules" />
## 表单联动
表单联动是一个非常常见的功能,可以通过 `dependencies` 属性进行联动。
_注意_ 需要指定 `dependencies``triggerFields` 属性,设置由谁的改动来触发,以便表单组件能够正确的联动。
<DemoPreview dir="demos/vben-form/dynamic" />
## 自定义组件
如果你的业务组件库没有提供某个组件,你可以自行封装一个组件,然后加到表单内部。
<DemoPreview dir="demos/vben-form/custom" />
## 操作
一些常见的表单操作。
<DemoPreview dir="demos/vben-form/api" />
## API
`useVbenForm` 返回一个数组,第一个元素是表单组件,第二个元素是表单的方法。
```vue
<script setup lang="ts">
import { useVbenForm } from '#/adapter';
// Form 为弹窗组件
// formApi 为弹窗的方法
const [Form, formApi] = useVbenForm({
// 属性
// 事件
});
</script>
<template>
<Form />
</template>
```
### FormApi
useVbenForm 返回的第二个参数,是一个对象,包含了一些表单的方法。
| 方法名 | 描述 | 类型 |
| --- | --- | --- |
| submitForm | 提交表单 | `(e:Event)=>Promise<Record<string,any>>` |
| resetForm | 重置表单 | `()=>Promise<void>` |
| setValues | 设置表单值 | `()=>Promise<Record<string,any>>` |
| getValues | 获取表单值 | `(fields:Record<string, any>,shouldValidate: boolean = false)=>Promise<void>` |
| validate | 表单校验 | `()=>Promise<void>` |
| resetValidate | 重置表单校验 | `()=>Promise<void>` |
| updateSchema | 更新formSchema | `(schema:FormSchema[])=>void` |
| setFieldValue | 设置字段值 | `(field: string, value: any, shouldValidate?: boolean)=>Promise<void>` |
| setState | 设置组件状态props | `(stateOrFn:\| ((prev: VbenFormProps) => Partial<VbenFormProps>)\| Partial<VbenFormProps>)=>Promise<void>` |
| getState | 获取组件状态props | `()=>Promise<VbenFormProps>` |
| form | 表单对象实例,可以操作表单,见 [useForm](https://vee-validate.logaretm.com/v4/api/use-form/) | - |
## Props
所有属性都可以传入 `useVbenForm` 的第一个参数中。
| 属性名 | 描述 | 类型 | 默认值 |
| --- | --- | --- | --- |
| layout | 表单项布局 | `'horizontal' \| 'vertical'` | `horizontal` |
| showCollapseButton | 是否显示折叠按钮 | `boolean` | `false` |
| wrapperClass | 表单的布局基于tailwindcss | `any` | - |
| actionWrapperClass | 表单操作区域class | `any` | - |
| handleReset | 表单重置回调 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
| handleSubmit | 表单提交回调 | `(values: Record<string, any>,) => Promise<void> \| void` | - |
| resetButtonOptions | 重置按钮组件参数 | `ActionButtonOptions` | - |
| submitButtonOptions | 提交按钮组件参数 | `ActionButtonOptions` | - |
| showDefaultActions | 是否显示默认操作按钮 | `boolean` | `true` |
| collapsed | 是否折叠,在`是否展开在showCollapseButton=true`时生效 | `boolean` | `false` |
| collapsedRows | 折叠时保持的行数 | `number` | `1` |
| commonConfig | 表单项的通用配置,每个配置都会传递到每个表单项,表单项可覆盖 | `FormCommonConfig` | - |
| schema | 表单项的每一项配置 | `FormSchema` | - |
### TS 类型说明
::: details ActionButtonOptions
```ts
export interface ActionButtonOptions {
/** 样式 */
class?: any;
/** 是否禁用 */
disabled?: boolean;
/** 是否加载中 */
loading?: boolean;
/** 按钮大小 */
size?: ButtonVariantSize;
/** 按钮类型 */
variant?: ButtonVariants;
/** 是否显示 */
show?: boolean;
/** 按钮文本 */
text?: string;
}
```
:::
::: details FormCommonConfig
```ts
export interface FormCommonConfig {
/**
* 所有表单项的props
*/
componentProps?: ComponentProps;
/**
* 所有表单项的控件样式
*/
controlClass?: string;
/**
* 所有表单项的禁用状态
* @default false
*/
disabled?: boolean;
/**
* 所有表单项的控件样式
* @default {}
*/
formFieldProps?: Partial<typeof Field>;
/**
* 所有表单项的栅格布局
* @default ""
*/
formItemClass?: string;
/**
* 隐藏所有表单项label
* @default false
*/
hideLabel?: boolean;
/**
* 是否隐藏必填标记
* @default false
*/
hideRequiredMark?: boolean;
/**
* 所有表单项的label样式
* @default ""
*/
labelClass?: string;
/**
* 所有表单项的label宽度
*/
labelWidth?: number;
/**
* 所有表单项的wrapper样式
*/
wrapperClass?: string;
}
```
:::
::: details FormSchema
```ts
export interface FormSchema<
T extends BaseFormComponentType = BaseFormComponentType,
> extends FormCommonConfig {
/** 组件 */
component: Component | T;
/** 组件参数 */
componentProps?: ComponentProps;
/** 默认值 */
defaultValue?: any;
/** 依赖 */
dependencies?: FormItemDependencies;
/** 描述 */
description?: string;
/** 字段名 */
fieldName: string;
/** 帮助信息 */
help?: string;
/** 表单项 */
label?: string;
// 自定义组件内部渲染
renderComponentContent?: RenderComponentContentType;
/** 字段规则 */
rules?: FormSchemaRuleType;
/** 后缀 */
suffix?: CustomRenderType;
}
```
:::
### 表单联动
表单联动需要通过 schema 内的 `dependencies` 属性进行联动,允许您添加字段之间的依赖项,以根据其他字段的值控制字段。
```ts
dependencies: {
// 只有当 name 字段的值变化时,才会触发联动
triggerFields: ['name'],
// 动态判断当前字段是否需要显示,不显示则直接销毁
if(values,formApi){},
// 动态判断当前字段是否需要显示不显示用css隐藏
show(values,formApi){},
// 动态判断当前字段是否需要禁用
disabled(values,formApi){},
// 字段变更时,都会触发该函数
trigger(values,formApi){},
// 动态rules
rules(values,formApi){},
// 动态必填
required(values,formApi){},
// 动态组件参数
componentProps(values,formApi){},
}
```
### 表单校验
表单联动需要通过 schema 内的 `rules` 属性进行配置。
rules的值可以是一个字符串也可以是一个zod的schema。
#### 字符串
```ts
// 表示字段必填默认会根据适配器的required进行国际化
{
rules: 'required';
}
// 表示字段必填默认会根据适配器的required进行国际化用于下拉选择之类
{
rules: 'selectRequired';
}
```
#### zod
rules也支持 zod 的 schema可以进行更复杂的校验zod 的使用请查看 [zod文档](https://zod.dev/)。
```ts
import { z } from '#/adapter';
// 基础类型
{
rules: z.string().min(1, { message: '请输入字符串' });
}
// 可选,并且携带默认值
{
rules: z.string().default('默认值').optional(),
}
// 复杂校验
{
z.string().min(1, { message: "请输入" })
.refine((value) => value === "123", {
message: "值必须为123",
});
}
```

View File

@ -0,0 +1,6 @@
<script lang="ts" setup>
import { VbenCountToAnimator } from '@vben/common-ui';
</script>
<template>
<VbenCountToAnimator :duration="3000" :end-val="30000" :start-val="1" />
</template>

View File

@ -0,0 +1,12 @@
<script lang="ts" setup>
import { VbenCountToAnimator } from '@vben/common-ui';
</script>
<template>
<VbenCountToAnimator
:duration="3000"
:end-val="2000000"
:start-val="1"
prefix="$"
separator="/"
/>
</template>

View File

@ -0,0 +1,236 @@
<script lang="ts" setup>
import { Button, message, Space } from 'ant-design-vue';
import { useVbenForm } from '#/adapter';
const [BaseForm, formApi] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
// 使 tailwindcss grid
//
handleSubmit: onSubmit,
// labelinputvertical
layout: 'horizontal',
// labelinput
schema: [
{
// #/adapter.ts
component: 'Input',
//
componentProps: {
placeholder: '请输入用户名',
},
//
fieldName: 'field1',
// label
label: 'field1',
},
{
component: 'Select',
componentProps: {
allowClear: true,
filterOption: true,
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
placeholder: '请选择',
showSearch: true,
},
fieldName: 'fieldOptions',
label: '下拉选',
},
],
wrapperClass: 'grid-cols-1 md:grid-cols-2',
});
function onSubmit(values: Record<string, any>) {
message.success({
content: `form values: ${JSON.stringify(values)}`,
});
}
function handleClick(
action:
| 'batchAddSchema'
| 'batchDeleteSchema'
| 'disabled'
| 'hiddenAction'
| 'hiddenResetButton'
| 'hiddenSubmitButton'
| 'labelWidth'
| 'resetDisabled'
| 'resetLabelWidth'
| 'showAction'
| 'showResetButton'
| 'showSubmitButton'
| 'updateActionAlign'
| 'updateResetButton'
| 'updateSchema'
| 'updateSubmitButton',
) {
switch (action) {
case 'updateSchema': {
formApi.updateSchema([
{
componentProps: {
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
{
label: '选项3',
value: '3',
},
],
},
fieldName: 'fieldOptions',
},
]);
message.success('字段 `fieldOptions` 下拉选项更新成功。');
break;
}
case 'labelWidth': {
formApi.setState({
commonConfig: {
labelWidth: 150,
},
});
break;
}
case 'resetLabelWidth': {
formApi.setState({
commonConfig: {
labelWidth: 100,
},
});
break;
}
case 'disabled': {
formApi.setState({ commonConfig: { disabled: true } });
break;
}
case 'resetDisabled': {
formApi.setState({ commonConfig: { disabled: false } });
break;
}
case 'hiddenAction': {
formApi.setState({ showDefaultActions: false });
break;
}
case 'showAction': {
formApi.setState({ showDefaultActions: true });
break;
}
case 'hiddenResetButton': {
formApi.setState({ resetButtonOptions: { show: false } });
break;
}
case 'showResetButton': {
formApi.setState({ resetButtonOptions: { show: true } });
break;
}
case 'hiddenSubmitButton': {
formApi.setState({ submitButtonOptions: { show: false } });
break;
}
case 'showSubmitButton': {
formApi.setState({ submitButtonOptions: { show: true } });
break;
}
case 'updateResetButton': {
formApi.setState({
resetButtonOptions: { disabled: true },
});
break;
}
case 'updateSubmitButton': {
formApi.setState({
submitButtonOptions: { loading: true },
});
break;
}
case 'updateActionAlign': {
formApi.setState({
// class
actionWrapperClass: 'text-center',
});
break;
}
case 'batchAddSchema': {
formApi.setState((prev) => {
const currentSchema = prev?.schema ?? [];
const newSchema = [];
for (let i = 0; i < 2; i++) {
newSchema.push({
component: 'Input',
componentProps: {
placeholder: '请输入',
},
fieldName: `field${i}${Date.now()}`,
label: `field+`,
});
}
return {
schema: [...currentSchema, ...newSchema],
};
});
break;
}
case 'batchDeleteSchema': {
formApi.setState((prev) => {
const currentSchema = prev?.schema ?? [];
return {
schema: currentSchema.slice(0, -2),
};
});
break;
}
}
}
</script>
<template>
<div>
<Space class="mb-5 flex-wrap">
<Button @click="handleClick('updateSchema')">updateSchema</Button>
<Button @click="handleClick('labelWidth')">labelWidth</Button>
<Button @click="handleClick('resetLabelWidth')">labelWidth</Button>
<Button @click="handleClick('disabled')"></Button>
<Button @click="handleClick('resetDisabled')"></Button>
<Button @click="handleClick('hiddenAction')"></Button>
<Button @click="handleClick('showAction')"></Button>
<Button @click="handleClick('hiddenResetButton')"></Button>
<Button @click="handleClick('showResetButton')"></Button>
<Button @click="handleClick('hiddenSubmitButton')"></Button>
<Button @click="handleClick('showSubmitButton')"></Button>
<Button @click="handleClick('updateResetButton')"></Button>
<Button @click="handleClick('updateSubmitButton')"></Button>
<Button @click="handleClick('updateActionAlign')">
调整操作按钮位置
</Button>
<Button @click="handleClick('batchAddSchema')"> </Button>
<Button @click="handleClick('batchDeleteSchema')">
批量删除表单项
</Button>
</Space>
<BaseForm />
</div>
</template>

View File

@ -0,0 +1,231 @@
<script lang="ts" setup>
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter';
const [BaseForm] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
//
handleSubmit: onSubmit,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: [
{
// #/adapter.ts
component: 'Input',
//
componentProps: {
placeholder: '请输入用户名',
},
//
fieldName: 'username',
// label
label: '字符串',
},
{
component: 'InputPassword',
componentProps: {
placeholder: '请输入密码',
},
fieldName: 'password',
label: '密码',
},
{
component: 'InputNumber',
componentProps: {
placeholder: '请输入',
},
fieldName: 'number',
label: '数字(带后缀)',
suffix: () => '¥',
},
{
component: 'Select',
componentProps: {
allowClear: true,
filterOption: true,
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
placeholder: '请选择',
showSearch: true,
},
fieldName: 'options',
label: '下拉选',
},
{
component: 'RadioGroup',
componentProps: {
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
},
fieldName: 'radioGroup',
label: '单选组',
},
{
component: 'Radio',
fieldName: 'radio',
label: '',
renderComponentContent: () => {
return {
default: () => ['Radio'],
};
},
},
{
component: 'CheckboxGroup',
componentProps: {
name: 'cname',
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
},
fieldName: 'checkboxGroup',
label: '多选组',
},
{
component: 'Checkbox',
fieldName: 'checkbox',
label: '',
renderComponentContent: () => {
return {
default: () => ['我已阅读并同意'],
};
},
},
{
component: 'Mentions',
componentProps: {
options: [
{
label: 'afc163',
value: 'afc163',
},
{
label: 'zombieJ',
value: 'zombieJ',
},
],
placeholder: '请输入',
},
fieldName: 'mentions',
label: '提及',
},
{
component: 'Rate',
fieldName: 'rate',
label: '评分',
},
{
component: 'Switch',
componentProps: {
class: 'w-auto',
},
fieldName: 'switch',
label: '开关',
},
{
component: 'DatePicker',
fieldName: 'datePicker',
label: '日期选择框',
},
{
component: 'RangePicker',
fieldName: 'rangePicker',
label: '范围选择器',
},
{
component: 'TimePicker',
fieldName: 'timePicker',
label: '时间选择框',
},
{
component: 'TreeSelect',
componentProps: {
allowClear: true,
placeholder: '请选择',
showSearch: true,
treeData: [
{
label: 'root 1',
value: 'root 1',
children: [
{
label: 'parent 1',
value: 'parent 1',
children: [
{
label: 'parent 1-0',
value: 'parent 1-0',
children: [
{
label: 'my leaf',
value: 'leaf1',
},
{
label: 'your leaf',
value: 'leaf2',
},
],
},
{
label: 'parent 1-1',
value: 'parent 1-1',
},
],
},
{
label: 'parent 2',
value: 'parent 2',
},
],
},
],
treeNodeFilterProp: 'label',
},
fieldName: 'treeSelect',
label: '树选择',
},
],
wrapperClass: 'grid-cols-1',
});
function onSubmit(values: Record<string, any>) {
message.success({
content: `form values: ${JSON.stringify(values)}`,
});
}
</script>
<template>
<BaseForm />
</template>

View File

@ -0,0 +1,68 @@
<script lang="ts" setup>
import { h } from 'vue';
import { Input, message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter';
const [Form] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
labelClass: 'w-2/6',
},
//
handleSubmit: onSubmit,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: [
{
// #/adapter.ts
component: 'Input',
fieldName: 'field',
label: '自定义后缀',
suffix: () => h('span', { class: 'text-red-600' }, '元'),
},
{
component: 'Input',
fieldName: 'field1',
label: '自定义组件slot',
renderComponentContent: () => ({
prefix: () => 'prefix',
suffix: () => 'suffix',
}),
},
{
component: h(Input, { placeholder: '请输入' }),
fieldName: 'field2',
label: '自定义组件',
rules: 'required',
},
{
component: 'Input',
fieldName: 'field3',
label: '自定义组件(slot)',
rules: 'required',
},
],
wrapperClass: 'grid-cols-1',
});
function onSubmit(values: Record<string, any>) {
message.success({
content: `form values: ${JSON.stringify(values)}`,
});
}
</script>
<template>
<Form>
<template #field3="slotProps">
<Input placeholder="请输入" v-bind="slotProps" />
</template>
</Form>
</template>

View File

@ -0,0 +1,168 @@
<script lang="ts" setup>
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter';
const [Form] = useVbenForm({
//
handleSubmit: onSubmit,
schema: [
{
component: 'Input',
defaultValue: 'hidden value',
dependencies: {
show: false,
//
triggerFields: ['field1Switch'],
},
fieldName: 'hiddenField',
label: '隐藏字段',
},
{
component: 'Switch',
defaultValue: true,
fieldName: 'field1Switch',
help: '通过Dom控制销毁',
label: '显示字段1',
},
{
component: 'Switch',
defaultValue: true,
fieldName: 'field2Switch',
help: '通过css控制隐藏',
label: '显示字段2',
},
{
component: 'Switch',
fieldName: 'field3Switch',
label: '禁用字段3',
},
{
component: 'Switch',
fieldName: 'field4Switch',
label: '字段4必填',
},
{
component: 'Input',
dependencies: {
if(values) {
return !!values.field1Switch;
},
//
triggerFields: ['field1Switch'],
},
//
fieldName: 'field1',
// label
label: '字段1',
},
{
component: 'Input',
dependencies: {
show(values) {
return !!values.field2Switch;
},
triggerFields: ['field2Switch'],
},
fieldName: 'field2',
label: '字段2',
},
{
component: 'Input',
dependencies: {
disabled(values) {
return !!values.field3Switch;
},
triggerFields: ['field3Switch'],
},
fieldName: 'field3',
label: '字段3',
},
{
component: 'Input',
dependencies: {
required(values) {
return !!values.field4Switch;
},
triggerFields: ['field4Switch'],
},
fieldName: 'field4',
label: '字段4',
},
{
component: 'Input',
dependencies: {
rules(values) {
if (values.field1 === '123') {
return 'required';
}
return null;
},
triggerFields: ['field1'],
},
fieldName: 'field5',
help: '当字段1的值为`123`时,必填',
label: '动态rules',
},
{
component: 'Select',
componentProps: {
allowClear: true,
class: 'w-full',
filterOption: true,
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
placeholder: '请选择',
showSearch: true,
},
dependencies: {
componentProps(values) {
if (values.field2 === '123') {
return {
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
{
label: '选项3',
value: '3',
},
],
};
}
return {};
},
triggerFields: ['field2'],
},
fieldName: 'field6',
help: '当字段2的值为`123`时,更改下拉选项',
label: '动态配置',
},
],
// 321
wrapperClass: 'grid-cols-1 md:grid-cols-2',
});
function onSubmit(values: Record<string, any>) {
message.success({
content: `form values: ${JSON.stringify(values)}`,
});
}
</script>
<template>
<Form />
</template>

View File

@ -0,0 +1,94 @@
<script lang="ts" setup>
import { message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter';
const [QueryForm] = useVbenForm({
//
collapsed: false,
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
//
handleSubmit: onSubmit,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: [
{
// #/adapter.ts
component: 'Input',
//
componentProps: {
placeholder: '请输入用户名',
},
//
fieldName: 'username',
// label
label: '字符串',
},
{
component: 'InputPassword',
componentProps: {
placeholder: '请输入密码',
},
fieldName: 'password',
label: '密码',
},
{
component: 'InputNumber',
componentProps: {
placeholder: '请输入',
},
fieldName: 'number',
label: '数字(带后缀)',
suffix: () => '¥',
},
{
component: 'Select',
componentProps: {
allowClear: true,
filterOption: true,
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
placeholder: '请选择',
showSearch: true,
},
fieldName: 'options',
label: '下拉选',
},
{
component: 'DatePicker',
fieldName: 'datePicker',
label: '日期选择框',
},
],
//
showCollapseButton: true,
submitButtonOptions: {
text: '查询',
},
wrapperClass: 'grid-cols-1 md:grid-cols-2',
});
function onSubmit(values: Record<string, any>) {
message.success({
content: `form values: ${JSON.stringify(values)}`,
});
}
</script>
<template>
<QueryForm />
</template>

View File

@ -0,0 +1,189 @@
<script lang="ts" setup>
import { message } from 'ant-design-vue';
import { useVbenForm, z } from '#/adapter';
const [Form] = useVbenForm({
//
commonConfig: {
//
componentProps: {
class: 'w-full',
},
},
//
handleSubmit: onSubmit,
// labelinputvertical
// labelinput
layout: 'horizontal',
schema: [
{
// #/adapter.ts
component: 'Input',
//
componentProps: {
placeholder: '请输入',
},
//
fieldName: 'field1',
// label
label: '字段1',
rules: 'required',
},
{
component: 'Input',
componentProps: {
placeholder: '请输入',
},
defaultValue: '默认值',
fieldName: 'field2',
label: '默认值(必填)',
rules: 'required',
},
{
component: 'Input',
componentProps: {
placeholder: '请输入',
},
fieldName: 'field3',
label: '默认值(非必填)',
rules: z.string().default('默认值').optional(),
},
{
component: 'Input',
componentProps: {
placeholder: '请输入',
},
fieldName: 'field31',
label: '自定义信息',
rules: z.string().min(1, { message: '最少输入1个字符' }),
},
{
component: 'Input',
//
componentProps: {
placeholder: '请输入',
},
//
fieldName: 'field4',
// label
label: '邮箱',
rules: z.string().email('请输入正确的邮箱'),
},
{
component: 'InputNumber',
componentProps: {
placeholder: '请输入',
},
fieldName: 'number',
label: '数字',
rules: 'required',
},
{
component: 'Select',
componentProps: {
allowClear: true,
filterOption: true,
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
placeholder: '请选择',
showSearch: true,
},
defaultValue: undefined,
fieldName: 'options',
label: '下拉选',
rules: 'selectRequired',
},
{
component: 'RadioGroup',
componentProps: {
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
},
fieldName: 'radioGroup',
label: '单选组',
rules: 'selectRequired',
},
{
component: 'CheckboxGroup',
componentProps: {
name: 'cname',
options: [
{
label: '选项1',
value: '1',
},
{
label: '选项2',
value: '2',
},
],
},
fieldName: 'checkboxGroup',
label: '多选组',
rules: 'selectRequired',
},
{
component: 'Checkbox',
fieldName: 'checkbox',
label: '',
renderComponentContent: () => {
return {
default: () => ['我已阅读并同意'],
};
},
rules: 'selectRequired',
},
{
component: 'DatePicker',
defaultValue: undefined,
fieldName: 'datePicker',
label: '日期选择框',
rules: 'selectRequired',
},
{
component: 'RangePicker',
defaultValue: undefined,
fieldName: 'rangePicker',
label: '区间选择框',
rules: 'selectRequired',
},
{
component: 'InputPassword',
componentProps: {
placeholder: '请输入',
},
fieldName: 'password',
label: '密码',
rules: 'required',
},
],
wrapperClass: 'grid-cols-1',
});
function onSubmit(values: Record<string, any>) {
message.success({
content: `form values: ${JSON.stringify(values)}`,
});
}
</script>
<template>
<Form />
</template>

View File

@ -1,6 +1,12 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "@vben/tsconfig/web.json",
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#/*": ["./src/_env/*"]
}
},
"include": [
".vitepress/*.mts",
".vitepress/**/*.ts",

View File

@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest';
import {
getFirstNonNullOrUndefined,
isBoolean,
isEmpty,
isHttpUrl,
isObject,
@ -96,6 +97,21 @@ describe('isWindow', () => {
});
});
describe('isBoolean', () => {
it('should return true for boolean values', () => {
expect(isBoolean(true)).toBe(true);
expect(isBoolean(false)).toBe(true);
});
it('should return false for non-boolean values', () => {
expect(isBoolean(null)).toBe(false);
expect(isBoolean(42)).toBe(false);
expect(isBoolean('string')).toBe(false);
expect(isBoolean({})).toBe(false);
expect(isBoolean([])).toBe(false);
});
});
describe('isObject', () => {
it('should return true for objects', () => {
expect(isObject({})).toBe(true);

View File

@ -10,6 +10,15 @@ function isUndefined(value?: unknown): value is undefined {
return value === undefined;
}
/**
* boolean
* @param value
* @returns truefalse
*/
function isBoolean(value: unknown): value is boolean {
return typeof value === 'boolean';
}
/**
*
*
@ -141,6 +150,7 @@ function getFirstNonNullOrUndefined<T>(
export {
getFirstNonNullOrUndefined,
isBoolean,
isEmpty,
isFunction,
isHttpUrl,

View File

@ -219,6 +219,12 @@ export class FormApi {
async validate(opts?: Partial<ValidationOptions>) {
const form = await this.getForm();
return await form.validate(opts);
const validateResult = await form.validate(opts);
if (Object.keys(validateResult?.errors ?? {}).length > 0) {
console.error('validate error', validateResult?.errors);
}
return validateResult;
}
}

View File

@ -6,7 +6,7 @@ import type {
import { computed, ref, watch } from 'vue';
import { isFunction } from '@vben-core/shared/utils';
import { isBoolean, isFunction } from '@vben-core/shared/utils';
import { useFormValues } from 'vee-validate';
@ -74,12 +74,18 @@ export default function useDependencies(
isIf.value = !!(await whenIf(formValues, formApi));
// 不渲染
if (!isIf.value) return;
} else if (isBoolean(whenIf)) {
isIf.value = whenIf;
if (!isIf.value) return;
}
// 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)) {
@ -92,6 +98,8 @@ export default function useDependencies(
if (isFunction(disabled)) {
isDisabled.value = !!(await disabled(formValues, formApi));
} else if (isBoolean(disabled)) {
isDisabled.value = disabled;
}
if (isFunction(required)) {

View File

@ -85,7 +85,15 @@ const currentRules = computed(() => {
return dynamicRules.value || rules;
});
const visible = computed(() => {
return isIf.value && isShow.value;
});
const shouldRequired = computed(() => {
if (!visible.value) {
return false;
}
if (!currentRules.value) {
return isRequired.value;
}
@ -113,6 +121,10 @@ const shouldRequired = computed(() => {
});
const fieldRules = computed(() => {
if (!visible.value) {
return null;
}
let rules = currentRules.value;
if (!rules) {
return isRequired.value ? 'required' : null;

View File

@ -88,12 +88,12 @@ export interface FormItemDependencies {
*
* @returns
*/
disabled?: FormItemDependenciesCondition;
disabled?: boolean | FormItemDependenciesCondition;
/**
* dom
* @returns
*/
if?: FormItemDependenciesCondition;
if?: boolean | FormItemDependenciesCondition;
/**
*
* @returns
@ -107,7 +107,7 @@ export interface FormItemDependencies {
* (Css)
* @returns
*/
show?: FormItemDependenciesCondition;
show?: boolean | FormItemDependenciesCondition;
/**
*
*/
@ -141,7 +141,7 @@ export interface FormCommonConfig {
disabled?: boolean;
/**
*
* @default ""
* @default {}
*/
formFieldProps?: Partial<typeof Field>;
/**
@ -161,7 +161,7 @@ export interface FormCommonConfig {
hideRequiredMark?: boolean;
/**
* label
* @default "w-[100px]"
* @default ""
*/
labelClass?: string;
/**
@ -295,6 +295,7 @@ export interface VbenFormProps<
/**
*
* @default true
*/
showDefaultActions?: boolean;

View File

@ -162,11 +162,11 @@ function handleConfirm() {
v-if="hintImage"
:alt="$t('ui.captcha.alt')"
:src="hintImage"
class="h-10 w-full rounded border border-solid border-slate-200"
class="border-border h-10 w-full rounded border"
/>
<div
v-else-if="hintText"
class="flex h-10 w-full items-center justify-center rounded border border-solid border-slate-200"
class="border-border flex-center h-10 w-full rounded border"
>
{{ `${$t('ui.captcha.clickInOrder')}` + `${hintText}` }}
</div>

View File

@ -5,4 +5,11 @@ export * from '@vben-core/form-ui';
export * from '@vben-core/popup-ui';
// 给文档用
export { VbenButton } from '@vben-core/shadcn-ui';
export {
VbenButton,
VbenCountToAnimator,
VbenInputPassword,
VbenLoading,
VbenPinInput,
VbenSpinner,
} from '@vben-core/shadcn-ui';

View File

@ -81,6 +81,7 @@ function handleClick(item: NotificationItem) {
<div class="flex items-center justify-between p-4 py-3">
<div class="text-foreground">{{ $t('widgets.notifications') }}</div>
<VbenIconButton
:disabled="notifications.length <= 0"
:tooltip="$t('widgets.markAllAsRead')"
@click="handleMakeAll"
>
@ -131,7 +132,12 @@ function handleClick(item: NotificationItem) {
<div
class="border-border flex items-center justify-between border-t px-4 py-3"
>
<VbenButton size="sm" variant="ghost" @click="handleClear">
<VbenButton
:disabled="notifications.length <= 0"
size="sm"
variant="ghost"
@click="handleClear"
>
{{ $t('widgets.clearNotifications') }}
</VbenButton>
<VbenButton size="sm" @click="handleViewAll">

View File

@ -27,13 +27,13 @@ import {
Select,
Space,
Switch,
Textarea,
TimePicker,
TreeSelect,
Upload,
} from 'ant-design-vue';
// 业务表单组件适配
// 这里需要自行根据业务组件库进行适配,需要用到的组件都需要在这里类型说明
export type FormComponentType =
| 'AutoComplete'
| 'Checkbox'
@ -51,6 +51,7 @@ export type FormComponentType =
| 'Select'
| 'Space'
| 'Switch'
| 'Textarea'
| 'TimePicker'
| 'TreeSelect'
| 'Upload'
@ -83,12 +84,16 @@ setupVbenForm<FormComponentType>({
Select,
Space,
Switch,
Textarea,
TimePicker,
TreeSelect,
Upload,
},
config: {
// ant design vue组件库默认都是 v-model:value
baseModelPropName: 'value',
// 一些组件是 v-model:checked 或者 v-model:fileList
modelPropNameMap: {
Checkbox: 'checked',
Radio: 'checked',
@ -97,12 +102,14 @@ setupVbenForm<FormComponentType>({
},
},
defineRules: {
// 输入项目必填国际化适配
required: (value, _params, ctx) => {
if ((!value && value !== 0) || value.length === 0) {
if (value === undefined || value === null || value.length === 0) {
return $t('formRules.required', [ctx.label]);
}
return true;
},
// 选择项目必填国际化适配
selectRequired: (value, _params, ctx) => {
if (value === undefined || value === null) {
return $t('formRules.selectRequired', [ctx.label]);

View File

@ -114,6 +114,7 @@ function handleClick(
fieldName: 'fieldOptions',
},
]);
message.success('字段 `fieldOptions` 下拉选项更新成功。');
break;
}

View File

@ -7,7 +7,7 @@ import { Card, Input, message } from 'ant-design-vue';
import { useVbenForm } from '#/adapter';
const [BaseForm] = useVbenForm({
const [Form] = useVbenForm({
//
commonConfig: {
//
@ -65,11 +65,11 @@ function onSubmit(values: Record<string, any>) {
<template>
<Page description="表单组件自定义示例" title="表单组件">
<Card title="基础示例">
<BaseForm>
<Form>
<template #field3="slotProps">
<Input placeholder="请输入" v-bind="slotProps" />
</template>
</BaseForm>
</Form>
</Card>
</Page>
</template>

View File

@ -9,6 +9,17 @@ const [Form, formApi] = useVbenForm({
//
handleSubmit: onSubmit,
schema: [
{
component: 'Input',
defaultValue: 'hidden value',
dependencies: {
show: false,
//
triggerFields: ['field1Switch'],
},
fieldName: 'hiddenField',
label: '隐藏字段',
},
{
component: 'Switch',
defaultValue: true,

View File

@ -37,8 +37,8 @@ catalogs:
specifier: ^4.1.2
version: 4.1.2
'@intlify/core-base':
specifier: ^10.0.1
version: 10.0.1
specifier: ^10.0.2
version: 10.0.2
'@intlify/unplugin-vue-i18n':
specifier: ^5.0.0
version: 5.0.0
@ -124,11 +124,11 @@ catalogs:
specifier: ^4.0.1
version: 4.0.1
'@vue/reactivity':
specifier: ^3.5.7
version: 3.5.7
specifier: ^3.5.8
version: 3.5.8
'@vue/shared':
specifier: ^3.5.7
version: 3.5.7
specifier: ^3.5.8
version: 3.5.8
'@vue/test-utils':
specifier: ^2.4.6
version: 2.4.6
@ -280,8 +280,8 @@ catalogs:
specifier: ^3.0.1
version: 3.0.1
jsdom:
specifier: ^25.0.0
version: 25.0.0
specifier: ^25.0.1
version: 25.0.1
jsonc-eslint-parser:
specifier: ^2.4.0
version: 2.4.0
@ -376,8 +376,8 @@ catalogs:
specifier: ^16.9.0
version: 16.9.0
stylelint-config-recess-order:
specifier: ^5.1.0
version: 5.1.0
specifier: ^5.1.1
version: 5.1.1
stylelint-config-recommended:
specifier: ^14.0.1
version: 14.0.1
@ -460,8 +460,8 @@ catalogs:
specifier: ^9.4.3
version: 9.4.3
vue-i18n:
specifier: ^10.0.1
version: 10.0.1
specifier: ^10.0.2
version: 10.0.2
vue-router:
specifier: ^4.4.5
version: 4.4.5
@ -553,7 +553,7 @@ importers:
version: 3.0.1
jsdom:
specifier: 'catalog:'
version: 25.0.0
version: 25.0.1
lint-staged:
specifier: 'catalog:'
version: 15.2.10
@ -577,7 +577,7 @@ importers:
version: 5.4.7(@types/node@22.5.5)(less@4.2.0)(sass@1.79.3)(terser@5.33.0)
vitest:
specifier: 'catalog:'
version: 2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(less@4.2.0)(sass@1.79.3)(terser@5.33.0)
version: 2.1.1(@types/node@22.5.5)(jsdom@25.0.1)(less@4.2.0)(sass@1.79.3)(terser@5.33.0)
vue:
specifier: 3.5.7
version: 3.5.7(typescript@5.6.2)
@ -799,9 +799,21 @@ importers:
'@vben/common-ui':
specifier: workspace:*
version: link:../packages/effects/common-ui
'@vben/hooks':
specifier: workspace:*
version: link:../packages/effects/hooks
'@vben/locales':
specifier: workspace:*
version: link:../packages/locales
'@vben/preferences':
specifier: workspace:*
version: link:../packages/preferences
'@vben/styles':
specifier: workspace:*
version: link:../packages/styles
ant-design-vue:
specifier: 'catalog:'
version: 4.2.5(vue@3.5.7(typescript@5.6.2))
lucide-vue-next:
specifier: 'catalog:'
version: 0.445.0(vue@3.5.7(typescript@5.6.2))
@ -911,7 +923,7 @@ importers:
version: 4.1.4(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))
eslint-plugin-vitest:
specifier: 'catalog:'
version: 0.5.4(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(less@4.2.0)(sass@1.79.3)(terser@5.33.0))
version: 0.5.4(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.1)(less@4.2.0)(sass@1.79.3)(terser@5.33.0))
eslint-plugin-vue:
specifier: 'catalog:'
version: 9.28.0(eslint@9.11.0(jiti@1.21.6))
@ -941,7 +953,7 @@ importers:
version: 3.0.1(stylelint@16.9.0(typescript@5.6.2))
stylelint-config-recess-order:
specifier: 'catalog:'
version: 5.1.0(stylelint@16.9.0(typescript@5.6.2))
version: 5.1.1(stylelint@16.9.0(typescript@5.6.2))
stylelint-scss:
specifier: 'catalog:'
version: 6.7.0(stylelint@16.9.0(typescript@5.6.2))
@ -1082,7 +1094,7 @@ importers:
dependencies:
'@intlify/unplugin-vue-i18n':
specifier: 'catalog:'
version: 5.0.0(@vue/compiler-dom@3.5.7)(eslint@9.11.0(jiti@1.21.6))(rollup@4.22.4)(typescript@5.6.2)(vue-i18n@10.0.1(vue@3.5.7(typescript@5.6.2)))(vue@3.5.7(typescript@5.6.2))
version: 5.0.0(@vue/compiler-dom@3.5.7)(eslint@9.11.0(jiti@1.21.6))(rollup@4.22.4)(typescript@5.6.2)(vue-i18n@10.0.2(vue@3.5.7(typescript@5.6.2)))(vue@3.5.7(typescript@5.6.2))
'@jspm/generator':
specifier: 'catalog:'
version: 2.3.1
@ -1181,10 +1193,10 @@ importers:
version: 0.5.5(vue@3.5.7(typescript@5.6.2))
'@vue/reactivity':
specifier: 'catalog:'
version: 3.5.7
version: 3.5.8
'@vue/shared':
specifier: 'catalog:'
version: 3.5.7
version: 3.5.8
clsx:
specifier: 2.1.1
version: 2.1.1
@ -1608,7 +1620,7 @@ importers:
dependencies:
'@intlify/core-base':
specifier: 'catalog:'
version: 10.0.1
version: 10.0.2
'@vben-core/composables':
specifier: workspace:*
version: link:../@core/composables
@ -1617,7 +1629,7 @@ importers:
version: 3.5.7(typescript@5.6.2)
vue-i18n:
specifier: 'catalog:'
version: 10.0.1(vue@3.5.7(typescript@5.6.2))
version: 10.0.2(vue@3.5.7(typescript@5.6.2))
packages/preferences:
dependencies:
@ -3903,24 +3915,24 @@ packages:
vue-i18n:
optional: true
'@intlify/core-base@10.0.1':
resolution: {integrity: sha512-6kpRGjhos95ph7QmEtP4tnWFTW102s71CLQAQwfsIGqOAcoJhzcYFpzIQ0gKXzqAIXsMD/hwM5qJ4ewqMHw3gg==}
'@intlify/core-base@10.0.2':
resolution: {integrity: sha512-0Ewg801c3f5ukktJVi/BVwxPVbX2lvGflK0G6QxTatbWaMt2YA1QheDGTXS2Nz/PupSDPNOabADsTG9LCoKA1A==}
engines: {node: '>= 16'}
'@intlify/message-compiler@10.0.0':
resolution: {integrity: sha512-OcaWc63NC/9p1cMdgoNKBj4d61BH8sUW1Hfs6YijTd9656ZR4rNqXAlRnBrfS5ABq0vjQjpa8VnyvH9hK49yBw==}
engines: {node: '>= 16'}
'@intlify/message-compiler@10.0.1':
resolution: {integrity: sha512-fPeykrcgVT5eOIlshTHiPCN8FV3AZyBOdMS3XaXzfQ6eL5wqfc29I/EdIv5YXVW5X8e/BgYeWjBC0Cuznsl/2g==}
'@intlify/message-compiler@10.0.2':
resolution: {integrity: sha512-PHFnGFEKknuk+RwcafKAjS537Ln0ptSfqmvVdsHKWBytTbiKqZZFX57pmfio2ln+ZLeHuyudcqbTi1zGJUNIcA==}
engines: {node: '>= 16'}
'@intlify/shared@10.0.0':
resolution: {integrity: sha512-6ngLfI7DOTew2dcF9WMJx+NnMWghMBhIiHbGg+wRvngpzD5KZJZiJVuzMsUQE1a5YebEmtpTEfUrDp/NqVGdiw==}
engines: {node: '>= 16'}
'@intlify/shared@10.0.1':
resolution: {integrity: sha512-b4h7IWdZl710DnAhET8lgfgZ4Y9A2IZx/gbli3Ec/zHtYCoPqLHmiM7kUNBrSZj7d/SSjcMMZHuz5I09x3PYZw==}
'@intlify/shared@10.0.2':
resolution: {integrity: sha512-sIF9cqB0CwUWLtDb1QDnl4PlTggE4GSnR1aA44thT9Y18rUVdWO2z4w2Ow6O60tsdNzC0WnUd6fU0VXyKQ6WBA==}
engines: {node: '>= 16'}
'@intlify/unplugin-vue-i18n@5.0.0':
@ -4843,6 +4855,9 @@ packages:
'@vue/reactivity@3.5.7':
resolution: {integrity: sha512-yF0EpokpOHRNXyn/h6abXc9JFIzfdAf0MJHIi92xxCWS0mqrXH6+2aZ+A6EbSrspGzX5MHTd5N8iBA28HnXu9g==}
'@vue/reactivity@3.5.8':
resolution: {integrity: sha512-mlgUyFHLCUZcAYkqvzYnlBRCh0t5ZQfLYit7nukn1GR96gc48Bp4B7OIcSfVSvlG1k3BPfD+p22gi1t2n9tsXg==}
'@vue/runtime-core@3.5.7':
resolution: {integrity: sha512-OzLpBpKbZEaZVSNfd+hQbfBrDKux+b7Yl5hYhhWWWhHD7fEpF+CdI3Brm5k5GsufHEfvMcjruPxwQZuBN6nFYQ==}
@ -4857,6 +4872,9 @@ packages:
'@vue/shared@3.5.7':
resolution: {integrity: sha512-NBE1PBIvzIedxIc2RZiKXvGbJkrZ2/hLf3h8GlS4/sP9xcXEZMFWOazFkNd6aGeUCMaproe5MHVYB3/4AW9q9g==}
'@vue/shared@3.5.8':
resolution: {integrity: sha512-mJleSWbAGySd2RJdX1RBtcrUBX6snyOc0qHpgk3lGi4l9/P/3ny3ELqFWqYdkXIwwNN/kdm8nD9ky8o6l/Lx2A==}
'@vue/test-utils@2.4.6':
resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==}
@ -7310,8 +7328,8 @@ packages:
resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==}
engines: {node: '>=12.0.0'}
jsdom@25.0.0:
resolution: {integrity: sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==}
jsdom@25.0.1:
resolution: {integrity: sha512-8i7LzZj7BF8uplX+ZyOlIz86V6TAsSs+np6m1kpW9u0JWi4z/1t+FzcK1aek+ybTnAC4KhBL4uXCNT0wcUIeCw==}
engines: {node: '>=18'}
peerDependencies:
canvas: ^2.11.2
@ -8778,9 +8796,6 @@ packages:
pseudomap@1.0.2:
resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
psl@1.9.0:
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
publint@0.2.11:
resolution: {integrity: sha512-/kxbd+sD/uEG515N/ZYpC6gYs8h89cQ4UIsAq1y6VT4qlNh8xmiSwcP2xU2MbzXFl8J0l2IdONKFweLfYoqhcA==}
engines: {node: '>=16'}
@ -8799,9 +8814,6 @@ packages:
engines: {node: '>=10.13.0'}
hasBin: true
querystringify@2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@ -8952,9 +8964,6 @@ packages:
require-package-name@2.0.1:
resolution: {integrity: sha512-uuoJ1hU/k6M0779t3VMVIYpb2VMJk05cehCaABFhXaibcbvfgR8wKiozLjVFSzJPmQMRqIcO0HMyTFqfV09V6Q==}
requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
resize-observer-polyfill@1.5.1:
resolution: {integrity: sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==}
@ -9437,8 +9446,8 @@ packages:
postcss-html: ^1.0.0
stylelint: '>=14.0.0'
stylelint-config-recess-order@5.1.0:
resolution: {integrity: sha512-ddapCF6B/kEtQYIFhQFReQ0dvK1ZdgJDM/SGFtIyeooYDbqaJqcOlGkRRGaVErCQYJY/bPSPsLRS2LdQtLJUVQ==}
stylelint-config-recess-order@5.1.1:
resolution: {integrity: sha512-eDAHWVBelzDbMbdMj15pSw0Ycykv5eLeriJdbGCp0zd44yvhgZLI+wyVHegzXp5NrstxTPSxl0fuOVKdMm0XLA==}
peerDependencies:
stylelint: '>=16'
@ -9653,6 +9662,13 @@ packages:
resolution: {integrity: sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==}
engines: {node: '>=14.0.0'}
tldts-core@6.1.47:
resolution: {integrity: sha512-6SWyFMnlst1fEt7GQVAAu16EGgFK0cLouH/2Mk6Ftlwhv3Ol40L0dlpGMcnnNiiOMyD2EV/aF3S+U2nKvvLvrA==}
tldts@6.1.47:
resolution: {integrity: sha512-R/K2tZ5MiY+mVrnSkNJkwqYT2vUv1lcT6wJvd2emGaMJ7PHUGRY4e3tUsdFCXgqxi2QgbHjL3yJgXCo40v9Hxw==}
hasBin: true
tmp@0.0.33:
resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==}
engines: {node: '>=0.6.0'}
@ -9673,9 +9689,9 @@ packages:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
tough-cookie@4.1.4:
resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
engines: {node: '>=6'}
tough-cookie@5.0.0:
resolution: {integrity: sha512-FRKsF7cz96xIIeMZ82ehjC3xW2E+O2+v11udrDYewUbszngYhsGa8z6YUMMzO9QJZzzyd0nGGXnML/TReX6W8Q==}
engines: {node: '>=16'}
tr46@0.0.3:
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
@ -9887,10 +9903,6 @@ packages:
resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==}
engines: {node: '>= 4.0.0'}
universalify@0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
@ -9983,9 +9995,6 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
url-parse@1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
urlpattern-polyfill@8.0.2:
resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==}
@ -10181,8 +10190,8 @@ packages:
peerDependencies:
eslint: '>=6.0.0'
vue-i18n@10.0.1:
resolution: {integrity: sha512-SQVlSm/1S6AaG1wexvwq3ebXUrrkx75ZHD78UAs4/rYD/X3tsQxfm6ElpT4ZPegJQEgRtOJjGripqSrfqAENtg==}
vue-i18n@10.0.2:
resolution: {integrity: sha512-osoes79ecpqdzYYhywp/pDLlPMoyQ5MHJvjAitQLmXiaCj/ejC8YIeWIwIsDdqWcvkrVFmROYDLcGgGCVn7g0Q==}
engines: {node: '>= 16'}
peerDependencies:
vue: 3.5.7
@ -12662,7 +12671,7 @@ snapshots:
dependencies:
'@swc/helpers': 0.5.13
'@intlify/bundle-utils@9.0.0-beta.0(vue-i18n@10.0.1(vue@3.5.7(typescript@5.6.2)))':
'@intlify/bundle-utils@9.0.0-beta.0(vue-i18n@10.0.2(vue@3.5.7(typescript@5.6.2)))':
dependencies:
'@intlify/message-compiler': 10.0.0
'@intlify/shared': 10.0.0
@ -12674,33 +12683,33 @@ snapshots:
source-map-js: 1.2.1
yaml-eslint-parser: 1.2.3
optionalDependencies:
vue-i18n: 10.0.1(vue@3.5.7(typescript@5.6.2))
vue-i18n: 10.0.2(vue@3.5.7(typescript@5.6.2))
'@intlify/core-base@10.0.1':
'@intlify/core-base@10.0.2':
dependencies:
'@intlify/message-compiler': 10.0.1
'@intlify/shared': 10.0.1
'@intlify/message-compiler': 10.0.2
'@intlify/shared': 10.0.2
'@intlify/message-compiler@10.0.0':
dependencies:
'@intlify/shared': 10.0.0
source-map-js: 1.2.1
'@intlify/message-compiler@10.0.1':
'@intlify/message-compiler@10.0.2':
dependencies:
'@intlify/shared': 10.0.1
'@intlify/shared': 10.0.2
source-map-js: 1.2.1
'@intlify/shared@10.0.0': {}
'@intlify/shared@10.0.1': {}
'@intlify/shared@10.0.2': {}
'@intlify/unplugin-vue-i18n@5.0.0(@vue/compiler-dom@3.5.7)(eslint@9.11.0(jiti@1.21.6))(rollup@4.22.4)(typescript@5.6.2)(vue-i18n@10.0.1(vue@3.5.7(typescript@5.6.2)))(vue@3.5.7(typescript@5.6.2))':
'@intlify/unplugin-vue-i18n@5.0.0(@vue/compiler-dom@3.5.7)(eslint@9.11.0(jiti@1.21.6))(rollup@4.22.4)(typescript@5.6.2)(vue-i18n@10.0.2(vue@3.5.7(typescript@5.6.2)))(vue@3.5.7(typescript@5.6.2))':
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@9.11.0(jiti@1.21.6))
'@intlify/bundle-utils': 9.0.0-beta.0(vue-i18n@10.0.1(vue@3.5.7(typescript@5.6.2)))
'@intlify/bundle-utils': 9.0.0-beta.0(vue-i18n@10.0.2(vue@3.5.7(typescript@5.6.2)))
'@intlify/shared': 10.0.0
'@intlify/vue-i18n-extensions': 6.2.0(@intlify/shared@10.0.0)(@vue/compiler-dom@3.5.7)(vue-i18n@10.0.1(vue@3.5.7(typescript@5.6.2)))(vue@3.5.7(typescript@5.6.2))
'@intlify/vue-i18n-extensions': 6.2.0(@intlify/shared@10.0.0)(@vue/compiler-dom@3.5.7)(vue-i18n@10.0.2(vue@3.5.7(typescript@5.6.2)))(vue@3.5.7(typescript@5.6.2))
'@rollup/pluginutils': 5.1.0(rollup@4.22.4)
'@typescript-eslint/scope-manager': 7.18.0
'@typescript-eslint/typescript-estree': 7.18.0(typescript@5.6.2)
@ -12715,7 +12724,7 @@ snapshots:
unplugin: 1.14.1
vue: 3.5.7(typescript@5.6.2)
optionalDependencies:
vue-i18n: 10.0.1(vue@3.5.7(typescript@5.6.2))
vue-i18n: 10.0.2(vue@3.5.7(typescript@5.6.2))
transitivePeerDependencies:
- '@vue/compiler-dom'
- eslint
@ -12724,14 +12733,14 @@ snapshots:
- typescript
- webpack-sources
'@intlify/vue-i18n-extensions@6.2.0(@intlify/shared@10.0.0)(@vue/compiler-dom@3.5.7)(vue-i18n@10.0.1(vue@3.5.7(typescript@5.6.2)))(vue@3.5.7(typescript@5.6.2))':
'@intlify/vue-i18n-extensions@6.2.0(@intlify/shared@10.0.0)(@vue/compiler-dom@3.5.7)(vue-i18n@10.0.2(vue@3.5.7(typescript@5.6.2)))(vue@3.5.7(typescript@5.6.2))':
dependencies:
'@babel/parser': 7.25.6
optionalDependencies:
'@intlify/shared': 10.0.0
'@vue/compiler-dom': 3.5.7
vue: 3.5.7(typescript@5.6.2)
vue-i18n: 10.0.1(vue@3.5.7(typescript@5.6.2))
vue-i18n: 10.0.2(vue@3.5.7(typescript@5.6.2))
'@ioredis/commands@1.2.0': {}
@ -13929,6 +13938,10 @@ snapshots:
dependencies:
'@vue/shared': 3.5.7
'@vue/reactivity@3.5.8':
dependencies:
'@vue/shared': 3.5.8
'@vue/runtime-core@3.5.7':
dependencies:
'@vue/reactivity': 3.5.7
@ -13949,6 +13962,8 @@ snapshots:
'@vue/shared@3.5.7': {}
'@vue/shared@3.5.8': {}
'@vue/test-utils@2.4.6':
dependencies:
js-beautify: 1.15.1
@ -15713,13 +15728,13 @@ snapshots:
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2)
eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(less@4.2.0)(sass@1.79.3)(terser@5.33.0)):
eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2)(vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.1)(less@4.2.0)(sass@1.79.3)(terser@5.33.0)):
dependencies:
'@typescript-eslint/utils': 7.18.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2)
eslint: 9.11.0(jiti@1.21.6)
optionalDependencies:
'@typescript-eslint/eslint-plugin': 8.6.0(@typescript-eslint/parser@8.6.0(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2))(eslint@9.11.0(jiti@1.21.6))(typescript@5.6.2)
vitest: 2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(less@4.2.0)(sass@1.79.3)(terser@5.33.0)
vitest: 2.1.1(@types/node@22.5.5)(jsdom@25.0.1)(less@4.2.0)(sass@1.79.3)(terser@5.33.0)
transitivePeerDependencies:
- supports-color
- typescript
@ -16738,7 +16753,7 @@ snapshots:
jsdoc-type-pratt-parser@4.1.0: {}
jsdom@25.0.0:
jsdom@25.0.1:
dependencies:
cssstyle: 4.1.0
data-urls: 5.0.0
@ -16753,7 +16768,7 @@ snapshots:
rrweb-cssom: 0.7.1
saxes: 6.0.0
symbol-tree: 3.2.4
tough-cookie: 4.1.4
tough-cookie: 5.0.0
w3c-xmlserializer: 5.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 3.1.1
@ -18273,8 +18288,6 @@ snapshots:
pseudomap@1.0.2: {}
psl@1.9.0: {}
publint@0.2.11:
dependencies:
npm-packlist: 5.1.3
@ -18293,8 +18306,6 @@ snapshots:
pngjs: 5.0.0
yargs: 15.4.1
querystringify@2.2.0: {}
queue-microtask@1.2.3: {}
queue-tick@1.0.1: {}
@ -18471,8 +18482,6 @@ snapshots:
require-package-name@2.0.1: {}
requires-port@1.0.0: {}
resize-observer-polyfill@1.5.1: {}
resolve-dir@1.0.1:
@ -18980,7 +18989,7 @@ snapshots:
postcss-html: 1.7.0
stylelint: 16.9.0(typescript@5.6.2)
stylelint-config-recess-order@5.1.0(stylelint@16.9.0(typescript@5.6.2)):
stylelint-config-recess-order@5.1.1(stylelint@16.9.0(typescript@5.6.2)):
dependencies:
stylelint: 16.9.0(typescript@5.6.2)
stylelint-order: 6.0.4(stylelint@16.9.0(typescript@5.6.2))
@ -19260,6 +19269,12 @@ snapshots:
tinyspy@3.0.2: {}
tldts-core@6.1.47: {}
tldts@6.1.47:
dependencies:
tldts-core: 6.1.47
tmp@0.0.33:
dependencies:
os-tmpdir: 1.0.2
@ -19274,12 +19289,9 @@ snapshots:
totalist@3.0.1: {}
tough-cookie@4.1.4:
tough-cookie@5.0.0:
dependencies:
psl: 1.9.0
punycode: 2.3.1
universalify: 0.2.0
url-parse: 1.5.10
tldts: 6.1.47
tr46@0.0.3: {}
@ -19524,8 +19536,6 @@ snapshots:
universalify@0.1.2: {}
universalify@0.2.0: {}
universalify@2.0.1: {}
unplugin-element-plus@0.8.0(rollup@4.22.4):
@ -19616,11 +19626,6 @@ snapshots:
dependencies:
punycode: 2.3.1
url-parse@1.5.10:
dependencies:
querystringify: 2.2.0
requires-port: 1.0.0
urlpattern-polyfill@8.0.2: {}
util-deprecate@1.0.2: {}
@ -19849,7 +19854,7 @@ snapshots:
- typescript
- universal-cookie
vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.0)(less@4.2.0)(sass@1.79.3)(terser@5.33.0):
vitest@2.1.1(@types/node@22.5.5)(jsdom@25.0.1)(less@4.2.0)(sass@1.79.3)(terser@5.33.0):
dependencies:
'@vitest/expect': 2.1.1
'@vitest/mocker': 2.1.1(@vitest/spy@2.1.1)(vite@5.4.7(@types/node@22.5.5)(less@4.2.0)(sass@1.79.3)(terser@5.33.0))
@ -19872,7 +19877,7 @@ snapshots:
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 22.5.5
jsdom: 25.0.0
jsdom: 25.0.1
transitivePeerDependencies:
- less
- lightningcss
@ -19912,10 +19917,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
vue-i18n@10.0.1(vue@3.5.7(typescript@5.6.2)):
vue-i18n@10.0.2(vue@3.5.7(typescript@5.6.2)):
dependencies:
'@intlify/core-base': 10.0.1
'@intlify/shared': 10.0.1
'@intlify/core-base': 10.0.2
'@intlify/shared': 10.0.2
'@vue/devtools-api': 6.6.4
vue: 3.5.7(typescript@5.6.2)

View File

@ -24,7 +24,7 @@ catalog:
'@iconify/json': ^2.2.251
'@iconify/tailwind': ^1.1.3
'@iconify/vue': ^4.1.2
'@intlify/core-base': ^10.0.1
'@intlify/core-base': ^10.0.2
'@intlify/unplugin-vue-i18n': ^5.0.0
'@jspm/generator': ^2.3.1
'@manypkg/get-packages': ^2.2.2
@ -53,8 +53,8 @@ catalog:
'@vite-pwa/vitepress': ^0.5.3
'@vitejs/plugin-vue': ^5.1.4
'@vitejs/plugin-vue-jsx': ^4.0.1
'@vue/reactivity': ^3.5.7
'@vue/shared': ^3.5.7
'@vue/reactivity': ^3.5.8
'@vue/shared': ^3.5.8
'@vue/test-utils': ^2.4.6
'@vueuse/core': ^11.1.0
'@vueuse/integrations': ^11.1.0
@ -106,7 +106,7 @@ catalog:
html-minifier-terser: ^7.2.0
husky: ^9.1.6
is-ci: ^3.0.1
jsdom: ^25.0.0
jsdom: ^25.0.1
jsonc-eslint-parser: ^2.4.0
jsonwebtoken: ^9.0.2
lint-staged: ^15.2.10
@ -139,7 +139,7 @@ catalog:
sass: ^1.79.3
sortablejs: ^1.15.3
stylelint: ^16.9.0
stylelint-config-recess-order: ^5.1.0
stylelint-config-recess-order: ^5.1.1
stylelint-config-recommended: ^14.0.1
stylelint-config-recommended-scss: ^14.1.0
stylelint-config-recommended-vue: ^1.5.0
@ -166,9 +166,9 @@ catalog:
vitepress: ^1.3.4
vitepress-plugin-group-icons: ^1.2.4
vitest: ^2.1.1
vue: ^3.5.7
vue: ^3.5.8
vue-eslint-parser: ^9.4.3
vue-i18n: ^10.0.1
vue-i18n: ^10.0.2
vue-router: ^4.4.5
vue-tsc: ^2.1.6
watermark-js-plus: ^1.5.6