Skip to content

Commit 66f8fbe

Browse files
authored
fix: revert "render Text in an NSTextView (#2286)" (#2676)
## Summary: Revert #2286 There are 3 commits that make Text Selection work via NSTextView on Fabric, but we only ever merged two of them in. The 3rd (currently in #2673 ) is a work-in-progress, as it currently doesn't work. I need to debug why text selection doesn't work, but as it stands, the diffs to render with an NSTextView add more complexity for not much gain without it. I'd rather reland all the commits together and test with an implementation of Text closer to iOS in the meanwhile. ## Test Plan: CI should pass
1 parent 5c684ef commit 66f8fbe

File tree

1 file changed

+74
-86
lines changed

1 file changed

+74
-86
lines changed

packages/react-native/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm

Lines changed: 74 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#if !TARGET_OS_OSX // [macOS]
1212
#import <MobileCoreServices/UTCoreTypes.h>
1313
#endif // [macOS]
14+
#if TARGET_OS_OSX // [macOS
15+
#import <QuartzCore/CAShapeLayer.h>
16+
#endif // macOS]
1417

1518
#import <react/renderer/components/text/ParagraphComponentDescriptor.h>
1619
#import <react/renderer/components/text/ParagraphProps.h>
@@ -25,36 +28,26 @@
2528
#import "RCTConversions.h"
2629
#import "RCTFabricComponentsPlugins.h"
2730

28-
#import <QuartzCore/QuartzCore.h> // [macOS]
29-
3031
using namespace facebook::react;
3132

32-
#if !TARGET_OS_OSX // [macOS]
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]
4136

4237
@property (nonatomic) ParagraphShadowNode::ConcreteState::Shared state;
4338
@property (nonatomic) ParagraphAttributes paragraphAttributes;
4439
@property (nonatomic) LayoutMetrics layoutMetrics;
4540

46-
#if TARGET_OS_OSX // [macOS]
47-
/// UIKit compatibility shim that simply calls `[self setNeedsDisplay:YES]`
48-
- (void)setNeedsDisplay;
49-
#endif
50-
5141
@end
5242

5343
#if !TARGET_OS_OSX // [macOS]
5444
@interface RCTParagraphComponentView () <UIEditMenuInteractionDelegate>
5545

5646
@property (nonatomic, nullable) UIEditMenuInteraction *editMenuInteraction API_AVAILABLE(ios(16.0));
5747

48+
@end
49+
#else // [macOS
50+
@interface RCTParagraphComponentView ()
5851
@end
5952
#endif // [macOS]
6053

@@ -64,7 +57,7 @@ @implementation RCTParagraphComponentView {
6457
RCTParagraphComponentAccessibilityProvider *_accessibilityProvider;
6558
#if !TARGET_OS_OSX // [macOS]
6659
UILongPressGestureRecognizer *_longPressGestureRecognizer;
67-
#endif // macOS]
60+
#endif // [macOS]
6861
RCTParagraphTextView *_textView;
6962
}
7063

@@ -73,30 +66,11 @@ - (instancetype)initWithFrame:(CGRect)frame
7366
if (self = [super initWithFrame:frame]) {
7467
_props = ParagraphShadowNode::defaultSharedProps();
7568

76-
#if !TARGET_OS_OSX // [macOS]
69+
#if !TARGET_OS_OSX // [macOS]
7770
self.opaque = NO;
71+
#endif // [macOS]
7872
_textView = [RCTParagraphTextView new];
7973
_textView.backgroundColor = RCTUIColor.clearColor; // [macOS]
80-
#else // [macOS
81-
// Make the RCTParagraphComponentView accessible and available in the a11y hierarchy.
82-
self.accessibilityElement = YES;
83-
self.accessibilityRole = NSAccessibilityStaticTextRole;
84-
// Fix blurry text on non-retina displays.
85-
self.canDrawSubviewsIntoLayer = YES;
86-
// The NSTextView is responsible for drawing text and managing selection.
87-
_textView = [[RCTParagraphTextView alloc] initWithFrame:self.bounds];
88-
// The RCTParagraphComponentUnfocusableTextView is only used for rendering and should not appear in the a11y hierarchy.
89-
_textView.accessibilityElement = NO;
90-
_textView.usesFontPanel = NO;
91-
_textView.drawsBackground = NO;
92-
_textView.linkTextAttributes = @{};
93-
_textView.editable = NO;
94-
_textView.selectable = NO;
95-
_textView.verticallyResizable = NO;
96-
_textView.layoutManager.usesFontLeading = NO;
97-
self.contentView = _textView;
98-
self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawDuringViewResize;
99-
#endif // macOS]
10074
self.contentView = _textView;
10175
}
10276

@@ -153,9 +127,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
153127
} else {
154128
[self disableContextMenu];
155129
}
156-
#else // [macOS
157-
_textView.selectable = newParagraphProps.isSelectable;
158-
#endif // macOS]
130+
#endif // [macOS]
159131
}
160132

161133
[super updateProps:props oldProps:oldProps];
@@ -213,7 +185,7 @@ - (BOOL)isAccessibilityElement
213185
return NO;
214186
}
215187

216-
#if !TARGET_OS_OSX // [macOS]
188+
#if !TARGET_OS_OSX // [macOS
217189
- (NSArray *)accessibilityElements
218190
{
219191
const auto &paragraphProps = static_cast<const ParagraphProps &>(*_props);
@@ -249,7 +221,12 @@ - (UIAccessibilityTraits)accessibilityTraits
249221
{
250222
return [super accessibilityTraits] | UIAccessibilityTraitStaticText;
251223
}
252-
#endif // [macOS]
224+
#else // [macOS
225+
- (NSAccessibilityRole)accessibilityRole
226+
{
227+
return [super accessibilityRole] ?: NSAccessibilityStaticTextRole;
228+
}
229+
#endif // macOS]
253230

254231
#pragma mark - RCTTouchableComponentViewProtocol
255232

@@ -333,6 +310,7 @@ - (BOOL)canBecomeFirstResponder
333310
return paragraphProps.isSelectable;
334311
}
335312

