diff --git a/packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm b/packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm index 152cde6f40a29a..b5e5f3c5c590ab 100644 --- a/packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm +++ b/packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm @@ -33,20 +33,22 @@ // ParagraphTextView is an auxiliary view we set as contentView so the drawing // can happen on top of the layers manipulated by RCTViewComponentView (the parent view) @interface RCTParagraphTextView : RCTUIView // [macOS] +#else // [macOS +// On macOS, we also defer drawing to an NSTextView, +// in order to get more native behaviors like text selection. +@interface RCTParagraphTextView : NSTextView // [macOS] +#endif // macOS] @property (nonatomic) ParagraphShadowNode::ConcreteState::Shared state; @property (nonatomic) ParagraphAttributes paragraphAttributes; @property (nonatomic) LayoutMetrics layoutMetrics; +#if TARGET_OS_OSX // [macOS] +/// UIKit compatibility shim that simply calls `[self setNeedsDisplay:YES]` +- (void)setNeedsDisplay; +#endif + @end -#else // [macOS -#if TARGET_OS_OSX // [macOS -// On macOS, we defer drawing to an NSTextView rather than a plan NSView, in order -// to get more native behaviors like text selection. We make sure this NSTextView -// does not take focus. -@interface RCTParagraphComponentUnfocusableTextView : NSTextView -@end -#endif // macOS] #if !TARGET_OS_OSX // [macOS] @interface RCTParagraphComponentView () @@ -62,10 +64,8 @@ @implementation RCTParagraphComponentView { RCTParagraphComponentAccessibilityProvider *_accessibilityProvider; #if !TARGET_OS_OSX // [macOS] UILongPressGestureRecognizer *_longPressGestureRecognizer; - RCTParagraphTextView *_textView; -#else // [macOS - RCTParagraphComponentUnfocusableTextView *_textView; #endif // macOS] + RCTParagraphTextView *_textView; } - (instancetype)initWithFrame:(CGRect)frame @@ -77,7 +77,6 @@ - (instancetype)initWithFrame:(CGRect)frame self.opaque = NO; _textView = [RCTParagraphTextView new]; _textView.backgroundColor = RCTUIColor.clearColor; // [macOS] - self.contentView = _textView; #else // [macOS // Make the RCTParagraphComponentView accessible and available in the a11y hierarchy. self.accessibilityElement = YES; @@ -85,7 +84,7 @@ - (instancetype)initWithFrame:(CGRect)frame // Fix blurry text on non-retina displays. self.canDrawSubviewsIntoLayer = YES; // The NSTextView is responsible for drawing text and managing selection. - _textView = [[RCTParagraphComponentUnfocusableTextView alloc] initWithFrame:self.bounds]; + _textView = [[RCTParagraphTextView alloc] initWithFrame:self.bounds]; // The RCTParagraphComponentUnfocusableTextView is only used for rendering and should not appear in the a11y hierarchy. _textView.accessibilityElement = NO; _textView.usesFontPanel = NO; @@ -98,6 +97,7 @@ - (instancetype)initWithFrame:(CGRect)frame self.contentView = _textView; self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize; #endif // macOS] + self.contentView = _textView; } return self; @@ -164,12 +164,9 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared & - (void)updateState:(const State::Shared &)state oldState:(const State::Shared &)oldState { _state = std::static_pointer_cast(state); -#if !TARGET_OS_OSX // [macOS] _textView.state = _state; [_textView setNeedsDisplay]; [self setNeedsLayout]; - [self _updateTextView]; -#endif // macOS] } - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics @@ -178,53 +175,10 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics // Using stored `_layoutMetrics` as `oldLayoutMetrics` here to avoid // re-applying individual sub-values which weren't changed. [super updateLayoutMetrics:layoutMetrics oldLayoutMetrics:_layoutMetrics]; -#if !TARGET_OS_OSX // [macOS] _textView.layoutMetrics = _layoutMetrics; [_textView setNeedsDisplay]; [self setNeedsLayout]; -#else // [macOS - [self _updateTextView]; -#endif // macOS] -} - -#if TARGET_OS_OSX // [macOS -- (void)_updateTextView -{ - if (!_state) { - return; - } - - auto textLayoutManager = _state->getData().paragraphLayoutManager.getTextLayoutManager(); - - if (!textLayoutManager) { - return; - } - - RCTTextLayoutManager *nativeTextLayoutManager = - (RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager()); - - CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); - - NSTextStorage *textStorage = [nativeTextLayoutManager getTextStorageForAttributedString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes frame:frame]; - - NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; - NSTextContainer *textContainer = layoutManager.textContainers.firstObject; - - [_textView replaceTextContainer:textContainer]; - - NSArray *managers = [[textStorage layoutManagers] copy]; - for (NSLayoutManager *manager in managers) { - [textStorage removeLayoutManager:manager]; - } - - _textView.minSize = frame.size; - _textView.maxSize = frame.size; - _textView.frame = frame; - _textView.textStorage.attributedString = textStorage; - - [self setNeedsDisplay]; } -#endif // macOS] - (void)prepareForRecycle { @@ -427,11 +381,13 @@ - (void)copy:(id)sender return RCTParagraphComponentView.class; } -#if !TARGET_OS_OSX // [macOS] @implementation RCTParagraphTextView { +#if !TARGET_OS_OSX // [macOS] CAShapeLayer *_highlightLayer; +#endif // macOS] } + - (void)drawRect:(CGRect)rect { if (!_state) { @@ -449,6 +405,7 @@ - (void)drawRect:(CGRect)rect CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); +#if !TARGET_OS_OSX // [macOS] [nativeTextLayoutManager drawAttributedString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes frame:frame @@ -466,12 +423,33 @@ - (void)drawRect:(CGRect)rect self->_highlightLayer = nil; } }]; +#else // [macOS + NSTextStorage *textStorage = [nativeTextLayoutManager getTextStorageForAttributedString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes size:frame.size]; + + NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject; + NSTextContainer *textContainer = layoutManager.textContainers.firstObject; + + [self replaceTextContainer:textContainer]; + + NSArray *managers = [[textStorage layoutManagers] copy]; + for (NSLayoutManager *manager in managers) { + [textStorage removeLayoutManager:manager]; + } + + self.minSize = frame.size; + self.maxSize = frame.size; + self.frame = frame; + [[self textStorage] setAttributedString:textStorage]; + + [super drawRect:rect]; +#endif } -@end -#else // [macOS #if TARGET_OS_OSX // [macOS -@implementation RCTParagraphComponentUnfocusableTextView +- (void)setNeedsDisplay +{ + [self setNeedsDisplay:YES]; +} - (BOOL)canBecomeKeyView { @@ -487,6 +465,6 @@ - (BOOL)resignFirstResponder return [super resignFirstResponder]; } +#endif // macOS] @end -#endif // macOS]