diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index bbb665f60d4106..44dd748d97f31c 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -606,21 +606,6 @@ var TextInput = React.createClass({ var text = event.nativeEvent.text; this.props.onChange && this.props.onChange(event); this.props.onChangeText && this.props.onChangeText(text); - - if (!this.refs.input) { - // calling `this.props.onChange` or `this.props.onChangeText` - // may clean up the input itself. Exits here. - return; - } - - // This is necessary in case native updates the text and JS decides - // that the update should be ignored and we should stick with the value - // that we have in JS. - if (text !== this.props.value && typeof this.props.value === 'string') { - this.refs.input.setNativeProps({ - text: this.props.value, - }); - } }, _onBlur: function(event: Event) { diff --git a/Libraries/Text/RCTTextField.h b/Libraries/Text/RCTTextField.h index 0448dcfca8ca8f..27ef20d5327b24 100644 --- a/Libraries/Text/RCTTextField.h +++ b/Libraries/Text/RCTTextField.h @@ -31,6 +31,7 @@ - (void)textFieldDidChange; - (void)sendKeyValueForString:(NSString *)string; +- (void)sendTextChangedForString:(NSString *)string; - (BOOL)textFieldShouldEndEditing:(RCTTextField *)textField; @end diff --git a/Libraries/Text/RCTTextField.m b/Libraries/Text/RCTTextField.m index 24b077baff106b..9e6613ba135e6d 100644 --- a/Libraries/Text/RCTTextField.m +++ b/Libraries/Text/RCTTextField.m @@ -58,6 +58,15 @@ - (void)sendKeyValueForString:(NSString *)string eventCount:_nativeEventCount]; } +- (void)sendTextChangedForString:(NSString *)string +{ + [_eventDispatcher sendTextEventWithType:RCTTextEventTypeChange + reactTag:self.reactTag + text:string + key:nil + eventCount:_nativeEventCount]; +} + // This method is overridden for `onKeyPress`. The manager // will not send a keyPress for text that was pasted. - (void)paste:(id)sender @@ -69,19 +78,25 @@ - (void)paste:(id)sender - (void)setText:(NSString *)text { NSInteger eventLag = _nativeEventCount - _mostRecentEventCount; - if (eventLag == 0 && ![text isEqualToString:self.text]) { - UITextRange *selection = self.selectedTextRange; - NSInteger oldTextLength = self.text.length; - - super.text = text; - - if (selection.empty) { - // maintain cursor position relative to the end of the old text - NSInteger offsetStart = [self offsetFromPosition:self.beginningOfDocument toPosition:selection.start]; - NSInteger offsetFromEnd = oldTextLength - offsetStart; - NSInteger newOffset = text.length - offsetFromEnd; - UITextPosition *position = [self positionFromPosition:self.beginningOfDocument offset:newOffset]; - self.selectedTextRange = [self textRangeFromPosition:position toPosition:position]; + if (eventLag == 0) { + if (text.length == 0) { + // Note: If we don't set 'super.text' it doesn't clear the autocorrect state; so ensure we do this when clearing the text field or autocorrect results will just keep appending + super.text = text; + } + else if (![text isEqualToString:self.text]) { + UITextRange *selection = self.selectedTextRange; + NSInteger oldTextLength = self.text.length; + + super.text = text; + + if (selection.empty) { + // maintain cursor position relative to the end of the old text + NSInteger offsetStart = [self offsetFromPosition:self.beginningOfDocument toPosition:selection.start]; + NSInteger offsetFromEnd = oldTextLength - offsetStart; + NSInteger newOffset = text.length - offsetFromEnd; + UITextPosition *position = [self positionFromPosition:self.beginningOfDocument offset:newOffset]; + self.selectedTextRange = [self textRangeFromPosition:position toPosition:position]; + } } } else if (eventLag > RCTTextUpdateLagWarningThreshold) { RCTLogWarn(@"Native TextInput(%@) is %zd events ahead of JS - try to make your JS faster.", self.text, eventLag); diff --git a/Libraries/Text/RCTTextFieldManager.m b/Libraries/Text/RCTTextFieldManager.m index 652639a0409f10..729889b6b20f52 100644 --- a/Libraries/Text/RCTTextFieldManager.m +++ b/Libraries/Text/RCTTextFieldManager.m @@ -37,9 +37,16 @@ - (BOOL)textField:(RCTTextField *)textField shouldChangeCharactersInRange:(NSRan [textField sendKeyValueForString:string]; } - if (textField.maxLength == nil || [string isEqualToString:@"\n"]) { // Make sure forms can be submitted via return + if ([string isEqualToString:@"\n"]) { // Make sure forms can be submitted via return return YES; } + + if (textField.maxLength == nil) { + NSMutableString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; + + [textField sendTextChangedForString:newString]; + return NO; + } NSUInteger allowedLength = textField.maxLength.integerValue - textField.text.length + range.length; if (string.length > allowedLength) { if (string.length > 1) { @@ -56,7 +63,10 @@ - (BOOL)textField:(RCTTextField *)textField shouldChangeCharactersInRange:(NSRan } return NO; } else { - return YES; + NSMutableString *newString = [textField.text stringByReplacingCharactersInRange:range withString:string]; + + [textField sendTextChangedForString:newString]; + return NO; } }