From 75c94a89070820618dd423355bfa6888a69a0d5a Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Thu, 14 Sep 2017 18:01:27 -0700 Subject: [PATCH] Native view manager event types exposed to JS via view config Differential Revision: D5814210 fbshipit-source-id: 41291f0d6b39af77f66173f6a699d88f9f4ccc74 --- .../ReactNative/requireNativeComponent.js | 6 + Libraries/Renderer/ReactNativeFiber-dev.js | 342 ++---------------- Libraries/Renderer/ReactNativeFiber-prod.js | 307 +--------------- .../shims/ReactNativeBridgeEventPlugin.js | 19 + Libraries/Renderer/shims/ReactNativeTypes.js | 18 + React/Modules/RCTUIManager.m | 12 +- .../uimanager/UIManagerModuleConstants.java | 9 + .../UIManagerModuleConstantsHelper.java | 24 +- .../textinput/ReactTextInputManager.java | 8 + 9 files changed, 121 insertions(+), 624 deletions(-) create mode 100644 Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js diff --git a/Libraries/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 3b3795f36496f4..b97e4c1a79c845 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -11,6 +11,7 @@ */ 'use strict'; +const ReactNativeBridgeEventPlugin = require('ReactNativeBridgeEventPlugin'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const UIManager = require('UIManager'); @@ -126,6 +127,11 @@ function requireNativeComponent( ); } + // Register this view's event types with the ReactNative renderer. + // This enables view managers to be initialized lazily, improving perf, + // While also enabling 3rd party components to define custom event types. + ReactNativeBridgeEventPlugin.processEventTypes(viewConfig); + return viewConfig; } diff --git a/Libraries/Renderer/ReactNativeFiber-dev.js b/Libraries/Renderer/ReactNativeFiber-dev.js index efdafee8c46e6b..4c91011552b0ca 100644 --- a/Libraries/Renderer/ReactNativeFiber-dev.js +++ b/Libraries/Renderer/ReactNativeFiber-dev.js @@ -14,7 +14,7 @@ __DEV__ && function() { var invariant = require("fbjs/lib/invariant"), require$$0 = require("fbjs/lib/warning"), ExceptionsManager = require("ExceptionsManager"), emptyObject = require("fbjs/lib/emptyObject"), react = require("react"), checkPropTypes = require("prop-types/checkPropTypes"), shallowEqual = require("fbjs/lib/shallowEqual"), deepDiffer = require("deepDiffer"), flattenStyle = require("flattenStyle"), TextInputState = require("TextInputState"), UIManager = require("UIManager"), deepFreezeAndThrowOnMutationInDev = require("deepFreezeAndThrowOnMutationInDev"); require("InitializeCore"); - var RCTEventEmitter = require("RCTEventEmitter"), emptyFunction = require("fbjs/lib/emptyFunction"), Platform = require("Platform"), ExecutionEnvironment = require("fbjs/lib/ExecutionEnvironment"), performanceNow = require("fbjs/lib/performanceNow"), defaultShowDialog = function(capturedError) { + var RCTEventEmitter = require("RCTEventEmitter"), emptyFunction = require("fbjs/lib/emptyFunction"), ExecutionEnvironment = require("fbjs/lib/ExecutionEnvironment"), performanceNow = require("fbjs/lib/performanceNow"), defaultShowDialog = function(capturedError) { return !0; }, showDialog = defaultShowDialog; function logCapturedError(capturedError) { @@ -2765,15 +2765,6 @@ __DEV__ && function() { function scheduleErrorRecovery(fiber) { scheduleUpdateImpl(fiber, TaskPriority$1, !0); } - function performWithPriority(priorityLevel, fn) { - var previousPriorityContext = priorityContext; - priorityContext = priorityLevel; - try { - fn(); - } finally { - priorityContext = previousPriorityContext; - } - } function batchedUpdates(fn, a) { var previousIsBatchingUpdates = isBatchingUpdates; isBatchingUpdates = !0; @@ -2815,7 +2806,6 @@ __DEV__ && function() { return { scheduleUpdate: scheduleUpdate, getPriorityContext: getPriorityContext, - performWithPriority: performWithPriority, batchedUpdates: batchedUpdates, unbatchedUpdates: unbatchedUpdates, flushSync: flushSync, @@ -3020,7 +3010,7 @@ __DEV__ && function() { node._children.forEach(recursivelyUncacheFiberNode)); } var NativeRenderer = function(config) { - var getPublicInstance = config.getPublicInstance, _ReactFiberScheduler = ReactFiberScheduler(config), scheduleUpdate = _ReactFiberScheduler.scheduleUpdate, getPriorityContext = _ReactFiberScheduler.getPriorityContext, performWithPriority = _ReactFiberScheduler.performWithPriority, batchedUpdates = _ReactFiberScheduler.batchedUpdates, unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, flushSync = _ReactFiberScheduler.flushSync, deferredUpdates = _ReactFiberScheduler.deferredUpdates; + var getPublicInstance = config.getPublicInstance, _ReactFiberScheduler = ReactFiberScheduler(config), scheduleUpdate = _ReactFiberScheduler.scheduleUpdate, getPriorityContext = _ReactFiberScheduler.getPriorityContext, batchedUpdates = _ReactFiberScheduler.batchedUpdates, unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, flushSync = _ReactFiberScheduler.flushSync, deferredUpdates = _ReactFiberScheduler.deferredUpdates; function scheduleTopLevelUpdate(current, element, callback) { "render" === ReactDebugCurrentFiber.phase && null !== ReactDebugCurrentFiber.current && warning$1(!1, "Render methods should be a pure function of props and state; " + "triggering nested component updates from render is not allowed. " + "If necessary, trigger nested updates in componentDidUpdate.\n\n" + "Check the render method of %s.", getComponentName(ReactDebugCurrentFiber.current) || "Unknown"); var forceAsync = ReactFeatureFlags_1.enableAsyncSubtreeAPI && null != element && null != element.type && null != element.type.prototype && !0 === element.type.prototype.unstable_isAsyncReactComponent, priorityLevel = getPriorityContext(current, forceAsync), nextState = { @@ -3040,7 +3030,6 @@ __DEV__ && function() { null === container.context ? container.context = context : container.pendingContext = context, scheduleTopLevelUpdate(current, element, callback); }, - performWithPriority: performWithPriority, batchedUpdates: batchedUpdates, unbatchedUpdates: unbatchedUpdates, deferredUpdates: deferredUpdates, @@ -3214,7 +3203,7 @@ __DEV__ && function() { }; var ReactNativeFiberInspector = { getInspectorDataForViewTag: getInspectorDataForViewTag - }, ReactVersion = "16.0.0-beta.5", ReactCurrentOwner$3 = ReactGlobalSharedState_1.ReactCurrentOwner, warning$11 = require$$0; + }, ReactVersion = "16.0.0-rc.1", ReactCurrentOwner$3 = ReactGlobalSharedState_1.ReactCurrentOwner, warning$11 = require$$0; function findNodeHandle(componentOrHandle) { var owner = ReactCurrentOwner$3.current; if (null !== owner && null !== owner.stateNode && (warning$11(owner.stateNode._warnedAboutRefsInRender, "%s is accessing findNodeHandle inside its render(). " + "render() should be a pure function of props and state. It should " + "never access something that requires stale data from the previous " + "render, such as refs. Move this logic to componentDidMount and " + "componentDidUpdate instead.", getComponentName_1(owner) || "A component"), @@ -3412,13 +3401,13 @@ __DEV__ && function() { getParentInstance: getParentInstance, traverseTwoPhase: traverseTwoPhase, traverseEnterLeave: traverseEnterLeave - }, getListener = EventPluginHub_1.getListener, warning$13 = require$$0; + }, getListener = EventPluginHub_1.getListener, warning$12 = require$$0; function listenerAtPhase(inst, event, propagationPhase) { var registrationName = event.dispatchConfig.phasedRegistrationNames[propagationPhase]; return getListener(inst, registrationName); } function accumulateDirectionalDispatches(inst, phase, event) { - warning$13(inst, "Dispatching inst must not be null"); + warning$12(inst, "Dispatching inst must not be null"); var listener = listenerAtPhase(inst, event, phase); listener && (event._dispatchListeners = accumulateInto_1(event._dispatchListeners, listener), event._dispatchInstances = accumulateInto_1(event._dispatchInstances, inst)); @@ -3459,7 +3448,7 @@ __DEV__ && function() { accumulateTwoPhaseDispatchesSkipTarget: accumulateTwoPhaseDispatchesSkipTarget, accumulateDirectDispatches: accumulateDirectDispatches, accumulateEnterLeaveDispatches: accumulateEnterLeaveDispatches - }, EventPropagators_1 = EventPropagators, didWarnForAddedNewProperty = !1, isProxySupported = "function" == typeof Proxy, EVENT_POOL_SIZE = 10, warning$14 = require$$0, shouldBeReleasedProperties = [ "dispatchConfig", "_targetInst", "nativeEvent", "isDefaultPrevented", "isPropagationStopped", "_dispatchListeners", "_dispatchInstances" ], EventInterface = { + }, EventPropagators_1 = EventPropagators, didWarnForAddedNewProperty = !1, isProxySupported = "function" == typeof Proxy, EVENT_POOL_SIZE = 10, warning$13 = require$$0, shouldBeReleasedProperties = [ "dispatchConfig", "_targetInst", "nativeEvent", "isDefaultPrevented", "isPropagationStopped", "_dispatchListeners", "_dispatchInstances" ], EventInterface = { type: null, target: null, currentTarget: emptyFunction.thatReturnsNull, @@ -3523,7 +3512,7 @@ __DEV__ && function() { apply: function(constructor, that, args) { return new Proxy(constructor.apply(that, args), { set: function(target, prop, value) { - return "isPersistent" === prop || target.constructor.Interface.hasOwnProperty(prop) || -1 !== shouldBeReleasedProperties.indexOf(prop) || (warning$14(didWarnForAddedNewProperty || target.isPersistent(), "This synthetic event is reused for performance reasons. If you're " + "seeing this, you're adding a new property in the synthetic event object. " + "The property is never released. See " + "https://fb.me/react-event-pooling for more information."), + return "isPersistent" === prop || target.constructor.Interface.hasOwnProperty(prop) || -1 !== shouldBeReleasedProperties.indexOf(prop) || (warning$13(didWarnForAddedNewProperty || target.isPersistent(), "This synthetic event is reused for performance reasons. If you're " + "seeing this, you're adding a new property in the synthetic event object. " + "The property is never released. See " + "https://fb.me/react-event-pooling for more information."), didWarnForAddedNewProperty = !0), target[prop] = value, !0; } }); @@ -3546,7 +3535,7 @@ __DEV__ && function() { getVal; } function warn(action, result) { - warning$14(!1, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + "If you must keep the original synthetic event around, use event.persist(). " + "See https://fb.me/react-event-pooling for more information.", action, propName, result); + warning$13(!1, "This synthetic event is reused for performance reasons. If you're seeing this, " + "you're %s `%s` on a released/nullified synthetic event. %s. " + "If you must keep the original synthetic event around, use event.persist(). " + "See https://fb.me/react-event-pooling for more information.", action, propName, result); } } function getPooledEvent(dispatchConfig, targetInst, nativeEvent, nativeInst) { @@ -3566,288 +3555,8 @@ __DEV__ && function() { function addEventPoolingTo(EventConstructor) { EventConstructor.eventPool = [], EventConstructor.getPooled = getPooledEvent, EventConstructor.release = releasePooledEvent; } - var 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" - } - } - }, 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" - } - }, ANDROID_BUBBLING_EVENT_TYPES = Object.assign({}, COMMON_BUBBLING_EVENT_TYPES, { - topSelect: { - phasedRegistrationNames: { - bubbled: "onSelect", - captured: "onSelectCapture" - } - }, - topTextInput: { - phasedRegistrationNames: { - bubbled: "onTextInput", - captured: "onTextInputCapture" - } - } - }), ANDROID_DIRECT_EVENT_TYPES = Object.assign({}, 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" - } - }), IOS_BUBBLING_EVENT_TYPES = Object.assign({}, 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" - } - } - }), IOS_DIRECT_EVENT_TYPES = Object.assign({}, 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" - }, - topSnapshotReady: { - registrationName: "onSnapshotReady" - }, - topStateChange: { - registrationName: "onStateChange" - }, - topTextInput: { - registrationName: "onTextInput" - }, - topTextLayout: { - registrationName: "onTextLayout" - } - }), ReactNativeEventTypes = void 0; - ReactNativeEventTypes = "ios" === Platform.OS ? { - customBubblingEventTypes: IOS_BUBBLING_EVENT_TYPES, - customDirectEventTypes: IOS_DIRECT_EVENT_TYPES - } : "android" === Platform.OS ? { - customBubblingEventTypes: ANDROID_BUBBLING_EVENT_TYPES, - customDirectEventTypes: ANDROID_DIRECT_EVENT_TYPES - } : { - customBubblingEventTypes: emptyObject, - customDirectEventTypes: emptyObject - }; - var ReactNativeEventTypes_1 = ReactNativeEventTypes, customBubblingEventTypes = ReactNativeEventTypes_1.customBubblingEventTypes, customDirectEventTypes = ReactNativeEventTypes_1.customDirectEventTypes, warning$12 = require$$0; - for (var directTypeName in customDirectEventTypes) warning$12(!customBubblingEventTypes[directTypeName], "Event cannot be both direct and bubbling: %s", directTypeName); - var ReactNativeBridgeEventPlugin = { - eventTypes: Object.assign({}, customBubblingEventTypes, customDirectEventTypes), + var customBubblingEventTypes = {}, customDirectEventTypes = {}, ReactNativeBridgeEventPlugin = { + eventTypes: {}, extractEvents: function(topLevelType, targetInst, nativeEvent, nativeEventTarget) { var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], directDispatchConfig = customDirectEventTypes[topLevelType]; invariant(bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', topLevelType); @@ -3857,6 +3566,12 @@ __DEV__ && function() { EventPropagators_1.accumulateDirectDispatches(event); } return event; + }, + processEventTypes: function(viewConfig) { + var bubblingEventTypes = viewConfig.bubblingEventTypes, directEventTypes = viewConfig.directEventTypes; + if (null != bubblingEventTypes && null != directEventTypes) for (var topLevelType in directEventTypes) invariant(null == bubblingEventTypes[topLevelType], "Event cannot be both direct and bubbling: %s", topLevelType); + if (null != bubblingEventTypes) for (var _topLevelType in bubblingEventTypes) null == customBubblingEventTypes[_topLevelType] && (ReactNativeBridgeEventPlugin.eventTypes[_topLevelType] = customBubblingEventTypes[_topLevelType] = bubblingEventTypes[_topLevelType]); + if (null != directEventTypes) for (var _topLevelType2 in directEventTypes) null == customDirectEventTypes[_topLevelType2] && (ReactNativeBridgeEventPlugin.eventTypes[_topLevelType2] = customDirectEventTypes[_topLevelType2] = directEventTypes[_topLevelType2]); } }, ReactNativeBridgeEventPlugin_1 = ReactNativeBridgeEventPlugin; function runEventQueueInBatch(events) { @@ -3866,7 +3581,7 @@ __DEV__ && function() { handleTopLevel: function(topLevelType, targetInst, nativeEvent, nativeEventTarget) { runEventQueueInBatch(EventPluginHub_1.extractEvents(topLevelType, targetInst, nativeEvent, nativeEventTarget)); } - }, ReactEventEmitterMixin_1 = ReactEventEmitterMixin, warning$15 = require$$0, EMPTY_NATIVE_EVENT = {}, touchSubsequence = function(touches, indices) { + }, ReactEventEmitterMixin_1 = ReactEventEmitterMixin, warning$14 = require$$0, EMPTY_NATIVE_EVENT = {}, touchSubsequence = function(touches, indices) { for (var ret = [], i = 0; i < indices.length; i++) ret.push(touches[indices[i]]); return ret; }, removeTouchesAtIndices = function(touches, indices) { @@ -3896,7 +3611,7 @@ __DEV__ && function() { var touch = changedTouches[jj]; touch.changedTouches = changedTouches, touch.touches = touches; var nativeEvent = touch, rootNodeID = null, target = nativeEvent.target; - null !== target && void 0 !== target && (target < ReactNativeTagHandles_1.tagsStartAt ? warning$15(!1, "A view is reporting that a touch occurred on tag zero.") : rootNodeID = target), + null !== target && void 0 !== target && (target < ReactNativeTagHandles_1.tagsStartAt ? warning$14(!1, "A view is reporting that a touch occurred on tag zero.") : rootNodeID = target), ReactNativeEventEmitter._receiveRootNodeIDEvent(rootNodeID, eventTopLevelType, nativeEvent); } } @@ -3916,7 +3631,7 @@ __DEV__ && function() { return SyntheticEvent_1.call(this, dispatchConfig, dispatchMarker, nativeEvent, nativeEventTarget); } SyntheticEvent_1.augmentClass(ResponderSyntheticEvent, ResponderEventInterface); - var ResponderSyntheticEvent_1 = ResponderSyntheticEvent, isEndish$2 = EventPluginUtils_1.isEndish, isMoveish$2 = EventPluginUtils_1.isMoveish, isStartish$2 = EventPluginUtils_1.isStartish, warning$16 = require$$0, MAX_TOUCH_BANK = 20, touchBank = [], touchHistory = { + var ResponderSyntheticEvent_1 = ResponderSyntheticEvent, isEndish$2 = EventPluginUtils_1.isEndish, isMoveish$2 = EventPluginUtils_1.isMoveish, isStartish$2 = EventPluginUtils_1.isStartish, warning$15 = require$$0, MAX_TOUCH_BANK = 20, touchBank = [], touchHistory = { touchBank: touchBank, numberActiveTouches: 0, indexOfSingleActiveTouch: -1, @@ -3948,7 +3663,7 @@ __DEV__ && function() { } function getTouchIdentifier(_ref) { var identifier = _ref.identifier; - return invariant(null != identifier, "Touch object is missing identifier."), warning$16(identifier <= MAX_TOUCH_BANK, "Touch identifier %s is greater than maximum supported %s which causes " + "performance issues backfilling array locations for all of the indices.", identifier, MAX_TOUCH_BANK), + return invariant(null != identifier, "Touch object is missing identifier."), warning$15(identifier <= MAX_TOUCH_BANK, "Touch identifier %s is greater than maximum supported %s which causes " + "performance issues backfilling array locations for all of the indices.", identifier, MAX_TOUCH_BANK), identifier; } function recordTouchStart(touch) { @@ -3996,7 +3711,7 @@ __DEV__ && function() { } } var activeRecord = touchBank[touchHistory.indexOfSingleActiveTouch]; - warning$16(null != activeRecord && activeRecord.touchActive, "Cannot find single active touch."); + warning$15(null != activeRecord && activeRecord.touchActive, "Cannot find single active touch."); } }, touchHistory: touchHistory @@ -4263,8 +3978,8 @@ __DEV__ && function() { return "number" != typeof view && "window" !== view && (view = findNumericNodeHandle(view) || "window"), UIManager.__takeSnapshot(view, options); } - var takeSnapshot_1 = takeSnapshot, ReactInvalidSetStateWarningHook = {}, warning$18 = require$$0, processingChildContext = !1, warnInvalidSetState = function() { - warning$18(!processingChildContext, "setState(...): Cannot call setState() inside getChildContext()"); + var takeSnapshot_1 = takeSnapshot, ReactInvalidSetStateWarningHook = {}, warning$17 = require$$0, processingChildContext = !1, warnInvalidSetState = function() { + warning$17(!processingChildContext, "setState(...): Cannot call setState() inside getChildContext()"); }; ReactInvalidSetStateWarningHook = { onBeginProcessingChildContext: function() { @@ -4289,11 +4004,11 @@ __DEV__ && function() { return history; } }; - var ReactHostOperationHistoryHook_1 = ReactHostOperationHistoryHook, ReactComponentTreeHook = ReactGlobalSharedState_1.ReactComponentTreeHook, warning$17 = require$$0, ReactDebugTool = null, hooks = [], didHookThrowForEvent = {}, callHook = function(event, fn, context, arg1, arg2, arg3, arg4, arg5) { + var ReactHostOperationHistoryHook_1 = ReactHostOperationHistoryHook, ReactComponentTreeHook = ReactGlobalSharedState_1.ReactComponentTreeHook, warning$16 = require$$0, ReactDebugTool = null, hooks = [], didHookThrowForEvent = {}, callHook = function(event, fn, context, arg1, arg2, arg3, arg4, arg5) { try { fn.call(context, arg1, arg2, arg3, arg4, arg5); } catch (e) { - warning$17(didHookThrowForEvent[event], "Exception thrown by hook while handling %s: %s", event, e + "\n" + e.stack), + warning$16(didHookThrowForEvent[event], "Exception thrown by hook while handling %s: %s", event, e + "\n" + e.stack), didHookThrowForEvent[event] = !0; } }, emitEvent = function(event, arg1, arg2, arg3, arg4, arg5) { @@ -4330,13 +4045,13 @@ __DEV__ && function() { } clearHistory(), currentFlushStartTime = performanceNow(), currentFlushMeasurements = []; }, checkDebugID = function(debugID) { - arguments.length > 1 && void 0 !== arguments[1] && arguments[1] && 0 === debugID || debugID || warning$17(!1, "ReactDebugTool: debugID may not be empty."); + arguments.length > 1 && void 0 !== arguments[1] && arguments[1] && 0 === debugID || debugID || warning$16(!1, "ReactDebugTool: debugID may not be empty."); }, beginLifeCycleTimer = function(debugID, timerType) { - 0 !== currentFlushNesting && (currentTimerType && !lifeCycleTimerHasWarned && (warning$17(!1, "There is an internal error in the React performance measurement code." + "\n\nDid not expect %s timer to start while %s timer is still in " + "progress for %s instance.", timerType, currentTimerType || "no", debugID === currentTimerDebugID ? "the same" : "another"), + 0 !== currentFlushNesting && (currentTimerType && !lifeCycleTimerHasWarned && (warning$16(!1, "There is an internal error in the React performance measurement code." + "\n\nDid not expect %s timer to start while %s timer is still in " + "progress for %s instance.", timerType, currentTimerType || "no", debugID === currentTimerDebugID ? "the same" : "another"), lifeCycleTimerHasWarned = !0), currentTimerStartTime = performanceNow(), currentTimerNestedFlushDuration = 0, currentTimerDebugID = debugID, currentTimerType = timerType); }, endLifeCycleTimer = function(debugID, timerType) { - 0 !== currentFlushNesting && (currentTimerType === timerType || lifeCycleTimerHasWarned || (warning$17(!1, "There is an internal error in the React performance measurement code. " + "We did not expect %s timer to stop while %s timer is still in " + "progress for %s instance. Please report this as a bug in React.", timerType, currentTimerType || "no", debugID === currentTimerDebugID ? "the same" : "another"), + 0 !== currentFlushNesting && (currentTimerType === timerType || lifeCycleTimerHasWarned || (warning$16(!1, "There is an internal error in the React performance measurement code. " + "We did not expect %s timer to stop while %s timer is still in " + "progress for %s instance. Please report this as a bug in React.", timerType, currentTimerType || "no", debugID === currentTimerDebugID ? "the same" : "another"), lifeCycleTimerHasWarned = !0), isProfiling && currentFlushMeasurements.push({ timerType: timerType, instanceID: debugID, @@ -4715,6 +4430,7 @@ __DEV__ && function() { flushSync: ReactNativeFiberRenderer.flushSync, __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { NativeMethodsMixin: NativeMethodsMixin_1, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin_1, ReactGlobalSharedState: ReactGlobalSharedState_1, ReactNativeComponentTree: ReactNativeComponentTree_1, ReactNativePropRegistry: ReactNativePropRegistry_1, diff --git a/Libraries/Renderer/ReactNativeFiber-prod.js b/Libraries/Renderer/ReactNativeFiber-prod.js index 080c6777cc2619..b9db5f05eceb5f 100644 --- a/Libraries/Renderer/ReactNativeFiber-prod.js +++ b/Libraries/Renderer/ReactNativeFiber-prod.js @@ -15,7 +15,7 @@ var invariant = require("fbjs/lib/invariant"), ExceptionsManager = require("Exce require("deepFreezeAndThrowOnMutationInDev"), require("InitializeCore"); -var RCTEventEmitter = require("RCTEventEmitter"), emptyFunction = require("fbjs/lib/emptyFunction"), Platform = require("Platform"), defaultShowDialog = function(capturedError) { +var RCTEventEmitter = require("RCTEventEmitter"), emptyFunction = require("fbjs/lib/emptyFunction"), defaultShowDialog = function(capturedError) { return !0; }, showDialog = defaultShowDialog; @@ -2470,15 +2470,6 @@ var injectInternals_1 = injectInternals$1, onCommitRoot_1 = onCommitRoot$1, onCo function scheduleErrorRecovery(fiber) { scheduleUpdateImpl(fiber, TaskPriority$1, !0); } - function performWithPriority(priorityLevel, fn) { - var previousPriorityContext = priorityContext; - priorityContext = priorityLevel; - try { - fn(); - } finally { - priorityContext = previousPriorityContext; - } - } function batchedUpdates(fn, a) { var previousIsBatchingUpdates = isBatchingUpdates; isBatchingUpdates = !0; @@ -2520,7 +2511,6 @@ var injectInternals_1 = injectInternals$1, onCommitRoot_1 = onCommitRoot$1, onCo return { scheduleUpdate: scheduleUpdate, getPriorityContext: getPriorityContext, - performWithPriority: performWithPriority, batchedUpdates: batchedUpdates, unbatchedUpdates: unbatchedUpdates, flushSync: flushSync, @@ -2548,7 +2538,7 @@ getContextForSubtree_1._injectFiber(function(fiber) { }); var ReactFiberReconciler = function(config) { - var getPublicInstance = config.getPublicInstance, _ReactFiberScheduler = ReactFiberScheduler(config), scheduleUpdate = _ReactFiberScheduler.scheduleUpdate, getPriorityContext = _ReactFiberScheduler.getPriorityContext, performWithPriority = _ReactFiberScheduler.performWithPriority, batchedUpdates = _ReactFiberScheduler.batchedUpdates, unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, flushSync = _ReactFiberScheduler.flushSync, deferredUpdates = _ReactFiberScheduler.deferredUpdates; + var getPublicInstance = config.getPublicInstance, _ReactFiberScheduler = ReactFiberScheduler(config), scheduleUpdate = _ReactFiberScheduler.scheduleUpdate, getPriorityContext = _ReactFiberScheduler.getPriorityContext, batchedUpdates = _ReactFiberScheduler.batchedUpdates, unbatchedUpdates = _ReactFiberScheduler.unbatchedUpdates, flushSync = _ReactFiberScheduler.flushSync, deferredUpdates = _ReactFiberScheduler.deferredUpdates; function scheduleTopLevelUpdate(current, element, callback) { var forceAsync = ReactFeatureFlags_1.enableAsyncSubtreeAPI && null != element && null != element.type && null != element.type.prototype && !0 === element.type.prototype.unstable_isAsyncReactComponent, priorityLevel = getPriorityContext(current, forceAsync), nextState = { element: element @@ -2565,7 +2555,6 @@ var ReactFiberReconciler = function(config) { null === container.context ? container.context = context : container.pendingContext = context, scheduleTopLevelUpdate(current, element, callback); }, - performWithPriority: performWithPriority, batchedUpdates: batchedUpdates, unbatchedUpdates: unbatchedUpdates, deferredUpdates: deferredUpdates, @@ -2893,7 +2882,7 @@ getInspectorDataForViewTag = function() { var ReactNativeFiberInspector = { getInspectorDataForViewTag: getInspectorDataForViewTag -}, ReactVersion = "16.0.0-beta.5"; +}, ReactVersion = "16.0.0-rc.1"; function findNodeHandle(componentOrHandle) { if (null == componentOrHandle) return null; @@ -3241,288 +3230,8 @@ function addEventPoolingTo(EventConstructor) { EventConstructor.eventPool = [], EventConstructor.getPooled = getPooledEvent, EventConstructor.release = releasePooledEvent; } -var 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" - } - } -}, 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" - } -}, ANDROID_BUBBLING_EVENT_TYPES = Object.assign({}, COMMON_BUBBLING_EVENT_TYPES, { - topSelect: { - phasedRegistrationNames: { - bubbled: "onSelect", - captured: "onSelectCapture" - } - }, - topTextInput: { - phasedRegistrationNames: { - bubbled: "onTextInput", - captured: "onTextInputCapture" - } - } -}), ANDROID_DIRECT_EVENT_TYPES = Object.assign({}, 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" - } -}), IOS_BUBBLING_EVENT_TYPES = Object.assign({}, 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" - } - } -}), IOS_DIRECT_EVENT_TYPES = Object.assign({}, 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" - }, - topSnapshotReady: { - registrationName: "onSnapshotReady" - }, - topStateChange: { - registrationName: "onStateChange" - }, - topTextInput: { - registrationName: "onTextInput" - }, - topTextLayout: { - registrationName: "onTextLayout" - } -}), ReactNativeEventTypes = void 0; - -ReactNativeEventTypes = "ios" === Platform.OS ? { - customBubblingEventTypes: IOS_BUBBLING_EVENT_TYPES, - customDirectEventTypes: IOS_DIRECT_EVENT_TYPES -} : "android" === Platform.OS ? { - customBubblingEventTypes: ANDROID_BUBBLING_EVENT_TYPES, - customDirectEventTypes: ANDROID_DIRECT_EVENT_TYPES -} : { - customBubblingEventTypes: emptyObject, - customDirectEventTypes: emptyObject -}; - -var ReactNativeEventTypes_1 = ReactNativeEventTypes, customBubblingEventTypes = ReactNativeEventTypes_1.customBubblingEventTypes, customDirectEventTypes = ReactNativeEventTypes_1.customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: Object.assign({}, customBubblingEventTypes, customDirectEventTypes), +var customBubblingEventTypes = {}, customDirectEventTypes = {}, ReactNativeBridgeEventPlugin = { + eventTypes: {}, extractEvents: function(topLevelType, targetInst, nativeEvent, nativeEventTarget) { var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], directDispatchConfig = customDirectEventTypes[topLevelType]; invariant(bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', topLevelType); @@ -3532,6 +3241,11 @@ var ReactNativeEventTypes_1 = ReactNativeEventTypes, customBubblingEventTypes = EventPropagators_1.accumulateDirectDispatches(event); } return event; + }, + processEventTypes: function(viewConfig) { + var bubblingEventTypes = viewConfig.bubblingEventTypes, directEventTypes = viewConfig.directEventTypes; + if (null != bubblingEventTypes) for (var _topLevelType in bubblingEventTypes) null == customBubblingEventTypes[_topLevelType] && (ReactNativeBridgeEventPlugin.eventTypes[_topLevelType] = customBubblingEventTypes[_topLevelType] = bubblingEventTypes[_topLevelType]); + if (null != directEventTypes) for (var _topLevelType2 in directEventTypes) null == customDirectEventTypes[_topLevelType2] && (ReactNativeBridgeEventPlugin.eventTypes[_topLevelType2] = customDirectEventTypes[_topLevelType2] = directEventTypes[_topLevelType2]); } }, ReactNativeBridgeEventPlugin_1 = ReactNativeBridgeEventPlugin; @@ -3985,6 +3699,7 @@ var ReactNativeFiber = { flushSync: ReactNativeFiberRenderer.flushSync, __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { NativeMethodsMixin: NativeMethodsMixin_1, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin_1, ReactGlobalSharedState: ReactGlobalSharedState_1, ReactNativeComponentTree: ReactNativeComponentTree_1, ReactNativePropRegistry: ReactNativePropRegistry_1, diff --git a/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js b/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js new file mode 100644 index 00000000000000..c7a1ed8c199c7a --- /dev/null +++ b/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js @@ -0,0 +1,19 @@ +/** + * Copyright 2013-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 ReactNativeBridgeEventPlugin + */ + +'use strict'; + +const { + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, +} = require('ReactNative'); + +module.exports = + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactNativeBridgeEventPlugin; diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index 2f5bea4048cae7..89c4948c63ae9f 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -34,9 +34,22 @@ export type MeasureLayoutOnSuccessCallback = ( height: number, ) => void; +type BubblingEventType = { + phasedRegistrationNames: { + captured: string, + bubbled: string, + }, +}; + +type DirectEventType = { + registrationName: string, +}; + export type ReactNativeBaseComponentViewConfig = { validAttributes: Object, uiViewClassName: string, + bubblingEventTypes?: {[topLevelType: string]: BubblingEventType}, + directEventTypes?: {[topLevelType: string]: DirectEventType}, propTypes?: Object, }; @@ -59,12 +72,17 @@ export type NativeMethodsMixinType = { setNativeProps(nativeProps: Object): void, }; +type ReactNativeBridgeEventPlugin = { + processEventTypes(viewConfig: ReactNativeBaseComponentViewConfig): void, +}; + type SecretInternalsType = { NativeMethodsMixin: NativeMethodsMixinType, createReactNativeComponentClass( name: string, callback: ViewConfigGetter, ): any, + ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, ReactNativeComponentTree: any, ReactNativePropRegistry: any, // TODO (bvaughn) Decide which additional types to expose here? diff --git a/React/Modules/RCTUIManager.m b/React/Modules/RCTUIManager.m index 4d57ef3bf41814..6f65cb1ae6c3ef 100644 --- a/React/Modules/RCTUIManager.m +++ b/React/Modules/RCTUIManager.m @@ -1446,6 +1446,11 @@ static void RCTMeasureLayout(RCTShadowView *view, [_componentDataByName enumerateKeysAndObjectsUsingBlock:^(NSString *name, RCTComponentData *componentData, __unused BOOL *stop) { NSMutableDictionary *moduleConstants = [NSMutableDictionary new]; + // Register which event-types this view dispatches. + // React needs this for the event plugin. + NSMutableDictionary *bubblingEventTypes = [NSMutableDictionary new]; + NSMutableDictionary *directEventTypes = [NSMutableDictionary new]; + // Add manager class moduleConstants[@"Manager"] = RCTBridgeModuleNameForClass(componentData.managerClass); @@ -1453,6 +1458,8 @@ static void RCTMeasureLayout(RCTShadowView *view, NSDictionary *viewConfig = [componentData viewConfig]; moduleConstants[@"NativeProps"] = viewConfig[@"propTypes"]; moduleConstants[@"baseModuleName"] = viewConfig[@"baseModuleName"]; + moduleConstants[@"bubblingEventTypes"] = bubblingEventTypes; + moduleConstants[@"directEventTypes"] = directEventTypes; // Add direct events for (NSString *eventName in viewConfig[@"directEvents"]) { @@ -1461,6 +1468,7 @@ static void RCTMeasureLayout(RCTShadowView *view, @"registrationName": [eventName stringByReplacingCharactersInRange:(NSRange){0, 3} withString:@"on"], }; } + directEventTypes[eventName] = directEvents[eventName]; if (RCT_DEBUG && bubblingEvents[eventName]) { RCTLogError(@"Component '%@' re-registered bubbling event '%@' as a " "direct event", componentData.name, eventName); @@ -1478,6 +1486,7 @@ static void RCTMeasureLayout(RCTShadowView *view, } }; } + bubblingEventTypes[eventName] = bubblingEvents[eventName]; if (RCT_DEBUG && directEvents[eventName]) { RCTLogError(@"Component '%@' re-registered direct event '%@' as a " "bubbling event", componentData.name, eventName); @@ -1488,9 +1497,6 @@ static void RCTMeasureLayout(RCTShadowView *view, constants[name] = moduleConstants; }]; - constants[@"customBubblingEventTypes"] = bubblingEvents; - constants[@"customDirectEventTypes"] = directEvents; - return constants; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java index 9dd93ac82f1e2f..cd6f331eca248f 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java @@ -68,6 +68,15 @@ "onTouchEnd", "captured", "onTouchEndCapture"))) + .put( + TouchEventType.CANCEL.getJSEventName(), + MapBuilder.of( + "phasedRegistrationNames", + MapBuilder.of( + "bubbled", + "onTouchCancel", + "captured", + "onTouchCancelCapture"))) .build(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java index 825f81dfe3220e..a5c879d6661242 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java @@ -25,14 +25,10 @@ */ /* package */ class UIManagerModuleConstantsHelper { - private static final String CUSTOM_BUBBLING_EVENT_TYPES_KEY = "customBubblingEventTypes"; - private static final String CUSTOM_DIRECT_EVENT_TYPES_KEY = "customDirectEventTypes"; - /** - * Generates map of constants that is then exposed by {@link UIManagerModule}. The constants map - * contains the following predefined fields for 'customBubblingEventTypes' and - * 'customDirectEventTypes'. Provided list of {@param viewManagers} is then used to populate - * content of those predefined fields using + * Generates map of constants that is then exposed by {@link UIManagerModule}. + * Provided list of {@param viewManagers} is then used to populate content of + * those predefined fields using * {@link ViewManager#getExportedCustomBubblingEventTypeConstants} and * {@link ViewManager#getExportedCustomDirectEventTypeConstants} respectively. Each view manager * is in addition allowed to expose viewmanager-specific constants that are placed under the key @@ -53,15 +49,21 @@ .arg("ViewManager", viewManager.getName()) .flush(); try { + Map viewManagerConstants = MapBuilder.newHashMap(); Map viewManagerBubblingEvents = viewManager.getExportedCustomBubblingEventTypeConstants(); if (viewManagerBubblingEvents != null) { - recursiveMerge(bubblingEventTypesConstants, viewManagerBubblingEvents); + recursiveMerge(viewManagerBubblingEvents, bubblingEventTypesConstants); + viewManagerConstants.put("bubblingEventTypes", viewManagerBubblingEvents); + } else { + viewManagerConstants.put("bubblingEventTypes", bubblingEventTypesConstants); } Map viewManagerDirectEvents = viewManager.getExportedCustomDirectEventTypeConstants(); if (viewManagerDirectEvents != null) { - recursiveMerge(directEventTypesConstants, viewManagerDirectEvents); + recursiveMerge(viewManagerDirectEvents, directEventTypesConstants); + viewManagerConstants.put("directEventTypes", viewManagerDirectEvents); + } else { + viewManagerConstants.put("directEventTypes", directEventTypesConstants); } - Map viewManagerConstants = MapBuilder.newHashMap(); Map customViewConstants = viewManager.getExportedViewConstants(); if (customViewConstants != null) { viewManagerConstants.put("Constants", customViewConstants); @@ -82,8 +84,6 @@ } } - constants.put(CUSTOM_BUBBLING_EVENT_TYPES_KEY, bubblingEventTypesConstants); - constants.put(CUSTOM_DIRECT_EVENT_TYPES_KEY, directEventTypesConstants); constants.put("AndroidLazyViewManagersEnabled", lazyViewManagersEnabled); return constants; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 882cfa059238a5..4767db367cedb6 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -140,6 +140,14 @@ public Map getExportedCustomBubblingEventTypeConstants() { .build(); } + @Nullable + @Override + public Map getExportedCustomDirectEventTypeConstants() { + return MapBuilder.builder() + .put(ScrollEventType.SCROLL.getJSEventName(), MapBuilder.of("registrationName", "onScroll")) + .build(); + } + @Override public @Nullable Map getCommandsMap() { return MapBuilder.of("focusTextInput", FOCUS_TEXT_INPUT, "blurTextInput", BLUR_TEXT_INPUT);