Remember ShadowNode of RawText's parent in attribute string

Summary:
When a user clicks on some text, `RCTSurfaceTouchHandler` will call into a method on `RCTParagraphComponentView`. That method (i.e: `touchEventEmitter`) would be responsible for identifying the closest ancestral `<Text/>` component to which we should dispatch the `onPress` event, given the point where the user clicked. To answer this query, we'll use a data structure called `UIAttributedString`.

This data structure represents a string, and a corresponding mapping from sequences of its characters to some arbitrary data. In this attributed string, we'll map sequences of characters to their closest ancestral `ParagraphShadowNode` or `TextShadowNode`. That way, when we get a click event on `RCTParagraphComponentView`, we can just look at the character that was clicked, and use that information to do a lookup in the attributed string to find the shadow node who's EventEmitter is responsible for processing the click event.

Reviewed By: shergin

Differential Revision: D9696904

fbshipit-source-id: a199649981ad271afa85414ce4c3f056851348be
This commit is contained in:
Ramanpreet Nara 2018-09-10 11:19:16 -07:00 committed by Facebook Github Bot
parent 4a4e083e2a
commit 4e841f2114
4 changed files with 16 additions and 4 deletions

View File

@ -39,6 +39,7 @@ public:
std::string string;
TextAttributes textAttributes;
SharedShadowNode shadowNode;
SharedShadowNode parentShadowNode;
};
using Fragments = std::vector<Fragment>;

View File

@ -29,6 +29,7 @@ AttributedString BaseTextShadowNode::getAttributedString(
AttributedString::Fragment fragment;
fragment.string = rawTextShadowNode->getProps()->text;
fragment.textAttributes = textAttributes;
fragment.parentShadowNode = parentNode;
attributedString.appendFragment(fragment);
continue;
}

View File

@ -13,11 +13,15 @@
NS_ASSUME_NONNULL_BEGIN
NSString *const RCTAttributedStringIsHighlightedAttributeName = @"IsHighlighted";
NSString *const RCTAttributedStringReactTagAttributeName = @"ReactTag";
NSString *const RCTAttributedStringParentShadowNode = @"ParentShadowNode";
/**
* Constructs ready-to-render `NSAttributedString` by given `AttributedString`.
*/
NSAttributedString *RCTNSAttributedStringFromAttributedString(const facebook::react::AttributedString &attributedString);
@interface RCTSharedShadowNodeWrapper : NSObject
@property (nonatomic, assign) facebook::react::SharedShadowNode node;
@end
NS_ASSUME_NONNULL_END

View File

@ -12,6 +12,9 @@
#include <fabric/textlayoutmanager/RCTFontUtils.h>
#include <fabric/textlayoutmanager/RCTTextPrimitivesConversions.h>
@implementation RCTSharedShadowNodeWrapper
@end
inline static UIFont *RCTEffectiveFontFromTextAttributes(const TextAttributes &textAttributes) {
NSString *fontFamily = [NSString stringWithCString:textAttributes.fontFamily.c_str()
encoding:NSUTF8StringEncoding];
@ -209,12 +212,15 @@ NSAttributedString *RCTNSAttributedStringFromAttributedString(const AttributedSt
NSMutableAttributedString *nsMutableAttributedStringFragment =
[[NSMutableAttributedString alloc] initWithAttributedString:nsAttributedStringFragment];
if (fragment.shadowNode) {
if (fragment.parentShadowNode) {
RCTSharedShadowNodeWrapper *parentShadowNode = [RCTSharedShadowNodeWrapper new];
parentShadowNode.node = fragment.parentShadowNode;
NSDictionary<NSAttributedStringKey, id> *additionalTextAttributes = @{
RCTAttributedStringReactTagAttributeName: @(fragment.shadowNode->getTag())
RCTAttributedStringParentShadowNode: parentShadowNode
};
[nsMutableAttributedStringFragment setAttributes:additionalTextAttributes
[nsMutableAttributedStringFragment addAttributes:additionalTextAttributes
range:NSMakeRange(0, nsMutableAttributedStringFragment.length)];
}