Skip to content

Commit ceec57d

Browse files
committed
rest
1 parent 39c5727 commit ceec57d

33 files changed

+1559
-503
lines changed

packages/react-native/Libraries/Image/RCTImageView.mm

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ - (instancetype)initWithBridge:(RCTBridge *)bridge
144144
_bridge = bridge;
145145
#if TARGET_OS_OSX // [macOS
146146
self.wantsLayer = YES;
147+
_resizeMode = RCTResizeModeCover;
148+
_imageView.contentMode = (UIViewContentMode)RCTResizeModeCover;
149+
[_imageView unregisterDraggedTypes];
147150
#endif // macOS]
148151
_imageView = [RCTUIImageViewAnimated new];
149152
_imageView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
@@ -195,10 +198,6 @@ - (void)updateWithImage:(UIImage *)image
195198
#else // [macOS
196199
image.capInsets = _capInsets;
197200
image.resizingMode = NSImageResizingModeTile;
198-
} else if (_resizeMode == RCTResizeModeCover) {
199-
if (!NSEqualSizes(self.bounds.size, NSZeroSize)) {
200-
image = RCTFillImagePreservingAspectRatio(image, self.bounds.size, self.window.backingScaleFactor ?: 1.0);
201-
}
202201
#endif // macOS]
203202
} else if (!UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _capInsets)) {
204203
// Applying capInsets of 0 will switch the "resizingMode" of the image to "tile" which is undesired
@@ -284,21 +283,9 @@ - (void)setResizeMode:(RCTResizeMode)resizeMode
284283
if (_resizeMode == RCTResizeModeRepeat) {
285284
// Repeat resize mode is handled by the UIImage. Use scale to fill
286285
// so the repeated image fills the UIImageView.
287-
#if !TARGET_OS_OSX // [macOS]
288286
_imageView.contentMode = UIViewContentModeScaleToFill;
289-
#else // [macOS
290-
_imageView.imageScaling = NSImageScaleAxesIndependently;
291-
#endif // macOS]
292287
} else {
293-
#if !TARGET_OS_OSX // [macOS]
294288
_imageView.contentMode = (UIViewContentMode)resizeMode;
295-
#else // [macOS
296-
// This relies on having previously resampled the image to a size that exceeds the image view.
297-
if (resizeMode == RCTResizeModeCover) {
298-
resizeMode = RCTResizeModeCenter;
299-
}
300-
_imageView.imageScaling = (NSImageScaling)resizeMode;
301-
#endif // macOS]
302289
}
303290

304291
if ([self shouldReloadImageSourceAfterResize]) {
@@ -566,7 +553,7 @@ - (void)reactSetFrame:(CGRect)frame
566553
!RCTShouldReloadImageForSizeChange(_targetSize, idealSize)) // [macOS
567554
#if TARGET_OS_OSX
568555
// Since macOS doen't support UIViewContentModeScaleAspectFill, we have to manually resample the image
569-
// If we're in cover mode we need to ensure that the image is re-sampled to the correct size when the container size (shrinking
556+
// If we're in cover mode we need to ensure that the image is re-sampled to the correct size when the container size (shrinking
570557
// being the most obvious case) otherwise we will end up in a state an image will not properly scale inside its container
571558
&& (RCTResizeModeFromUIViewContentMode(_imageView.contentMode) != RCTResizeModeCover ||
572559
(imageSize.width == idealSize.width && imageSize.height == idealSize.height))
@@ -617,13 +604,13 @@ - (void)didMoveToWindow
617604
[self reloadImage];
618605
}
619606
}
620-
607+
621608
#if TARGET_OS_OSX // [macOS
622609
- (void)viewDidChangeBackingProperties
623610
{
624611
[self reloadImage];
625612
}
626-
613+
627614
- (RCTPlatformView *)reactAccessibilityElement
628615
{
629616
return _imageView;

packages/react-native/Libraries/Image/RCTResizeMode.h

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,12 @@
88
#import <React/RCTConvert.h>
99

1010
typedef NS_ENUM(NSInteger, RCTResizeMode) {
11-
#if !TARGET_OS_OSX // [macOS]
1211
RCTResizeModeCover = UIViewContentModeScaleAspectFill,
1312
RCTResizeModeContain = UIViewContentModeScaleAspectFit,
1413
RCTResizeModeStretch = UIViewContentModeScaleToFill,
1514
RCTResizeModeCenter = UIViewContentModeCenter,
16-
RCTResizeModeRepeat = -1, // Use negative values to avoid
1715
RCTResizeModeNone = UIViewContentModeTopLeft,
18-
#else // [macOS
19-
RCTResizeModeCover = -2, // Not supported by NSImageView
20-
RCTResizeModeContain = NSImageScaleProportionallyUpOrDown,
21-
RCTResizeModeStretch = NSImageScaleAxesIndependently,
22-
RCTResizeModeCenter = -3, // assumes NSImageAlignmentCenter
23-
RCTResizeModeRepeat = -1,
24-
RCTResizeModeNone = NSImageScaleNone,
25-
#endif // macOS]
16+
RCTResizeModeRepeat = -1, // Use negative values to avoid conflicts with iOS enum values.
2617
};
2718

2819
static inline RCTResizeMode RCTResizeModeFromUIViewContentMode(UIViewContentMode mode)

packages/react-native/Libraries/Text/Text/RCTTextView.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212

1313
NS_ASSUME_NONNULL_BEGIN
1414

15+
#if !TARGET_OS_OSX // [macOS]
1516
@interface RCTTextView : RCTUIView // [macOS]
17+
#else // [macOS
18+
@interface RCTTextView : RCTUIView <ExtensibleNativeMenuProtocol>
19+
#endif // macOS]
1620

1721
- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher; // [macOS]
1822

packages/react-native/Libraries/Text/Text/RCTTextView.mm

Lines changed: 45 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#import <QuartzCore/QuartzCore.h>
2323

2424
#if TARGET_OS_OSX // [macOS
25+
#import <React/RCTRootContentView.h>
26+
#import <React/RCTTouchHandler.h>
2527

2628
// We are managing the key view loop using the RCTTextView.
2729
// Disable key view for backed NSTextView so we don't get double focus.
@@ -35,6 +37,16 @@ - (BOOL)canBecomeKeyView
3537
return NO;
3638
}
3739

