mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-07 09:26:06 +08:00
feat: introduce rc-input (#34206)
* feat: introduce rc-input * fix: export InputRef alias * docs: fix demo * chore: code clean * test: fix lint * test: test coverage * chore: code clean * chore: code clean * test: update snapshot
This commit is contained in:
parent
faff0ec888
commit
bfebb88bdb
@ -107,7 +107,7 @@ exports[`renders ./components/auto-complete/demo/certain-category.md extend cont
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-select-selection-search-input"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-select-selection-search-input ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -1989,7 +1989,7 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md extend co
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-input-search-with-button ant-select-selection-search-input"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-select-selection-search-input ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
|
@ -79,7 +79,7 @@ exports[`renders ./components/auto-complete/demo/certain-category.md correctly 1
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-select-selection-search-input"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-select-selection-search-input ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -1118,7 +1118,7 @@ exports[`renders ./components/auto-complete/demo/uncertain-category.md correctly
|
||||
class="ant-select-selection-search"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-input-search-with-button ant-select-selection-search-input"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-select-selection-search-input ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
|
@ -13744,7 +13744,7 @@ exports[`ConfigProvider components Input configProvider componentSize large 1`]
|
||||
value=""
|
||||
/>
|
||||
<span
|
||||
class="config-input-group-wrapper config-input-group-wrapper-lg config-input-search config-input-search-large"
|
||||
class="config-input-group-wrapper config-input-search config-input-search-large config-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="config-input-wrapper config-input-group"
|
||||
@ -13786,11 +13786,11 @@ exports[`ConfigProvider components Input configProvider componentSize large 1`]
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="config-input-affix-wrapper config-input-affix-wrapper-lg config-input-password"
|
||||
class="config-input-affix-wrapper config-input-password config-input-affix-wrapper-lg"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
class="config-input config-input-lg"
|
||||
class="config-input"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
|
@ -20704,10 +20704,14 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -20723,6 +20727,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
@ -20875,10 +20880,14 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -20894,6 +20903,7 @@ exports[`renders ./components/form/demo/validate-static.md extend context correc
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-label="eye-invisible"
|
||||
class="anticon anticon-eye-invisible ant-input-password-icon"
|
||||
|
@ -8531,10 +8531,14 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -8550,6 +8554,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-feedback-icon"
|
||||
>
|
||||
@ -8702,10 +8707,14 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden ant-input-clear-icon-has-suffix"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -8721,6 +8730,7 @@ exports[`renders ./components/form/demo/validate-static.md correctly 1`] = `
|
||||
/>
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
aria-label="eye-invisible"
|
||||
class="anticon anticon-eye-invisible ant-input-password-icon"
|
||||
|
@ -92,7 +92,7 @@ export { default as Form } from './form';
|
||||
|
||||
export { default as Grid } from './grid';
|
||||
|
||||
export type { InputProps } from './input';
|
||||
export type { InputProps, InputRef } from './input';
|
||||
export { default as Input } from './input';
|
||||
|
||||
export type { ImageProps } from './image';
|
||||
|
@ -8,7 +8,6 @@ import { cloneElement } from '../_util/reactNode';
|
||||
import { getMergedStatus, getStatusClassNames, InputStatus } from '../_util/statusUtils';
|
||||
import { tuple } from '../_util/type';
|
||||
import type { InputProps } from './Input';
|
||||
import { getInputClassName, hasPrefixSuffix } from './utils';
|
||||
|
||||
const ClearableInputType = tuple('text', 'input');
|
||||
|
||||
@ -46,21 +45,8 @@ export interface ClearableInputProps extends BasicProps {
|
||||
}
|
||||
|
||||
class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
/** @private Do Not use out of this class. We do not promise this is always keep. */
|
||||
private containerRef = React.createRef<HTMLSpanElement>();
|
||||
|
||||
onInputMouseUp: React.MouseEventHandler = e => {
|
||||
if (this.containerRef.current?.contains(e.target as Element)) {
|
||||
const { triggerFocus } = this.props;
|
||||
triggerFocus?.();
|
||||
}
|
||||
};
|
||||
|
||||
renderClearIcon(prefixCls: string) {
|
||||
const { allowClear, value, disabled, readOnly, handleReset, suffix } = this.props;
|
||||
if (!allowClear) {
|
||||
return null;
|
||||
}
|
||||
const { value, disabled, readOnly, handleReset, suffix } = this.props;
|
||||
const needClear = !disabled && !readOnly && value;
|
||||
const className = `${prefixCls}-clear-icon`;
|
||||
return (
|
||||
@ -81,151 +67,6 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
);
|
||||
}
|
||||
|
||||
renderSuffix(prefixCls: string) {
|
||||
const { suffix, allowClear } = this.props;
|
||||
if (suffix || allowClear) {
|
||||
return (
|
||||
<span className={`${prefixCls}-suffix`}>
|
||||
{this.renderClearIcon(prefixCls)}
|
||||
{suffix}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
renderLabeledIcon(
|
||||
prefixCls: string,
|
||||
element: React.ReactElement,
|
||||
statusContext: FormItemStatusContextProps,
|
||||
) {
|
||||
const {
|
||||
focused,
|
||||
value,
|
||||
prefix,
|
||||
className,
|
||||
size,
|
||||
suffix,
|
||||
disabled,
|
||||
allowClear,
|
||||
direction,
|
||||
style,
|
||||
readOnly,
|
||||
bordered,
|
||||
hidden,
|
||||
status: customStatus,
|
||||
} = this.props;
|
||||
|
||||
const { status: contextStatus, hasFeedback } = statusContext;
|
||||
|
||||
if (!hasPrefixSuffix(this.props)) {
|
||||
return cloneElement(element, {
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
||||
const suffixNode = this.renderSuffix(prefixCls);
|
||||
const prefixNode = prefix ? <span className={`${prefixCls}-prefix`}>{prefix}</span> : null;
|
||||
|
||||
const affixWrapperCls = classNames(
|
||||
`${prefixCls}-affix-wrapper`,
|
||||
{
|
||||
[`${prefixCls}-affix-wrapper-focused`]: focused,
|
||||
[`${prefixCls}-affix-wrapper-disabled`]: disabled,
|
||||
[`${prefixCls}-affix-wrapper-sm`]: size === 'small',
|
||||
[`${prefixCls}-affix-wrapper-lg`]: size === 'large',
|
||||
[`${prefixCls}-affix-wrapper-input-with-clear-btn`]: suffix && allowClear && value,
|
||||
[`${prefixCls}-affix-wrapper-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-affix-wrapper-readonly`]: readOnly,
|
||||
[`${prefixCls}-affix-wrapper-borderless`]: !bordered,
|
||||
// className will go to addon wrapper
|
||||
[`${className}`]: !hasAddon(this.props) && className,
|
||||
},
|
||||
getStatusClassNames(
|
||||
`${prefixCls}-affix-wrapper`,
|
||||
getMergedStatus(contextStatus, customStatus),
|
||||
hasFeedback,
|
||||
),
|
||||
);
|
||||
return (
|
||||
<span
|
||||
ref={this.containerRef}
|
||||
className={affixWrapperCls}
|
||||
style={style}
|
||||
onMouseUp={this.onInputMouseUp}
|
||||
hidden={hidden}
|
||||
>
|
||||
{prefixNode}
|
||||
{cloneElement(element, {
|
||||
style: null,
|
||||
value,
|
||||
className: getInputClassName(prefixCls, bordered, size, disabled),
|
||||
})}
|
||||
{suffixNode}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
renderInputWithLabel(
|
||||
prefixCls: string,
|
||||
labeledElement: React.ReactElement,
|
||||
statusContext: FormItemStatusContextProps,
|
||||
) {
|
||||
const {
|
||||
addonBefore,
|
||||
addonAfter,
|
||||
style,
|
||||
size,
|
||||
className,
|
||||
direction,
|
||||
hidden,
|
||||
status: customStatus,
|
||||
} = this.props;
|
||||
const { status: contextStatus, hasFeedback } = statusContext;
|
||||
// Not wrap when there is not addons
|
||||
if (!hasAddon(this.props)) {
|
||||
return labeledElement;
|
||||
}
|
||||
|
||||
const wrapperClassName = `${prefixCls}-group`;
|
||||
const addonClassName = `${wrapperClassName}-addon`;
|
||||
const addonBeforeNode = addonBefore ? (
|
||||
<span className={addonClassName}>{addonBefore}</span>
|
||||
) : null;
|
||||
const addonAfterNode = addonAfter ? <span className={addonClassName}>{addonAfter}</span> : null;
|
||||
|
||||
const mergedWrapperClassName = classNames(`${prefixCls}-wrapper`, wrapperClassName, {
|
||||
[`${wrapperClassName}-rtl`]: direction === 'rtl',
|
||||
});
|
||||
|
||||
const mergedGroupClassName = classNames(
|
||||
`${prefixCls}-group-wrapper`,
|
||||
{
|
||||
[`${prefixCls}-group-wrapper-sm`]: size === 'small',
|
||||
[`${prefixCls}-group-wrapper-lg`]: size === 'large',
|
||||
[`${prefixCls}-group-wrapper-rtl`]: direction === 'rtl',
|
||||
},
|
||||
getStatusClassNames(
|
||||
`${prefixCls}-group-wrapper`,
|
||||
getMergedStatus(contextStatus, customStatus),
|
||||
hasFeedback,
|
||||
),
|
||||
className,
|
||||
);
|
||||
|
||||
// Need another wrapper for changing display:table to display:inline-block
|
||||
// and put style prop in wrapper
|
||||
return (
|
||||
<span className={mergedGroupClassName} style={style} hidden={hidden}>
|
||||
<span className={mergedWrapperClassName}>
|
||||
{addonBeforeNode}
|
||||
{cloneElement(labeledElement, { style: null })}
|
||||
{addonAfterNode}
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
renderTextAreaWithClearIcon(
|
||||
prefixCls: string,
|
||||
element: React.ReactElement,
|
||||
@ -283,11 +124,6 @@ class ClearableLabeledInput extends React.Component<ClearableInputProps> {
|
||||
if (inputType === ClearableInputType[0]) {
|
||||
return this.renderTextAreaWithClearIcon(prefixCls, element, statusContext);
|
||||
}
|
||||
return this.renderInputWithLabel(
|
||||
prefixCls,
|
||||
this.renderLabeledIcon(prefixCls, element, statusContext),
|
||||
statusContext,
|
||||
);
|
||||
}}
|
||||
</FormItemStatusContext.Consumer>
|
||||
);
|
||||
|
@ -1,69 +1,25 @@
|
||||
import * as React from 'react';
|
||||
import React, { forwardRef, useContext, useEffect, useRef } from 'react';
|
||||
import RcInput, { InputProps as RcInputProps, InputRef } from 'rc-input';
|
||||
import CloseCircleFilled from '@ant-design/icons/CloseCircleFilled';
|
||||
import classNames from 'classnames';
|
||||
import omit from 'rc-util/lib/omit';
|
||||
import { ValidateStatus } from '../form/FormItem';
|
||||
import type Group from './Group';
|
||||
import type Search from './Search';
|
||||
import type TextArea from './TextArea';
|
||||
import type Password from './Password';
|
||||
import { LiteralUnion } from '../_util/type';
|
||||
import ClearableLabeledInput from './ClearableLabeledInput';
|
||||
import { ConfigConsumer, ConfigConsumerProps, DirectionType } from '../config-provider';
|
||||
import { composeRef } from 'rc-util/lib/ref';
|
||||
import SizeContext, { SizeType } from '../config-provider/SizeContext';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import { getInputClassName, hasPrefixSuffix } from './utils';
|
||||
import {
|
||||
getFeedbackIcon,
|
||||
getMergedStatus,
|
||||
getStatusClassNames,
|
||||
InputStatus,
|
||||
} from '../_util/statusUtils';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import { FormItemStatusContext } from '../form/context';
|
||||
import { getFeedbackIcon, InputStatus, getMergedStatus } from '../_util/statusUtils';
|
||||
import { hasPrefixSuffix } from './utils';
|
||||
import devWarning from '../_util/devWarning';
|
||||
|
||||
export interface InputFocusOptions extends FocusOptions {
|
||||
cursor?: 'start' | 'end' | 'all';
|
||||
}
|
||||
|
||||
export interface ShowCountProps {
|
||||
formatter: (args: { count: number; maxLength?: number }) => React.ReactNode;
|
||||
}
|
||||
|
||||
export interface InputProps
|
||||
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix' | 'type'> {
|
||||
prefixCls?: string;
|
||||
size?: SizeType;
|
||||
// ref: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#%3Cinput%3E_types
|
||||
type?: LiteralUnion<
|
||||
| 'button'
|
||||
| 'checkbox'
|
||||
| 'color'
|
||||
| 'date'
|
||||
| 'datetime-local'
|
||||
| 'email'
|
||||
| 'file'
|
||||
| 'hidden'
|
||||
| 'image'
|
||||
| 'month'
|
||||
| 'number'
|
||||
| 'password'
|
||||
| 'radio'
|
||||
| 'range'
|
||||
| 'reset'
|
||||
| 'search'
|
||||
| 'submit'
|
||||
| 'tel'
|
||||
| 'text'
|
||||
| 'time'
|
||||
| 'url'
|
||||
| 'week',
|
||||
string
|
||||
>;
|
||||
onPressEnter?: React.KeyboardEventHandler<HTMLInputElement>;
|
||||
addonBefore?: React.ReactNode;
|
||||
addonAfter?: React.ReactNode;
|
||||
prefix?: React.ReactNode;
|
||||
suffix?: React.ReactNode;
|
||||
allowClear?: boolean;
|
||||
showCount?: boolean | ShowCountProps;
|
||||
bordered?: boolean;
|
||||
htmlSize?: number;
|
||||
status?: InputStatus;
|
||||
}
|
||||
export type { InputRef };
|
||||
|
||||
export function fixControlledValue<T>(value: T) {
|
||||
if (typeof value === 'undefined' || value === null) {
|
||||
@ -154,303 +110,133 @@ export function triggerFocus(
|
||||
}
|
||||
}
|
||||
|
||||
export interface InputState {
|
||||
value: any;
|
||||
focused: boolean;
|
||||
/** `value` from prev props */
|
||||
prevValue: any;
|
||||
export interface InputProps
|
||||
extends Omit<
|
||||
RcInputProps,
|
||||
'wrapperClassName' | 'groupClassName' | 'inputClassName' | 'affixWrapperClassName' | 'clearIcon'
|
||||
> {
|
||||
size?: SizeType;
|
||||
status?: InputStatus;
|
||||
bordered?: boolean;
|
||||
}
|
||||
|
||||
class Input extends React.Component<InputProps, InputState> {
|
||||
static Group: typeof Group;
|
||||
const Input = forwardRef<InputRef, InputProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
bordered = true,
|
||||
status: customStatus,
|
||||
size: customSize,
|
||||
onBlur,
|
||||
onFocus,
|
||||
suffix,
|
||||
...rest
|
||||
} = props;
|
||||
const { getPrefixCls, direction, input } = React.useContext(ConfigContext);
|
||||
|
||||
static Search: typeof Search;
|
||||
const prefixCls = getPrefixCls('input', customizePrefixCls);
|
||||
const inputRef = useRef<InputRef>(null);
|
||||
|
||||
static TextArea: typeof TextArea;
|
||||
// ===================== Status =====================
|
||||
const size = React.useContext(SizeContext);
|
||||
const mergedSize = customSize || size;
|
||||
|
||||
static Password: typeof Password;
|
||||
// ===================== Status =====================
|
||||
const { status: contextStatus, hasFeedback } = useContext(FormItemStatusContext);
|
||||
const mergedStatus = getMergedStatus(contextStatus, customStatus);
|
||||
|
||||
static defaultProps = {
|
||||
type: 'text',
|
||||
};
|
||||
|
||||
input!: HTMLInputElement;
|
||||
|
||||
clearableInput!: ClearableLabeledInput;
|
||||
|
||||
removePasswordTimeout: any;
|
||||
|
||||
direction: DirectionType = 'ltr';
|
||||
|
||||
constructor(props: InputProps) {
|
||||
super(props);
|
||||
const value = typeof props.value === 'undefined' ? props.defaultValue : props.value;
|
||||
this.state = {
|
||||
value,
|
||||
focused: false,
|
||||
// eslint-disable-next-line react/no-unused-state
|
||||
prevValue: props.value,
|
||||
};
|
||||
}
|
||||
|
||||
static getDerivedStateFromProps(nextProps: InputProps, { prevValue }: InputState) {
|
||||
const newState: Partial<InputState> = { prevValue: nextProps.value };
|
||||
if (nextProps.value !== undefined || prevValue !== nextProps.value) {
|
||||
newState.value = nextProps.value;
|
||||
}
|
||||
if (nextProps.disabled) {
|
||||
newState.focused = false;
|
||||
}
|
||||
return newState;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.clearPasswordValueAttribute();
|
||||
}
|
||||
|
||||
// Since polyfill `getSnapshotBeforeUpdate` need work with `componentDidUpdate`.
|
||||
// We keep an empty function here.
|
||||
componentDidUpdate() {}
|
||||
|
||||
getSnapshotBeforeUpdate(prevProps: InputProps) {
|
||||
if (hasPrefixSuffix(prevProps) !== hasPrefixSuffix(this.props)) {
|
||||
// ===================== Focus warning =====================
|
||||
const inputHasPrefixSuffix = hasPrefixSuffix(props);
|
||||
const prevHasPrefixSuffix = useRef<boolean>(inputHasPrefixSuffix);
|
||||
useEffect(() => {
|
||||
if (inputHasPrefixSuffix && !prevHasPrefixSuffix.current) {
|
||||
devWarning(
|
||||
this.input !== document.activeElement,
|
||||
document.activeElement === inputRef.current?.input,
|
||||
'Input',
|
||||
`When Input is focused, dynamic add or remove prefix / suffix will make it lose focus caused by dom structure change. Read more: https://ant.design/components/input/#FAQ`,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
prevHasPrefixSuffix.current = inputHasPrefixSuffix;
|
||||
}, [inputHasPrefixSuffix]);
|
||||
|
||||
componentWillUnmount() {
|
||||
if (this.removePasswordTimeout) {
|
||||
clearTimeout(this.removePasswordTimeout);
|
||||
// ===================== Remove Password value =====================
|
||||
const removePasswordTimeoutRef = useRef<number[]>([]);
|
||||
const removePasswordTimeout = () => {
|
||||
removePasswordTimeoutRef.current.push(
|
||||
window.setTimeout(() => {
|
||||
if (
|
||||
inputRef.current?.input &&
|
||||
inputRef.current?.input.getAttribute('type') === 'password' &&
|
||||
inputRef.current?.input.hasAttribute('value')
|
||||
) {
|
||||
inputRef.current?.input.removeAttribute('value');
|
||||
}
|
||||
}
|
||||
|
||||
focus = (option?: InputFocusOptions) => {
|
||||
triggerFocus(this.input, option);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
blur() {
|
||||
this.input.blur();
|
||||
}
|
||||
useEffect(() => {
|
||||
removePasswordTimeout();
|
||||
return () => removePasswordTimeoutRef.current.forEach(item => window.clearTimeout(item));
|
||||
}, []);
|
||||
|
||||
setSelectionRange(start: number, end: number, direction?: 'forward' | 'backward' | 'none') {
|
||||
this.input.setSelectionRange(start, end, direction);
|
||||
}
|
||||
|
||||
select() {
|
||||
this.input.select();
|
||||
}
|
||||
|
||||
saveClearableInput = (input: ClearableLabeledInput) => {
|
||||
this.clearableInput = input;
|
||||
};
|
||||
|
||||
saveInput = (input: HTMLInputElement) => {
|
||||
this.input = input;
|
||||
};
|
||||
|
||||
onFocus: React.FocusEventHandler<HTMLInputElement> = e => {
|
||||
const { onFocus } = this.props;
|
||||
this.setState({ focused: true }, this.clearPasswordValueAttribute);
|
||||
onFocus?.(e);
|
||||
};
|
||||
|
||||
onBlur: React.FocusEventHandler<HTMLInputElement> = e => {
|
||||
const { onBlur } = this.props;
|
||||
this.setState({ focused: false }, this.clearPasswordValueAttribute);
|
||||
const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||
removePasswordTimeout();
|
||||
onBlur?.(e);
|
||||
};
|
||||
|
||||
setValue(value: string, callback?: () => void) {
|
||||
if (this.props.value === undefined) {
|
||||
this.setState({ value }, callback);
|
||||
} else {
|
||||
callback?.();
|
||||
}
|
||||
}
|
||||
|
||||
handleReset = (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
||||
this.setValue('', () => {
|
||||
this.focus();
|
||||
});
|
||||
resolveOnChange(this.input, e, this.props.onChange);
|
||||
const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
|
||||
removePasswordTimeout();
|
||||
onFocus?.(e);
|
||||
};
|
||||
|
||||
renderInput = (
|
||||
prefixCls: string,
|
||||
size: SizeType | undefined,
|
||||
bordered: boolean,
|
||||
status?: ValidateStatus,
|
||||
input: ConfigConsumerProps['input'] = {},
|
||||
) => {
|
||||
const {
|
||||
className,
|
||||
addonBefore,
|
||||
addonAfter,
|
||||
size: customizeSize,
|
||||
disabled,
|
||||
htmlSize,
|
||||
} = this.props;
|
||||
// Fix https://fb.me/react-unknown-prop
|
||||
const otherProps = omit(this.props as InputProps & { inputType: any }, [
|
||||
'prefixCls',
|
||||
'onPressEnter',
|
||||
'addonBefore',
|
||||
'addonAfter',
|
||||
'prefix',
|
||||
'suffix',
|
||||
'allowClear',
|
||||
// Input elements must be either controlled or uncontrolled,
|
||||
// specify either the value prop, or the defaultValue prop, but not both.
|
||||
'defaultValue',
|
||||
'size',
|
||||
'inputType',
|
||||
'bordered',
|
||||
'htmlSize',
|
||||
'showCount',
|
||||
'status',
|
||||
]);
|
||||
|
||||
return (
|
||||
<input
|
||||
autoComplete={input.autoComplete}
|
||||
{...otherProps}
|
||||
onChange={this.handleChange}
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
className={classNames(
|
||||
getInputClassName(
|
||||
prefixCls,
|
||||
bordered,
|
||||
customizeSize || size,
|
||||
disabled,
|
||||
this.direction,
|
||||
status,
|
||||
),
|
||||
{
|
||||
[className!]: className && !addonBefore && !addonAfter,
|
||||
},
|
||||
)}
|
||||
ref={this.saveInput}
|
||||
size={htmlSize}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
clearPasswordValueAttribute = () => {
|
||||
// https://github.com/ant-design/ant-design/issues/20541
|
||||
this.removePasswordTimeout = setTimeout(() => {
|
||||
if (
|
||||
this.input &&
|
||||
this.input.getAttribute('type') === 'password' &&
|
||||
this.input.hasAttribute('value')
|
||||
) {
|
||||
this.input.removeAttribute('value');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setValue(e.target.value, this.clearPasswordValueAttribute);
|
||||
resolveOnChange(this.input, e, this.props.onChange);
|
||||
};
|
||||
|
||||
handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
|
||||
const { onPressEnter, onKeyDown } = this.props;
|
||||
if (onPressEnter && e.keyCode === 13) {
|
||||
onPressEnter(e);
|
||||
}
|
||||
onKeyDown?.(e);
|
||||
};
|
||||
|
||||
renderShowCountSuffix = (prefixCls: string) => {
|
||||
const { value } = this.state;
|
||||
const { maxLength, suffix, showCount } = this.props;
|
||||
// Max length value
|
||||
const hasMaxLength = Number(maxLength) > 0;
|
||||
|
||||
if (suffix || showCount) {
|
||||
const valueLength = [...fixControlledValue(value)].length;
|
||||
let dataCount = null;
|
||||
if (typeof showCount === 'object') {
|
||||
dataCount = showCount.formatter({ count: valueLength, maxLength });
|
||||
} else {
|
||||
dataCount = `${valueLength}${hasMaxLength ? ` / ${maxLength}` : ''}`;
|
||||
}
|
||||
return (
|
||||
!!showCount && (
|
||||
<span
|
||||
className={classNames(`${prefixCls}-show-count-suffix`, {
|
||||
[`${prefixCls}-show-count-has-suffix`]: !!suffix,
|
||||
})}
|
||||
>
|
||||
{dataCount}
|
||||
</span>
|
||||
)
|
||||
);
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
renderSuffix = (prefixCls: string, hasFeedback?: boolean, status?: ValidateStatus) => {
|
||||
const { suffix, showCount } = this.props;
|
||||
|
||||
return (
|
||||
(showCount || suffix || hasFeedback) && (
|
||||
const suffixNode = (hasFeedback || suffix) && (
|
||||
<>
|
||||
{this.renderShowCountSuffix(prefixCls)}
|
||||
{suffix}
|
||||
{hasFeedback && getFeedbackIcon(prefixCls, status)}
|
||||
{hasFeedback && getFeedbackIcon(prefixCls, mergedStatus)}
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
renderComponent = ({ getPrefixCls, direction, input }: ConfigConsumerProps) => {
|
||||
const { value, focused } = this.state;
|
||||
const { prefixCls: customizePrefixCls, bordered = true, status: customStatus } = this.props;
|
||||
const prefixCls = getPrefixCls('input', customizePrefixCls);
|
||||
this.direction = direction;
|
||||
|
||||
return (
|
||||
<SizeContext.Consumer>
|
||||
{size => (
|
||||
<FormItemStatusContext.Consumer>
|
||||
{({ status: contextStatus, hasFeedback }) => {
|
||||
const mergedStatus = getMergedStatus(contextStatus, customStatus);
|
||||
|
||||
return (
|
||||
<ClearableLabeledInput
|
||||
size={size}
|
||||
{...this.props}
|
||||
<RcInput
|
||||
ref={composeRef(ref, inputRef)}
|
||||
prefixCls={prefixCls}
|
||||
inputType="input"
|
||||
value={fixControlledValue(value)}
|
||||
element={this.renderInput(prefixCls, size, bordered, mergedStatus, input)}
|
||||
handleReset={this.handleReset}
|
||||
ref={this.saveClearableInput}
|
||||
direction={direction}
|
||||
focused={focused}
|
||||
triggerFocus={this.focus}
|
||||
bordered={bordered}
|
||||
suffix={this.renderSuffix(prefixCls, hasFeedback, mergedStatus)}
|
||||
autoComplete={input?.autoComplete}
|
||||
{...rest}
|
||||
onBlur={handleBlur}
|
||||
onFocus={handleFocus}
|
||||
suffix={suffixNode}
|
||||
clearIcon={<CloseCircleFilled />}
|
||||
inputClassName={classNames(
|
||||
{
|
||||
[`${prefixCls}-sm`]: mergedSize === 'small',
|
||||
[`${prefixCls}-lg`]: mergedSize === 'large',
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
},
|
||||
getStatusClassNames(prefixCls, mergedStatus),
|
||||
)}
|
||||
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),
|
||||
)}
|
||||
wrapperClassName={classNames({
|
||||
[`${prefixCls}-group-rtl`]: direction === 'rtl',
|
||||
})}
|
||||
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),
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</FormItemStatusContext.Consumer>
|
||||
)}
|
||||
</SizeContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
return <ConfigConsumer>{this.renderComponent}</ConfigConsumer>;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default Input;
|
||||
|
@ -5,8 +5,8 @@ import EyeOutlined from '@ant-design/icons/EyeOutlined';
|
||||
import EyeInvisibleOutlined from '@ant-design/icons/EyeInvisibleOutlined';
|
||||
|
||||
import { useState } from 'react';
|
||||
import Input, { InputRef, InputProps } from './Input';
|
||||
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
|
||||
import Input, { InputProps } from './Input';
|
||||
|
||||
export interface PasswordProps extends InputProps {
|
||||
readonly inputPrefixCls?: string;
|
||||
@ -20,7 +20,7 @@ const ActionMap: Record<string, string> = {
|
||||
hover: 'onMouseOver',
|
||||
};
|
||||
|
||||
const Password = React.forwardRef<any, PasswordProps>((props, ref) => {
|
||||
const Password = React.forwardRef<InputRef, PasswordProps>((props, ref) => {
|
||||
const [visible, setVisible] = useState(false);
|
||||
|
||||
const onVisibleChange = () => {
|
||||
|
@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { composeRef } from 'rc-util/lib/ref';
|
||||
import SearchOutlined from '@ant-design/icons/SearchOutlined';
|
||||
import Input, { InputProps } from './Input';
|
||||
import Input, { InputProps, InputRef } from './Input';
|
||||
import Button from '../button';
|
||||
import SizeContext from '../config-provider/SizeContext';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
@ -21,7 +21,7 @@ export interface SearchProps extends InputProps {
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
const Search = React.forwardRef<Input, SearchProps>((props, ref) => {
|
||||
const Search = React.forwardRef<InputRef, SearchProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
inputPrefixCls: customizeInputPrefixCls,
|
||||
@ -42,7 +42,7 @@ const Search = React.forwardRef<Input, SearchProps>((props, ref) => {
|
||||
|
||||
const size = customizeSize || contextSize;
|
||||
|
||||
const inputRef = React.useRef<Input>(null);
|
||||
const inputRef = React.useRef<InputRef>(null);
|
||||
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e && e.target && e.type === 'click' && customOnSearch) {
|
||||
@ -61,7 +61,7 @@ const Search = React.forwardRef<Input, SearchProps>((props, ref) => {
|
||||
|
||||
const onSearch = (e: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLInputElement>) => {
|
||||
if (customOnSearch) {
|
||||
customOnSearch(inputRef.current?.input.value!, e);
|
||||
customOnSearch(inputRef.current?.input?.value!, e);
|
||||
}
|
||||
};
|
||||
|
||||
@ -129,7 +129,7 @@ const Search = React.forwardRef<Input, SearchProps>((props, ref) => {
|
||||
|
||||
return (
|
||||
<Input
|
||||
ref={composeRef<Input>(inputRef, ref)}
|
||||
ref={composeRef<InputRef>(inputRef, ref)}
|
||||
onPressEnter={onSearch}
|
||||
{...restProps}
|
||||
size={size}
|
||||
|
@ -25,7 +25,7 @@ describe('Input.Password', () => {
|
||||
|
||||
it('should support size', () => {
|
||||
const wrapper = mount(<Password size="large" />);
|
||||
expect(wrapper.find('input').hasClass('ant-input-lg')).toBe(true);
|
||||
expect(wrapper.find('.ant-input-affix-wrapper-lg')).toBeTruthy();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
exports[`Input.Password rtl render component should be rendered correctly in RTL direction 1`] = `
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-rtl ant-input-password"
|
||||
class="ant-input-affix-wrapper ant-input-password ant-input-affix-wrapper-rtl"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
@ -159,11 +159,11 @@ exports[`Input.Password should change type when click 3`] = `
|
||||
|
||||
exports[`Input.Password should support size 1`] = `
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-lg ant-input-password ant-input-password-large"
|
||||
class="ant-input-affix-wrapper ant-input-password ant-input-password-large ant-input-affix-wrapper-lg"
|
||||
>
|
||||
<input
|
||||
action="click"
|
||||
class="ant-input ant-input-lg"
|
||||
class="ant-input"
|
||||
type="password"
|
||||
value=""
|
||||
/>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
exports[`Input.Search rtl render component should be rendered correctly in RTL direction 1`] = `
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-rtl ant-input-search ant-input-search-rtl"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-rtl ant-input-group-wrapper-rtl"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group ant-input-group-rtl"
|
||||
|
@ -4857,10 +4857,14 @@ Array [
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -4877,6 +4881,7 @@ Array [
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<br />,
|
||||
@ -5004,7 +5009,7 @@ exports[`renders ./components/input/demo/borderless-debug.md extend context corr
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-borderless"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-borderless"
|
||||
class="ant-input"
|
||||
placeholder="Unbordered"
|
||||
type="text"
|
||||
value=""
|
||||
@ -5013,10 +5018,14 @@ exports[`renders ./components/input/demo/borderless-debug.md extend context corr
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -5034,6 +5043,7 @@ exports[`renders ./components/input/demo/borderless-debug.md extend context corr
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-borderless"
|
||||
>
|
||||
@ -5043,7 +5053,7 @@ exports[`renders ./components/input/demo/borderless-debug.md extend context corr
|
||||
¥
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-borderless"
|
||||
class="ant-input"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
@ -5062,7 +5072,7 @@ exports[`renders ./components/input/demo/borderless-debug.md extend context corr
|
||||
¥
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-disabled ant-input-borderless"
|
||||
class="ant-input ant-input-disabled"
|
||||
disabled=""
|
||||
type="text"
|
||||
value=""
|
||||
@ -5485,10 +5495,14 @@ exports[`renders ./components/input/demo/group.md extend context correctly 1`] =
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon"
|
||||
class="ant-input-clear-icon"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -5506,6 +5520,7 @@ exports[`renders ./components/input/demo/group.md extend context correctly 1`] =
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -5555,10 +5570,14 @@ exports[`renders ./components/input/demo/group.md extend context correctly 1`] =
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon"
|
||||
class="ant-input-clear-icon"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -5576,6 +5595,7 @@ exports[`renders ./components/input/demo/group.md extend context correctly 1`] =
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -8937,10 +8957,14 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -8958,6 +8982,7 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -9018,10 +9043,14 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -9039,6 +9068,7 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -9122,7 +9152,7 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-input-search-with-button"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -9131,7 +9161,7 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-lg"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-lg"
|
||||
class="ant-input"
|
||||
placeholder="input search text"
|
||||
type="text"
|
||||
value=""
|
||||
@ -9140,10 +9170,14 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -9161,6 +9195,7 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -9180,7 +9215,7 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-input-search-with-button"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -9189,7 +9224,7 @@ exports[`renders ./components/input/demo/search-input.md extend context correctl
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-lg"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-lg"
|
||||
class="ant-input"
|
||||
placeholder="input search text"
|
||||
type="text"
|
||||
value=""
|
||||
@ -9336,7 +9371,7 @@ Array [
|
||||
<br />,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-input-search-with-button"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -9450,7 +9485,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-lg"
|
||||
class="ant-input"
|
||||
placeholder="large size"
|
||||
type="text"
|
||||
value=""
|
||||
@ -9520,7 +9555,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-sm"
|
||||
class="ant-input"
|
||||
placeholder="small size"
|
||||
type="text"
|
||||
value=""
|
||||
|
@ -1074,10 +1074,14 @@ Array [
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -1094,6 +1098,7 @@ Array [
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>,
|
||||
<br />,
|
||||
<br />,
|
||||
@ -1221,7 +1226,7 @@ exports[`renders ./components/input/demo/borderless-debug.md correctly 1`] = `
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-borderless"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-borderless"
|
||||
class="ant-input"
|
||||
placeholder="Unbordered"
|
||||
type="text"
|
||||
value=""
|
||||
@ -1230,10 +1235,14 @@ exports[`renders ./components/input/demo/borderless-debug.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -1251,6 +1260,7 @@ exports[`renders ./components/input/demo/borderless-debug.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-borderless"
|
||||
>
|
||||
@ -1260,7 +1270,7 @@ exports[`renders ./components/input/demo/borderless-debug.md correctly 1`] = `
|
||||
¥
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-borderless"
|
||||
class="ant-input"
|
||||
type="text"
|
||||
value=""
|
||||
/>
|
||||
@ -1279,7 +1289,7 @@ exports[`renders ./components/input/demo/borderless-debug.md correctly 1`] = `
|
||||
¥
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-disabled ant-input-borderless"
|
||||
class="ant-input ant-input-disabled"
|
||||
disabled=""
|
||||
type="text"
|
||||
value=""
|
||||
@ -1596,10 +1606,14 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon"
|
||||
class="ant-input-clear-icon"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -1617,6 +1631,7 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -1666,10 +1681,14 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon"
|
||||
class="ant-input-clear-icon"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -1687,6 +1706,7 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -2711,10 +2731,14 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -2732,6 +2756,7 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -2792,10 +2817,14 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -2813,6 +2842,7 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -2896,7 +2926,7 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
style="margin-bottom:8px"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-input-search-with-button"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -2905,7 +2935,7 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-lg"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-lg"
|
||||
class="ant-input"
|
||||
placeholder="input search text"
|
||||
type="text"
|
||||
value=""
|
||||
@ -2914,10 +2944,14 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -2935,6 +2969,7 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
class="ant-input-group-addon"
|
||||
>
|
||||
@ -2954,7 +2989,7 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
class="ant-space-item"
|
||||
>
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-input-search-with-button"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -2963,7 +2998,7 @@ exports[`renders ./components/input/demo/search-input.md correctly 1`] = `
|
||||
class="ant-input-affix-wrapper ant-input-affix-wrapper-lg"
|
||||
>
|
||||
<input
|
||||
class="ant-input ant-input-lg"
|
||||
class="ant-input"
|
||||
placeholder="input search text"
|
||||
type="text"
|
||||
value=""
|
||||
@ -3110,7 +3145,7 @@ Array [
|
||||
<br />,
|
||||
<br />,
|
||||
<span
|
||||
class="ant-input-group-wrapper ant-input-group-wrapper-lg ant-input-search ant-input-search-large ant-input-search-with-button"
|
||||
class="ant-input-group-wrapper ant-input-search ant-input-search-large ant-input-search-with-button ant-input-group-wrapper-lg"
|
||||
>
|
||||
<span
|
||||
class="ant-input-wrapper ant-input-group"
|
||||
@ -3224,7 +3259,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-lg"
|
||||
class="ant-input"
|
||||
placeholder="large size"
|
||||
type="text"
|
||||
value=""
|
||||
@ -3294,7 +3329,7 @@ Array [
|
||||
</span>
|
||||
</span>
|
||||
<input
|
||||
class="ant-input ant-input-sm"
|
||||
class="ant-input"
|
||||
placeholder="small size"
|
||||
type="text"
|
||||
value=""
|
||||
|
@ -13,10 +13,14 @@ exports[`Input allowClear should change type when click 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon"
|
||||
class="ant-input-clear-icon"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -33,6 +37,7 @@ exports[`Input allowClear should change type when click 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@ -49,10 +54,14 @@ exports[`Input allowClear should change type when click 2`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -69,6 +78,7 @@ exports[`Input allowClear should change type when click 2`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@ -85,10 +95,14 @@ exports[`Input allowClear should not show icon if defaultValue is undefined, nul
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -105,6 +119,7 @@ exports[`Input allowClear should not show icon if defaultValue is undefined, nul
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@ -121,10 +136,14 @@ exports[`Input allowClear should not show icon if defaultValue is undefined, nul
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -141,6 +160,7 @@ exports[`Input allowClear should not show icon if defaultValue is undefined, nul
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@ -157,10 +177,14 @@ exports[`Input allowClear should not show icon if defaultValue is undefined, nul
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -177,6 +201,7 @@ exports[`Input allowClear should not show icon if defaultValue is undefined, nul
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@ -193,10 +218,14 @@ exports[`Input allowClear should not show icon if value is undefined, null or em
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -213,6 +242,7 @@ exports[`Input allowClear should not show icon if value is undefined, null or em
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@ -229,10 +259,14 @@ exports[`Input allowClear should not show icon if value is undefined, null or em
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -249,6 +283,7 @@ exports[`Input allowClear should not show icon if value is undefined, null or em
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@ -265,10 +300,14 @@ exports[`Input allowClear should not show icon if value is undefined, null or em
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -285,6 +324,7 @@ exports[`Input allowClear should not show icon if value is undefined, null or em
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { spyElementPrototypes } from 'rc-util/lib/test/domHook';
|
||||
import { InputRef } from '../Input';
|
||||
import Input from '..';
|
||||
|
||||
const { TextArea } = Input;
|
||||
@ -30,8 +31,8 @@ describe('Input.Focus', () => {
|
||||
});
|
||||
|
||||
it('start', () => {
|
||||
const ref = React.createRef<Input>();
|
||||
mount(<Input ref={ref} defaultValue="light" />);
|
||||
const ref = React.createRef<InputRef>();
|
||||
mount(<TextArea ref={ref} defaultValue="light" />);
|
||||
ref.current!.focus({ cursor: 'start' });
|
||||
|
||||
expect(focus).toHaveBeenCalled();
|
||||
@ -39,8 +40,8 @@ describe('Input.Focus', () => {
|
||||
});
|
||||
|
||||
it('end', () => {
|
||||
const ref = React.createRef<Input>();
|
||||
mount(<Input ref={ref} defaultValue="light" />);
|
||||
const ref = React.createRef<InputRef>();
|
||||
mount(<TextArea ref={ref} defaultValue="light" />);
|
||||
ref.current!.focus({ cursor: 'end' });
|
||||
|
||||
expect(focus).toHaveBeenCalled();
|
||||
@ -62,6 +63,7 @@ describe('Input.Focus', () => {
|
||||
expect(wrapper.exists('.ant-input-affix-wrapper-focused')).toBeTruthy();
|
||||
|
||||
wrapper.setProps({ disabled: true });
|
||||
wrapper.update();
|
||||
expect(wrapper.exists('.ant-input-affix-wrapper-focused')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
@ -3,7 +3,6 @@ import { mount } from 'enzyme';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import Form from '../../form';
|
||||
import Input from '..';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
|
||||
@ -18,7 +17,6 @@ describe('Input', () => {
|
||||
errorSpy.mockRestore();
|
||||
});
|
||||
|
||||
focusTest(Input);
|
||||
mountTest(Input);
|
||||
mountTest(Input.Group);
|
||||
|
||||
@ -31,8 +29,9 @@ describe('Input', () => {
|
||||
});
|
||||
|
||||
it('select()', () => {
|
||||
const wrapper = mount(<Input />);
|
||||
wrapper.instance().select();
|
||||
const ref = React.createRef();
|
||||
mount(<Input ref={ref} />);
|
||||
ref.current?.select();
|
||||
});
|
||||
|
||||
it('should support size', () => {
|
||||
@ -63,8 +62,8 @@ describe('Input', () => {
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
it('trigger warning', () => {
|
||||
const wrapper = mount(<Input />, { attachTo: document.body });
|
||||
wrapper.find('input').instance().focus();
|
||||
const wrapper = mount(<Input />);
|
||||
wrapper.find('input').first().getDOMNode().focus();
|
||||
wrapper.setProps({
|
||||
suffix: 'light',
|
||||
});
|
||||
@ -78,10 +77,11 @@ describe('Input', () => {
|
||||
it('set mouse cursor position', () => {
|
||||
const defaultValue = '11111';
|
||||
const valLength = defaultValue.length;
|
||||
const wrapper = mount(<Input autoFocus defaultValue={defaultValue} />);
|
||||
wrapper.instance().setSelectionRange(valLength, valLength);
|
||||
expect(wrapper.instance().input.selectionStart).toEqual(5);
|
||||
expect(wrapper.instance().input.selectionEnd).toEqual(5);
|
||||
const ref = React.createRef();
|
||||
const wrapper = mount(<Input ref={ref} autoFocus defaultValue={defaultValue} />);
|
||||
ref.current?.setSelectionRange(valLength, valLength);
|
||||
expect(wrapper.find('input').first().getDOMNode().selectionStart).toEqual(5);
|
||||
expect(wrapper.find('input').first().getDOMNode().selectionEnd).toEqual(5);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -486,4 +486,27 @@ describe('TextArea allowClear', () => {
|
||||
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/31200
|
||||
it('should not lost focus when clear input', () => {
|
||||
const onBlur = jest.fn();
|
||||
const wrapper = mount(<TextArea allowClear defaultValue="value" onBlur={onBlur} />, {
|
||||
attachTo: document.body,
|
||||
});
|
||||
wrapper.find('textarea').getDOMNode().focus();
|
||||
wrapper.find('.ant-input-clear-icon').at(0).simulate('mouseDown');
|
||||
wrapper.find('.ant-input-clear-icon').at(0).simulate('click');
|
||||
wrapper.find('.ant-input-clear-icon').at(0).simulate('mouseUp');
|
||||
wrapper.find('.ant-input-clear-icon').at(0).simulate('focus');
|
||||
wrapper.find('.ant-input-clear-icon').at(0).getDOMNode().click();
|
||||
expect(onBlur).not.toBeCalled();
|
||||
wrapper.unmount();
|
||||
});
|
||||
|
||||
it('should focus text area after clear', () => {
|
||||
const wrapper = mount(<TextArea allowClear defaultValue="111" />, { attachTo: document.body });
|
||||
wrapper.find('.ant-input-clear-icon').at(0).simulate('click');
|
||||
expect(document.activeElement).toBe(wrapper.find('textarea').at(0).getDOMNode());
|
||||
wrapper.unmount();
|
||||
});
|
||||
});
|
||||
|
@ -1,15 +1,26 @@
|
||||
import Input from './Input';
|
||||
import * as React from 'react';
|
||||
import InternalInput, { InputProps, InputRef } from './Input';
|
||||
import Group from './Group';
|
||||
import Search from './Search';
|
||||
import TextArea from './TextArea';
|
||||
import Password from './Password';
|
||||
|
||||
export { InputProps } from './Input';
|
||||
export { InputProps, InputRef } from './Input';
|
||||
export { GroupProps } from './Group';
|
||||
export { SearchProps } from './Search';
|
||||
export { TextAreaProps } from './TextArea';
|
||||
export { PasswordProps } from './Password';
|
||||
|
||||
interface CompoundedComponent
|
||||
extends React.ForwardRefExoticComponent<InputProps & React.RefAttributes<InputRef>> {
|
||||
Group: typeof Group;
|
||||
Search: typeof Search;
|
||||
TextArea: typeof TextArea;
|
||||
Password: typeof Password;
|
||||
}
|
||||
|
||||
const Input = InternalInput as CompoundedComponent;
|
||||
|
||||
Input.Group = Group;
|
||||
Input.Search = Search;
|
||||
Input.TextArea = TextArea;
|
||||
|
@ -2,7 +2,7 @@
|
||||
@input-prefix-cls: ~'@{ant-prefix}-input';
|
||||
|
||||
// ========================= Input =========================
|
||||
.@{iconfont-css-prefix}.@{ant-prefix}-input-clear-icon {
|
||||
.@{ant-prefix}-input-clear-icon {
|
||||
margin: 0;
|
||||
color: @disabled-color;
|
||||
font-size: @font-size-sm;
|
||||
|
@ -1,33 +1,7 @@
|
||||
import classNames from 'classnames';
|
||||
import { ValidateStatus } from '../form/FormItem';
|
||||
import type { DirectionType } from '../config-provider';
|
||||
import type { SizeType } from '../config-provider/SizeContext';
|
||||
import type { ClearableInputProps } from './ClearableLabeledInput';
|
||||
import type { InputProps } from './Input';
|
||||
import { getStatusClassNames } from '../_util/statusUtils';
|
||||
|
||||
export function getInputClassName(
|
||||
prefixCls: string,
|
||||
bordered: boolean,
|
||||
size?: SizeType,
|
||||
disabled?: boolean,
|
||||
direction?: DirectionType,
|
||||
status?: ValidateStatus,
|
||||
hasFeedback?: boolean,
|
||||
) {
|
||||
return classNames(
|
||||
prefixCls,
|
||||
{
|
||||
[`${prefixCls}-sm`]: size === 'small',
|
||||
[`${prefixCls}-lg`]: size === 'large',
|
||||
[`${prefixCls}-disabled`]: disabled,
|
||||
[`${prefixCls}-rtl`]: direction === 'rtl',
|
||||
[`${prefixCls}-borderless`]: !bordered,
|
||||
},
|
||||
getStatusClassNames(prefixCls, status, hasFeedback),
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export function hasPrefixSuffix(props: InputProps | ClearableInputProps) {
|
||||
return !!(props.prefix || props.suffix || props.allowClear);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@ Table with editable cells. When work with `shouldCellUpdate`, please take care o
|
||||
|
||||
```tsx
|
||||
import React, { useContext, useState, useEffect, useRef } from 'react';
|
||||
import { Table, Input, Button, Popconfirm, Form } from 'antd';
|
||||
import { Table, Input, Button, Popconfirm, Form, InputRef } from 'antd';
|
||||
import { FormInstance } from 'antd/lib/form';
|
||||
|
||||
const EditableContext = React.createContext<FormInstance<any> | null>(null);
|
||||
@ -61,7 +61,7 @@ const EditableCell: React.FC<EditableCellProps> = ({
|
||||
...restProps
|
||||
}) => {
|
||||
const [editing, setEditing] = useState(false);
|
||||
const inputRef = useRef<Input>(null);
|
||||
const inputRef = useRef<InputRef>(null);
|
||||
const form = useContext(EditableContext)!;
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -225,10 +225,14 @@ exports[`renders ./components/transfer/demo/advanced.md extend context correctly
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -246,6 +250,7 @@ exports[`renders ./components/transfer/demo/advanced.md extend context correctly
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -593,10 +598,14 @@ exports[`renders ./components/transfer/demo/advanced.md extend context correctly
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -614,6 +623,7 @@ exports[`renders ./components/transfer/demo/advanced.md extend context correctly
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -4626,10 +4636,14 @@ exports[`renders ./components/transfer/demo/search.md extend context correctly 1
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -4647,6 +4661,7 @@ exports[`renders ./components/transfer/demo/search.md extend context correctly 1
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -4974,10 +4989,14 @@ exports[`renders ./components/transfer/demo/search.md extend context correctly 1
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -4995,6 +5014,7 @@ exports[`renders ./components/transfer/demo/search.md extend context correctly 1
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -5810,10 +5830,14 @@ exports[`renders ./components/transfer/demo/status.md extend context correctly 1
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -5831,6 +5855,7 @@ exports[`renders ./components/transfer/demo/status.md extend context correctly 1
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -6158,10 +6183,14 @@ exports[`renders ./components/transfer/demo/status.md extend context correctly 1
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -6179,6 +6208,7 @@ exports[`renders ./components/transfer/demo/status.md extend context correctly 1
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
|
@ -96,10 +96,14 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -117,6 +121,7 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -335,10 +340,14 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -356,6 +365,7 @@ exports[`renders ./components/transfer/demo/advanced.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -2894,10 +2904,14 @@ exports[`renders ./components/transfer/demo/search.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -2915,6 +2929,7 @@ exports[`renders ./components/transfer/demo/search.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -3113,10 +3128,14 @@ exports[`renders ./components/transfer/demo/search.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -3134,6 +3153,7 @@ exports[`renders ./components/transfer/demo/search.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -3562,10 +3582,14 @@ exports[`renders ./components/transfer/demo/status.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -3583,6 +3607,7 @@ exports[`renders ./components/transfer/demo/status.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
@ -3781,10 +3806,14 @@ exports[`renders ./components/transfer/demo/status.md correctly 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -3802,6 +3831,7 @@ exports[`renders ./components/transfer/demo/status.md correctly 1`] = `
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
class="ant-transfer-list-body-not-found"
|
||||
|
@ -37,10 +37,14 @@ exports[`Transfer.Search should show cross icon when input value exists 1`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon-hidden ant-input-clear-icon"
|
||||
class="ant-input-clear-icon ant-input-clear-icon-hidden"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -57,6 +61,7 @@ exports[`Transfer.Search should show cross icon when input value exists 1`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
||||
@ -97,10 +102,14 @@ exports[`Transfer.Search should show cross icon when input value exists 2`] = `
|
||||
class="ant-input-suffix"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle ant-input-clear-icon"
|
||||
class="ant-input-clear-icon"
|
||||
role="button"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
aria-label="close-circle"
|
||||
class="anticon anticon-close-circle"
|
||||
role="img"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
@ -117,5 +126,6 @@ exports[`Transfer.Search should show cross icon when input value exists 2`] = `
|
||||
</svg>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
|
@ -129,6 +129,7 @@
|
||||
"rc-dropdown": "~3.3.2",
|
||||
"rc-field-form": "~1.23.0",
|
||||
"rc-image": "~5.2.5",
|
||||
"rc-input": "^0.0.1-alpha.3",
|
||||
"rc-input-number": "~7.3.0",
|
||||
"rc-mentions": "~1.6.1",
|
||||
"rc-menu": "~9.2.1",
|
||||
|
Loading…
Reference in New Issue
Block a user