diff --git a/components/_util/statusUtils.tsx b/components/_util/statusUtils.tsx
index 25153ba93f..c88e93a6dc 100644
--- a/components/_util/statusUtils.tsx
+++ b/components/_util/statusUtils.tsx
@@ -1,8 +1,3 @@
-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';
@@ -10,22 +5,6 @@ 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 ? (
-
-
-
- ) : null;
-};
-
export function getStatusClassNames(
prefixCls: string,
status?: ValidateStatus,
diff --git a/components/cascader/index.tsx b/components/cascader/index.tsx
index 03abae2c21..ac64f80ca6 100644
--- a/components/cascader/index.tsx
+++ b/components/cascader/index.tsx
@@ -149,7 +149,12 @@ const Cascader = React.forwardRef((props: CascaderProps, ref: React.Ref, ref: React.Ref(
generateConfig: GenerateConfig,
@@ -39,23 +38,6 @@ export default function generateRangePicker(
}
};
- renderFeedback = (prefixCls: string) => (
-
- {({ hasFeedback, status: contextStatus }) => {
- const { status: customStatus } = this.props;
- const status = getMergedStatus(contextStatus, customStatus);
- return hasFeedback && getFeedbackIcon(prefixCls, status);
- }}
-
- );
-
- renderSuffix = (prefixCls: string, mergedPicker?: PickerMode) => (
- <>
- {mergedPicker === 'time' ? : }
- {this.renderFeedback(prefixCls)}
- >
- );
-
renderPicker = (contextLocale: PickerLocale) => {
const locale = { ...contextLocale, ...this.props.locale };
const { getPrefixCls, direction, getPopupContainer } = this.context;
@@ -89,46 +71,55 @@ export default function generateRangePicker(
return (
- {({ hasFeedback, status: contextStatus }) => (
-
- separator={
-
-
-
- }
- ref={this.pickerRef}
- dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
- placeholder={getRangePlaceholder(picker, locale, placeholder)}
- suffixIcon={this.renderSuffix(prefixCls, picker)}
- clearIcon={}
- prevIcon={}
- nextIcon={}
- superPrevIcon={}
- superNextIcon={}
- allowClear
- transitionName={`${rootPrefixCls}-slide-up`}
- {...restProps}
- {...additionalOverrideProps}
- className={classNames(
- {
- [`${prefixCls}-${mergedSize}`]: mergedSize,
- [`${prefixCls}-borderless`]: !bordered,
- },
- getStatusClassNames(
- prefixCls,
- getMergedStatus(contextStatus, customStatus),
- hasFeedback,
- ),
- className,
- )}
- locale={locale!.lang}
- prefixCls={prefixCls}
- getPopupContainer={customGetPopupContainer || getPopupContainer}
- generateConfig={generateConfig}
- components={Components}
- direction={direction}
- />
- )}
+ {({ hasFeedback, status: contextStatus, feedbackIcon }) => {
+ const suffixNode = (
+ <>
+ {picker === 'time' ? : }
+ {hasFeedback && feedbackIcon}
+ >
+ );
+
+ return (
+
+ separator={
+
+
+
+ }
+ ref={this.pickerRef}
+ dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
+ placeholder={getRangePlaceholder(picker, locale, placeholder)}
+ suffixIcon={suffixNode}
+ clearIcon={}
+ prevIcon={}
+ nextIcon={}
+ superPrevIcon={}
+ superNextIcon={}
+ allowClear
+ transitionName={`${rootPrefixCls}-slide-up`}
+ {...restProps}
+ {...additionalOverrideProps}
+ className={classNames(
+ {
+ [`${prefixCls}-${mergedSize}`]: mergedSize,
+ [`${prefixCls}-borderless`]: !bordered,
+ },
+ getStatusClassNames(
+ prefixCls,
+ getMergedStatus(contextStatus, customStatus),
+ hasFeedback,
+ ),
+ className,
+ )}
+ locale={locale!.lang}
+ prefixCls={prefixCls}
+ getPopupContainer={customGetPopupContainer || getPopupContainer}
+ generateConfig={generateConfig}
+ components={Components}
+ direction={direction}
+ />
+ );
+ }}
);
}}
diff --git a/components/date-picker/generatePicker/generateSinglePicker.tsx b/components/date-picker/generatePicker/generateSinglePicker.tsx
index 2e182f900a..6fbae02e3d 100644
--- a/components/date-picker/generatePicker/generateSinglePicker.tsx
+++ b/components/date-picker/generatePicker/generateSinglePicker.tsx
@@ -22,12 +22,7 @@ import {
} from '.';
import { PickerComponentClass } from './interface';
import { FormItemInputContext } from '../../form/context';
-import {
- getFeedbackIcon,
- getMergedStatus,
- getStatusClassNames,
- InputStatus,
-} from '../../_util/statusUtils';
+import { getMergedStatus, getStatusClassNames, InputStatus } from '../../_util/statusUtils';
export default function generatePicker(generateConfig: GenerateConfig) {
type DatePickerProps = PickerProps & {
@@ -68,23 +63,6 @@ export default function generatePicker(generateConfig: GenerateConfig<
}
};
- renderFeedback = (prefixCls: string) => (
-
- {({ hasFeedback, status: contextStatus }) => {
- const { status: customStatus } = this.props;
- const status = getMergedStatus(contextStatus, customStatus);
- return hasFeedback && getFeedbackIcon(prefixCls, status);
- }}
-
- );
-
- renderSuffix = (prefixCls: string, mergedPicker?: PickerMode) => (
- <>
- {mergedPicker === 'time' ? : }
- {this.renderFeedback(prefixCls)}
- >
- );
-
renderPicker = (contextLocale: PickerLocale) => {
const locale = { ...contextLocale, ...this.props.locale };
const { getPrefixCls, direction, getPopupContainer } = this.context;
@@ -128,42 +106,51 @@ export default function generatePicker(generateConfig: GenerateConfig<
return (
- {({ hasFeedback, status: contextStatus }) => (
-
- ref={this.pickerRef}
- placeholder={getPlaceholder(mergedPicker, locale, placeholder)}
- suffixIcon={this.renderSuffix(prefixCls, mergedPicker)}
- dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
- clearIcon={}
- prevIcon={}
- nextIcon={}
- superPrevIcon={}
- superNextIcon={}
- allowClear
- transitionName={`${rootPrefixCls}-slide-up`}
- {...additionalProps}
- {...restProps}
- {...additionalOverrideProps}
- locale={locale!.lang}
- className={classNames(
- {
- [`${prefixCls}-${mergedSize}`]: mergedSize,
- [`${prefixCls}-borderless`]: !bordered,
- },
- getStatusClassNames(
- prefixCls,
- getMergedStatus(contextStatus, customStatus),
- hasFeedback,
- ),
- className,
- )}
- prefixCls={prefixCls}
- getPopupContainer={customizeGetPopupContainer || getPopupContainer}
- generateConfig={generateConfig}
- components={Components}
- direction={direction}
- />
- )}
+ {({ hasFeedback, status: contextStatus, feedbackIcon }) => {
+ const suffixNode = (
+ <>
+ {mergedPicker === 'time' ? : }
+ {hasFeedback && feedbackIcon}
+ >
+ );
+
+ return (
+
+ ref={this.pickerRef}
+ placeholder={getPlaceholder(mergedPicker, locale, placeholder)}
+ suffixIcon={suffixNode}
+ dropdownAlign={transPlacement2DropdownAlign(direction, placement)}
+ clearIcon={}
+ prevIcon={}
+ nextIcon={}
+ superPrevIcon={}
+ superNextIcon={}
+ allowClear
+ transitionName={`${rootPrefixCls}-slide-up`}
+ {...additionalProps}
+ {...restProps}
+ {...additionalOverrideProps}
+ locale={locale!.lang}
+ className={classNames(
+ {
+ [`${prefixCls}-${mergedSize}`]: mergedSize,
+ [`${prefixCls}-borderless`]: !bordered,
+ },
+ getStatusClassNames(
+ prefixCls,
+ getMergedStatus(contextStatus, customStatus),
+ hasFeedback,
+ ),
+ className,
+ )}
+ prefixCls={prefixCls}
+ getPopupContainer={customizeGetPopupContainer || getPopupContainer}
+ generateConfig={generateConfig}
+ components={Components}
+ direction={direction}
+ />
+ );
+ }}
);
}}
diff --git a/components/date-picker/style/status.less b/components/date-picker/style/status.less
index be3adba330..4087bf5cf4 100644
--- a/components/date-picker/style/status.less
+++ b/components/date-picker/style/status.less
@@ -21,10 +21,6 @@
.active(@text-color, @hoverBorderColor, @outlineColor);
}
}
-
- .@{picker-prefix-cls}-feedback-icon {
- color: @text-color;
- }
}
.@{picker-prefix-cls} {
@@ -35,18 +31,4 @@
&-status-warning {
.picker-status-color(@warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
}
-
- &-status-validating {
- .@{picker-prefix-cls}-feedback-icon {
- display: inline-block;
- color: @primary-color;
- }
- }
-
- &-status-success {
- .@{picker-prefix-cls}-feedback-icon {
- color: @success-color;
- animation-name: diffZoomIn1 !important;
- }
- }
}
diff --git a/components/form/FormItem.tsx b/components/form/FormItem.tsx
index 2772ec5967..654c3af108 100644
--- a/components/form/FormItem.tsx
+++ b/components/form/FormItem.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { useContext, useMemo } from 'react';
+import { ReactNode, 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';
@@ -7,6 +7,10 @@ import { Meta, NamePath } from 'rc-field-form/lib/interface';
import { supportRef } from 'rc-util/lib/ref';
import useState from 'rc-util/lib/hooks/useState';
import omit from 'rc-util/lib/omit';
+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 Row from '../grid/row';
import { ConfigContext } from '../config-provider';
import { tuple } from '../_util/type';
@@ -88,6 +92,13 @@ function genEmptyMeta(): Meta {
};
}
+const iconMap = {
+ success: CheckCircleFilled,
+ warning: ExclamationCircleFilled,
+ error: CloseCircleFilled,
+ validating: LoadingOutlined,
+};
+
function FormItem(props: FormItemProps): React.ReactElement {
const {
name,
@@ -219,14 +230,29 @@ function FormItem(props: FormItemProps): React.ReactElemen
mergedValidateStatus = 'success';
}
- const formItemStatusContext = useMemo(
- () => ({
+ const formItemStatusContext = useMemo(() => {
+ let feedbackIcon: ReactNode;
+ if (hasFeedback) {
+ const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus];
+ feedbackIcon = IconNode ? (
+
+
+
+ ) : null;
+ }
+
+ return {
status: mergedValidateStatus,
hasFeedback,
+ feedbackIcon,
isFormItemInput: true,
- }),
- [mergedValidateStatus, hasFeedback],
- );
+ };
+ }, [mergedValidateStatus, hasFeedback]);
// ======================== Render ========================
function renderLayout(
diff --git a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap
index 50d6db95ec..79f3367bef 100644
--- a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap
+++ b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap
@@ -5188,7 +5188,7 @@ exports[`renders ./components/form/demo/register.md extend context correctly 1`]
class="ant-form-item-control-input-content"
>
-
+
+
@@ -22268,7 +22272,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
class="ant-form-item-control-input-content"
>
diff --git a/components/form/__tests__/__snapshots__/demo.test.js.snap b/components/form/__tests__/__snapshots__/demo.test.js.snap
index e785a95fcc..790218f1a6 100644
--- a/components/form/__tests__/__snapshots__/demo.test.js.snap
+++ b/components/form/__tests__/__snapshots__/demo.test.js.snap
@@ -4370,7 +4370,7 @@ exports[`renders ./components/form/demo/register.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
-
+
+
@@ -8998,7 +9002,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
class="ant-form-item-control-input-content"
>
diff --git a/components/form/context.tsx b/components/form/context.tsx
index 6ece4507a7..b355d47ab4 100644
--- a/components/form/context.tsx
+++ b/components/form/context.tsx
@@ -3,7 +3,7 @@ import omit from 'rc-util/lib/omit';
import { Meta } from 'rc-field-form/lib/interface';
import { FormProvider as RcFormProvider } from 'rc-field-form';
import { FormProviderProps as RcFormProviderProps } from 'rc-field-form/lib/FormContext';
-import { FC, PropsWithChildren, useMemo } from 'react';
+import { FC, PropsWithChildren, ReactNode, useMemo } from 'react';
import { ColProps } from '../grid/col';
import { FormLabelAlign } from './interface';
import { RequiredMark } from './Form';
@@ -56,6 +56,7 @@ export interface FormItemStatusContextProps {
isFormItemInput?: boolean;
status?: ValidateStatus;
hasFeedback?: boolean;
+ feedbackIcon?: ReactNode;
}
export const FormItemInputContext = React.createContext({});
diff --git a/components/form/style/index.less b/components/form/style/index.less
index a3920c5e42..6fe346d0fc 100644
--- a/components/form/style/index.less
+++ b/components/form/style/index.less
@@ -212,17 +212,38 @@
min-height: @form-item-margin-bottom;
}
- .@{ant-prefix}-input-textarea-show-count {
- &::after {
- margin-bottom: -22px;
- }
- }
-
&-with-help &-explain {
height: auto;
min-height: @form-item-margin-bottom;
opacity: 1;
}
+
+ // ==============================================================
+ // = Feedback Icon =
+ // ==============================================================
+ &-feedback-icon {
+ font-size: @font-size-base;
+ text-align: center;
+ visibility: visible;
+ animation: zoomIn 0.3s @ease-out-back;
+ pointer-events: none;
+
+ &-success {
+ color: @success-color;
+ }
+
+ &-error {
+ color: @error-color;
+ }
+
+ &-warning {
+ color: @warning-color;
+ }
+
+ &-validating {
+ color: @primary-color;
+ }
+ }
}
// >>>>>>>>>> Motion <<<<<<<<<<
diff --git a/components/input-number/index.tsx b/components/input-number/index.tsx
index 1e316022c2..85309a6df7 100644
--- a/components/input-number/index.tsx
+++ b/components/input-number/index.tsx
@@ -8,13 +8,8 @@ import { ConfigContext } from '../config-provider';
import SizeContext, { SizeType } from '../config-provider/SizeContext';
import { FormItemInputContext, NoFormStatus } from '../form/context';
import { cloneElement } from '../_util/reactNode';
-import {
- getFeedbackIcon,
- getStatusClassNames,
- InputStatus,
- getMergedStatus,
-} from '../_util/statusUtils';
import useStyle from './style';
+import { getStatusClassNames, InputStatus, getMergedStatus } from '../_util/statusUtils';
type ValueType = string | number;
@@ -76,7 +71,12 @@ const InputNumber = React.forwardRef((props,
);
}
- const { hasFeedback, status: contextStatus, isFormItemInput } = useContext(FormItemInputContext);
+ const {
+ hasFeedback,
+ status: contextStatus,
+ isFormItemInput,
+ feedbackIcon,
+ } = useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
const mergeSize = customizeSize || size;
@@ -144,9 +144,7 @@ const InputNumber = React.forwardRef((props,
props.onBlur?.(event);
},
})}
- {hasFeedback && (
- {getFeedbackIcon(prefixCls, mergedStatus)}
- )}
+ {hasFeedback && {feedbackIcon}}
);
}
diff --git a/components/input-number/style/status.less b/components/input-number/style/status.less
index df6255880c..f785da9ad6 100644
--- a/components/input-number/style/status.less
+++ b/components/input-number/style/status.less
@@ -18,22 +18,6 @@ each(@input-number-wrapper-cls, {
}
});
-.@{input-number-prefix-cls}-affix-wrapper {
- &-status-validating {
- .@{input-number-prefix-cls}-feedback-icon {
- display: inline-block;
- color: @primary-color;
- }
- }
-
- &-status-success {
- .@{input-number-prefix-cls}-feedback-icon {
- color: @success-color;
- animation-name: diffZoomIn1 !important;
- }
- }
-}
-
.@{input-number-prefix-cls}-group-wrapper {
&-status-error {
.group-status-color(@input-number-prefix-cls, @error-color, @error-color);
diff --git a/components/input/Input.tsx b/components/input/Input.tsx
index 6eaa1664d0..b04faf9f38 100644
--- a/components/input/Input.tsx
+++ b/components/input/Input.tsx
@@ -4,12 +4,7 @@ import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import classNames from 'classnames';
import { composeRef } from 'rc-util/lib/ref';
import SizeContext, { SizeType } from '../config-provider/SizeContext';
-import {
- getFeedbackIcon,
- getMergedStatus,
- getStatusClassNames,
- InputStatus,
-} from '../_util/statusUtils';
+import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
import { ConfigContext } from '../config-provider';
import { FormItemInputContext, NoFormStatus } from '../form/context';
import { hasPrefixSuffix } from './utils';
@@ -151,7 +146,7 @@ const Input = forwardRef((props, ref) => {
const mergedSize = customSize || size;
// ===================== Status =====================
- const { status: contextStatus, hasFeedback } = useContext(FormItemInputContext);
+ const { status: contextStatus, hasFeedback, feedbackIcon } = useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
// ===================== Focus warning =====================
@@ -202,7 +197,7 @@ const Input = forwardRef((props, ref) => {
const suffixNode = (hasFeedback || suffix) && (
<>
{suffix}
- {hasFeedback && getFeedbackIcon(prefixCls, mergedStatus)}
+ {hasFeedback && feedbackIcon}
>
);
diff --git a/components/input/TextArea.tsx b/components/input/TextArea.tsx
index c791a296cb..565360ae95 100644
--- a/components/input/TextArea.tsx
+++ b/components/input/TextArea.tsx
@@ -7,12 +7,7 @@ import * as React from 'react';
import { ConfigContext } from '../config-provider';
import SizeContext, { SizeType } from '../config-provider/SizeContext';
import { FormItemInputContext } from '../form/context';
-import {
- getFeedbackIcon,
- getStatusClassNames,
- InputStatus,
- getMergedStatus,
-} from '../_util/statusUtils';
+import { getStatusClassNames, InputStatus, getMergedStatus } from '../_util/statusUtils';
import ClearableLabeledInput from './ClearableLabeledInput';
import { fixControlledValue, InputFocusOptions, resolveOnChange, triggerFocus } from './Input';
import useStyle from './style';
@@ -80,7 +75,12 @@ const TextArea = React.forwardRef(
const { getPrefixCls, direction, iconPrefixCls } = React.useContext(ConfigContext);
const size = React.useContext(SizeContext);
- const { status: contextStatus, hasFeedback } = React.useContext(FormItemInputContext);
+ const {
+ status: contextStatus,
+ hasFeedback,
+ isFormItemInput,
+ feedbackIcon,
+ } = React.useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
const innerRef = React.useRef(null);
@@ -240,6 +240,7 @@ const TextArea = React.forwardRef(
{
[`${prefixCls}-textarea-rtl`]: direction === 'rtl',
[`${prefixCls}-textarea-show-count`]: showCount,
+ [`${prefixCls}-textarea-in-form-item`]: isFormItemInput,
},
getStatusClassNames(`${prefixCls}-textarea`, mergedStatus, hasFeedback),
className,
@@ -249,7 +250,7 @@ const TextArea = React.forwardRef(
data-count={dataCount}
>
{textareaNode}
- {hasFeedback && getFeedbackIcon(prefixCls, mergedStatus)}
+ {hasFeedback && {feedbackIcon}}
);
}
diff --git a/components/input/style/index.tsx b/components/input/style/index.tsx
index d502e655ca..077c7d1d41 100644
--- a/components/input/style/index.tsx
+++ b/components/input/style/index.tsx
@@ -96,7 +96,7 @@ export const genStatusStyle = (token: InputToken): CSSObject => {
}),
},
- [`.${prefixCls}-feedback-icon, .${prefixCls}-prefix`]: {
+ [`.${prefixCls}-prefix`]: {
color: colorError,
},
},
@@ -114,7 +114,7 @@ export const genStatusStyle = (token: InputToken): CSSObject => {
}),
},
- [`.${prefixCls}-feedback-icon, .${prefixCls}-prefix`]: {
+ [`.${prefixCls}-prefix`]: {
color: colorWarning,
},
},
@@ -510,22 +510,6 @@ const genInputStyle: GenerateStyle = (token: InputToken) => {
paddingBottom: 3, // FIXME: magic number
},
},
-
- '&-textarea-show-count': {
- // https://github.com/ant-design/ant-design/issues/33049
- [`> .${prefixCls}`]: {
- height: '100%',
- },
-
- '&::after': {
- textAlign: 'end',
- color: token.colorTextSecondary,
- whiteSpace: 'nowrap',
- content: 'attr(data-count)',
- pointerEvents: 'none',
- display: 'block',
- },
- },
},
};
};
@@ -633,6 +617,10 @@ const genAffixStyle: GenerateStyle = (token: InputToken) => {
display: 'flex',
flex: 'none',
alignItems: 'center',
+
+ '> *:not(:last-child)': {
+ marginInlineEnd: 8, // FIXME: magic number
+ },
},
'&-show-count-suffix': {
@@ -640,7 +628,7 @@ const genAffixStyle: GenerateStyle = (token: InputToken) => {
},
'&-show-count-has-suffix': {
- marginInlineEnd: 2, // FIXME: magic number
+ marginInlineEnd: token.marginXXS,
},
'&-prefix': {
@@ -667,18 +655,6 @@ const genAffixStyle: GenerateStyle = (token: InputToken) => {
// status
...genStatusStyle(token),
- '&-status-validating': {
- [`.${prefixCls}-feedback-icon`]: {
- display: 'inline-block',
- color: colorPrimary,
- },
- },
- '&-status-success': {
- [`.${prefixCls}-feedback-icon`]: {
- color: colorSuccess,
- // FIXME: animationName
- },
- },
},
};
};
@@ -834,7 +810,7 @@ const genTextAreaStyle: GenerateStyle = token => {
return {
[textareaPrefixCls]: {
- [`.${prefixCls}-feedback-icon`]: {
+ [`${textareaPrefixCls}-suffix`]: {
position: 'absolute',
top: 0,
insetInlineEnd: inputPaddingHorizontal,
@@ -855,6 +831,28 @@ const genTextAreaStyle: GenerateStyle = token => {
},
},
},
+
+ '&-show-count': {
+ // https://github.com/ant-design/ant-design/issues/33049
+ [`> .${prefixCls}`]: {
+ height: '100%',
+ },
+
+ '&::after': {
+ textAlign: 'end',
+ color: token.colorTextSecondary,
+ whiteSpace: 'nowrap',
+ content: 'attr(data-count)',
+ pointerEvents: 'none',
+ display: 'block',
+ },
+
+ [`&${textareaPrefixCls}-in-form-item`]: {
+ '&::after': {
+ marginBottom: -Math.floor(token.fontSize * token.lineHeight),
+ },
+ },
+ },
},
};
};
diff --git a/components/input/style/mixin.less b/components/input/style/mixin.less
index 75b9afea78..0263f9edbb 100644
--- a/components/input/style/mixin.less
+++ b/components/input/style/mixin.less
@@ -453,10 +453,6 @@
@hoverBorderColor: @primary-color-hover;
@outlineColor: @primary-color-outline;
) {
- .@{prefix-cls}-feedback-icon {
- color: @text-color;
- }
-
.@{prefix-cls}-prefix {
color: @text-color;
}
diff --git a/components/input/style/status.less b/components/input/style/status.less
index f3279d83ae..e6562e6024 100644
--- a/components/input/style/status.less
+++ b/components/input/style/status.less
@@ -18,47 +18,7 @@ each(@input-wrapper-cls, {
}
});
-.@{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,
diff --git a/components/mentions/index.tsx b/components/mentions/index.tsx
index f100555179..8bfc327671 100644
--- a/components/mentions/index.tsx
+++ b/components/mentions/index.tsx
@@ -6,13 +6,8 @@ import { composeRef } from 'rc-util/lib/ref';
import Spin from '../spin';
import { ConfigContext } from '../config-provider';
import { FormItemInputContext } from '../form/context';
-import {
- getFeedbackIcon,
- getMergedStatus,
- getStatusClassNames,
- InputStatus,
-} from '../_util/statusUtils';
import useStyle from './style';
+import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
export const { Option } = RcMentions;
@@ -72,7 +67,11 @@ const InternalMentions: React.ForwardRefRenderFunction =
const innerRef = React.useRef();
const mergedRef = composeRef(ref, innerRef);
const { getPrefixCls, renderEmpty, direction, iconPrefixCls } = React.useContext(ConfigContext);
- const { status: contextStatus, hasFeedback } = React.useContext(FormItemInputContext);
+ const {
+ status: contextStatus,
+ hasFeedback,
+ feedbackIcon,
+ } = React.useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
const onFocus: React.FocusEventHandler = (...args) => {
@@ -162,7 +161,7 @@ const InternalMentions: React.ForwardRefRenderFunction =
)}
>
{mentions}
- {getFeedbackIcon(prefixCls, mergedStatus)}
+ {feedbackIcon}
);
}
diff --git a/components/mentions/style/index.tsx b/components/mentions/style/index.tsx
index 9f7fe4b15c..495c7e0104 100644
--- a/components/mentions/style/index.tsx
+++ b/components/mentions/style/index.tsx
@@ -61,6 +61,17 @@ const genMentionsStyle: GenerateStyle = token => {
...genActiveStyle(token),
},
+ [`&-affix-wrapper ${mentionsCls}-suffix`]: {
+ position: 'absolute',
+ top: 0,
+ insetInlineEnd: inputPaddingHorizontal,
+ bottom: 0,
+ zIndex: 1,
+ display: 'inline-flex',
+ alignItems: 'center',
+ margin: 'auto',
+ },
+
// ================= Input Area =================
[`> textarea, ${mentionsCls}-measure`]: {
minHeight: controlHeight - 2,
diff --git a/components/mentions/style/status.less b/components/mentions/style/status.less
index 83cbb3ab8e..92d61e3378 100644
--- a/components/mentions/style/status.less
+++ b/components/mentions/style/status.less
@@ -13,31 +13,4 @@
.status-color(@mention-prefix-cls, @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);
}
-
- &-affix-wrapper {
- position: relative;
-
- .@{mention-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 {
- .@{mention-prefix-cls}-feedback-icon {
- color: @error-color;
- }
- }
-
- &-has-warning {
- .@{mention-prefix-cls}-feedback-icon {
- color: @warning-color;
- }
- }
- }
}
diff --git a/components/select/index.tsx b/components/select/index.tsx
index 2d798861d6..aee8caa20f 100755
--- a/components/select/index.tsx
+++ b/components/select/index.tsx
@@ -105,7 +105,12 @@ const InternalSelect = svg {
-// vertical-align: top;
-// }
-
-// &:not(.@{select-prefix-cls}-suffix) {
-// pointer-events: auto;
-// }
-// }
-
-// .@{select-prefix-cls}-disabled & {
-// cursor: not-allowed;
-// }
-// }
-
-// // ========================== Clear ==========================
-// &-clear {
-// position: absolute;
-// top: 50%;
-// right: @control-padding-horizontal - 1px;
-// z-index: 1;
-// display: inline-block;
-// width: @font-size-sm;
-// height: @font-size-sm;
-// margin-top: (-@font-size-sm / 2);
-// color: @disabled-color;
-// font-size: @font-size-sm;
-// font-style: normal;
-// line-height: 1;
-// text-align: center;
-// text-transform: none;
-// background: @select-clear-background;
-// cursor: pointer;
-// opacity: 0;
-// transition: color 0.3s ease, opacity 0.15s ease;
-// text-rendering: auto;
-
-// &::before {
-// display: block;
-// }
-
-// &:hover {
-// color: @text-color-secondary;
-// }
-
-// .@{select-prefix-cls}:hover & {
-// opacity: 1;
-// }
-// }
-
-// // ========================== Popup ==========================
-// &-dropdown {
-// .reset-component();
-// position: absolute;
-// top: -9999px;
-// left: -9999px;
-// z-index: @zindex-dropdown;
-// box-sizing: border-box;
-// padding: @select-dropdown-edge-child-vertical-padding 0;
-// overflow: hidden;
-// font-size: @font-size-base;
-// // Fix select render lag of long text in chrome
-// // https://github.com/ant-design/ant-design/issues/11456
-// // https://github.com/ant-design/ant-design/issues/11843
-// font-variant: initial;
-// background-color: @select-dropdown-bg;
-// border-radius: @border-radius-base;
-// outline: none;
-// box-shadow: @box-shadow-base;
-
-// &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomLeft,
-// &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomLeft {
-// animation-name: antSlideUpIn;
-// }
-
-// &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
-// &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft {
-// animation-name: antSlideDownIn;
-// }
-
-// &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomLeft {
-// animation-name: antSlideUpOut;
-// }
-
-// &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft {
-// animation-name: antSlideDownOut;
-// }
-
-// &-hidden {
-// display: none;
-// }
-
-// &-empty {
-// color: @disabled-color;
-// }
-// }
-
-// // ========================= Options =========================
-// .item() {
-// position: relative;
-// display: block;
-// min-height: @select-dropdown-height;
-// padding: @select-dropdown-vertical-padding @control-padding-horizontal;
-// color: @text-color;
-// font-weight: normal;
-// font-size: @select-dropdown-font-size;
-// line-height: @select-dropdown-line-height;
-// }
-
-// &-item-empty {
-// .item();
-// color: @disabled-color;
-// }
-
-// &-item {
-// .item();
-
-// cursor: pointer;
-// transition: background 0.3s ease;
-
-// // =========== Group ============
-// &-group {
-// color: @text-color-secondary;
-// font-size: @font-size-sm;
-// cursor: default;
-// }
-
-// // =========== Option ===========
-// &-option {
-// display: flex;
-
-// &-content {
-// flex: auto;
-// overflow: hidden;
-// white-space: nowrap;
-// text-overflow: ellipsis;
-// }
-
-// &-state {
-// flex: none;
-// }
-
-// &-active:not(&-disabled) {
-// background-color: @select-item-active-bg;
-// }
-
-// &-selected:not(&-disabled) {
-// color: @select-item-selected-color;
-// font-weight: @select-item-selected-font-weight;
-// background-color: @select-item-selected-bg;
-
-// .@{select-prefix-cls}-item-option-state {
-// color: @primary-color;
-// }
-// }
-
-// &-disabled {
-// &.@{select-prefix-cls}-item-option-selected {
-// background-color: @select-multiple-disabled-background;
-// }
-// color: @disabled-color;
-// cursor: not-allowed;
-// }
-
-// &-grouped {
-// padding-left: @control-padding-horizontal * 2;
-// }
-// }
-// }
-
-// // ============================================================
-// // == Size ==
-// // ============================================================
-// &-lg {
-// font-size: @font-size-lg;
-// }
-
-// // no border style
-// &-borderless &-selector {
-// background-color: transparent !important;
-// border-color: transparent !important;
-// box-shadow: none !important;
-// }
-// }
-
-// @import './rtl';
+//@import '../../style/themes/index';
+//@import '../../style/mixins/index';
+//@import '../../input/style/mixin';
+//@import './single';
+//@import './multiple';
+//@import './status';
+//
+//@select-prefix-cls: ~'@{ant-prefix}-select';
+//@select-height-without-border: @input-height-base - 2 * @border-width-base;
+//@select-dropdown-edge-child-vertical-padding: @dropdown-edge-child-vertical-padding;
+//
+//.select-selector() {
+// position: relative;
+// background-color: @select-background;
+// border: @border-width-base @border-style-base @select-border-color;
+// border-radius: @border-radius-base;
+// transition: all 0.3s @ease-in-out;
+//
+// input {
+// cursor: pointer;
+// }
+//
+// .@{select-prefix-cls}-show-search& {
+// cursor: text;
+//
+// input {
+// cursor: auto;
+// }
+// }
+//
+// .@{select-prefix-cls}-focused:not(.@{select-prefix-cls}-disabled)& {
+// .active();
+// }
+//
+// .@{select-prefix-cls}-disabled& {
+// color: @disabled-color;
+// background: @input-disabled-bg;
+// cursor: not-allowed;
+//
+// .@{select-prefix-cls}-multiple& {
+// background: @select-multiple-disabled-background;
+// }
+//
+// input {
+// cursor: not-allowed;
+// }
+// }
+//}
+//
+///* Reset search input style */
+//.select-search-input-without-border() {
+// .@{select-prefix-cls}-selection-search-input {
+// margin: 0;
+// padding: 0;
+// background: transparent;
+// border: none;
+// outline: none;
+// appearance: none;
+//
+// &::-webkit-search-cancel-button {
+// display: none;
+// /* stylelint-disable-next-line property-no-vendor-prefix */
+// -webkit-appearance: none;
+// }
+// }
+//}
+//
+//.@{select-prefix-cls} {
+// .reset-component();
+// position: relative;
+// display: inline-block;
+// cursor: pointer;
+//
+// &:not(&-customize-input) &-selector {
+// .select-selector();
+// .select-search-input-without-border();
+// }
+//
+// &:not(&-disabled):hover &-selector {
+// .hover();
+// }
+//
+// // ======================== Selection ========================
+// &-selection-item {
+// flex: 1;
+// overflow: hidden;
+// font-weight: normal;
+// white-space: nowrap;
+// text-overflow: ellipsis;
+//
+// // IE11 css hack. `*::-ms-backdrop,` is a must have
+// @media all and (-ms-high-contrast: none) {
+// *::-ms-backdrop,
+// & {
+// flex: auto;
+// }
+// }
+// }
+//
+// // ======================= Placeholder =======================
+// &-selection-placeholder {
+// flex: 1;
+// overflow: hidden;
+// color: @input-placeholder-color;
+// white-space: nowrap;
+// text-overflow: ellipsis;
+// pointer-events: none;
+//
+// // IE11 css hack. `*::-ms-backdrop,` is a must have
+// @media all and (-ms-high-contrast: none) {
+// *::-ms-backdrop,
+// & {
+// flex: auto;
+// }
+// }
+// }
+//
+// // ========================== Arrow ==========================
+// &-arrow {
+// .iconfont-mixin();
+// position: absolute;
+// top: 50%;
+// right: @control-padding-horizontal - 1px;
+// display: flex;
+// align-items: center;
+// height: @font-size-sm;
+// margin-top: (-@font-size-sm / 2);
+// color: @disabled-color;
+// font-size: @font-size-sm;
+// line-height: 1;
+// text-align: center;
+// pointer-events: none;
+//
+// .@{iconfont-css-prefix} {
+// vertical-align: top;
+// transition: transform 0.3s;
+//
+// > svg {
+// vertical-align: top;
+// }
+//
+// &:not(.@{select-prefix-cls}-suffix) {
+// pointer-events: auto;
+// }
+// }
+//
+// .@{select-prefix-cls}-disabled & {
+// cursor: not-allowed;
+// }
+// }
+//
+// // ========================== Clear ==========================
+// &-clear {
+// position: absolute;
+// top: 50%;
+// right: @control-padding-horizontal - 1px;
+// z-index: 1;
+// display: inline-block;
+// width: @font-size-sm;
+// height: @font-size-sm;
+// margin-top: (-@font-size-sm / 2);
+// color: @disabled-color;
+// font-size: @font-size-sm;
+// font-style: normal;
+// line-height: 1;
+// text-align: center;
+// text-transform: none;
+// background: @select-clear-background;
+// cursor: pointer;
+// opacity: 0;
+// transition: color 0.3s ease, opacity 0.15s ease;
+// text-rendering: auto;
+//
+// &::before {
+// display: block;
+// }
+//
+// &:hover {
+// color: @text-color-secondary;
+// }
+//
+// .@{select-prefix-cls}:hover & {
+// opacity: 1;
+// }
+// }
+//
+// // ========================== Popup ==========================
+// &-dropdown {
+// .reset-component();
+// position: absolute;
+// top: -9999px;
+// left: -9999px;
+// z-index: @zindex-dropdown;
+// box-sizing: border-box;
+// padding: @select-dropdown-edge-child-vertical-padding 0;
+// overflow: hidden;
+// font-size: @font-size-base;
+// // Fix select render lag of long text in chrome
+// // https://github.com/ant-design/ant-design/issues/11456
+// // https://github.com/ant-design/ant-design/issues/11843
+// font-variant: initial;
+// background-color: @select-dropdown-bg;
+// border-radius: @border-radius-base;
+// outline: none;
+// box-shadow: @box-shadow-base;
+//
+// &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-bottomLeft,
+// &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-bottomLeft {
+// animation-name: antSlideUpIn;
+// }
+//
+// &.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
+// &.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft {
+// animation-name: antSlideDownIn;
+// }
+//
+// &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-bottomLeft {
+// animation-name: antSlideUpOut;
+// }
+//
+// &.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft {
+// animation-name: antSlideDownOut;
+// }
+//
+// &-hidden {
+// display: none;
+// }
+//
+// &-empty {
+// color: @disabled-color;
+// }
+// }
+//
+// // ========================= Options =========================
+// .item() {
+// position: relative;
+// display: block;
+// min-height: @select-dropdown-height;
+// padding: @select-dropdown-vertical-padding @control-padding-horizontal;
+// color: @text-color;
+// font-weight: normal;
+// font-size: @select-dropdown-font-size;
+// line-height: @select-dropdown-line-height;
+// }
+//
+// &-item-empty {
+// .item();
+// color: @disabled-color;
+// }
+//
+// &-item {
+// .item();
+//
+// cursor: pointer;
+// transition: background 0.3s ease;
+//
+// // =========== Group ============
+// &-group {
+// color: @text-color-secondary;
+// font-size: @font-size-sm;
+// cursor: default;
+// }
+//
+// // =========== Option ===========
+// &-option {
+// display: flex;
+//
+// &-content {
+// flex: auto;
+// overflow: hidden;
+// white-space: nowrap;
+// text-overflow: ellipsis;
+// }
+//
+// &-state {
+// flex: none;
+// }
+//
+// &-active:not(&-disabled) {
+// background-color: @select-item-active-bg;
+// }
+//
+// &-selected:not(&-disabled) {
+// color: @select-item-selected-color;
+// font-weight: @select-item-selected-font-weight;
+// background-color: @select-item-selected-bg;
+//
+// .@{select-prefix-cls}-item-option-state {
+// color: @primary-color;
+// }
+// }
+//
+// &-disabled {
+// &.@{select-prefix-cls}-item-option-selected {
+// background-color: @select-multiple-disabled-background;
+// }
+// color: @disabled-color;
+// cursor: not-allowed;
+// }
+//
+// &-grouped {
+// padding-left: @control-padding-horizontal * 2;
+// }
+// }
+// }
+//
+// // ============================================================
+// // == Size ==
+// // ============================================================
+// &-lg {
+// font-size: @font-size-lg;
+// }
+//
+// // no border style
+// &-borderless &-selector {
+// background-color: transparent !important;
+// border-color: transparent !important;
+// box-shadow: none !important;
+// }
+//}
+//
+//@import './rtl';
diff --git a/components/select/style/index.tsx b/components/select/style/index.tsx
index 31b788bdc9..0c41dc38d9 100644
--- a/components/select/style/index.tsx
+++ b/components/select/style/index.tsx
@@ -179,7 +179,6 @@ const genBaseStyle: GenerateStyle = token => {
top: '50%',
insetInlineStart: 'auto',
insetInlineEnd: inputPaddingHorizontalBase,
- width: token.fontSizeSM,
height: token.fontSizeSM,
marginTop: -token.fontSizeSM / 2,
color: token.colorTextDisabled,
@@ -187,6 +186,8 @@ const genBaseStyle: GenerateStyle = token => {
lineHeight: 1,
textAlign: 'center',
pointerEvents: 'none',
+ display: 'flex',
+ alignItems: 'center',
[`.${iconPrefixCls}`]: {
verticalAlign: 'top',
@@ -204,6 +205,10 @@ const genBaseStyle: GenerateStyle = token => {
[`${selectCls}-disabled &`]: {
cursor: 'not-allowed',
},
+
+ '> *:not(:last-child)': {
+ marginInlineEnd: 8, // FIXME: magic
+ },
},
// ========================== Clear ==========================
@@ -248,23 +253,6 @@ const genBaseStyle: GenerateStyle = token => {
[`${selectCls}-clear`]: {
insetInlineEnd: token.padding * 2,
},
-
- // FIXME: what's this? @MadCcc
- [`${selectCls}-selection-selected-value`]: {
- paddingInlineEnd: 42,
- },
-
- [`${selectCls}-feedback-icon`]: {
- fontSize: token.fontSize,
- textAlign: 'center',
- visibility: 'visible',
- animation: `zoomIn ${token.motionDurationSlow} ${token.motionEaseOutBack}`,
- pointerEvents: 'none',
-
- '&:not(:first-child)': {
- marginInlineStart: token.marginXS,
- },
- },
},
};
};
diff --git a/components/select/style/status.less b/components/select/style/status.less
index 728b3e7acb..a746a04f62 100644
--- a/components/select/style/status.less
+++ b/components/select/style/status.less
@@ -19,10 +19,6 @@
.active(@border-color, @hoverBorderColor, @outlineColor);
}
}
-
- .@{select-prefix-cls}-feedback-icon {
- color: @text-color;
- }
}
.@{select-prefix-cls} {
@@ -34,18 +30,6 @@
.select-status-color(@warning-color, @warning-color, @input-bg, @warning-color-hover, @warning-color-outline);
}
- &-status-success {
- .@{select-prefix-cls}-feedback-icon {
- color: @success-color;
- }
- }
-
- &-status-validating {
- .@{select-prefix-cls}-feedback-icon {
- color: @primary-color;
- }
- }
-
&-status-error,
&-status-warning,
&-status-success,
@@ -61,16 +45,4 @@
}
}
}
-
- &-feedback-icon {
- font-size: @font-size-base;
- text-align: center;
- visibility: visible;
- animation: zoomIn 0.3s @ease-out-back;
- pointer-events: none;
-
- &:not(:first-child) {
- margin-left: 8px;
- }
- }
}
diff --git a/components/select/utils/iconUtil.tsx b/components/select/utils/iconUtil.tsx
index e6e8a7c094..72257c7150 100644
--- a/components/select/utils/iconUtil.tsx
+++ b/components/select/utils/iconUtil.tsx
@@ -6,8 +6,6 @@ import CheckOutlined from '@ant-design/icons/CheckOutlined';
import CloseOutlined from '@ant-design/icons/CloseOutlined';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import SearchOutlined from '@ant-design/icons/SearchOutlined';
-import { ValidateStatus } from '../../form/FormItem';
-import { getFeedbackIcon } from '../../_util/statusUtils';
export default function getIcons({
suffixIcon,
@@ -17,9 +15,9 @@ export default function getIcons({
loading,
multiple,
hasFeedback,
- status,
prefixCls,
showArrow,
+ feedbackIcon,
}: {
suffixIcon?: React.ReactNode;
clearIcon?: React.ReactNode;
@@ -28,7 +26,7 @@ export default function getIcons({
loading?: boolean;
multiple?: boolean;
hasFeedback?: boolean;
- status?: ValidateStatus;
+ feedbackIcon?: ReactNode;
prefixCls: string;
showArrow?: boolean;
}) {
@@ -42,7 +40,7 @@ export default function getIcons({
const getSuffixIconNode = (arrowIcon?: ReactNode) => (
<>
{showArrow !== false && arrowIcon}
- {hasFeedback && getFeedbackIcon(prefixCls, status)}
+ {hasFeedback && feedbackIcon}
>
);
diff --git a/components/tree-select/index.tsx b/components/tree-select/index.tsx
index 9a1be69133..eb674489e6 100644
--- a/components/tree-select/index.tsx
+++ b/components/tree-select/index.tsx
@@ -117,16 +117,21 @@ const InternalTreeSelect =