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..956ab190ced --- /dev/null +++ b/change/react-native-windows-2020-08-14-09-57-33-fix-touchable-mouse.json @@ -0,0 +1,8 @@ +{ + "type": "patch", + "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/playground/windows/playground/MainPage.xaml b/packages/playground/windows/playground/MainPage.xaml index a4824be9fba..3c055e45a2c 100644 --- a/packages/playground/windows/playground/MainPage.xaml +++ b/packages/playground/windows/playground/MainPage.xaml @@ -68,7 +68,6 @@ - diff --git a/vnext/.flowconfig b/vnext/.flowconfig index a4b73ab4f67..227e661cd79 100644 --- a/vnext/.flowconfig +++ b/vnext/.flowconfig @@ -43,6 +43,8 @@ /Libraries/StyleSheet/processColor.js /Libraries/StyleSheet/processColorArray.js /Libraries/StyleSheet/StyleSheetTypes.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/src/Libraries/Components/Touchable/TouchableHighlight.windows.js b/vnext/src/Libraries/Components/Touchable/TouchableHighlight.windows.js index 2e14386084a..f465c4641fd 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 { getPressOutDelayMS: () => this.props.delayPressOut, getPressRectOffset: () => this.props.pressRetentionOffset, getTouchSoundDisabled: () => 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 35d5339180f..f0a4f286382 100644 --- a/vnext/src/Libraries/Components/Touchable/TouchableOpacity.windows.js +++ b/vnext/src/Libraries/Components/Touchable/TouchableOpacity.windows.js @@ -150,6 +150,8 @@ class TouchableOpacity extends React.Component { getPressDelayMS: () => this.props.delayPressIn, getPressOutDelayMS: () => this.props.delayPressOut, getPressRectOffset: () => 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 bcd4de3adba..b94fa9cbed8 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] |}>; @@ -127,6 +128,8 @@ class TouchableWithoutFeedback extends React.Component { getPressOutDelayMS: () => this.props.delayPressOut, getPressRectOffset: () => this.props.pressRetentionOffset, getTouchSoundDisabled: () => this.props.touchSoundDisabled, + onMouseEnter: this.props.onMouseEnter, // [Windows] + onMouseLeave: this.props.onMouseLeave, // [Windows] onBlur: event => { if (this.props.onBlur != null) { this.props.onBlur(event); diff --git a/vnext/src/Libraries/Components/View/ViewPropTypes.windows.js b/vnext/src/Libraries/Components/View/ViewPropTypes.windows.js index 8a50a858811..f3f09713c9c 100644 --- a/vnext/src/Libraries/Components/View/ViewPropTypes.windows.js +++ b/vnext/src/Libraries/Components/View/ViewPropTypes.windows.js @@ -434,8 +434,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 31883d6d352..4f64a0a20c1 100644 --- a/vnext/src/Libraries/Pressability/Pressability.windows.js +++ b/vnext/src/Libraries/Pressability/Pressability.windows.js @@ -20,7 +20,7 @@ import type { PressEvent, MouseEvent, KeyEvent, // [Windows] -} from '../Types/CoreEventTypes.js'; +} from '../Types/CoreEventTypes'; // [Windows] remove explicit .js import Platform from '../Utilities/Platform'; import UIManager from '../ReactNative/UIManager'; import type {HostComponent} from '../Renderer/shims/ReactNativeTypes'; @@ -129,6 +129,22 @@ export type PressabilityConfig = $ReadOnly<{| * Returns whether to start a press gesture. */ onStartShouldSetResponder?: ?() => 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] |}>; type EventHandlers = $ReadOnly<{| @@ -528,6 +544,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(); @@ -546,6 +568,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 b2a4f0f6902..993887fa2e7 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 a554aaeb707..d472f6c8736 100644 --- a/vnext/src/RNTester/js/utils/RNTesterList.windows.ts +++ b/vnext/src/RNTester/js/utils/RNTesterList.windows.ts @@ -203,6 +203,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'), diff --git a/vnext/src/overrides.json b/vnext/src/overrides.json index c02cfcdb585..cbc34ac6551 100644 --- a/vnext/src/overrides.json +++ b/vnext/src/overrides.json @@ -674,7 +674,7 @@ }, { "type": "patch", - "file": "Libraries\\Types\\CoreEventTypes.js", + "file": "Libraries\\Types\\CoreEventTypes.windows.js", "baseFile": "Libraries\\Types\\CoreEventTypes.js", "baseVersion": "0.62.0-rc.3", "baseHash": "83b203d547d9bdc57a8f3346ecee6f6e34b25f5d",