40+
- (BOOL)resignFirstResponder
41+
{
42+
// Don't relinquish first responder while selecting text.
43+
if (self.selectable && NSRunLoop.currentRunLoop.currentMode == NSEventTrackingRunLoopMode) {
44+
return NO;
45+
}
46+
47+
return [super resignFirstResponder];
48+
}
49+
3850
@end
3951

4052
#endif // macOS]
@@ -64,6 +76,10 @@ @implementation RCTTextView {
6476
CGRect _contentFrame;
6577
}
6678

79+
#if TARGET_OS_OSX // [macOS
80+
@synthesize additionalMenuItems = _additionalMenuItems;
81+
#endif // macOS]
82+
6783
// [macOS
6884
- (instancetype)initWithEventDispatcher:(id<RCTEventDispatcherProtocol>)eventDispatcher
6985
{
@@ -82,12 +98,16 @@ - (instancetype)initWithFrame:(CGRect)frame
8298
self.accessibilityTraits |= UIAccessibilityTraitStaticText;
8399
self.opaque = NO;
84100
#else // [macOS
101+
// Make the RCTTextView accessible and available in the a11y hierarchy.
102+
self.accessibilityElement = YES;
85103
self.accessibilityRole = NSAccessibilityStaticTextRole;
86104
// Fix blurry text on non-retina displays.
87105
self.canDrawSubviewsIntoLayer = YES;
88106
// The NSTextView is responsible for drawing text and managing selection.
89107
_textView = [[RCTUnfocusableTextView alloc] initWithFrame:self.bounds];
90108
_textView.delegate = self;
109+
// The RCTUnfocusableTextView is only used for rendering and should not appear in the a11y hierarchy.
110+
_textView.accessibilityElement = NO;
91111
_textView.usesFontPanel = NO;
92112
_textView.drawsBackground = NO;
93113
_textView.linkTextAttributes = @{};
@@ -134,9 +154,6 @@ - (void)setSelectable:(BOOL)selectable
134154
}
135155
#else // [macOS
136156
_textView.selectable = _selectable;
137-
if (_selectable) {
138-
[self setFocusable:YES];
139-
}
140157
#endif // macOS]
141158
}
142159

