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'),