2023-09-11 17:28:04 +08:00
import React , { forwardRef , useContext , useEffect , useRef } from 'react' ;
2016-03-31 17:46:35 +08:00
import classNames from 'classnames' ;
2024-02-27 10:25:35 +08:00
import type { InputRef , InputProps as RcInputProps } from 'rc-input' ;
2022-06-06 23:39:00 +08:00
import RcInput from 'rc-input' ;
2022-03-01 14:17:48 +08:00
import { composeRef } from 'rc-util/lib/ref' ;
2023-09-11 17:28:04 +08:00
2024-02-27 10:25:35 +08:00
import getAllowClear from '../_util/getAllowClear' ;
2023-05-12 14:53:47 +08:00
import type { InputStatus } from '../_util/statusUtils' ;
import { getMergedStatus , getStatusClassNames } from '../_util/statusUtils' ;
2023-09-11 17:28:04 +08:00
import { devUseWarning } from '../_util/warning' ;
2022-06-06 23:39:00 +08:00
import { ConfigContext } from '../config-provider' ;
import DisabledContext from '../config-provider/DisabledContext' ;
2024-02-27 10:25:35 +08:00
import useCSSVarCls from '../config-provider/hooks/useCSSVarCls' ;
2023-05-12 14:53:47 +08:00
import useSize from '../config-provider/hooks/useSize' ;
2023-09-11 17:28:04 +08:00
import type { SizeType } from '../config-provider/SizeContext' ;
2022-06-06 23:39:00 +08:00
import { FormItemInputContext , NoFormStyle } from '../form/context' ;
2024-02-27 10:25:35 +08:00
import type { Variant } from '../form/hooks/useVariants' ;
import useVariant from '../form/hooks/useVariants' ;
2022-10-18 16:23:10 +08:00
import { NoCompactStyle , useCompactItemContext } from '../space/Compact' ;
2022-10-13 15:07:43 +08:00
import useRemovePasswordTimeout from './hooks/useRemovePasswordTimeout' ;
2022-03-09 10:38:02 +08:00
import useStyle from './style' ;
2023-05-12 14:53:47 +08:00
import { hasPrefixSuffix } from './utils' ;
2022-03-09 10:38:02 +08:00
2020-12-29 22:42:04 +08:00
export interface InputFocusOptions extends FocusOptions {
cursor ? : 'start' | 'end' | 'all' ;
}
2022-03-01 14:17:48 +08:00
export type { InputRef } ;
2016-08-19 17:11:06 +08:00
2020-12-29 22:42:04 +08:00
export function triggerFocus (
element? : HTMLInputElement | HTMLTextAreaElement ,
option? : InputFocusOptions ,
) {
2022-09-30 15:58:34 +08:00
if ( ! element ) {
return ;
}
2020-12-29 22:42:04 +08:00
element . focus ( option ) ;
// Selection content
const { cursor } = option || { } ;
if ( cursor ) {
const len = element . value . length ;
switch ( cursor ) {
case 'start' :
element . setSelectionRange ( 0 , 0 ) ;
break ;
case 'end' :
element . setSelectionRange ( len , len ) ;
break ;
default :
element . setSelectionRange ( 0 , len ) ;
}
}
}
2022-03-01 14:17:48 +08:00
export interface InputProps
extends Omit <
RcInputProps ,
2023-03-28 09:57:55 +08:00
'wrapperClassName' | 'groupClassName' | 'inputClassName' | 'affixWrapperClassName' | 'classes'
2022-03-01 14:17:48 +08:00
> {
2023-01-20 11:03:50 +08:00
rootClassName? : string ;
2022-03-01 14:17:48 +08:00
size? : SizeType ;
2022-04-29 20:48:10 +08:00
disabled? : boolean ;
2022-03-01 14:17:48 +08:00
status? : InputStatus ;
2023-12-11 10:20:32 +08:00
/** @deprecated Use `variant="borderless"` instead. */
2022-03-01 14:17:48 +08:00
bordered? : boolean ;
2023-12-11 10:20:32 +08:00
/ * *
2023-12-18 17:53:31 +08:00
* @since 5.13 . 0
2023-12-11 15:34:07 +08:00
* @default "outlined"
2023-12-11 10:20:32 +08:00
* /
2023-12-22 10:05:15 +08:00
variant? : Variant ;
2022-08-04 10:03:58 +08:00
[ key : ` data- ${ string } ` ] : string | undefined ;
2019-11-01 18:19:29 +08:00
}
2022-03-01 14:17:48 +08:00
const Input = forwardRef < InputRef , InputProps > ( ( props , ref ) = > {
const {
prefixCls : customizePrefixCls ,
bordered = true ,
status : customStatus ,
size : customSize ,
2022-04-29 20:48:10 +08:00
disabled : customDisabled ,
2022-03-01 14:17:48 +08:00
onBlur ,
onFocus ,
suffix ,
2022-03-08 01:40:24 +08:00
allowClear ,
2022-03-10 19:04:51 +08:00
addonAfter ,
addonBefore ,
2022-10-18 16:23:10 +08:00
className ,
2023-06-28 11:53:26 +08:00
style ,
styles ,
2023-01-20 11:03:50 +08:00
rootClassName ,
2022-09-29 23:40:24 +08:00
onChange ,
2023-03-28 09:57:55 +08:00
classNames : classes ,
2023-12-11 10:20:32 +08:00
variant : customVariant ,
2022-03-01 14:17:48 +08:00
. . . rest
} = props ;
2023-12-11 10:20:32 +08:00
if ( process . env . NODE_ENV !== 'production' ) {
const { deprecated } = devUseWarning ( 'Input' ) ;
deprecated ( ! ( 'bordered' in props ) , 'bordered' , 'variant' ) ;
}
2022-04-06 21:49:30 +08:00
const { getPrefixCls , direction , input } = React . useContext ( ConfigContext ) ;
2022-03-01 14:17:48 +08:00
const prefixCls = getPrefixCls ( 'input' , customizePrefixCls ) ;
const inputRef = useRef < InputRef > ( null ) ;
2022-03-09 10:38:02 +08:00
// Style
2023-12-14 14:58:53 +08:00
const rootCls = useCSSVarCls ( prefixCls ) ;
const [ wrapCSSVar , hashId , cssVarCls ] = useStyle ( prefixCls , rootCls ) ;
2022-03-09 10:38:02 +08:00
2022-10-18 16:23:10 +08:00
// ===================== Compact Item =====================
const { compactSize , compactItemClassnames } = useCompactItemContext ( prefixCls , direction ) ;
2022-03-16 16:04:01 +08:00
// ===================== Size =====================
2023-06-19 14:26:48 +08:00
const mergedSize = useSize ( ( ctx ) = > customSize ? ? compactSize ? ? ctx ) ;
2022-03-01 14:17:48 +08:00
2022-04-29 20:48:10 +08:00
// ===================== Disabled =====================
const disabled = React . useContext ( DisabledContext ) ;
2022-09-20 16:48:59 +08:00
const mergedDisabled = customDisabled ? ? disabled ;
2022-04-29 20:48:10 +08:00
2022-03-01 14:17:48 +08:00
// ===================== Status =====================
2022-03-25 17:48:12 +08:00
const { status : contextStatus , hasFeedback , feedbackIcon } = useContext ( FormItemInputContext ) ;
2022-03-01 14:17:48 +08:00
const mergedStatus = getMergedStatus ( contextStatus , customStatus ) ;
// ===================== Focus warning =====================
2022-03-14 15:37:02 +08:00
const inputHasPrefixSuffix = hasPrefixSuffix ( props ) || ! ! hasFeedback ;
2022-03-01 14:17:48 +08:00
const prevHasPrefixSuffix = useRef < boolean > ( inputHasPrefixSuffix ) ;
2023-09-11 17:28:04 +08:00
/* eslint-disable react-hooks/rules-of-hooks */
if ( process . env . NODE_ENV !== 'production' ) {
2023-09-13 22:07:33 +08:00
const warning = devUseWarning ( 'Input' ) ;
2023-09-11 17:28:04 +08:00
useEffect ( ( ) = > {
if ( inputHasPrefixSuffix && ! prevHasPrefixSuffix . current ) {
warning (
document . activeElement === inputRef . current ? . input ,
'usage' ,
` 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 ` ,
) ;
}
prevHasPrefixSuffix . current = inputHasPrefixSuffix ;
} , [ inputHasPrefixSuffix ] ) ;
}
/* eslint-enable */
2022-03-01 14:17:48 +08:00
// ===================== Remove Password value =====================
2022-10-13 15:07:43 +08:00
const removePasswordTimeout = useRemovePasswordTimeout ( inputRef , true ) ;
2022-02-14 17:09:35 +08:00
2022-03-01 14:17:48 +08:00
const handleBlur = ( e : React.FocusEvent < HTMLInputElement > ) = > {
removePasswordTimeout ( ) ;
onBlur ? . ( e ) ;
2022-02-14 17:09:35 +08:00
} ;
2022-03-01 14:17:48 +08:00
const handleFocus = ( e : React.FocusEvent < HTMLInputElement > ) = > {
removePasswordTimeout ( ) ;
onFocus ? . ( e ) ;
2018-12-05 19:12:18 +08:00
} ;
2022-09-29 23:40:24 +08:00
const handleChange = ( e : React.ChangeEvent < HTMLInputElement > ) = > {
removePasswordTimeout ( ) ;
onChange ? . ( e ) ;
} ;
2022-03-01 14:17:48 +08:00
const suffixNode = ( hasFeedback || suffix ) && (
< >
{ suffix }
2022-03-25 17:48:12 +08:00
{ hasFeedback && feedbackIcon }
2022-03-01 14:17:48 +08:00
< / >
) ;
2024-05-22 19:30:07 +08:00
const getAddon = ( addon : React.ReactNode ) = >
addon && (
< NoCompactStyle >
< NoFormStyle override status >
{ addon }
< / NoFormStyle >
< / NoCompactStyle >
) ;
2024-02-27 10:25:35 +08:00
const mergedAllowClear = getAllowClear ( allowClear ? ? input ? . allowClear ) ;
2023-12-22 10:05:15 +08:00
const [ variant , enableVariantCls ] = useVariant ( customVariant , bordered ) ;
2023-12-11 10:20:32 +08:00
2023-11-10 17:32:43 +08:00
return wrapCSSVar (
2022-03-01 14:17:48 +08:00
< RcInput
ref = { composeRef ( ref , inputRef ) }
prefixCls = { prefixCls }
autoComplete = { input ? . autoComplete }
{ . . . rest }
2023-01-16 09:55:52 +08:00
disabled = { mergedDisabled }
2022-03-01 14:17:48 +08:00
onBlur = { handleBlur }
onFocus = { handleFocus }
2023-06-28 11:53:26 +08:00
style = { { . . . input ? . style , . . . style } }
styles = { { . . . input ? . styles , . . . styles } }
2022-03-01 14:17:48 +08:00
suffix = { suffixNode }
2022-03-08 01:40:24 +08:00
allowClear = { mergedAllowClear }
2023-11-10 17:32:43 +08:00
className = { classNames (
className ,
rootClassName ,
cssVarCls ,
2023-12-14 14:58:53 +08:00
rootCls ,
2023-11-10 17:32:43 +08:00
compactItemClassnames ,
input ? . className ,
) }
2022-09-29 23:40:24 +08:00
onChange = { handleChange }
2024-05-22 19:30:07 +08:00
addonBefore = { getAddon ( addonBefore ) }
addonAfter = { getAddon ( addonAfter ) }
2023-03-28 09:57:55 +08:00
classNames = { {
. . . classes ,
2023-06-28 11:53:26 +08:00
. . . input ? . classNames ,
2023-01-11 14:18:13 +08:00
input : classNames (
{
[ ` ${ prefixCls } -sm ` ] : mergedSize === 'small' ,
[ ` ${ prefixCls } -lg ` ] : mergedSize === 'large' ,
[ ` ${ prefixCls } -rtl ` ] : direction === 'rtl' ,
} ,
2023-03-28 09:57:55 +08:00
classes ? . input ,
2023-06-28 11:53:26 +08:00
input ? . classNames ? . input ,
2023-01-11 14:18:13 +08:00
hashId ,
) ,
2023-12-18 17:53:31 +08:00
variant : classNames (
{
[ ` ${ prefixCls } - ${ variant } ` ] : enableVariantCls ,
} ,
getStatusClassNames ( prefixCls , mergedStatus ) ,
) ,
2023-01-11 14:18:13 +08:00
affixWrapper : classNames (
{
[ ` ${ prefixCls } -affix-wrapper-sm ` ] : mergedSize === 'small' ,
[ ` ${ prefixCls } -affix-wrapper-lg ` ] : mergedSize === 'large' ,
[ ` ${ prefixCls } -affix-wrapper-rtl ` ] : direction === 'rtl' ,
} ,
hashId ,
) ,
wrapper : classNames (
{
[ ` ${ prefixCls } -group-rtl ` ] : direction === 'rtl' ,
} ,
hashId ,
) ,
2023-12-18 17:53:31 +08:00
groupWrapper : classNames (
2023-01-11 14:18:13 +08:00
{
[ ` ${ prefixCls } -group-wrapper-sm ` ] : mergedSize === 'small' ,
[ ` ${ prefixCls } -group-wrapper-lg ` ] : mergedSize === 'large' ,
[ ` ${ prefixCls } -group-wrapper-rtl ` ] : direction === 'rtl' ,
2023-12-18 17:53:31 +08:00
[ ` ${ prefixCls } -group-wrapper- ${ variant } ` ] : enableVariantCls ,
2023-01-11 14:18:13 +08:00
} ,
getStatusClassNames ( ` ${ prefixCls } -group-wrapper ` , mergedStatus , hasFeedback ) ,
hashId ,
) ,
} }
2022-03-09 10:38:02 +08:00
/ > ,
2022-03-01 14:17:48 +08:00
) ;
} ) ;
2018-12-26 22:47:55 +08:00
2024-03-28 14:05:58 +08:00
if ( process . env . NODE_ENV !== 'production' ) {
Input . displayName = 'Input' ;
}
2018-12-26 22:47:55 +08:00
export default Input ;