diff --git a/change/react-native-windows-2020-08-14-09-57-33-fix-touchable-mouse.json b/change/react-native-windows-2020-08-14-09-57-33-fix-touchable-mouse.json new file mode 100644 index 00000000000..145678c97f7 --- /dev/null +++ b/change/react-native-windows-2020-08-14-09-57-33-fix-touchable-mouse.json @@ -0,0 +1,8 @@ +{ + "type": "prerelease", + "comment": "Restore Previous Behavior Allowing onMouseEnter and onMouseLeave on Touchables", + "packageName": "react-native-windows", + "email": "ngerlem@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-08-14T16:57:33.938Z" +} diff --git a/packages/E2ETest/wdio/test/VisitAllPages.spec.ts b/packages/E2ETest/wdio/test/VisitAllPages.spec.ts index a05a184ea8e..b6cf61ed734 100644 --- a/packages/E2ETest/wdio/test/VisitAllPages.spec.ts +++ b/packages/E2ETest/wdio/test/VisitAllPages.spec.ts @@ -52,6 +52,7 @@ let pages = [ 'Layout Events', 'Linking', 'Layout - Flexbox', + 'Mouse Events', 'Native Animated Example', 'PanResponder Sample', 'PlatformColor', diff --git a/packages/playground/windows/playground/MainPage.xaml b/packages/playground/windows/playground/MainPage.xaml index d416bdc9501..68e01a6bd20 100644 --- a/packages/playground/windows/playground/MainPage.xaml +++ b/packages/playground/windows/playground/MainPage.xaml @@ -69,7 +69,6 @@ - diff --git a/vnext/.flowconfig b/vnext/.flowconfig index a3c11493049..77a452679bf 100644 --- a/vnext/.flowconfig +++ b/vnext/.flowconfig @@ -29,6 +29,8 @@ /Libraries/Network/RCTNetworking.js /Libraries/NewAppScreen/components/DebugInstructions.js /Libraries/NewAppScreen/components/ReloadInstructions.js +/Libraries/Pressability/Pressability.js +/Libraries/Types/CoreEventTypes.js /RNTester/js/components/ListExampleShared.js /RNTester/js/components/RNTesterExampleList.js /RNTester/js/examples/ScrollView/ScrollViewExample.js diff --git a/vnext/overrides.json b/vnext/overrides.json index a52c40c9acb..3675e3c5d32 100644 --- a/vnext/overrides.json +++ b/vnext/overrides.json @@ -437,7 +437,7 @@ }, { "type": "patch", - "file": "src/Libraries/Types/CoreEventTypes.js", + "file": "src/Libraries/Types/CoreEventTypes.windows.js", "baseFile": "Libraries/Types/CoreEventTypes.js", "baseVersion": "0.0.0-d8e6c4578", "baseHash": "83b203d547d9bdc57a8f3346ecee6f6e34b25f5d", diff --git a/vnext/src/Libraries/Components/Touchable/TouchableHighlight.windows.js b/vnext/src/Libraries/Components/Touchable/TouchableHighlight.windows.js index 2588a12cf72..50abe262b66 100644 --- a/vnext/src/Libraries/Components/Touchable/TouchableHighlight.windows.js +++ b/vnext/src/Libraries/Components/Touchable/TouchableHighlight.windows.js @@ -176,6 +176,8 @@ class TouchableHighlight extends React.Component { delayPressOut: this.props.delayPressOut, pressRectOffset: this.props.pressRetentionOffset, android_disableSound: this.props.touchSoundDisabled, + onMouseEnter: this.props.onMouseEnter, // [Windows] + onMouseLeave: this.props.onMouseLeave, // [Windows] onBlur: event => { if (Platform.isTV) { this._hideUnderlay(); diff --git a/vnext/src/Libraries/Components/Touchable/TouchableOpacity.windows.js b/vnext/src/Libraries/Components/Touchable/TouchableOpacity.windows.js index 33467a804db..3614afedb2e 100644 --- a/vnext/src/Libraries/Components/Touchable/TouchableOpacity.windows.js +++ b/vnext/src/Libraries/Components/Touchable/TouchableOpacity.windows.js @@ -148,6 +148,8 @@ class TouchableOpacity extends React.Component { delayPressIn: this.props.delayPressIn, delayPressOut: this.props.delayPressOut, pressRectOffset: this.props.pressRetentionOffset, + onMouseEnter: this.props.onMouseEnter, // [Windows] + onMouseLeave: this.props.onMouseLeave, // [Windows] onBlur: event => { if (Platform.isTV) { this._opacityInactive(250); diff --git a/vnext/src/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js b/vnext/src/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js index bb375e82310..fd8df17b1c2 100644 --- a/vnext/src/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js +++ b/vnext/src/Libraries/Components/Touchable/TouchableWithoutFeedback.windows.js @@ -27,6 +27,7 @@ import type { BlurEvent, FocusEvent, LayoutEvent, + MouseEvent, // [Windows] PressEvent, } from '../../Types/CoreEventTypes'; import Platform from '../../Utilities/Platform'; @@ -70,8 +71,8 @@ type Props = $ReadOnly<{| accessibilityPosInSet?: ?number, // [Windows] accessibilitySetSize?: ?number, // [Windows] onAccessibilityTap?: ?() => void, // [Windows] - onMouseEnter?: ?(event: SyntheticEvent<{}>) => void, // [Windows] - onMouseLeave?: ?(event: SyntheticEvent<{}>) => void, // [Windows] + onMouseEnter?: ?(event: MouseEvent) => void, // [Windows] + onMouseLeave?: ?(event: MouseEvent) => void, // [Windows] tabIndex?: ?number, // [Windows] tooltip?: ?Stringish, // [Windows] |}>; @@ -206,6 +207,8 @@ function createPressabilityConfig(props: Props): PressabilityConfig { onPress: props.onPress, onPressIn: props.onPressIn, onPressOut: props.onPressOut, + onMouseEnter: props.onMouseEnter, // [Windows] + onMouseLeave: props.onMouseLeave, // [Windows] }; } diff --git a/vnext/src/Libraries/Components/View/ViewPropTypes.windows.js b/vnext/src/Libraries/Components/View/ViewPropTypes.windows.js index a1c23fa94ce..5fa36a42259 100644 --- a/vnext/src/Libraries/Components/View/ViewPropTypes.windows.js +++ b/vnext/src/Libraries/Components/View/ViewPropTypes.windows.js @@ -435,8 +435,8 @@ type WindowsViewProps = $ReadOnly<{| onFocus?: ?(event: FocusEvent) => mixed, onBlur?: ?(event: FocusEvent) => mixed, - onMouseLeave?: ?(event: SyntheticEvent<{}>) => mixed, - onMouseEnter?: ?(event: SyntheticEvent<{}>) => mixed, + onMouseLeave?: ?(event: MouseEvent) => mixed, + onMouseEnter?: ?(event: MouseEvent) => mixed, |}>; // Windows] diff --git a/vnext/src/Libraries/Pressability/Pressability.windows.js b/vnext/src/Libraries/Pressability/Pressability.windows.js index 8c40816b89e..23582aebf5a 100644 --- a/vnext/src/Libraries/Pressability/Pressability.windows.js +++ b/vnext/src/Libraries/Pressability/Pressability.windows.js @@ -146,6 +146,22 @@ export type PressabilityConfig = $ReadOnly<{| * @deprecated */ onStartShouldSetResponder_DEPRECATED?: ?() => boolean, + + // [Windows + /** + * Raw handler for onMouseEnter that will be preferred if set over hover + * events. This is to preserve compatibility with pre-0.62 behavior which + * allowed attaching mouse event handlers to Touchables + */ + onMouseEnter?: ?(event: MouseEvent) => mixed, + + /** + * Raw handler for onMouseLeave that will be preferred if set over hover + * events. This is to preserve compatibility with pre-0.62 behavior which + * allowed attaching mouse event handlers to Touchables + */ + onMouseLeave?: ?(event: MouseEvent) => mixed, + // Windows] |}>; export type EventHandlers = $ReadOnly<{| @@ -562,6 +578,12 @@ export default class Pressability { ? null : { onMouseEnter: (event: MouseEvent): void => { + // [Windows Add attached raw mouse event handler for compat + if (this._config.onMouseEnter) { + this._config.onMouseEnter(event); + } + // Windows] + if (isHoverEnabled()) { this._isHovered = true; this._cancelHoverOutDelayTimeout(); @@ -582,6 +604,12 @@ export default class Pressability { }, onMouseLeave: (event: MouseEvent): void => { + // [Windows Add attached raw mouse event handler for compat + if (this._config.onMouseLeave) { + this._config.onMouseLeave(event); + } + // Windows] + if (this._isHovered) { this._isHovered = false; this._cancelHoverInDelayTimeout(); diff --git a/vnext/src/Libraries/Types/CoreEventTypes.js b/vnext/src/Libraries/Types/CoreEventTypes.windows.js similarity index 86% rename from vnext/src/Libraries/Types/CoreEventTypes.js rename to vnext/src/Libraries/Types/CoreEventTypes.windows.js index 3758e8356fc..cdb4d305025 100644 --- a/vnext/src/Libraries/Types/CoreEventTypes.js +++ b/vnext/src/Libraries/Types/CoreEventTypes.windows.js @@ -151,15 +151,32 @@ export type FocusEvent = SyntheticEvent< |}>, >; +// [Windows Mouse events on Windows don't match up with the version in core +// introduced for react-native-web. Replace typings with our values to catch +// anything dependent on react-native-web specific values export type MouseEvent = SyntheticEvent< $ReadOnly<{| - clientX: number, - clientY: number, + target: number, + identifier: number, pageX: number, pageY: number, + locationX: number, + locationY: number, timestamp: number, + pointerType: string, + force: number, + isLeftButton: boolean, + isRightButton: boolean, + isMiddleButton: boolean, + isBarrelButtonPressed: boolean, + isHorizontalScrollWheel: boolean, + isEraser: boolean, + shiftKey: boolean, + ctrlKey: boolean, + altKey: boolean, |}>, >; +// Windows] // [Windows export type KeyEvent = SyntheticEvent< diff --git a/packages/playground/Samples/mouse.tsx b/vnext/src/RNTester/js/examples-win/Mouse/MouseExample.windows.js similarity index 88% rename from packages/playground/Samples/mouse.tsx rename to vnext/src/RNTester/js/examples-win/Mouse/MouseExample.windows.js index 0c5d4bdf403..5ff0b74d660 100644 --- a/packages/playground/Samples/mouse.tsx +++ b/vnext/src/RNTester/js/examples-win/Mouse/MouseExample.windows.js @@ -3,16 +3,31 @@ * Licensed under the MIT License. * @format */ -import * as React from 'react'; -import { - AppRegistry, + +'use strict'; + +const React = require('react'); + +const { StyleSheet, View, Text, GestureResponderEvent, TouchableHighlight, BackHandler, -} from 'react-native'; +} = require('react-native'); + +exports.displayName = 'MouseExample'; +exports.title = 'Mouse Events'; +exports.description = 'Tests that mouse events can be observed'; +exports.examples = [ + { + title: 'onMouseEnter and onMouseLeave affect style\n', + render: function(): React.Node { + return ; + }, + }, +]; const styles = StyleSheet.create({ page: { @@ -68,16 +83,16 @@ const styles = StyleSheet.create({ }, }); -export default class Bootstrap extends React.Component< +export default class ExampleComponent extends React.Component< {}, { - clicked: number; - pageHover: boolean; - contentHover: boolean; - contentChildHover: boolean; - overlayHover: boolean; - overlayChildHover: boolean; - } + clicked: number, + pageHover: boolean, + contentHover: boolean, + contentChildHover: boolean, + overlayHover: boolean, + overlayChildHover: boolean, + }, > { constructor(props: {}) { super(props); @@ -225,5 +240,3 @@ export default class Bootstrap extends React.Component< return true; }; } - -AppRegistry.registerComponent('Bootstrap', () => Bootstrap); diff --git a/vnext/src/RNTester/js/utils/RNTesterList.windows.ts b/vnext/src/RNTester/js/utils/RNTesterList.windows.ts index 508b7ce85fd..95163ac0f5a 100644 --- a/vnext/src/RNTester/js/utils/RNTesterList.windows.ts +++ b/vnext/src/RNTester/js/utils/RNTesterList.windows.ts @@ -221,6 +221,10 @@ const APIExamples: Array = [ key: 'LayoutExample', module: require('react-native/RNTester/js/examples/Layout/LayoutExample'), }, + { + key: 'MouseExample', + module: require('./../examples-win/Mouse/MouseExample'), + }, { key: 'NativeAnimationsExample', module: require('react-native/RNTester/js/examples/NativeAnimation/NativeAnimationsExample'),