refactor: TextArea (#40045)

* refactor: TextArea

* chore: update snapshot

* chore: update snapshot

* chore: fix lint

* chore: classes

* refactor: mentions

* chore: bump rc-textarea

* chore: code clean

* chore: code clean

* chore: UPDATE SNAPSHOT

* chore: code clean

* test: cov

* fix: textarea size
This commit is contained in:
MadCcc 2023-01-11 14:18:13 +08:00 committed by GitHub
parent 3f87a2d263
commit 642bb582eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 759 additions and 885 deletions

View File

@ -8999,7 +8999,7 @@ exports[`renders ./components/form/demo/register.tsx extend context correctly 1`
class="ant-form-item-control-input-content"
>
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
data-count="0 / 100"
>
<textarea
@ -9007,6 +9007,11 @@ exports[`renders ./components/form/demo/register.tsx extend context correctly 1`
class="ant-input"
id="register_intro"
/>
<span
class="ant-input-data-count"
>
0 / 100
</span>
</div>
</div>
</div>
@ -26427,8 +26432,8 @@ exports[`renders ./components/form/demo/validate-static.tsx extend context corre
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-mentions-affix-wrapper ant-mentions-affix-wrapper-status-error ant-mentions-affix-wrapper-has-feedback"
<span
class="ant-mentions-affix-wrapper"
>
<div
class="ant-mentions ant-mentions-status-error"
@ -26465,7 +26470,7 @@ exports[`renders ./components/form/demo/validate-static.tsx extend context corre
</span>
</span>
</span>
</div>
</span>
</div>
</div>
</div>
@ -26497,62 +26502,76 @@ exports[`renders ./components/form/demo/validate-static.tsx extend context corre
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"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
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"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper ant-input-affix-wrapper-status-error"
>
<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"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix"
role="button"
tabindex="-1"
>
<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
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
class="ant-input-textarea-suffix"
>
<span
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<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>
<span
class="ant-input-textarea-suffix"
class="ant-input-data-count"
>
<span
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<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>
0
</span>
</div>
</div>

View File

@ -6098,7 +6098,7 @@ exports[`renders ./components/form/demo/register.tsx correctly 1`] = `
class="ant-form-item-control-input-content"
>
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
data-count="0 / 100"
>
<textarea
@ -6106,6 +6106,11 @@ exports[`renders ./components/form/demo/register.tsx correctly 1`] = `
class="ant-input"
id="register_intro"
/>
<span
class="ant-input-data-count"
>
0 / 100
</span>
</div>
</div>
</div>
@ -11022,8 +11027,8 @@ exports[`renders ./components/form/demo/validate-static.tsx correctly 1`] = `
<div
class="ant-form-item-control-input-content"
>
<div
class="ant-mentions-affix-wrapper ant-mentions-affix-wrapper-status-error ant-mentions-affix-wrapper-has-feedback"
<span
class="ant-mentions-affix-wrapper"
>
<div
class="ant-mentions ant-mentions-status-error"
@ -11060,7 +11065,7 @@ exports[`renders ./components/form/demo/validate-static.tsx correctly 1`] = `
</span>
</span>
</span>
</div>
</span>
</div>
</div>
</div>
@ -11092,62 +11097,76 @@ exports[`renders ./components/form/demo/validate-static.tsx correctly 1`] = `
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"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
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"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper ant-input-affix-wrapper-status-error"
>
<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"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix"
role="button"
tabindex="-1"
>
<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
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
class="ant-input-textarea-suffix"
>
<span
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<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>
<span
class="ant-input-textarea-suffix"
class="ant-input-data-count"
>
<span
class="ant-form-item-feedback-icon ant-form-item-feedback-icon-error"
>
<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>
0
</span>
</div>
</div>

View File

@ -1,137 +0,0 @@
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import classNames from 'classnames';
import * as React from 'react';
import type { DirectionType } from '../config-provider';
import type { SizeType } from '../config-provider/SizeContext';
import type { FormItemStatusContextProps } from '../form/context';
import { FormItemInputContext } from '../form/context';
import { cloneElement } from '../_util/reactNode';
import type { InputStatus } from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import type { InputProps } from './Input';
const ClearableInputType = ['text', 'input'] as const;
function hasAddon(props: InputProps | ClearableInputProps) {
return !!(props.addonBefore || props.addonAfter);
}
/** This basic props required for input and textarea. */
interface BasicProps {
prefixCls: string;
inputType: typeof ClearableInputType[number];
value?: any;
allowClear?: boolean;
element: React.ReactElement;
handleReset: (event: React.MouseEvent<HTMLElement, MouseEvent>) => void;
className?: string;
style?: React.CSSProperties;
disabled?: boolean;
direction?: DirectionType;
focused?: boolean;
readOnly?: boolean;
bordered: boolean;
hidden?: boolean;
}
/** This props only for input. */
export interface ClearableInputProps extends BasicProps {
size?: SizeType;
suffix?: React.ReactNode;
prefix?: React.ReactNode;
addonBefore?: React.ReactNode;
addonAfter?: React.ReactNode;
triggerFocus?: () => void;
status?: InputStatus;
hashId?: string;
}
class ClearableLabeledInput extends React.Component<ClearableInputProps> {
renderClearIcon(prefixCls: string) {
const { value, disabled, readOnly, handleReset, suffix } = this.props;
const needClear = !disabled && !readOnly && value;
const className = `${prefixCls}-clear-icon`;
return (
<CloseCircleFilled
onClick={handleReset}
// Do not trigger onBlur when clear input
// https://github.com/ant-design/ant-design/issues/31200
onMouseDown={(e) => e.preventDefault()}
className={classNames(
{
[`${className}-hidden`]: !needClear,
[`${className}-has-suffix`]: !!suffix,
},
className,
)}
role="button"
/>
);
}
renderTextAreaWithClearIcon(
prefixCls: string,
element: React.ReactElement,
statusContext: FormItemStatusContextProps,
) {
const {
value,
allowClear,
className,
style,
direction,
bordered,
hidden,
status: customStatus,
hashId,
} = this.props;
const { status: contextStatus, hasFeedback } = statusContext;
if (!allowClear) {
return cloneElement(element, {
value,
});
}
const affixWrapperCls = classNames(
`${prefixCls}-affix-wrapper`,
`${prefixCls}-affix-wrapper-textarea-with-clear-btn`,
getStatusClassNames(
`${prefixCls}-affix-wrapper`,
getMergedStatus(contextStatus, customStatus),
hasFeedback,
),
{
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
// className will go to addon wrapper
[`${className}`]: !hasAddon(this.props) && className,
},
hashId,
);
return (
<span className={affixWrapperCls} style={style} hidden={hidden}>
{cloneElement(element, {
style: null,
value,
})}
{this.renderClearIcon(prefixCls)}
</span>
);
}
render() {
return (
<FormItemInputContext.Consumer>
{(statusContext) => {
const { prefixCls, inputType, element } = this.props;
if (inputType === ClearableInputType[0]) {
return this.renderTextAreaWithClearIcon(prefixCls, element, statusContext);
}
}}
</FormItemInputContext.Consumer>
);
}
}
export default ClearableLabeledInput;

View File

@ -26,67 +26,6 @@ export interface InputFocusOptions extends FocusOptions {
export type { InputRef };
export function fixControlledValue<T>(value: T) {
if (typeof value === 'undefined' || value === null) {
return '';
}
return String(value);
}
export function resolveOnChange<E extends HTMLInputElement | HTMLTextAreaElement>(
target: E,
e:
| React.ChangeEvent<E>
| React.MouseEvent<HTMLElement, MouseEvent>
| React.CompositionEvent<HTMLElement>,
onChange: undefined | ((event: React.ChangeEvent<E>) => void),
targetValue?: string,
) {
if (!onChange) {
return;
}
let event = e as React.ChangeEvent<E>;
if (e.type === 'click') {
// Clone a new target for event.
// Avoid the following usage, the setQuery method gets the original value.
//
// const [query, setQuery] = React.useState('');
// <Input
// allowClear
// value={query}
// onChange={(e)=> {
// setQuery((prevStatus) => e.target.value);
// }}
// />
const currentTarget = target.cloneNode(true) as E;
// click clear icon
event = Object.create(e, {
target: { value: currentTarget },
currentTarget: { value: currentTarget },
});
currentTarget.value = '';
onChange(event);
return;
}
// Trigger by composition event, this means we need force change the input value
if (targetValue !== undefined) {
event = Object.create(e, {
target: { value: target },
currentTarget: { value: target },
});
target.value = targetValue;
onChange(event);
return;
}
onChange(event);
}
export function triggerFocus(
element?: HTMLInputElement | HTMLTextAreaElement,
option?: InputFocusOptions,
@ -246,41 +185,43 @@ const Input = forwardRef<InputRef, InputProps>((props, ref) => {
</NoCompactStyle>
)
}
inputClassName={classNames(
{
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-lg`]: mergedSize === 'large',
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-borderless`]: !bordered,
},
!inputHasPrefixSuffix && getStatusClassNames(prefixCls, mergedStatus),
hashId,
)}
affixWrapperClassName={classNames(
{
[`${prefixCls}-affix-wrapper-sm`]: mergedSize === 'small',
[`${prefixCls}-affix-wrapper-lg`]: mergedSize === 'large',
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
},
getStatusClassNames(`${prefixCls}-affix-wrapper`, mergedStatus, hasFeedback),
hashId,
)}
wrapperClassName={classNames(
{
[`${prefixCls}-group-rtl`]: direction === 'rtl',
},
hashId,
)}
groupClassName={classNames(
{
[`${prefixCls}-group-wrapper-sm`]: mergedSize === 'small',
[`${prefixCls}-group-wrapper-lg`]: mergedSize === 'large',
[`${prefixCls}-group-wrapper-rtl`]: direction === 'rtl',
},
getStatusClassNames(`${prefixCls}-group-wrapper`, mergedStatus, hasFeedback),
hashId,
)}
classes={{
input: classNames(
{
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-lg`]: mergedSize === 'large',
[`${prefixCls}-rtl`]: direction === 'rtl',
[`${prefixCls}-borderless`]: !bordered,
},
!inputHasPrefixSuffix && getStatusClassNames(prefixCls, mergedStatus),
hashId,
),
affixWrapper: classNames(
{
[`${prefixCls}-affix-wrapper-sm`]: mergedSize === 'small',
[`${prefixCls}-affix-wrapper-lg`]: mergedSize === 'large',
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
},
getStatusClassNames(`${prefixCls}-affix-wrapper`, mergedStatus, hasFeedback),
hashId,
),
wrapper: classNames(
{
[`${prefixCls}-group-rtl`]: direction === 'rtl',
},
hashId,
),
group: classNames(
{
[`${prefixCls}-group-wrapper-sm`]: mergedSize === 'small',
[`${prefixCls}-group-wrapper-lg`]: mergedSize === 'large',
[`${prefixCls}-group-wrapper-rtl`]: direction === 'rtl',
},
getStatusClassNames(`${prefixCls}-group-wrapper`, mergedStatus, hasFeedback),
hashId,
),
}}
/>,
);
});

View File

@ -1,91 +1,58 @@
import classNames from 'classnames';
import type { TextAreaProps as RcTextAreaProps } from 'rc-textarea';
import RcTextArea from 'rc-textarea';
import type { ResizableTextAreaRef } from 'rc-textarea/lib/ResizableTextArea';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import omit from 'rc-util/lib/omit';
import type { TextAreaProps as RcTextAreaProps } from 'rc-textarea/lib/interface';
import type { TextAreaRef as RcTextAreaRef } from 'rc-textarea';
import { forwardRef } from 'react';
import * as React from 'react';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import RcTextArea from 'rc-textarea';
import classNames from 'classnames';
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
import type { BaseInputProps } from 'rc-input/lib/interface';
import { FormItemInputContext } from '../form/context';
import useStyle from './style';
import type { SizeType } from '../config-provider/SizeContext';
import SizeContext from '../config-provider/SizeContext';
import { FormItemInputContext } from '../form/context';
import type { InputStatus } from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import ClearableLabeledInput from './ClearableLabeledInput';
import type { InputFocusOptions } from './Input';
import { fixControlledValue, resolveOnChange, triggerFocus } from './Input';
import useStyle from './style';
import { triggerFocus } from './Input';
import DisabledContext from '../config-provider/DisabledContext';
import { ConfigContext } from '../config-provider';
interface ShowCountProps {
formatter: (args: { value: string; count: number; maxLength?: number }) => string;
}
function fixEmojiLength(value: string, maxLength: number) {
return [...(value || '')].slice(0, maxLength).join('');
}
function setTriggerValue(
isCursorInEnd: boolean,
preValue: string,
triggerValue: string,
maxLength: number,
) {
let newTriggerValue = triggerValue;
if (isCursorInEnd) {
// 光标在尾部,直接截断
newTriggerValue = fixEmojiLength(triggerValue, maxLength!);
} else if (
[...(preValue || '')].length < triggerValue.length &&
[...(triggerValue || '')].length > maxLength!
) {
// 光标在中间,如果最后的值超过最大值,则采用原先的值
newTriggerValue = preValue;
}
return newTriggerValue;
}
export interface TextAreaProps extends RcTextAreaProps {
allowClear?: boolean;
export interface TextAreaProps extends Omit<RcTextAreaProps, 'suffix'> {
bordered?: boolean;
showCount?: boolean | ShowCountProps;
size?: SizeType;
disabled?: boolean;
status?: InputStatus;
}
export interface TextAreaRef {
focus: (options?: InputFocusOptions) => void;
blur: () => void;
resizableTextArea?: ResizableTextAreaRef;
resizableTextArea?: RcTextAreaRef['resizableTextArea'];
}
const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
const TextArea = forwardRef<TextAreaRef, TextAreaProps>(
(
{
prefixCls: customizePrefixCls,
bordered = true,
showCount = false,
maxLength,
className,
style,
size: customizeSize,
disabled: customDisabled,
onCompositionStart,
onCompositionEnd,
onChange,
status: customStatus,
...props
allowClear,
...rest
},
ref,
) => {
const { getPrefixCls, direction } = React.useContext(ConfigContext);
// ===================== Size =====================
const size = React.useContext(SizeContext);
const mergedSize = customizeSize || size;
// ===================== Disabled =====================
const disabled = React.useContext(DisabledContext);
const mergedDisabled = customDisabled ?? disabled;
// ===================== Status =====================
const {
status: contextStatus,
hasFeedback,
@ -93,87 +60,8 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
} = React.useContext(FormItemInputContext);
const mergedStatus = getMergedStatus(contextStatus, customStatus);
const innerRef = React.useRef<RcTextArea>(null);
const clearableInputRef = React.useRef<ClearableLabeledInput>(null);
const [compositing, setCompositing] = React.useState(false);
const oldCompositionValueRef = React.useRef<string>();
const oldSelectionStartRef = React.useRef<number>(0);
const [value, setValue] = useMergedState(props.defaultValue, {
value: props.value,
});
const { hidden } = props;
const handleSetValue = (val: string, callback?: () => void) => {
if (props.value === undefined) {
setValue(val);
callback?.();
}
};
// =========================== Value Update ===========================
// Max length value
const hasMaxLength = Number(maxLength) > 0;
const onInternalCompositionStart: React.CompositionEventHandler<HTMLTextAreaElement> = (e) => {
setCompositing(true);
// 拼音输入前保存一份旧值
oldCompositionValueRef.current = value as string;
// 保存旧的光标位置
oldSelectionStartRef.current = e.currentTarget.selectionStart;
onCompositionStart?.(e);
};
const onInternalCompositionEnd: React.CompositionEventHandler<HTMLTextAreaElement> = (e) => {
setCompositing(false);
let triggerValue = e.currentTarget.value;
if (hasMaxLength) {
const isCursorInEnd =
oldSelectionStartRef.current >= maxLength! + 1 ||
oldSelectionStartRef.current === oldCompositionValueRef.current?.length;
triggerValue = setTriggerValue(
isCursorInEnd,
oldCompositionValueRef.current as string,
triggerValue,
maxLength!,
);
}
// Patch composition onChange when value changed
if (triggerValue !== value) {
handleSetValue(triggerValue);
resolveOnChange(e.currentTarget, e, onChange, triggerValue);
}
onCompositionEnd?.(e);
};
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
let triggerValue = e.target.value;
if (!compositing && hasMaxLength) {
// 1. 复制粘贴超过maxlength的情况 2.未超过maxlength的情况
const isCursorInEnd =
e.target.selectionStart >= maxLength! + 1 ||
e.target.selectionStart === triggerValue.length ||
!e.target.selectionStart;
triggerValue = setTriggerValue(isCursorInEnd, value as string, triggerValue, maxLength!);
}
handleSetValue(triggerValue);
resolveOnChange(e.currentTarget, e, onChange, triggerValue);
};
// ============================== Reset ===============================
const handleReset = (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
handleSetValue('');
innerRef.current?.focus();
resolveOnChange(innerRef.current?.resizableTextArea?.textArea!, e, onChange);
};
const prefixCls = getPrefixCls('input', customizePrefixCls);
// Style
const [wrapSSR, hashId] = useStyle(prefixCls);
// ===================== Ref =====================
const innerRef = React.useRef<RcTextAreaRef>(null);
React.useImperativeHandle(ref, () => ({
resizableTextArea: innerRef.current?.resizableTextArea,
@ -183,89 +71,58 @@ const TextArea = React.forwardRef<TextAreaRef, TextAreaProps>(
blur: () => innerRef.current?.blur(),
}));
const textArea = (
const prefixCls = getPrefixCls('input', customizePrefixCls);
// Allow clear
let mergedAllowClear: BaseInputProps['allowClear'];
if (typeof allowClear === 'object' && allowClear?.clearIcon) {
mergedAllowClear = allowClear;
} else if (allowClear) {
mergedAllowClear = { clearIcon: <CloseCircleFilled /> };
}
// ===================== Style =====================
const [wrapSSR, hashId] = useStyle(prefixCls);
return wrapSSR(
<RcTextArea
{...omit(props, ['allowClear'])}
{...rest}
disabled={mergedDisabled}
className={classNames(
{
[`${prefixCls}-borderless`]: !bordered,
[className!]: className && !showCount,
[`${prefixCls}-sm`]: size === 'small' || customizeSize === 'small',
[`${prefixCls}-lg`]: size === 'large' || customizeSize === 'large',
},
getStatusClassNames(prefixCls, mergedStatus),
hashId,
)}
style={showCount ? { resize: style?.resize } : style}
prefixCls={prefixCls}
onCompositionStart={onInternalCompositionStart}
onChange={handleChange}
onCompositionEnd={onInternalCompositionEnd}
ref={innerRef}
/>
);
let val = fixControlledValue(value) as string;
if (!compositing && hasMaxLength && (props.value === null || props.value === undefined)) {
// fix #27612 将value转为数组进行截取解决 '😂'.length === 2 等emoji表情导致的截取乱码的问题
val = fixEmojiLength(val, maxLength!);
}
// TextArea
const textareaNode = (
<ClearableLabeledInput
disabled={mergedDisabled}
{...props}
prefixCls={prefixCls}
direction={direction}
inputType="text"
value={val}
element={textArea}
handleReset={handleReset}
ref={clearableInputRef}
bordered={bordered}
status={customStatus}
style={showCount ? undefined : style}
hashId={hashId}
/>
);
// Only show text area wrapper when needed
if (showCount || hasFeedback) {
const valueLength = [...val].length;
let dataCount = '';
if (typeof showCount === 'object') {
dataCount = showCount.formatter({ value: val, count: valueLength, maxLength });
} else {
dataCount = `${valueLength}${hasMaxLength ? ` / ${maxLength}` : ''}`;
}
return (
<div
hidden={hidden}
className={classNames(
`${prefixCls}-textarea`,
allowClear={mergedAllowClear}
classes={{
affixWrapper: classNames(
`${prefixCls}-textarea-affix-wrapper`,
{
[`${prefixCls}-textarea-rtl`]: direction === 'rtl',
[`${prefixCls}-textarea-show-count`]: showCount,
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
[`${prefixCls}-affix-wrapper-sm`]: mergedSize === 'small',
[`${prefixCls}-affix-wrapper-lg`]: mergedSize === 'large',
},
getStatusClassNames(`${prefixCls}-textarea`, mergedStatus, hasFeedback),
className,
getStatusClassNames(`${prefixCls}-affix-wrapper`, mergedStatus),
hashId,
)}
style={style}
data-count={dataCount}
>
{textareaNode}
{hasFeedback && <span className={`${prefixCls}-textarea-suffix`}>{feedbackIcon}</span>}
</div>
);
}
return wrapSSR(textareaNode);
),
countWrapper: classNames(
`${prefixCls}-textarea`,
`${prefixCls}-textarea-show-count`,
hashId,
),
textarea: classNames(
{
[`${prefixCls}-borderless`]: !bordered,
[`${prefixCls}-sm`]: mergedSize === 'small',
[`${prefixCls}-lg`]: mergedSize === 'large',
},
getStatusClassNames(prefixCls, mergedStatus),
hashId,
),
}}
prefixCls={prefixCls}
suffix={
hasFeedback && <span className={`${prefixCls}-textarea-suffix`}>{feedbackIcon}</span>
}
ref={innerRef}
/>,
);
},
);

View File

@ -4902,31 +4902,40 @@ Array [
<br />,
<br />,
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
placeholder="textarea with clear icon"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>,
]
@ -4994,31 +5003,40 @@ exports[`renders ./components/input/demo/borderless-debug.tsx extend context cor
placeholder="Unbordered"
/>
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn ant-input-affix-wrapper-borderless"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper ant-input-affix-wrapper-borderless"
>
<textarea
class="ant-input ant-input-borderless"
placeholder="Unbordered"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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
@ -5100,31 +5118,40 @@ exports[`renders ./components/input/demo/borderless-debug.tsx extend context cor
</span>
</span>
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
style="border:2px solid #000"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
@ -9707,12 +9734,17 @@ Array [
<br />,
<br />,
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
data-count="0 / 100"
>
<textarea
class="ant-input"
/>
<span
class="ant-input-data-count"
>
0 / 100
</span>
</div>,
]
`;
@ -9970,31 +10002,40 @@ Array [
The autoSize property applies to textarea nodes, and only the height changes automatically. In addition, autoSize can be set to an object, specifying the minimum number of rows and the maximum number of rows. The autoSize property applies to textarea nodes, and only the height changes automatically. In addition, autoSize can be set to an object, specifying the minimum number of rows and the maximum number of rows.
</textarea>,
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
style="width:93px"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>,
]
@ -10003,7 +10044,7 @@ Array [
exports[`renders ./components/input/demo/textarea-show-count.tsx extend context correctly 1`] = `
Array [
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
data-count="0 / 100"
style="height:120px;margin-bottom:24px"
>
@ -10011,9 +10052,14 @@ Array [
class="ant-input"
placeholder="can resize"
/>
<span
class="ant-input-data-count"
>
0 / 100
</span>
</div>,
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
data-count="0 / 100"
style="height:120px;resize:none"
>
@ -10022,6 +10068,11 @@ Array [
placeholder="disable resize"
style="resize:none"
/>
<span
class="ant-input-data-count"
>
0 / 100
</span>
</div>,
]
`;

View File

@ -1103,31 +1103,40 @@ Array [
<br />,
<br />,
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
placeholder="textarea with clear icon"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>,
]
@ -1195,31 +1204,40 @@ exports[`renders ./components/input/demo/borderless-debug.tsx correctly 1`] = `
placeholder="Unbordered"
/>
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn ant-input-affix-wrapper-borderless"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper ant-input-affix-wrapper-borderless"
>
<textarea
class="ant-input ant-input-borderless"
placeholder="Unbordered"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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
@ -1301,31 +1319,40 @@ exports[`renders ./components/input/demo/borderless-debug.tsx correctly 1`] = `
</span>
</span>
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
style="border:2px solid #000"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
@ -3455,12 +3482,17 @@ Array [
<br />,
<br />,
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
data-count="0 / 100"
>
<textarea
class="ant-input"
/>
<span
class="ant-input-data-count"
>
0 / 100
</span>
</div>,
]
`;
@ -3718,31 +3750,40 @@ Array [
The autoSize property applies to textarea nodes, and only the height changes automatically. In addition, autoSize can be set to an object, specifying the minimum number of rows and the maximum number of rows. The autoSize property applies to textarea nodes, and only the height changes automatically. In addition, autoSize can be set to an object, specifying the minimum number of rows and the maximum number of rows.
</textarea>,
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
style="width:93px"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>,
]
@ -3751,7 +3792,7 @@ Array [
exports[`renders ./components/input/demo/textarea-show-count.tsx correctly 1`] = `
Array [
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
data-count="0 / 100"
style="height:120px;margin-bottom:24px"
>
@ -3759,9 +3800,14 @@ Array [
class="ant-input"
placeholder="can resize"
/>
<span
class="ant-input-data-count"
>
0 / 100
</span>
</div>,
<div
class="ant-input-textarea ant-input-textarea-show-count"
class="ant-input-show-count ant-input-textarea ant-input-textarea-show-count"
data-count="0 / 100"
style="height:120px;resize:none"
>
@ -3770,6 +3816,11 @@ Array [
placeholder="disable resize"
style="resize:none"
/>
<span
class="ant-input-data-count"
>
0 / 100
</span>
</div>,
]
`;

View File

@ -2,7 +2,7 @@
exports[`TextArea allowClear should change type when click 1`] = `
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
@ -10,234 +10,306 @@ exports[`TextArea allowClear should change type when click 1`] = `
111
</textarea>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon"
role="button"
tabindex="-1"
>
<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
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>
`;
exports[`TextArea allowClear should change type when click 2`] = `
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
`;
exports[`TextArea allowClear should not show icon if defaultValue is undefined, null or empty string 1`] = `
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
`;
exports[`TextArea allowClear should not show icon if defaultValue is undefined, null or empty string 2`] = `
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
`;
exports[`TextArea allowClear should not show icon if defaultValue is undefined, null or empty string 3`] = `
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
`;
exports[`TextArea allowClear should not show icon if value is undefined, null or empty string 1`] = `
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
`;
exports[`TextArea allowClear should not show icon if value is undefined, null or empty string 2`] = `
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
`;
exports[`TextArea allowClear should not show icon if value is undefined, null or empty string 3`] = `
<span
class="ant-input-affix-wrapper ant-input-affix-wrapper-textarea-with-clear-btn"
class="ant-input-affix-wrapper ant-input-textarea-affix-wrapper"
>
<textarea
class="ant-input"
/>
<span
aria-label="close-circle"
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
role="button"
tabindex="-1"
class="ant-input-suffix"
>
<svg
aria-hidden="true"
data-icon="close-circle"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
<span
class="ant-input-clear-icon ant-input-clear-icon-hidden"
role="button"
tabindex="-1"
>
<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
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>
`;

View File

@ -574,4 +574,9 @@ describe('TextArea allowClear', () => {
textareaSpy.mockRestore();
});
it('should support custom clearIcon', () => {
const { container } = render(<TextArea allowClear={{ clearIcon: 'clear' }} />);
expect(container.querySelector('.ant-input-clear-icon')?.textContent).toBe('clear');
});
});

View File

@ -562,19 +562,6 @@ const genAllowClearStyle = (token: InputToken): CSSObject => {
margin: `0 ${token.inputAffixPadding}px`,
},
},
// ======================= TextArea ========================
'&-textarea-with-clear-btn': {
padding: '0 !important',
border: '0 !important',
[`${componentCls}-clear-icon`]: {
position: 'absolute',
insetBlockStart: token.paddingXS,
insetInlineEnd: token.paddingXS,
zIndex: 1,
},
},
};
};
@ -870,53 +857,79 @@ export function initInputToken<T extends GlobalToken = GlobalToken>(token: T): I
}
const genTextAreaStyle: GenerateStyle<InputToken> = (token) => {
const { componentCls, inputPaddingHorizontal, paddingLG } = token;
const { componentCls, paddingLG } = token;
const textareaPrefixCls = `${componentCls}-textarea`;
return {
[textareaPrefixCls]: {
position: 'relative',
[`${textareaPrefixCls}-suffix`]: {
position: 'absolute',
top: 0,
insetInlineEnd: inputPaddingHorizontal,
bottom: 0,
zIndex: 1,
display: 'inline-flex',
alignItems: 'center',
margin: 'auto',
},
[`&-status-error,
&-status-warning,
&-status-success,
&-status-validating`]: {
[`&${textareaPrefixCls}-has-feedback`]: {
[`${componentCls}`]: {
paddingInlineEnd: paddingLG,
},
},
},
'&-show-count': {
// https://github.com/ant-design/ant-design/issues/33049
[`> ${componentCls}`]: {
height: '100%',
},
'&::after': {
[`${componentCls}-data-count`]: {
color: token.colorTextDescription,
whiteSpace: 'nowrap',
content: 'attr(data-count)',
pointerEvents: 'none',
float: 'right',
marginBottom: -token.fontSize * token.lineHeight,
},
'&-rtl': {
[`${componentCls}-data-count`]: {
float: 'left',
},
},
},
'&-rtl': {
'&::after': {
float: 'left',
[`&-affix-wrapper${textareaPrefixCls}-has-feedback`]: {
[`${componentCls}`]: {
paddingInlineEnd: paddingLG,
},
},
[`&-affix-wrapper${componentCls}-affix-wrapper`]: {
padding: 0,
[`> textarea${componentCls}`]: {
fontSize: 'inherit',
border: 'none',
outline: 'none',
'&:focus': {
boxShadow: 'none !important',
},
},
[`${componentCls}-suffix`]: {
margin: 0,
'> *:not(:last-child)': {
marginInline: 0,
},
// Clear Icon
[`${componentCls}-clear-icon`]: {
position: 'absolute',
insetInlineEnd: token.paddingXS,
insetBlockStart: token.paddingXS,
},
// Feedback Icon
[`${textareaPrefixCls}-suffix`]: {
position: 'absolute',
top: 0,
insetInlineEnd: token.inputPaddingHorizontal,
bottom: 0,
zIndex: 1,
display: 'inline-flex',
alignItems: 'center',
margin: 'auto',
pointerEvents: 'none',
},
},
},
},

View File

@ -1,7 +1,6 @@
import type { ClearableInputProps } from './ClearableLabeledInput';
import type { InputProps } from './Input';
// eslint-disable-next-line import/prefer-default-export
export function hasPrefixSuffix(props: InputProps | ClearableInputProps) {
export function hasPrefixSuffix(props: InputProps) {
return !!(props.prefix || props.suffix || props.allowClear);
}

View File

@ -35,7 +35,7 @@ export interface OptionProps {
[key: string]: any;
}
export interface MentionProps extends RcMentionsProps {
export interface MentionProps extends Omit<RcMentionsProps, 'suffix'> {
loading?: boolean;
status?: InputStatus;
options?: MentionsOptionProps[];
@ -44,10 +44,6 @@ export interface MentionProps extends RcMentionsProps {
export interface MentionsRef extends RcMentionsRef {}
export interface MentionState {
focused: boolean;
}
interface MentionsConfig {
prefix?: string | string[];
split?: string;
@ -179,27 +175,15 @@ const InternalMentions: React.ForwardRefRenderFunction<MentionsRef, MentionProps
dropdownClassName={classNames(popupClassName, hashId)}
ref={mergedRef as any}
options={mergedOptions}
suffix={hasFeedback && feedbackIcon}
classes={{
affixWrapper: classNames(hashId, className),
}}
>
{getOptions()}
</RcMentions>
);
if (hasFeedback) {
return (
<div
className={classNames(
`${prefixCls}-affix-wrapper`,
getStatusClassNames(`${prefixCls}-affix-wrapper`, mergedStatus, hasFeedback),
className,
hashId,
)}
>
{mentions}
<span className={`${prefixCls}-suffix`}>{feedbackIcon}</span>
</div>
);
}
return wrapSSR(mentions);
};

View File

@ -4,7 +4,7 @@ import EditOutlined from '@ant-design/icons/EditOutlined';
import classNames from 'classnames';
import copy from 'copy-to-clipboard';
import ResizeObserver from 'rc-resize-observer';
import type { AutoSizeType } from 'rc-textarea/lib/ResizableTextArea';
import type { AutoSizeType } from 'rc-textarea';
import toArray from 'rc-util/lib/Children/toArray';
import useIsomorphicLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect';
import useMergedState from 'rc-util/lib/hooks/useMergedState';

View File

@ -1,6 +1,6 @@
import EnterOutlined from '@ant-design/icons/EnterOutlined';
import classNames from 'classnames';
import type { AutoSizeType } from 'rc-textarea/lib/ResizableTextArea';
import type { AutoSizeType } from 'rc-textarea';
import KeyCode from 'rc-util/lib/KeyCode';
import * as React from 'react';
import type { DirectionType } from '../config-provider';

View File

@ -127,9 +127,9 @@
"rc-dropdown": "~4.0.0",
"rc-field-form": "~1.27.0",
"rc-image": "~5.13.0",
"rc-input": "~0.1.4",
"rc-input": "~0.2.1",
"rc-input-number": "~7.4.0",
"rc-mentions": "~1.13.1",
"rc-mentions": "~2.0.0",
"rc-menu": "~9.8.0",
"rc-motion": "^2.6.1",
"rc-notification": "~5.0.0",
@ -145,7 +145,7 @@
"rc-switch": "~4.0.0",
"rc-table": "~7.30.2",
"rc-tabs": "~12.5.1",
"rc-textarea": "~0.4.5",
"rc-textarea": "~1.0.0",
"rc-tooltip": "~5.2.0",
"rc-tree": "~5.7.0",
"rc-tree-select": "~5.6.0",