3333// ParagraphTextView is an auxiliary view we set as contentView so the drawing
3434// can happen on top of the layers manipulated by RCTViewComponentView (the parent view)
3535@interface RCTParagraphTextView : RCTUIView // [macOS]
36+ #else // [macOS
37+ // On macOS, we also defer drawing to an NSTextView,
38+ // in order to get more native behaviors like text selection.
39+ @interface RCTParagraphTextView : NSTextView // [macOS]
40+ #endif // macOS]
3641
3742@property (nonatomic ) ParagraphShadowNode::ConcreteState::Shared state;
3843@property (nonatomic ) ParagraphAttributes paragraphAttributes;
3944@property (nonatomic ) LayoutMetrics layoutMetrics;
4045
46+ #if TARGET_OS_OSX // [macOS]
47+ // / UIKit compatibility shim that simply calls `[self setNeedsDisplay:YES]`
48+ - (void )setNeedsDisplay ;
49+ #endif
50+
4151@end
42- #else // [macOS
43- #if TARGET_OS_OSX // [macOS
44- // On macOS, we defer drawing to an NSTextView rather than a plan NSView, in order
45- // to get more native behaviors like text selection. We make sure this NSTextView
46- // does not take focus.
47- @interface RCTParagraphComponentUnfocusableTextView : NSTextView
48- @end
49- #endif // macOS]
5052
5153#if !TARGET_OS_OSX // [macOS]
5254@interface RCTParagraphComponentView () <UIEditMenuInteractionDelegate>
@@ -62,10 +64,8 @@ @implementation RCTParagraphComponentView {
6264 RCTParagraphComponentAccessibilityProvider *_accessibilityProvider;
6365#if !TARGET_OS_OSX // [macOS]
6466 UILongPressGestureRecognizer *_longPressGestureRecognizer;
65- RCTParagraphTextView *_textView;
66- #else // [macOS
67- RCTParagraphComponentUnfocusableTextView *_textView;
6867#endif // macOS]
68+ RCTParagraphTextView *_textView;
6969}
7070
7171- (instancetype )initWithFrame : (CGRect)frame
@@ -77,15 +77,14 @@ - (instancetype)initWithFrame:(CGRect)frame
7777 self.opaque = NO ;
7878 _textView = [RCTParagraphTextView new ];
7979 _textView.backgroundColor = RCTUIColor.clearColor ; // [macOS]
80- self.contentView = _textView;
8180#else // [macOS
8281 // Make the RCTParagraphComponentView accessible and available in the a11y hierarchy.
8382 self.accessibilityElement = YES ;
8483 self.accessibilityRole = NSAccessibilityStaticTextRole ;
8584 // Fix blurry text on non-retina displays.
8685 self.canDrawSubviewsIntoLayer = YES ;
8786 // The NSTextView is responsible for drawing text and managing selection.
88- _textView = [[RCTParagraphComponentUnfocusableTextView alloc ] initWithFrame: self .bounds];
87+ _textView = [[RCTParagraphTextView alloc ] initWithFrame: self .bounds];
8988 // The RCTParagraphComponentUnfocusableTextView is only used for rendering and should not appear in the a11y hierarchy.
9089 _textView.accessibilityElement = NO ;
9190 _textView.usesFontPanel = NO ;
@@ -98,6 +97,7 @@ - (instancetype)initWithFrame:(CGRect)frame
9897 self.contentView = _textView;
9998 self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
10099#endif // macOS]
100+ self.contentView = _textView;
101101 }
102102
103103 return self;
@@ -164,12 +164,9 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
164164- (void )updateState : (const State::Shared &)state oldState : (const State::Shared &)oldState
165165{
166166 _state = std::static_pointer_cast<const ParagraphShadowNode::ConcreteState>(state);
167- #if !TARGET_OS_OSX // [macOS]
168167 _textView.state = _state;
169168 [_textView setNeedsDisplay ];
170169 [self setNeedsLayout ];
171- [self _updateTextView ];
172- #endif // macOS]
173170}
174171
175172- (void )updateLayoutMetrics : (const LayoutMetrics &)layoutMetrics
@@ -178,53 +175,10 @@ - (void)updateLayoutMetrics:(const LayoutMetrics &)layoutMetrics
178175 // Using stored `_layoutMetrics` as `oldLayoutMetrics` here to avoid
179176 // re-applying individual sub-values which weren't changed.
180177 [super updateLayoutMetrics: layoutMetrics oldLayoutMetrics: _layoutMetrics];
181- #if !TARGET_OS_OSX // [macOS]
182178 _textView.layoutMetrics = _layoutMetrics;
183179 [_textView setNeedsDisplay ];
184180 [self setNeedsLayout ];
185- #else // [macOS
186- [self _updateTextView ];
187- #endif // macOS]
188- }
189-
190- #if TARGET_OS_OSX // [macOS
191- - (void )_updateTextView
192- {
193- if (!_state) {
194- return ;
195- }
196-
197- auto textLayoutManager = _state->getData ().paragraphLayoutManager .getTextLayoutManager ();
198-
199- if (!textLayoutManager) {
200- return ;
201- }
202-
203- RCTTextLayoutManager *nativeTextLayoutManager =
204- (RCTTextLayoutManager *)unwrapManagedObject (textLayoutManager->getNativeTextLayoutManager ());
205-
206- CGRect frame = RCTCGRectFromRect (_layoutMetrics.getContentFrame ());
207-
208- NSTextStorage *textStorage = [nativeTextLayoutManager getTextStorageForAttributedString: _state->getData ().attributedString paragraphAttributes: _paragraphAttributes frame: frame];
209-
210- NSLayoutManager *layoutManager = textStorage.layoutManagers .firstObject ;
211- NSTextContainer *textContainer = layoutManager.textContainers .firstObject ;
212-
213- [_textView replaceTextContainer: textContainer];
214-
215- NSArray <NSLayoutManager *> *managers = [[textStorage layoutManagers ] copy ];
216- for (NSLayoutManager *manager in managers) {
217- [textStorage removeLayoutManager: manager];
218- }
219-
220- _textView.minSize = frame.size ;
221- _textView.maxSize = frame.size ;
222- _textView.frame = frame;
223- _textView.textStorage .attributedString = textStorage;
224-
225- [self setNeedsDisplay ];
226181}
227- #endif // macOS]
228182
229183- (void )prepareForRecycle
230184{
@@ -427,11 +381,13 @@ - (void)copy:(id)sender
427381 return RCTParagraphComponentView.class ;
428382}
429383
430- #if !TARGET_OS_OSX // [macOS]
431384@implementation RCTParagraphTextView {
385+ #if !TARGET_OS_OSX // [macOS]
432386 CAShapeLayer *_highlightLayer;
387+ #endif // macOS]
433388}
434389
390+
435391- (void )drawRect : (CGRect)rect
436392{
437393 if (!_state) {
@@ -449,6 +405,7 @@ - (void)drawRect:(CGRect)rect
449405
450406 CGRect frame = RCTCGRectFromRect (_layoutMetrics.getContentFrame ());
451407
408+ #if !TARGET_OS_OSX // [macOS]
452409 [nativeTextLayoutManager drawAttributedString: _state->getData ().attributedString
453410 paragraphAttributes: _paragraphAttributes
454411 frame: frame
@@ -466,12 +423,33 @@ - (void)drawRect:(CGRect)rect
466423 self->_highlightLayer = nil ;
467424 }
468425 }];
426+ #else // [macOS
427+ NSTextStorage *textStorage = [nativeTextLayoutManager getTextStorageForAttributedString: _state->getData ().attributedString paragraphAttributes: _paragraphAttributes size: frame.size];
428+
429+ NSLayoutManager *layoutManager = textStorage.layoutManagers .firstObject ;
430+ NSTextContainer *textContainer = layoutManager.textContainers .firstObject ;
431+
432+ [self replaceTextContainer: textContainer];
433+
434+ NSArray <NSLayoutManager *> *managers = [[textStorage layoutManagers ] copy ];
435+ for (NSLayoutManager *manager in managers) {
436+ [textStorage removeLayoutManager: manager];
437+ }
438+
439+ self.minSize = frame.size ;
440+ self.maxSize = frame.size ;
441+ self.frame = frame;
442+ [[self textStorage ] setAttributedString: textStorage];
443+
444+ [super drawRect: rect];
445+ #endif
469446}
470447
471- @end
472- #else // [macOS
473448#if TARGET_OS_OSX // [macOS
474- @implementation RCTParagraphComponentUnfocusableTextView
449+ - (void )setNeedsDisplay
450+ {
451+ [self setNeedsDisplay: YES ];
452+ }
475453
476454- (BOOL )canBecomeKeyView
477455{
@@ -487,6 +465,6 @@ - (BOOL)resignFirstResponder
487465
488466 return [super resignFirstResponder ];
489467}
468+ #endif // macOS]
490469
491470@end
492- #endif // macOS]
0 commit comments