Skip to content

Commit

Permalink
Implement cursor style prop for iOS/visionOS
Browse files Browse the repository at this point in the history
  • Loading branch information
Saadnajmi committed Feb 26, 2024
1 parent 2a774a0 commit ea647ee
Show file tree
Hide file tree
Showing 20 changed files with 625 additions and 174 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
borderTopLeftRadius: true,
borderTopRightRadius: true,
borderTopStartRadius: true,
cursor: true,
cursor: true, // [macOS] [visionOS]
opacity: true,
pointerEvents: true,

Expand Down
26 changes: 26 additions & 0 deletions packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@ export type DimensionValue =
type AnimatableNumericValue = number | Animated.AnimatedNode;
type AnimatableStringValue = string | Animated.AnimatedNode;

// [macOS
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';
// macOS]

/**
* Flex Prop Types
* @see https://reactnative.dev/docs/flexbox
Expand Down Expand Up @@ -273,6 +297,7 @@ export interface ViewStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
* Controls whether the View can be the target of touch events.
*/
pointerEvents?: 'box-none' | 'none' | 'box-only' | 'auto' | undefined;
cursor?: CursorValue | undefined;
}

export type FontVariant =
Expand Down Expand Up @@ -363,4 +388,5 @@ export interface ImageStyle extends FlexStyle, ShadowStyleIOS, TransformsStyle {
tintColor?: ColorValue | undefined;
opacity?: AnimatableNumericValue | undefined;
objectFit?: 'cover' | 'contain' | 'fill' | 'scale-down' | undefined;
cursor?: CursorValue | undefined;
}
30 changes: 15 additions & 15 deletions packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,20 @@ import type {
} from './private/_StyleSheetTypesOverrides';
import type {____TransformStyle_Internal} from './private/_TransformStyle';

declare export opaque type NativeColorValue;
export type ____ColorValue_Internal = null | string | number | NativeColorValue;
export type ColorArrayValue = null | $ReadOnlyArray<____ColorValue_Internal>;
export type PointValue = {
x: number,
y: number,
};
export type EdgeInsetsValue = {
top: number,
left: number,
right: number,
bottom: number,
};