313+
#if !TARGET_OS_OSX // [macOS]
336314
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
337315
{
338316
const auto &paragraphProps = static_cast<const ParagraphProps &>(*_props);
@@ -341,12 +319,9 @@ - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
341319
return YES;
342320
}
343321

344-
#if !TARGET_OS_OSX // [macOS]
345322
return [self.nextResponder canPerformAction:action withSender:sender];
346-
#else // [macOS
347-
return NO;
348-
#endif // macOS]
349323
}
324+
#endif // [macOS]
350325

351326
- (void)copy:(id)sender
352327
{
@@ -382,12 +357,10 @@ - (void)copy:(id)sender
382357
}
383358

384359
@implementation RCTParagraphTextView {
385-
#if !TARGET_OS_OSX // [macOS]
386360
CAShapeLayer *_highlightLayer;
387-
#endif // macOS]
388361
}
389362

390-
- (RCTUIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event // [macOS]
363+
- (RCTUIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
391364
{
392365
return nil;
393366
}
@@ -409,7 +382,6 @@ - (void)drawRect:(CGRect)rect
409382

410383
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
411384

412-
#if !TARGET_OS_OSX // [macOS]
413385
[nativeTextLayoutManager drawAttributedString:_state->getData().attributedString
414386
paragraphAttributes:_paragraphAttributes
415387
frame:frame
@@ -421,54 +393,70 @@ - (void)drawRect:(CGRect)rect
421393
[self.layer addSublayer:self->_highlightLayer];
422394
}
423395
self->_highlightLayer.position = frame.origin;
396+
397+
#if !TARGET_OS_OSX // [macOS]
424398
self->_highlightLayer.path = highlightPath.CGPath;
399+
#else // [macOS Update once our minimum is macOS 14
400+
self->_highlightLayer.path = UIBezierPathCreateCGPathRef(highlightPath);
401+
#endif // macOS]
425402
} else {
426403
[self->_highlightLayer removeFromSuperlayer];
427404
self->_highlightLayer = nil;
428405
}
429406
}];
430-
#else // [macOS
431-
NSTextStorage *textStorage = [nativeTextLayoutManager getTextStorageForAttributedString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes size:frame.size];
432-
433-
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
434-
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
435-
436-
[self replaceTextContainer:textContainer];
437-
438-
NSArray<NSLayoutManager *> *managers = [[textStorage layoutManagers] copy];
439-
for (NSLayoutManager *manager in managers) {
440-
[textStorage removeLayoutManager:manager];
441-
}
442-
443-
self.minSize = frame.size;
444-
self.maxSize = frame.size;
445-
self.frame = frame;
446-
[[self textStorage] setAttributedString:textStorage];
447-
448-
[super drawRect:rect];
449-
#endif
450407
}
451408

452-
#if TARGET_OS_OSX // [macOS
453-
- (void)setNeedsDisplay
454-
{
455-
[self setNeedsDisplay:YES];
456-
}
457-
458-
- (BOOL)canBecomeKeyView
459-
{
460-
return NO;
461-
}
409+
@end
462410

463-
- (BOOL)resignFirstResponder
411+
#if TARGET_OS_OSX // [macOS
412+
// Copied from RCTUIKit
413+
CGPathRef UIBezierPathCreateCGPathRef(UIBezierPath *bezierPath)
464414
{
465-
// Don't relinquish first responder while selecting text.
466-
if (self.selectable && NSRunLoop.currentRunLoop.currentMode == NSEventTrackingRunLoopMode) {
467-
return NO;
415+
CGPathRef immutablePath = NULL;
416+
417+
// Draw the path elements.
418+
NSInteger numElements = [bezierPath elementCount];
419+
if (numElements > 0)
420+
{
421+
CGMutablePathRef path = CGPathCreateMutable();
422+
NSPoint points[3];
423+
BOOL didClosePath = YES;
424+
425+
for (NSInteger i = 0; i < numElements; i++)
426+
{
427+
switch ([bezierPath elementAtIndex:i associatedPoints:points])
428+
{
429+
case NSBezierPathElementMoveTo:
430+
CGPathMoveToPoint(path, NULL, points[0].x, points[0].y);
431+
break;
432+
433+
case NSBezierPathElementLineTo:
434+
CGPathAddLineToPoint(path, NULL, points[0].x, points[0].y);
435+
didClosePath = NO;
436+
break;
437+
438+
case NSBezierPathElementCurveTo:
439+
CGPathAddCurveToPoint(path, NULL, points[0].x, points[0].y,
440+
points[1].x, points[1].y,
441+
points[2].x, points[2].y);
442+
didClosePath = NO;
443+
break;
444+
445+
case NSBezierPathElementClosePath:
446+
CGPathCloseSubpath(path);
447+
didClosePath = YES;
448+
break;
449+
}
450+
}
451+
452+
// Be sure the path is closed or Quartz may not do valid hit detection.
453+
if (!didClosePath)
454+
CGPathCloseSubpath(path);
455+
456+
immutablePath = CGPathCreateCopy(path);
457+
CGPathRelease(path);
468458
}
469-
470-
return [super resignFirstResponder];
459+
460+
return immutablePath;
471461
}
472462
#endif // macOS]
473-
474-
@end

0 commit comments

Comments
 (0)