fix: Form validate message shaking (#36575)

* refactor: move component out

* refactor: clean up code

* chore: stable it

* chore: back of container

* chore: adjust leave motion

* test: update snapshot

* chore: update motion logic

* fix: list start motion

* test: update snapshot

* test: update snapshot

* test: test for marginBottom
This commit is contained in:
二货机器人 2022-07-19 16:01:31 +08:00 committed by GitHub
parent 3301b4d6fc
commit 03ea767cad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 38734 additions and 37276 deletions

View File

@ -215,45 +215,53 @@ exports[`renders ./components/comment/demo/editor.md extend context correctly 1`
class="ant-comment-content-detail"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<textarea
class="ant-input"
rows="4"
/>
<div
class="ant-form-item-control-input-content"
>
<textarea
class="ant-input"
rows="4"
/>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
<div
class="ant-form-item-control-input-content"
>
<span>
Add Comment
</span>
</button>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Add Comment
</span>
</button>
</div>
</div>
</div>
</div>

View File

@ -143,45 +143,53 @@ exports[`renders ./components/comment/demo/editor.md correctly 1`] = `
class="ant-comment-content-detail"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<textarea
class="ant-input"
rows="4"
/>
<div
class="ant-form-item-control-input-content"
>
<textarea
class="ant-input"
rows="4"
/>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
<div
class="ant-form-item-control-input-content"
>
<span>
Add Comment
</span>
</button>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Add Comment
</span>
</button>
</div>
</div>
</div>
</div>

View File

@ -15668,32 +15668,26 @@ exports[`ConfigProvider components Form configProvider 1`] = `
class="config-form config-form-horizontal"
>
<div
class="config-row config-form-item config-form-item-with-help config-form-item-has-error"
class="config-form-item config-form-item-with-help config-form-item-has-error"
>
<div
class="config-col config-form-item-control"
class="config-row config-form-item-row"
>
<div
class="config-form-item-control-input"
class="config-col config-form-item-control"
>
<div
class="config-form-item-control-input-content"
class="config-form-item-control-input"
>
<input
class="config-input config-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="config-form-item-explain config-form-item-explain-connected"
>
<div
class="config-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="config-form-item-control-input-content"
>
<input
class="config-input config-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15706,33 +15700,27 @@ exports[`ConfigProvider components Form configProvider componentDisabled 1`] = `
class="config-form config-form-horizontal"
>
<div
class="config-row config-form-item config-form-item-with-help config-form-item-has-error"
class="config-form-item config-form-item-with-help config-form-item-has-error"
>
<div
class="config-col config-form-item-control"
class="config-row config-form-item-row"
>
<div
class="config-form-item-control-input"
class="config-col config-form-item-control"
>
<div
class="config-form-item-control-input-content"
class="config-form-item-control-input"
>
<input
class="config-input config-input-disabled config-input-status-error"
disabled=""
type="text"
value=""
/>
</div>
</div>
<div
class="config-form-item-explain config-form-item-explain-connected"
>
<div
class="config-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="config-form-item-control-input-content"
>
<input
class="config-input config-input-disabled config-input-status-error"
disabled=""
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15745,32 +15733,26 @@ exports[`ConfigProvider components Form configProvider componentSize large 1`] =
class="config-form config-form-horizontal config-form-large"
>
<div
class="config-row config-form-item config-form-item-with-help config-form-item-has-error"
class="config-form-item config-form-item-with-help config-form-item-has-error"
>
<div
class="config-col config-form-item-control"
class="config-row config-form-item-row"
>
<div
class="config-form-item-control-input"
class="config-col config-form-item-control"
>
<div
class="config-form-item-control-input-content"
class="config-form-item-control-input"
>
<input
class="config-input config-input-lg config-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="config-form-item-explain config-form-item-explain-connected"
>
<div
class="config-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="config-form-item-control-input-content"
>
<input
class="config-input config-input-lg config-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15783,32 +15765,26 @@ exports[`ConfigProvider components Form configProvider componentSize middle 1`]
class="config-form config-form-horizontal config-form-middle"
>
<div
class="config-row config-form-item config-form-item-with-help config-form-item-has-error"
class="config-form-item config-form-item-with-help config-form-item-has-error"
>
<div
class="config-col config-form-item-control"
class="config-row config-form-item-row"
>
<div
class="config-form-item-control-input"
class="config-col config-form-item-control"
>
<div
class="config-form-item-control-input-content"
class="config-form-item-control-input"
>
<input
class="config-input config-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="config-form-item-explain config-form-item-explain-connected"
>
<div
class="config-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="config-form-item-control-input-content"
>
<input
class="config-input config-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15821,32 +15797,26 @@ exports[`ConfigProvider components Form configProvider virtual and dropdownMatch
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-error"
class="ant-form-item ant-form-item-with-help ant-form-item-has-error"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<input
class="ant-input ant-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="ant-form-item-explain ant-form-item-explain-connected"
>
<div
class="ant-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input ant-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15859,32 +15829,26 @@ exports[`ConfigProvider components Form normal 1`] = `
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-error"
class="ant-form-item ant-form-item-with-help ant-form-item-has-error"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<input
class="ant-input ant-input-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="ant-form-item-explain ant-form-item-explain-connected"
>
<div
class="ant-form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input ant-input-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>
@ -15897,32 +15861,26 @@ exports[`ConfigProvider components Form prefixCls 1`] = `
class="prefix-Form prefix-Form-horizontal"
>
<div
class="ant-row prefix-Form-item prefix-Form-item-with-help prefix-Form-item-has-error"
class="prefix-Form-item prefix-Form-item-with-help prefix-Form-item-has-error"
>
<div
class="ant-col prefix-Form-item-control"
class="ant-row prefix-Form-item-row"
>
<div
class="prefix-Form-item-control-input"
class="ant-col prefix-Form-item-control"
>
<div
class="prefix-Form-item-control-input-content"
class="prefix-Form-item-control-input"
>
<input
class="prefix-Form prefix-Form-status-error"
type="text"
value=""
/>
</div>
</div>
<div
class="prefix-Form-item-explain prefix-Form-item-explain-connected"
>
<div
class="prefix-Form-item-explain-error"
role="alert"
>
Bamboo is Light
<div
class="prefix-Form-item-control-input-content"
>
<input
class="prefix-Form prefix-Form-status-error"
type="text"
value=""
/>
</div>
</div>
</div>
</div>

View File

@ -5,38 +5,42 @@ exports[`ConfigProvider.Form form requiredMark set requiredMark optional 1`] = `
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class="ant-form-item-required-mark-optional"
for="age"
title="年龄"
>
年龄
<span
class="ant-form-item-optional"
title=""
>
(optional)
</span>
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class="ant-form-item-required-mark-optional"
for="age"
title="年龄"
>
年龄
<span
class="ant-form-item-optional"
title=""
>
(optional)
</span>
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<input
id="age"
value="18"
/>
<div
class="ant-form-item-control-input-content"
>
<input
id="age"
value="18"
/>
</div>
</div>
</div>
</div>

View File

@ -34,6 +34,7 @@ export interface ErrorListProps {
errors?: React.ReactNode[];
warnings?: React.ReactNode[];
className?: string;
onVisibleChanged?: (visible: boolean) => void;
}
export default function ErrorList({
@ -42,6 +43,7 @@ export default function ErrorList({
errors = EMPTY_LIST,
warnings = EMPTY_LIST,
className: rootClassName,
onVisibleChanged,
}: ErrorListProps) {
const { prefixCls } = React.useContext(FormItemPrefixContext);
const { getPrefixCls } = React.useContext(ConfigContext);
@ -69,16 +71,10 @@ export default function ErrorList({
return (
<CSSMotion
{...collapseMotion}
motionDeadline={collapseMotion.motionDeadline}
motionName={`${rootPrefixCls}-show-help`}
motionAppear={false}
motionEnter={false}
visible={!!fullKeyList.length}
onLeaveStart={node => {
// Force disable css override style in index.less configured
node.style.height = 'auto';
return { height: node.offsetHeight };
}}
onVisibleChanged={onVisibleChanged}
>
{holderProps => {
const { className: holderClassName, style: holderStyle } = holderProps;

View File

@ -0,0 +1,209 @@
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
import classNames from 'classnames';
import * as React from 'react';
import omit from 'rc-util/lib/omit';
import type { Meta } from 'rc-field-form/lib/interface';
import { Row } from '../../grid';
import FormItemLabel from '../FormItemLabel';
import FormItemInput from '../FormItemInput';
import type { FormItemStatusContextProps, ReportMetaChange } from '../context';
import { FormContext, FormItemInputContext, NoStyleItemContext } from '../context';
import type { FormItemProps, ValidateStatus } from '.';
import useDebounce from '../hooks/useDebounce';
const iconMap = {
success: CheckCircleFilled,
warning: ExclamationCircleFilled,
error: CloseCircleFilled,
validating: LoadingOutlined,
};
export interface ItemHolderProps extends FormItemProps {
prefixCls: string;
className?: string;
style?: React.CSSProperties;
errors: React.ReactNode[];
warnings: React.ReactNode[];
meta: Meta;
children?: React.ReactNode;
fieldId?: string;
isRequired?: boolean;
onSubItemMetaChange: ReportMetaChange;
}
export default function ItemHolder(props: ItemHolderProps) {
const {
prefixCls,
className,
style,
help,
errors,
warnings,
validateStatus,
meta,
hasFeedback,
hidden,
children,
fieldId,
isRequired,
onSubItemMetaChange,
...restProps
} = props;
const itemPrefixCls = `${prefixCls}-item`;
const { requiredMark } = React.useContext(FormContext);
// ======================== Margin ========================
const itemRef = React.useRef<HTMLDivElement>(null);
const debounceErrors = useDebounce(errors);
const debounceWarnings = useDebounce(warnings);
const hasHelp = help !== undefined && help !== null;
const hasError = !!(hasHelp || errors.length || warnings.length);
const [marginBottom, setMarginBottom] = React.useState<number | null>(null);
useLayoutEffect(() => {
if (hasError && itemRef.current) {
const itemStyle = getComputedStyle(itemRef.current);
setMarginBottom(parseInt(itemStyle.marginBottom, 10));
}
}, [hasError]);
const onErrorVisibleChanged = (nextVisible: boolean) => {
if (!nextVisible) {
setMarginBottom(null);
}
};
// ======================== Status ========================
let mergedValidateStatus: ValidateStatus = '';
if (validateStatus !== undefined) {
mergedValidateStatus = validateStatus;
} else if (meta.validating) {
mergedValidateStatus = 'validating';
} else if (debounceErrors.length) {
mergedValidateStatus = 'error';
} else if (debounceWarnings.length) {
mergedValidateStatus = 'warning';
} else if (meta.touched) {
mergedValidateStatus = 'success';
}
const formItemStatusContext = React.useMemo<FormItemStatusContextProps>(() => {
let feedbackIcon: React.ReactNode;
if (hasFeedback) {
const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
feedbackIcon = IconNode ? (
<span
className={classNames(
`${itemPrefixCls}-feedback-icon`,
`${itemPrefixCls}-feedback-icon-${mergedValidateStatus}`,
)}
>
<IconNode />
</span>
) : null;
}
return {
status: mergedValidateStatus,
hasFeedback,
feedbackIcon,
isFormItemInput: true,
};
}, [mergedValidateStatus, hasFeedback]);
// ======================== Render ========================
const itemClassName = {
[itemPrefixCls]: true,
[`${itemPrefixCls}-with-help`]: hasHelp || debounceErrors.length || debounceWarnings.length,
[`${className}`]: !!className,
// Status
[`${itemPrefixCls}-has-feedback`]: mergedValidateStatus && hasFeedback,
[`${itemPrefixCls}-has-success`]: mergedValidateStatus === 'success',
[`${itemPrefixCls}-has-warning`]: mergedValidateStatus === 'warning',
[`${itemPrefixCls}-has-error`]: mergedValidateStatus === 'error',
[`${itemPrefixCls}-is-validating`]: mergedValidateStatus === 'validating',
[`${itemPrefixCls}-hidden`]: hidden,
};
return (
<div className={classNames(itemClassName)} style={style} ref={itemRef}>
<Row
className={`${itemPrefixCls}-row`}
{...omit(restProps, [
'_internalItemRender' as any,
'colon',
'dependencies',
'extra',
'fieldKey',
'getValueFromEvent',
'getValueProps',
'htmlFor',
'id', // It is deprecated because `htmlFor` is its replacement.
'initialValue',
'isListField',
'label',
'labelAlign',
'labelCol',
'labelWrap',
'messageVariables',
'name',
'normalize',
'noStyle',
'preserve',
'required',
'requiredMark',
'rules',
'shouldUpdate',
'trigger',
'tooltip',
'validateFirst',
'validateTrigger',
'valuePropName',
'wrapperCol',
])}
>
{/* Label */}
<FormItemLabel
htmlFor={fieldId}
required={isRequired}
requiredMark={requiredMark}
{...props}
prefixCls={prefixCls}
/>
{/* Input Group */}
<FormItemInput
{...props}
{...meta}
errors={debounceErrors}
warnings={debounceWarnings}
prefixCls={prefixCls}
status={mergedValidateStatus}
help={help}
marginBottom={marginBottom}
onErrorVisibleChanged={onErrorVisibleChanged}
>
<NoStyleItemContext.Provider value={onSubItemMetaChange}>
<FormItemInputContext.Provider value={formItemStatusContext}>
{children}
</FormItemInputContext.Provider>
</NoStyleItemContext.Provider>
</FormItemInput>
</Row>
{!!marginBottom && (
<div
className={`${itemPrefixCls}-margin-offset`}
style={{
marginBottom: -marginBottom,
}}
/>
)}
</div>
);
}

View File

@ -1,34 +1,23 @@
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import classNames from 'classnames';
import type { FormInstance } from 'rc-field-form';
import { Field, FieldContext, ListContext } from 'rc-field-form';
import type { FieldProps } from 'rc-field-form/lib/Field';
import type { Meta, NamePath } from 'rc-field-form/lib/interface';
import useState from 'rc-util/lib/hooks/useState';
import omit from 'rc-util/lib/omit';
import { supportRef } from 'rc-util/lib/ref';
import type { ReactNode } from 'react';
import * as React from 'react';
import { useContext, useMemo } from 'react';
import useFormItemStatus from './hooks/useFormItemStatus';
import { ConfigContext } from '../config-provider';
import Row from '../grid/row';
import { cloneElement, isValidElement } from '../_util/reactNode';
import { tuple } from '../_util/type';
import warning from '../_util/warning';
import type { FormItemStatusContextProps } from './context';
import { FormContext, FormItemInputContext, NoStyleItemContext } from './context';
import type { FormItemInputProps } from './FormItemInput';
import FormItemInput from './FormItemInput';
import type { FormItemLabelProps, LabelTooltipType } from './FormItemLabel';
import FormItemLabel from './FormItemLabel';
import useDebounce from './hooks/useDebounce';
import useFrameState from './hooks/useFrameState';
import useItemRef from './hooks/useItemRef';
import { getFieldId, toArray } from './util';
import { useContext } from 'react';
import useFormItemStatus from '../hooks/useFormItemStatus';
import { ConfigContext } from '../../config-provider';
import { cloneElement, isValidElement } from '../../_util/reactNode';
import { tuple } from '../../_util/type';
import warning from '../../_util/warning';
import { FormContext, NoStyleItemContext } from '../context';
import type { FormItemInputProps } from '../FormItemInput';
import type { FormItemLabelProps, LabelTooltipType } from '../FormItemLabel';
import useFrameState from '../hooks/useFrameState';
import useItemRef from '../hooks/useItemRef';
import { getFieldId, toArray } from '../util';
import ItemHolder from './ItemHolder';
const NAME_SPLIT = '__SPLIT__';
@ -93,26 +82,14 @@ function genEmptyMeta(): Meta {
};
}
const iconMap = {
success: CheckCircleFilled,
warning: ExclamationCircleFilled,
error: CloseCircleFilled,
validating: LoadingOutlined,
};
function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.ReactElement {
const {
name,
noStyle,
dependencies,
prefixCls: customizePrefixCls,
style,
className,
shouldUpdate,
hasFeedback,
help,
rules,
validateStatus,
children,
required,
label,
@ -120,10 +97,9 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
trigger = 'onChange',
validateTrigger,
hidden,
...restProps
} = props;
const { getPrefixCls } = useContext(ConfigContext);
const { name: formName, requiredMark } = useContext(FormContext);
const { name: formName } = useContext(FormContext);
const isRenderProps = typeof children === 'function';
const notifyParentMetaChange = useContext(NoStyleItemContext);
@ -211,50 +187,9 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
return [errorList, warningList];
}, [subFieldErrors, meta.errors, meta.warnings]);
const debounceErrors = useDebounce(mergedErrors);
const debounceWarnings = useDebounce(mergedWarnings);
// ===================== Children Ref =====================
const getItemRef = useItemRef();
// ======================== Status ========================
let mergedValidateStatus: ValidateStatus = '';
if (validateStatus !== undefined) {
mergedValidateStatus = validateStatus;
} else if (meta?.validating) {
mergedValidateStatus = 'validating';
} else if (debounceErrors.length) {
mergedValidateStatus = 'error';
} else if (debounceWarnings.length) {
mergedValidateStatus = 'warning';
} else if (meta?.touched) {
mergedValidateStatus = 'success';
}
const formItemStatusContext = useMemo<FormItemStatusContextProps>(() => {
let feedbackIcon: ReactNode;
if (hasFeedback) {
const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
feedbackIcon = IconNode ? (
<span
className={classNames(
`${prefixCls}-item-feedback-icon`,
`${prefixCls}-item-feedback-icon-${mergedValidateStatus}`,
)}
>
<IconNode />
</span>
) : null;
}
return {
status: mergedValidateStatus,
hasFeedback,
feedbackIcon,
isFormItemInput: true,
};
}, [mergedValidateStatus, hasFeedback]);
// ======================== Render ========================
function renderLayout(
baseChildren: React.ReactNode,
@ -265,75 +200,20 @@ function InternalFormItem<Values = any>(props: FormItemProps<Values>): React.Rea
return baseChildren;
}
const itemClassName = {
[`${prefixCls}-item`]: true,
[`${prefixCls}-item-with-help`]:
(help !== undefined && help !== null) || debounceErrors.length || debounceWarnings.length,
[`${className}`]: !!className,
// Status
[`${prefixCls}-item-has-feedback`]: mergedValidateStatus && hasFeedback,
[`${prefixCls}-item-has-success`]: mergedValidateStatus === 'success',
[`${prefixCls}-item-has-warning`]: mergedValidateStatus === 'warning',
[`${prefixCls}-item-has-error`]: mergedValidateStatus === 'error',
[`${prefixCls}-item-is-validating`]: mergedValidateStatus === 'validating',
[`${prefixCls}-item-hidden`]: hidden,
};
// ======================= Children =======================
return (
<Row
className={classNames(itemClassName)}
style={style}
<ItemHolder
key="row"
{...omit(restProps, [
'colon',
'extra',
'fieldKey',
'requiredMark',
'getValueFromEvent',
'getValueProps',
'htmlFor',
'id', // It is deprecated because `htmlFor` is its replacement.
'initialValue',
'isListField',
'labelAlign',
'labelWrap',
'labelCol',
'normalize',
'preserve',
'tooltip',
'validateFirst',
'valuePropName',
'wrapperCol',
'_internalItemRender' as any,
])}
{...props}
prefixCls={prefixCls}
fieldId={fieldId}
isRequired={isRequired}
errors={mergedErrors}
warnings={mergedWarnings}
meta={meta}
onSubItemMetaChange={onSubItemMetaChange}
>
{/* Label */}
<FormItemLabel
htmlFor={fieldId}
required={isRequired}
requiredMark={requiredMark}
{...props}
prefixCls={prefixCls}
/>
{/* Input Group */}
<FormItemInput
{...props}
{...meta}
errors={debounceErrors}
warnings={debounceWarnings}
prefixCls={prefixCls}
status={mergedValidateStatus}
help={help}
>
<NoStyleItemContext.Provider value={onSubItemMetaChange}>
<FormItemInputContext.Provider value={formItemStatusContext}>
{baseChildren}
</FormItemInputContext.Provider>
</NoStyleItemContext.Provider>
</FormItemInput>
</Row>
{baseChildren}
</ItemHolder>
);
}

View File

@ -11,6 +11,8 @@ interface FormItemInputMiscProps {
children: React.ReactNode;
errors: React.ReactNode[];
warnings: React.ReactNode[];
marginBottom?: number | null;
onErrorVisibleChanged?: (visible: boolean) => void;
/** @private Internal Usage, do not use in any of your production. */
_internalItemRender?: {
mark: string;
@ -18,7 +20,7 @@ interface FormItemInputMiscProps {
props: FormItemInputProps & FormItemInputMiscProps,
domList: {
input: JSX.Element;
errorList: JSX.Element;
errorList: JSX.Element | null;
extra: JSX.Element | null;
},
) => React.ReactNode;
@ -43,6 +45,8 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
_internalItemRender: formItemRender,
extra,
help,
marginBottom,
onErrorVisibleChanged,
} = props;
const baseClassName = `${prefixCls}-item`;
@ -63,17 +67,22 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
</div>
);
const formItemContext = React.useMemo(() => ({ prefixCls, status }), [prefixCls, status]);
const errorListDom = (
<FormItemPrefixContext.Provider value={formItemContext}>
<ErrorList
errors={errors}
warnings={warnings}
help={help}
helpStatus={status}
className={`${baseClassName}-explain-connected`}
/>
</FormItemPrefixContext.Provider>
);
const errorListDom =
marginBottom !== null || errors.length || warnings.length ? (
<div style={{ display: 'flex', flexWrap: 'nowrap' }}>
<FormItemPrefixContext.Provider value={formItemContext}>
<ErrorList
errors={errors}
warnings={warnings}
help={help}
helpStatus={status}
className={`${baseClassName}-explain-connected`}
onVisibleChanged={onErrorVisibleChanged}
/>
</FormItemPrefixContext.Provider>
{!!marginBottom && <div style={{ width: 0, height: marginBottom }} />}
</div>
) : null;
// If extra = 0, && will goes wrong
// 0&&error -> 0

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1303,4 +1303,31 @@ describe('Form', () => {
'custom-input-status-error',
);
});
it('item customize margin', async () => {
const computeSpy = jest.spyOn(window, 'getComputedStyle').mockImplementation(() => ({
marginBottom: 24,
}));
const { container } = render(
<Form>
<Form.Item name="required" initialValue="bamboo" rules={[{ required: true }]}>
<Input />
</Form.Item>
</Form>,
);
fireEvent.change(container.querySelector('input'), {
target: {
value: '',
},
});
await sleep(0);
computeSpy.mockRestore();
expect(container.querySelector('.ant-form-item-margin-offset')).toHaveStyle({
marginBottom: -24,
});
});
});

View File

@ -62,11 +62,8 @@
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;
transition: none;
}
@ -203,9 +200,7 @@
}
&-explain-connected {
height: 0;
min-height: 0;
opacity: 0;
width: 100%;
}
&-extra {
@ -214,7 +209,7 @@
&-with-help &-explain {
height: auto;
min-height: @form-item-margin-bottom;
// min-height: @form-item-margin-bottom;
opacity: 1;
}
@ -249,15 +244,22 @@
// >>>>>>>>>> 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;
transition: opacity @animation-duration-slow @ease-in-out;
&-leave {
min-height: @form-item-margin-bottom;
&-appear,
&-enter {
opacity: 0;
&-active {
min-height: 0;
opacity: 1;
}
}
&-leave {
opacity: 1;
&-active {
opacity: 0;
}
}
}
@ -279,6 +281,11 @@
}
}
&-leave {
transition: height @animation-duration-base @ease-in-out,
opacity @animation-duration-base @ease-in-out, transform @animation-duration-base @ease-in-out !important;
}
&-leave-active {
transform: translateY(-5px);
}

View File

@ -364,22 +364,26 @@ exports[`Input should support size in form 1`] = `
class="ant-form ant-form-horizontal ant-form-large"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<input
class="ant-input ant-input-lg"
type="text"
value=""
/>
<div
class="ant-form-item-control-input-content"
>
<input
class="ant-input ant-input-lg"
type="text"
value=""
/>
</div>
</div>
</div>
</div>

View File

@ -43,107 +43,119 @@ exports[`renders ./components/mentions/demo/form.md extend context correctly 1`]
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class=""
for="coders"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class=""
for="coders"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-mentions"
class="ant-form-item-control-input-content"
>
<textarea
class="rc-textarea"
id="coders"
rows="1"
/>
<div
class="ant-mentions"
>
<textarea
class="rc-textarea"
id="coders"
rows="1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="bio"
title="Bio"
>
Bio
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="bio"
title="Bio"
>
Bio
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-mentions"
class="ant-form-item-control-input-content"
>
<textarea
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"
rows="3"
/>
<div
class="ant-mentions"
>
<textarea
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"
rows="3"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-14 ant-col-offset-6 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-14 ant-col-offset-6 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
<div
class="ant-form-item-control-input-content"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
</div>
</div>
</div>
</div>

View File

@ -43,107 +43,119 @@ exports[`renders ./components/mentions/demo/form.md correctly 1`] = `
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class=""
for="coders"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class=""
for="coders"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-mentions"
class="ant-form-item-control-input-content"
>
<textarea
class="rc-textarea"
id="coders"
rows="1"
/>
<div
class="ant-mentions"
>
<textarea
class="rc-textarea"
id="coders"
rows="1"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="bio"
title="Bio"
>
Bio
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-6 ant-form-item-label"
>
<label
class="ant-form-item-required"
for="bio"
title="Bio"
>
Bio
</label>
</div>
<div
class="ant-col ant-col-16 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-mentions"
class="ant-form-item-control-input-content"
>
<textarea
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"
rows="3"
/>
<div
class="ant-mentions"
>
<textarea
class="rc-textarea"
id="bio"
placeholder="You can use @ to ref user here"
rows="3"
/>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-14 ant-col-offset-6 ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-14 ant-col-offset-6 ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<button
class="ant-btn ant-btn-primary"
type="submit"
<div
class="ant-form-item-control-input-content"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
<button
class="ant-btn ant-btn-primary"
type="submit"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn ant-btn-default"
type="button"
>
<span>
Reset
</span>
</button>
</div>
</div>
</div>
</div>

View File

@ -230,342 +230,362 @@ Array [
style="margin:16px 0"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Active"
>
Active
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<div
class="ant-form-item-control-input-content"
<label
class=""
title="Active"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
Active
</label>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button and Input Block"
>
Button and Input Block
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Size"
>
Size
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="large"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Large
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="small"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Small
</span>
</label>
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button Shape"
>
Button Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button and Input Block"
>
Button and Input Block
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="round"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Round
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Avatar Shape"
>
Avatar Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class=""
title="Size"
>
Size
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
<div
class="ant-radio-group ant-radio-group-outline"
>
<span
class="ant-radio-button"
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="large"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Large
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="small"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Small
</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button Shape"
>
Button Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-radio-group ant-radio-group-outline"
>
<span
class="ant-radio-button ant-radio-button-checked"
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="round"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Round
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Avatar Shape"
>
Avatar Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-radio-group ant-radio-group-outline"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
</div>
</div>
</div>
</div>

View File

@ -230,342 +230,362 @@ Array [
style="margin:16px 0"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Active"
>
Active
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<div
class="ant-form-item-control-input-content"
<label
class=""
title="Active"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
Active
</label>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button and Input Block"
>
Button and Input Block
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
>
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Size"
>
Size
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="large"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Large
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="small"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Small
</span>
</label>
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button Shape"
>
Button Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button and Input Block"
>
Button and Input Block
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
<button
aria-checked="false"
class="ant-switch"
role="switch"
type="button"
>
<div
class="ant-switch-handle"
/>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="round"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Round
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
class="ant-switch-inner"
/>
</button>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Avatar Shape"
>
Avatar Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-form-item-label"
>
<label
class=""
title="Size"
>
Size
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<div
class="ant-radio-group ant-radio-group-outline"
class="ant-form-item-control-input-content"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
<div
class="ant-radio-group ant-radio-group-outline"
>
<span
class="ant-radio-button"
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="large"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Large
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="small"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Small
</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Button Shape"
>
Button Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-radio-group ant-radio-group-outline"
>
<span
class="ant-radio-button ant-radio-button-checked"
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="default"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Default
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="round"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Round
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="ant-form-item"
>
<div
class="ant-row ant-form-item-row"
>
<div
class="ant-col ant-form-item-label"
>
<label
class=""
title="Avatar Shape"
>
Avatar Shape
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input"
>
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-radio-group ant-radio-group-outline"
>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button"
>
<input
class="ant-radio-button-input"
type="radio"
value="square"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Square
</span>
</label>
<label
class="ant-radio-button-wrapper ant-radio-button-wrapper-checked ant-radio-button-wrapper-in-form-item"
>
<span
class="ant-radio-button ant-radio-button-checked"
>
<input
checked=""
class="ant-radio-button-input"
type="radio"
value="circle"
/>
<span
class="ant-radio-button-inner"
/>
</span>
<span>
Circle
</span>
</label>
</div>
</div>
</div>
</div>

File diff suppressed because it is too large Load Diff

View File

@ -3780,77 +3780,81 @@ exports[`renders ./components/upload/demo/upload-with-aliyun-oss.md extend conte
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-4 ant-form-item-label"
>
<label
class=""
for="photos"
title="Photos"
>
Photos
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-4 ant-form-item-label"
>
<label
class=""
for="photos"
title="Photos"
>
Photos
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<span
class=""
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-upload ant-upload-select ant-upload-select-text"
<span
class=""
>
<span
class="ant-upload"
role="button"
tabindex="0"
<div
class="ant-upload ant-upload-select ant-upload-select-text"
>
<input
accept=""
style="display:none"
type="file"
/>
<button
class="ant-btn ant-btn-default"
type="button"
<span
class="ant-upload"
role="button"
tabindex="0"
>
<span
aria-label="upload"
class="anticon anticon-upload"
role="img"
<input
accept=""
style="display:none"
type="file"
/>
<button
class="ant-btn ant-btn-default"
type="button"
>
<svg
aria-hidden="true"
data-icon="upload"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="upload"
class="anticon anticon-upload"
role="img"
>
<path
d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
<span>
Click to Upload
</span>
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
/>
</span>
<svg
aria-hidden="true"
data-icon="upload"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
<span>
Click to Upload
</span>
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
/>
</span>
</div>
</div>
</div>
</div>

View File

@ -3564,77 +3564,81 @@ exports[`renders ./components/upload/demo/upload-with-aliyun-oss.md correctly 1`
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
class="ant-form-item"
>
<div
class="ant-col ant-col-4 ant-form-item-label"
>
<label
class=""
for="photos"
title="Photos"
>
Photos
</label>
</div>
<div
class="ant-col ant-form-item-control"
class="ant-row ant-form-item-row"
>
<div
class="ant-form-item-control-input"
class="ant-col ant-col-4 ant-form-item-label"
>
<label
class=""
for="photos"
title="Photos"
>
Photos
</label>
</div>
<div
class="ant-col ant-form-item-control"
>
<div
class="ant-form-item-control-input-content"
class="ant-form-item-control-input"
>
<span
class=""
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-upload ant-upload-select ant-upload-select-text"
<span
class=""
>
<span
class="ant-upload"
role="button"
tabindex="0"
<div
class="ant-upload ant-upload-select ant-upload-select-text"
>
<input
accept=""
style="display:none"
type="file"
/>
<button
class="ant-btn ant-btn-default"
type="button"
<span
class="ant-upload"
role="button"
tabindex="0"
>
<span
aria-label="upload"
class="anticon anticon-upload"
role="img"
<input
accept=""
style="display:none"
type="file"
/>
<button
class="ant-btn ant-btn-default"
type="button"
>
<svg
aria-hidden="true"
data-icon="upload"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
aria-label="upload"
class="anticon anticon-upload"
role="img"
>
<path
d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
<span>
Click to Upload
</span>
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
/>
</span>
<svg
aria-hidden="true"
data-icon="upload"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M400 317.7h73.9V656c0 4.4 3.6 8 8 8h60c4.4 0 8-3.6 8-8V317.7H624c6.7 0 10.4-7.7 6.3-12.9L518.3 163a8 8 0 00-12.6 0l-112 141.7c-4.1 5.3-.4 13 6.3 13zM878 626h-60c-4.4 0-8 3.6-8 8v154H214V634c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8v198c0 17.7 14.3 32 32 32h684c17.7 0 32-14.3 32-32V634c0-4.4-3.6-8-8-8z"
/>
</svg>
</span>
<span>
Click to Upload
</span>
</button>
</span>
</div>
<div
class="ant-upload-list ant-upload-list-text"
/>
</span>
</div>
</div>
</div>
</div>

View File

@ -135,7 +135,7 @@
"rc-input-number": "~7.3.0",
"rc-mentions": "~1.9.0",
"rc-menu": "~9.6.0",
"rc-motion": "^2.5.1",
"rc-motion": "^2.6.1",
"rc-notification": "~4.6.0",
"rc-pagination": "~3.1.17",
"rc-picker": "~2.6.10",