diff --git a/docs/components/TextInput.md b/docs/components/TextInput.md index dc983360..aec937eb 100644 --- a/docs/components/TextInput.md +++ b/docs/components/TextInput.md @@ -43,6 +43,14 @@ Automatically correct spelling mistakes (only available in iOS Safari). If `true`, focuses the input on `componentDidMount`. Only the first form element in a document with `autofocus` is focused. +**blurOnSubmit**: bool + +If `true`, the text field will blur when submitted. The default value is `true` +for single-line fields and `false` for multiline fields. Note, for multiline +fields setting `blurOnSubmit` to `true` means that pressing return will blur +the field and trigger the `onSubmitEditing` event instead of inserting a +newline into the field. + **clearTextOnFocus**: bool = false If `true`, clears the text field automatically when focused. @@ -106,11 +114,15 @@ Callback that is called when the text input is focused. Callback that is called when a key is pressed. Pressed key value is passed as an argument to the callback handler. Fires before `onChange` callbacks. -(web) **onSelectionChange**: function +**onSelectionChange**: function Callback that is called when the text input's selection changes. The following object is passed as an argument to the callback handler. +**onSubmitEditing**: function + +Callback that is called when the keyboard's submit button is pressed. + ```js { selectionDirection, diff --git a/src/components/TextInput/index.js b/src/components/TextInput/index.js index 28b36ea4..bfc837f1 100644 --- a/src/components/TextInput/index.js +++ b/src/components/TextInput/index.js @@ -14,6 +14,13 @@ import React, { Component, PropTypes } from 'react'; const viewStyleProps = Object.keys(ViewStylePropTypes); +const normalizeEventHandler = (handler) => (e) => { + if (handler) { + e.nativeEvent.text = e.target.value; + return handler(e); + } +}; + class TextInput extends Component { static displayName = 'TextInput'; @@ -23,6 +30,7 @@ class TextInput extends Component { autoComplete: PropTypes.string, autoCorrect: PropTypes.bool, autoFocus: PropTypes.bool, + blurOnSubmit: PropTypes.bool, clearTextOnFocus: PropTypes.bool, defaultValue: PropTypes.string, editable: PropTypes.bool, @@ -144,37 +152,32 @@ class TextInput extends Component { const rootStyles = pick(flattenedStyle, viewStyleProps); const textStyles = omit(flattenedStyle, viewStyleProps); - const propsCommon = { + const props = { autoCapitalize, autoComplete, autoCorrect: autoCorrect ? 'on' : 'off', autoFocus, defaultValue, maxLength, - onBlur: this._handleBlur, - onChange: this._handleChange, - onFocus: this._handleFocus, - onKeyPress, - onSelect: onSelectionChange && this._handleSelectionChange, + onBlur: normalizeEventHandler(this._handleBlur), + onChange: normalizeEventHandler(this._handleChange), + onFocus: normalizeEventHandler(this._handleFocus), + onKeyPress: normalizeEventHandler(this._handleKeyPress), + onSelect: normalizeEventHandler(this._handleSelectionChange), readOnly: !editable, ref: this._setInputRef, style: [ styles.input, textStyles, { outline: style.outline } ], value }; - const propsMultiline = { - ...propsCommon, - maxRows: maxNumberOfLines || numberOfLines, - minRows: numberOfLines - }; - - const propsSingleline = { - ...propsCommon, - type - }; + if (multiline) { + props.maxRows = maxNumberOfLines || numberOfLines; + props.minRows = numberOfLines; + } else { + props.type = type; + } const component = multiline ? TextareaAutosize : 'input'; - const props = multiline ? propsMultiline : propsSingleline; const optionalPlaceholder = placeholder && this.state.showPlaceholder && ( @@ -207,40 +210,46 @@ class TextInput extends Component { _handleBlur = (e) => { const { onBlur } = this.props; - const text = e.target.value; + const { text } = e.nativeEvent; this.setState({ showPlaceholder: text === '' }); - this.blur(); if (onBlur) { onBlur(e); } } _handleChange = (e) => { const { onChange, onChangeText } = this.props; - const text = e.target.value; - e.nativeEvent.text = text; + const { text } = e.nativeEvent; this.setState({ showPlaceholder: text === '' }); if (onChange) { onChange(e); } if (onChangeText) { onChangeText(text); } - if (!this._inputRef) { - // calling `this.props.onChange` or `this.props.onChangeText` - // may clean up the input itself. Exits here. - return; - } } _handleClick = (e) => { - this.focus(); + if (this.props.editable) { + this.focus(); + } } _handleFocus = (e) => { const { clearTextOnFocus, onFocus, selectTextOnFocus } = this.props; + const { text } = e.nativeEvent; const node = ReactDOM.findDOMNode(this._inputRef); - const text = e.target.value; if (onFocus) { onFocus(e); } if (clearTextOnFocus) { this.clear(); } - if (selectTextOnFocus) { node.select(); } + if (selectTextOnFocus) { node && node.select(); } this.setState({ showPlaceholder: text === '' }); } + _handleKeyPress = (e) => { + const { blurOnSubmit, multiline, onKeyPress, onSubmitEditing } = this.props; + const blurOnSubmitDefault = !multiline; + const shouldBlurOnSubmit = blurOnSubmit == null ? blurOnSubmitDefault : blurOnSubmit + if (onKeyPress) { onKeyPress(e); } + if (!e.isDefaultPrevented() && e.which === 13) { + if (onSubmitEditing) { onSubmitEditing(e); } + if (shouldBlurOnSubmit) { this.blur(); } + } + } + _handleSelectionChange = (e) => { const { onSelectionChange } = this.props; try { @@ -282,7 +291,6 @@ const styles = StyleSheet.create({ }, placeholder: { bottom: 0, - justifyContent: 'center', left: 0, position: 'absolute', right: 0,