Fix multi-character TextInput
Reviewed By: hnery Differential Revision: D3457105 fbshipit-source-id: dcb364123ed82842d4fb2dee9108f2805249a8f9
This commit is contained in:
parent
57d85f1c3e
commit
cc959273da
|
@ -18,6 +18,7 @@
|
|||
#import "RCTText.h"
|
||||
#import "RCTUtils.h"
|
||||
#import "RCTConvert.h"
|
||||
#import "RCTTextView.h"
|
||||
|
||||
NSString *const RCTShadowViewAttributeName = @"RCTShadowViewAttributeName";
|
||||
NSString *const RCTIsHighlightedAttributeName = @"IsHighlightedAttributeName";
|
||||
|
@ -98,10 +99,24 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
|||
UIEdgeInsets padding = self.paddingAsInsets;
|
||||
CGFloat width = self.frame.size.width - (padding.left + padding.right);
|
||||
|
||||
NSNumber *parentTag = [[self reactSuperview] reactTag];
|
||||
NSTextStorage *textStorage = [self buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
|
||||
[applierBlocks addObject:^(NSDictionary<NSNumber *, RCTText *> *viewRegistry) {
|
||||
RCTText *view = viewRegistry[self.reactTag];
|
||||
[applierBlocks addObject:^(NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
RCTText *view = (RCTText *)viewRegistry[self.reactTag];
|
||||
view.textStorage = textStorage;
|
||||
|
||||
/**
|
||||
* NOTE: this logic is included to support rich text editing inside multiline
|
||||
* `<TextInput>` controls. It is required in order to ensure that the
|
||||
* textStorage (aka attributed string) is copied over from the RCTShadowText
|
||||
* to the RCTText view in time to be used to update the editable text content.
|
||||
* TODO: we should establish a delegate relationship betweeen RCTTextView
|
||||
* and its contaned RCTText element when they get inserted and get rid of this
|
||||
*/
|
||||
UIView *parentView = viewRegistry[parentTag];
|
||||
if ([parentView respondsToSelector:@selector(performTextUpdate)]) {
|
||||
[(RCTTextView *)parentView performTextUpdate];
|
||||
}
|
||||
}];
|
||||
|
||||
return parentProperties;
|
||||
|
@ -167,13 +182,13 @@ static css_dim_t RCTMeasure(void *context, float width, css_measure_mode_t width
|
|||
|
||||
NSTextContainer *textContainer = [NSTextContainer new];
|
||||
textContainer.lineFragmentPadding = 0.0;
|
||||
|
||||
|
||||
if (_numberOfLines > 0) {
|
||||
textContainer.lineBreakMode = _lineBreakMode;
|
||||
} else {
|
||||
textContainer.lineBreakMode = NSLineBreakByClipping;
|
||||
}
|
||||
|
||||
|
||||
textContainer.maximumNumberOfLines = _numberOfLines;
|
||||
textContainer.size = (CGSize){widthMode == CSS_MEASURE_MODE_UNDEFINED ? CGFLOAT_MAX : width, CGFLOAT_MAX};
|
||||
|
||||
|
|
|
@ -155,7 +155,6 @@ static void collectNonTextDescendants(RCTText *view, NSMutableArray *nonTextDesc
|
|||
return reactTag;
|
||||
}
|
||||
|
||||
|
||||
- (void)didMoveToWindow
|
||||
{
|
||||
[super didMoveToWindow];
|
||||
|
|
|
@ -78,7 +78,6 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
|
|||
|
||||
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry
|
||||
{
|
||||
NSMutableSet *textViewTagsToUpdate = [NSMutableSet new];
|
||||
for (RCTShadowView *rootView in shadowViewRegistry.allValues) {
|
||||
if (![rootView isReactRootView]) {
|
||||
// This isn't a root view
|
||||
|
@ -103,19 +102,6 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
|
|||
RCTLogError(@"Raw text cannot be used outside of a <Text> tag. Not rendering string: '%@'",
|
||||
[(RCTShadowRawText *)shadowView text]);
|
||||
} else {
|
||||
NSNumber *reactTag = shadowView.reactTag;
|
||||
// This isn't pretty, but hopefully it's temporary
|
||||
// the problem is, there's no easy way (besides the viewName)
|
||||
// to tell from the shadowView if the view is an RKTextView
|
||||
if ([shadowView.viewName hasSuffix:@"TextView"]) {
|
||||
// Add to textViewTagsToUpdate only if has a RCTShadowText subview
|
||||
for (RCTShadowView *subview in shadowView.reactSubviews) {
|
||||
if ([subview isKindOfClass:[RCTShadowText class]]) {
|
||||
[textViewTagsToUpdate addObject:reactTag];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (RCTShadowView *child in [shadowView reactSubviews]) {
|
||||
if ([child isTextDirty]) {
|
||||
[queue addObject:child];
|
||||
|
@ -127,52 +113,7 @@ RCT_EXPORT_SHADOW_PROPERTY(textShadowColor, UIColor)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: this logic is included to support rich text editing inside multiline
|
||||
* `<TextInput>` controls. It is required in order to ensure that the
|
||||
* textStorage (aka attributed string) is copied over from the RCTShadowText
|
||||
* to the RCTText view in time to be used to update the editable text content.
|
||||
*/
|
||||
if (textViewTagsToUpdate.count) {
|
||||
|
||||
NSMutableArray<RCTViewManagerUIBlock> *uiBlocks = [NSMutableArray new];
|
||||
for (NSNumber *reactTag in textViewTagsToUpdate) {
|
||||
RCTShadowView *shadowTextView = shadowViewRegistry[reactTag];
|
||||
RCTShadowText *shadowText;
|
||||
for (RCTShadowText *subview in shadowTextView.reactSubviews) {
|
||||
if ([subview isKindOfClass:[RCTShadowText class]]) {
|
||||
shadowText = subview;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UIEdgeInsets padding = shadowText.paddingAsInsets;
|
||||
CGFloat width = shadowText.frame.size.width - (padding.left + padding.right);
|
||||
|
||||
NSTextStorage *textStorage = [shadowText buildTextStorageForWidth:width widthMode:CSS_MEASURE_MODE_EXACTLY];
|
||||
[uiBlocks addObject:^(RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTTextView *> *viewRegistry) {
|
||||
RCTTextView *textView = viewRegistry[reactTag];
|
||||
RCTText *text;
|
||||
for (RCTText *subview in textView.reactSubviews) {
|
||||
if ([subview isKindOfClass:[RCTText class]]) {
|
||||
text = subview;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
text.textStorage = textStorage;
|
||||
[textView performTextUpdate];
|
||||
}];
|
||||
}
|
||||
|
||||
return ^(RCTUIManager *uiManager, NSDictionary<NSNumber *, UIView *> *viewRegistry) {
|
||||
for (RCTViewManagerUIBlock uiBlock in uiBlocks) {
|
||||
uiBlock(uiManager, viewRegistry);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowView:(RCTShadowText *)shadowView
|
||||
|
|
|
@ -125,6 +125,8 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|||
attrs[NSBackgroundColorAttributeName] = subview.backgroundColor;
|
||||
_textView.typingAttributes = attrs;
|
||||
}
|
||||
|
||||
[self performTextUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,6 +135,7 @@ RCT_NOT_IMPLEMENTED(- (instancetype)initWithCoder:(NSCoder *)aDecoder)
|
|||
[super removeReactSubview:subview];
|
||||
if (_richTextView == subview) {
|
||||
_richTextView = nil;
|
||||
[self performTextUpdate];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ typedef void (^RCTViewManagerUIBlock)(RCTUIManager *uiManager, NSDictionary<NSNu
|
|||
/**
|
||||
* Called after view hierarchy manipulation has finished, and all shadow props
|
||||
* have been set, but before layout has been performed. Useful for performing
|
||||
* custo layout logic or tasks that involve walking the view hierarchy.
|
||||
* custom layout logic or tasks that involve walking the view hierarchy.
|
||||
* To be deprecated, hopefully.
|
||||
*/
|
||||
- (RCTViewManagerUIBlock)uiBlockToAmendWithShadowViewRegistry:(NSDictionary<NSNumber *, RCTShadowView *> *)shadowViewRegistry;
|
||||
|
|
Loading…
Reference in New Issue