diff --git a/components/upload/UploadList/listAnimation.ts b/components/_util/collapseMotion.tsx similarity index 82% rename from components/upload/UploadList/listAnimation.ts rename to components/_util/collapseMotion.tsx index 9c37d266f..2c189fdcb 100644 --- a/components/upload/UploadList/listAnimation.ts +++ b/components/_util/collapseMotion.tsx @@ -1,16 +1,16 @@ -import { addClass, removeClass } from '../../vc-util/Dom/class'; import { nextTick } from 'vue'; -import type { CSSMotionProps } from '../../_util/transition'; +import { addClass, removeClass } from '../vc-util/Dom/class'; +import type { CSSMotionProps } from './transition'; -const listAnimation = (name): CSSMotionProps => { +const collapseMotion = (name = 'ant-motion-collapse'): CSSMotionProps => { return { name, appear: true, css: true, onBeforeEnter: (node: HTMLDivElement) => { - addClass(node, name); node.style.height = '0px'; node.style.opacity = '0'; + addClass(node, name); }, onEnter: (node: HTMLDivElement) => { nextTick(() => { @@ -41,4 +41,4 @@ const listAnimation = (name): CSSMotionProps => { }, }; }; -export default listAnimation; +export default collapseMotion; diff --git a/components/_util/hooks/useConfigInject.ts b/components/_util/hooks/useConfigInject.ts index 56e9d4cfb..079ac95b3 100644 --- a/components/_util/hooks/useConfigInject.ts +++ b/components/_util/hooks/useConfigInject.ts @@ -19,6 +19,7 @@ export default ( pageHeader: ComputedRef<{ ghost: boolean }>; form?: ComputedRef<{ requiredMark?: RequiredMark; + colon?: boolean; }>; autoInsertSpaceInButton: ComputedRef<boolean>; renderEmpty?: ComputedRef<(componentName?: string) => VueNode>; diff --git a/components/_util/transition.tsx b/components/_util/transition.tsx index 2a118849e..f610f9af6 100644 --- a/components/_util/transition.tsx +++ b/components/_util/transition.tsx @@ -129,13 +129,17 @@ export interface CSSMotionProps extends Partial<BaseTransitionProps<Element>> { css?: boolean; } -const collapseMotion = (style: Ref<CSSProperties>, className: Ref<string>): CSSMotionProps => { +const collapseMotion = ( + name = 'ant-motion-collapse', + style: Ref<CSSProperties>, + className: Ref<string>, +): CSSMotionProps => { return { - name: 'ant-motion-collapse', + name, appear: true, css: true, onBeforeEnter: node => { - className.value = 'ant-motion-collapse'; + className.value = name; style.value = getCollapsedHeight(node); }, onEnter: node => { @@ -148,7 +152,7 @@ const collapseMotion = (style: Ref<CSSProperties>, className: Ref<string>): CSSM style.value = {}; }, onBeforeLeave: node => { - className.value = 'ant-motion-collapse'; + className.value = name; style.value = getCurrentHeight(node); }, onLeave: node => { diff --git a/components/form/ErrorList.tsx b/components/form/ErrorList.tsx index 1a1aa073c..b707e0dd1 100644 --- a/components/form/ErrorList.tsx +++ b/components/form/ErrorList.tsx @@ -1,9 +1,9 @@ import { useInjectFormItemPrefix } from './context'; import type { VueNode } from '../_util/type'; -import { defineComponent, onBeforeUnmount, ref, watch } from 'vue'; -import classNames from '../_util/classNames'; -import Transition, { getTransitionProps } from '../_util/transition'; +import { computed, defineComponent, ref, watch } from 'vue'; +import { getTransitionGroupProps, TransitionGroup } from '../_util/transition'; import useConfigInject from '../_util/hooks/useConfigInject'; +import collapseMotion from '../_util/collapseMotion'; export interface ErrorListProps { errors?: VueNode[]; @@ -15,72 +15,40 @@ export interface ErrorListProps { export default defineComponent({ name: 'ErrorList', - props: ['errors', 'help', 'onDomErrorVisibleChange'], + props: ['errors', 'help', 'onDomErrorVisibleChange', 'helpStatus', 'warnings'], setup(props) { const { prefixCls: rootPrefixCls } = useConfigInject('', props); const { prefixCls, status } = useInjectFormItemPrefix(); - const visible = ref(!!(props.errors && props.errors.length)); + const baseClassName = computed(() => `${prefixCls.value}-item-explain`); + const visible = computed(() => !!(props.errors && props.errors.length)); const innerStatus = ref(status.value); - const timeout = ref(); - const cacheErrors = ref([...props.errors]); - watch([() => [...props.errors], () => props.help], newValues => { - clearTimeout(timeout.value); - if (props.help) { - visible.value = !!(props.errors && props.errors.length); - if (visible.value) { - cacheErrors.value = newValues[0]; - } - } else { - timeout.value = setTimeout(() => { - visible.value = !!(props.errors && props.errors.length); - if (visible.value) { - cacheErrors.value = newValues[0]; - } - }); - } - }); - onBeforeUnmount(() => { - clearTimeout(timeout.value); - }); + // Memo status in same visible watch([visible, status], () => { if (visible.value) { innerStatus.value = status.value; } }); - watch( - visible, - () => { - if (visible.value) { - props.onDomErrorVisibleChange?.(true); - } - }, - { immediate: true, flush: 'post' }, - ); + return () => { - const baseClassName = `${prefixCls.value}-item-explain`; - const transitionProps = getTransitionProps(`${rootPrefixCls.value}-show-help`, { - onAfterLeave: () => { - props.onDomErrorVisibleChange?.(false); - }, - }); + const colMItem = collapseMotion(`${rootPrefixCls.value}-show-help-item`); + const transitionGroupProps = getTransitionGroupProps( + `${rootPrefixCls.value}-show-help-item`, + colMItem, + ); + (transitionGroupProps as any).class = baseClassName.value; return ( - <Transition {...transitionProps}> - {visible.value ? ( + <TransitionGroup {...transitionGroupProps} tag="div"> + {props.errors?.map((error: any, index: number) => ( <div - class={classNames(baseClassName, { - [`${baseClassName}-${innerStatus.value}`]: innerStatus.value, - })} - key="help" + key={index} + role="alert" + class={innerStatus.value ? `${baseClassName.value}-${innerStatus.value}` : ''} > - {cacheErrors.value?.map((error: any, index: number) => ( - <div key={index} role="alert"> - {error} - </div> - ))} + {error} </div> - ) : null} - </Transition> + ))} + </TransitionGroup> ); }; }, diff --git a/components/form/Form.tsx b/components/form/Form.tsx index d07cf83ed..5ce8f0292 100755 --- a/components/form/Form.tsx +++ b/components/form/Form.tsx @@ -66,6 +66,7 @@ export const formProps = { wrapperCol: { type: Object as PropType<ColProps & HTMLAttributes> }, colon: PropTypes.looseBool, labelAlign: PropTypes.oneOf(tuple('left', 'right')), + labelWrap: PropTypes.looseBool, prefixCls: PropTypes.string, requiredMark: { type: [String, Boolean] as PropType<RequiredMark | ''>, default: undefined }, /** @deprecated Will warning in future branch. Pls use `requiredMark` instead. */ @@ -145,6 +146,7 @@ const Form = defineComponent({ } return true; }); + const mergedColon = computed(() => props.colon ?? contextForm.value?.colon); const validateMessages = computed(() => { return { ...defaultValidateMessages, @@ -367,9 +369,10 @@ const Form = defineComponent({ name: computed(() => props.name), labelAlign: computed(() => props.labelAlign), labelCol: computed(() => props.labelCol), + labelWrap: computed(() => props.labelWrap), wrapperCol: computed(() => props.wrapperCol), vertical: computed(() => props.layout === 'vertical'), - colon: computed(() => props.colon), + colon: mergedColon, requiredMark: mergedRequiredMark, validateTrigger: computed(() => props.validateTrigger), rules: computed(() => props.rules), diff --git a/components/form/FormItem.tsx b/components/form/FormItem.tsx index 9a6ab25c5..a0d673ba6 100644 --- a/components/form/FormItem.tsx +++ b/components/form/FormItem.tsx @@ -134,7 +134,6 @@ export default defineComponent({ const fieldName = computed(() => props.name || props.prop); const errors = ref([]); const validateDisabled = ref(false); - const domErrorVisible = ref(false); const inputRef = ref(); const namePath = computed(() => { const val = fieldName.value; @@ -388,7 +387,9 @@ export default defineComponent({ {...attrs} class={[ itemClassName.value, - domErrorVisible.value || !!help ? `${prefixCls.value}-item-with-help` : '', + (help !== undefined && help !== null) || errors.value.length + ? `${prefixCls.value}-item-with-help` + : '', attrs.class, ]} key="row" @@ -411,7 +412,6 @@ export default defineComponent({ errors={help !== undefined && help !== null ? toArray(help) : errors.value} prefixCls={prefixCls.value} status={validateState.value} - onDomErrorVisibleChange={(v: boolean) => (domErrorVisible.value = v)} validateStatus={validateState.value} ref={inputRef} help={help} diff --git a/components/form/FormItemInput.tsx b/components/form/FormItemInput.tsx index 6eadb736c..580a72f81 100644 --- a/components/form/FormItemInput.tsx +++ b/components/form/FormItemInput.tsx @@ -11,14 +11,13 @@ import classNames from '../_util/classNames'; import type { ValidateStatus } from './FormItem'; import type { VueNode } from '../_util/type'; import type { HTMLAttributes } from 'vue'; -import { computed, defineComponent, onUnmounted } from 'vue'; +import { computed, defineComponent } from 'vue'; export interface FormItemInputMiscProps { prefixCls: string; errors: VueNode[]; hasFeedback?: boolean; validateStatus?: ValidateStatus; - onDomErrorVisibleChange: (visible: boolean) => void; } export interface FormItemInputProps { @@ -62,17 +61,12 @@ const FormItemInput = defineComponent({ status: computed(() => props.status), }); - onUnmounted(() => { - props.onDomErrorVisibleChange(false); - }); - return () => { const { prefixCls, wrapperCol, help = slots.help?.(), errors = slots.errors?.(), - onDomErrorVisibleChange, hasFeedback, validateStatus, extra = slots.extra?.(), @@ -105,7 +99,7 @@ const FormItemInput = defineComponent({ <ErrorList errors={errors} help={help} - onDomErrorVisibleChange={onDomErrorVisibleChange} + class={`${baseClassName}-explain-connected`} /> {extra ? <div class={`${baseClassName}-extra`}>{extra}</div> : null} </> diff --git a/components/form/FormItemLabel.tsx b/components/form/FormItemLabel.tsx index 8ffe92429..f79ff0942 100644 --- a/components/form/FormItemLabel.tsx +++ b/components/form/FormItemLabel.tsx @@ -33,6 +33,7 @@ const FormItemLabel: FunctionalComponent<FormItemLabelProps> = (props, { slots, vertical, labelAlign: contextLabelAlign, labelCol: contextLabelCol, + labelWrap, colon: contextColon, } = useInjectForm(); const mergedLabelCol: FormItemLabelProps['labelCol'] = labelCol || contextLabelCol?.value || {}; @@ -44,6 +45,9 @@ const FormItemLabel: FunctionalComponent<FormItemLabelProps> = (props, { slots, labelClsBasic, mergedLabelAlign === 'left' && `${labelClsBasic}-left`, mergedLabelCol.class, + { + [`${labelClsBasic}-wrap`]: !!labelWrap.value, + }, ); let labelChildren = label; diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap index d926893d1..9079c75e8 100644 --- a/components/form/__tests__/__snapshots__/demo.test.js.snap +++ b/components/form/__tests__/__snapshots__/demo.test.js.snap @@ -14,7 +14,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-1" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -29,7 +29,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-2" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -44,7 +44,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-3" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -59,7 +59,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-4" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -74,7 +74,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-5" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -89,7 +89,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-6" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -104,7 +104,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-7" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -119,7 +119,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-8" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -134,7 +134,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-9" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -149,7 +149,7 @@ exports[`renders ./components/form/demo/advanced-search.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="placeholder" type="text" id="advanced_search_field-10" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -178,7 +178,7 @@ exports[`renders ./components/form/demo/basic.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" id="basic_username" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -191,7 +191,7 @@ exports[`renders ./components/form/demo/basic.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><span class="ant-input-affix-wrapper ant-input-password"><!----><input id="basic_password" type="password" class="ant-input"><span class="ant-input-suffix"><!----><span tabindex="-1" role="img" aria-label="eye-invisible" class="anticon anticon-eye-invisible ant-input-password-icon"><svg focusable="false" class="" data-icon="eye-invisible" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"></path><path d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"></path></svg></span></span></span></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -202,7 +202,7 @@ exports[`renders ./components/form/demo/basic.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><label class="ant-checkbox-wrapper ant-checkbox-wrapper-checked"><span class="ant-checkbox ant-checkbox-checked"><input id="basic_remember" type="checkbox" class="ant-checkbox-input"><span class="ant-checkbox-inner"></span></span><span>Remember me</span></label></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -215,7 +215,7 @@ exports[`renders ./components/form/demo/basic.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -233,7 +233,7 @@ exports[`renders ./components/form/demo/custom-validation.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input autocomplete="off" type="password" id="custom-validation_pass" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -246,7 +246,7 @@ exports[`renders ./components/form/demo/custom-validation.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input autocomplete="off" type="password" id="custom-validation_checkPass" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -264,7 +264,7 @@ exports[`renders ./components/form/demo/custom-validation.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -279,7 +279,7 @@ exports[`renders ./components/form/demo/custom-validation.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -302,7 +302,7 @@ exports[`renders ./components/form/demo/customized-form-controls.vue correctly 1 </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -315,7 +315,7 @@ exports[`renders ./components/form/demo/customized-form-controls.vue correctly 1 </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -333,7 +333,7 @@ exports[`renders ./components/form/demo/dynamic-form-item.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -348,7 +348,7 @@ exports[`renders ./components/form/demo/dynamic-form-item.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -366,7 +366,7 @@ exports[`renders ./components/form/demo/dynamic-form-items.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -379,7 +379,7 @@ exports[`renders ./components/form/demo/dynamic-form-items.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -406,7 +406,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.vue correctly </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -419,7 +419,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.vue correctly </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -432,7 +432,7 @@ exports[`renders ./components/form/demo/dynamic-form-items-complex.vue correctly </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -450,7 +450,7 @@ exports[`renders ./components/form/demo/dynamic-rule.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" id="dynamic_rule_username" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -463,7 +463,7 @@ exports[`renders ./components/form/demo/dynamic-rule.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" id="dynamic_rule_nickname" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -474,7 +474,7 @@ exports[`renders ./components/form/demo/dynamic-rule.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><label class="ant-checkbox-wrapper"><span class="ant-checkbox"><input id="dynamic_rule_checkNick" type="checkbox" class="ant-checkbox-input"><span class="ant-checkbox-inner"></span></span><span>Nickname is required</span></label></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -487,7 +487,7 @@ exports[`renders ./components/form/demo/dynamic-rule.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -505,7 +505,7 @@ exports[`renders ./components/form/demo/form-context.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" id="form_context_group" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -520,7 +520,7 @@ exports[`renders ./components/form/demo/form-context.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -535,7 +535,7 @@ exports[`renders ./components/form/demo/form-context.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -562,7 +562,7 @@ exports[`renders ./components/form/demo/horizontal-login.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -575,7 +575,7 @@ exports[`renders ./components/form/demo/horizontal-login.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -588,7 +588,7 @@ exports[`renders ./components/form/demo/horizontal-login.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -608,7 +608,7 @@ exports[`renders ./components/form/demo/inline-login.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -621,7 +621,7 @@ exports[`renders ./components/form/demo/inline-login.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><span class="ant-input-affix-wrapper ant-input-password"><span class="ant-input-prefix"><span role="img" aria-label="lock" class="anticon anticon-lock site-form-item-icon"><svg focusable="false" class="" data-icon="lock" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 10-56 0z"></path></svg></span></span><input id="horizontal_login_password" type="password" class="ant-input"><span class="ant-input-suffix"><!----><span tabindex="-1" role="img" aria-label="eye-invisible" class="anticon anticon-eye-invisible ant-input-password-icon"><svg focusable="false" class="" data-icon="eye-invisible" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"></path><path d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"></path></svg></span></span></span></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -634,7 +634,7 @@ exports[`renders ./components/form/demo/inline-login.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -652,7 +652,7 @@ exports[`renders ./components/form/demo/lable-width.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -667,7 +667,7 @@ exports[`renders ./components/form/demo/lable-width.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -682,7 +682,7 @@ exports[`renders ./components/form/demo/lable-width.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -697,7 +697,7 @@ exports[`renders ./components/form/demo/lable-width.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -710,7 +710,7 @@ exports[`renders ./components/form/demo/lable-width.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="textarea" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -725,7 +725,7 @@ exports[`renders ./components/form/demo/lable-width.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -745,7 +745,7 @@ exports[`renders ./components/form/demo/layout.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -758,7 +758,7 @@ exports[`renders ./components/form/demo/layout.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="input placeholder" type="text" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -771,7 +771,7 @@ exports[`renders ./components/form/demo/layout.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input placeholder="input placeholder" type="text" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -784,7 +784,7 @@ exports[`renders ./components/form/demo/layout.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -802,7 +802,7 @@ exports[`renders ./components/form/demo/nest-messages.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" id="nest-messages_user_name" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -815,7 +815,7 @@ exports[`renders ./components/form/demo/nest-messages.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" id="nest-messages_user_email" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -833,7 +833,7 @@ exports[`renders ./components/form/demo/nest-messages.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -846,7 +846,7 @@ exports[`renders ./components/form/demo/nest-messages.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" id="nest-messages_user_website" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -859,7 +859,7 @@ exports[`renders ./components/form/demo/nest-messages.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><textarea id="nest-messages_user_introduction" class="ant-input"></textarea></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -872,7 +872,7 @@ exports[`renders ./components/form/demo/nest-messages.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -892,7 +892,7 @@ exports[`renders ./components/form/demo/normal-login.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -905,7 +905,7 @@ exports[`renders ./components/form/demo/normal-login.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><span class="ant-input-affix-wrapper ant-input-password"><span class="ant-input-prefix"><span role="img" aria-label="lock" class="anticon anticon-lock site-form-item-icon"><svg focusable="false" class="" data-icon="lock" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M832 464h-68V240c0-70.7-57.3-128-128-128H388c-70.7 0-128 57.3-128 128v224h-68c-17.7 0-32 14.3-32 32v384c0 17.7 14.3 32 32 32h640c17.7 0 32-14.3 32-32V496c0-17.7-14.3-32-32-32zM332 240c0-30.9 25.1-56 56-56h248c30.9 0 56 25.1 56 56v224H332V240zm460 600H232V536h560v304zM484 701v53c0 4.4 3.6 8 8 8h40c4.4 0 8-3.6 8-8v-53a48.01 48.01 0 10-56 0z"></path></svg></span></span><input id="normal_login_password" type="password" class="ant-input"><span class="ant-input-suffix"><!----><span tabindex="-1" role="img" aria-label="eye-invisible" class="anticon anticon-eye-invisible ant-input-password-icon"><svg focusable="false" class="" data-icon="eye-invisible" width="1em" height="1em" fill="currentColor" aria-hidden="true" viewBox="64 64 896 896"><path d="M942.2 486.2Q889.47 375.11 816.7 305l-50.88 50.88C807.31 395.53 843.45 447.4 874.7 512 791.5 684.2 673.4 766 512 766q-72.67 0-133.87-22.38L323 798.75Q408 838 512 838q288.3 0 430.2-300.3a60.29 60.29 0 000-51.5zm-63.57-320.64L836 122.88a8 8 0 00-11.32 0L715.31 232.2Q624.86 186 512 186q-288.3 0-430.2 300.3a60.3 60.3 0 000 51.5q56.69 119.4 136.5 191.41L112.48 835a8 8 0 000 11.31L155.17 889a8 8 0 0011.31 0l712.15-712.12a8 8 0 000-11.32zM149.3 512C232.6 339.8 350.7 258 512 258c54.54 0 104.13 9.36 149.12 28.39l-70.3 70.3a176 176 0 00-238.13 238.13l-83.42 83.42C223.1 637.49 183.3 582.28 149.3 512zm246.7 0a112.11 112.11 0 01146.2-106.69L401.31 546.2A112 112 0 01396 512z"></path><path d="M508 624c-3.46 0-6.87-.16-10.25-.47l-52.82 52.82a176.09 176.09 0 00227.42-227.42l-52.82 52.82c.31 3.38.47 6.79.47 10.25a111.94 111.94 0 01-112 112z"></path></svg></span></span></span></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -919,7 +919,7 @@ exports[`renders ./components/form/demo/normal-login.vue correctly 1`] = ` </button> Or <a href="">register now!</a></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -944,7 +944,7 @@ exports[`renders ./components/form/demo/time-related-controls.vue correctly 1`] </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -964,7 +964,7 @@ exports[`renders ./components/form/demo/time-related-controls.vue correctly 1`] </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -984,7 +984,7 @@ exports[`renders ./components/form/demo/time-related-controls.vue correctly 1`] </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1006,7 +1006,7 @@ exports[`renders ./components/form/demo/time-related-controls.vue correctly 1`] </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1028,7 +1028,7 @@ exports[`renders ./components/form/demo/time-related-controls.vue correctly 1`] </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1048,7 +1048,7 @@ exports[`renders ./components/form/demo/time-related-controls.vue correctly 1`] </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1061,7 +1061,7 @@ exports[`renders ./components/form/demo/time-related-controls.vue correctly 1`] </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1079,7 +1079,7 @@ exports[`renders ./components/form/demo/useForm-basic.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1101,7 +1101,7 @@ exports[`renders ./components/form/demo/useForm-basic.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1116,7 +1116,7 @@ exports[`renders ./components/form/demo/useForm-basic.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1131,7 +1131,7 @@ exports[`renders ./components/form/demo/useForm-basic.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1149,7 +1149,7 @@ exports[`renders ./components/form/demo/useForm-merge.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1171,7 +1171,7 @@ exports[`renders ./components/form/demo/useForm-merge.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1186,7 +1186,7 @@ exports[`renders ./components/form/demo/useForm-merge.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1201,7 +1201,7 @@ exports[`renders ./components/form/demo/useForm-merge.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1219,7 +1219,7 @@ exports[`renders ./components/form/demo/useForm-nested.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1232,7 +1232,7 @@ exports[`renders ./components/form/demo/useForm-nested.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1247,7 +1247,7 @@ exports[`renders ./components/form/demo/useForm-nested.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1265,7 +1265,7 @@ exports[`renders ./components/form/demo/useForm-trigger.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1287,7 +1287,7 @@ exports[`renders ./components/form/demo/useForm-trigger.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1302,7 +1302,7 @@ exports[`renders ./components/form/demo/useForm-trigger.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1320,7 +1320,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><span class="ant-form-text">China</span></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1342,7 +1342,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1370,7 +1370,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1388,7 +1388,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1403,7 +1403,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1425,7 +1425,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1440,7 +1440,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1455,7 +1455,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1479,7 +1479,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1525,7 +1525,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1542,7 +1542,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <div class="ant-form-item-extra">longgggggggggggggggggggggggggggggggggg</div> </div> </div> @@ -1562,7 +1562,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1575,7 +1575,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1593,7 +1593,7 @@ exports[`renders ./components/form/demo/validation.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><input type="text" id="form_item_name" class="ant-input"></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1615,7 +1615,7 @@ exports[`renders ./components/form/demo/validation.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1635,7 +1635,7 @@ exports[`renders ./components/form/demo/validation.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1650,7 +1650,7 @@ exports[`renders ./components/form/demo/validation.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1665,7 +1665,7 @@ exports[`renders ./components/form/demo/validation.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1680,7 +1680,7 @@ exports[`renders ./components/form/demo/validation.vue correctly 1`] = ` </div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1693,7 +1693,7 @@ exports[`renders ./components/form/demo/validation.vue correctly 1`] = ` <div class="ant-form-item-control-input-content"><textarea id="form_item_desc" class="ant-input"></textarea></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> @@ -1708,7 +1708,7 @@ exports[`renders ./components/form/demo/validation.vue correctly 1`] = ` </button></div> <!----> </div> - <!----> + <div class="ant-form-item-explain ant-form-item-explain-connected"></div> <!----> </div> </div> diff --git a/components/form/context.ts b/components/form/context.ts index 8e78827b0..18a19a3d0 100644 --- a/components/form/context.ts +++ b/components/form/context.ts @@ -12,6 +12,7 @@ export interface FormContextProps { name?: ComputedRef<string>; colon?: ComputedRef<boolean>; labelAlign?: ComputedRef<FormLabelAlign>; + labelWrap?: ComputedRef<boolean>; labelCol?: ComputedRef<ColProps>; wrapperCol?: ComputedRef<ColProps>; requiredMark?: ComputedRef<RequiredMark>; diff --git a/components/form/index.en-US.md b/components/form/index.en-US.md index 495768913..67b4e0436 100644 --- a/components/form/index.en-US.md +++ b/components/form/index.en-US.md @@ -36,6 +36,7 @@ A form consists of one or more form fields whose type includes input, textarea, | hideRequiredMark | Hide required mark of all form items | Boolean | false | | | layout | Define form layout | 'horizontal'\|'vertical'\|'inline' | 'horizontal' | | | labelAlign | text align of label of all items | 'left' \| 'right' | 'right' | | +| labelWrap | whether label can be wrap | boolean | false | 3.0 | | labelCol | The layout of label. You can set `span` `offset` to something like `{span: 3, offset: 12}` or `sm: {span: 3, offset: 12}` same as with `<Col>` | [object](/components/grid/#Col) | | | | wrapperCol | The layout for input controls, same as `labelCol` | [object](/components/grid/#Col) | | | | colon | change default props colon value of Form.Item (only effective when prop layout is horizontal) | boolean | true | | diff --git a/components/form/index.zh-CN.md b/components/form/index.zh-CN.md index a5c9768f6..2b085736e 100644 --- a/components/form/index.zh-CN.md +++ b/components/form/index.zh-CN.md @@ -36,9 +36,10 @@ cover: https://gw.alipayobjects.com/zos/alicdn/ORmcdeaoO/Form.svg | rules | 表单验证规则 | object | | | | hideRequiredMark | 隐藏所有表单项的必选标记 | Boolean | false | | | labelAlign | label 标签的文本对齐方式 | 'left' \| 'right' | 'right' | | -| layout | 表单布局 | 'horizontal'\|'vertical'\|'inline' | 'horizontal' | | +| labelWrap | label 标签的文本换行方式 | boolean | false | 3.0 | | labelCol | label 标签布局,同 `<Col>` 组件,设置 `span` `offset` 值,如 `{span: 3, offset: 12}` 或 `sm: {span: 3, offset: 12}` | [object](/components/grid-cn/#Col) | | | | wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol | [object](/components/grid-cn/#Col) | | | +| layout | 表单布局 | 'horizontal'\|'vertical'\|'inline' | 'horizontal' | | | colon | 配置 Form.Item 的 colon 的默认值 (只有在属性 layout 为 horizontal 时有效) | boolean | true | | | validateOnRuleChange | 是否在 rules 属性改变后立即触发一次验证 | boolean | true | | | scrollToFirstError | 提交失败自动滚动到第一个错误字段 | boolean \| [options](https://github.com/stipsan/scroll-into-view-if-needed/#options) | false | 2.0.0 | diff --git a/components/form/style/components.less b/components/form/style/components.less index 4dc1b2147..53d4773d9 100644 --- a/components/form/style/components.less +++ b/components/form/style/components.less @@ -1,14 +1,12 @@ -@import './index'; +@import (reference) '../../style/themes/index'; + +@form-prefix-cls: ~'@{ant-prefix}-form'; +@form-item-prefix-cls: ~'@{form-prefix-cls}-item'; // ================================================================ // = Children Component = // ================================================================ .@{form-item-prefix-cls} { - .@{ant-prefix}-mentions, - textarea.@{ant-prefix}-input { - height: auto; - } - // input[type=file] .@{ant-prefix}-upload { background: transparent; @@ -51,6 +49,7 @@ + .@{form-prefix-cls}-text { margin-left: 8px; } + &-handler-wrap { z-index: 2; // https://github.com/ant-design/ant-design/issues/6289 } diff --git a/components/form/style/horizontal.less b/components/form/style/horizontal.less index 83b664d44..f8238982a 100644 --- a/components/form/style/horizontal.less +++ b/components/form/style/horizontal.less @@ -1,4 +1,7 @@ -@import './index'; +@import (reference) '../../style/themes/index'; + +@form-prefix-cls: ~'@{ant-prefix}-form'; +@form-item-prefix-cls: ~'@{form-prefix-cls}-item'; .@{form-prefix-cls}-horizontal { .@{form-item-prefix-cls}-label { @@ -7,4 +10,9 @@ .@{form-item-prefix-cls}-control { flex: 1 1 0; } + // https://github.com/ant-design/ant-design/issues/32980 + .@{form-item-prefix-cls}-control:not(.@{ant-prefix}-col) { + // https://github.com/ant-design/ant-design/issues/32777 + min-width: 0; + } } diff --git a/components/form/style/index.less b/components/form/style/index.less index 5ea9f43c2..3f168b022 100644 --- a/components/form/style/index.less +++ b/components/form/style/index.less @@ -39,6 +39,7 @@ &-small { .formSize(@input-height-sm); } + &-large { .formSize(@input-height-lg); } @@ -61,9 +62,12 @@ margin-bottom: @form-item-margin-bottom; vertical-align: top; + // We delay one frame (0.017s) here to let CSSMotion goes + transition: margin-bottom @animation-duration-slow 0.017s linear; &-with-help { - margin-bottom: 0; + // margin-bottom: 0; + transition: none; } &-hidden, @@ -87,11 +91,17 @@ text-align: left; } + &-wrap { + overflow: unset; + line-height: (@line-height-base - 0.25em); + white-space: unset; + } + > label { position: relative; - // display: inline; display: inline-flex; align-items: center; + max-width: 100%; height: @form-item-label-height; color: @label-color; font-size: @form-item-label-font-size; @@ -179,10 +189,12 @@ } } + // ============================================================== + // = Explain = + // ============================================================== &-explain, &-extra { clear: both; - min-height: @form-item-margin-bottom; color: @text-color-secondary; font-size: @font-size-base; line-height: @line-height-base; @@ -190,43 +202,66 @@ .explainAndExtraDistance((@form-item-margin-bottom - @form-font-height) / 2); } + &-explain-connected { + height: 0; + min-height: @form-item-margin-bottom; + opacity: 0; + margin-top: -@form-item-margin-bottom; + transform: translateY(@form-item-margin-bottom); + } + + &-extra { + min-height: @form-item-margin-bottom; + } + .@{ant-prefix}-input-textarea-show-count { &::after { margin-bottom: -22px; } } -} -.show-help-motion(@className, @keyframeName, @duration: @animation-duration-slow) { - @name: ~'@{ant-prefix}-@{className}'; - .make-motion(@name, @keyframeName, @duration); - .@{name}-enter, - .@{name}-appear { - opacity: 0; - animation-timing-function: @ease-in-out; - } - .@{name}-leave { - animation-timing-function: @ease-in-out; - } -} - -.show-help-motion(show-help, antShowHelp, 0.3s); - -@keyframes antShowHelpIn { - 0% { - transform: translateY(-5px); - opacity: 0; - } - 100% { - transform: translateY(0); + &-with-help &-explain { + height: auto; + min-height: @form-item-margin-bottom; opacity: 1; } } -@keyframes antShowHelpOut { - to { +// >>>>>>>>>> Motion <<<<<<<<<< +// Explain holder +.@{ant-prefix}-show-help { + transition: height @animation-duration-slow linear, min-height @animation-duration-slow linear, + margin-bottom @animation-duration-slow @ease-in-out, + opacity @animation-duration-slow @ease-in-out; + + &-leave { + min-height: @form-item-margin-bottom; + + &-active { + min-height: 0; + } + } +} + +// Explain +.@{ant-prefix}-show-help-item { + overflow: hidden; + transition: height @animation-duration-slow @ease-in-out, + opacity @animation-duration-slow @ease-in-out, transform @animation-duration-slow @ease-in-out !important; + + &-appear, + &-enter { transform: translateY(-5px); opacity: 0; + + &-active { + transform: translateY(0); + opacity: 1; + } + } + + &-leave-active { + transform: translateY(-5px); } } @@ -235,27 +270,36 @@ @keyframes diffZoomIn1 { 0% { transform: scale(0); + opacity: 0; } + 100% { transform: scale(1); + opacity: 1; } } @keyframes diffZoomIn2 { 0% { transform: scale(0); + opacity: 0; } + 100% { transform: scale(1); + opacity: 1; } } @keyframes diffZoomIn3 { 0% { transform: scale(0); + opacity: 0; } + 100% { transform: scale(1); + opacity: 1; } } diff --git a/components/form/style/index.ts b/components/form/style/index.tsx similarity index 100% rename from components/form/style/index.ts rename to components/form/style/index.tsx diff --git a/components/form/style/inline.less b/components/form/style/inline.less index 6cd0c4d40..63946752d 100644 --- a/components/form/style/inline.less +++ b/components/form/style/inline.less @@ -1,4 +1,7 @@ -@import './index'; +@import (reference) '../../style/themes/index'; + +@form-prefix-cls: ~'@{ant-prefix}-form'; +@form-item-prefix-cls: ~'@{form-prefix-cls}-item'; .@{form-prefix-cls}-inline { display: flex; diff --git a/components/form/style/mixin.less b/components/form/style/mixin.less index 44c5a0e37..603212a27 100644 --- a/components/form/style/mixin.less +++ b/components/form/style/mixin.less @@ -12,7 +12,8 @@ } // 输入框的不同校验状态 :not(.@{ant-prefix}-input-disabled):not(.@{ant-prefix}-input-borderless).@{ant-prefix}-input, - :not(.@{ant-prefix}-input-affix-wrapper-disabled):not(.@{ant-prefix}-input-affix-wrapper-borderless).@{ant-prefix}-input-affix-wrapper { + :not(.@{ant-prefix}-input-affix-wrapper-disabled):not(.@{ant-prefix}-input-affix-wrapper-borderless).@{ant-prefix}-input-affix-wrapper, + :not(.@{ant-prefix}-input-number-affix-wrapper-disabled):not(.@{ant-prefix}-input-number-affix-wrapper-borderless).@{ant-prefix}-input-number-affix-wrapper { &, &:hover { background-color: @background-color; @@ -29,7 +30,8 @@ .active(@border-color, @hoverBorderColor, @outlineColor); } - .@{ant-prefix}-input-prefix { + .@{ant-prefix}-input-prefix, + .@{ant-prefix}-input-number-prefix { color: @text-color; } diff --git a/components/form/style/rtl.less b/components/form/style/rtl.less index 9fcbabad5..505ee0c52 100644 --- a/components/form/style/rtl.less +++ b/components/form/style/rtl.less @@ -80,6 +80,14 @@ } } + .@{ant-prefix}-input-number-affix-wrapper { + .@{ant-prefix}-input-number { + .@{form-prefix-cls}-rtl & { + padding: 0; + } + } + } + .@{ant-prefix}-input-search:not(.@{ant-prefix}-input-search-enter-button) { .@{ant-prefix}-input-suffix { .@{form-prefix-cls}-rtl & { diff --git a/components/form/style/status.less b/components/form/style/status.less index fc78ccb36..e16cf5753 100644 --- a/components/form/style/status.less +++ b/components/form/style/status.less @@ -1,19 +1,24 @@ -@import './index.less'; +@import (reference) '../../style/themes/index'; + +@form-prefix-cls: ~'@{ant-prefix}-form'; +@form-item-prefix-cls: ~'@{form-prefix-cls}-item'; .@{form-item-prefix-cls} { // ================================================================ // = Status = // ================================================================ + /* Some non-status related component style is in `components.less` */ // ========================= Explain ========================= + /* To support leave along ErrorList. We add additional className to handle explain style */ &-explain { - &&-error { + &-error { color: @error-color; } - &&-warning { + &-warning { color: @warning-color; } } @@ -67,6 +72,17 @@ padding-right: 42px; } + // ======================= Cascader ======================== + .@{ant-prefix}-cascader-picker { + &-arrow { + margin-right: 19px; + } + + &-clear { + right: 32px; + } + } + // ======================== Picker ========================= // Fix issue: https://github.com/ant-design/ant-design/issues/4783 .@{ant-prefix}-picker { @@ -132,7 +148,7 @@ } &.@{ant-prefix}-select-open .@{ant-prefix}-select-selector, &.@{ant-prefix}-select-focused .@{ant-prefix}-select-selector { - .active(@warning-color); + .active(@warning-color, @warning-color-hover, @warning-color-outline); } } @@ -141,10 +157,12 @@ .@{ant-prefix}-picker { background-color: @form-warning-input-bg; border-color: @warning-color; + &-focused, &:focus { - .active(@warning-color); + .active(@warning-color, @warning-color-hover, @warning-color-outline); } + &:not([disabled]):hover { background-color: @form-warning-input-bg; border-color: @warning-color; @@ -152,7 +170,7 @@ } .@{ant-prefix}-cascader-picker:focus .@{ant-prefix}-cascader-input { - .active(@warning-color); + .active(@warning-color, @warning-color-hover, @warning-color-outline); } } @@ -173,7 +191,7 @@ } &.@{ant-prefix}-select-open .@{ant-prefix}-select-selector, &.@{ant-prefix}-select-focused .@{ant-prefix}-select-selector { - .active(@error-color); + .active(@error-color, @error-color-hover, @error-color-outline); } } @@ -201,10 +219,12 @@ .@{ant-prefix}-picker { background-color: @form-error-input-bg; border-color: @error-color; + &-focused, &:focus { - .active(@error-color); + .active(@error-color, @error-color-hover, @error-color-outline); } + &:not([disabled]):hover { background-color: @form-error-input-bg; border-color: @error-color; @@ -221,11 +241,11 @@ } &.@{ant-prefix}-mention-active:not([disabled]) .@{ant-prefix}-mention-editor, .@{ant-prefix}-mention-editor:not([disabled]):focus { - .active(@error-color); + .active(@error-color, @error-color-hover, @error-color-outline); } } - // cascader + // Cascader .@{ant-prefix}-cascader-picker { &:hover .@{ant-prefix}-cascader-picker-label:hover @@ -235,11 +255,11 @@ &:focus .@{ant-prefix}-cascader-input { background-color: @form-error-input-bg; - .active(@error-color); + .active(@error-color, @error-color-hover, @error-color-outline); } } - // transfer + // Transfer .@{ant-prefix}-transfer { &-list { border-color: @error-color; @@ -258,7 +278,7 @@ } } - // RadioGroup + // Radio.Group .@{ant-prefix}-radio-button-wrapper { border-color: @error-color !important; @@ -268,6 +288,16 @@ } } } + + // Mentions + .@{ant-prefix}-mentions { + border-color: @error-color !important; + + &-focused, + &:focus { + .active(@error-color, @error-color-hover, @error-color-outline); + } + } } // ====================== Validating ======================= diff --git a/components/form/style/vertical.less b/components/form/style/vertical.less index 8e2249554..7626b5363 100644 --- a/components/form/style/vertical.less +++ b/components/form/style/vertical.less @@ -1,4 +1,7 @@ -@import './index'; +@import (reference) '../../style/themes/index'; + +@form-prefix-cls: ~'@{ant-prefix}-form'; +@form-item-prefix-cls: ~'@{form-prefix-cls}-item'; // ================== Label ================== .make-vertical-layout-label() { @@ -46,7 +49,7 @@ } .@{form-prefix-cls}-vertical .@{form-item-prefix-cls}-label, - // when labelCol is 24, it is a vertical form +/* when labelCol is 24, it is a vertical form */ .@{ant-prefix}-col-24.@{form-item-prefix-cls}-label, .@{ant-prefix}-col-xl-24.@{form-item-prefix-cls}-label { .make-vertical-layout-label(); diff --git a/components/menu/src/InlineSubMenuList.tsx b/components/menu/src/InlineSubMenuList.tsx index 1d34de925..3931d64af 100644 --- a/components/menu/src/InlineSubMenuList.tsx +++ b/components/menu/src/InlineSubMenuList.tsx @@ -36,7 +36,7 @@ export default defineComponent({ const mergedMotion = computed(() => { const m = motion.value || defaultMotions.value?.[fixedMode.value] || defaultMotions.value?.other; - const res = typeof m === 'function' ? m(style, className) : m; + const res = typeof m === 'function' ? m(undefined, style, className) : m; return { ...res, appear: props.keyPath.length <= 1 }; }); return () => { diff --git a/components/menu/src/PopupTrigger.tsx b/components/menu/src/PopupTrigger.tsx index 1025df0d3..587e79eed 100644 --- a/components/menu/src/PopupTrigger.tsx +++ b/components/menu/src/PopupTrigger.tsx @@ -75,7 +75,7 @@ export default defineComponent({ const className = ref(''); const mergedMotion = computed(() => { const m = motion.value || defaultMotions.value?.[mode.value] || defaultMotions.value?.other; - const res = typeof m === 'function' ? m(style, className) : m; + const res = typeof m === 'function' ? m(undefined, style, className) : m; return res ? getTransitionProps(res.name, { css: true }) : undefined; }); return () => { diff --git a/components/menu/src/hooks/useMenuContext.ts b/components/menu/src/hooks/useMenuContext.ts index dfc9e4c90..e97711074 100644 --- a/components/menu/src/hooks/useMenuContext.ts +++ b/components/menu/src/hooks/useMenuContext.ts @@ -61,7 +61,7 @@ export interface MenuContextProps { defaultMotions?: ComputedRef<Partial<{ [key in MenuMode | 'other']: | CSSMotionProps - | ((style: Ref<CSSProperties>, className: Ref<string>) => CSSMotionProps); + | ((name: string, style: Ref<CSSProperties>, className: Ref<string>) => CSSMotionProps); }> | null>; // // Popup diff --git a/components/upload/UploadList/index.tsx b/components/upload/UploadList/index.tsx index 6947f061d..acd1fbb17 100644 --- a/components/upload/UploadList/index.tsx +++ b/components/upload/UploadList/index.tsx @@ -14,7 +14,7 @@ import { initDefaultProps, isValidElement } from '../../_util/props-util'; import type { VueNode } from '../../_util/type'; import useConfigInject from '../../_util/hooks/useConfigInject'; import { getTransitionGroupProps, TransitionGroup } from '../../_util/transition'; -import listAnimation from './listAnimation'; +import collapseMotion from '../../_util/collapseMotion'; const HackSlot = (_, { slots }) => { return slots.default?.()[0]; @@ -143,7 +143,7 @@ export default defineComponent({ [`${prefixCls.value}-list-rtl`]: direction.value === 'rtl', })); const transitionGroupProps = computed(() => ({ - ...listAnimation( + ...collapseMotion( `${prefixCls.value}-${props.listType === 'picture-card' ? 'animate-inline' : 'animate'}`, ), ...getTransitionGroupProps( diff --git a/components/vc-tree/MotionTreeNode.tsx b/components/vc-tree/MotionTreeNode.tsx index d72eb541f..a67019fb6 100644 --- a/components/vc-tree/MotionTreeNode.tsx +++ b/components/vc-tree/MotionTreeNode.tsx @@ -42,7 +42,7 @@ export default defineComponent({ if (props.motion) { return props.motion; } else { - return collapseMotion(transitionStyle, transitionClass); + return collapseMotion(undefined, transitionStyle, transitionClass); } }); const onMotionEnd = (type?: 'appear' | 'leave') => {