From c30fc6b09686b4d0b66409979debfdf470716ffe Mon Sep 17 00:00:00 2001 From: Liron Yahdav Date: Mon, 19 Apr 2021 13:01:44 -0600 Subject: [PATCH] Fix spellCheck and autoCorrect props (#1292) Summary: This fixes `autoCorrect` to correctly map to `automaticSpellingCorrectionEnabled`, and `spellCheck` to map to `continuousSpellCheckingEnabled`. Note: automaticTextReplacementEnabled is a different feature than automaticSpellingCorrectionEnabled https://developer.apple.com/documentation/appkit/nstextview/1449210-automatictextreplacementenabled https://developer.apple.com/documentation/appkit/nstextview/1449254-isautomaticspellingcorrectionena Co-authored-by: Scott Kyle # Conflicts: # Libraries/Text/TextInput/Singleline/RCTUITextField.h # Libraries/Text/TextInput/Singleline/RCTUITextField.m --- .../Components/Touchable/TouchableBounce.js | 1 + .../Touchable/TouchableHighlight.js | 1 + .../Components/Touchable/TouchableOpacity.js | 1 + .../Touchable/TouchableWithoutFeedback.js | 2 + .../View/ReactNativeStyleAttributes.js | 1 + .../View/ReactNativeViewViewConfig.js | 1 + .../View/ReactNativeViewViewConfigMacOS.js | 1 + Libraries/Components/View/ViewPropTypes.js | 6 + Libraries/StyleSheet/StyleSheetTypes.js | 25 +++++ .../Text/BaseText/RCTBaseTextViewManager.m | 7 ++ Libraries/Text/RCTTextAttributes.h | 7 ++ Libraries/Text/RCTTextAttributes.m | 26 ++++- Libraries/Text/Text/RCTTextView.m | 5 + React/Base/macOS/RCTUIKit.m | 7 ++ React/Views/RCTCursor.h | 37 +++++++ React/Views/RCTCursor.m | 103 ++++++++++++++++++ React/Views/RCTView.h | 5 + React/Views/RCTView.m | 41 ++++--- React/Views/RCTViewManager.m | 5 + .../js/examples/Text/TextExample.ios.js | 24 ++++ .../rn-tester/js/examples/View/ViewExample.js | 60 ++++++++++ 21 files changed, 345 insertions(+), 21 deletions(-) create mode 100644 React/Views/RCTCursor.h create mode 100644 React/Views/RCTCursor.m diff --git a/Libraries/Components/Touchable/TouchableBounce.js b/Libraries/Components/Touchable/TouchableBounce.js index d67cd80ff8bfd2..197042e71aaee5 100644 --- a/Libraries/Components/Touchable/TouchableBounce.js +++ b/Libraries/Components/Touchable/TouchableBounce.js @@ -164,6 +164,7 @@ class TouchableBounce extends React.Component { !this.props.disabled } focusable={this.props.focusable !== false && !this.props.disabled} + cursor={this.props.cursor} tooltip={this.props.tooltip} onMouseEnter={this.props.onMouseEnter} onMouseLeave={this.props.onMouseLeave} diff --git a/Libraries/Components/Touchable/TouchableHighlight.js b/Libraries/Components/Touchable/TouchableHighlight.js index 69070319d54427..8e2df405dae3c2 100644 --- a/Libraries/Components/Touchable/TouchableHighlight.js +++ b/Libraries/Components/Touchable/TouchableHighlight.js @@ -335,6 +335,7 @@ class TouchableHighlight extends React.Component { } focusable={this.props.focusable !== false && !this.props.disabled} tooltip={this.props.tooltip} + cursor={this.props.cursor} onMouseEnter={this.props.onMouseEnter} onMouseLeave={this.props.onMouseLeave} onDragEnter={this.props.onDragEnter} diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 8dd118e6c8791e..10093dbaf2800f 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -287,6 +287,7 @@ class TouchableOpacity extends React.Component { } focusable={this.props.focusable !== false && !this.props.disabled} tooltip={this.props.tooltip} + cursor={this.props.cursor} onMouseEnter={this.props.onMouseEnter} onMouseLeave={this.props.onMouseLeave} onDragEnter={this.props.onDragEnter} diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index adb35b87914909..817f84dbe8516d 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -20,6 +20,7 @@ import type { AccessibilityValue, } from '../../Components/View/ViewAccessibility'; import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; +import type {CursorValue} from '../../StyleSheet/StyleSheetTypes'; import type { BlurEvent, FocusEvent, @@ -48,6 +49,7 @@ type Props = $ReadOnly<{| accessibilityViewIsModal?: ?boolean, accessible?: ?boolean, children?: ?React.Node, + cursor?: ?CursorValue, delayLongPress?: ?number, delayPressIn?: ?number, delayPressOut?: ?number, diff --git a/Libraries/Components/View/ReactNativeStyleAttributes.js b/Libraries/Components/View/ReactNativeStyleAttributes.js index 9525991e831b53..7b4224b86d830c 100644 --- a/Libraries/Components/View/ReactNativeStyleAttributes.js +++ b/Libraries/Components/View/ReactNativeStyleAttributes.js @@ -116,6 +116,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = { borderTopLeftRadius: true, borderTopRightRadius: true, borderTopStartRadius: true, + cursor: true, opacity: true, /** diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 4323cc4841dbd2..5902cc231a06e2 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -273,6 +273,7 @@ const ReactNativeViewConfig: ViewConfig = { borderWidth: true, bottom: true, color: {process: require('../../StyleSheet/processColor')}, + cursor: true, decomposedMatrix: true, direction: true, display: true, diff --git a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js index 306db82352f372..b6c9c7936d5752 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js +++ b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js @@ -37,6 +37,7 @@ const ReactNativeViewViewConfigMacOS = { validAttributes: { acceptsFirstMouse: true, accessibilityTraits: true, + cursor: true, draggedTypes: true, enableFocusRing: true, onBlur: true, diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 22ce4f52121996..ebbd5697597fd1 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -23,6 +23,7 @@ import type { import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; import type {Node} from 'react'; import type {ViewStyleProp} from '../../StyleSheet/StyleSheet'; +import type {CursorValue} from '../../StyleSheet/StyleSheetTypes'; import type { AccessibilityRole, AccessibilityState, @@ -633,4 +634,9 @@ export type ViewProps = $ReadOnly<{| * @platform macos */ draggedTypes?: ?DraggedTypesType, // TODO(macOS GH#774) + + /* + * Sets the type of mouse cursor, to show when the mouse pointer is over the view. + */ + cursor?: ?CursorValue, // TODO(macOS GH#774) |}>; diff --git a/Libraries/StyleSheet/StyleSheetTypes.js b/Libraries/StyleSheet/StyleSheetTypes.js index 10decd25cb9b87..57ba92b8154e75 100644 --- a/Libraries/StyleSheet/StyleSheetTypes.js +++ b/Libraries/StyleSheet/StyleSheetTypes.js @@ -16,6 +16,29 @@ import type {NativeColorValue} from './PlatformColorValueTypes'; export type ____ColorValue_Internal = null | string | NativeColorValue; +export type CursorValue = ?( + | 'alias' + | 'auto' + | 'col-resize' + | 'context-menu' + | 'copy' + | 'crosshair' + | 'default' + | 'disappearing-item' + | 'e-resize' + | 'grab' + | 'grabbing' + | 'n-resize' + | 'no-drop' + | 'not-allowed' + | 'pointer' + | 'row-resize' + | 's-resize' + | 'text' + | 'vertical-text' + | 'w-resize' +) + export type ColorArrayValue = null | $ReadOnlyArray<____ColorValue_Internal>; export type PointValue = {| x: number, @@ -584,6 +607,7 @@ export type ____ViewStyle_Internal = $ReadOnly<{| borderTopWidth?: number | AnimatedNode, opacity?: number | AnimatedNode, elevation?: number, + cursor?: CursorValue, |}>; export type ____FontWeight_Internal = @@ -638,6 +662,7 @@ export type ____TextStyle_Internal = $ReadOnly<{| textDecorationColor?: ____ColorValue_Internal, textTransform?: 'none' | 'capitalize' | 'uppercase' | 'lowercase', writingDirection?: 'auto' | 'ltr' | 'rtl', + cursor?: CursorValue, |}>; export type ____ImageStyle_Internal = $ReadOnly<{| diff --git a/Libraries/Text/BaseText/RCTBaseTextViewManager.m b/Libraries/Text/BaseText/RCTBaseTextViewManager.m index 031f714ed09968..4129ed37b3d055 100644 --- a/Libraries/Text/BaseText/RCTBaseTextViewManager.m +++ b/Libraries/Text/BaseText/RCTBaseTextViewManager.m @@ -6,6 +6,9 @@ */ #import +#if TARGET_OS_OSX // TODO(macOS ISS#2323203) +#import +#endif // TODO(macOS ISS#2323203) @implementation RCTBaseTextViewManager @@ -55,4 +58,8 @@ - (RCTShadowView *)shadowView RCT_REMAP_SHADOW_PROPERTY(isHighlighted, textAttributes.isHighlighted, BOOL) RCT_REMAP_SHADOW_PROPERTY(textTransform, textAttributes.textTransform, RCTTextTransform) +#if TARGET_OS_OSX // TODO(macOS ISS#2323203) +RCT_REMAP_SHADOW_PROPERTY(cursor, textAttributes.cursor, RCTCursor) +#endif // TODO(macOS ISS#2323203) + @end diff --git a/Libraries/Text/RCTTextAttributes.h b/Libraries/Text/RCTTextAttributes.h index f5549990a39ac6..81178b83eca529 100644 --- a/Libraries/Text/RCTTextAttributes.h +++ b/Libraries/Text/RCTTextAttributes.h @@ -6,6 +6,9 @@ */ #import // TODO(macOS GH#774) +#if TARGET_OS_OSX // TODO(macOS GH#774) +#import +#endif // TODO(macOS GH#774) #import #import // TODO(OSS Candidate ISS#2710739) @@ -59,6 +62,10 @@ extern NSString *const RCTTextAttributesTagAttributeName; @property (nonatomic, assign) UIUserInterfaceLayoutDirection layoutDirection; @property (nonatomic, assign) RCTTextTransform textTransform; +#if TARGET_OS_OSX // TODO(macOS ISS#2323203) +@property (nonatomic, assign) RCTCursor cursor; +#endif // TODO(macOS ISS#2323203) + #pragma mark - Inheritance - (void)applyTextAttributes:(RCTTextAttributes *)textAttributes; diff --git a/Libraries/Text/RCTTextAttributes.m b/Libraries/Text/RCTTextAttributes.m index 0690ea3bdf27b9..e83788bc6deb05 100644 --- a/Libraries/Text/RCTTextAttributes.m +++ b/Libraries/Text/RCTTextAttributes.m @@ -11,6 +11,10 @@ #import #import +#if TARGET_OS_OSX // TODO(macOS ISS#2323203) +#import +#endif // TODO(macOS ISS#2323203) + NSString *const RCTTextAttributesIsHighlightedAttributeName = @"RCTTextAttributesIsHighlightedAttributeName"; NSString *const RCTTextAttributesFontSmoothingAttributeName = @"RCTTextAttributesFontSmoothingAttributeName"; // TODO(OSS Candidate ISS#2710739) NSString *const RCTTextAttributesTagAttributeName = @"RCTTextAttributesTagAttributeName"; @@ -45,6 +49,9 @@ - (instancetype)init // [TODO(macOS GH#774) _foregroundColor = [RCTTextAttributes defaultForegroundColor]; // ]TODO(macOS GH#774) +#if TARGET_OS_OSX // TODO(macOS ISS#2323203) + _cursor = RCTCursorAuto; +#endif // TODO(macOS ISS#2323203) } return self; @@ -93,6 +100,10 @@ - (void)applyTextAttributes:(RCTTextAttributes *)textAttributes _tag = textAttributes->_tag ?: _tag; _layoutDirection = textAttributes->_layoutDirection != UIUserInterfaceLayoutDirectionLeftToRight ? textAttributes->_layoutDirection : _layoutDirection; _textTransform = textAttributes->_textTransform != RCTTextTransformUndefined ? textAttributes->_textTransform : _textTransform; + +#if TARGET_OS_OSX // TODO(macOS ISS#2323203) + _cursor = textAttributes->_cursor != RCTCursorAuto ? textAttributes->_cursor : _cursor; +#endif // TODO(macOS ISS#2323203) } - (NSParagraphStyle *)effectiveParagraphStyle @@ -109,27 +120,27 @@ - (NSParagraphStyle *)effectiveParagraphStyle alignment = NSTextAlignmentRight; } } - + paragraphStyle.alignment = alignment; isParagraphStyleUsed = YES; } - + if (_baseWritingDirection != NSWritingDirectionNatural) { paragraphStyle.baseWritingDirection = _baseWritingDirection; isParagraphStyleUsed = YES; } - + if (!isnan(_lineHeight)) { CGFloat lineHeight = _lineHeight * self.effectiveFontSizeMultiplier; paragraphStyle.minimumLineHeight = lineHeight; paragraphStyle.maximumLineHeight = lineHeight; isParagraphStyleUsed = YES; } - + if (isParagraphStyleUsed) { return [paragraphStyle copy]; } - + return nil; } @@ -209,6 +220,11 @@ - (NSParagraphStyle *)effectiveParagraphStyle attributes[RCTTextAttributesTagAttributeName] = _tag; } +#if TARGET_OS_OSX // TODO(macOS ISS#2323203) + if (_cursor != RCTCursorAuto) { + attributes[NSCursorAttributeName] = [RCTConvert NSCursor:_cursor]; + } +#endif // TODO(macOS ISS#2323203) return [attributes copy]; } diff --git a/Libraries/Text/Text/RCTTextView.m b/Libraries/Text/Text/RCTTextView.m index f2acf25de9eb50..c02fc732e5bde0 100644 --- a/Libraries/Text/Text/RCTTextView.m +++ b/Libraries/Text/Text/RCTTextView.m @@ -85,6 +85,11 @@ - (instancetype)initWithFrame:(CGRect)frame } #if TARGET_OS_OSX // [TODO(macOS GH#774) +- (void)setCursor:(RCTCursor)cursor +{ + // This is required because the RCTTextViewManager inherits from RCTViewManager which has a cursor prop. +} + - (NSView *)hitTest:(NSPoint)point { // We will forward mouse events to the NSTextView ourselves. diff --git a/React/Base/macOS/RCTUIKit.m b/React/Base/macOS/RCTUIKit.m index b7ee45c50841eb..3d0ea62bf04c9c 100644 --- a/React/Base/macOS/RCTUIKit.m +++ b/React/Base/macOS/RCTUIKit.m @@ -423,6 +423,13 @@ - (void)setBackgroundColor:(NSColor *)backgroundColor } } +// We purposely don't use RCTCursor for the parameter type here because it would introduce an import cycle: +// RCTUIKit > RCTCursor > RCTConvert > RCTUIKit +- (void)setCursor:(NSInteger)cursor +{ + // This method is required to be defined due to [RCTVirtualTextViewManager view] returning a RCTUIView. +} + @end // RCTUIScrollView diff --git a/React/Views/RCTCursor.h b/React/Views/RCTCursor.h new file mode 100644 index 00000000000000..34a51ac9cb4aed --- /dev/null +++ b/React/Views/RCTCursor.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +typedef NS_ENUM(NSInteger, RCTCursor) { + RCTCursorAuto, + RCTCursorArrow, + RCTCursorIBeam, + RCTCursorCrosshair, + RCTCursorClosedHand, + RCTCursorOpenHand, + RCTCursorPointingHand, + RCTCursorResizeLeft, + RCTCursorResizeRight, + RCTCursorResizeLeftRight, + RCTCursorResizeUp, + RCTCursorResizeDown, + RCTCursorResizeUpDown, + RCTCursorDisappearingItem, + RCTCursorIBeamCursorForVerticalLayout, + RCTCursorOperationNotAllowed, + RCTCursorDragLink, + RCTCursorDragCopy, + RCTCursorContextualMenu, +}; + +@interface RCTConvert (RCTCursor) + ++ (RCTCursor)RCTCursor:(id)json; ++ (NSCursor *)NSCursor:(RCTCursor)rctCursor; + +@end diff --git a/React/Views/RCTCursor.m b/React/Views/RCTCursor.m new file mode 100644 index 00000000000000..f70ad56f5bda17 --- /dev/null +++ b/React/Views/RCTCursor.m @@ -0,0 +1,103 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import + +@implementation RCTConvert (RCTCursor) + +RCT_ENUM_CONVERTER( + RCTCursor, + (@{ + @"alias" : @(RCTCursorDragLink), + @"auto" : @(RCTCursorAuto), + @"col-resize" : @(RCTCursorResizeLeftRight), + @"context-menu" : @(RCTCursorContextualMenu), + @"copy" : @(RCTCursorDragCopy), + @"crosshair" : @(RCTCursorCrosshair), + @"default" : @(RCTCursorArrow), + @"disappearing-item" : @(RCTCursorDisappearingItem), + @"e-resize" : @(RCTCursorResizeRight), + @"grab" : @(RCTCursorOpenHand), + @"grabbing" : @(RCTCursorClosedHand), + @"n-resize" : @(RCTCursorResizeUp), + @"no-drop" : @(RCTCursorOperationNotAllowed), + @"not-allowed" : @(RCTCursorOperationNotAllowed), + @"pointer" : @(RCTCursorPointingHand), + @"row-resize" : @(RCTCursorResizeUpDown), + @"s-resize" : @(RCTCursorResizeDown), + @"text" : @(RCTCursorIBeam), + @"vertical-text" : @(RCTCursorIBeamCursorForVerticalLayout), + @"w-resize" : @(RCTCursorResizeLeft), + }), + RCTCursorAuto, + integerValue) + ++ (NSCursor *)NSCursor:(RCTCursor)rctCursor +{ + NSCursor *cursor; + + switch (rctCursor) { + case RCTCursorArrow: + cursor = [NSCursor arrowCursor]; + break; + case RCTCursorClosedHand: + cursor = [NSCursor closedHandCursor]; + break; + case RCTCursorContextualMenu: + cursor = [NSCursor contextualMenuCursor]; + break; + case RCTCursorCrosshair: + cursor = [NSCursor crosshairCursor]; + break; + case RCTCursorDisappearingItem: + cursor = [NSCursor disappearingItemCursor]; + break; + case RCTCursorDragCopy: + cursor = [NSCursor dragCopyCursor]; + break; + case RCTCursorDragLink: + cursor = [NSCursor dragLinkCursor]; + break; + case RCTCursorIBeam: + cursor = [NSCursor IBeamCursor]; + break; + case RCTCursorIBeamCursorForVerticalLayout: + cursor = [NSCursor IBeamCursorForVerticalLayout]; + break; + case RCTCursorOpenHand: + cursor = [NSCursor openHandCursor]; + break; + case RCTCursorOperationNotAllowed: + cursor = [NSCursor operationNotAllowedCursor]; + break; + case RCTCursorPointingHand: + cursor = [NSCursor pointingHandCursor]; + break; + case RCTCursorResizeDown: + cursor = [NSCursor resizeDownCursor]; + break; + case RCTCursorResizeLeft: + cursor = [NSCursor resizeLeftCursor]; + break; + case RCTCursorResizeLeftRight: + cursor = [NSCursor resizeLeftRightCursor]; + break; + case RCTCursorResizeRight: + cursor = [NSCursor resizeRightCursor]; + break; + case RCTCursorResizeUp: + cursor = [NSCursor resizeUpCursor]; + break; + case RCTCursorResizeUpDown: + cursor = [NSCursor resizeUpDownCursor]; + break; + } + + return cursor; +} + +@end diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index 64b6b6a06029aa..483e30d18d2ebe 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -12,6 +12,10 @@ #import // TODO(OSS Candidate ISS#2710739) #import +#if TARGET_OS_OSX // TODO(macOS GH#774) +#import +#endif // TODO(macOS GH#774) + #if !TARGET_OS_OSX // TODO(macOS GH#774) extern const UIAccessibilityTraits SwitchAccessibilityTrait; #endif // TODO(macOS GH#774) @@ -124,6 +128,7 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; /** * macOS Properties */ +@property (nonatomic, assign) RCTCursor cursor; @property (nonatomic, assign) CATransform3D transform3D; diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index f1c31d64bf929d..5fd368dfefeaa2 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -742,16 +742,16 @@ - (void)viewBoundsChanged:(NSNotification*)__unused inNotif // the mouseExited: event does not get called on the view where mouseEntered: was previously called. // This creates an unnatural pairing of mouse enter and exit events and can cause problems. // We therefore explicitly check for this here and handle them by calling the appropriate callbacks. - + if (!_hasMouseOver && self.onMouseEnter) { NSPoint locationInWindow = [[self window] mouseLocationOutsideOfEventStream]; NSPoint locationInView = [self convertPoint:locationInWindow fromView:nil]; - + if (NSPointInRect(locationInView, [self bounds])) { _hasMouseOver = YES; - + [self sendMouseEventWithBlock:self.onMouseEnter locationInfo:[self locationInfoFromDraggingLocation:locationInWindow] modifierFlags:0 @@ -762,11 +762,11 @@ - (void)viewBoundsChanged:(NSNotification*)__unused inNotif { NSPoint locationInWindow = [[self window] mouseLocationOutsideOfEventStream]; NSPoint locationInView = [self convertPoint:locationInWindow fromView:nil]; - + if (!NSPointInRect(locationInView, [self bounds])) { _hasMouseOver = NO; - + [self sendMouseEventWithBlock:self.onMouseLeave locationInfo:[self locationInfoFromDraggingLocation:locationInWindow] modifierFlags:0 @@ -1365,6 +1365,15 @@ - (void)drawFocusRingMask #pragma mark - macOS Event Handler #if TARGET_OS_OSX +- (void)resetCursorRects +{ + [self discardCursorRects]; + NSCursor *cursor = [RCTConvert NSCursor:self.cursor]; + if (cursor) { + [self addCursorRect:self.bounds cursor:cursor]; + } +} + - (void)setOnDoubleClick:(RCTDirectEventBlock)block { if (_onDoubleClick != block) { @@ -1411,7 +1420,7 @@ - (void)updateTrackingAreas if (_trackingArea) { [self removeTrackingArea:_trackingArea]; } - + if (self.onMouseEnter || self.onMouseLeave) { _trackingArea = [[NSTrackingArea alloc] initWithRect:self.bounds options:NSTrackingActiveAlways|NSTrackingMouseEnteredAndExited @@ -1419,7 +1428,7 @@ - (void)updateTrackingAreas userInfo:nil]; [self addTrackingArea:_trackingArea]; } - + [super updateTrackingAreas]; } @@ -1445,7 +1454,7 @@ - (NSDictionary*)locationInfoFromEvent:(NSEvent*)event { NSPoint locationInWindow = event.locationInWindow; NSPoint locationInView = [self convertPoint:locationInWindow fromView:nil]; - + return @{@"screenX": @(locationInWindow.x), @"screenY": @(locationInWindow.y), @"clientX": @(locationInView.x), @@ -1476,15 +1485,15 @@ - (void)sendMouseEventWithBlock:(RCTDirectEventBlock)block if (modifierFlags & NSEventModifierFlagCommand) { body[@"metaKey"] = @YES; } - + if (locationInfo) { [body addEntriesFromDictionary:locationInfo]; } - + if (additionalData) { [body addEntriesFromDictionary:additionalData]; } - + block(body); } @@ -1510,7 +1519,7 @@ - (NSDictionary*)dataTransferInfoFromPasteboard:(NSPasteboard*)pasteboard MIMETypeString = (__bridge_transfer NSString *)MIMEType; } } - + NSNumber *fileSizeValue = nil; NSError *fileSizeError = nil; BOOL success = [fileURL getResourceValue:&fileSizeValue @@ -1532,11 +1541,11 @@ - (NSDictionary*)dataTransferInfoFromPasteboard:(NSPasteboard*)pasteboard @"width": RCTNullIfNil(width), @"height": RCTNullIfNil(height) }]; - + [items addObject:@{@"kind": @"file", @"type": RCTNullIfNil(MIMETypeString), }]; - + [types addObject:RCTNullIfNil(MIMETypeString)]; } } @@ -1569,7 +1578,7 @@ - (NSDictionary*)dataTransferInfoFromPasteboard:(NSPasteboard*)pasteboard - (NSDictionary*)locationInfoFromDraggingLocation:(NSPoint)locationInWindow { NSPoint locationInView = [self convertPoint:locationInWindow fromView:nil]; - + return @{@"screenX": @(locationInWindow.x), @"screenY": @(locationInWindow.y), @"clientX": @(locationInView.x), @@ -1581,7 +1590,7 @@ - (NSDragOperation)draggingEntered:(id )sender { NSPasteboard *pboard = sender.draggingPasteboard; NSDragOperation sourceDragMask = sender.draggingSourceOperationMask; - + [self sendMouseEventWithBlock:self.onDragEnter locationInfo:[self locationInfoFromDraggingLocation:sender.draggingLocation] modifierFlags:0 diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index f360aab40138a0..c1a1b424505a53 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -21,6 +21,10 @@ #import "RCTView.h" #import "UIView+React.h" +#if TARGET_OS_OSX // TODO(macOS GH#774) +#import "RCTCursor.h" +#endif // TODO(macOS GH774) + #if !TARGET_OS_OSX // TODO(macOS GH#774) @implementation RCTConvert (UIAccessibilityTraits) @@ -471,6 +475,7 @@ - (RCTShadowView *)shadowView #if TARGET_OS_OSX // [TODO(macOS GH#774) #pragma mark - macOS properties +RCT_EXPORT_VIEW_PROPERTY(cursor, RCTCursor) RCT_EXPORT_VIEW_PROPERTY(onDoubleClick, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onClick, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onMouseEnter, RCTDirectEventBlock) diff --git a/packages/rn-tester/js/examples/Text/TextExample.ios.js b/packages/rn-tester/js/examples/Text/TextExample.ios.js index 132d390b25fc26..a7a7bdc76e42f2 100644 --- a/packages/rn-tester/js/examples/Text/TextExample.ios.js +++ b/packages/rn-tester/js/examples/Text/TextExample.ios.js @@ -1244,5 +1244,29 @@ exports.examples = [ ); }, + }, + { + title: 'Cursor', + render: function(): React.Node { + return ( + + + This text has pointer cursor. + + + ); + }, }, + { + title: 'Cursor virtual text', + render: function(): React.Node { + return ( + + + This text has regular cursor. This text has pointer cursor. + + + ); + }, + }, ]; diff --git a/packages/rn-tester/js/examples/View/ViewExample.js b/packages/rn-tester/js/examples/View/ViewExample.js index 528e4ef91a2fc7..251605db0c646f 100644 --- a/packages/rn-tester/js/examples/View/ViewExample.js +++ b/packages/rn-tester/js/examples/View/ViewExample.js @@ -47,6 +47,66 @@ exports.examples = [ ); }, }, + { + title: 'Cursor', + render(): React.Node { + return ( + <> + + auto + + + default + + + context-menu + + + pointer + + + text + + + vertical-text + + + alias + + + copy + + + not-allowed + + + grab + + + grabbing + + + col-resize + + + row-resize + + + n-resize + + + e-resize + + + s-resize + + + w-resize + + + ); + }, + }, { title: 'Padding/Margin', render(): React.Node {