@@ -253,8 +270,8 @@ - (void)drawRect:(CGRect)rect
253270
usingBlock:^(CGRect enclosingRect, __unused BOOL *anotherStop) {
254271
// [macOS
255272
UIBezierPath *path = UIBezierPathWithRoundedRect(
256-
CGRectInset(enclosingRect, -2, -2),
257-
2);
273+
CGRectInset(enclosingRect, -2, -2),
274+
2);
258275
// [macOS]
259276
if (highlightPath) {
260277
#if !TARGET_OS_OSX // [macOS]
@@ -403,17 +420,38 @@ - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture
403420

404421
#else // [macOS
405422

423+
- (NSMenu *)textView:(NSTextView *)view menu:(NSMenu *)menu forEvent:(NSEvent *)event atIndex:(NSUInteger)charIndex
424+
{
425+
[[RCTTouchHandler touchHandlerForView:self] willShowMenuWithEvent:event];
426+
427+
[menu setAutoenablesItems:NO];
428+
429+
RCTHideMenuItemsWithFilterPredicate(menu, ^bool(NSMenuItem *item) {
430+
// Remove items not applicable for readonly text.
431+
return (item.action == @selector(cut:) || item.action == @selector(paste:) || RCTMenuItemHasSubmenuItemWithAction(item, @selector(checkSpelling:)) || RCTMenuItemHasSubmenuItemWithAction(item, @selector(orderFrontSubstitutionsPanel:)));
432+
});
433+
434+
if (_additionalMenuItems && _additionalMenuItems.count > 0) {
435+
[menu insertItem:[NSMenuItem separatorItem] atIndex:0];
436+
for (NSMenuItem* item in [_additionalMenuItems reverseObjectEnumerator]) {
437+
[menu insertItem:item atIndex:0];
438+
}
439+
}
440+
441+
return menu;
442+
}
443+
406444
- (NSView *)hitTest:(NSPoint)point
407445
{
408446
// We will forward mouse click events to the NSTextView ourselves to prevent NSTextView from swallowing events that may be handled in JS (e.g. long press).
409447
NSView *hitView = [super hitTest:point];
410-
448+
411449
NSEventType eventType = NSApp.currentEvent.type;
412450
BOOL isMouseClickEvent = NSEvent.pressedMouseButtons > 0;
413451
BOOL isMouseMoveEventType = eventType == NSEventTypeMouseMoved || eventType == NSEventTypeMouseEntered || eventType == NSEventTypeMouseExited || eventType == NSEventTypeCursorUpdate;
414452
BOOL isMouseMoveEvent = !isMouseClickEvent && isMouseMoveEventType;
415453
BOOL isTextViewClick = (hitView && hitView == _textView) && !isMouseMoveEvent;
416-
454+
417455
return isTextViewClick ? self : hitView;
418456
}
419457

@@ -483,21 +521,6 @@ - (BOOL)canBecomeFirstResponder
483521
return _selectable;
484522
}
485523
#else // [macOS
486-
- (BOOL)canBecomeKeyView
487-
{
488-
return self.focusable;
489-
}
490-
491-
- (void)drawFocusRingMask {
492-
if (self.focusable && self.enableFocusRing) {
493-
NSRectFill([self bounds]);
494-
}
495-
}
496-
497-
- (NSRect)focusRingMaskBounds {
498-
return [self bounds];
499-
}
500-
501524
- (BOOL)becomeFirstResponder
502525
{
503526
if (![super becomeFirstResponder]) {
@@ -510,16 +533,6 @@ - (BOOL)becomeFirstResponder
510533
return YES;
511534
}
512535

513-
- (BOOL)resignFirstResponder
514-
{
515-
// Don't relinquish first responder while selecting text.
516-
if (_selectable && NSRunLoop.currentRunLoop.currentMode == NSEventTrackingRunLoopMode) {
517-
return NO;
518-
}
519-
520-
return [super resignFirstResponder];
521-
}
522-
523536
- (BOOL)canBecomeFirstResponder
524537
{
525538
return self.focusable;

packages/react-native/Libraries/Text/TextInput/Multiline/RCTUITextView.mm

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@
1313
#import <React/RCTBackedTextInputDelegateAdapter.h>
1414
#import <React/RCTTextAttributes.h>
1515

16+
#if TARGET_OS_OSX // [macOS
17+
#import <React/RCTTouchHandler.h>
18+
#endif // macOS]
19+
1620
@implementation RCTUITextView {
1721
#if !TARGET_OS_OSX // [macOS]
1822
UILabel *_placeholderView;
@@ -130,6 +134,25 @@ - (NSString *)accessibilityLabel
130134
return accessibilityLabel;
131135
}
132136

137+
#pragma mark - Context menu
138+
139+
#if TARGET_OS_OSX // [macOS
140+
- (NSMenu *)menuForEvent:(NSEvent *)event
141+
{
142+
NSMenu *menu = [super menuForEvent:event];
143+
if (menu) {
144+
[[RCTTouchHandler touchHandlerForView:self] willShowMenuWithEvent:event];
145+
}
146+
147+
RCTHideMenuItemsWithFilterPredicate(menu, ^bool(NSMenuItem *item) {
148+
// hide font & layout orientation menu options
149+
return (RCTMenuItemHasSubmenuItemWithAction(item, @selector(orderFrontFontPanel:)) || RCTMenuItemHasSubmenuItemWithAction(item, @selector(changeLayoutOrientation:)));
150+
});
151+
152+
return menu;
153+
}
154+
#endif // macOS]
155+
133156
#pragma mark - Properties
134157

135158
- (void)setPlaceholder:(NSString *)placeholder
@@ -234,12 +257,8 @@ - (BOOL)becomeFirstResponder
234257

235258
- (BOOL)resignFirstResponder
236259
{
237-
if (self.selectable) {
238-
self.selectedRange = NSMakeRange(NSNotFound, 0);
239-
}
240-
241260
BOOL success = [super resignFirstResponder];
242-
261+
243262
if (success) {
244263
// Break undo coalescing when losing focus.
245264
[self breakUndoCoalescing];
@@ -395,7 +414,7 @@ - (NSTouchBar *)makeTouchBar
395414
- (void)paste:(id)sender
396415
{
397416
#if TARGET_OS_OSX // [macOS
398-
if ([self.textInputDelegate textInputShouldHandlePaste:self])
417+
if ([self.textInputDelegate textInputShouldHandlePaste:self])
399418
{
400419
#endif // macOS]
401420
_textWasPasted = YES;
@@ -429,19 +448,19 @@ - (NSAttributedString*)placeholderTextAttributedString
429448
- (void)drawRect:(NSRect)dirtyRect
430449
{
431450
[super drawRect:dirtyRect];
432-
451+
433452
if (self.text.length == 0 && self.placeholder) {
434453
NSAttributedString *attributedPlaceholderString = self.placeholderTextAttributedString;
435-
454+
436455
if (attributedPlaceholderString) {
437456
NSTextStorage *textStorage = [[NSTextStorage alloc] initWithAttributedString:attributedPlaceholderString];
438457
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithContainerSize:self.textContainer.containerSize];
439458
NSLayoutManager *layoutManager = [NSLayoutManager new];
440-
459+
441460
textContainer.lineFragmentPadding = self.textContainer.lineFragmentPadding;
442461
[layoutManager addTextContainer:textContainer];
443462
[textStorage addLayoutManager:layoutManager];
444-
463+
445464
NSRange glyphRange = [layoutManager glyphRangeForTextContainer:textContainer];
446465
[layoutManager drawGlyphsForGlyphRange:glyphRange atPoint:self.textContainerOrigin];
447466
}
@@ -633,7 +652,7 @@ - (void)keyDown:(NSEvent *)event {
633652
}
634653

635654
// textInputShouldHandleKeyEvent represents if native should handle the event instead of JS.
636-
// textInputShouldHandleKeyEvent also sends keyDown event to JS internally, so we only call this once
655+
// textInputShouldHandleKeyEvent also sends keyDown event to JS internally, so we only call this once
637656
if ([self.textInputDelegate textInputShouldHandleKeyEvent:event]) {
638657
[super keyDown:event];
639658
[self.textInputDelegate submitOnKeyDownIfNeeded:event];

0 commit comments

Comments
 (0)