Skip to content

Commit

Permalink
fix: fixed an error in the form onChange within Naive (#4558)
Browse files Browse the repository at this point in the history
* fix: fixed an error in the form onChange within Naive

* chore: update
  • Loading branch information
anncwb authored Oct 3, 2024
1 parent 64428b9 commit 0cd865e
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 65 deletions.
5 changes: 3 additions & 2 deletions apps/web-antd/src/adapter/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type {
VbenFormProps,
} from '@vben/common-ui';

import { type Component, h, type SetupContext } from 'vue';
import type { Component, SetupContext } from 'vue';
import { h } from 'vue';

import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
Expand Down Expand Up @@ -63,7 +64,7 @@ const withDefaultPlaceholder = <T extends Component>(
) => {
return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
const placeholder = props?.placeholder || $t(`placeholder.${type}`);
return h(component, { ...props, attrs, placeholder }, slots);
return h(component, { ...props, ...attrs, placeholder }, slots);
};
};

Expand Down
19 changes: 15 additions & 4 deletions apps/web-ele/src/adapter/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
VbenFormProps,
} from '@vben/common-ui';

import type { Component, SetupContext } from 'vue';
import { h } from 'vue';

import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
Expand Down Expand Up @@ -42,6 +43,16 @@ export type FormComponentType =
| 'Upload'
| BaseFormComponentType;

const withDefaultPlaceholder = <T extends Component>(
component: T,
type: 'input' | 'select',
) => {
return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
const placeholder = props?.placeholder || $t(`placeholder.${type}`);
return h(component, { ...props, ...attrs, placeholder }, slots);
};
};

