Skip to content

Instantly share code, notes, and snippets.

@codewithpassion
Forked from catchin/MultilineTextInput.js
Last active January 26, 2018 12:39
Show Gist options
  • Save codewithpassion/d2d1a3e4d94c547e6b343ea5e9fe9845 to your computer and use it in GitHub Desktop.
Save codewithpassion/d2d1a3e4d94c547e6b343ea5e9fe9845 to your computer and use it in GitHub Desktop.
This is a workaround for the buggy react-native TextInput multiline on Android. Inspired by the comments on https://github.com/facebook/react-native/issues/12717. Based the work of @catchin with the addition of handling the state via the container.
import React, { PropTypes, PureComponent } from 'react';
import { TextInput } from 'react-native';
import debounce from 'debounce';
/**
* This is a workaround for the buggy react-native TextInput multiline on Android.
*
* Can be removed once https://github.com/facebook/react-native/issues/12717
* is fixed.
*
* Example for usage:
* <MultilineTextInput value={this.state.text} onChangeText={text => setState({text})} />
*/
export default class MultilineTextInput extends PureComponent {
constructor(props) {
super(props);
this.state = { selection: { start: 0, end: 0 } };
// Prevent 2 newlines for some Android versions, because they dispatch onSubmitEditing twice
this.onSubmitEditing = debounce(this.onSubmitEditing.bind(this), 100, true);
}
componentWillReceiveProps(props) {
if (props.selection) {
this.setState({ selection: props.selection });
}
}
focus() {
this.refs.text.focus();
}
onSubmitEditing() {
const { selection } = this.state;
const { value } = this.props;
const newText = `${value.slice(0, selection.start)}\n${value.slice(selection.end)}`;
this.props.onChangeText(newText);
// move cursor only for this case, because in other cases a change of the selection is not allowed by Android
if (selection.start !== this.props.value.length && selection.start === selection.end) {
const newSelection = {
selection: {
start: selection.start + 1,
end: selection.end + 1,
},
};
if (this.props.onSelectionChange) {
this.props.onSelectionChange({ nativeEvent: newSelection });
} else {
this.setState(newSelection);
}
}
}
render() {
return (
<TextInput
ref="text"
multiline
blurOnSubmit={false}
selection={this.state.selection}
value={this.props.value}
onSelectionChange={event => this.setState({ selection: event.nativeEvent.selection })}
onChangeText={this.props.onChangeText}
onSubmitEditing={this.onSubmitEditing}
{...this.props}
/>
);
}
}
MultilineTextInput.propTypes = {
value: PropTypes.string.isRequired,
onChangeText: PropTypes.func.isRequired,
};
Copy link

ghost commented Dec 19, 2017

Thank you very much for this workaround. :)
It was a great help and we used it in our project work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment