diff --git a/components/input/__docs__/demo/clear/index.tsx b/components/input/__docs__/demo/clear/index.tsx index cb9d086e07..88112bd421 100644 --- a/components/input/__docs__/demo/clear/index.tsx +++ b/components/input/__docs__/demo/clear/index.tsx @@ -42,6 +42,24 @@ ReactDOM.render( />

+ +
+
+ +
+
, mountNode ); diff --git a/components/input/__docs__/index.en-us.md b/components/input/__docs__/index.en-us.md index 718d6bb451..af55029d5b 100644 --- a/components/input/__docs__/index.en-us.md +++ b/components/input/__docs__/index.en-us.md @@ -16,83 +16,84 @@ Form Input, use it with Form components usually. ### Input -| Param | Descripiton | Type | Default Value | -| --------------- | ------------------------------------------------------------------------------------------------------------------------------------- | ------------- | --------- | -| value | current value | String/Number | - | -| size | Size

option:
'small'
'medium'
'large' | Enum | 'medium' | -| defaultValue | inital value | String/Number | - | -| onChange | callback when value changes

**signature**:
Function(value: String, e: Event) => void
**params**:
_value_: {String} data
_e_: {Event} DOM Event Object | Function | func.noop | -| onKeyDown | callback when on key down

**signature**:
Function(e: Event, opts: Object) => void
**params**:
_e_: {Event} DOM Event Object
_opts_: {Object} extended information:
- opts.overMaxLength: {Boolean} input has reached max length
- opts.beTrimed: {Boolean} input whitespace has been trimed | Function | func.noop | -| disabled | disabled state | Boolean | false | -| maxLength | max length | Number | null | -| showLimitHint | limit max num of characters | Boolean | false | -| cutString | when maxLength is set, auto cut string | Boolean | true | -| readOnly | read only, forbid editing | Boolean | false | -| trim | onChange will auto trim text | Boolean | false | -| placeholder | place holder | String | - | -| onFocus | callback when input get focused

**signature**:
Function(e: Event) => void
**params**:
_e_: {Event} DOM Event Object | Function | func.noop | -| onBlur | callback when input lose focused

**signature**:
Function(e: Event) => void
**params**:
_e_: {Event} DOM Event Object | Function | func.noop | -| getValueLength | define the value length caculation

**signature**:
Function(value: String) => Number
**params**:
_value_: {String} Data
returns:
{Number} caculated length
| Function | func.noop | -| htmlType | html input type | String | - | -| state | state

option:
'error'
'loading'
'success' | Enum | - | -| label | label | ReactNode | - | -| hasClear | clear button displays or not | Boolean | - | -| hasBorder | input border displays or not | Boolean | true | -| onKeyDown | callback when keyboard press down

**signature**:
Function() => void | Function | func.noop | -| onPressEnter | callback when the enter key press down

**signature**:
Function() => void | Function | func.noop | -| hint | watermark, a type of Icon, share a place with hasClear | String | - | -| innerBefore | Elements appended before text | ReactNode | - | -| innerAfter | Elements appended after text | ReactNode | - | -| addonBefore | Elements appended before input | ReactNode | - | -| addonAfter | Elements appended after input | ReactNode | - | -| addonTextBefore | text appended before input | ReactNode | - | -| addonTextAfter | text appended before input | ReactNode | - | -| autoComplete | require browser support | String | 'off' | -| autoFocus | require browser support | Boolean | - | -| hoverShowClear | show clear while hover (use while hasClear=true) | Boolean | false | 1.24 | +| Param | Descripiton | Type | Default Value | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------- | ------------- | ---- | +| value | current value | String/Number | - | +| size | Size

option:
'small'
'medium'
'large' | Enum | 'medium' | +| defaultValue | inital value | String/Number | - | +| onChange | callback when value changes

**signature**:
Function(value: String, e: Event) => void
**params**:
_value_: {String} data
_e_: {Event} DOM Event Object | Function | func.noop | +| onKeyDown | callback when on key down

**signature**:
Function(e: Event, opts: Object) => void
**params**:
_e_: {Event} DOM Event Object
_opts_: {Object} extended information:
- opts.overMaxLength: {Boolean} input has reached max length
- opts.beTrimed: {Boolean} input whitespace has been trimed | Function | func.noop | +| disabled | disabled state | Boolean | false | +| maxLength | max length | Number | null | +| showLimitHint | limit max num of characters | Boolean | false | +| cutString | when maxLength is set, auto cut string | Boolean | true | +| readOnly | read only, forbid editing | Boolean | false | +| trim | onChange will auto trim text | Boolean | false | +| placeholder | place holder | String | - | +| onFocus | callback when input get focused

**signature**:
Function(e: Event) => void
**params**:
_e_: {Event} DOM Event Object | Function | func.noop | +| onBlur | callback when input lose focused

**signature**:
Function(e: Event) => void
**params**:
_e_: {Event} DOM Event Object | Function | func.noop | +| getValueLength | define the value length caculation

**signature**:
Function(value: String) => Number
**params**:
_value_: {String} Data
returns:
{Number} caculated length
| Function | func.noop | +| htmlType | html input type | String | - | +| state | state

option:
'error'
'loading'
'success' | Enum | - | +| label | label | ReactNode | - | +| hasClear | clear button displays or not | Boolean | - | +| hasBorder | input border displays or not | Boolean | true | +| onKeyDown | callback when keyboard press down