// 初始化表单组件,并注册到form组件内部
setupVbenForm<FormComponentType>({
components: {
Expand All @@ -56,14 +67,14 @@ setupVbenForm<FormComponentType>({
return h(ElButton, { ...props, attrs, type: 'primary' }, slots);
},
Divider: ElDivider,
Input: ElInput,
InputNumber: ElInputNumber,
Input: withDefaultPlaceholder(ElInput, 'input'),
InputNumber: withDefaultPlaceholder(ElInputNumber, 'input'),
RadioGroup: ElRadioGroup,
Select: ElSelect,
Select: withDefaultPlaceholder(ElSelect, 'select'),
Space: ElSpace,
Switch: ElSwitch,
TimePicker: ElTimePicker,
TreeSelect: ElTreeSelect,
TreeSelect: withDefaultPlaceholder(ElTreeSelect, 'select'),
Upload: ElUpload,
},
config: {
Expand Down
20 changes: 16 additions & 4 deletions apps/web-naive/src/adapter/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
VbenFormProps,
} from '@vben/common-ui';

import type { Component, SetupContext } from 'vue';
import { h } from 'vue';

import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
Expand Down Expand Up @@ -43,6 +44,16 @@ export type FormComponentType =
| 'Upload'
| BaseFormComponentType;

const withDefaultPlaceholder = <T extends Component>(
component: T,
type: 'input' | 'select',
) => {
return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
const placeholder = props?.placeholder || $t(`placeholder.${type}`);
return h(component, { ...props, ...attrs, placeholder }, slots);
};
};

// 初始化表单组件,并注册到form组件内部
setupVbenForm<FormComponentType>({
components: {
Expand All @@ -62,17 +73,18 @@ setupVbenForm<FormComponentType>({
);
},
Divider: NDivider,
Input: NInput,
InputNumber: NInputNumber,
Input: withDefaultPlaceholder(NInput, 'input'),
InputNumber: withDefaultPlaceholder(NInputNumber, 'input'),
RadioGroup: NRadioGroup,
Select: NSelect,
Select: withDefaultPlaceholder(NSelect, 'select'),
Space: NSpace,
Switch: NSwitch,
TimePicker: NTimePicker,
TreeSelect: NTreeSelect,
TreeSelect: withDefaultPlaceholder(NTreeSelect, 'select'),
Upload: NUpload,
},
config: {
disabledOnChangeListener: true,
baseModelPropName: 'value',
modelPropNameMap: {
Checkbox: 'checked',
Expand Down
1 change: 0 additions & 1 deletion apps/web-naive/src/router/routes/modules/demos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const routes: RouteRecordRaw[] = [
},
{
meta: {
icon: 'mdi:shield-key-outline',
title: $t('page.demos.table'),
},
name: 'Table',
Expand Down
11 changes: 10 additions & 1 deletion packages/@core/ui-kit/form-ui/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import type { BaseFormComponentType, VbenFormAdapterOptions } from './types';
import type {
BaseFormComponentType,
FormCommonConfig,
VbenFormAdapterOptions,
} from './types';

import type { Component } from 'vue';
import { h } from 'vue';
Expand All @@ -16,6 +20,8 @@ import { defineRule } from 'vee-validate';

const DEFAULT_MODEL_PROP_NAME = 'modelValue';

export const DEFAULT_FORM_COMMON_CONFIG: FormCommonConfig = {};

export const COMPONENT_MAP: Record<BaseFormComponentType, Component> = {
DefaultResetActionButton: h(VbenButton, { size: 'sm', variant: 'outline' }),
DefaultSubmitActionButton: h(VbenButton, { size: 'sm', variant: 'default' }),
Expand All @@ -37,6 +43,9 @@ export function setupVbenForm<
>(options: VbenFormAdapterOptions<T>) {
const { components, config, defineRules } = options;

DEFAULT_FORM_COMMON_CONFIG.disabledOnChangeListener =
config?.disabledOnChangeListener ?? false;

if (defineRules) {
for (const key of Object.keys(defineRules)) {
defineRule(key, defineRules[key as never]);
Expand Down
46 changes: 25 additions & 21 deletions packages/@core/ui-kit/form-ui/src/form-render/form-field.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { ZodType } from 'zod';
import type { FormSchema, MaybeComponentProps } from '../types';
import { computed, nextTick, ref, watch } from 'vue';
import { computed, nextTick, useTemplateRef, watch } from 'vue';
import {
FormControl,
Expand Down Expand Up @@ -32,6 +32,7 @@ const {
dependencies,
description,
disabled,
disabledOnChangeListener,
fieldName,
formFieldProps,
label,
Expand All @@ -49,19 +50,10 @@ const { componentBindEventMap, componentMap, isVertical } = useFormContext();
const formRenderProps = injectRenderFormProps();
const values = useFormValues();
const errors = useFieldError(fieldName);
const fieldComponentRef = useTemplateRef<HTMLInputElement>('fieldComponentRef');
const formApi = formRenderProps.form;
const isInValid = computed(() => errors.value?.length > 0);
const fieldComponentRef = ref<HTMLInputElement | null>(null);
const focus = () => {
if (
fieldComponentRef.value &&
typeof fieldComponentRef.value.focus === 'function' &&
document.activeElement !== fieldComponentRef.value // 检查当前是否有元素被聚焦
) {
fieldComponentRef.value.focus();
}
};
const fieldComponent = computed(() => {
const finalComponent = isString(component)
Expand Down Expand Up @@ -171,7 +163,7 @@ watch(
(value) => {
if (value === true) {
nextTick(() => {
focus();
autofocus();
});
}
},
Expand Down Expand Up @@ -222,15 +214,16 @@ function fieldBindEvent(slotProps: Record<string, any>) {
return {
[`onUpdate:${bindEventField}`]: handler,
[bindEventField]: value,
onChange: (e: Record<string, any>) => {
const shouldUnwrap = isEventObjectLike(e);
const onChange = slotProps?.componentField?.onChange;
if (!shouldUnwrap) {
return onChange?.(e);
}
return onChange?.(e?.target?.[bindEventField] ?? e);
},
onChange: disabledOnChangeListener
? undefined
: (e: Record<string, any>) => {
const shouldUnwrap = isEventObjectLike(e);
const onChange = slotProps?.componentField?.onChange;
if (!shouldUnwrap) {
return onChange?.(e);
}
return onChange?.(e?.target?.[bindEventField] ?? e);
},
onInput: () => {},
};
}
Expand All @@ -248,6 +241,17 @@ function createComponentProps(slotProps: Record<string, any>) {
return binds;
}
function autofocus() {
if (
fieldComponentRef.value &&
isFunction(fieldComponentRef.value.focus) &&
// 检查当前是否有元素被聚焦
document.activeElement !== fieldComponentRef.value
) {
fieldComponentRef.value?.focus?.();
}
}
</script>

<template>
Expand Down
29 changes: 20 additions & 9 deletions packages/@core/ui-kit/form-ui/src/form-render/form.vue
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
<script setup lang="ts">
import type { ZodTypeAny } from 'zod';
import type { FormRenderProps, FormSchema, FormShape } from '../types';
import type {
FormCommonConfig,
FormRenderProps,
FormSchema,
FormShape,
} from '../types';
import { computed } from 'vue';
import { Form } from '@vben-core/shadcn-ui';
import { cn, isString } from '@vben-core/shared/utils';
import { cn, isString, mergeWithArrayOverride } from '@vben-core/shared/utils';
import { type GenericObject } from 'vee-validate';
Expand All @@ -17,12 +22,16 @@ import { getBaseRules, getDefaultValueInZodStack } from './helper';
interface Props extends FormRenderProps {}
const props = withDefaults(defineProps<Props>(), {
collapsedRows: 1,
commonConfig: () => ({}),
showCollapseButton: false,
wrapperClass: 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3',
});
const props = withDefaults(
defineProps<{ globalCommonConfig?: FormCommonConfig } & Props>(),
{
collapsedRows: 1,
commonConfig: () => ({}),
globalCommonConfig: () => ({}),
showCollapseButton: false,
wrapperClass: 'grid-cols-1 sm:grid-cols-2 md:grid-cols-3',
},
);
const emits = defineEmits<{
submit: [event: any];
Expand Down Expand Up @@ -77,14 +86,15 @@ const computedSchema = computed(
componentProps = {},
controlClass = '',
disabled,
disabledOnChangeListener = false,
formFieldProps = {},
formItemClass = '',
hideLabel = false,
hideRequiredMark = false,
labelClass = '',
labelWidth = 100,
wrapperClass = '',
} = props.commonConfig;
} = mergeWithArrayOverride(props.commonConfig, props.globalCommonConfig);
return (props.schema || []).map((schema, index) => {
const keepIndex = keepFormItemIndex.value;
Expand All @@ -96,6 +106,7 @@ const computedSchema = computed(
return {
disabled,
disabledOnChangeListener,
hideLabel,
hideRequiredMark,
labelWidth,
Expand Down
6 changes: 6 additions & 0 deletions packages/@core/ui-kit/form-ui/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,11 @@ export interface FormCommonConfig {
* @default false
*/
disabled?: boolean;
/**
* 是否禁用所有表单项的change事件监听
* @default false
*/
disabledOnChangeListener?: boolean;
/**
* 所有表单项的控件样式
* @default {}
Expand Down Expand Up @@ -317,6 +322,7 @@ export interface VbenFormAdapterOptions<
components: Partial<Record<T, Component>>;
config?: {
baseModelPropName?: string;
disabledOnChangeListener?: boolean;
modelPropNameMap?: Partial<Record<T, string>>;
};
defineRules?: {
Expand Down
7 changes: 6 additions & 1 deletion packages/@core/ui-kit/form-ui/src/vben-form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ import { ref, watchEffect } from 'vue';
import { useForwardPropsEmits } from '@vben-core/composables';
import FormActions from './components/form-actions.vue';
import { COMPONENT_BIND_EVENT_MAP, COMPONENT_MAP } from './config';
import {
COMPONENT_BIND_EVENT_MAP,
COMPONENT_MAP,
DEFAULT_FORM_COMMON_CONFIG,
} from './config';
import { Form } from './form-render';
import { provideFormProps, useFormInitial } from './use-form-context';
Expand Down Expand Up @@ -51,6 +55,7 @@ watchEffect(() => {
:component-bind-event-map="COMPONENT_BIND_EVENT_MAP"
:component-map="COMPONENT_MAP"
:form="form"
:global-common-config="DEFAULT_FORM_COMMON_CONFIG"
>
<template
v-for="slotName in delegatedSlots"
Expand Down
8 changes: 6 additions & 2 deletions packages/@core/ui-kit/form-ui/src/vben-use-form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ import type { ExtendedFormApi, VbenFormProps } from './types';
import { useForwardPriorityValues } from '@vben-core/composables';
import FormActions from './components/form-actions.vue';
import { COMPONENT_BIND_EVENT_MAP, COMPONENT_MAP } from './config';
import {
COMPONENT_BIND_EVENT_MAP,
COMPONENT_MAP,
DEFAULT_FORM_COMMON_CONFIG,
} from './config';
import { Form } from './form-render';
import { provideFormProps, useFormInitial } from './use-form-context';
// 通过 extends 会导致热更新卡死,所以重复写了一遍
interface Props extends VbenFormProps {
formApi: ExtendedFormApi;
Expand Down Expand Up @@ -36,6 +39,7 @@ const handleUpdateCollapsed = (value: boolean) => {
:component-bind-event-map="COMPONENT_BIND_EVENT_MAP"
:component-map="COMPONENT_MAP"
:form="form"
:global-common-config="DEFAULT_FORM_COMMON_CONFIG"
>
<template
v-for="slotName in delegatedSlots"
Expand Down
5 changes: 3 additions & 2 deletions playground/src/adapter/form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import type {
VbenFormProps,
} from '@vben/common-ui';

import { type Component, h, type SetupContext } from 'vue';
import type { Component, SetupContext } from 'vue';
import { h } from 'vue';

import { setupVbenForm, useVbenForm as useForm, z } from '@vben/common-ui';
import { $t } from '@vben/locales';
Expand Down Expand Up @@ -63,7 +64,7 @@ const withDefaultPlaceholder = <T extends Component>(
) => {
return (props: any, { attrs, slots }: Omit<SetupContext, 'expose'>) => {
const placeholder = props?.placeholder || $t(`placeholder.${type}`);
return h(component, { ...props, attrs, placeholder }, slots);
return h(component, { ...props, ...attrs, placeholder }, slots);
};
};

Expand Down
Loading

0 comments on commit 0cd865e

Please sign in to comment.