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..0781c923f4 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, @@ -240,7 +240,26 @@ class Base extends React.Component { }); this.props.onBlur(e); } + + 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(); + } renderLength() { const { maxLength, showLimitHint, prefix, rtl } = this.props; const len = maxLength > 0 && this.state.value ? this.getValueLength(this.state.value) : 0; @@ -252,18 +271,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/input.jsx b/components/input/input.jsx index 5f214e7da0..d31bcd02ca 100644 --- a/components/input/input.jsx +++ b/components/input/input.jsx @@ -240,27 +240,6 @@ class Input extends Base { this.onKeyDown(e); }; - 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(); - } - render() { const { size, diff --git a/components/input/main.scss b/components/input/main.scss index d292b14f2a..1a9f67d02e 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,34 @@ border-radius: $input-multiple-corner; } - #{$input-prefix}-len { + #{$input-prefix}-textarea-control { + display: flex; + justify-content: end; padding: 0 $input-l-icon-padding-right 4px; + } + + #{$input-prefix}-len, + #{$input-prefix}-textarea-clear { display: block; text-align: right; width: auto; } + + #{$input-prefix}-textarea-clear { + cursor: pointer; + padding-left: 4px; + } + + #{$input-prefix}-textarea-control-line { + &::after { + content: "|"; + color: $input-disabled-border-color; + display: inline-block; + font-size: $input-multiple-font-size; + + } + } + border-radius: $input-multiple-corner; font-size: 0; } @@ -126,12 +150,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 +168,7 @@ @mixin clear-icon-visible { opacity: 1; - + #{$input-prefix}-hint { + +#{$input-prefix}-hint { opacity: 0; } } @@ -150,7 +177,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 +219,8 @@ border-color: $input-feedback-error-border-color; background-color: $input-feedback-error-bg-color; - input, textarea { + input, + textarea { color: $input-feedback-error-color; } @@ -215,7 +244,9 @@ } &-control { - #{$input-prefix}-len { + + #{$input-prefix}-len, + #{$input-prefix}-textarea-clear { font-size: $input-maxlen-font-size; line-height: $input-maxlen-font-size; color: $input-maxlen-color; @@ -232,13 +263,13 @@ } } - > * { + >* { display: table-cell; width: 1%; top: 0; } - > *:not(:last-child) { + >*:not(:last-child) { padding-right: $s-1; } @@ -249,23 +280,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 +310,8 @@ } } - &-label, &-inner-text { + &-label, + &-inner-text { color: $input-label-color; } @@ -285,15 +323,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 +343,7 @@ #{$input-prefix}-clear { opacity: 0; } + #{$input-prefix}-hint { opacity: 1; } @@ -319,7 +361,9 @@ } } - &-inner, &-control, &-label { + &-inner, + &-control, + &-label { display: table-cell; width: 1px; vertical-align: middle; @@ -343,15 +387,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 +413,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 +431,7 @@ } } } + &-group-addon { width: 1px; display: table-cell; @@ -394,40 +442,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 +494,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..c06002fd4c 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 zhCN from '../locale/zh-cn'; import { obj, env } from '../util'; import Base from './base'; @@ -71,6 +72,10 @@ export default class TextArea extends Base { * @param {number} value 评分值 */ renderPreview: PropTypes.func, + /** + * 国际化配置 + */ + locale: PropTypes.object, }; static defaultProps = { @@ -79,6 +84,7 @@ export default class TextArea extends Base { isPreview: false, rows: 4, autoHeight: false, + locale: zhCN.TextArea, }; constructor(props) { @@ -218,6 +224,46 @@ export default class TextArea extends Base { this.helpRef = ref; } + renderClear() { + const { hasClear, readOnly, state, prefix, disabled, locale } = this.props; + let clearWrap = null; + // showClear属性应该与disable属性为互斥状态 + const showClear = hasClear && !readOnly && !!`${this.state.value}` && !disabled; + const cls = classNames({ + [`${prefix}input-textarea-clear`]: true, + }); + clearWrap = showClear ? ( + + {' '} + {locale.clear} + + ) : null; + if (state === 'loading') { + clearWrap = null; + } + return clearWrap; + } + + renderControl() { + const { prefix } = this.props; + const lenWrap = this.renderLength(); + const clearText = this.renderClear(); + const isShowLine = Boolean(lenWrap && clearText); + + const cls = classNames(`${prefix}input-control`, `${prefix}input-textarea-control`); + + return lenWrap || clearText ? ( + this.focus()} className={cls}> + {lenWrap} + {isShowLine && } + {clearText} + + ) : null; + } render() { const { rows, diff --git a/components/locale/en-us.ts b/components/locale/en-us.ts index bc6b5c49a0..33aa6c2dcc 100644 --- a/components/locale/en-us.ts +++ b/components/locale/en-us.ts @@ -73,6 +73,9 @@ const locale: Locale = { Input: { clear: 'Clear', }, + TextArea: { + clear: 'Clear', + }, List: { empty: 'No Data', }, diff --git a/components/locale/id-id.ts b/components/locale/id-id.ts index 2afba5114d..ec3a731e52 100644 --- a/components/locale/id-id.ts +++ b/components/locale/id-id.ts @@ -74,6 +74,9 @@ const locale: Locale = { Input: { clear: 'Reset', }, + TextArea: { + clear: 'Reset', + }, List: { empty: 'Tidak Ada Data', }, diff --git a/components/locale/it-it.ts b/components/locale/it-it.ts index b7ad3bbeb0..fdb0d2dcd2 100644 --- a/components/locale/it-it.ts +++ b/components/locale/it-it.ts @@ -74,6 +74,9 @@ const locale: Locale = { Input: { clear: 'Cancella', }, + TextArea: { + clear: 'Cancella', + }, List: { empty: 'Nessun dato', }, diff --git a/components/locale/ja-jp.ts b/components/locale/ja-jp.ts index eb8c36889b..356a8ff55e 100644 --- a/components/locale/ja-jp.ts +++ b/components/locale/ja-jp.ts @@ -73,6 +73,9 @@ const locale: Locale = { Input: { clear: 'クリア', }, + TextArea: { + clear: 'クリア', + }, List: { empty: 'データなし', }, diff --git a/components/locale/ko-kr.ts b/components/locale/ko-kr.ts index c00634f98f..b982ec5c0c 100644 --- a/components/locale/ko-kr.ts +++ b/components/locale/ko-kr.ts @@ -73,6 +73,9 @@ const locale: Locale = { Input: { clear: '삭제', }, + TextArea: { + clear: '삭제', + }, List: { empty: '노데이터', }, diff --git a/components/locale/ms-my.ts b/components/locale/ms-my.ts index 97671a21a2..cc165c17c6 100644 --- a/components/locale/ms-my.ts +++ b/components/locale/ms-my.ts @@ -73,6 +73,9 @@ const locale: Locale = { Input: { clear: 'Jelas', }, + TextArea: { + clear: 'Jelas', + }, List: { empty: 'tiada data', }, diff --git a/components/locale/pt-pt.ts b/components/locale/pt-pt.ts index 11352ccfc7..309b102692 100644 --- a/components/locale/pt-pt.ts +++ b/components/locale/pt-pt.ts @@ -73,6 +73,9 @@ const locale = { Input: { clear: 'Limpar', }, + TextArea: { + clear: 'Limpar', + }, List: { empty: 'Vazio', }, diff --git a/components/locale/th-th.ts b/components/locale/th-th.ts index dbb4ac9877..db27ca9d67 100644 --- a/components/locale/th-th.ts +++ b/components/locale/th-th.ts @@ -73,6 +73,9 @@ const locale: Locale = { Input: { clear: 'ชัดเจน', }, + TextArea: { + clear: 'ชัดเจน', + }, List: { empty: 'ไม่มีข้อมูล', }, diff --git a/components/locale/types.ts b/components/locale/types.ts index b1fbe45403..9f1aaf432b 100644 --- a/components/locale/types.ts +++ b/components/locale/types.ts @@ -80,6 +80,9 @@ export interface Locale extends LocaleConfig { Input: { clear: string; }; + TextArea: { + clear: string; + }; List: { empty: string; }; diff --git a/components/locale/vi-vn.ts b/components/locale/vi-vn.ts index 0baba4d46b..d4cd5ddb68 100644 --- a/components/locale/vi-vn.ts +++ b/components/locale/vi-vn.ts @@ -74,6 +74,9 @@ const locale: Locale = { Input: { clear: 'Xóa', }, + TextArea: { + clear: 'Xóa', + }, List: { empty: 'Không có dữ liệu', }, diff --git a/components/locale/zh-cn.ts b/components/locale/zh-cn.ts index f5fcb1ea3b..16a48d535b 100644 --- a/components/locale/zh-cn.ts +++ b/components/locale/zh-cn.ts @@ -73,6 +73,9 @@ const locale: Locale = { Input: { clear: '清除', }, + TextArea: { + clear: '清除', + }, List: { empty: '没有数据', }, diff --git a/components/locale/zh-hk.ts b/components/locale/zh-hk.ts index 32188bf3bf..e9fd332bc6 100644 --- a/components/locale/zh-hk.ts +++ b/components/locale/zh-hk.ts @@ -73,6 +73,9 @@ const locale: Locale = { Input: { clear: '清除', }, + TextArea: { + clear: '清除', + }, List: { empty: '沒有數據', }, diff --git a/components/locale/zh-tw.ts b/components/locale/zh-tw.ts index f0a4f995eb..180d0452c7 100644 --- a/components/locale/zh-tw.ts +++ b/components/locale/zh-tw.ts @@ -73,6 +73,9 @@ const locale: Locale = { Input: { clear: '清除', }, + TextArea: { + clear: '清除', + }, List: { empty: '沒有數據', },