feat: Form.List support rules (#26676)

* Add ErrorList component

* move class to ErrorList

* support cache of status

* update doc

* update snapshot

* patch test case

* clean up

* docs: add faq
This commit is contained in:
二货机器人 2020-09-11 21:27:51 +08:00 committed by GitHub
parent faa534c1c0
commit 1faabb219d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 312 additions and 113 deletions

View File

@ -14190,7 +14190,7 @@ exports[`ConfigProvider components Form configProvider 1`] = `
</div>
</div>
<div
class="config-form-item-explain"
class="config-form-item-explain config-form-item-explain-error"
>
<div
role="alert"
@ -14227,7 +14227,7 @@ exports[`ConfigProvider components Form configProvider componentSize large 1`] =
</div>
</div>
<div
class="config-form-item-explain"
class="config-form-item-explain config-form-item-explain-error"
>
<div
role="alert"
@ -14264,7 +14264,7 @@ exports[`ConfigProvider components Form configProvider componentSize middle 1`]
</div>
</div>
<div
class="config-form-item-explain"
class="config-form-item-explain config-form-item-explain-error"
>
<div
role="alert"
@ -14301,7 +14301,7 @@ exports[`ConfigProvider components Form configProvider virtual and dropdownMatch
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -14338,7 +14338,7 @@ exports[`ConfigProvider components Form normal 1`] = `
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -14375,7 +14375,7 @@ exports[`ConfigProvider components Form prefixCls 1`] = `
</div>
</div>
<div
class="prefix-Form-item-explain"
class="prefix-Form-item-explain prefix-Form-item-explain-error"
>
<div
role="alert"

View File

@ -0,0 +1,95 @@
import * as React from 'react';
import classNames from 'classnames';
import CSSMotion from 'rc-motion';
import useMemo from 'rc-util/lib/hooks/useMemo';
import useCacheErrors from './hooks/useCacheErrors';
import useForceUpdate from '../_util/hooks/useForceUpdate';
import { FormItemPrefixContext } from './context';
const EMPTY_LIST: React.ReactNode[] = [];
export interface ErrorListProps {
errors?: React.ReactNode[];
/** @private Internal usage. Do not use in your production */
help?: React.ReactNode;
/** @private Internal usage. Do not use in your production */
onDomErrorVisibleChange?: (visible: boolean) => void;
}
export default function ErrorList({
errors = EMPTY_LIST,
help,
onDomErrorVisibleChange,
}: ErrorListProps) {
const forceUpdate = useForceUpdate();
const { prefixCls, status } = React.useContext(FormItemPrefixContext);
const [visible, cacheErrors] = useCacheErrors(
errors,
changedVisible => {
if (changedVisible) {
/**
* We trigger in sync to avoid dom shaking but this get warning in react 16.13.
* So use Promise to keep in micro async to handle this.
* https://github.com/ant-design/ant-design/issues/21698#issuecomment-593743485
*/
Promise.resolve().then(() => {
onDomErrorVisibleChange?.(true);
});
}
forceUpdate();
},
!!help,
);
const memoErrors = useMemo(
() => cacheErrors,
visible,
(_, nextVisible) => nextVisible,
);
// Memo status in same visible
const [innerStatus, setInnerStatus] = React.useState(status);
React.useEffect(() => {
if (visible && status) {
setInnerStatus(status);
}
}, [visible, status]);
const baseClassName = `${prefixCls}-item-explain`;
return (
<CSSMotion
motionDeadline={500}
visible={visible}
motionName="show-help"
onLeaveEnd={() => {
onDomErrorVisibleChange?.(false);
}}
motionAppear
removeOnLeave
>
{({ className: motionClassName }: { className: string }) => {
return (
<div
className={classNames(
baseClassName,
{
[`${baseClassName}-${innerStatus}`]: innerStatus,
},
motionClassName,
)}
key="help"
>
{memoErrors.map((error, index) => (
// eslint-disable-next-line react/no-array-index-key
<div key={index} role="alert">
{error}
</div>
))}
</div>
);
}}
</CSSMotion>
);
}

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import { useContext, useRef } from 'react';
import isEqual from 'lodash/isEqual';
import classNames from 'classnames';
import { Field, FormInstance } from 'rc-field-form';
@ -86,15 +87,14 @@ function FormItem(props: FormItemProps): React.ReactElement {
hidden,
...restProps
} = props;
const destroyRef = React.useRef(false);
const { getPrefixCls } = React.useContext(ConfigContext);
const { name: formName, requiredMark } = React.useContext(FormContext);
const { updateItemErrors } = React.useContext(FormItemContext);
const destroyRef = useRef(false);
const { getPrefixCls } = useContext(ConfigContext);
const { name: formName, requiredMark } = useContext(FormContext);
const { updateItemErrors } = useContext(FormItemContext);
const [domErrorVisible, innerSetDomErrorVisible] = React.useState(!!help);
const prevValidateStatusRef = React.useRef<ValidateStatus | undefined>(validateStatus);
const [inlineErrors, setInlineErrors] = useFrameState<Record<string, string[]>>({});
const { validateTrigger: contextValidateTrigger } = React.useContext(FieldContext);
const { validateTrigger: contextValidateTrigger } = useContext(FieldContext);
const mergedValidateTrigger =
validateTrigger !== undefined ? validateTrigger : contextValidateTrigger;
@ -107,7 +107,7 @@ function FormItem(props: FormItemProps): React.ReactElement {
const hasName = hasValidName(name);
// Cache Field NamePath
const nameRef = React.useRef<(string | number)[]>([]);
const nameRef = useRef<(string | number)[]>([]);
// Should clean up if Field removed
React.useEffect(() => {
@ -176,10 +176,6 @@ function FormItem(props: FormItemProps): React.ReactElement {
mergedValidateStatus = 'success';
}
if (domErrorVisible && help) {
prevValidateStatusRef.current = mergedValidateStatus;
}
const itemClassName = {
[`${prefixCls}-item`]: true,
[`${prefixCls}-item-with-help`]: domErrorVisible || help,
@ -190,8 +186,6 @@ function FormItem(props: FormItemProps): React.ReactElement {
[`${prefixCls}-item-has-success`]: mergedValidateStatus === 'success',
[`${prefixCls}-item-has-warning`]: mergedValidateStatus === 'warning',
[`${prefixCls}-item-has-error`]: mergedValidateStatus === 'error',
[`${prefixCls}-item-has-error-leave`]:
!help && domErrorVisible && prevValidateStatusRef.current === 'error',
[`${prefixCls}-item-is-validating`]: mergedValidateStatus === 'validating',
[`${prefixCls}-item-hidden`]: hidden,
};
@ -239,6 +233,7 @@ function FormItem(props: FormItemProps): React.ReactElement {
{...meta}
errors={mergedErrors}
prefixCls={prefixCls}
status={mergedValidateStatus}
onDomErrorVisibleChange={setDomErrorVisible}
validateStatus={mergedValidateStatus}
>
@ -253,7 +248,7 @@ function FormItem(props: FormItemProps): React.ReactElement {
const isRenderProps = typeof children === 'function';
// Record for real component render
const updateRef = React.useRef(0);
const updateRef = useRef(0);
updateRef.current += 1;
if (!hasName && !isRenderProps && !dependencies) {

View File

@ -4,14 +4,11 @@ import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import useMemo from 'rc-util/lib/hooks/useMemo';
import CSSMotion from 'rc-motion';
import Col, { ColProps } from '../grid/col';
import { ValidateStatus } from './FormItem';
import { FormContext } from './context';
import useCacheErrors from './hooks/useCacheErrors';
import useForceUpdate from '../_util/hooks/useForceUpdate';
import { FormContext, FormItemPrefixContext } from './context';
import ErrorList from './ErrorList';
interface FormItemInputMiscProps {
prefixCls: string;
@ -26,6 +23,7 @@ export interface FormItemInputProps {
wrapperCol?: ColProps;
help?: React.ReactNode;
extra?: React.ReactNode;
status?: ValidateStatus;
}
const iconMap: { [key: string]: any } = {
@ -37,6 +35,7 @@ const iconMap: { [key: string]: any } = {
const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = ({
prefixCls,
status,
wrapperCol,
children,
help,
@ -46,8 +45,6 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = ({
validateStatus,
extra,
}) => {
const forceUpdate = useForceUpdate();
const baseClassName = `${prefixCls}-item`;
const formContext = React.useContext(FormContext);
@ -56,24 +53,6 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = ({
const className = classNames(`${baseClassName}-control`, mergedWrapperCol.className);
const [visible, cacheErrors] = useCacheErrors(
errors,
changedVisible => {
if (changedVisible) {
/**
* We trigger in sync to avoid dom shaking but this get warning in react 16.13.
* So use Promise to keep in micro async to handle this.
* https://github.com/ant-design/ant-design/issues/21698#issuecomment-593743485
*/
Promise.resolve().then(() => {
onDomErrorVisibleChange(true);
});
}
forceUpdate();
},
!!help,
);
React.useEffect(
() => () => {
onDomErrorVisibleChange(false);
@ -81,12 +60,6 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = ({
[],
);
const memoErrors = useMemo(
() => cacheErrors,
visible,
(_, nextVisible) => nextVisible,
);
// Should provides additional icon if `hasFeedback`
const IconNode = validateStatus && iconMap[validateStatus];
const icon =
@ -108,29 +81,13 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = ({
<div className={`${baseClassName}-control-input-content`}>{children}</div>
{icon}
</div>
<CSSMotion
motionDeadline={500}
visible={visible}
motionName="show-help"
onLeaveEnd={() => {
onDomErrorVisibleChange(false);
}}
motionAppear
removeOnLeave
>
{({ className: motionClassName }: { className: string }) => {
return (
<div className={classNames(`${baseClassName}-explain`, motionClassName)} key="help">
{memoErrors.map((error, index) => (
// eslint-disable-next-line react/no-array-index-key
<div key={index} role="alert">
{error}
</div>
))}
</div>
);
}}
</CSSMotion>
<FormItemPrefixContext.Provider value={{ prefixCls, status }}>
<ErrorList
errors={errors}
help={help}
onDomErrorVisibleChange={onDomErrorVisibleChange}
/>
</FormItemPrefixContext.Provider>
{extra && <div className={`${baseClassName}-extra`}>{extra}</div>}
</Col>
</FormContext.Provider>

View File

@ -2,6 +2,8 @@ import * as React from 'react';
import { List } from 'rc-field-form';
import { StoreValue } from 'rc-field-form/lib/interface';
import devWarning from '../_util/devWarning';
import { ConfigContext } from '../config-provider';
import { FormItemPrefixContext } from './context';
export interface FormListFieldData {
name: number;
@ -16,19 +18,38 @@ export interface FormListOperation {
}
export interface FormListProps {
prefixCls?: string;
name: string | number | (string | number)[];
children: (fields: FormListFieldData[], operation: FormListOperation) => React.ReactNode;
children: (
fields: FormListFieldData[],
operation: FormListOperation,
meta: { errors: React.ReactNode[] },
) => React.ReactNode;
}
const FormList: React.FC<FormListProps> = ({ children, ...props }) => {
const FormList: React.FC<FormListProps> = ({
prefixCls: customizePrefixCls,
children,
...props
}) => {
devWarning(!!props.name, 'Form.List', 'Miss `name` prop.');
const { getPrefixCls } = React.useContext(ConfigContext);
const prefixCls = getPrefixCls('form', customizePrefixCls);
return (
<List {...props}>
{(fields, operation) => {
return children(
fields.map(field => ({ ...field, fieldKey: field.key })),
operation,
{(fields, operation, meta) => {
return (
<FormItemPrefixContext.Provider value={{ prefixCls, status: 'error' }}>
{children(
fields.map(field => ({ ...field, fieldKey: field.key })),
operation,
{
errors: meta.errors,
},
)}
</FormItemPrefixContext.Provider>
);
}}
</List>

View File

@ -1078,7 +1078,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -1120,7 +1120,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -1193,7 +1193,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -1235,7 +1235,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -1334,7 +1334,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -1389,7 +1389,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -1480,7 +1480,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -1531,7 +1531,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -6229,7 +6229,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -6356,7 +6356,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</span>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-validating"
>
<div
role="alert"
@ -6536,7 +6536,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</span>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"
@ -6924,7 +6924,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</span>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-validating"
>
<div
role="alert"
@ -7013,7 +7013,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
</div>
</div>
<div
class="ant-form-item-explain"
class="ant-form-item-explain ant-form-item-explain-error"
>
<div
role="alert"

View File

@ -164,4 +164,76 @@ describe('Form.List', () => {
await sleep();
expect(onFinish).toHaveBeenLastCalledWith({ list: ['input2', 'input3'] });
});
it('list errors', async () => {
jest.useFakeTimers();
let operation;
const wrapper = mount(
<Form>
<Form.List
name="list"
rules={[
{
validator: async (_, value) => {
if (value.length < 2) {
return Promise.reject(new Error('At least 2'));
}
},
},
]}
>
{(_, opt, { errors }) => {
operation = opt;
return <Form.ErrorList errors={errors} />;
}}
</Form.List>
</Form>,
);
async function addItem() {
await act(async () => {
operation.add();
await sleep();
jest.runAllTimers();
wrapper.update();
});
}
await addItem();
expect(wrapper.find('.ant-form-item-explain div').text()).toEqual('At least 2');
await addItem();
expect(wrapper.find('.ant-form-item-explain div')).toHaveLength(0);
jest.useRealTimers();
});
describe('ErrorList component', () => {
it('should trigger onDomErrorVisibleChange by motion end', async () => {
jest.useFakeTimers();
const onDomErrorVisibleChange = jest.fn();
const wrapper = mount(
<Form.ErrorList
errors={['bamboo is light']}
onDomErrorVisibleChange={onDomErrorVisibleChange}
/>,
);
await act(async () => {
await sleep();
jest.runAllTimers();
wrapper.update();
});
act(() => {
wrapper.find('CSSMotion').props().onLeaveEnd();
});
expect(onDomErrorVisibleChange).toHaveBeenCalledWith(false);
jest.useRealTimers();
});
});
});

View File

@ -5,6 +5,7 @@ import { FormProviderProps as RcFormProviderProps } from 'rc-field-form/lib/Form
import { ColProps } from '../grid/col';
import { FormLabelAlign } from './interface';
import { RequiredMark } from './Form';
import { ValidateStatus } from './FormItem';
/**
* Form Context
@ -49,3 +50,15 @@ export const FormProvider: React.FC<FormProviderProps> = props => {
const providerProps = omit(props, ['prefixCls']);
return <RcFormProvider {...providerProps} />;
};
/**
* Used for ErrorList only
*/
export interface FormItemPrefixContextProps {
prefixCls: string;
status?: ValidateStatus;
}
export const FormItemPrefixContext = React.createContext<FormItemPrefixContextProps>({
prefixCls: '',
});

View File

@ -41,8 +41,19 @@ const DynamicFieldSet = () => {
return (
<Form name="dynamic_form_item" {...formItemLayoutWithOutLabel} onFinish={onFinish}>
<Form.List name="names">
{(fields, { add, remove }) => {
<Form.List
name="names"
rules={[
{
validator: async (_, names) => {
if (!names || names.length < 2) {
return Promise.reject(new Error('At least 2 passengers'));
}
},
},
]}
>
{(fields, { add, remove }, { errors }) => {
return (
<div>
{fields.map((field, index) => (
@ -96,6 +107,8 @@ const DynamicFieldSet = () => {
>
<PlusOutlined /> Add field at head
</Button>
<Form.ErrorList errors={errors} />
</Form.Item>
</div>
);

View File

@ -165,10 +165,11 @@ You can modify the default verification information of Form.Item through `messag
Provides array management for fields.
| Property | Description | Type | Default |
| --- | --- | --- | --- |
| name | Field name, support array | [NamePath](#NamePath) | - |
| children | Render function | (fields: Field[], operation: { add, remove, move }) => React.ReactNode | - |
| Property | Description | Type | Default | Version |
| --- | --- | --- | --- | --- |
| name | Field name, support array | [NamePath](#NamePath) | - | |
| children | Render function | (fields: Field[], operation: { add, remove, move }) => React.ReactNode | - | |
| rules | Validate rules, only support customize validator. Should work with [ErrorList](#Form.ErrorList) | { validator, message }[] | - | 4.7.0 |
```tsx
<Form.List>
@ -194,6 +195,14 @@ Some operator functions in render form of Form.List.
| remove | remove form item | (index: number \| number[]) => void | number[]: 4.5.0 |
| move | move form item | (from: number, to: number) => void | - |
## Form.ErrorList
New in 4.7.0. Show error messages, should only work with `rules` of Form.List.
| Property | Description | Type | Default |
| -------- | ----------- | ----------- | ------- |
| errors | Error list | ReactNode[] | - |
## Form.Provider
Provide linkage between forms. If a sub form with `name` prop update, it will auto trigger Provider related events. See [example](#components-form-demo-form-context).
@ -379,6 +388,10 @@ Validating is also part of the value updating. It pass follow steps:
In each `onFieldsChange`, you will get `false` > `true` > `false` with `isFieldValidating`.
### Why Form.List do not support `label` and need ErrorList to show errors?
Form.List use renderProps which mean internal structure is flexible. Thus `label` and `error` can not have best place. If you want to use antd `label`, you can wrap with Form.Item instead.
<style>
.site-form-item-icon {
color: rgba(0, 0, 0, 0.25);

View File

@ -1,6 +1,7 @@
import { Rule, RuleObject, RuleRender } from 'rc-field-form/lib/interface';
import InternalForm, { useForm, FormInstance, FormProps } from './Form';
import Item, { FormItemProps } from './FormItem';
import ErrorList, { ErrorListProps } from './ErrorList';
import List from './FormList';
import { FormProvider } from './context';
import devWarning from '../_util/devWarning';
@ -10,6 +11,7 @@ interface Form extends InternalForm {
useForm: typeof useForm;
Item: typeof Item;
List: typeof List;
ErrorList: typeof ErrorList;
Provider: typeof FormProvider;
/** @deprecated Only for warning usage. Do not use. */
@ -20,6 +22,7 @@ const Form: Form = InternalForm as Form;
Form.Item = Item;
Form.List = List;
Form.ErrorList = ErrorList;
Form.useForm = useForm;
Form.Provider = FormProvider;
Form.create = () => {
@ -30,6 +33,6 @@ Form.create = () => {
);
};
export { FormInstance, FormProps, FormItemProps, Rule, RuleObject, RuleRender };
export { FormInstance, FormProps, FormItemProps, ErrorListProps, Rule, RuleObject, RuleRender };
export default Form;

View File

@ -166,10 +166,11 @@ Form 通过增量更新方式,只更新被修改的字段相关组件以达到
为字段提供数组化管理。
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| name | 字段名,支持数组 | [NamePath](#NamePath) | - |
| children | 渲染函数 | (fields: Field[], operation: { add, remove, move }) => React.ReactNode | - |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| name | 字段名,支持数组 | [NamePath](#NamePath) | - | |
| children | 渲染函数 | (fields: Field[], operation: { add, remove, move }) => React.ReactNode | - | |
| rules | 校验规则,仅支持自定义规则。需要配合 [ErrorList](#Form.ErrorList) 一同使用。 | { validator, message }[] | - | 4.7.0 |
```tsx
<Form.List>
@ -196,6 +197,14 @@ Form.List 渲染表单相关操作函数。
| remove | 删除表单项 | (index: number \| number[]) => void | number[]: 4.5.0 |
| move | 移动表单项 | (from: number, to: number) => void | - |
## Form.ErrorList
4.7.0 新增。错误展示组件,仅限配合 Form.List 的 rules 一同使用。
| 参数 | 说明 | 类型 | 默认值 |
| ------ | -------- | ----------- | ------ |
| errors | 错误列表 | ReactNode[] | - |
## Form.Provider
提供表单间联动功能,其下设置 `name` 的 Form 更新时,会自动触发对应事件。查看[示例](#components-form-demo-form-context)。
@ -381,6 +390,10 @@ validator(rule, value, callback) => {
在触发过程中,调用 `isFieldValidating` 会经历 `false` > `true` > `false` 的变化过程。
### 为什么 Form.List 不支持 `label` 还需要使用 ErrorList 展示错误?
Form.List 本身是 renderProps内部样式非常自由。因而默认配置 `label``error` 节点很难与之配合。如果你需要 antd 样式的 `label`,可以通过外部包裹 Form.Item 来实现。
<style>
.site-form-item-icon {
color: rgba(0, 0, 0, 0.25);

View File

@ -1,7 +1,6 @@
@import '../../input/style/mixin';
.form-control-validation(@text-color: @input-color; @border-color: @input-border-color; @background-color: @input-bg) {
.@{ant-prefix}-form-item-explain,
.@{ant-prefix}-form-item-split {
color: @text-color;
}

View File

@ -6,6 +6,18 @@
// ================================================================
/* 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 {
color: @error-color;
}
&&-warning {
color: @warning-color;
}
}
&-has-feedback {
// ========================= Input =========================
.@{ant-prefix}-input {
@ -234,13 +246,6 @@
}
}
// Patch to keep error explain color
&-has-error-leave {
.@{form-item-prefix-cls}-explain {
color: @error-color;
}
}
// ====================== Validating =======================
&-is-validating {
&.@{form-item-prefix-cls}-has-feedback .@{form-item-prefix-cls}-children-icon {

View File

@ -124,7 +124,7 @@
"rc-dialog": "~8.3.0",
"rc-drawer": "~4.1.0",
"rc-dropdown": "~3.1.2",
"rc-field-form": "~1.10.0",
"rc-field-form": "~1.11.0",
"rc-image": "~3.0.6",
"rc-input-number": "~6.0.0",
"rc-mentions": "~1.4.0",