Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,96 @@

#if RCT_NEW_ARCH_ENABLED
#import "RCTVersion.h"
#import "RCTParagraphComponentView.h"
#import "RCTConversions.h"
#import "ParagraphProps.h"
#if RCT_VERSION_MINOR <= 73
#import "RCTConversions.h"
#endif

namespace rct = facebook::react;
typedef facebook::react::Props::Shared (*RCTFabricWrapperPropsIMP)(id, SEL);
#endif

@implementation RCTFabricWrapper

#if RCT_NEW_ARCH_ENABLED
/**
* `RCTParagraphComponentView` is compiled into the app (it's not a lazily-loaded plugin), so
* the class is resolvable as soon as this method can be called at all — it's safe to resolve
* it once and cache it rather than paying for an `NSClassFromString` lookup on every view
* checked during snapshotting.
*/
+ (nullable Class)paragraphComponentViewClass {
static Class sClass;
static dispatch_once_t sOnceToken;
dispatch_once(&sOnceToken, ^{
sClass = NSClassFromString(@"RCTParagraphComponentView");
});
return sClass;
}

/**
* `-props` is declared on RCTComponentViewProtocol (not on RCTParagraphComponentView itself),
* so its selector is looked up dynamically too rather than relying on the protocol's header.
*/
+ (SEL)propsSelector {
static SEL sSelector;
static dispatch_once_t sOnceToken;
dispatch_once(&sOnceToken, ^{
sSelector = NSSelectorFromString(@"props");
});
return sSelector;
}

/**
* `-props` returns a C++ shared_ptr, so it can't be reached through KVC — its IMP is looked up
* and cached once instead, since it's the same for every instance of the (fixed) class above.
*/
+ (nullable RCTFabricWrapperPropsIMP)propsIMP {
static RCTFabricWrapperPropsIMP sImp;
static dispatch_once_t sOnceToken;
dispatch_once(&sOnceToken, ^{
Class paragraphComponentViewClass = [self paragraphComponentViewClass];
SEL propsSelector = [self propsSelector];
if (paragraphComponentViewClass != nil && [paragraphComponentViewClass instancesRespondToSelector:propsSelector]) {
sImp = (RCTFabricWrapperPropsIMP)[paragraphComponentViewClass instanceMethodForSelector:propsSelector];
}
});
return sImp;
}
#endif

/**
* Extracts the text properties from the given UIView when the view is of type RCTParagraphComponentView, returns nil otherwise.
*
* This deliberately avoids importing RCTParagraphComponentView.h / RCTComponentViewProtocol.h:
* both live in the React-RCTFabric pod, which React Native's "prebuilt core" CocoaPods facade
* (RN >= 0.87) ships without public headers, aside from a narrow allowlist that doesn't cover
* either of them. The class and its `-props` accessor are resolved dynamically instead, and
* cached (see paragraphComponentViewClass / propsIMP above) since this runs on every view
* checked during snapshotting.
*/
- (nullable RCTTextPropertiesWrapper*)tryToExtractTextPropertiesFromView:(UIView *)view {
#if RCT_NEW_ARCH_ENABLED
if (![view isKindOfClass:[RCTParagraphComponentView class]]) {
Class paragraphComponentViewClass = [RCTFabricWrapper paragraphComponentViewClass];
if (paragraphComponentViewClass == nil || ![view isKindOfClass:paragraphComponentViewClass]) {
return nil;
}

// Cast view to RCTParagraphComponentView
RCTParagraphComponentView* paragraphComponentView = (RCTParagraphComponentView *)view;
if (paragraphComponentView == nil) {
RCTFabricWrapperPropsIMP getProps = [RCTFabricWrapper propsIMP];
if (getProps == NULL) {
return nil;
}

// Retrieve ParagraphProps from shared pointer
const rct::ParagraphProps* props = (rct::ParagraphProps*)paragraphComponentView.props.get();
facebook::react::Props::Shared sharedProps = getProps(view, [RCTFabricWrapper propsSelector]);
const rct::ParagraphProps* props = (rct::ParagraphProps*)sharedProps.get();
if (props == nil) {
return nil;
}

// Extract Attributes
RCTTextPropertiesWrapper* textPropertiesWrapper = [[RCTTextPropertiesWrapper alloc] init];
textPropertiesWrapper.text = [RCTFabricWrapper getTextFromView:paragraphComponentView];
textPropertiesWrapper.contentRect = paragraphComponentView.bounds;
textPropertiesWrapper.text = [RCTFabricWrapper getTextFromView:view];
textPropertiesWrapper.contentRect = view.bounds;

rct::TextAttributes textAttributes = props->textAttributes;
textPropertiesWrapper.alignment = [RCTFabricWrapper getAlignmentFromAttributes:textAttributes];
Expand All @@ -54,12 +111,15 @@ - (nullable RCTTextPropertiesWrapper*)tryToExtractTextPropertiesFromView:(UIView
}

#if RCT_NEW_ARCH_ENABLED
+ (NSString* _Nonnull)getTextFromView:(RCTParagraphComponentView*)view {
if (view == nil || view.attributedText == nil) {
+ (NSString* _Nonnull)getTextFromView:(UIView*)view {
// `attributedText` is a plain Objective-C property on RCTParagraphComponentView, so it's
// safe to read through KVC without importing that class's header (see the note above).
NSAttributedString* attributedText = [view valueForKey:@"attributedText"];
if (attributedText == nil) {
return RCTTextPropertiesDefaultText;
}

return view.attributedText.string;
return attributedText.string;
}

+ (NSTextAlignment)getAlignmentFromAttributes:(rct::TextAttributes)textAttributes {
Expand Down