diff --git a/Libraries/Components/Pressable/Pressable.js b/Libraries/Components/Pressable/Pressable.js index 29f99fdae4f560..5a7566e106fe25 100644 --- a/Libraries/Components/Pressable/Pressable.js +++ b/Libraries/Components/Pressable/Pressable.js @@ -196,12 +196,66 @@ type Props = $ReadOnly<{| */ validKeysUp?: ?Array, + /** + * Specifies whether the view should receive the mouse down event when the + * containing window is in the background. + * + * @platform macos + */ acceptsFirstMouse?: ?boolean, + + /** + * Specifies whether clicking and dragging the view can move the window. This is useful + * to disable in Button like components like Pressable where mouse the user should still + * be able to click and drag off the view to cancel the click without accidentally moving the window. + * + * @platform macos + */ + mouseDownCanMoveWindow?: ?boolean, + + /** + * Specifies whether system focus ring should be drawn when the view has keyboard focus. + * + * @platform macos + */ enableFocusRing?: ?boolean, + + /** + * Specifies the Tooltip for the Pressable. + * @platform macos + */ tooltip?: ?string, + + /** + * Fired when a file is dragged into the Pressable via the mouse. + * + * @platform macos + */ onDragEnter?: (event: MouseEvent) => void, + + /** + * Fired when a file is dragged out of the Pressable via the mouse. + * + * @platform macos + */ onDragLeave?: (event: MouseEvent) => void, + + /** + * Fired when a file is dropped on the Pressable via the mouse. + * + * @platform macos + */ onDrop?: (event: MouseEvent) => void, + + /** + * The types of dragged files that the Pressable will accept. + * + * Possible values for `draggedTypes` are: + * + * - `'fileUrl'` + * + * @platform macos + */ draggedTypes?: ?DraggedTypesType, // macOS] @@ -250,8 +304,6 @@ type Props = $ReadOnly<{| * LTI update could not be added via codemod */ function Pressable(props: Props, forwardedRef): React.Node { const { - acceptsFirstMouse, // [macOS] - enableFocusRing, // [macOS] accessible, accessibilityState, 'aria-live': ariaLive, @@ -282,6 +334,9 @@ function Pressable(props: Props, forwardedRef): React.Node { onBlur, onKeyDown, onKeyUp, + acceptsFirstMouse, + mouseDownCanMoveWindow, + enableFocusRing, // macOS] pressRetentionOffset, style, @@ -322,7 +377,8 @@ function Pressable(props: Props, forwardedRef): React.Node { const restPropsWithDefaults: React.ElementConfig = { ...restProps, ...android_rippleConfig?.viewProps, - acceptsFirstMouse: acceptsFirstMouse !== false && !disabled, // [macOS + acceptsFirstMouse: acceptsFirstMouse !== false && !disabled, // [macOS] + mouseDownCanMoveWindow: false, // [macOS] enableFocusRing: enableFocusRing !== false && !disabled, accessible: accessible !== false, accessibilityViewIsModal: diff --git a/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap b/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap index 8e571950980012..5787caa7154bc6 100644 --- a/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap +++ b/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap @@ -24,6 +24,7 @@ exports[` should render as expected: should deep render when mocked collapsable={false} enableFocusRing={true} focusable={true} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -64,6 +65,7 @@ exports[` should render as expected: should deep render when not mo collapsable={false} enableFocusRing={true} focusable={true} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -116,6 +118,7 @@ exports[` should be disabled when disabled is true: collapsable={false} enableFocusRing={false} focusable={false} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -156,6 +159,7 @@ exports[` should be disabled when disabled is true: collapsable={false} enableFocusRing={false} focusable={false} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -212,6 +216,7 @@ exports[` should be disable collapsable={false} enableFocusRing={false} focusable={false} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -252,6 +257,7 @@ exports[` should be disable collapsable={false} enableFocusRing={false} focusable={false} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -310,6 +316,7 @@ exports[` shou collapsable={false} enableFocusRing={false} focusable={false} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -350,6 +357,7 @@ exports[` shou collapsable={false} enableFocusRing={false} focusable={false} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -416,6 +424,7 @@ exports[` sh collapsable={false} enableFocusRing={false} focusable={false} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} @@ -456,6 +465,7 @@ exports[` sh collapsable={false} enableFocusRing={false} focusable={false} + mouseDownCanMoveWindow={false} onBlur={[Function]} onClick={[Function]} onFocus={[Function]} diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index fd080347102970..64e6adc28ea3fa 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -37,6 +37,7 @@ const UIView = { style: ReactNativeStyleAttributes, // [macOS acceptsFirstMouse: true, + mouseDownCanMoveWindow: true, enableFocusRing: true, focusable: true, onMouseEnter: true, diff --git a/Libraries/Components/View/ViewPropTypes.d.ts b/Libraries/Components/View/ViewPropTypes.d.ts index 36af4b64b7a2a0..56cfe79a45eda9 100644 --- a/Libraries/Components/View/ViewPropTypes.d.ts +++ b/Libraries/Components/View/ViewPropTypes.d.ts @@ -173,6 +173,7 @@ export type DraggedTypesType = DraggedType | DraggedType[]; export interface ViewPropsMacOS { acceptsFirstMouse?: boolean | undefined; + mouseDownCanMoveWindow?: boolean | undefined; enableFocusRing?: boolean | undefined; onMouseEnter?: ((event: MouseEvent) => void) | undefined; onMouseLeave?: ((event: MouseEvent) => void) | undefined; diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 8213299119cb85..f05c0981431579 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -474,14 +474,14 @@ type IOSViewProps = $ReadOnly<{| // [macOS type MacOSViewProps = $ReadOnly<{| /** - * Fired when a dragged element enters a valid drop target + * Fired when a file is dragged into the view via the mouse. * * @platform macos */ onDragEnter?: (event: MouseEvent) => void, /** - * Fired when a dragged element leaves a valid drop target + * Fired when a file is dragged out of the view via the mouse. * * @platform macos */ @@ -509,14 +509,23 @@ type MacOSViewProps = $ReadOnly<{| acceptsFirstMouse?: ?boolean, /** - * Specifies whether focus ring should be drawn when the view has the first responder status. + * Specifies whether clicking and dragging the view can move the window. This is useful + * to disable in Button like components like Pressable where mouse the user should still + * be able to click and drag off the view to cancel the click without accidentally moving the window. + * + * @platform macos + */ + mouseDownCanMoveWindow?: ?boolean, + + /** + * Specifies whether system focus ring should be drawn when the view has keyboard focus. * * @platform macos */ enableFocusRing?: ?boolean, /** - * Enables Drag'n'Drop Support for certain types of dragged types + * The types of dragged files that the view will accept. * * Possible values for `draggedTypes` are: * diff --git a/Libraries/NativeComponent/BaseViewConfig.macos.js b/Libraries/NativeComponent/BaseViewConfig.macos.js index c11630c41a58ba..3040f72245b909 100644 --- a/Libraries/NativeComponent/BaseViewConfig.macos.js +++ b/Libraries/NativeComponent/BaseViewConfig.macos.js @@ -54,6 +54,7 @@ const validAttributesForNonEventProps = { tooltip: true, validKeysDown: true, validKeysUp: true, + mouseDownCanMoveWindow: true, }; // Props for bubbling and direct events diff --git a/React/Base/RCTUIKit.h b/React/Base/RCTUIKit.h index de7eb1f23202f5..79d4ffbe139f29 100644 --- a/React/Base/RCTUIKit.h +++ b/React/Base/RCTUIKit.h @@ -405,6 +405,9 @@ CGPathRef UIBezierPathCreateCGPathRef(UIBezierPath *path); * containing window is in the background. */ @property (nonatomic, assign) BOOL acceptsFirstMouse; + +@property (nonatomic, assign) BOOL mouseDownCanMoveWindow; + /** * Specifies whether the view participates in the key view loop as user tabs through different controls * This is equivalent to acceptsFirstResponder on mac OS. diff --git a/React/Base/macOS/RCTUIKit.m b/React/Base/macOS/RCTUIKit.m index 1c5fba8c651dc7..8745a182b8fd48 100644 --- a/React/Base/macOS/RCTUIKit.m +++ b/React/Base/macOS/RCTUIKit.m @@ -215,6 +215,7 @@ @implementation RCTUIView NSColor *_backgroundColor; BOOL _clipsToBounds; BOOL _userInteractionEnabled; + BOOL _mouseDownCanMoveWindow; } + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key @@ -243,6 +244,7 @@ @implementation RCTUIView self.wantsLayer = YES; self->_userInteractionEnabled = YES; self->_enableFocusRing = YES; + self->_mouseDownCanMoveWindow = YES; } return self; } @@ -288,6 +290,14 @@ - (void)viewDidMoveToWindow [self didMoveToWindow]; } +- (BOOL)mouseDownCanMoveWindow{ + return _mouseDownCanMoveWindow; +} + +- (void)setMouseDownCanMoveWindow:(BOOL)mouseDownCanMoveWindow{ + _mouseDownCanMoveWindow = mouseDownCanMoveWindow; +} + - (BOOL)isFlipped { return YES; diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index a15d2a9eb67f37..4046d374cef5a0 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -133,6 +133,7 @@ @implementation RCTView { #if TARGET_OS_OSX // [macOS NSTrackingArea *_trackingArea; BOOL _hasMouseOver; + BOOL _mouseDownCanMoveWindow; #endif // macOS] NSMutableDictionary *accessibilityActionsNameMap; NSMutableDictionary *accessibilityActionsLabelMap; @@ -172,6 +173,7 @@ - (instancetype)initWithFrame:(CGRect)frame #if TARGET_OS_OSX // [macOS _transform3D = CATransform3DIdentity; _shadowColor = nil; + _mouseDownCanMoveWindow = YES; #endif // macOS] _backgroundColor = super.backgroundColor; @@ -1495,6 +1497,15 @@ - (void)mouseExited:(NSEvent *)event additionalData:nil]; } +- (BOOL)mouseDownCanMoveWindow{ + return _mouseDownCanMoveWindow; +} + +- (void)setMouseDownCanMoveWindow:(BOOL)mouseDownCanMoveWindow{ + _mouseDownCanMoveWindow = mouseDownCanMoveWindow; +} + + - (NSDictionary*)locationInfoFromEvent:(NSEvent*)event { NSPoint locationInWindow = event.locationInWindow; diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index a7889608d55a88..9b7a97ebcb039b 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -417,12 +417,16 @@ - (RCTShadowView *)shadowView view.acceptsFirstMouse = json ? [RCTConvert BOOL:json] : defaultView.acceptsFirstMouse; } } + +RCT_EXPORT_VIEW_PROPERTY(mouseDownCanMoveWindow, BOOL) + RCT_CUSTOM_VIEW_PROPERTY(focusable, BOOL, RCTView) { if ([view respondsToSelector:@selector(setFocusable:)]) { view.focusable = json ? [RCTConvert BOOL:json] : defaultView.focusable; } } + RCT_CUSTOM_VIEW_PROPERTY(enableFocusRing, BOOL, RCTView) { if ([view respondsToSelector:@selector(setEnableFocusRing:)]) { @@ -511,6 +515,7 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTDirectEventBlock) // macOS keyboard events RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray) RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray) + #endif // macOS] #pragma mark - ShadowView properties diff --git a/packages/rn-tester/Podfile.lock b/packages/rn-tester/Podfile.lock index 4f7f49518ebf40..26cc7d60fc2c2d 100644 --- a/packages/rn-tester/Podfile.lock +++ b/packages/rn-tester/Podfile.lock @@ -534,4 +534,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 3957102092bb49bb662ae384e29ce5c5a237f6a6 -COCOAPODS: 1.12.1 +COCOAPODS: 1.12.0