From e34ac7c0668906f588883e1ec8b936495bf0a9d9 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 31 Aug 2017 15:27:54 -0700 Subject: [PATCH] Embed ReactNative event types in JavaScript (#10567) * ReactNative doesn't query UIManager for native event types This is a pre-req to unblock Prepack optimiations for ReactNative apps * Replaced mock ReactNativeEventTypes with mock Platform * Added Platform.OS to RN host hooks Flow types --- flow/react-native-host-hooks.js | 3 + scripts/rollup/bundles.js | 1 + src/__mocks__/Platform.js | 13 + src/__mocks__/UIManager.js | 46 --- .../native/ReactNativeBridgeEventPlugin.js | 6 +- src/renderers/native/ReactNativeEventTypes.js | 316 ++++++++++++++++++ 6 files changed, 336 insertions(+), 49 deletions(-) create mode 100644 src/__mocks__/Platform.js create mode 100644 src/renderers/native/ReactNativeEventTypes.js diff --git a/flow/react-native-host-hooks.js b/flow/react-native-host-hooks.js index 11db414b1fe6e..f29c4976bbd18 100644 --- a/flow/react-native-host-hooks.js +++ b/flow/react-native-host-hooks.js @@ -32,6 +32,9 @@ declare module 'ExceptionsManager' { isFatal: boolean, ) : void; } +declare module 'Platform' { + declare var OS : string; +} declare module 'UIManager' { declare var customBubblingEventTypes : Object; declare var customDirectEventTypes : Object; diff --git a/scripts/rollup/bundles.js b/scripts/rollup/bundles.js index ae4ee59b3f3a6..e5685f0115691 100644 --- a/scripts/rollup/bundles.js +++ b/scripts/rollup/bundles.js @@ -263,6 +263,7 @@ const bundles = [ externals: [ 'ExceptionsManager', 'InitializeCore', + 'Platform', 'RCTEventEmitter', 'TextInputState', 'UIManager', diff --git a/src/__mocks__/Platform.js b/src/__mocks__/Platform.js new file mode 100644 index 0000000000000..4616105cf1ca4 --- /dev/null +++ b/src/__mocks__/Platform.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +'use strict'; + +module.exports = { + OS: 'ios', +}; diff --git a/src/__mocks__/UIManager.js b/src/__mocks__/UIManager.js index 28aa5304a6d73..d84e19cd01f93 100644 --- a/src/__mocks__/UIManager.js +++ b/src/__mocks__/UIManager.js @@ -155,52 +155,6 @@ var RCTUIManager = { }), replaceExistingNonRootView: jest.fn(), __takeSnapshot: jest.fn(), - customBubblingEventTypes: { - topBlur: { - phasedRegistrationNames: { - bubbled: 'onBlur', - captured: 'onBlurCapture', - }, - }, - topFocus: { - phasedRegistrationNames: { - bubbled: 'onFocus', - captured: 'onFocusCapture', - }, - }, - topTouchCancel: { - phasedRegistrationNames: { - bubbled: 'onTouchCancel', - captured: 'onTouchCancelCapture', - }, - }, - topTouchEnd: { - phasedRegistrationNames: { - bubbled: 'onTouchEnd', - captured: 'onTouchEndCapture', - }, - }, - topTouchMove: { - phasedRegistrationNames: { - bubbled: 'onTouchMove', - captured: 'onTouchMoveCapture', - }, - }, - topTouchStart: { - phasedRegistrationNames: { - bubbled: 'onTouchStart', - captured: 'onTouchStartCapture', - }, - }, - }, - customDirectEventTypes: { - topAccessibilityTap: { - registrationName: 'onAccessibilityTap', - }, - topTextLayout: { - registrationName: 'onTextLayout', - }, - }, }; module.exports = RCTUIManager; diff --git a/src/renderers/native/ReactNativeBridgeEventPlugin.js b/src/renderers/native/ReactNativeBridgeEventPlugin.js index 121f7663a368a..051ef35c6afe1 100644 --- a/src/renderers/native/ReactNativeBridgeEventPlugin.js +++ b/src/renderers/native/ReactNativeBridgeEventPlugin.js @@ -13,10 +13,10 @@ var EventPropagators = require('EventPropagators'); var SyntheticEvent = require('SyntheticEvent'); -var UIManager = require('UIManager'); +var ReactNativeEventTypes = require('ReactNativeEventTypes'); -var customBubblingEventTypes = UIManager.customBubblingEventTypes; -var customDirectEventTypes = UIManager.customDirectEventTypes; +var customBubblingEventTypes = ReactNativeEventTypes.customBubblingEventTypes; +var customDirectEventTypes = ReactNativeEventTypes.customDirectEventTypes; if (__DEV__) { var warning = require('fbjs/lib/warning'); diff --git a/src/renderers/native/ReactNativeEventTypes.js b/src/renderers/native/ReactNativeEventTypes.js new file mode 100644 index 0000000000000..179b1bc5c928c --- /dev/null +++ b/src/renderers/native/ReactNativeEventTypes.js @@ -0,0 +1,316 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactNativeEventTypes + * @flow + */ +'use strict'; + +const Platform = require('Platform'); + +const emptyObject = require('fbjs/lib/emptyObject'); + +const COMMON_BUBBLING_EVENT_TYPES = { + topBlur: { + phasedRegistrationNames: { + captured: 'onBlurCapture', + bubbled: 'onBlur', + }, + }, + topChange: { + phasedRegistrationNames: { + captured: 'onChangeCapture', + bubbled: 'onChange', + }, + }, + topEndEditing: { + phasedRegistrationNames: { + captured: 'onEndEditingCapture', + bubbled: 'onEndEditing', + }, + }, + topFocus: { + phasedRegistrationNames: { + captured: 'onFocusCapture', + bubbled: 'onFocus', + }, + }, + topSubmitEditing: { + phasedRegistrationNames: { + captured: 'onSubmitEditingCapture', + bubbled: 'onSubmitEditing', + }, + }, + topTouchEnd: { + phasedRegistrationNames: { + captured: 'onTouchEndCapture', + bubbled: 'onTouchEnd', + }, + }, + topTouchMove: { + phasedRegistrationNames: { + captured: 'onTouchMoveCapture', + bubbled: 'onTouchMove', + }, + }, + topTouchStart: { + phasedRegistrationNames: { + captured: 'onTouchStartCapture', + bubbled: 'onTouchStart', + }, + }, +}; + +const COMMON_DIRECT_EVENT_TYPES = { + topError: { + registrationName: 'onError', + }, + topLayout: { + registrationName: 'onLayout', + }, + topLoad: { + registrationName: 'onLoad', + }, + topLoadEnd: { + registrationName: 'onLoadEnd', + }, + topLoadStart: { + registrationName: 'onLoadStart', + }, + topLoadingError: { + registrationName: 'onLoadingError', + }, + topLoadingFinish: { + registrationName: 'onLoadingFinish', + }, + topLoadingStart: { + registrationName: 'onLoadingStart', + }, + topMessage: { + registrationName: 'onMessage', + }, + topMomentumScrollBegin: { + registrationName: 'onMomentumScrollBegin', + }, + topMomentumScrollEnd: { + registrationName: 'onMomentumScrollEnd', + }, + topRefresh: { + registrationName: 'onRefresh', + }, + topScroll: { + registrationName: 'onScroll', + }, + topScrollAnimationEnd: { + registrationName: 'onScrollAnimationEnd', + }, + topScrollBeginDrag: { + registrationName: 'onScrollBeginDrag', + }, + topScrollEndDrag: { + registrationName: 'onScrollEndDrag', + }, + topSelectionChange: { + registrationName: 'onSelectionChange', + }, + topShow: { + registrationName: 'onShow', + }, +}; + +const ANDROID_BUBBLING_EVENT_TYPES = { + ...COMMON_BUBBLING_EVENT_TYPES, + topSelect: { + phasedRegistrationNames: { + bubbled: 'onSelect', + captured: 'onSelectCapture', + }, + }, + topTextInput: { + phasedRegistrationNames: { + bubbled: 'onTextInput', + captured: 'onTextInputCapture', + }, + }, +}; + +const ANDROID_DIRECT_EVENT_TYPES = { + ...COMMON_DIRECT_EVENT_TYPES, + topContentSizeChange: { + registrationName: 'onContentSizeChange', + }, + topDrawerClosed: { + registrationName: 'onDrawerClose', + }, + topDrawerOpened: { + registrationName: 'onDrawerOpen', + }, + topDrawerSlide: { + registrationName: 'onDrawerSlide', + }, + topDrawerStateChanged: { + registrationName: 'onDrawerStateChanged', + }, + topPageScroll: { + registrationName: 'onPageScroll', + }, + topPageScrollStateChanged: { + registrationName: 'onPageScrollStateChanged', + }, + topPageSelected: { + registrationName: 'onPageSelected', + }, + topRequestClose: { + registrationName: 'onRequestClose', + }, + topSlidingComplete: { + registrationName: 'onSlidingComplete', + }, + topVideoProgress: { + registrationName: 'onProgress', + }, + topVideoSizeDetected: { + registrationName: 'onVideoSizeDetected', + }, + topVideoStateChange: { + registrationName: 'onStateChange', + }, + topZoom: { + registrationName: 'onZoom', + }, +}; + +const IOS_BUBBLING_EVENT_TYPES = { + ...COMMON_BUBBLING_EVENT_TYPES, + topAnnotationBlur: { + phasedRegistrationNames: { + captured: 'onAnnotationBlurCapture', + bubbled: 'onAnnotationBlur', + }, + }, + topAnnotationDragStateChange: { + phasedRegistrationNames: { + captured: 'onAnnotationDragStateChangeCapture', + bubbled: 'onAnnotationDragStateChange', + }, + }, + topAnnotationFocus: { + phasedRegistrationNames: { + captured: 'onAnnotationFocusCapture', + bubbled: 'onAnnotationFocus', + }, + }, + topContentSizeChange: { + phasedRegistrationNames: { + captured: 'onContentSizeChangeCapture', + bubbled: 'onContentSizeChange', + }, + }, + topKeyPress: { + phasedRegistrationNames: { + captured: 'onKeyPressCapture', + bubbled: 'onKeyPress', + }, + }, + topLeftButtonPress: { + phasedRegistrationNames: { + captured: 'onLeftButtonPressCapture', + bubbled: 'onLeftButtonPress', + }, + }, + topNavigationComplete: { + phasedRegistrationNames: { + captured: 'onNavigationCompleteCapture', + bubbled: 'onNavigationComplete', + }, + }, + topPress: { + phasedRegistrationNames: { + captured: 'onPressCapture', + bubbled: 'onPress', + }, + }, + topRightButtonPress: { + phasedRegistrationNames: { + captured: 'onRightButtonPressCapture', + bubbled: 'onRightButtonPress', + }, + }, + topSlidingComplete: { + phasedRegistrationNames: { + captured: 'onSlidingCompleteCapture', + bubbled: 'onSlidingComplete', + }, + }, + topTouchCancel: { + phasedRegistrationNames: { + captured: 'onTouchCancelCapture', + bubbled: 'onTouchCancel', + }, + }, + topValueChange: { + phasedRegistrationNames: { + captured: 'onValueChangeCapture', + bubbled: 'onValueChange', + }, + }, +}; + +const IOS_DIRECT_EVENT_TYPES = { + ...COMMON_DIRECT_EVENT_TYPES, + topAccessibilityTap: { + registrationName: 'onAccessibilityTap', + }, + topMagicTap: { + registrationName: 'onMagicTap', + }, + topNavigationProgress: { + registrationName: 'onNavigationProgress', + }, + topOrientationChange: { + registrationName: 'onOrientationChange', + }, + topPartialLoad: { + registrationName: 'onPartialLoad', + }, + topProgress: { + registrationName: 'onProgress', + }, + topShouldStartLoadWithRequest: { + registrationName: 'onShouldStartLoadWithRequest', + }, + topStateChange: { + registrationName: 'onStateChange', + }, + topTextInput: { + registrationName: 'onTextInput', + }, + topTextLayout: { + registrationName: 'onTextLayout', + }, +}; + +let ReactNativeEventTypes; +if (Platform.OS === 'ios') { + ReactNativeEventTypes = { + customBubblingEventTypes: IOS_BUBBLING_EVENT_TYPES, + customDirectEventTypes: IOS_DIRECT_EVENT_TYPES, + }; +} else if (Platform.OS === 'android') { + ReactNativeEventTypes = { + customBubblingEventTypes: ANDROID_BUBBLING_EVENT_TYPES, + customDirectEventTypes: ANDROID_DIRECT_EVENT_TYPES, + }; +} else { + ReactNativeEventTypes = { + customBubblingEventTypes: emptyObject, + customDirectEventTypes: emptyObject, + }; +} + +module.exports = ReactNativeEventTypes;