Skip to content

Commit cc95927

Browse files
javacheFacebook Github Bot 1
authored andcommitted
Fix multi-character TextInput
Reviewed By: hnery Differential Revision: D3457105 fbshipit-source-id: dcb364123ed82842d4fb2dee9108f2805249a8f9
1 parent 57d85f1 commit cc95927

File tree

5 files changed

+24
-66
lines changed

5 files changed

+24
-66
lines changed

Libraries/Text/RCTShadowText.m

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#import "RCTText.h"
1919
#import "RCTUtils.h"
2020
#import "RCTConvert.h"
21+
#import "RCTTextView.h"
2122

2223
NSString *const RCTShadowViewAttributeName = @"RCTShadowViewAttributeName";
2324
NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName";
@@ -98,10 +99,24 @@ - (void)contentSizeMultiplierDidChange:(NSNotification *)note
9899
UIEdgeInsets padding = self.paddingAsInsets;
99100
CGFloat width = self.frame.size.width - (padding.left + padding.right);
100101

102+
NSNumber *parentTag = [[self reactSuperview] reactTag];
101103
NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
102-
[applierBlocks addObject:^(NSDictionary<NSNumber *, RCTText *> *viewRegistry) {
103-
RCTText *view = viewRegistry[self.reactTag];
104+
[applierBlocks addObject:^(NSDictionary<NSNumber *, UIView *> *viewRegistry) {
105+
RCTText *view = (RCTText *)viewRegistry[self.reactTag];
104106
view.textStorage = textStorage;
107+
108+
/**
109+
* NOTE: this logic is included to support rich text editing inside multiline
110+
* `<TextInput>` controls. It is required in order to ensure that the
111+
* textStorage (aka attributed string) is copied over from the RCTShadowText
112+
* to the RCTText view in time to be used to update the editable text content.
113+
* TODO: we should establish a delegate relationship betweeen RCTTextView
114+
* and its contaned RCTText element when they get inserted and get rid of this
115+
*/
116+
UIView *parentView = viewRegistry[parentTag];
117+
if ([parentView respondsToSelector:@selector(performTextUpdate)]) {
118+
[(RCTTextView *)parentView performTextUpdate];
119+
}
105120
}];
106121

107122
return parentProperties;
@@ -167,13 +182,13 @@ - (NSTextStorage *)buildTextStorageForWidth:(CGFloat)width widthMode:(css_measur
167182

168183
NSTextContainer *textContainer = [NSTextContainer new];
169184
textContainer.lineFragmentPadding = 0.0;
170-
185+
171186
if (_numberOfLines > 0) {
172187
textContainer.lineBreakMode = _lineBreakMode;
173188
} else {
174189
textContainer.lineBreakMode = NSLineBreakByClipping;
175190
}
176-
191+
177192
textContainer.maximumNumberOfLines = _numberOfLines;
178193
textContainer.size = (CGSize){widthMode == CSS_MEASURE_MODE_UNDEFINED ? CGFLOAT_MAX : width, CGFLOAT_MAX};
179194

Libraries/Text/RCTText.m

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,6 @@ - (NSNumber *)reactTagAtPoint:(CGPoint)point
155155
return reactTag;
156156
}
157157

158-
159158
- (void)didMoveToWindow
160159
{
161160
[super didMoveToWindow];

Libraries/Text/RCTTextManager.m

Lines changed: 1 addition & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ - (RCTShadowView *)shadowView
7878

7979
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry
8080
{
81-
NSMutableSet *textViewTagsToUpdate = [NSMutableSet new];
8281
for (RCTShadowView *rootView in shadowViewRegistry.allValues) {
8382
if (![rootView isReactRootView]) {
8483
// This isn't a root view
@@ -103,19 +102,6 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNu
103102
RCTLogError(@"Raw text cannot be used outside of a <Text> tag. Not rendering string: '%@'",
104103
[(RCTShadowRawText *)shadowView text]);
105104
} else {
106-
NSNumber *reactTag = shadowView.reactTag;
107-
// This isn't pretty, but hopefully it's temporary
108-
// the problem is, there's no easy way (besides the viewName)
109-
// to tell from the shadowView if the view is an RKTextView
110-
if ([shadowView.viewName hasSuffix:@"TextView"]) {
111-
// Add to textViewTagsToUpdate only if has a RCTShadowText subview
112-
for (RCTShadowView *subview in shadowView.reactSubviews) {
113-
if ([subview isKindOfClass:[RCTShadowText class]]) {
114-
[textViewTagsToUpdate addObject:reactTag];
115-
break;
116-
}
117-
}
118-
}
119105
for (RCTShadowView *child in [shadowView reactSubviews]) {
120106
if ([child isTextDirty]) {
121107
[queue addObject:child];
@@ -127,52 +113,7 @@ - (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNu
127113
}
128114
}
129115

130-
/**
131-
* NOTE: this logic is included to support rich text editing inside multiline
132-
* `<TextInput>` controls. It is required in order to ensure that the
133-
* textStorage (aka attributed string) is copied over from the RCTShadowText
134-
* to the RCTText view in time to be used to update the editable text content.
135-
*/
136-
if (textViewTagsToUpdate.count) {
137-
138-
NSMutableArray<RCTViewManagerUIBlock> *uiBlocks = [NSMutableArray new];
139-
for (NSNumber *reactTag in textViewTagsToUpdate) {
140-
RCTShadowView *shadowTextView = shadowViewRegistry[reactTag];
141-
RCTShadowText *shadowText;
142-
for (RCTShadowText *subview in shadowTextView.reactSubviews) {
143-
if ([subview isKindOfClass:[RCTShadowText class]]) {
144-
shadowText = subview;
145-
break;
146-
}
147-
}
148-
149-
UIEdgeInsets padding = shadowText.paddingAsInsets;
150-
CGFloat width = shadowText.frame.size.width - (padding.left + padding.right);
151-
152-
NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
153-
[uiBlocks addObject:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTTextView *> *viewRegistry) {
154-
RCTTextView *textView = viewRegistry[reactTag];
155-
RCTText *text;
156-
for (RCTText *subview in textView.reactSubviews) {
157-
if ([subview isKindOfClass:[RCTText class]]) {
158-
text = subview;
159-
break;
160-
}
161-
}
162-
163-
text.textStorage = textStorage;
164-
[textView performTextUpdate];
165-
}];
166-
}
167-
168-
return ^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
169-
for (RCTViewManagerUIBlock uiBlock in uiBlocks) {
170-
uiBlock(uiManager, viewRegistry);
171-
}
172-
};
173-
} else {
174-
return nil;
175-
}
116+
return nil;
176117
}
177118

178119
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowText *)shadowView

Libraries/Text/RCTTextView.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ - (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)index
125125
attrs[NSBackgroundColorAttributeName] = subview.backgroundColor;
126126
_textView.typingAttributes = attrs;
127127
}
128+
129+
[self performTextUpdate];
128130
}
129131
}
130132

@@ -133,6 +135,7 @@ - (void)removeReactSubview:(UIView *)subview
133135
[super removeReactSubview:subview];
134136
if (_richTextView == subview) {
135137
_richTextView = nil;
138+
[self performTextUpdate];
136139
}
137140
}
138141

React/Views/RCTViewManager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, NSDictionary<NSNu
8585
/**
8686
* Called after view hierarchy manipulation has finished, and all shadow props
8787
* have been set, but before layout has been performed. Useful for performing
88-
* custo layout logic or tasks that involve walking the view hierarchy.
88+
* custom layout logic or tasks that involve walking the view hierarchy.
8989
* To be deprecated, hopefully.
9090
*/
9191
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry;

0 commit comments

Comments
 (0)