Skip to content

Instantly share code, notes, and snippets.

@BCGen
Last active November 22, 2017 06:18
Show Gist options
  • Save BCGen/9ba9f7d96459fd063e42bd53f9839217 to your computer and use it in GitHub Desktop.
Save BCGen/9ba9f7d96459fd063e42bd53f9839217 to your computer and use it in GitHub Desktop.
Solution for expo SDK 16 and RN 0.43.2, TextInput Multiline={true} issue, In RN 0.46 fixed android onContentSizeChange issue.
import { action } from 'mobx';
import React, { PureComponent } from 'react';
import { StyleSheet, TextInputProperties, TextStyle, ViewStyle } from 'react-native';
import MultilineInput from './MultilineInput';
interface State {
height: number;
}
// In RN 0.46 fixed conContentSizeChange problem.
export default class AutoExpandingInput extends PureComponent<TextInputProperties, State> {
_inputRef;
constructor(props) {
super(props);
this.state = {
height: 0,
};
}
@action
componentWillReceiveProps(props) {
if (!props.value) {
this.setState({ height: 100 });
}
}
render() {
const {
onContentSizeChange,
style,
...otherProps,
} = this.props;
return (
<MultilineInput
{...otherProps}
ref={this._ref}
onContentSizeChange={this._onContentSizeChange}
style={[styles.textInputStyle, style, { height: this.state.height }]}
/>
);
}
focus = () => {
this._inputRef.focus();
}
private _onContentSizeChange = (event): void => {
const height = event.nativeEvent.contentSize.height;
const { onContentSizeChange } = this.props;
this.setState({ height });
if (onContentSizeChange) {
onContentSizeChange(event);
}
}
private _ref = ref => {
this._inputRef = ref;
}
}
// set textAlignVertical: 'top' make sure text one the top and
// not shock when TextInput's height changed.
interface Styles {
textInputStyle: TextStyle & ViewStyle;
}
const styles = StyleSheet.create<Styles>({
textInputStyle: {
fontSize : 20,
paddingHorizontal: 10,
paddingVertical : 10,
textAlignVertical: 'top',
}
});
import React, { PureComponent } from 'react';
import { TextInput, TextInputProperties } from 'react-native';
interface State {
cursorPosition: {
end: number,
start: number,
};
isSubmit: boolean;
value: string;
}
/*
* below only test on android, when set TextInput multiline={true}, some
* keyboard will blur and call onSubmitEditing when press enter key,
* so set blurOnSubmit={false}, and in onSubmitEditing() call onChangeText()
* then add one line below value, on android onSubmitEditing will trigger twice,
* so check if SubmitEditing already called.
*/
export default class MultilineInput extends PureComponent<TextInputProperties, State> {
constructor(props) {
super(props);
this.state = {
cursorPosition: { end: 0, start: 0 },
isSubmit : false,
value : '',
};
}
render() {
const {
blurOnSubmit = false,
multiline = true,
onChangeText = this._onChangeText,
onSubmitEditing,
value = this.state.value,
...other,
} = this.props;
const { end, start } = this.state.cursorPosition;
return (
<TextInput
{...other}
blurOnSubmit={blurOnSubmit}
multiline={multiline}
selection={{ start, end }}
onChangeText={onChangeText}
onSubmitEditing={this._onSubmitEditing}
onSelectionChange={this._onSelectionChange}
value={value}
/>
);
}
private _onChangeText = (value: string): void => {
this.setState({ value });
}
private _onSelectionChange = (event): void => {
this.setState({ cursorPosition: event.nativeEvent.selection });
}
// on android onSubmitEditing trigger twice, not test on ios.
// when first time, add new line after value(thanks to nikolay-radkov),
// second move cursor to next position (start of new line).
private _onSubmitEditing = (event): void => {
const { onChangeText, onSubmitEditing, value = this.state.value } = this.props;
if (!this.state.isSubmit) {
let newValue = value;
if (value.length === this.state.cursorPosition.end) {
newValue = value + '\n';
} else {
const ar = newValue.split('');
ar.splice(this.state.cursorPosition.end, 0, '\n');
newValue = ar.join('');
}
if (onChangeText) {
onChangeText(newValue);
} else {
this._onChangeText(newValue);
}
if (onSubmitEditing) {
onSubmitEditing(event);
}
const newPosition = this.state.cursorPosition.end + 1;
this.setState({
cursorPosition: { start: newPosition, end: newPosition },
});
}
this.setState({ isSubmit: !this.state.isSubmit });
}
}
@bhatti-waqas
Copy link

I got an error when trying to use it:
Undefined isn't an object evaluation _react.PorpTypes.string

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