**signature**:
Function() => void | Function | func.noop | +| onPressEnter | callback when the enter key press down

**signature**:
Function() => void | Function | func.noop | +| hint | watermark, a type of Icon, share a place with hasClear | String | - | +| innerBefore | Elements appended before text | ReactNode | - | +| innerAfter | Elements appended after text | ReactNode | - | +| addonBefore | Elements appended before input | ReactNode | - | +| addonAfter | Elements appended after input | ReactNode | - | +| addonTextBefore | text appended before input | ReactNode | - | +| addonTextAfter | text appended before input | ReactNode | - | +| autoComplete | require browser support | String | 'off' | +| autoFocus | require browser support | Boolean | - | +| hoverShowClear | show clear while hover (use while hasClear=true) | Boolean | false | 1.24 | ### Input.TextArea -| Param | Descripiton | Type | Default Value | -| -------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------- | --------- | -| value | currentValue | String/Number | - | -| defaultValue | inital value | String/Number | - | -| onChange | callback when value changes

**signature**:
Function(value: String, e: Event) => void
**params**:
_value_: {String} Data
_e_: {Event} DOM Event | Function | func.noop | -| onKeyDown | callback when on key down

**signature**:
Function(e: Event, opts: Object) => void
**params**:
_e_: {Event} DOM Event Object
_opts_: {Object} extended information:
- opts.overMaxLength: {Boolean} input has reached max length
- opts.beTrimed: {Boolean} input whitespace has been trimed | Function | func.noop | -| disabled | disabled state | Boolean | false | -| maxLength | max length | Number | null | -| showLimitHint | limit max num of characters | Boolean | false | -| cutString | when maxLength is set, auto cut string | Boolean | true | -| readOnly | read only, forbid editing | Boolean | false | -| trim | onChange will auto trim text | Boolean | false | -| placeholder | placeholder | String | - | -| onFocus | callback when input get focused

**signature**:
Function() => void | Function | func.noop | -| onBlur | callback when input lose focused

**signature**:
Function() => void | Function | func.noop | -| getValueLength | define the value length caculation

**signature**:
Function(value: String) => Number
**params**:
_value_: {String} Data
returns:
{Number} caculated length
| Function | func.noop | -| htmlType | html input type | String | - | -| state | state

