mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 11:10:01 +08:00
feat: Input support status (#33995)
* feat: remove form status style && input support status * test: update snapshot * feat: update status prop in config provider * fix: form item validateStatus support * chore: code clean * feat: status classname change * test: update snapshot * refactor: move formItemStatusContext to form folder * refactor: merge utils * refactor: rename statusUtils * chore: code clean * test: fix coverage * chore: remove status prop of Form.Item * chore: code clean * docs: update demo * test: fix lint * feat: status only success and warning * test: fix lint * docs: update deamo
This commit is contained in:
parent
2843bd32dd
commit
37e042358d
41
components/_util/statusUtils.tsx
Normal file
41
components/_util/statusUtils.tsx
Normal file
@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import CheckCircleFilled from '@ant-design/icons/CheckCircleFilled';
|
||||
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
|
||||
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
|
||||
import LoadingOutlined from '@ant-design/icons/LoadingOutlined';
|
||||
import classNames from 'classnames';
|
||||
import { ValidateStatus } from '../form/FormItem';
|
||||
import { tuple } from './type';
|
||||
|
||||
const InputStatuses = tuple('warning', 'error', '');
|
||||
export type InputStatus = typeof InputStatuses[number];
|
||||
|
||||
const iconMap = {
|
||||
success: CheckCircleFilled,
|
||||
warning: ExclamationCircleFilled,
|
||||
error: CloseCircleFilled,
|
||||
validating: LoadingOutlined,
|
||||
};
|
||||
|
||||
export const getFeedbackIcon = (prefixCls: string, status?: ValidateStatus) => {
|
||||
const IconNode = status && iconMap[status];
|
||||
return IconNode ? (
|
||||
<span className={`${prefixCls}-feedback-icon`}>
|
||||
<IconNode />
|
||||
</span>
|
||||
) : null;
|
||||
};
|
||||
|
||||
export function getStatusClassNames(
|
||||
prefixCls: string,
|
||||
status?: ValidateStatus,
|
||||
hasFeedback?: boolean,
|
||||
) {
|
||||
return classNames({
|
||||
[`${prefixCls}-status-success`]: status === 'success',
|
||||
[`${prefixCls}-status-warning`]: status === 'warning',
|
||||
[`${prefixCls}-status-error`]: status === 'error',
|
||||
[`${prefixCls}-status-validating`]: status === 'validating',
|
||||
[`${prefixCls}-has-feedback`]: hasFeedback,
|
||||
});
|
||||
}
|
@ -13367,7 +13367,7 @@ exports[`ConfigProvider components Form configProvider 1`] = `
|
||||
class="config-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="config-input"
|
||||
class="config-input config-input-status-error"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
@ -13405,7 +13405,7 @@ exports[`ConfigProvider components Form configProvider componentSize large 1`] =
|
||||
class="config-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="config-input config-input-lg"
|
||||
class="config-input config-input-lg config-input-status-error"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
@ -13443,7 +13443,7 @@ exports[`ConfigProvider components Form configProvider componentSize middle 1`]
|
||||
class="config-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="config-input"
|
||||
class="config-input config-input-status-error"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
@ -13481,7 +13481,7 @@ exports[`ConfigProvider components Form configProvider virtual and dropdownMatch
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
class="ant-input ant-input-status-error"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
@ -13519,7 +13519,7 @@ exports[`ConfigProvider components Form normal 1`] = `
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
class="ant-input ant-input-status-error"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
@ -13557,7 +13557,7 @@ exports[`ConfigProvider components Form prefixCls 1`] = `
|
||||
class="prefix-Form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="prefix-Form"
|
||||
class="prefix-Form prefix-Form-status-error"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { useContext } from 'react';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Field, FormInstance, FieldContext, ListContext } from 'rc-field-form';
|
||||
import { FieldProps } from 'rc-field-form/lib/Field';
|
||||
@ -12,7 +12,12 @@ import { tuple } from '../_util/type';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import FormItemLabel, { FormItemLabelProps, LabelTooltipType } from './FormItemLabel';
|
||||
import FormItemInput, { FormItemInputProps } from './FormItemInput';
|
||||
import { FormContext, NoStyleItemContext } from './context';
|
||||
import {
|
||||
FormContext,
|
||||
FormItemStatusContext,
|
||||
NoStyleItemContext,
|
||||
FormItemStatusContextProps,
|
||||
} from './context';
|
||||
import { toArray, getFieldId } from './util';
|
||||
import { cloneElement, isValidElement } from '../_util/reactNode';
|
||||
import useFrameState from './hooks/useFrameState';
|
||||
@ -199,6 +204,28 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
|
||||
// ===================== 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>(
|
||||
() => ({
|
||||
status: mergedValidateStatus,
|
||||
hasFeedback,
|
||||
}),
|
||||
[mergedValidateStatus, hasFeedback],
|
||||
);
|
||||
|
||||
// ======================== Render ========================
|
||||
function renderLayout(
|
||||
baseChildren: React.ReactNode,
|
||||
@ -208,19 +235,6 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
|
||||
if (noStyle && !hidden) {
|
||||
return baseChildren;
|
||||
}
|
||||
// ======================== 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 itemClassName = {
|
||||
[`${prefixCls}-item`]: true,
|
||||
@ -281,11 +295,12 @@ function FormItem<Values = any>(props: FormItemProps<Values>): React.ReactElemen
|
||||
warnings={debounceWarnings}
|
||||
prefixCls={prefixCls}
|
||||
status={mergedValidateStatus}
|
||||
validateStatus={mergedValidateStatus}
|
||||
help={help}
|
||||
>
|
||||
<NoStyleItemContext.Provider value={onSubItemMetaChange}>
|
||||
{baseChildren}
|
||||
<FormItemStatusContext.Provider value={formItemStatusContext}>
|
||||
{baseChildren}
|
||||
</FormItemStatusContext.Provider>
|
||||
</NoStyleItemContext.Provider>
|
||||
</FormItemInput>
|
||||
</Row>
|
||||
|
@ -1,10 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
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 Col, { ColProps } from '../grid/col';
|
||||
import { ValidateStatus } from './FormItem';
|
||||
import { FormContext, FormItemPrefixContext } from './context';
|
||||
@ -15,8 +10,6 @@ interface FormItemInputMiscProps {
|
||||
children: React.ReactNode;
|
||||
errors: React.ReactNode[];
|
||||
warnings: React.ReactNode[];
|
||||
hasFeedback?: boolean;
|
||||
validateStatus?: ValidateStatus;
|
||||
/** @private Internal Usage, do not use in any of your production. */
|
||||
_internalItemRender?: {
|
||||
mark: string;
|
||||
@ -38,13 +31,6 @@ export interface FormItemInputProps {
|
||||
help?: React.ReactNode;
|
||||
}
|
||||
|
||||
const iconMap: { [key: string]: any } = {
|
||||
success: CheckCircleFilled,
|
||||
warning: ExclamationCircleFilled,
|
||||
error: CloseCircleFilled,
|
||||
validating: LoadingOutlined,
|
||||
};
|
||||
|
||||
const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = props => {
|
||||
const {
|
||||
prefixCls,
|
||||
@ -53,9 +39,7 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
|
||||
children,
|
||||
errors,
|
||||
warnings,
|
||||
hasFeedback,
|
||||
_internalItemRender: formItemRender,
|
||||
validateStatus,
|
||||
extra,
|
||||
help,
|
||||
} = props;
|
||||
@ -67,15 +51,6 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
|
||||
|
||||
const className = classNames(`${baseClassName}-control`, mergedWrapperCol.className);
|
||||
|
||||
// Should provides additional icon if `hasFeedback`
|
||||
const IconNode = validateStatus && iconMap[validateStatus];
|
||||
const icon =
|
||||
hasFeedback && IconNode ? (
|
||||
<span className={`${baseClassName}-children-icon`}>
|
||||
<IconNode />
|
||||
</span>
|
||||
) : null;
|
||||
|
||||
// Pass to sub FormItem should not with col info
|
||||
const subFormContext = React.useMemo(() => ({ ...formContext }), [formContext]);
|
||||
delete subFormContext.labelCol;
|
||||
@ -84,7 +59,6 @@ const FormItemInput: React.FC<FormItemInputProps & FormItemInputMiscProps> = pro
|
||||
const inputDom = (
|
||||
<div className={`${baseClassName}-control-input`}>
|
||||
<div className={`${baseClassName}-control-input-content`}>{children}</div>
|
||||
{icon}
|
||||
</div>
|
||||
);
|
||||
const formItemContext = React.useMemo(() => ({ prefixCls, status }), [prefixCls, status]);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1197,7 +1197,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
class="ant-input ant-input-status-error"
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
value="Buggy!"
|
||||
@ -1239,7 +1239,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-disabled"
|
||||
class="ant-input ant-input-disabled ant-input-status-error"
|
||||
disabled=""
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
@ -1314,7 +1314,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
class="ant-input ant-input-status-error"
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
value="Buggy!"
|
||||
@ -1356,7 +1356,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-disabled"
|
||||
class="ant-input ant-input-disabled ant-input-status-error"
|
||||
disabled=""
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
@ -1444,7 +1444,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper"
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-status-error"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -1455,7 +1455,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
Buggy!
|
||||
</span>
|
||||
<input
|
||||
class="ant-input"
|
||||
class="ant-input ant-input-status-error"
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
value=""
|
||||
@ -1499,7 +1499,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper"
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-status-error"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -1510,7 +1510,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
Buggy!
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-disabled"
|
||||
class="ant-input ant-input-disabled ant-input-status-error"
|
||||
disabled=""
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
@ -1596,7 +1596,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper"
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-error"
|
||||
>
|
||||
<span
|
||||
class="ant-input-prefix"
|
||||
@ -1647,7 +1647,7 @@ exports[`renders ./components/form/demo/disabled-input-debug.md correctly 1`] =
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-disabled"
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-disabled ant-input-affix-wrapper-status-error"
|
||||
>
|
||||
<span
|
||||
class="ant-input-prefix"
|
||||
@ -3630,7 +3630,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-password"
|
||||
class="ant-input-affix-wrapper ant-input-password ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
@ -3695,7 +3695,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-password"
|
||||
class="ant-input-affix-wrapper ant-input-password ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
@ -7229,7 +7229,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
class="ant-input ant-input-status-error"
|
||||
id="error"
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
@ -7272,7 +7272,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper"
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-warning"
|
||||
>
|
||||
<span
|
||||
class="ant-input-prefix"
|
||||
@ -7330,38 +7330,46 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
id="validating"
|
||||
placeholder="I'm the content is being validated"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="loading"
|
||||
class="anticon anticon-loading anticon-spin"
|
||||
role="img"
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-validating ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="loading"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="0 0 1024 1024"
|
||||
width="1em"
|
||||
<input
|
||||
class="ant-input"
|
||||
id="validating"
|
||||
placeholder="I'm the content is being validated"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<path
|
||||
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="loading"
|
||||
class="anticon anticon-loading anticon-spin"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="loading"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="0 0 1024 1024"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
@ -7396,38 +7404,46 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
id="success"
|
||||
placeholder="I'm the content"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="check-circle"
|
||||
class="anticon anticon-check-circle"
|
||||
role="img"
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-success ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="check-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<input
|
||||
class="ant-input"
|
||||
id="success"
|
||||
placeholder="I'm the content"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="check-circle"
|
||||
class="anticon anticon-check-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="check-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -7452,38 +7468,46 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
id="warning2"
|
||||
placeholder="Warning"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle"
|
||||
role="img"
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-warning ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<input
|
||||
class="ant-input"
|
||||
id="warning2"
|
||||
placeholder="Warning"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -7508,38 +7532,46 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
id="error2"
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-error ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
<input
|
||||
class="ant-input"
|
||||
id="error2"
|
||||
placeholder="unavailable choice"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
@ -7616,29 +7648,6 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="check-circle"
|
||||
class="anticon anticon-check-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="check-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -7708,29 +7717,6 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -7783,7 +7769,9 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
>
|
||||
I'm Select
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@ -7813,29 +7801,6 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -7887,7 +7852,9 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
/>
|
||||
>
|
||||
I'm Cascader
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@ -7917,29 +7884,6 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="loading"
|
||||
class="anticon anticon-loading anticon-spin"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="loading"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="0 0 1024 1024"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M988 548c-19.9 0-36-16.1-36-36 0-59.4-11.6-117-34.6-171.3a440.45 440.45 0 00-94.3-139.9 437.71 437.71 0 00-139.9-94.3C629 83.6 571.4 72 512 72c-19.9 0-36-16.1-36-36s16.1-36 36-36c69.1 0 136.2 13.5 199.3 40.3C772.3 66 827 103 874 150c47 47 83.9 101.8 109.7 162.7 26.7 63.1 40.2 130.2 40.2 199.3.1 19.9-16 36-35.9 36z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
@ -7953,6 +7897,99 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-feedback ant-form-item-has-warning"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-6"
|
||||
>
|
||||
<label
|
||||
class=""
|
||||
title="Warning"
|
||||
>
|
||||
Warning
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control ant-col-xs-24 ant-col-sm-14"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<div
|
||||
class="ant-select ant-tree-select ant-select-single ant-select-allow-clear ant-select-show-arrow"
|
||||
>
|
||||
<div
|
||||
class="ant-select-selector"
|
||||
>
|
||||
<span
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<input
|
||||
aria-autocomplete="list"
|
||||
aria-controls="undefined_list"
|
||||
aria-haspopup="listbox"
|
||||
aria-owns="undefined_list"
|
||||
autocomplete="off"
|
||||
class="ant-select-selection-search-input"
|
||||
readonly=""
|
||||
role="combobox"
|
||||
style="opacity:0"
|
||||
type="search"
|
||||
unselectable="on"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
<span
|
||||
class="ant-select-selection-placeholder"
|
||||
>
|
||||
I'm TreeSelect
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
class="ant-select-arrow"
|
||||
style="user-select:none;-webkit-user-select:none"
|
||||
unselectable="on"
|
||||
>
|
||||
<span
|
||||
aria-label="down"
|
||||
class="anticon anticon-down ant-select-suffix"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="down"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M884 256h-75c-5.1 0-9.9 2.5-12.9 6.6L512 654.2 227.9 262.6c-3-4.1-7.8-6.6-12.9-6.6h-75c-6.5 0-10.3 7.4-6.5 12.7l352.6 486.1c12.8 17.6 39 17.6 51.7 0l352.6-486.1c3.9-5.3.1-12.7-6.4-12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-warning"
|
||||
role="alert"
|
||||
>
|
||||
Need to be checked
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item"
|
||||
style="margin-bottom:0"
|
||||
@ -8204,29 +8241,6 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="check-circle"
|
||||
class="anticon anticon-check-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="check-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -8253,7 +8267,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper"
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-success ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
class="ant-input"
|
||||
@ -8266,7 +8280,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix ant-input-clear-icon"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
@ -8284,32 +8298,32 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="check-circle"
|
||||
class="anticon anticon-check-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="check-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="check-circle"
|
||||
class="anticon anticon-check-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="check-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm193.5 301.7l-210.6 292a31.8 31.8 0 01-51.7 0L318.5 484.9c-3.8-5.3 0-12.7 6.5-12.7h46.9c10.2 0 19.9 4.9 25.9 13.3l71.2 98.8 157.2-218c6-8.3 15.6-13.3 25.9-13.3H699c6.5 0 10.3 7.4 6.5 12.7z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -8336,7 +8350,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-password"
|
||||
class="ant-input-affix-wrapper ant-input-password ant-input-affix-wrapper-status-warning ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
@ -8371,32 +8385,32 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="exclamation-circle"
|
||||
class="anticon anticon-exclamation-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="exclamation-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm-32 232c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V296zm32 440a48.01 48.01 0 010-96 48.01 48.01 0 010 96z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -8423,7 +8437,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-password"
|
||||
class="ant-input-affix-wrapper ant-input-password ant-input-affix-wrapper-status-error ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
@ -8478,32 +8492,32 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<span
|
||||
class="ant-form-item-children-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -8541,6 +8555,97 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-row ant-form-item ant-form-item-with-help ant-form-item-has-feedback ant-form-item-has-error"
|
||||
>
|
||||
<div
|
||||
class="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-6"
|
||||
>
|
||||
<label
|
||||
class=""
|
||||
title="Fail"
|
||||
>
|
||||
Fail
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class="ant-col ant-form-item-control ant-col-xs-24 ant-col-sm-14"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-control-input-content"
|
||||
>
|
||||
<div
|
||||
class="ant-input-textarea ant-input-textarea-show-count ant-input-textarea-status-error ant-input-textarea-has-feedback"
|
||||
data-count="0"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn ant-input-affix-wrapper-status-error ant-input-affix-wrapper-has-feedback"
|
||||
>
|
||||
<textarea
|
||||
class="ant-input ant-input-status-error"
|
||||
/>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="close-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm165.4 618.2l-66-.3L512 563.4l-99.3 118.4-66.1.3c-4.4 0-8-3.5-8-8 0-1.9.7-3.7 1.9-5.2l130.1-155L340.5 359a8.32 8.32 0 01-1.9-5.2c0-4.4 3.6-8 8-8l66.1.3L512 464.6l99.3-118.4 66-.3c4.4 0 8 3.5 8 8 0 1.9-.7 3.7-1.9 5.2L553.5 514l130 155c1.2 1.5 1.9 3.3 1.9 5.2 0 4.4-3.6 8-8 8z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="ant-form-item-explain ant-form-item-explain-connected"
|
||||
>
|
||||
<div
|
||||
class="ant-form-item-explain-error"
|
||||
role="alert"
|
||||
>
|
||||
Should have something
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
|
@ -50,3 +50,10 @@ export interface FormItemPrefixContextProps {
|
||||
export const FormItemPrefixContext = React.createContext<FormItemPrefixContextProps>({
|
||||
prefixCls: '',
|
||||
});
|
||||
|
||||
export interface FormItemStatusContextProps {
|
||||
status?: ValidateStatus;
|
||||
hasFeedback?: boolean;
|
||||
}
|
||||
|
||||
export const FormItemStatusContext = React.createContext<FormItemStatusContextProps>({});
|
||||
|
@ -23,7 +23,17 @@ We provide properties like `validateStatus` `help` `hasFeedback` to customize yo
|
||||
|
||||
```tsx
|
||||
import { SmileOutlined } from '@ant-design/icons';
|
||||
import { Form, Input, DatePicker, TimePicker, Select, Cascader, InputNumber, Mentions } from 'antd';
|
||||
import {
|
||||
Form,
|
||||
Input,
|
||||
DatePicker,
|
||||
TimePicker,
|
||||
Select,
|
||||
Cascader,
|
||||
InputNumber,
|
||||
Mentions,
|
||||
TreeSelect,
|
||||
} from 'antd';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
@ -87,7 +97,7 @@ ReactDOM.render(
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Error" hasFeedback validateStatus="error">
|
||||
<Select allowClear>
|
||||
<Select placeholder="I'm Select" allowClear>
|
||||
<Option value="1">Option 1</Option>
|
||||
<Option value="2">Option 2</Option>
|
||||
<Option value="3">Option 3</Option>
|
||||
@ -100,7 +110,15 @@ ReactDOM.render(
|
||||
validateStatus="validating"
|
||||
help="The information is being validated..."
|
||||
>
|
||||
<Cascader options={[{ value: 'xx', label: 'xx' }]} allowClear />
|
||||
<Cascader placeholder="I'm Cascader" options={[{ value: 'xx', label: 'xx' }]} allowClear />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Warning" hasFeedback validateStatus="warning" help="Need to be checked">
|
||||
<TreeSelect
|
||||
placeholder="I'm TreeSelect"
|
||||
treeData={[{ value: 'xx', label: 'xx' }]}
|
||||
allowClear
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="inline" style={{ marginBottom: 0 }}>
|
||||
@ -140,6 +158,10 @@ ReactDOM.render(
|
||||
<Form.Item label="Fail" validateStatus="error">
|
||||
<Mentions />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item label="Fail" validateStatus="error" hasFeedback help="Should have something">
|
||||
<Input.TextArea allowClear showCount />
|
||||
</Form.Item>
|
||||
</Form>,
|
||||
mountNode,
|
||||
);
|
||||
|
@ -19,9 +19,10 @@ import { Form, InputNumber } from 'antd';
|
||||
|
||||
type ValidateStatus = Parameters<typeof Form.Item>[0]['validateStatus'];
|
||||
|
||||
function validatePrimeNumber(
|
||||
number: number,
|
||||
): { validateStatus: ValidateStatus; errorMsg: string | null } {
|
||||
function validatePrimeNumber(number: number): {
|
||||
validateStatus: ValidateStatus;
|
||||
errorMsg: string | null;
|
||||
} {
|
||||
if (number === 11) {
|
||||
return {
|
||||
validateStatus: 'success',
|
||||
|
@ -10,40 +10,10 @@
|
||||
.@{ant-prefix}-form-item-split {
|
||||
color: @text-color;
|
||||
}
|
||||
// 输入框的不同校验状态
|
||||
: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-number-affix-wrapper-disabled):not(.@{ant-prefix}-input-number-affix-wrapper-borderless).@{ant-prefix}-input-number-affix-wrapper {
|
||||
&,
|
||||
&:hover {
|
||||
background-color: @background-color;
|
||||
border-color: @border-color;
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&-focused {
|
||||
.active(@border-color, @hoverBorderColor, @outlineColor);
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-calendar-picker-open .@{ant-prefix}-calendar-picker-input {
|
||||
.active(@border-color, @hoverBorderColor, @outlineColor);
|
||||
}
|
||||
|
||||
.@{ant-prefix}-input-prefix,
|
||||
.@{ant-prefix}-input-number-prefix {
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
.@{ant-prefix}-input-group-addon,
|
||||
.@{ant-prefix}-input-number-group-addon {
|
||||
color: @text-color;
|
||||
border-color: @border-color;
|
||||
}
|
||||
|
||||
.has-feedback {
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset form styles
|
||||
|
@ -24,287 +24,19 @@
|
||||
}
|
||||
|
||||
&-has-feedback {
|
||||
// ========================= Input =========================
|
||||
.@{ant-prefix}-input {
|
||||
padding-right: 24px;
|
||||
}
|
||||
// https://github.com/ant-design/ant-design/issues/19884
|
||||
.@{ant-prefix}-input-affix-wrapper {
|
||||
.@{ant-prefix}-input-suffix {
|
||||
padding-right: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
// Fix issue: https://github.com/ant-design/ant-design/issues/7854
|
||||
.@{ant-prefix}-input-search:not(.@{ant-prefix}-input-search-enter-button) {
|
||||
.@{ant-prefix}-input-suffix {
|
||||
right: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== Switch =========================
|
||||
.@{ant-prefix}-switch {
|
||||
margin: 2px 0 4px;
|
||||
}
|
||||
|
||||
// ======================== Select =========================
|
||||
// Fix overlapping between feedback icon and <Select>'s arrow.
|
||||
// https://github.com/ant-design/ant-design/issues/4431
|
||||
> .@{ant-prefix}-select .@{ant-prefix}-select-arrow,
|
||||
> .@{ant-prefix}-select .@{ant-prefix}-select-clear,
|
||||
:not(.@{ant-prefix}-input-group-addon) > .@{ant-prefix}-select .@{ant-prefix}-select-arrow,
|
||||
:not(.@{ant-prefix}-input-group-addon) > .@{ant-prefix}-select .@{ant-prefix}-select-clear,
|
||||
:not(.@{ant-prefix}-input-number-group-addon)
|
||||
> .@{ant-prefix}-select
|
||||
.@{ant-prefix}-select-arrow,
|
||||
:not(.@{ant-prefix}-input-number-group-addon)
|
||||
> .@{ant-prefix}-select
|
||||
.@{ant-prefix}-select-clear {
|
||||
right: 32px;
|
||||
}
|
||||
> .@{ant-prefix}-select .@{ant-prefix}-select-selection-selected-value,
|
||||
:not(.@{ant-prefix}-input-group-addon)
|
||||
> .@{ant-prefix}-select
|
||||
.@{ant-prefix}-select-selection-selected-value,
|
||||
:not(.@{ant-prefix}-input-number-group-addon)
|
||||
> .@{ant-prefix}-select
|
||||
.@{ant-prefix}-select-selection-selected-value {
|
||||
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 {
|
||||
padding-right: @input-padding-horizontal-base + @font-size-base * 1.3;
|
||||
|
||||
&-large {
|
||||
padding-right: @input-padding-horizontal-lg + @font-size-base * 1.3;
|
||||
}
|
||||
|
||||
&-small {
|
||||
padding-right: @input-padding-horizontal-sm + @font-size-base * 1.3;
|
||||
}
|
||||
}
|
||||
|
||||
// ===================== Status Group ======================
|
||||
&.@{form-item-prefix-cls} {
|
||||
&-has-success,
|
||||
&-has-warning,
|
||||
&-has-error,
|
||||
&-is-validating {
|
||||
// ====================== Icon ======================
|
||||
.@{form-item-prefix-cls}-children-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
width: @input-height-base;
|
||||
height: 20px;
|
||||
margin-top: -10px;
|
||||
font-size: @font-size-base;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
visibility: visible;
|
||||
animation: zoomIn 0.3s @ease-out-back;
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== Success ========================
|
||||
&-has-success {
|
||||
&.@{form-item-prefix-cls}-has-feedback .@{form-item-prefix-cls}-children-icon {
|
||||
color: @success-color;
|
||||
animation-name: diffZoomIn1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== Warning ========================
|
||||
&-has-warning {
|
||||
.form-control-validation(@warning-color; @warning-color; @form-warning-input-bg; @warning-color-hover; @warning-color-outline);
|
||||
|
||||
&.@{form-item-prefix-cls}-has-feedback .@{form-item-prefix-cls}-children-icon {
|
||||
color: @warning-color;
|
||||
animation-name: diffZoomIn3 !important;
|
||||
}
|
||||
|
||||
// Select
|
||||
.@{ant-prefix}-select:not(.@{ant-prefix}-select-disabled):not(.@{ant-prefix}-select-customize-input) {
|
||||
.@{ant-prefix}-select-selector {
|
||||
background-color: @form-warning-input-bg;
|
||||
border-color: @warning-color !important;
|
||||
}
|
||||
&.@{ant-prefix}-select-open .@{ant-prefix}-select-selector,
|
||||
&.@{ant-prefix}-select-focused .@{ant-prefix}-select-selector {
|
||||
.active(@warning-color, @warning-color-hover, @warning-color-outline);
|
||||
}
|
||||
}
|
||||
|
||||
// InputNumber, TimePicker
|
||||
.@{ant-prefix}-input-number,
|
||||
.@{ant-prefix}-picker {
|
||||
background-color: @form-warning-input-bg;
|
||||
border-color: @warning-color;
|
||||
|
||||
&-focused,
|
||||
&:focus {
|
||||
.active(@warning-color, @warning-color-hover, @warning-color-outline);
|
||||
}
|
||||
|
||||
&:not([disabled]):hover {
|
||||
background-color: @form-warning-input-bg;
|
||||
border-color: @warning-color;
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-cascader-picker:focus .@{ant-prefix}-cascader-input {
|
||||
.active(@warning-color, @warning-color-hover, @warning-color-outline);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================= Error =========================
|
||||
&-has-error {
|
||||
.form-control-validation(@error-color; @error-color; @form-error-input-bg; @error-color-hover; @error-color-outline);
|
||||
|
||||
&.@{form-item-prefix-cls}-has-feedback .@{form-item-prefix-cls}-children-icon {
|
||||
color: @error-color;
|
||||
animation-name: diffZoomIn2 !important;
|
||||
}
|
||||
|
||||
// Select
|
||||
.@{ant-prefix}-select:not(.@{ant-prefix}-select-disabled):not(.@{ant-prefix}-select-customize-input) {
|
||||
.@{ant-prefix}-select-selector {
|
||||
background-color: @form-error-input-bg;
|
||||
border-color: @error-color !important;
|
||||
}
|
||||
&.@{ant-prefix}-select-open .@{ant-prefix}-select-selector,
|
||||
&.@{ant-prefix}-select-focused .@{ant-prefix}-select-selector {
|
||||
.active(@error-color, @error-color-hover, @error-color-outline);
|
||||
}
|
||||
}
|
||||
|
||||
// fixes https://github.com/ant-design/ant-design/issues/20482
|
||||
.@{ant-prefix}-input-group-addon,
|
||||
.@{ant-prefix}-input-number-group-addon {
|
||||
.@{ant-prefix}-select {
|
||||
&.@{ant-prefix}-select-single:not(.@{ant-prefix}-select-customize-input)
|
||||
.@{ant-prefix}-select-selector {
|
||||
background-color: inherit;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-select.@{ant-prefix}-select-auto-complete {
|
||||
.@{ant-prefix}-input:focus {
|
||||
border-color: @error-color;
|
||||
}
|
||||
}
|
||||
|
||||
// InputNumber, TimePicker
|
||||
.@{ant-prefix}-input-number,
|
||||
.@{ant-prefix}-picker {
|
||||
background-color: @form-error-input-bg;
|
||||
border-color: @error-color;
|
||||
|
||||
&-focused,
|
||||
&:focus {
|
||||
.active(@error-color, @error-color-hover, @error-color-outline);
|
||||
}
|
||||
|
||||
&:not([disabled]):hover {
|
||||
background-color: @form-error-input-bg;
|
||||
border-color: @error-color;
|
||||
}
|
||||
}
|
||||
|
||||
.@{ant-prefix}-mention-wrapper {
|
||||
.@{ant-prefix}-mention-editor {
|
||||
&,
|
||||
&:not([disabled]):hover {
|
||||
background-color: @form-error-input-bg;
|
||||
border-color: @error-color;
|
||||
}
|
||||
}
|
||||
&.@{ant-prefix}-mention-active:not([disabled]) .@{ant-prefix}-mention-editor,
|
||||
.@{ant-prefix}-mention-editor:not([disabled]):focus {
|
||||
.active(@error-color, @error-color-hover, @error-color-outline);
|
||||
}
|
||||
}
|
||||
|
||||
// Cascader
|
||||
.@{ant-prefix}-cascader-picker {
|
||||
&:hover
|
||||
.@{ant-prefix}-cascader-picker-label:hover
|
||||
+ .@{ant-prefix}-cascader-input.@{ant-prefix}-input {
|
||||
border-color: @error-color;
|
||||
}
|
||||
|
||||
&:focus .@{ant-prefix}-cascader-input {
|
||||
background-color: @form-error-input-bg;
|
||||
.active(@error-color, @error-color-hover, @error-color-outline);
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer
|
||||
.@{ant-prefix}-transfer {
|
||||
&-list {
|
||||
border-color: @error-color;
|
||||
|
||||
&-search:not([disabled]) {
|
||||
border-color: @input-border-color;
|
||||
|
||||
&:hover {
|
||||
.hover();
|
||||
}
|
||||
|
||||
&:focus {
|
||||
.active();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Radio.Group
|
||||
.@{ant-prefix}-radio-button-wrapper {
|
||||
border-color: @error-color !important;
|
||||
|
||||
&:not(:first-child) {
|
||||
&::before {
|
||||
background-color: @error-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mentions
|
||||
.@{ant-prefix}-mentions {
|
||||
border-color: @error-color !important;
|
||||
|
||||
&-focused,
|
||||
&:focus {
|
||||
.active(@error-color, @error-color-hover, @error-color-outline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ====================== Validating =======================
|
||||
&-is-validating {
|
||||
&.@{form-item-prefix-cls}-has-feedback .@{form-item-prefix-cls}-children-icon {
|
||||
display: inline-block;
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,13 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
|
||||
import { tuple } from '../_util/type';
|
||||
import type { InputProps } from './Input';
|
||||
import classNames from 'classnames';
|
||||
import * as React from 'react';
|
||||
import { DirectionType } from '../config-provider';
|
||||
import { SizeType } from '../config-provider/SizeContext';
|
||||
import { FormItemStatusContext, FormItemStatusContextProps } from '../form/context';
|
||||
import { cloneElement } from '../_util/reactNode';
|
||||
import { getStatusClassNames, InputStatus } from '../_util/statusUtils';
|
||||
import { tuple } from '../_util/type';
|
||||
import type { InputProps } from './Input';
|
||||
import { getInputClassName, hasPrefixSuffix } from './utils';
|
||||
|
||||
const ClearableInputType = tuple('text', 'input');
|
||||
@ -40,6 +42,7 @@ export interface ClearableInputProps extends BasicProps {
|
||||
addonBefore?: React.ReactNode;
|
||||
addonAfter?: React.ReactNode;
|
||||
triggerFocus?: () => void;
|
||||
status?: InputStatus;
|
||||
}
|
||||
|
||||
class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
@ -91,7 +94,11 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
return null;
|
||||
}
|
||||
|
||||
renderLabeledIcon(prefixCls: string, element: React.ReactElement) {
|
||||
renderLabeledIcon(
|
||||
prefixCls: string,
|
||||
element: React.ReactElement,
|
||||
statusContext: FormItemStatusContextProps,
|
||||
) {
|
||||
const {
|
||||
focused,
|
||||
value,
|
||||
@ -106,7 +113,11 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
readOnly,
|
||||
bordered,
|
||||
hidden,
|
||||
status: customStatus,
|
||||
} = this.props;
|
||||
|
||||
const { status: contextStatus, hasFeedback } = statusContext;
|
||||
|
||||
if (!hasPrefixSuffix(this.props)) {
|
||||
return cloneElement(element, {
|
||||
value,
|
||||
@ -116,18 +127,22 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
const suffixNode = this.renderSuffix(prefixCls);
|
||||
const prefixNode = prefix ? <span className={`${prefixCls}-prefix`}>{prefix}</span> : null;
|
||||
|
||||
const affixWrapperCls = classNames(`${prefixCls}-affix-wrapper`, {
|
||||
[`${prefixCls}-affix-wrapper-focused`]: focused,
|
||||
[`${prefixCls}-affix-wrapper-disabled`]: disabled,
|
||||
[`${prefixCls}-affix-wrapper-sm`]: size === 'small',
|
||||
[`${prefixCls}-affix-wrapper-lg`]: size === 'large',
|
||||
[`${prefixCls}-affix-wrapper-input-with-clear-btn`]: suffix && allowClear && value,
|
||||
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-affix-wrapper-readonly`]: readOnly,
|
||||
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
|
||||
// className will go to addon wrapper
|
||||
[`${className}`]: !hasAddon(this.props) && className,
|
||||
});
|
||||
const affixWrapperCls = classNames(
|
||||
`${prefixCls}-affix-wrapper`,
|
||||
{
|
||||
[`${prefixCls}-affix-wrapper-focused`]: focused,
|
||||
[`${prefixCls}-affix-wrapper-disabled`]: disabled,
|
||||
[`${prefixCls}-affix-wrapper-sm`]: size === 'small',
|
||||
[`${prefixCls}-affix-wrapper-lg`]: size === 'large',
|
||||
[`${prefixCls}-affix-wrapper-input-with-clear-btn`]: suffix && allowClear && value,
|
||||
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-affix-wrapper-readonly`]: readOnly,
|
||||
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
|
||||
// className will go to addon wrapper
|
||||
[`${className}`]: !hasAddon(this.props) && className,
|
||||
},
|
||||
getStatusClassNames(`${prefixCls}-affix-wrapper`, contextStatus || customStatus, hasFeedback),
|
||||
);
|
||||
return (
|
||||
<span
|
||||
ref={this.containerRef}
|
||||
@ -147,8 +162,22 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
);
|
||||
}
|
||||
|
||||
renderInputWithLabel(prefixCls: string, labeledElement: React.ReactElement) {
|
||||
const { addonBefore, addonAfter, style, size, className, direction, hidden } = this.props;
|
||||
renderInputWithLabel(
|
||||
prefixCls: string,
|
||||
labeledElement: React.ReactElement,
|
||||
statusContext: FormItemStatusContextProps,
|
||||
) {
|
||||
const {
|
||||
addonBefore,
|
||||
addonAfter,
|
||||
style,
|
||||
size,
|
||||
className,
|
||||
direction,
|
||||
hidden,
|
||||
status: customStatus,
|
||||
} = this.props;
|
||||
const { status: contextStatus, hasFeedback } = statusContext;
|
||||
// Not wrap when there is not addons
|
||||
if (!hasAddon(this.props)) {
|
||||
return labeledElement;
|
||||
@ -172,6 +201,7 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
[`${prefixCls}-group-wrapper-lg`]: size === 'large',
|
||||
[`${prefixCls}-group-wrapper-rtl`]: direction === 'rtl',
|
||||
},
|
||||
getStatusClassNames(`${prefixCls}-group-wrapper`, contextStatus || customStatus, hasFeedback),
|
||||
className,
|
||||
);
|
||||
|
||||
@ -188,8 +218,24 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
);
|
||||
}
|
||||
|
||||
renderTextAreaWithClearIcon(prefixCls: string, element: React.ReactElement) {
|
||||
const { value, allowClear, className, style, direction, bordered, hidden } = this.props;
|
||||
renderTextAreaWithClearIcon(
|
||||
prefixCls: string,
|
||||
element: React.ReactElement,
|
||||
statusContext: FormItemStatusContextProps,
|
||||
) {
|
||||
const {
|
||||
value,
|
||||
allowClear,
|
||||
className,
|
||||
style,
|
||||
direction,
|
||||
bordered,
|
||||
hidden,
|
||||
status: customStatus,
|
||||
} = this.props;
|
||||
|
||||
const { status: contextStatus, hasFeedback } = statusContext;
|
||||
|
||||
if (!allowClear) {
|
||||
return cloneElement(element, {
|
||||
value,
|
||||
@ -198,6 +244,7 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
const affixWrapperCls = classNames(
|
||||
`${prefixCls}-affix-wrapper`,
|
||||
`${prefixCls}-affix-wrapper-textarea-with-clear-btn`,
|
||||
getStatusClassNames(`${prefixCls}-affix-wrapper`, contextStatus || customStatus, hasFeedback),
|
||||
{
|
||||
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
|
||||
@ -217,11 +264,21 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { prefixCls, inputType, element } = this.props;
|
||||
if (inputType === ClearableInputType[0]) {
|
||||
return this.renderTextAreaWithClearIcon(prefixCls, element);
|
||||
}
|
||||
return this.renderInputWithLabel(prefixCls, this.renderLabeledIcon(prefixCls, element));
|
||||
return (
|
||||
<FormItemStatusContext.Consumer>
|
||||
{statusContext => {
|
||||
const { prefixCls, inputType, element } = this.props;
|
||||
if (inputType === ClearableInputType[0]) {
|
||||
return this.renderTextAreaWithClearIcon(prefixCls, element, statusContext);
|
||||
}
|
||||
return this.renderInputWithLabel(
|
||||
prefixCls,
|
||||
this.renderLabeledIcon(prefixCls, element, statusContext),
|
||||
statusContext,
|
||||
);
|
||||
}}
|
||||
</FormItemStatusContext.Consumer>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import { ValidateStatus } from '../form/FormItem';
|
||||
import type Group from './Group';
|
||||
import type Search from './Search';
|
||||
import type TextArea from './TextArea';
|
||||
@ -11,6 +12,8 @@ import { ConfigConsumer, ConfigConsumerProps, DirectionType } from '../config-pr
|
||||
import SizeContext, { SizeType } from '../config-provider/SizeContext';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import { getInputClassName, hasPrefixSuffix } from './utils';
|
||||
import { FormItemStatusContext } from '../form/context';
|
||||
import { getFeedbackIcon, InputStatus } from '../_util/statusUtils';
|
||||
|
||||
export interface InputFocusOptions extends FocusOptions {
|
||||
cursor?: 'start' | 'end' | 'all';
|
||||
@ -59,6 +62,7 @@ export interface InputProps
|
||||
showCount?: boolean | ShowCountProps;
|
||||
bordered?: boolean;
|
||||
htmlSize?: number;
|
||||
status?: InputStatus;
|
||||
}
|
||||
|
||||
export function fixControlledValue<T>(value: T) {
|
||||
@ -280,6 +284,7 @@ class Input extends React.Component<InputProps, InputState> {
|
||||
prefixCls: string,
|
||||
size: SizeType | undefined,
|
||||
bordered: boolean,
|
||||
status?: ValidateStatus,
|
||||
input: ConfigConsumerProps['input'] = {},
|
||||
) => {
|
||||
const {
|
||||
@ -307,7 +312,9 @@ class Input extends React.Component<InputProps, InputState> {
|
||||
'bordered',
|
||||
'htmlSize',
|
||||
'showCount',
|
||||
'status',
|
||||
]);
|
||||
|
||||
return (
|
||||
<input
|
||||
autoComplete={input.autoComplete}
|
||||
@ -317,7 +324,14 @@ class Input extends React.Component<InputProps, InputState> {
|
||||
onBlur={this.onBlur}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
className={classNames(
|
||||
getInputClassName(prefixCls, bordered, customizeSize || size, disabled, this.direction),
|
||||
getInputClassName(
|
||||
prefixCls,
|
||||
bordered,
|
||||
customizeSize || size,
|
||||
disabled,
|
||||
this.direction,
|
||||
status,
|
||||
),
|
||||
{
|
||||
[className!]: className && !addonBefore && !addonAfter,
|
||||
},
|
||||
@ -369,49 +383,66 @@ class Input extends React.Component<InputProps, InputState> {
|
||||
dataCount = `${valueLength}${hasMaxLength ? ` / ${maxLength}` : ''}`;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{!!showCount && (
|
||||
<span
|
||||
className={classNames(`${prefixCls}-show-count-suffix`, {
|
||||
[`${prefixCls}-show-count-has-suffix`]: !!suffix,
|
||||
})}
|
||||
>
|
||||
{dataCount}
|
||||
</span>
|
||||
)}
|
||||
{suffix}
|
||||
</>
|
||||
!!showCount && (
|
||||
<span
|
||||
className={classNames(`${prefixCls}-show-count-suffix`, {
|
||||
[`${prefixCls}-show-count-has-suffix`]: !!suffix,
|
||||
})}
|
||||
>
|
||||
{dataCount}
|
||||
</span>
|
||||
)
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
renderSuffix = (prefixCls: string, hasFeedback?: boolean, status?: ValidateStatus) => {
|
||||
const { suffix, showCount } = this.props;
|
||||
|
||||
return (
|
||||
(showCount || suffix || hasFeedback) && (
|
||||
<>
|
||||
{this.renderShowCountSuffix(prefixCls)}
|
||||
{suffix}
|
||||
{hasFeedback && getFeedbackIcon(prefixCls, status)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
renderComponent = ({ getPrefixCls, direction, input }: ConfigConsumerProps) => {
|
||||
const { value, focused } = this.state;
|
||||
const { prefixCls: customizePrefixCls, bordered = true } = this.props;
|
||||
const { prefixCls: customizePrefixCls, bordered = true, status: customStatus } = this.props;
|
||||
const prefixCls = getPrefixCls('input', customizePrefixCls);
|
||||
this.direction = direction;
|
||||
|
||||
const showCountSuffix = this.renderShowCountSuffix(prefixCls);
|
||||
|
||||
return (
|
||||
<SizeContext.Consumer>
|
||||
{size => (
|
||||
<ClearableLabeledInput
|
||||
size={size}
|
||||
{...this.props}
|
||||
prefixCls={prefixCls}
|
||||
inputType="input"
|
||||
value={fixControlledValue(value)}
|
||||
element={this.renderInput(prefixCls, size, bordered, input)}
|
||||
handleReset={this.handleReset}
|
||||
ref={this.saveClearableInput}
|
||||
direction={direction}
|
||||
focused={focused}
|
||||
triggerFocus={this.focus}
|
||||
bordered={bordered}
|
||||
suffix={showCountSuffix}
|
||||
/>
|
||||
<FormItemStatusContext.Consumer>
|
||||
{({ status: contextStatus, hasFeedback }) => {
|
||||
const mergedStatus = contextStatus || customStatus;
|
||||
|
||||
return (
|
||||
<ClearableLabeledInput
|
||||
size={size}
|
||||
{...this.props}
|
||||
prefixCls={prefixCls}
|
||||
inputType="input"
|
||||
value={fixControlledValue(value)}
|
||||
element={this.renderInput(prefixCls, size, bordered, mergedStatus, input)}
|
||||
handleReset={this.handleReset}
|
||||
ref={this.saveClearableInput}
|
||||
direction={direction}
|
||||
focused={focused}
|
||||
triggerFocus={this.focus}
|
||||
bordered={bordered}
|
||||
suffix={this.renderSuffix(prefixCls, hasFeedback, mergedStatus)}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</FormItemStatusContext.Consumer>
|
||||
)}
|
||||
</SizeContext.Consumer>
|
||||
);
|
||||
|
@ -1,13 +1,15 @@
|
||||
import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import RcTextArea, { TextAreaProps as RcTextAreaProps } from 'rc-textarea';
|
||||
import ResizableTextArea from 'rc-textarea/lib/ResizableTextArea';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import classNames from 'classnames';
|
||||
import useMergedState from 'rc-util/lib/hooks/useMergedState';
|
||||
import ClearableLabeledInput from './ClearableLabeledInput';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import * as React from 'react';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { fixControlledValue, resolveOnChange, triggerFocus, InputFocusOptions } from './Input';
|
||||
import SizeContext, { SizeType } from '../config-provider/SizeContext';
|
||||
import { FormItemStatusContext } from '../form/context';
|
||||
import { getFeedbackIcon, getStatusClassNames, InputStatus } from '../_util/statusUtils';
|
||||
import ClearableLabeledInput from './ClearableLabeledInput';
|
||||
import { fixControlledValue, InputFocusOptions, resolveOnChange, triggerFocus } from './Input';
|
||||
|
||||
interface ShowCountProps {
|
||||
formatter: (args: { count: number; maxLength?: number }) => string;
|
||||
@ -22,6 +24,7 @@ export interface TextAreaProps extends RcTextAreaProps {
|
||||
bordered?: boolean;
|
||||
showCount?: boolean | ShowCountProps;
|
||||
size?: SizeType;
|
||||
status?: InputStatus;
|
||||
}
|
||||
|
||||
export interface TextAreaRef {
|
||||
@ -43,6 +46,7 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
|
||||
onCompositionStart,
|
||||
onCompositionEnd,
|
||||
onChange,
|
||||
status: customStatus,
|
||||
...props
|
||||
},
|
||||
ref,
|
||||
@ -50,6 +54,9 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
|
||||
const { getPrefixCls, direction } = React.useContext(ConfigContext);
|
||||
const size = React.useContext(SizeContext);
|
||||
|
||||
const { status: contextStatus, hasFeedback } = React.useContext(FormItemStatusContext);
|
||||
const mergedStatus = contextStatus || customStatus;
|
||||
|
||||
const innerRef = React.useRef<RcTextArea>(null);
|
||||
const clearableInputRef = React.useRef<ClearableLabeledInput>(null);
|
||||
|
||||
@ -124,12 +131,15 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
|
||||
const textArea = (
|
||||
<RcTextArea
|
||||
{...omit(props, ['allowClear'])}
|
||||
className={classNames({
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
[className!]: className && !showCount,
|
||||
[`${prefixCls}-sm`]: size === 'small' || customizeSize === 'small',
|
||||
[`${prefixCls}-lg`]: size === 'large' || customizeSize === 'large',
|
||||
})}
|
||||
className={classNames(
|
||||
{
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
[className!]: className && !showCount,
|
||||
[`${prefixCls}-sm`]: size === 'small' || customizeSize === 'small',
|
||||
[`${prefixCls}-lg`]: size === 'large' || customizeSize === 'large',
|
||||
},
|
||||
getStatusClassNames(prefixCls, mergedStatus),
|
||||
)}
|
||||
style={showCount ? undefined : style}
|
||||
prefixCls={prefixCls}
|
||||
onCompositionStart={onInternalCompositionStart}
|
||||
@ -158,12 +168,13 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
|
||||
handleReset={handleReset}
|
||||
ref={clearableInputRef}
|
||||
bordered={bordered}
|
||||
status={customStatus}
|
||||
style={showCount ? undefined : style}
|
||||
/>
|
||||
);
|
||||
|
||||
// Only show text area wrapper when needed
|
||||
if (showCount) {
|
||||
if (showCount || hasFeedback) {
|
||||
const valueLength = [...val].length;
|
||||
|
||||
let dataCount = '';
|
||||
@ -180,14 +191,16 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
|
||||
`${prefixCls}-textarea`,
|
||||
{
|
||||
[`${prefixCls}-textarea-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-textarea-show-count`]: showCount,
|
||||
},
|
||||
`${prefixCls}-textarea-show-count`,
|
||||
getStatusClassNames(`${prefixCls}-textarea`, mergedStatus, hasFeedback),
|
||||
className,
|
||||
)}
|
||||
style={style}
|
||||
data-count={dataCount}
|
||||
>
|
||||
{textareaNode}
|
||||
{hasFeedback && getFeedbackIcon(prefixCls, mergedStatus)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -9529,6 +9529,117 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/input/demo/status.md extend context correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-status-error"
|
||||
placeholder="Error"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-status-warning"
|
||||
placeholder="Warning"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-error"
|
||||
>
|
||||
<span
|
||||
class="ant-input-prefix"
|
||||
>
|
||||
<span
|
||||
aria-label="clock-circle"
|
||||
class="anticon anticon-clock-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="clock-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
/>
|
||||
<path
|
||||
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input"
|
||||
placeholder="Error with prefix"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-warning"
|
||||
>
|
||||
<span
|
||||
class="ant-input-prefix"
|
||||
>
|
||||
<span
|
||||
aria-label="clock-circle"
|
||||
class="anticon anticon-clock-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="clock-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
/>
|
||||
<path
|
||||
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input"
|
||||
placeholder="Warning with prefix"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/input/demo/textarea.md extend context correctly 1`] = `
|
||||
<textarea
|
||||
class="ant-input"
|
||||
|
@ -3303,6 +3303,117 @@ Array [
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`renders ./components/input/demo/status.md correctly 1`] = `
|
||||
<div
|
||||
class="ant-space ant-space-vertical"
|
||||
style="width:100%"
|
||||
>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-status-error"
|
||||
placeholder="Error"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-status-warning"
|
||||
placeholder="Warning"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-error"
|
||||
>
|
||||
<span
|
||||
class="ant-input-prefix"
|
||||
>
|
||||
<span
|
||||
aria-label="clock-circle"
|
||||
class="anticon anticon-clock-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="clock-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
/>
|
||||
<path
|
||||
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input"
|
||||
placeholder="Error with prefix"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-status-warning"
|
||||
>
|
||||
<span
|
||||
class="ant-input-prefix"
|
||||
>
|
||||
<span
|
||||
aria-label="clock-circle"
|
||||
class="anticon anticon-clock-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
data-icon="clock-circle"
|
||||
fill="currentColor"
|
||||
focusable="false"
|
||||
height="1em"
|
||||
viewBox="64 64 896 896"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm0 820c-205.4 0-372-166.6-372-372s166.6-372 372-372 372 166.6 372 372-166.6 372-372 372z"
|
||||
/>
|
||||
<path
|
||||
d="M686.7 638.6L544.1 535.5V288c0-4.4-3.6-8-8-8H488c-4.4 0-8 3.6-8 8v275.4c0 2.6 1.2 5 3.3 6.5l165.4 120.6c3.6 2.6 8.6 1.8 11.2-1.7l28.6-39c2.6-3.7 1.8-8.7-1.8-11.2z"
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input"
|
||||
placeholder="Warning with prefix"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`renders ./components/input/demo/textarea.md correctly 1`] = `
|
||||
<textarea
|
||||
class="ant-input"
|
||||
|
30
components/input/demo/status.md
Normal file
30
components/input/demo/status.md
Normal file
@ -0,0 +1,30 @@
|
||||
---
|
||||
order: 19
|
||||
title:
|
||||
zh-CN: 自定义状态
|
||||
en-US: Status
|
||||
---
|
||||
|
||||
## zh-CN
|
||||
|
||||
使用 `status` 为 Input 添加状态。可选 `error` 或者 `warning`。
|
||||
|
||||
## en-US
|
||||
|
||||
Add status to Input with `status`, which could be `error` or `warning`。
|
||||
|
||||
```tsx
|
||||
import { Input, Space } from 'antd';
|
||||
import ClockCircleOutlined from '@ant-design/icons/ClockCircleOutlined';
|
||||
|
||||
const ValidateInputs: React.FC = () => (
|
||||
<Space direction="vertical" style={{ width: '100%' }}>
|
||||
<Input status="error" placeholder="Error" />
|
||||
<Input status="warning" placeholder="Warning" />
|
||||
<Input status="error" prefix={<ClockCircleOutlined />} placeholder="Error with prefix" />
|
||||
<Input status="warning" prefix={<ClockCircleOutlined />} placeholder="Warning with prefix" />
|
||||
</Space>
|
||||
);
|
||||
|
||||
ReactDOM.render(<ValidateInputs />, mountNode);
|
||||
```
|
@ -27,6 +27,7 @@ A basic widget for getting the user input is a text field. Keyboard and mouse ca
|
||||
| id | The ID for input | string | - | |
|
||||
| maxLength | The max length | number | - | |
|
||||
| showCount | Whether show text count | boolean \| { formatter: ({ count: number, maxLength?: number }) => ReactNode } | false | 4.18.0 |
|
||||
| status | Set validation status | 'error' \| 'warning' | - | 4.19.0 |
|
||||
| prefix | The prefix icon for the Input | ReactNode | - | |
|
||||
| size | The size of the input box. Note: in the context of a form, the `large` size is used | `large` \| `middle` \| `small` | - | |
|
||||
| suffix | The suffix icon for the Input | ReactNode | - | |
|
||||
|
@ -28,6 +28,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/xS9YEJhfe/Input.svg
|
||||
| id | 输入框的 id | string | - | |
|
||||
| maxLength | 最大长度 | number | - | |
|
||||
| showCount | 是否展示字数 | boolean \| { formatter: ({ count: number, maxLength?: number }) => ReactNode } | false | 4.18.0 |
|
||||
| status | 设置校验状态 | 'error' \| 'warning' | - | 4.19.0 |
|
||||
| prefix | 带有前缀图标的 input | ReactNode | - | |
|
||||
| size | 控件大小。注:标准表单内的输入框大小限制为 `large` | `large` \| `middle` \| `small` | - | |
|
||||
| suffix | 带有后缀图标的 input | ReactNode | - | |
|
||||
|
@ -50,6 +50,10 @@
|
||||
display: flex;
|
||||
flex: none;
|
||||
align-items: center;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
&-show-count-suffix {
|
||||
|
@ -3,6 +3,7 @@
|
||||
@import './mixin';
|
||||
@import './affix';
|
||||
@import './allow-clear';
|
||||
@import './status';
|
||||
|
||||
@input-prefix-cls: ~'@{ant-prefix}-input';
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import '../../style/index.less';
|
||||
import './index.less';
|
||||
|
||||
// deps-lint-skip: form
|
||||
// style dependencies
|
||||
import '../../button/style';
|
||||
|
132
components/input/style/status.less
Normal file
132
components/input/style/status.less
Normal file
@ -0,0 +1,132 @@
|
||||
@import './mixin';
|
||||
|
||||
@input-prefix-cls: ~'@{ant-prefix}-input';
|
||||
|
||||
.status-color(
|
||||
@prefix-cls: @input-prefix-cls;
|
||||
@text-color: @input-color;
|
||||
@border-color: @input-border-color;
|
||||
@background-color: @input-bg;
|
||||
@hoverBorderColor: @primary-color-hover;
|
||||
@outlineColor: @primary-color-outline;
|
||||
) {
|
||||
&:not(.@{prefix-cls}-disabled):not(.@{prefix-cls}-borderless).@{prefix-cls} {
|
||||
&,
|
||||
&:hover {
|
||||
background: @background-color;
|
||||
border-color: @border-color;
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&-focused {
|
||||
.active(@text-color, @hoverBorderColor, @outlineColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-color-common(
|
||||
@prefix-cls: @input-prefix-cls;
|
||||
@text-color: @input-color;
|
||||
@border-color: @input-border-color;
|
||||
@background-color: @input-bg;
|
||||
@hoverBorderColor: @primary-color-hover;
|
||||
@outlineColor: @primary-color-outline;
|
||||
) {
|
||||
.@{prefix-cls}-feedback-icon {
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
.@{prefix-cls}-prefix {
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
|
||||
.group-status-color(
|
||||
@prefix-cls: @input-prefix-cls;
|
||||
@text-color: @input-color;
|
||||
@border-color: @input-border-color;
|
||||
) {
|
||||
.@{prefix-cls}-group-addon {
|
||||
color: @text-color;
|
||||
border-color: @border-color;
|
||||
}
|
||||
}
|
||||
|
||||
@input-wrapper-cls: @input-prefix-cls, ~'@{input-prefix-cls}-affix-wrapper';
|
||||
|
||||
each(@input-wrapper-cls, {
|
||||
.@{value} {
|
||||
&-status-error {
|
||||
.status-color(@value, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);
|
||||
.status-color-common(@input-prefix-cls, @error-color, @error-color, @input-bg, @error-color-hover, @error-color-outline);
|
||||
}
|
||||
|
||||
&-status-warning {
|
||||
.status-color(@value, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
|
||||
.status-color-common(@input-prefix-cls, @warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
.@{input-prefix-cls}-textarea,
|
||||
.@{input-prefix-cls}-affix-wrapper {
|
||||
&-status-validating {
|
||||
.@{input-prefix-cls}-feedback-icon {
|
||||
display: inline-block;
|
||||
color: @primary-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-status-success {
|
||||
.@{input-prefix-cls}-feedback-icon {
|
||||
color: @success-color;
|
||||
animation-name: diffZoomIn1 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{input-prefix-cls}-textarea {
|
||||
&-status-error {
|
||||
.@{input-prefix-cls}-feedback-icon {
|
||||
color: @error-color;
|
||||
}
|
||||
}
|
||||
|
||||
&-status-warning {
|
||||
.@{input-prefix-cls}-feedback-icon {
|
||||
color: @warning-color;
|
||||
}
|
||||
}
|
||||
|
||||
.@{input-prefix-cls}-feedback-icon {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: @input-padding-horizontal-base;
|
||||
bottom: 0;
|
||||
z-index: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
&-status-error,
|
||||
&-status-warning,
|
||||
&-status-success,
|
||||
&-status-validating {
|
||||
&.@{input-prefix-cls}-textarea-has-feedback {
|
||||
.@{input-prefix-cls} {
|
||||
padding-right: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.@{input-prefix-cls}-group-wrapper {
|
||||
&-status-error {
|
||||
.group-status-color(@input-prefix-cls, @error-color, @error-color);
|
||||
}
|
||||
|
||||
&-status-warning {
|
||||
.group-status-color(@input-prefix-cls, @warning-color, @warning-color);
|
||||
}
|
||||
}
|
@ -1,8 +1,10 @@
|
||||
import classNames from 'classnames';
|
||||
import { ValidateStatus } from '../form/FormItem';
|
||||
import type { DirectionType } from '../config-provider';
|
||||
import type { SizeType } from '../config-provider/SizeContext';
|
||||
import type { ClearableInputProps } from './ClearableLabeledInput';
|
||||
import type { InputProps } from './Input';
|
||||
import { getStatusClassNames } from '../_util/statusUtils';
|
||||
|
||||
export function getInputClassName(
|
||||
prefixCls: string,
|
||||
@ -10,14 +12,20 @@ export function getInputClassName(
|
||||
size?: SizeType,
|
||||
disabled?: boolean,
|
||||
direction?: DirectionType,
|
||||
status?: ValidateStatus,
|
||||
hasFeedback?: boolean,
|
||||
) {
|
||||
return classNames(prefixCls, {
|
||||
[`${prefixCls}-sm`]: size === 'small',
|
||||
[`${prefixCls}-lg`]: size === 'large',
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
});
|
||||
return classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-sm`]: size === 'small',
|
||||
[`${prefixCls}-lg`]: size === 'large',
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
},
|
||||
getStatusClassNames(prefixCls, status, hasFeedback),
|
||||
);
|
||||
}
|
||||
|
||||
export function hasPrefixSuffix(props: InputProps | ClearableInputProps) {
|
||||
|
Loading…
Reference in New Issue
Block a user