diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js
index 44641d875..1400f31f1 100644
--- a/Libraries/Components/TextInput/TextInput.js
+++ b/Libraries/Components/TextInput/TextInput.js
@@ -443,8 +443,8 @@ var TextInput = React.createClass({
!(props.value && childCount),
'Cannot specify both value and children.'
);
- if (childCount > 1) {
- children = {children};
+ if (childCount >= 1) {
+ children = {children};
}
if (props.inputView) {
children = [children, props.inputView];
diff --git a/Libraries/Text/RCTTextView.m b/Libraries/Text/RCTTextView.m
index 07eb7a37a..fad4719d4 100644
--- a/Libraries/Text/RCTTextView.m
+++ b/Libraries/Text/RCTTextView.m
@@ -11,6 +11,7 @@
#import "RCTConvert.h"
#import "RCTEventDispatcher.h"
+#import "RCTShadowText.h"
#import "RCTText.h"
#import "RCTUtils.h"
#import "UIView+React.h"
@@ -110,6 +111,18 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
}
_richTextView = (RCTText *)subview;
[_subviews insertObject:_richTextView atIndex:index];
+
+ // If this is in rich text editing mode, and the child node providing rich text
+ // styling has a backgroundColor, then the attributedText produced by the child node will have an
+ // NSBackgroundColor attribute. We need to forward this attribute to the text view manually because the text view
+ // always has a clear background color in -initWithEventDispatcher:.
+ //
+ // TODO: This should be removed when the related hack in -performPendingTextUpdate is removed.
+ if (subview.backgroundColor) {
+ NSMutableDictionary *attrs = [_textView.typingAttributes mutableCopy];
+ attrs[NSBackgroundColorAttributeName] = subview.backgroundColor;
+ _textView.typingAttributes = attrs;
+ }
} else {
[_subviews insertObject:subview atIndex:index];
[self insertSubview:subview atIndex:index];
@@ -149,12 +162,31 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
}
}
+static NSAttributedString *removeReactTagFromString(NSAttributedString *string)
+{
+ if (string.length == 0) {
+ return string;
+ } else {
+ NSMutableAttributedString *mutableString = [[NSMutableAttributedString alloc] initWithAttributedString:string];
+ [mutableString removeAttribute:RCTReactTagAttributeName range:NSMakeRange(0, mutableString.length)];
+ return mutableString;
+ }
+}
+
- (void)performPendingTextUpdate
{
if (!_pendingAttributedText || _mostRecentEventCount < _nativeEventCount) {
return;
}
+ // The underlying node that produces _pendingAttributedText has a react tag attribute on it that causes the
+ // -isEqualToAttributedString: comparison below to spuriously fail. We don't want that comparison to fail unless it
+ // needs to because when the comparison fails, we end up setting attributedText on the text view, which clears
+ // autocomplete state for CKJ text input.
+ //
+ // TODO: Kill this after we finish passing all style/attribute info into JS.
+ _pendingAttributedText = removeReactTagFromString(_pendingAttributedText);
+
if ([_textView.attributedText isEqualToAttributedString:_pendingAttributedText]) {
_pendingAttributedText = nil; // Don't try again.
return;