// [macOS
export type CursorValue = ?(
| 'alias'
Expand All @@ -45,20 +59,6 @@ export type CursorValue = ?(
);
// macOS]

declare export opaque type NativeColorValue;
export type ____ColorValue_Internal = null | string | number | NativeColorValue;
export type ColorArrayValue = null | $ReadOnlyArray<____ColorValue_Internal>;
export type PointValue = {
x: number,
y: number,
};
export type EdgeInsetsValue = {
top: number,
left: number,
right: number,
bottom: number,
};

export type DimensionValue = number | string | 'auto' | AnimatedNode | null;
export type AnimatableNumericValue = number | AnimatedNode;

Expand Down Expand Up @@ -752,7 +752,7 @@ export type ____ViewStyle_InternalCore = $ReadOnly<{
opacity?: AnimatableNumericValue,
elevation?: number,
pointerEvents?: 'auto' | 'none' | 'box-none' | 'box-only',
cursor?: CursorValue, // [macOS]
cursor?: CursorValue, // [macOS][visionOS]
}>;

export type ____ViewStyle_Internal = $ReadOnly<{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
*/

#import <React/RCTBaseTextViewManager.h>
#if TARGET_OS_OSX // [macOS
#import <React/RCTCursor.h>
#endif // macOS]
#import <React/RCTCursor.h> // [macOS]

@implementation RCTBaseTextViewManager

Expand Down
5 changes: 1 addition & 4 deletions packages/react-native/Libraries/Text/RCTTextAttributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,12 @@

#import <React/RCTUIKit.h> // [macOS]

#import <React/RCTCursor.h> // [macOS]
#import <React/RCTDynamicTypeRamp.h>
#import <React/RCTTextDecorationLineType.h>

#import "RCTTextTransform.h"

#if TARGET_OS_OSX // [macOS
#import <React/RCTCursor.h>
#endif // macOS]

NS_ASSUME_NONNULL_BEGIN

extern NSString *const RCTTextAttributesIsHighlightedAttributeName;
Expand Down
79 changes: 74 additions & 5 deletions packages/react-native/Libraries/Text/RCTTextAttributes.mm
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,85 @@
#import <React/RCTTextAttributes.h>

#import <React/RCTAssert.h>
#import <React/RCTCursor.h> // [macOS]
#import <React/RCTFont.h>
#import <React/RCTLog.h>

#if TARGET_OS_OSX // [macOS
#import <React/RCTCursor.h>
#endif // macOS]

NSString *const RCTTextAttributesIsHighlightedAttributeName = @"RCTTextAttributesIsHighlightedAttributeName";
NSString *const RCTTextAttributesTagAttributeName = @"RCTTextAttributesTagAttributeName";

#if TARGET_OS_OSX // [macOS
// Duplicate this function here as RCTTextAttributes doesn't depend on RCTView
static NSCursor *NSCursorFromRCTCursor(RCTCursor cursor)
{
NSCursor *platformCursor;

switch (cursor) {
case RCTCursorAlias:
platformCursor = [NSCursor dragLinkCursor];
break;
case RCTCursorAuto:
platformCursor = [NSCursor arrowCursor];
break;
case RCTCursorColumnResize:
platformCursor = [NSCursor resizeLeftRightCursor];
break;
case RCTCursorContextualMenu:
platformCursor = [NSCursor contextualMenuCursor];
break;
case RCTCursorCopy:
platformCursor = [NSCursor dragCopyCursor];
break;
case RCTCursorCrosshair:
platformCursor = [NSCursor crosshairCursor];
break;
case RCTCursorDefault:
platformCursor = [NSCursor arrowCursor];
break;
case RCTCursorDisappearingItem:
platformCursor = [NSCursor disappearingItemCursor];
break;
case RCTCursorEastResize:
platformCursor = [NSCursor resizeRightCursor];
break;
case RCTCursorGrab:
platformCursor = [NSCursor openHandCursor];
break;
case RCTCursorGrabbing:
platformCursor = [NSCursor closedHandCursor];
break;
case RCTCursorNorthResize:
platformCursor = [NSCursor resizeUpCursor];
break;
case RCTCursorNoDrop:
platformCursor = [NSCursor operationNotAllowedCursor];
break;
case RCTCursorNotAllowed:
platformCursor = [NSCursor operationNotAllowedCursor];
break;
case RCTCursorPointer:
platformCursor = [NSCursor pointingHandCursor];
break;
case RCTCursorRowResize:
platformCursor = [NSCursor resizeUpDownCursor];
break;
case RCTCursorSouthResize:
platformCursor = [NSCursor resizeDownCursor];
break;
case RCTCursorText:
platformCursor = [NSCursor IBeamCursor];
break;
case RCTCursorVerticalText:
platformCursor = [NSCursor IBeamCursorForVerticalLayout];
break;
case RCTCursorWestResize:
platformCursor = [NSCursor resizeLeftCursor];
break;
}
return platformCursor;
}
#endif // macOS]

@implementation RCTTextAttributes

// [macOS
Expand Down Expand Up @@ -235,7 +304,7 @@ - (NSParagraphStyle *)effectiveParagraphStyle

#if TARGET_OS_OSX // [macOS
if (_cursor != RCTCursorAuto) {
attributes[NSCursorAttributeName] = [RCTConvert NSCursor:_cursor];
attributes[NSCursorAttributeName] = NSCursorFromRCTCursor(_cursor);
}
#endif // macOS]

Expand Down
3 changes: 3 additions & 0 deletions packages/react-native/React/Base/RCTConvert.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#import <React/RCTAnimationType.h>
#import <React/RCTBorderCurve.h>
#import <React/RCTBorderStyle.h>
#import <React/RCTCursor.h> // [macOS] [visionOS]
#import <React/RCTDefines.h>
#import <React/RCTLog.h>
#import <React/RCTPointerEvents.h>
Expand Down Expand Up @@ -84,6 +85,8 @@ typedef NSURL RCTFileURL;
#endif
#endif // [macOS]

+ (RCTCursor)RCTCursor:(id)json; // [macOS] [visionOS]

#if TARGET_OS_OSX // [macOS
+ (NSTextCheckingTypes)NSTextCheckingTypes:(id)json;
#endif // macOS]
Expand Down
33 changes: 32 additions & 1 deletion packages/react-native/React/Base/RCTConvert.m
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,38 @@ + (UIKeyboardType)UIKeyboardType:(id)json RCT_DYNAMIC
}),
UIBarStyleDefault,
integerValue)
#else // [macOS
#endif // [macOS]

// [macOS [visionOS]
RCT_ENUM_CONVERTER(
RCTCursor,
(@{
@"alias" : @(RCTCursorAlias),
@"auto" : @(RCTCursorAuto),
@"col-resize" : @(RCTCursorColumnResize),
@"context-menu" : @(RCTCursorContextualMenu),
@"copy" : @(RCTCursorCopy),
@"crosshair" : @(RCTCursorCrosshair),
@"default" : @(RCTCursorDefault),
@"disappearing-item" : @(RCTCursorDisappearingItem),
@"e-resize" : @(RCTCursorEastResize),
@"grab" : @(RCTCursorGrab),
@"grabbing" : @(RCTCursorGrabbing),
@"n-resize" : @(RCTCursorNorthResize),
@"no-drop" : @(RCTCursorNoDrop),
@"not-allowed" : @(RCTCursorNotAllowed),
@"pointer" : @(RCTCursorPointer),
@"row-resize" : @(RCTCursorRowResize),
@"s-resize" : @(RCTCursorSouthResize),
@"text" : @(RCTCursorText),
@"vertical-text" : @(RCTCursorVerticalText),
@"w-resize" : @(RCTCursorWestResize),
}),
RCTCursorAuto,
integerValue)
// macOS] [visionOS]

#if TARGET_OS_OSX // [macOS
RCT_MULTI_ENUM_CONVERTER(NSTextCheckingTypes, (@{
@"ortography": @(NSTextCheckingTypeOrthography),
@"spelling": @(NSTextCheckingTypeSpelling),
Expand Down
Loading

0 comments on commit ea647ee

Please sign in to comment.