option:
'error'
'loading'
'success' | Enum | - | -| autoHeight | height auto fit, exapmle: true / {minRows: 2, maxRows: 4} | Boolean/Object | false | -| rows | multiline text height
(Never use `height` to controll textarea's height for compatibility with IE9/10) | Number | 4 | +| Param | Descripiton | Type | Default Value | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- | ------------- | +| value | currentValue | String/Number | - | +| defaultValue | inital value | String/Number | - | +| onChange | callback when value changes

**signature**:
Function(value: String, e: Event) => void
**params**:
_value_: {String} Data
_e_: {Event} DOM Event | Function | func.noop | +| onKeyDown | callback when on key down

**signature**:
Function(e: Event, opts: Object) => void
**params**:
_e_: {Event} DOM Event Object
_opts_: {Object} extended information:
- opts.overMaxLength: {Boolean} input has reached max length
- opts.beTrimed: {Boolean} input whitespace has been trimed | Function | func.noop | +| disabled | disabled state | Boolean | false | +| maxLength | max length | Number | null | +| showLimitHint | limit max num of characters | Boolean | false | +| cutString | when maxLength is set, auto cut string | Boolean | true | +| readOnly | read only, forbid editing | Boolean | false | +| trim | onChange will auto trim text | Boolean | false | +| placeholder | placeholder | String | - | +| onFocus | callback when input get focused

**signature**:
Function() => void | Function | func.noop | +| onBlur | callback when input lose focused

**signature**:
Function() => void | Function | func.noop | +| getValueLength | define the value length caculation

**signature**:
Function(value: String) => Number
**params**:
_value_: {String} Data
returns:
{Number} caculated length
| Function | func.noop | +| htmlType | html input type | String | - | +| state | state

option:
'error'
'loading'
'success' | Enum | - | +| autoHeight | height auto fit, exapmle: true / {minRows: 2, maxRows: 4} | Boolean/Object | false | +| rows | multiline text height
(Never use `height` to controll textarea's height for compatibility with IE9/10) | Number | 4 | +| hasClear | clear button displays or not | Boolean | - | ### Input.Group -| Param | Descripiton | Type | Default Value | -| -------------------- | ----------- | --------- | --- | -| addonBefore | Elements appended before input | ReactNode | - | -| addonBeforeClassName | Classnames before input, usually use for css | String | - | -| addonAfter | Elements appended after input | ReactNode | - | -| addonAfterClassName | Classnames after input , usually use for css | String | - | +| Param | Descripiton | Type | Default Value | +| -------------------- | -------------------------------------------- | --------- | ------------- | +| addonBefore | Elements appended before input | ReactNode | - | +| addonBeforeClassName | Classnames before input, usually use for css | String | - | +| addonAfter | Elements appended after input | ReactNode | - | +| addonAfterClassName | Classnames after input , usually use for css | String | - | ## Input/TextArea Inner Methods(Got by refs) -| Param | Descripiton | Type | Default Value | -| ------------ | ------------------------------------------------------------------------------------------------------------------------ | -------- | --- | -| getInputNode | get truely input html dom node | Function | | -| focus | get foucs

**signature**:
Function(start:Number, end: Number)
**params**:
_start_: {Number} cursor postion
_end_: {Number} select end postion | Function | | - +| Param | Descripiton | Type | Default Value | +| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------- | +| getInputNode | get truely input html dom node | Function | | +| focus | get foucs

**signature**:
Function(start:Number, end: Number)
**params**:
_start_: {Number} cursor postion
_end_: {Number} select end postion | Function | | ## ARIA and KeyBoard -| KeyBoard | Descripiton | -| :---------- | :------------------------------ | -| Enter | Trigger the onKeyDown event | -| Any | Trigger the onChange event | + +| KeyBoard | Descripiton | +| :------- | :-------------------------- | +| Enter | Trigger the onKeyDown event | +| Any | Trigger the onChange event | diff --git a/components/input/__docs__/index.md b/components/input/__docs__/index.md index 303647fa85..58e4be3362 100644 --- a/components/input/__docs__/index.md +++ b/components/input/__docs__/index.md @@ -11,7 +11,7 @@ ## 何时使用 -表单输入,一般配合 Form 使用。 +表单输入,一般配合 Form 使用。 - Input 不支持 Number 类型数字,如有需要使用 NumberPicker 支持数字选择 - `1.23` 版本新增了 API `composition` , 开启后可以在输入法结束后再触发 onChange (包括中文输入法、日语输入法等) @@ -20,93 +20,94 @@ ### Input -| 参数 | 说明 | 类型 | 默认值 | 版本支持 | -| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- | --------- | ---- | -| value | 当前值 | String/Number | - | | -| size | 尺寸

**可选值**:
'small'(小)
'medium'(中)
'large'(大) | Enum | 'medium' | | -| defaultValue | 初始化值 | String/Number | - | | -| onChange | 发生改变的时候触发的回调

**签名**:
Function(value: String, e: Event) => void
**参数**:
_value_: {String} 数据
_e_: {Event} DOM事件对象 | Function | func.noop | | -| onKeyDown | 键盘按下的时候触发的回调

**签名**:
Function(e: Event, opts: Object) => void
**参数**:
_e_: {Event} DOM事件对象
_opts_: {Object} 可扩展的附加信息:
- opts.overMaxLength: {Boolean} 已超出最大长度
- opts.beTrimed: {Boolean} 输入的空格被清理 | Function | func.noop | | -| disabled | 禁用状态 | Boolean | false | | -| maxLength | 最大长度 | Number | null | | -| showLimitHint | 是否展现最大长度样式(旧版本为 hasLimitHint,目前仍兼容旧用法,将在2.x直接废弃) | Boolean | false | | -| cutString | 当设置了maxLength时,是否截断超出字符串 | Boolean | true | | -| readOnly | 只读 | Boolean | false | | -| trim | onChange返回会自动去除头尾空字符 | Boolean | false | | -| placeholder | 输入提示 | String | - | | -| onFocus | 获取焦点时候触发的回调

**签名**:
Function(e: Event) => void
**参数**:
_e_: {Event} DOM事件对象 | Function | func.noop | | -| onBlur | 失去焦点时候触发的回调

**签名**:
Function(e: Event) => void
**参数**:
_e_: {Event} DOM事件对象 | Function | func.noop | | -| getValueLength | 自定义字符串计算长度方式

**签名**:
Function(value: String) => Number
**参数**:
_value_: {String} 数据
**返回值**:
{Number} 自定义长度
| Function | func.noop | | -| htmlType | 原生type | String | - | | -| name | name | String | - | | -| state | 状态

**可选值**:
'error'(错误)
'loading'(校验中)
'success'(成功)
'warning'(警告) | Enum | - | | -| isPreview | 是否为预览态 | Boolean | false | | -| renderPreview | 预览态模式下渲染的内容

**签名**:
Function(value: number) => void
**参数**:
_value_: {number} 评分值 | Function | - | | -| composition | 开启后会过滤输入法中间字母状态,文字输入完成后才会触发 onChange | Boolean | false | 1.23 | -| label | label | ReactNode | - | | -| hasClear | 是否出现clear按钮 | Boolean | - | | -| hasBorder | 是否有边框 | Boolean | true | | -| onPressEnter | 按下回车的回调

**签名**:
Function() => void | Function | func.noop | | -| hint | 水印 (Icon的type类型,和hasClear占用一个地方) | String/ReactNode | - | | -| innerBefore | 文字前附加内容 | ReactNode | - | | -| innerAfter | 文字后附加内容 | ReactNode | - | | -| addonBefore | 输入框前附加内容 | ReactNode | - | | -| addonAfter | 输入框后附加内容 | ReactNode | - | | -| addonTextBefore | 输入框前附加文字 | ReactNode | - | | -| addonTextAfter | 输入框后附加文字 | ReactNode | - | | -| autoComplete | (原生input支持) | String | 'off' | | -| autoFocus | 自动聚焦(原生input支持) | Boolean | - | | -| hoverShowClear | hover展示clear (配合 hasClear=true使用) | Boolean | false | 1.24 | +| 参数 | 说明 | 类型 | 默认值 | 版本支持 | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------- | --------- | -------- | +| value | 当前值 | String/Number | - | | +| size | 尺寸

**可选值**:
'small'(小)
'medium'(中)
'large'(大) | Enum | 'medium' | | +| defaultValue | 初始化值 | String/Number | - | | +| onChange | 发生改变的时候触发的回调

**签名**:
Function(value: String, e: Event) => void
**参数**:
_value_: {String} 数据
_e_: {Event} DOM事件对象 | Function | func.noop | | +| onKeyDown | 键盘按下的时候触发的回调

**签名**:
Function(e: Event, opts: Object) => void
**参数**:
_e_: {Event} DOM事件对象
_opts_: {Object} 可扩展的附加信息:
- opts.overMaxLength: {Boolean} 已超出最大长度
- opts.beTrimed: {Boolean} 输入的空格被清理 | Function | func.noop | | +| disabled | 禁用状态 | Boolean | false | | +| maxLength | 最大长度 | Number | null | | +| showLimitHint | 是否展现最大长度样式(旧版本为 hasLimitHint,目前仍兼容旧用法,将在2.x直接废弃) | Boolean | false | | +| cutString | 当设置了maxLength时,是否截断超出字符串 | Boolean | true | | +| readOnly | 只读 | Boolean | false | | +| trim | onChange返回会自动去除头尾空字符 | Boolean | false | | +| placeholder | 输入提示 | String | - | | +| onFocus | 获取焦点时候触发的回调

**签名**:
Function(e: Event) => void
**参数**:
_e_: {Event} DOM事件对象 | Function | func.noop | | +| onBlur | 失去焦点时候触发的回调

**签名**:
Function(e: Event) => void
**参数**:
_e_: {Event} DOM事件对象 | Function | func.noop | | +| getValueLength | 自定义字符串计算长度方式

**签名**:
Function(value: String) => Number
**参数**:
_value_: {String} 数据
**返回值**:
{Number} 自定义长度
| Function | func.noop | | +| htmlType | 原生type | String | - | | +| name | name | String | - | | +| state | 状态

**可选值**:
'error'(错误)
'loading'(校验中)
'success'(成功)
'warning'(警告) | Enum | - | | +| isPreview | 是否为预览态 | Boolean | false | | +| renderPreview | 预览态模式下渲染的内容

**签名**:
Function(value: number) => void
**参数**:
_value_: {number} 评分值 | Function | - | | +| composition | 开启后会过滤输入法中间字母状态,文字输入完成后才会触发 onChange | Boolean | false | 1.23 | +| label | label | ReactNode | - | | +| hasClear | 是否出现clear按钮 | Boolean | - | | +| hasBorder | 是否有边框 | Boolean | true | | +| onPressEnter | 按下回车的回调

**签名**:
Function() => void | Function | func.noop | | +| hint | 水印 (Icon的type类型,和hasClear占用一个地方) | String/ReactNode | - | | +| innerBefore | 文字前附加内容 | ReactNode | - | | +| innerAfter | 文字后附加内容 | ReactNode | - | | +| addonBefore | 输入框前附加内容 | ReactNode | - | | +| addonAfter | 输入框后附加内容 | ReactNode | - | | +| addonTextBefore | 输入框前附加文字 | ReactNode | - | | +| addonTextAfter | 输入框后附加文字 | ReactNode | - | | +| autoComplete | (原生input支持) | String | 'off' | | +| autoFocus | 自动聚焦(原生input支持) | Boolean | - | | +| hoverShowClear | hover展示clear (配合 hasClear=true使用) | Boolean | false | 1.24 | ### Input.TextArea -| 参数 | 说明 | 类型 | 默认值 | 版本支持 | -| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | --------- | ---- | -| value | 当前值 | String/Number | - | | -| size | 尺寸

**可选值**:
'small'(小)
'medium'(中)
'large'(大) | Enum | 'medium' | | -| defaultValue | 初始化值 | String/Number | - | | -| onChange | 发生改变的时候触发的回调

**签名**:
Function(value: String, e: Event) => void
**参数**:
_value_: {String} 数据
_e_: {Event} DOM事件对象 | Function | func.noop | | -| onKeyDown | 键盘按下的时候触发的回调

**签名**:
Function(e: Event, opts: Object) => void
**参数**:
_e_: {Event} DOM事件对象
_opts_: {Object} 可扩展的附加信息:
- opts.overMaxLength: {Boolean} 已超出最大长度
- opts.beTrimed: {Boolean} 输入的空格被清理 | Function | func.noop | | -| disabled | 禁用状态 | Boolean | false | | -| maxLength | 最大长度 | Number | null | | -| showLimitHint | 是否展现最大长度样式(旧版本为 hasLimitHint,目前仍兼容旧用法,将在2.x直接废弃) | Boolean | false | | -| cutString | 当设置了maxLength时,是否截断超出字符串 | Boolean | true | | -| readOnly | 只读 | Boolean | false | | -| trim | onChange返回会自动去除头尾空字符 | Boolean | false | | -| placeholder | 输入提示 | String | - | | -| onFocus | 获取焦点时候触发的回调

**签名**:
Function(e: Event) => void
**参数**:
_e_: {Event} DOM事件对象 | Function | func.noop | | -| onBlur | 失去焦点时候触发的回调

**签名**:
Function(e: Event) => void
**参数**:
_e_: {Event} DOM事件对象 | Function | func.noop | | -| getValueLength | 自定义字符串计算长度方式

**签名**:
Function(value: String) => Number
**参数**:
_value_: {String} 数据
**返回值**:
{Number} 自定义长度
| Function | func.noop | | -| htmlType | 原生type | String | - | | -| name | name | String | - | | -| state | 状态

**可选值**:
'error'(错误)
'warning' | Enum | - | | -| isPreview | 是否为预览态 | Boolean | false | | -| renderPreview | 预览态模式下渲染的内容

**签名**:
Function(value: number) => void
**参数**:
_value_: {number} 评分值 | Function | - | | -| composition | 开启后会过滤输入法中间字母状态,文字输入完成后才会触发 onChange | Boolean | false | 1.23 | -| hasBorder | 是否有边框 | Boolean | true | | -| autoHeight | 自动高度 true / {minRows: 2, maxRows: 4} | Boolean/Object | false | | -| rows | 多行文本框高度
(不要直接用height设置多行文本框的高度, ie9 10会有兼容性问题) | Number | 4 | | +| 参数 | 说明 | 类型 | 默认值 | 版本支持 | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------- | --------- | -------- | +| value | 当前值 | String/Number | - | | +| size | 尺寸

**可选值**:
'small'(小)
'medium'(中)
'large'(大) | Enum | 'medium' | | +| defaultValue | 初始化值 | String/Number | - | | +| onChange | 发生改变的时候触发的回调

**签名**:
Function(value: String, e: Event) => void
**参数**:
_value_: {String} 数据
_e_: {Event} DOM事件对象 | Function | func.noop | | +| onKeyDown | 键盘按下的时候触发的回调

**签名**:
Function(e: Event, opts: Object) => void
**参数**:
_e_: {Event} DOM事件对象
_opts_: {Object} 可扩展的附加信息:
- opts.overMaxLength: {Boolean} 已超出最大长度
- opts.beTrimed: {Boolean} 输入的空格被清理 | Function | func.noop | | +| disabled | 禁用状态 | Boolean | false | | +| maxLength | 最大长度 | Number | null | | +| showLimitHint | 是否展现最大长度样式(旧版本为 hasLimitHint,目前仍兼容旧用法,将在2.x直接废弃) | Boolean | false | | +| cutString | 当设置了maxLength时,是否截断超出字符串 | Boolean | true | | +| readOnly | 只读 | Boolean | false | | +| trim | onChange返回会自动去除头尾空字符 | Boolean | false | | +| placeholder | 输入提示 | String | - | | +| onFocus | 获取焦点时候触发的回调

**签名**:
Function(e: Event) => void
**参数**:
_e_: {Event} DOM事件对象 | Function | func.noop | | +| onBlur | 失去焦点时候触发的回调

**签名**:
Function(e: Event) => void
**参数**:
_e_: {Event} DOM事件对象 | Function | func.noop | | +| getValueLength | 自定义字符串计算长度方式

**签名**:
Function(value: String) => Number
**参数**:
_value_: {String} 数据
**返回值**:
{Number} 自定义长度
| Function | func.noop | | +| htmlType | 原生type | String | - | | +| name | name | String | - | | +| state | 状态

**可选值**:
'error'(错误)
'warning' | Enum | - | | +| isPreview | 是否为预览态 | Boolean | false | | +| renderPreview | 预览态模式下渲染的内容

**签名**:
Function(value: number) => void
**参数**:
_value_: {number} 评分值 | Function | - | | +| composition | 开启后会过滤输入法中间字母状态,文字输入完成后才会触发 onChange | Boolean | false | 1.23 | +| hasBorder | 是否有边框 | Boolean | true | | +| autoHeight | 自动高度 true / {minRows: 2, maxRows: 4} | Boolean/Object | false | | +| rows | 多行文本框高度
(不要直接用height设置多行文本框的高度, ie9 10会有兼容性问题) | Number | 4 | | +| hasClear | 是否出现clear按钮 | Boolean | - | | ### Input.Group -| 参数 | 说明 | 类型 | 默认值 | -| -------------------- | ----------- | --------- | --- | -| addonBefore | 输入框前附加内容 | ReactNode | - | -| addonBeforeClassName | 输入框前附加内容css | String | - | -| addonAfter | 输入框后附加内容 | ReactNode | - | -| addonAfterClassName | 输入框后额外css | String | - | -| rtl | rtl | Boolean | - | +| 参数 | 说明 | 类型 | 默认值 | +| -------------------- | ------------------- | --------- | ------ | +| addonBefore | 输入框前附加内容 | ReactNode | - | +| addonBeforeClassName | 输入框前附加内容css | String | - | +| addonAfter | 输入框后附加内容 | ReactNode | - | +| addonAfterClassName | 输入框后额外css | String | - | +| rtl | rtl | Boolean | - | ## Input/TextArea 内部函数(通过refs获取) -| 参数 | 说明 | 类型 | 默认值 | -| ------------ | ---------------------------------------------------------------------------------------------------------------------------- | -------- | --- | -| getInputNode | 获取真正input节点 | Function | | -| focus | 获取焦点

**签名**:
Function(start:Number, end: Number)
**参数**:
_start_: {Number} 光标起始位置
_end_: {Number} 选择结束位置 | Function | | +| 参数 | 说明 | 类型 | 默认值 | +| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------- | ------ | +| getInputNode | 获取真正input节点 | Function | | +| focus | 获取焦点

**签名**:
Function(start:Number, end: Number)
**参数**:
_start_: {Number} 光标起始位置
_end_: {Number} 选择结束位置 | Function | | ## 无障碍键盘操作指南 -| 按键 | 说明 | -| :---- | :------------ | +| 按键 | 说明 | +| :---- | :---------------- | | Enter | 触发onKeyDown事件 | | Any | 触发onChange事件 | diff --git a/components/input/__tests__/textarea-spec.js b/components/input/__tests__/textarea-spec.js index 3635785399..fa15bf328a 100644 --- a/components/input/__tests__/textarea-spec.js +++ b/components/input/__tests__/textarea-spec.js @@ -1,4 +1,5 @@ -import React from 'react'; +import React, { useState } from 'react'; +import ReactTestUtils from 'react-dom/test-utils'; import ReactDOM from 'react-dom'; import Enzyme, { mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; @@ -7,7 +8,10 @@ import assert from 'power-assert'; import Input from '../index'; Enzyme.configure({ adapter: new Adapter() }); - +function delay(duration) { + return new Promise(resolve => setTimeout(resolve, duration)); +} +/* eslint-disable no-undef, react/jsx-filename-extension */ describe('TextArea', () => { describe('render', () => { let parent; @@ -23,23 +27,55 @@ describe('TextArea', () => { }); it('should textarea isPreview', () => { - ReactDOM.render(, parent); + ReactDOM.render( + , + parent + ); assert(document.querySelectorAll('#ispreview-input')[0].innerText === 'abc'); }); it('should textarea isPreview compatible value null', () => { - ReactDOM.render(, parent); + ReactDOM.render( + , + parent + ); assert(document.querySelectorAll('#ispreview-input-null')[0].innerText === ''); }); it('should textarea renderPreview', () => { ReactDOM.render( - 'ddd'} />, + 'ddd'} + />, parent ); assert(document.querySelectorAll('#renderpreview-input')[0].innerText === 'ddd'); }); + it('should support hasClear ,close #4334', async () => { + const ref = { current: null }; + function Demo() { + const [value, setValue] = useState('aaa'); + ref.current = { value }; + return ( + setValue(v)} + /> + ); + } + mount(, { attachTo: parent }); + await delay(100); + const btn = parent.querySelector('.next-input-clear'); + ReactTestUtils.Simulate.click(btn); + assert(ref.current.value === ''); + }); }); describe('behavior', () => { @@ -48,7 +84,9 @@ describe('TextArea', () => { const onChange = sinon.spy(); const onFocus = sinon.spy(); const onBlur = sinon.spy(); - const wrapper = mount(); + const wrapper = mount( + + ); wrapper.find('textarea').simulate('change', { target: { value: '20' } }); assert(onChange.calledOnce); wrapper.find('textarea').simulate('focus'); @@ -125,7 +163,9 @@ describe('TextArea', () => { }); it('should support maxLength & hasLimitHint', done => { - const wrapper = mount(); + const wrapper = mount( + + ); assert(!wrapper.find('.next-input-len').hasClass('next-error')); wrapper.find('textarea').simulate('change', { target: { value: '12345678901' } }); @@ -176,7 +216,9 @@ describe('TextArea', () => { { - assert(this.refs.textarea.getInstance().getInputNode() !== undefined); + assert( + this.refs.textarea.getInstance().getInputNode() !== undefined + ); }} /> ); @@ -191,7 +233,13 @@ describe('TextArea', () => { it('should support getValueLength', done => { const getValueLength = sinon.spy(); - mount(); + mount( + + ); assert(getValueLength.calledOnce); let getValueLength2 = value => { @@ -208,7 +256,12 @@ describe('TextArea', () => { assert(wrapper.find('.next-input-len').text() === '1/10'); const wrapper2 = mount( - + ); assert(wrapper2.find('.next-input-len').text() === '1/10'); @@ -219,15 +272,23 @@ describe('TextArea', () => { const wrapper = mount(); // console.log(wrapper.find('textarea[data-real]').instance().clientHeight) // let originHeight = wrapper.find('textarea[data-real]').instance().clientHeight; - wrapper.find('textarea[data-real]').simulate('change', { target: { value: '1\n2\n3\n4\n5\n' } }); + wrapper + .find('textarea[data-real]') + .simulate('change', { target: { value: '1\n2\n3\n4\n5\n' } }); // assert(wrapper.find('textarea[data-real]').at(0).getElement().clientHeight > originHeight); - const wrapper2 = mount(); + const wrapper2 = mount( + + ); // console.log(wrapper2.find('textarea[data-real]').instance().clientHeight) // let originHeight = wrapper2.find('textarea[data-real]').instance().clientHeight; - wrapper2.find('textarea[data-real]').simulate('change', { target: { value: '1\n2\n3\n4\n5\n' } }); - wrapper2.find('textarea[data-real]').simulate('change', { target: { value: '1\n2\n3\n4' } }); + wrapper2 + .find('textarea[data-real]') + .simulate('change', { target: { value: '1\n2\n3\n4\n5\n' } }); + wrapper2 + .find('textarea[data-real]') + .simulate('change', { target: { value: '1\n2\n3\n4' } }); // @@ -241,10 +302,7 @@ describe('TextArea', () => { } } const wrapper = mount(); - wrapper - .ref('textarea') - .getInstance() - .focus(); + wrapper.ref('textarea').getInstance().focus(); wrapper.update(); // assert(wrapper.find('.next-input').hasClass('next-focus')); diff --git a/components/input/base.jsx b/components/input/base.jsx index f2644bb557..9695afbee5 100644 --- a/components/input/base.jsx +++ b/components/input/base.jsx @@ -2,11 +2,11 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import { polyfill } from 'react-lifecycles-compat'; - import ConfigProvider from '../config-provider'; import { func } from '../util'; import zhCN from '../locale/zh-cn'; + class Base extends React.Component { static propTypes = { ...ConfigProvider.propTypes, @@ -252,18 +252,10 @@ class Base extends React.Component { const content = rtl ? `${maxLength}/${len}` : `${len}/${maxLength}`; - return maxLength && showLimitHint ? {content} : null; + return maxLength && showLimitHint ? {content} : null } - renderControl() { - const lenWrap = this.renderLength(); - return lenWrap ? ( - this.focus()} className={`${this.props.prefix}input-control`}> - {lenWrap} - - ) : null; - } getClass() { const { disabled, state, prefix } = this.props; diff --git a/components/input/index.d.ts b/components/input/index.d.ts index efaea760e7..ba8fd838cd 100644 --- a/components/input/index.d.ts +++ b/components/input/index.d.ts @@ -133,6 +133,10 @@ export interface TextAreaProps extends HTMLAttributesWeak, CommonProps { * 开启后会过滤输入法中间字母状态,文字输入完成后才会触发 onChange */ composition?: boolean; + /** + * 是否出现clear按钮 + */ + hasClear?: boolean; } export class TextArea extends React.Component {} diff --git a/components/input/main.scss b/components/input/main.scss index d292b14f2a..d9181b08d2 100644 --- a/components/input/main.scss +++ b/components/input/main.scss @@ -55,6 +55,7 @@ } } + display: inline-table; border-collapse: separate; font-size: 0; @@ -97,6 +98,7 @@ &.#{$css-prefix}small textarea { font-size: $form-element-medium-font-size; } + &.#{$css-prefix}large textarea { font-size: $form-element-large-font-size; } @@ -107,12 +109,26 @@ border-radius: $input-multiple-corner; } + #{$input-prefix}-control-textarea { + display: flex; + justify-content: end; + padding: 0 $input-l-icon-padding-right 4px ; + } #{$input-prefix}-len { - padding: 0 $input-l-icon-padding-right 4px; display: block; text-align: right; width: auto; } + + #{$input-prefix}-clear-before { + &::before { + content: "|"; + color:$input-disabled-border-color; + display: inline-block; + padding: 0 4px 0 2px; + } + } + border-radius: $input-multiple-corner; font-size: 0; } @@ -126,12 +142,15 @@ z-index: 1; position: absolute; } + #{$input-prefix}-hint { opacity: 1; } } - #{$input-prefix}-clear-icon, .#{$css-prefix}icon-eye, .#{$css-prefix}icon-eye-close { + #{$input-prefix}-clear-icon, + .#{$css-prefix}icon-eye, + .#{$css-prefix}icon-eye-close { &:hover { cursor: pointer; color: $input-hint-hover-color; @@ -141,7 +160,7 @@ @mixin clear-icon-visible { opacity: 1; - + #{$input-prefix}-hint { + +#{$input-prefix}-hint { opacity: 0; } } @@ -150,7 +169,8 @@ opacity: 0; } - &:hover, &.#{$css-prefix}focus { + &:hover, + &.#{$css-prefix}focus { border-color: $input-hover-border-color; background-color: $input-hover-bg-color; @@ -191,7 +211,8 @@ border-color: $input-feedback-error-border-color; background-color: $input-feedback-error-bg-color; - input, textarea { + input, + textarea { color: $input-feedback-error-color; } @@ -232,13 +253,13 @@ } } - > * { + >* { display: table-cell; width: 1%; top: 0; } - > *:not(:last-child) { + >*:not(:last-child) { padding-right: $s-1; } @@ -249,23 +270,29 @@ #{$input-prefix}-warning-icon { color: $input-feedback-warning-color; + &::before { content: $input-feedback-warning-icon; } } + #{$input-prefix}-success-icon { color: $input-feedback-success-color; + &::before { content: $input-feedback-success-icon; } } + #{$input-prefix}-loading-icon { color: $input-feedback-loading-color; + &::before { content: $input-feedback-loading-icon; animation: loadingCircle 1s infinite linear; } } + #{$input-prefix}-clear-icon { &::before { content: $input-feedback-clear-icon; @@ -273,7 +300,8 @@ } } - &-label, &-inner-text { + &-label, + &-inner-text { color: $input-label-color; } @@ -285,15 +313,18 @@ &.#{$css-prefix}disabled { @include input-disabled(); - input, textarea { + input, + textarea { -webkit-text-fill-color: $input-disabled-color; color: $input-disabled-color; @include input-placeholder($input-disabled-color); } - #{$input-prefix}-label, #{$input-prefix}-inner-text { + #{$input-prefix}-label, + #{$input-prefix}-inner-text { color: $input-disabled-color; } + #{$input-prefix}-len { color: $input-disabled-color; } @@ -302,6 +333,7 @@ #{$input-prefix}-clear { opacity: 0; } + #{$input-prefix}-hint { opacity: 1; } @@ -319,7 +351,9 @@ } } - &-inner, &-control, &-label { + &-inner, + &-control, + &-label { display: table-cell; width: 1px; vertical-align: middle; @@ -343,15 +377,17 @@ border-radius: 0 !important; } - > #{$input-prefix} { + >#{$input-prefix} { border-radius: 0; - &.#{$css-prefix}focus,&:hover { + + &.#{$css-prefix}focus, + &:hover { position: relative; z-index: 1; } } - > #{$input-prefix}:first-child { + >#{$input-prefix}:first-child { &.#{$css-prefix}small { border-top-left-radius: $form-element-small-corner !important; border-bottom-left-radius: $form-element-small-corner !important; @@ -367,7 +403,8 @@ border-bottom-left-radius: $form-element-large-corner !important; } } - > #{$input-prefix}:last-child { + + >#{$input-prefix}:last-child { &.#{$css-prefix}small { border-top-right-radius: $form-element-small-corner !important; border-bottom-right-radius: $form-element-small-corner !important; @@ -384,6 +421,7 @@ } } } + &-group-addon { width: 1px; display: table-cell; @@ -394,40 +432,48 @@ &:first-child { border-bottom-right-radius: 0 !important; border-top-right-radius: 0 !important; + //TODO: removed in 2.x - > * { + >* { margin-right: calc(0px - #{$input-border-width}); border-bottom-right-radius: 0 !important; border-top-right-radius: 0 !important; + &.#{$css-prefix}focus { position: relative; z-index: 1; } - > #{$input-prefix} { + + >#{$input-prefix} { border-bottom-right-radius: 0 !important; border-top-right-radius: 0 !important; } - > #{$input-prefix}.#{$css-prefix}focus { + + >#{$input-prefix}.#{$css-prefix}focus { position: relative; z-index: 1; } } } + &:last-child { border-bottom-left-radius: 0 !important; border-top-left-radius: 0 !important; + //TODO: removed in 2.x - > * { + >* { margin-left: calc(0px - #{$input-border-width}); border-bottom-left-radius: 0 !important; border-top-left-radius: 0 !important; - > #{$input-prefix} { + + >#{$input-prefix} { border-bottom-left-radius: 0 !important; border-top-left-radius: 0 !important; } } } } + &-group-text { color: $input-addon-text-color; background-color: $input-addon-bg-color; @@ -438,6 +484,7 @@ &:first-child { border-right-width: 0; } + &:last-child { border-left-width: 0; } diff --git a/components/input/textarea.jsx b/components/input/textarea.jsx index 27f0ef4eba..f31db89e20 100644 --- a/components/input/textarea.jsx +++ b/components/input/textarea.jsx @@ -2,6 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import PropTypes from 'prop-types'; import classNames from 'classnames'; +import Input from '../locale/zh-cn'; import { obj, env } from '../util'; import Base from './base'; @@ -36,6 +37,10 @@ const hiddenStyle = { right: 0, }; +function preventDefault(e) { + e.preventDefault(); +} + /** * Input.TextArea * @order 2 @@ -71,6 +76,10 @@ export default class TextArea extends Base { * @param {number} value 评分值 */ renderPreview: PropTypes.func, + /** + * 国际化配置 + */ + locale: PropTypes.object, }; static defaultProps = { @@ -79,6 +88,7 @@ export default class TextArea extends Base { isPreview: false, rows: 4, autoHeight: false, + locale: Input.Input, }; constructor(props) { @@ -217,7 +227,62 @@ export default class TextArea extends Base { saveHelpRef(ref) { this.helpRef = ref; } + handleKeyDownFromClear = e => { + if (e.keyCode === 13) { + this.onClear(e); + } + }; + + onClear(e) { + if (this.props.disabled) { + return; + } + // 非受控模式清空内部数据 + if (!('value' in this.props)) { + this.setState({ + value: '', + }); + } + this.props.onChange('', e, 'clear'); + this.focus(); + } + renderClear() { + const { hasClear, readOnly, state, prefix, disabled, showLimitHint, maxLength,locale } = this.props; + const len = maxLength > 0 && this.state.value ? this.getValueLength(this.state.value) : 0; + let clearWrap = null; + // showClear属性应该与disable属性为互斥状态 + const showClear = hasClear && !readOnly && !!`${this.state.value}` && !disabled; + const cls = classNames({ + [`${prefix}input-clear-before`]: !!showLimitHint, + [`${prefix}input-len`]: true, + [`${prefix}error`]: len > maxLength, + }) + clearWrap = showClear ? + {locale.clear} + : null; + if (state === 'loading') { + clearWrap = null; + } + return clearWrap; + } + renderControl() { + const lenWrap = this.renderLength(); + const { prefix } = this.props + const cls = classNames({ + [`${prefix}input-control`]: true, + [`${prefix}input-control-textarea`]: true, + }) + return ( + this.focus()} className={cls}> + {lenWrap && lenWrap} {this.renderClear()} + + ); + } render() { const { rows,