From 906dde06b3f25b4e87adcbc8ed64f72bc930ac6a Mon Sep 17 00:00:00 2001 From: Sebastian Markbage Date: Tue, 10 Apr 2018 15:19:57 -0700 Subject: [PATCH] React sync for revisions 7a3416f...725c054 Reviewed By: bvaughn Differential Revision: D7565731 fbshipit-source-id: 91d76a11b7c91dab2fb3295418d1372ca9c1b572 --- Libraries/Components/View/FabricView.js | 102 +- Libraries/ReactNative/ReactFabricInternals.js | 8 +- .../ReactNative/requireFabricComponent.js | 10 +- .../ReactNative/requireNativeComponent.js | 6 - Libraries/Renderer/REVISION | 2 +- Libraries/Renderer/ReactFabric-dev.js | 1476 ++++++----------- Libraries/Renderer/ReactFabric-prod.js | 673 +++----- Libraries/Renderer/ReactNativeRenderer-dev.js | 1372 ++++++--------- .../Renderer/ReactNativeRenderer-prod.js | 600 +++---- .../shims/ReactNativeBridgeEventPlugin.js | 17 - Libraries/Renderer/shims/ReactNativeTypes.js | 23 +- .../shims/ReactNativeViewConfigRegistry.js | 106 ++ .../shims/createReactNativeComponentClass.js | 24 +- Libraries/Text/FabricText.js | 231 +-- 14 files changed, 1533 insertions(+), 3117 deletions(-) delete mode 100644 Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js create mode 100644 Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js diff --git a/Libraries/Components/View/FabricView.js b/Libraries/Components/View/FabricView.js index 4d686f7beb2..d5618905287 100644 --- a/Libraries/Components/View/FabricView.js +++ b/Libraries/Components/View/FabricView.js @@ -10,104 +10,4 @@ */ 'use strict'; -/** - * This is a temporary fork of View.js for Fabric purpose. - * Do not use outside of Fabric tree. - */ - -const Platform = require('Platform'); -const React = require('React'); -const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); -const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); -const ViewPropTypes = require('ViewPropTypes'); -const {NativeMethodsMixin} = require('ReactFabricInternals'); -const {ViewContextTypes} = require('ViewContext'); - -const createReactClass = require('create-react-class'); -const invariant = require('fbjs/lib/invariant'); -const requireFabricComponent = require('requireFabricComponent'); - -import type {ViewProps} from 'ViewPropTypes'; -import type {ViewChildContext} from 'ViewContext'; - -export type Props = ViewProps; - -/** - * The most fundamental component for building a UI. - * - * See http://facebook.github.io/react-native/docs/view.html - */ -const View = createReactClass({ - displayName: 'View', - // TODO: We should probably expose the mixins, viewConfig, and statics publicly. For example, - // one of the props is of type AccessibilityComponentType. That is defined as a const[] above, - // but it is not rendered by the docs, since `statics` below is not rendered. So its Possible - // values had to be hardcoded. - mixins: [NativeMethodsMixin], - - // `propTypes` should not be accessed directly on View since this wrapper only - // exists for DEV mode. However it's important for them to be declared. - // If the object passed to `createClass` specifies `propTypes`, Flow will - // create a static type from it. - propTypes: ViewPropTypes, - - /** - * `NativeMethodsMixin` will look for this when invoking `setNativeProps`. We - * make `this` look like an actual native component class. - */ - viewConfig: { - uiViewClassName: 'RCTView', - validAttributes: ReactNativeViewAttributes.RCTView, - }, - - childContextTypes: ViewContextTypes, - - getChildContext(): ViewChildContext { - return { - isInAParentText: false, - }; - }, - - render() { - invariant( - !(this.context.isInAParentText && Platform.OS === 'android'), - 'Nesting of within is not supported on Android.', - ); - - // WARNING: This method will not be used in production mode as in that mode we - // replace wrapper component View with generated native wrapper RCTView. Avoid - // adding functionality this component that you'd want to be available in both - // dev and prod modes. - return ; - }, -}); - -const RCTView = requireFabricComponent('RCTView', View, { - nativeOnly: { - nativeBackgroundAndroid: true, - nativeForegroundAndroid: true, - }, - fabric: true, -}); - -if (__DEV__) { - const UIManager = require('UIManager'); - const viewConfig = - (UIManager.viewConfigs && UIManager.viewConfigs.RCTView) || {}; - for (const prop in viewConfig.nativeProps) { - const viewAny: any = View; // Appease flow - if (!viewAny.propTypes[prop] && !ReactNativeStyleAttributes[prop]) { - throw new Error( - 'View is missing propType for native prop `' + prop + '`', - ); - } - } -} - -let ViewToExport = RCTView; -if (__DEV__) { - ViewToExport = View; -} - -// No one should depend on the DEV-mode createClass View wrapper. -module.exports = ((ViewToExport: any): typeof RCTView); +module.exports = require('View'); diff --git a/Libraries/ReactNative/ReactFabricInternals.js b/Libraries/ReactNative/ReactFabricInternals.js index d360803412a..72f37a41232 100644 --- a/Libraries/ReactNative/ReactFabricInternals.js +++ b/Libraries/ReactNative/ReactFabricInternals.js @@ -14,19 +14,15 @@ const { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, } = require('ReactFabric'); +const createReactNativeComponentClass = require('createReactNativeComponentClass'); import type {NativeMethodsMixinType} from 'ReactNativeTypes'; -const { - NativeMethodsMixin, - ReactNativeBridgeEventPlugin, - createReactNativeComponentClass, -} = __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; +const {NativeMethodsMixin} = __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; module.exports = { NativeMethodsMixin: ((NativeMethodsMixin: any): $Exact< NativeMethodsMixinType, >), - ReactNativeBridgeEventPlugin, createReactNativeComponentClass, }; diff --git a/Libraries/ReactNative/requireFabricComponent.js b/Libraries/ReactNative/requireFabricComponent.js index 4d9fca04cd5..dfd02bfeb61 100644 --- a/Libraries/ReactNative/requireFabricComponent.js +++ b/Libraries/ReactNative/requireFabricComponent.js @@ -11,10 +11,7 @@ 'use strict'; const Platform = require('Platform'); -const { - ReactNativeBridgeEventPlugin, - createReactNativeComponentClass, -} = require('ReactFabricInternals'); +const {createReactNativeComponentClass} = require('ReactFabricInternals'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const UIManager = require('UIManager'); @@ -200,11 +197,6 @@ function requireNativeComponent( hasAttachedDefaultEventTypes = true; } - // 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/ReactNative/requireNativeComponent.js b/Libraries/ReactNative/requireNativeComponent.js index 453be93f715..77141b1c049 100644 --- a/Libraries/ReactNative/requireNativeComponent.js +++ b/Libraries/ReactNative/requireNativeComponent.js @@ -11,7 +11,6 @@ 'use strict'; const Platform = require('Platform'); -const ReactNativeBridgeEventPlugin = require('ReactNativeBridgeEventPlugin'); const ReactNativeStyleAttributes = require('ReactNativeStyleAttributes'); const UIManager = require('UIManager'); @@ -198,11 +197,6 @@ function requireNativeComponent( hasAttachedDefaultEventTypes = true; } - // 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/REVISION b/Libraries/Renderer/REVISION index f505341495f..4d4db61db4a 100644 --- a/Libraries/Renderer/REVISION +++ b/Libraries/Renderer/REVISION @@ -1 +1 @@ -7a3416f27532ac25849dfbc505300d469b43bbcc \ No newline at end of file +52afbe0ebb6fca0fe480e77c6fa8482870ddb2c9 \ No newline at end of file diff --git a/Libraries/Renderer/ReactFabric-dev.js b/Libraries/Renderer/ReactFabric-dev.js index e51c0254b90..e933ab8f0bb 100644 --- a/Libraries/Renderer/ReactFabric-dev.js +++ b/Libraries/Renderer/ReactFabric-dev.js @@ -19,6 +19,7 @@ require("InitializeCore"); var invariant = require("fbjs/lib/invariant"); var warning = require("fbjs/lib/warning"); var emptyFunction = require("fbjs/lib/emptyFunction"); +var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); var UIManager = require("UIManager"); var TextInputState = require("TextInputState"); var deepDiffer = require("deepDiffer"); @@ -1294,7 +1295,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return { configurable: true, set: set, - get: get + get: get$$1 }; function set(val) { @@ -1303,7 +1304,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return val; } - function get() { + function get$$1() { var action = isFunction ? "accessing the method" : "accessing the property"; var result = isFunction ? "This is a no-op function" @@ -1620,7 +1621,7 @@ var changeResponder = function(nextResponderInst, blockHostResponder) { } }; -var eventTypes = { +var eventTypes$1 = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? @@ -1885,12 +1886,12 @@ function setResponderAndExtractTransfer( nativeEventTarget ) { var shouldSetEventType = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder + ? eventTypes$1.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder + ? eventTypes$1.moveShouldSetResponder : topLevelType === "topSelectionChange" - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst @@ -1924,7 +1925,7 @@ function setResponderAndExtractTransfer( } var extracted = void 0; var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, + eventTypes$1.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget @@ -1935,7 +1936,7 @@ function setResponderAndExtractTransfer( var blockHostResponder = executeDirectDispatch(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, + eventTypes$1.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -1952,7 +1953,7 @@ function setResponderAndExtractTransfer( if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, + eventTypes$1.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -1963,7 +1964,7 @@ function setResponderAndExtractTransfer( changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, + eventTypes$1.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2032,7 +2033,7 @@ var ResponderEventPlugin = { return responderInst; }, - eventTypes: eventTypes, + eventTypes: eventTypes$1, /** * We must be resilient to `targetInst` being `null` on `touchMove` or @@ -2082,10 +2083,10 @@ var ResponderEventPlugin = { var isResponderTouchMove = responderInst && isMoveish(topLevelType); var isResponderTouchEnd = responderInst && isEndish(topLevelType); var incrementalTouch = isResponderTouchStart - ? eventTypes.responderStart + ? eventTypes$1.responderStart : isResponderTouchMove - ? eventTypes.responderMove - : isResponderTouchEnd ? eventTypes.responderEnd : null; + ? eventTypes$1.responderMove + : isResponderTouchEnd ? eventTypes$1.responderEnd : null; if (incrementalTouch) { var gesture = ResponderSyntheticEvent.getPooled( @@ -2107,8 +2108,8 @@ var ResponderEventPlugin = { isEndish(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate - ? eventTypes.responderTerminate - : isResponderRelease ? eventTypes.responderRelease : null; + ? eventTypes$1.responderTerminate + : isResponderRelease ? eventTypes$1.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent.getPooled( finalTouch, @@ -2160,11 +2161,14 @@ var ResponderEventPlugin = { } }; -var customBubblingEventTypes = {}; -var customDirectEventTypes = {}; +var customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes; +var customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes; +var eventTypes$2 = ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: {}, + eventTypes: eventTypes$2, /** * @see {EventPluginHub.extractEvents} @@ -2179,8 +2183,8 @@ var ReactNativeBridgeEventPlugin = { // Probably a node belonging to another renderer's tree. return null; } - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; - var directDispatchConfig = customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType]; + var directDispatchConfig = customDirectEventTypes$1[topLevelType]; invariant( bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', @@ -2200,45 +2204,6 @@ var ReactNativeBridgeEventPlugin = { return null; } return event; - }, - - processEventTypes: function(viewConfig) { - var bubblingEventTypes = viewConfig.bubblingEventTypes, - directEventTypes = viewConfig.directEventTypes; - - { - if (bubblingEventTypes != null && directEventTypes != null) { - for (var topLevelType in directEventTypes) { - invariant( - bubblingEventTypes[topLevelType] == null, - "Event cannot be both direct and bubbling: %s", - topLevelType - ); - } - } - } - - if (bubblingEventTypes != null) { - for (var _topLevelType in bubblingEventTypes) { - if (customBubblingEventTypes[_topLevelType] == null) { - ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType - ] = customBubblingEventTypes[_topLevelType] = - bubblingEventTypes[_topLevelType]; - } - } - } - - if (directEventTypes != null) { - for (var _topLevelType2 in directEventTypes) { - if (customDirectEventTypes[_topLevelType2] == null) { - ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType2 - ] = customDirectEventTypes[_topLevelType2] = - directEventTypes[_topLevelType2]; - } - } - } } }; @@ -2402,56 +2367,6 @@ function createPortal( }; } -// Use to restore controlled state after a change event has fired. - -var fiberHostComponent = null; - -var restoreTarget = null; -var restoreQueue = null; - -function restoreStateOfTarget(target) { - // We perform this translation at the end of the event loop so that we - // always receive the correct fiber here - var internalInstance = getInstanceFromNode(target); - if (!internalInstance) { - // Unmounted - return; - } - invariant( - fiberHostComponent && - typeof fiberHostComponent.restoreControlledState === "function", - "Fiber needs to be injected to handle a fiber target for controlled " + - "events. This error is likely caused by a bug in React. Please file an issue." - ); - var props = getFiberCurrentPropsFromNode(internalInstance.stateNode); - fiberHostComponent.restoreControlledState( - internalInstance.stateNode, - internalInstance.type, - props - ); -} - -function needsStateRestore() { - return restoreTarget !== null || restoreQueue !== null; -} - -function restoreStateIfNeeded() { - if (!restoreTarget) { - return; - } - var target = restoreTarget; - var queuedTargets = restoreQueue; - restoreTarget = null; - restoreQueue = null; - - restoreStateOfTarget(target); - if (queuedTargets) { - for (var i = 0; i < queuedTargets.length; i++) { - restoreStateOfTarget(queuedTargets[i]); - } - } -} - // Used as a way to call batchedUpdates when we don't have a reference to // the renderer. Such as when we're dispatching events or if third party // libraries need to call batchedUpdates. Eventually, this API will go away when @@ -2467,33 +2382,6 @@ var _interactiveUpdates = function(fn, a, b) { }; var _flushInteractiveUpdates = function() {}; -var isBatching = false; -function batchedUpdates(fn, bookkeeping) { - if (isBatching) { - // If we are currently inside another batch, we need to wait until it - // fully completes before restoring state. - return fn(bookkeeping); - } - isBatching = true; - try { - return _batchedUpdates(fn, bookkeeping); - } finally { - // Here we wait until all updates have propagated, which is important - // when using controlled components within layers: - // https://github.com/facebook/react/issues/1698 - // Then we restore state of any controlled component. - isBatching = false; - var controlledComponentsHavePendingUpdates = needsStateRestore(); - if (controlledComponentsHavePendingUpdates) { - // If a controlled event was fired, we may need to restore the state of - // the DOM node back to the controlled value. This is necessary when React - // bails out of the update without touching the DOM. - _flushInteractiveUpdates(); - restoreStateIfNeeded(); - } - } -} - var injection$2 = { injectRenderer: function(renderer) { _batchedUpdates = renderer.batchedUpdates; @@ -2502,195 +2390,10 @@ var injection$2 = { } }; -var TouchHistoryMath = { - /** - * This code is optimized and not intended to look beautiful. This allows - * computing of touch centroids that have moved after `touchesChangedAfter` - * timeStamp. You can compute the current centroid involving all touches - * moves after `touchesChangedAfter`, or you can compute the previous - * centroid of all touches that were moved after `touchesChangedAfter`. - * - * @param {TouchHistoryMath} touchHistory Standard Responder touch track - * data. - * @param {number} touchesChangedAfter timeStamp after which moved touches - * are considered "actively moving" - not just "active". - * @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension. - * @param {boolean} ofCurrent Compute current centroid for actively moving - * touches vs. previous centroid of now actively moving touches. - * @return {number} value of centroid in specified dimension. - */ - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank; - var total = 0; - var count = 0; - - var oneTouchData = - touchHistory.numberActiveTouches === 1 - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - - if (oneTouchData !== null) { - if ( - oneTouchData.touchActive && - oneTouchData.currentTimeStamp > touchesChangedAfter - ) { - total += - ofCurrent && isXAxis - ? oneTouchData.currentPageX - : ofCurrent && !isXAxis - ? oneTouchData.currentPageY - : !ofCurrent && isXAxis - ? oneTouchData.previousPageX - : oneTouchData.previousPageY; - count = 1; - } - } else { - for (var i = 0; i < touchBank.length; i++) { - var touchTrack = touchBank[i]; - if ( - touchTrack !== null && - touchTrack !== undefined && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter - ) { - var toAdd = void 0; // Yuck, program temporarily in invalid state. - if (ofCurrent && isXAxis) { - toAdd = touchTrack.currentPageX; - } else if (ofCurrent && !isXAxis) { - toAdd = touchTrack.currentPageY; - } else if (!ofCurrent && isXAxis) { - toAdd = touchTrack.previousPageX; - } else { - toAdd = touchTrack.previousPageY; - } - total += toAdd; - count++; - } - } - } - return count > 0 ? total / count : TouchHistoryMath.noCentroid; - }, - - currentCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - true, // isXAxis - true - ); - }, - - currentCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - false, // isXAxis - true - ); - }, - - previousCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - true, // isXAxis - false - ); - }, - - previousCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - false, // isXAxis - false - ); - }, - - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension( - touchHistory, - 0, // touchesChangedAfter - true, // isXAxis - true - ); - }, - - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension( - touchHistory, - 0, // touchesChangedAfter - false, // isXAxis - true - ); - }, - - noCentroid: -1 -}; - // TODO: this is special because it gets imported during build. var ReactVersion = "16.3.1"; -function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} - -var objects = {}; -var uniqueID = 1; -var emptyObject$2 = {}; - -var ReactNativePropRegistry = (function() { - function ReactNativePropRegistry() { - _classCallCheck(this, ReactNativePropRegistry); - } - - ReactNativePropRegistry.register = function register(object) { - var id = ++uniqueID; - { - Object.freeze(object); - } - objects[id] = object; - return id; - }; - - ReactNativePropRegistry.getByID = function getByID(id) { - if (!id) { - // Used in the style={[condition && id]} pattern, - // we want it to be a no-op when the value is false or null - return emptyObject$2; - } - - var object = objects[id]; - if (!object) { - console.warn("Invalid style with id `" + id + "`. Skipping ..."); - return emptyObject$2; - } - return object; - }; - - return ReactNativePropRegistry; -})(); - // Modules provided by RN: var emptyObject$1 = {}; @@ -2717,13 +2420,6 @@ function defaultDiffer(prevProp, nextProp) { } } -function resolveObject(idOrObject) { - if (typeof idOrObject === "number") { - return ReactNativePropRegistry.getByID(idOrObject); - } - return idOrObject; -} - function restoreDeletedValuesInNestedArray( updatePayload, node, @@ -2739,7 +2435,7 @@ function restoreDeletedValuesInNestedArray( ); } } else if (node && removedKeyCount > 0) { - var obj = resolveObject(node); + var obj = node; for (var propKey in removedKeys) { if (!removedKeys[propKey]) { continue; @@ -2843,12 +2539,7 @@ function diffNestedProperty( if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) { // Both are leaves, we can diff the leaves. - return diffProperties( - updatePayload, - resolveObject(prevProp), - resolveObject(nextProp), - validAttributes - ); + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); } if (Array.isArray(prevProp) && Array.isArray(nextProp)) { @@ -2867,14 +2558,14 @@ function diffNestedProperty( // $FlowFixMe - We know that this is always an object when the input is. flattenStyle(prevProp), // $FlowFixMe - We know that this isn't an array because of above flow. - resolveObject(nextProp), + nextProp, validAttributes ); } return diffProperties( updatePayload, - resolveObject(prevProp), + prevProp, // $FlowFixMe - We know that this is always an object when the input is. flattenStyle(nextProp), validAttributes @@ -2893,11 +2584,7 @@ function addNestedProperty(updatePayload, nextProp, validAttributes) { if (!Array.isArray(nextProp)) { // Add each property of the leaf. - return addProperties( - updatePayload, - resolveObject(nextProp), - validAttributes - ); + return addProperties(updatePayload, nextProp, validAttributes); } for (var i = 0; i < nextProp.length; i++) { @@ -2923,11 +2610,7 @@ function clearNestedProperty(updatePayload, prevProp, validAttributes) { if (!Array.isArray(prevProp)) { // Add each property of the leaf. - return clearProperties( - updatePayload, - resolveObject(prevProp), - validAttributes - ); + return clearProperties(updatePayload, prevProp, validAttributes); } for (var i = 0; i < prevProp.length; i++) { @@ -3214,361 +2897,195 @@ function warnForStyleProps(props, validAttributes) { } } -/** - * `ReactInstanceMap` maintains a mapping from a public facing stateful - * instance (key) and the internal representation (value). This allows public - * methods to accept the user facing instance as an argument and map them back - * to internal methods. - * - * Note that this module is currently shared and assumed to be stateless. - * If this becomes an actual Map, that will break. - */ - -/** - * This API should be called `delete` but we'd have to make sure to always - * transform these to strings for IE support. When this transform is fully - * supported we can rename it. - */ - -function get(key) { - return key._reactInternalFiber; -} - -function set(key, value) { - key._reactInternalFiber = value; -} - -var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; -var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; - -function getComponentName(fiber) { - var type = fiber.type; - - if (typeof type === "function") { - return type.displayName || type.name; - } - if (typeof type === "string") { - return type; - } - switch (type) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - return null; -} - -// TODO: Share this module between Fabric and React Native renderers -// so that both can be used in the same tree. - -var findHostInstance = function(fiber) { - return null; -}; - -var findHostInstanceFabric = function(fiber) { - return null; -}; - -function injectFindHostInstanceFabric(impl) { - findHostInstanceFabric = impl; -} - -/** - * ReactNative vs ReactWeb - * ----------------------- - * React treats some pieces of data opaquely. This means that the information - * is first class (it can be passed around), but cannot be inspected. This - * allows us to build infrastructure that reasons about resources, without - * making assumptions about the nature of those resources, and this allows that - * infra to be shared across multiple platforms, where the resources are very - * different. General infra (such as `ReactMultiChild`) reasons opaquely about - * the data, but platform specific code (such as `ReactNativeBaseComponent`) can - * make assumptions about the data. - * - * - * `rootNodeID`, uniquely identifies a position in the generated native view - * tree. Many layers of composite components (created with `React.createClass`) - * can all share the same `rootNodeID`. - * - * `nodeHandle`: A sufficiently unambiguous way to refer to a lower level - * resource (dom node, native view etc). The `rootNodeID` is sufficient for web - * `nodeHandle`s, because the position in a tree is always enough to uniquely - * identify a DOM node (we never have nodes in some bank outside of the - * document). The same would be true for `ReactNative`, but we must maintain a - * mapping that we can send efficiently serializable - * strings across native boundaries. - * - * Opaque name TodaysWebReact FutureWebWorkerReact ReactNative - * ---------------------------------------------------------------------------- - * nodeHandle N/A rootNodeID tag - */ - -// TODO (bvaughn) Rename the findNodeHandle module to something more descriptive -// eg findInternalHostInstance. This will reduce the likelihood of someone -// accidentally deep-requiring this version. -function findNodeHandle(componentOrHandle) { - { - var owner = ReactCurrentOwner.current; - if (owner !== null && owner.stateNode !== null) { - !owner.stateNode._warnedAboutRefsInRender - ? warning( - false, - "%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(owner) || "A component" - ) - : void 0; - - owner.stateNode._warnedAboutRefsInRender = true; - } - } - if (componentOrHandle == null) { - return null; - } - if (typeof componentOrHandle === "number") { - // Already a node handle - return componentOrHandle; - } - - var component = componentOrHandle; - - // TODO (balpert): Wrap iOS native components in a composite wrapper, then - // ReactInstanceMap.get here will always succeed for mounted components - var internalInstance = get(component); - if (internalInstance) { - return ( - findHostInstance(internalInstance) || - findHostInstanceFabric(internalInstance) - ); - } else { - if (component) { - return component; - } else { - invariant( - // Native - (typeof component === "object" && "_nativeTag" in component) || - // Composite - (component.render != null && typeof component.render === "function"), - "findNodeHandle(...): Argument is not a component " + - "(type: %s, keys: %s)", - typeof component, - Object.keys(component) - ); - invariant( - false, - "findNodeHandle(...): Unable to find node handle for unmounted " + - "component." - ); - } - } -} - -/** - * External users of findNodeHandle() expect the host tag number return type. - * The injected findNodeHandle() strategy returns the instance wrapper though. - * See NativeMethodsMixin#setNativeProps for more info on why this is done. - */ -function findNumericNodeHandleFiber(componentOrHandle) { - var instance = findNodeHandle(componentOrHandle); - if (instance == null || typeof instance === "number") { - return instance; - } - return instance._nativeTag; -} - // Modules provided by RN: -/** - * `NativeMethodsMixin` provides methods to access the underlying native - * component directly. This can be useful in cases when you want to focus - * a view or measure its on-screen dimensions, for example. - * - * The methods described here are available on most of the default components - * provided by React Native. Note, however, that they are *not* available on - * composite components that aren't directly backed by a native view. This will - * generally include most components that you define in your own app. For more - * information, see [Direct - * Manipulation](docs/direct-manipulation.html). - * - * Note the Flow $Exact<> syntax is required to support mixins. - * React createClass mixins can only be used with exact types. - */ -var NativeMethodsMixin = { +var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { /** - * Determines the location on screen, width, and height of the given view and - * returns the values via an async callback. If successful, the callback will - * be called with the following arguments: + * `NativeMethodsMixin` provides methods to access the underlying native + * component directly. This can be useful in cases when you want to focus + * a view or measure its on-screen dimensions, for example. * - * - x - * - y - * - width - * - height - * - pageX - * - pageY + * The methods described here are available on most of the default components + * provided by React Native. Note, however, that they are *not* available on + * composite components that aren't directly backed by a native view. This will + * generally include most components that you define in your own app. For more + * information, see [Direct + * Manipulation](docs/direct-manipulation.html). * - * Note that these measurements are not available until after the rendering - * has been completed in native. If you need the measurements as soon as - * possible, consider using the [`onLayout` - * prop](docs/view.html#onlayout) instead. + * Note the Flow $Exact<> syntax is required to support mixins. + * React createClass mixins can only be used with exact types. */ - measure: function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - - /** - * Determines the location of the given view in the window and returns the - * values via an async callback. If the React root view is embedded in - * another native view, this will give you the absolute coordinates. If - * successful, the callback will be called with the following - * arguments: - * - * - x - * - y - * - width - * - height - * - * Note that these measurements are not available until after the rendering - * has been completed in native. - */ - measureInWindow: function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - - /** - * Like [`measure()`](#measure), but measures the view relative an ancestor, - * specified as `relativeToNativeNode`. This means that the returned x, y - * are relative to the origin x, y of the ancestor view. - * - * As always, to obtain a native node handle for a component, you can use - * `findNumericNodeHandle(component)`. - */ - measureLayout: function( - relativeToNativeNode, - onSuccess, - onFail /* currently unused */ - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, - - /** - * This function sends props straight to native. They will not participate in - * future diff process - this means that if you do not include them in the - * next render, they will remain active (see [Direct - * Manipulation](docs/direct-manipulation.html)). - */ - setNativeProps: function(nativeProps) { - // Class components don't have viewConfig -> validateAttributes. - // Nor does it make sense to set native props on a non-native component. - // Instead, find the nearest host component and set props on it. - // Use findNodeHandle() rather than findNumericNodeHandle() because - // We want the instance/wrapper (not the native tag). - var maybeInstance = void 0; - - // Fiber errors if findNodeHandle is called for an umounted component. - // Tests using ReactTestRenderer will trigger this case indirectly. - // Mimicking stack behavior, we should silently ignore this case. - // TODO Fix ReactTestRenderer so we can remove this try/catch. - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - - // If there is no host component beneath this we should fail silently. - // This is not an error; it could mean a class component rendered null. - if (maybeInstance == null) { - return; - } - - var viewConfig = maybeInstance.viewConfig; - - { - warnForStyleProps(nativeProps, viewConfig.validAttributes); - } - - var updatePayload = create(nativeProps, viewConfig.validAttributes); - - // Avoid the overhead of bridge calls if there's no update. - // This is an expensive no-op for Android, and causes an unnecessary - // view invalidation for certain components (eg RCTTextInput) on iOS. - if (updatePayload != null) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload + var NativeMethodsMixin = { + /** + * Determines the location on screen, width, and height of the given view and + * returns the values via an async callback. If successful, the callback will + * be called with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * Note that these measurements are not available until after the rendering + * has been completed in native. If you need the measurements as soon as + * possible, consider using the [`onLayout` + * prop](docs/view.html#onlayout) instead. + */ + measure: function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) ); + }, + + /** + * Determines the location of the given view in the window and returns the + * values via an async callback. If the React root view is embedded in + * another native view, this will give you the absolute coordinates. If + * successful, the callback will be called with the following + * arguments: + * + * - x + * - y + * - width + * - height + * + * Note that these measurements are not available until after the rendering + * has been completed in native. + */ + measureInWindow: function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + + /** + * Like [`measure()`](#measure), but measures the view relative an ancestor, + * specified as `relativeToNativeNode`. This means that the returned x, y + * are relative to the origin x, y of the ancestor view. + * + * As always, to obtain a native node handle for a component, you can use + * `findNodeHandle(component)`. + */ + measureLayout: function( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }, + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + setNativeProps: function(nativeProps) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + var viewConfig = maybeInstance.viewConfig; + + { + warnForStyleProps(nativeProps, viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }, + + /** + * Requests focus for the given input or view. The exact behavior triggered + * will depend on the platform and type of view. + */ + focus: function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); } - }, + }; - /** - * Requests focus for the given input or view. The exact behavior triggered - * will depend on the platform and type of view. - */ - focus: function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }, + { + // hide this from Flow since we can't define these properties outside of + // true without actually implementing them (setting them to undefined + // isn't allowed by ReactClass) + var NativeMethodsMixin_DEV = NativeMethodsMixin; + invariant( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, + "Do not override existing functions." + ); + // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, + // Once these lifecycles have been remove from the reconciler. + NativeMethodsMixin_DEV.componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) { + throwOnStylesProp(this, newProps); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function( + newProps + ) { + throwOnStylesProp(this, newProps); + }; - /** - * Removes focus from an input or view. This is the opposite of `focus()`. - */ - blur: function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); + // React may warn about cWM/cWRP/cWU methods being deprecated. + // Add a flag to suppress these warnings for this special case. + // TODO (bvaughn) Remove this flag once the above methods have been removed. + NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; + NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; } + + return NativeMethodsMixin; }; -{ - // hide this from Flow since we can't define these properties outside of - // true without actually implementing them (setting them to undefined - // isn't allowed by ReactClass) - var NativeMethodsMixin_DEV = NativeMethodsMixin; - invariant( - !NativeMethodsMixin_DEV.componentWillMount && - !NativeMethodsMixin_DEV.componentWillReceiveProps && - !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && - !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, - "Do not override existing functions." - ); - // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, - // Once these lifecycles have been remove from the reconciler. - NativeMethodsMixin_DEV.componentWillMount = function() { - throwOnStylesProp(this, this.props); - }; - NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) { - throwOnStylesProp(this, newProps); - }; - NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() { - throwOnStylesProp(this, this.props); - }; - NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function(newProps) { - throwOnStylesProp(this, newProps); - }; - - // React may warn about cWM/cWRP/cWU methods being deprecated. - // Add a flag to suppress these warnings for this special case. - // TODO (bvaughn) Remove this flag once the above methods have been removed. - NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; - NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; -} - -function _classCallCheck$1(instance, Constructor) { +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } @@ -3607,166 +3124,171 @@ function _inherits(subClass, superClass) { } // Modules provided by RN: -/** - * Superclass that provides methods to access the underlying native component. - * This can be useful when you want to focus a view or measure its dimensions. - * - * Methods implemented by this class are available on most default components - * provided by React Native. However, they are *not* available on composite - * components that are not directly backed by a native view. For more - * information, see [Direct Manipulation](docs/direct-manipulation.html). - * - * @abstract - */ - -var ReactNativeComponent = (function(_React$Component) { - _inherits(ReactNativeComponent, _React$Component); - - function ReactNativeComponent() { - _classCallCheck$1(this, ReactNativeComponent); - - return _possibleConstructorReturn( - this, - _React$Component.apply(this, arguments) - ); - } - +var ReactNativeComponent = function(findNodeHandle, findHostInstance) { /** - * Removes focus. This is the opposite of `focus()`. - */ - - /** - * Due to bugs in Flow's handling of React.createClass, some fields already - * declared in the base class need to be redeclared below. - */ - ReactNativeComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - }; - - /** - * Requests focus. The exact behavior depends on the platform and view. - */ - - ReactNativeComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }; - - /** - * Measures the on-screen location and dimensions. If successful, the callback - * will be called asynchronously with the following arguments: + * Superclass that provides methods to access the underlying native component. + * This can be useful when you want to focus a view or measure its dimensions. * - * - x - * - y - * - width - * - height - * - pageX - * - pageY + * Methods implemented by this class are available on most default components + * provided by React Native. However, they are *not* available on composite + * components that are not directly backed by a native view. For more + * information, see [Direct Manipulation](docs/direct-manipulation.html). * - * These values are not available until after natives rendering completes. If - * you need the measurements as soon as possible, consider using the - * [`onLayout` prop](docs/view.html#onlayout) instead. + * @abstract */ + var ReactNativeComponent = (function(_React$Component) { + _inherits(ReactNativeComponent, _React$Component); - ReactNativeComponent.prototype.measure = function measure(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; + function ReactNativeComponent() { + _classCallCheck(this, ReactNativeComponent); - /** - * Measures the on-screen location and dimensions. Even if the React Native - * root view is embedded within another native view, this method will give you - * the absolute coordinates measured from the window. If successful, the - * callback will be called asynchronously with the following arguments: - * - * - x - * - y - * - width - * - height - * - * These values are not available until after natives rendering completes. - */ - - ReactNativeComponent.prototype.measureInWindow = function measureInWindow( - callback - ) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - - /** - * Similar to [`measure()`](#measure), but the resulting location will be - * relative to the supplied ancestor's location. - * - * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. - */ - - ReactNativeComponent.prototype.measureLayout = function measureLayout( - relativeToNativeNode, - onSuccess, - onFail /* currently unused */ - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - - /** - * This function sends props straight to native. They will not participate in - * future diff process - this means that if you do not include them in the - * next render, they will remain active (see [Direct - * Manipulation](docs/direct-manipulation.html)). - */ - - ReactNativeComponent.prototype.setNativeProps = function setNativeProps( - nativeProps - ) { - // Class components don't have viewConfig -> validateAttributes. - // Nor does it make sense to set native props on a non-native component. - // Instead, find the nearest host component and set props on it. - // Use findNodeHandle() rather than ReactNative.findNodeHandle() because - // We want the instance/wrapper (not the native tag). - var maybeInstance = void 0; - - // Fiber errors if findNodeHandle is called for an umounted component. - // Tests using ReactTestRenderer will trigger this case indirectly. - // Mimicking stack behavior, we should silently ignore this case. - // TODO Fix ReactTestRenderer so we can remove this try/catch. - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - - // If there is no host component beneath this we should fail silently. - // This is not an error; it could mean a class component rendered null. - if (maybeInstance == null) { - return; - } - - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - - var updatePayload = create(nativeProps, viewConfig.validAttributes); - - // Avoid the overhead of bridge calls if there's no update. - // This is an expensive no-op for Android, and causes an unnecessary - // view invalidation for certain components (eg RCTTextInput) on iOS. - if (updatePayload != null) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload + return _possibleConstructorReturn( + this, + _React$Component.apply(this, arguments) ); } - }; + + /** + * Removes focus. This is the opposite of `focus()`. + */ + + /** + * Due to bugs in Flow's handling of React.createClass, some fields already + * declared in the base class need to be redeclared below. + */ + ReactNativeComponent.prototype.blur = function blur() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + + /** + * Requests focus. The exact behavior depends on the platform and view. + */ + + ReactNativeComponent.prototype.focus = function focus() { + TextInputState.focusTextInput(findNodeHandle(this)); + }; + + /** + * Measures the on-screen location and dimensions. If successful, the callback + * will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * These values are not available until after natives rendering completes. If + * you need the measurements as soon as possible, consider using the + * [`onLayout` prop](docs/view.html#onlayout) instead. + */ + + ReactNativeComponent.prototype.measure = function measure(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + + /** + * Measures the on-screen location and dimensions. Even if the React Native + * root view is embedded within another native view, this method will give you + * the absolute coordinates measured from the window. If successful, the + * callback will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * + * These values are not available until after natives rendering completes. + */ + + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + + /** + * Similar to [`measure()`](#measure), but the resulting location will be + * relative to the supplied ancestor's location. + * + * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. + */ + + ReactNativeComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + + ReactNativeComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than ReactNative.findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions return ReactNativeComponent; -})(React.Component); +}; var hasNativePerformanceNow = typeof performance === "object" && typeof performance.now === "function"; @@ -3817,47 +3339,55 @@ function cancelDeferredCallback(callbackID) { clearTimeout(callbackID); } -var viewConfigCallbacks = new Map(); -var viewConfigs = new Map(); +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ /** - * Registers a native view/component by name. - * A callback is provided to load the view config from UIManager. - * The callback is deferred until the view is actually rendered. - * This is done to avoid causing Prepack deopts. + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. */ -function register(name, callback) { - invariant( - !viewConfigCallbacks.has(name), - "Tried to register two views with the same name %s", - name - ); - viewConfigCallbacks.set(name, callback); - return name; + +function get$1(key) { + return key._reactInternalFiber; } -/** - * Retrieves a config for the specified view. - * If this is the first time the view has been used, - * This configuration will be lazy-loaded from UIManager. - */ -function get$1(name) { - var viewConfig = void 0; - if (!viewConfigs.has(name)) { - var callback = viewConfigCallbacks.get(name); - invariant( - typeof callback === "function", - "View config not found for name %s", - name - ); - viewConfigCallbacks.set(name, null); - viewConfig = callback(); - viewConfigs.set(name, viewConfig); - } else { - viewConfig = viewConfigs.get(name); +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; +var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; + +function getComponentName(fiber) { + var type = fiber.type; + + if (typeof type === "function") { + return type.displayName || type.name; } - invariant(viewConfig, "View config not found for name %s", name); - return viewConfig; + if (typeof type === "string") { + return type; + } + switch (type) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + return null; } // Don't change these two values. They're used by React Dev Tools. @@ -3940,7 +3470,7 @@ function isMounted(component) { } } - var fiber = get(component); + var fiber = get$1(component); if (!fiber) { return false; } @@ -5947,7 +5477,7 @@ var ReactFiberClassComponent = function( var updater = { isMounted: isMounted, enqueueSetState: function(instance, partialState, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "setState"); @@ -5966,7 +5496,7 @@ var ReactFiberClassComponent = function( scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function(instance, state, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "replaceState"); @@ -5985,7 +5515,7 @@ var ReactFiberClassComponent = function( scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function(instance, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "forceUpdate"); @@ -9418,7 +8948,7 @@ var ReactFiberCompleteWork = function( function markUpdate(workInProgress) { // Tag the fiber with an update effect. This turns a Placement into - // an UpdateAndPlacement. + // a PlacementAndUpdate. workInProgress.effectTag |= Update; } @@ -13584,7 +13114,7 @@ var ReactFiberReconciler$1 = function(config) { return emptyObject; } - var fiber = get(parentComponent); + var fiber = get$1(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); return isContextProvider(fiber) ? processChildContext(fiber, parentContext) @@ -13682,7 +13212,19 @@ var ReactFiberReconciler$1 = function(config) { ); } - function findHostInstance(fiber) { + function findHostInstance(component) { + var fiber = get$1(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + invariant(false, "Unable to find node on an unmounted component."); + } else { + invariant( + false, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + ); + } + } var hostFiber = findCurrentHostFiber(fiber); if (hostFiber === null) { return null; @@ -13775,7 +13317,11 @@ var ReactFiberReconciler$1 = function(config) { return injectInternals( Object.assign({}, devToolsConfig, { findHostInstanceByFiber: function(fiber) { - return findHostInstance(fiber); + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; }, findFiberByHostInstance: function(instance) { if (!findFiberByHostInstance) { @@ -13805,62 +13351,26 @@ var reactReconciler = ReactFiberReconciler$3["default"] ? ReactFiberReconciler$3["default"] : ReactFiberReconciler$3; -/** - * Keeps track of allocating and associating native "tags" which are numeric, - * unique view IDs. All the native tags are negative numbers, to avoid - * collisions, but in the JS we keep track of them as positive integers to store - * them effectively in Arrays. So we must refer to them as "inverses" of the - * native tags (that are * normally negative). - * - * It *must* be the case that every `rootNodeID` always maps to the exact same - * `tag` forever. The easiest way to accomplish this is to never delete - * anything from this table. - * Why: Because `dangerouslyReplaceNodeWithMarkupByID` relies on being able to - * unmount a component with a `rootNodeID`, then mount a new one in its place, - */ -var INITIAL_TAG_COUNT = 1; -var ReactNativeTagHandles = { - tagsStartAt: INITIAL_TAG_COUNT, - tagCount: INITIAL_TAG_COUNT, - - allocateTag: function() { - // Skip over root IDs as those are reserved for native - while (this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount)) { - ReactNativeTagHandles.tagCount++; - } - var tag = ReactNativeTagHandles.tagCount; - ReactNativeTagHandles.tagCount++; - return tag; - }, - - assertRootTag: function(tag) { - invariant( - this.reactTagIsNativeTopRootID(tag), - "Expect a native root tag, instead got %s", - tag - ); - }, - - reactTagIsNativeTopRootID: function(reactTag) { - // We reserve all tags that are 1 mod 10 for native root views - return reactTag % 10 === 1; - } -}; - -function _classCallCheck$2(instance, Constructor) { +function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // Modules provided by RN: +// Counter for uniquely identifying views. +// % 10 === 1 means it is a rootTag. +// % 2 === 0 means it is a Fabric tag. +// This means that they never overlap. +var nextReactTag = 2; + /** * This is used for refs on host components. */ var ReactFabricHostComponent = (function() { function ReactFabricHostComponent(tag, viewConfig, props) { - _classCallCheck$2(this, ReactFabricHostComponent); + _classCallCheck$1(this, ReactFabricHostComponent); this._nativeTag = tag; this.viewConfig = viewConfig; @@ -13936,8 +13446,10 @@ var ReactFabricRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - var tag = ReactNativeTagHandles.allocateTag(); - var viewConfig = get$1(type); + var tag = nextReactTag; + nextReactTag += 2; + + var viewConfig = ReactNativeViewConfigRegistry.get(type); { for (var key in viewConfig.validAttributes) { @@ -13970,7 +13482,8 @@ var ReactFabricRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - var tag = ReactNativeTagHandles.allocateTag(); + var tag = nextReactTag; + nextReactTag += 2; var node = FabricUIManager.createNode( tag, // reactTag @@ -14190,56 +13703,59 @@ var getInspectorDataForViewTag = void 0; }; } -/** - * Creates a renderable ReactNative host component. - * Use this method for view configs that are loaded from UIManager. - * Use createReactNativeComponentClass() for view configs defined within JavaScript. - * - * @param {string} config iOS View configuration. - * @private - */ -var createReactNativeComponentClass = function(name, callback) { - return register(name, callback); -}; +var findHostInstance = ReactFabricRenderer.findHostInstance; -// Module provided by RN: -/** - * Capture an image of the screen, window or an individual view. The image - * will be stored in a temporary file that will only exist for as long as the - * app is running. - * - * The `view` argument can be the literal string `window` if you want to - * capture the entire window, or it can be a reference to a specific - * React Native component. - * - * The `options` argument may include: - * - width/height (number) - the width and height of the image to capture. - * - format (string) - either 'png' or 'jpeg'. Defaults to 'png'. - * - quality (number) - the quality when using jpeg. 0.0 - 1.0 (default). - * - * Returns a Promise. - * @platform ios - */ -function takeSnapshot(view, options) { - if (typeof view !== "number" && view !== "window") { - view = findNumericNodeHandleFiber(view) || "window"; +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warning( + false, + "%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(owner) || "A component" + ) + : void 0; + + owner.stateNode._warnedAboutRefsInRender = true; + } } - - // Call the hidden '__takeSnapshot' method; the main one throws an error to - // prevent accidental backwards-incompatible usage. - return UIManager.__takeSnapshot(view, options); + if (componentOrHandle == null) { + return null; + } + if (typeof componentOrHandle === "number") { + // Already a node handle + return componentOrHandle; + } + if (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) { + return componentOrHandle.canonical._nativeTag; + } + var hostInstance = findHostInstance(componentOrHandle); + if (hostInstance == null) { + return hostInstance; + } + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; } -injectFindHostInstanceFabric(ReactFabricRenderer.findHostInstance); - injection$2.injectRenderer(ReactFabricRenderer); var roots = new Map(); var ReactFabric = { - NativeComponent: ReactNativeComponent, + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), - findNodeHandle: findNumericNodeHandleFiber, + findNodeHandle: findNodeHandle, render: function(element, containerTag, callback) { var root = roots.get(containerTag); @@ -14263,9 +13779,6 @@ var ReactFabric = { }); } }, - unmountComponentAtNodeAndRemoveContainer: function(containerTag) { - ReactFabric.unmountComponentAtNode(containerTag); - }, createPortal: function(children, containerTag) { var key = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; @@ -14273,20 +13786,11 @@ var ReactFabric = { return createPortal(children, containerTag, null, key); }, - unstable_batchedUpdates: batchedUpdates, - - flushSync: ReactFabricRenderer.flushSync, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { // Used as a mixin in many createClass-based components - NativeMethodsMixin: NativeMethodsMixin, + NativeMethodsMixin: NativeMethodsMixin(findNodeHandle, findHostInstance), // Used by react-native-github/Libraries/ components - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, // requireNativeComponent - ReactNativeComponentTree: ReactNativeComponentTree, // ScrollResponder - ReactNativePropRegistry: ReactNativePropRegistry, // flattenStyle, Stylesheet - TouchHistoryMath: TouchHistoryMath, // PanResponder - createReactNativeComponentClass: createReactNativeComponentClass, // RCTText, RCTView, ReactNativeART - takeSnapshot: takeSnapshot + ReactNativeComponentTree: ReactNativeComponentTree } }; diff --git a/Libraries/Renderer/ReactFabric-prod.js b/Libraries/Renderer/ReactFabric-prod.js index c57d9bb9d0c..d264fcf0163 100644 --- a/Libraries/Renderer/ReactFabric-prod.js +++ b/Libraries/Renderer/ReactFabric-prod.js @@ -13,6 +13,7 @@ require("InitializeCore"); var invariant = require("fbjs/lib/invariant"), emptyFunction = require("fbjs/lib/emptyFunction"), + ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), UIManager = require("UIManager"), TextInputState = require("TextInputState"), deepDiffer = require("deepDiffer"), @@ -528,7 +529,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes = { +var eventTypes$1 = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -568,7 +569,7 @@ var eventTypes = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes, + eventTypes: eventTypes$1, extractEvents: function( topLevelType, targetInst, @@ -594,12 +595,12 @@ var eventTypes = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder + ? eventTypes$1.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder + ? eventTypes$1.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -685,7 +686,7 @@ var eventTypes = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, + eventTypes$1.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -695,7 +696,7 @@ var eventTypes = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, + eventTypes$1.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -707,7 +708,7 @@ var eventTypes = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, + eventTypes$1.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -721,7 +722,7 @@ var eventTypes = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, + eventTypes$1.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -749,10 +750,10 @@ var eventTypes = { depthA = responderInst && isEndish(topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes.responderStart + ? eventTypes$1.responderStart : targetInst - ? eventTypes.responderMove - : depthA ? eventTypes.responderEnd : null) + ? eventTypes$1.responderMove + : depthA ? eventTypes$1.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( JSCompiler_temp$jscomp$0, @@ -803,8 +804,8 @@ var eventTypes = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes.responderTerminate - : topLevelType ? eventTypes.responderRelease : null) + ? eventTypes$1.responderTerminate + : topLevelType ? eventTypes$1.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( topLevelType, @@ -836,10 +837,12 @@ var eventTypes = { } } }, - customBubblingEventTypes = {}, - customDirectEventTypes = {}, + customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes, + customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: {}, + eventTypes: ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -847,8 +850,8 @@ var eventTypes = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], - directDispatchConfig = customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType], + directDispatchConfig = customDirectEventTypes$1[topLevelType]; invariant( bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', @@ -866,24 +869,6 @@ var eventTypes = { forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); else return null; return topLevelType; - }, - processEventTypes: function(viewConfig) { - var bubblingEventTypes = viewConfig.bubblingEventTypes; - viewConfig = viewConfig.directEventTypes; - if (null != bubblingEventTypes) - for (var _topLevelType in bubblingEventTypes) - null == customBubblingEventTypes[_topLevelType] && - (ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType - ] = customBubblingEventTypes[_topLevelType] = - bubblingEventTypes[_topLevelType]); - if (null != viewConfig) - for (var _topLevelType2 in viewConfig) - null == customDirectEventTypes[_topLevelType2] && - (ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType2 - ] = customDirectEventTypes[_topLevelType2] = - viewConfig[_topLevelType2]); } }, instanceCache = {}, @@ -968,155 +953,9 @@ function createPortal(children, containerInfo, implementation) { implementation: implementation }; } -var restoreTarget = null, - restoreQueue = null; -function restoreStateOfTarget(target) { - if ((target = getInstanceFromNode(target))) { - invariant( - null, - "Fiber needs to be injected to handle a fiber target for controlled events. This error is likely caused by a bug in React. Please file an issue." - ); - var props = getFiberCurrentPropsFromNode(target.stateNode); - null.restoreControlledState(target.stateNode, target.type, props); - } -} -function _batchedUpdates(fn, bookkeeping) { - return fn(bookkeeping); -} -function _flushInteractiveUpdates() {} -var isBatching = !1, - TouchHistoryMath = { - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank, - total = 0, - count = 0; - touchHistory = - 1 === touchHistory.numberActiveTouches - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - if (null !== touchHistory) - touchHistory.touchActive && - touchHistory.currentTimeStamp > touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchHistory.currentPageX - : ofCurrent && !isXAxis - ? touchHistory.currentPageY - : !ofCurrent && isXAxis - ? touchHistory.previousPageX - : touchHistory.previousPageY), - (count = 1)); - else - for ( - touchHistory = 0; - touchHistory < touchBank.length; - touchHistory++ - ) { - var touchTrack = touchBank[touchHistory]; - null !== touchTrack && - void 0 !== touchTrack && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchTrack.currentPageX - : ofCurrent && !isXAxis - ? touchTrack.currentPageY - : !ofCurrent && isXAxis - ? touchTrack.previousPageX - : touchTrack.previousPageY), - count++); - } - return 0 < count ? total / count : TouchHistoryMath.noCentroid; - }, - currentCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !0 - ); - }, - currentCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !0 - ); - }, - previousCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !1 - ); - }, - previousCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !1 - ); - }, - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !0, !0); - }, - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !1, !0); - }, - noCentroid: -1 - }, - objects = {}, - uniqueID = 1, - emptyObject$2 = {}, - ReactNativePropRegistry = (function() { - function ReactNativePropRegistry() { - if (!(this instanceof ReactNativePropRegistry)) - throw new TypeError("Cannot call a class as a function"); - } - ReactNativePropRegistry.register = function(object) { - var id = ++uniqueID; - objects[id] = object; - return id; - }; - ReactNativePropRegistry.getByID = function(id) { - if (!id) return emptyObject$2; - var object = objects[id]; - return object - ? object - : (console.warn("Invalid style with id `" + id + "`. Skipping ..."), - emptyObject$2); - }; - return ReactNativePropRegistry; - })(), - emptyObject$1 = {}, +var emptyObject$1 = {}, removedKeys = null, removedKeyCount = 0; -function resolveObject(idOrObject) { - return "number" === typeof idOrObject - ? ReactNativePropRegistry.getByID(idOrObject) - : idOrObject; -} function restoreDeletedValuesInNestedArray( updatePayload, node, @@ -1130,7 +969,7 @@ function restoreDeletedValuesInNestedArray( validAttributes ); else if (node && 0 < removedKeyCount) - for (i in ((node = resolveObject(node)), removedKeys)) + for (i in removedKeys) if (removedKeys[i]) { var _nextProp = node[i]; if (void 0 !== _nextProp) { @@ -1169,12 +1008,7 @@ function diffNestedProperty( ? clearNestedProperty(updatePayload, prevProp, validAttributes) : updatePayload; if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) - return diffProperties( - updatePayload, - resolveObject(prevProp), - resolveObject(nextProp), - validAttributes - ); + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); if (Array.isArray(prevProp) && Array.isArray(nextProp)) { var minLength = prevProp.length < nextProp.length ? prevProp.length : nextProp.length, @@ -1204,12 +1038,12 @@ function diffNestedProperty( ? diffProperties( updatePayload, flattenStyle(prevProp), - resolveObject(nextProp), + nextProp, validAttributes ) : diffProperties( updatePayload, - resolveObject(prevProp), + prevProp, flattenStyle(nextProp), validAttributes ); @@ -1217,9 +1051,11 @@ function diffNestedProperty( function addNestedProperty(updatePayload, nextProp, validAttributes) { if (!nextProp) return updatePayload; if (!Array.isArray(nextProp)) - return ( - (nextProp = resolveObject(nextProp)), - diffProperties(updatePayload, emptyObject$1, nextProp, validAttributes) + return diffProperties( + updatePayload, + emptyObject$1, + nextProp, + validAttributes ); for (var i = 0; i < nextProp.length; i++) updatePayload = addNestedProperty( @@ -1232,9 +1068,11 @@ function addNestedProperty(updatePayload, nextProp, validAttributes) { function clearNestedProperty(updatePayload, prevProp, validAttributes) { if (!prevProp) return updatePayload; if (!Array.isArray(prevProp)) - return ( - (prevProp = resolveObject(prevProp)), - diffProperties(updatePayload, prevProp, emptyObject$1, validAttributes) + return diffProperties( + updatePayload, + prevProp, + emptyObject$1, + validAttributes ); for (var i = 0; i < prevProp.length; i++) updatePayload = clearNestedProperty( @@ -1347,53 +1185,6 @@ function mountSafeCallback(context, callback) { } }; } -var ReactCurrentOwner = - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; -function getComponentName(fiber) { - fiber = fiber.type; - if ("function" === typeof fiber) return fiber.displayName || fiber.name; - if ("string" === typeof fiber) return fiber; - switch (fiber) { - case REACT_FRAGMENT_TYPE: - return "ReactFragment"; - case REACT_PORTAL_TYPE: - return "ReactPortal"; - case REACT_CALL_TYPE: - return "ReactCall"; - case REACT_RETURN_TYPE: - return "ReactReturn"; - } - return null; -} -function findHostInstanceFabric() { - return null; -} -function findNodeHandle(componentOrHandle) { - if (null == componentOrHandle) return null; - if ("number" === typeof componentOrHandle) return componentOrHandle; - var internalInstance = componentOrHandle._reactInternalFiber; - if (internalInstance) return findHostInstanceFabric(internalInstance); - if (componentOrHandle) return componentOrHandle; - invariant( - ("object" === typeof componentOrHandle && - "_nativeTag" in componentOrHandle) || - (null != componentOrHandle.render && - "function" === typeof componentOrHandle.render), - "findNodeHandle(...): Argument is not a component (type: %s, keys: %s)", - typeof componentOrHandle, - Object.keys(componentOrHandle) - ); - invariant( - !1, - "findNodeHandle(...): Unable to find node handle for unmounted component." - ); -} -function findNumericNodeHandleFiber(componentOrHandle) { - componentOrHandle = findNodeHandle(componentOrHandle); - return null == componentOrHandle || "number" === typeof componentOrHandle - ? componentOrHandle - : componentOrHandle._nativeTag; -} function _inherits(subClass, superClass) { if ("function" !== typeof superClass && null !== superClass) throw new TypeError( @@ -1413,75 +1204,7 @@ function _inherits(subClass, superClass) { ? Object.setPrototypeOf(subClass, superClass) : (subClass.__proto__ = superClass)); } -var ReactNativeComponent = (function(_React$Component) { - function ReactNativeComponent() { - if (!(this instanceof ReactNativeComponent)) - throw new TypeError("Cannot call a class as a function"); - var call = _React$Component.apply(this, arguments); - if (!this) - throw new ReferenceError( - "this hasn't been initialised - super() hasn't been called" - ); - return !call || ("object" !== typeof call && "function" !== typeof call) - ? this - : call; - } - _inherits(ReactNativeComponent, _React$Component); - ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - }; - ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }; - ReactNativeComponent.prototype.measure = function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureLayout = function( - relativeToNativeNode, - onSuccess, - onFail - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps - ); - } - }; - return ReactNativeComponent; - })(React.Component), - now = +var now = "object" === typeof performance && "function" === typeof performance.now ? function() { return performance.now(); @@ -1503,8 +1226,24 @@ function setTimeoutCallback() { scheduledCallback = null; null !== callback && callback(frameDeadlineObject); } -var viewConfigCallbacks = new Map(), - viewConfigs = new Map(); +var ReactCurrentOwner = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; +function getComponentName(fiber) { + fiber = fiber.type; + if ("function" === typeof fiber) return fiber.displayName || fiber.name; + if ("string" === typeof fiber) return fiber; + switch (fiber) { + case REACT_FRAGMENT_TYPE: + return "ReactFragment"; + case REACT_PORTAL_TYPE: + return "ReactPortal"; + case REACT_CALL_TYPE: + return "ReactCall"; + case REACT_RETURN_TYPE: + return "ReactReturn"; + } + return null; +} function isFiberMountedImpl(fiber) { var node = fiber; if (fiber.alternate) for (; node["return"]; ) node = node["return"]; @@ -5649,10 +5388,6 @@ function ReactFiberReconciler$1(config) { scheduleWork(currentTime, expirationTime); return expirationTime; } - function findHostInstance(fiber) { - fiber = findCurrentHostFiber(fiber); - return null === fiber ? null : fiber.stateNode; - } var getPublicInstance = config.getPublicInstance; config = ReactFiberScheduler(config); var recalculateCurrentTime = config.recalculateCurrentTime, @@ -5731,7 +5466,19 @@ function ReactFiberReconciler$1(config) { return container.child.stateNode; } }, - findHostInstance: findHostInstance, + findHostInstance: function(component) { + var fiber = component._reactInternalFiber; + void 0 === fiber && + ("function" === typeof component.render + ? invariant(!1, "Unable to find node on an unmounted component.") + : invariant( + !1, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + )); + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; + }, findHostInstanceWithNoPortals: function(fiber) { fiber = findCurrentHostFiberWithNoPortals(fiber); return null === fiber ? null : fiber.stateNode; @@ -5741,7 +5488,8 @@ function ReactFiberReconciler$1(config) { return injectInternals( Object.assign({}, devToolsConfig, { findHostInstanceByFiber: function(fiber) { - return findHostInstance(fiber); + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: function(instance) { return findFiberByHostInstance @@ -5760,27 +5508,7 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), reactReconciler = ReactFiberReconciler$3["default"] ? ReactFiberReconciler$3["default"] : ReactFiberReconciler$3, - ReactNativeTagHandles = { - tagsStartAt: 1, - tagCount: 1, - allocateTag: function() { - for (; this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount); ) - ReactNativeTagHandles.tagCount++; - var tag = ReactNativeTagHandles.tagCount; - ReactNativeTagHandles.tagCount++; - return tag; - }, - assertRootTag: function(tag) { - invariant( - this.reactTagIsNativeTopRootID(tag), - "Expect a native root tag, instead got %s", - tag - ); - }, - reactTagIsNativeTopRootID: function(reactTag) { - return 1 === reactTag % 10; - } - }, + nextReactTag = 2, ReactFabricHostComponent = (function() { function ReactFabricHostComponent(tag, viewConfig, props) { if (!(this instanceof ReactFabricHostComponent)) @@ -5843,21 +5571,10 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), hostContext, internalInstanceHandle ) { - hostContext = ReactNativeTagHandles.allocateTag(); - if (viewConfigs.has(type)) var viewConfig = viewConfigs.get(type); - else - (viewConfig = viewConfigCallbacks.get(type)), - invariant( - "function" === typeof viewConfig, - "View config not found for name %s", - type - ), - viewConfigCallbacks.set(type, null), - (viewConfig = viewConfig()), - viewConfigs.set(type, viewConfig); - invariant(viewConfig, "View config not found for name %s", type); - type = viewConfig; - viewConfig = diffProperties( + hostContext = nextReactTag; + nextReactTag += 2; + type = ReactNativeViewConfigRegistry.get(type); + var updatePayload = diffProperties( null, emptyObject$1, props, @@ -5867,7 +5584,7 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), hostContext, type.uiViewClassName, rootContainerInstance, - viewConfig, + updatePayload, internalInstanceHandle ); props = new ReactFabricHostComponent(hostContext, type, props); @@ -5879,7 +5596,8 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), hostContext, internalInstanceHandle ) { - hostContext = ReactNativeTagHandles.allocateTag(); + hostContext = nextReactTag; + nextReactTag += 2; return { node: FabricUIManager.createNode( hostContext, @@ -5968,13 +5686,94 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), getInspectorDataForViewTag = function() { invariant(!1, "getInspectorDataForViewTag() is not available in production"); }; -findHostInstanceFabric = ReactFabricRenderer.findHostInstance; -_batchedUpdates = ReactFabricRenderer.batchedUpdates; -_flushInteractiveUpdates = ReactFabricRenderer.flushInteractiveUpdates; +var findHostInstance = ReactFabricRenderer.findHostInstance; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} var roots = new Map(), ReactFabric = { - NativeComponent: ReactNativeComponent, - findNodeHandle: findNumericNodeHandleFiber, + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.focus = function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.measure = function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, render: function(element, containerTag, callback) { var root = roots.get(containerTag); root || @@ -5990,9 +5789,6 @@ var roots = new Map(), roots["delete"](containerTag); }); }, - unmountComponentAtNodeAndRemoveContainer: function(containerTag) { - ReactFabric.unmountComponentAtNode(containerTag); - }, createPortal: function(children, containerTag) { return createPortal( children, @@ -6001,98 +5797,59 @@ var roots = new Map(), 2 < arguments.length && void 0 !== arguments[2] ? arguments[2] : null ); }, - unstable_batchedUpdates: function(fn, bookkeeping) { - if (isBatching) return fn(bookkeeping); - isBatching = !0; - try { - return _batchedUpdates(fn, bookkeeping); - } finally { - if ( - ((isBatching = !1), null !== restoreTarget || null !== restoreQueue) - ) - if ( - (_flushInteractiveUpdates(), - restoreTarget && - ((bookkeeping = restoreTarget), - (fn = restoreQueue), - (restoreQueue = restoreTarget = null), - restoreStateOfTarget(bookkeeping), - fn)) - ) - for (bookkeeping = 0; bookkeeping < fn.length; bookkeeping++) - restoreStateOfTarget(fn[bookkeeping]); - } - }, - flushSync: ReactFabricRenderer.flushSync, __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { - NativeMethodsMixin: { - measure: function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - measureInWindow: function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - measureLayout: function(relativeToNativeNode, onSuccess, onFail) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, - setNativeProps: function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = maybeInstance.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps + }, + measureInWindow: function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = maybeInstance.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); } - }, - focus: function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }, - blur: function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - } - }, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, - ReactNativeComponentTree: ReactNativeComponentTree, - ReactNativePropRegistry: ReactNativePropRegistry, - TouchHistoryMath: TouchHistoryMath, - createReactNativeComponentClass: function(name, callback) { - invariant( - !viewConfigCallbacks.has(name), - "Tried to register two views with the same name %s", - name - ); - viewConfigCallbacks.set(name, callback); - return name; - }, - takeSnapshot: function(view, options) { - "number" !== typeof view && - "window" !== view && - (view = findNumericNodeHandleFiber(view) || "window"); - return UIManager.__takeSnapshot(view, options); - } + }; + })(findNodeHandle, findHostInstance), + ReactNativeComponentTree: ReactNativeComponentTree } }; ReactFabricRenderer.injectIntoDevTools({ diff --git a/Libraries/Renderer/ReactNativeRenderer-dev.js b/Libraries/Renderer/ReactNativeRenderer-dev.js index 97bbfa4bef4..51e4aa2b0ad 100644 --- a/Libraries/Renderer/ReactNativeRenderer-dev.js +++ b/Libraries/Renderer/ReactNativeRenderer-dev.js @@ -19,6 +19,7 @@ require("InitializeCore"); var invariant = require("fbjs/lib/invariant"); var warning = require("fbjs/lib/warning"); var emptyFunction = require("fbjs/lib/emptyFunction"); +var ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"); var UIManager = require("UIManager"); var RCTEventEmitter = require("RCTEventEmitter"); var TextInputState = require("TextInputState"); @@ -1449,7 +1450,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return { configurable: true, set: set, - get: get + get: get$$1 }; function set(val) { @@ -1458,7 +1459,7 @@ function getPooledWarningPropertyDefinition(propName, getVal) { return val; } - function get() { + function get$$1() { var action = isFunction ? "accessing the method" : "accessing the property"; var result = isFunction ? "This is a no-op function" @@ -1775,7 +1776,7 @@ var changeResponder = function(nextResponderInst, blockHostResponder) { } }; -var eventTypes = { +var eventTypes$1 = { /** * On a `touchStart`/`mouseDown`, is it desired that this element become the * responder? @@ -2040,12 +2041,12 @@ function setResponderAndExtractTransfer( nativeEventTarget ) { var shouldSetEventType = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder + ? eventTypes$1.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder + ? eventTypes$1.moveShouldSetResponder : topLevelType === "topSelectionChange" - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.scrollShouldSetResponder; // TODO: stop one short of the current responder. var bubbleShouldSetFrom = !responderInst @@ -2079,7 +2080,7 @@ function setResponderAndExtractTransfer( } var extracted = void 0; var grantEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, + eventTypes$1.responderGrant, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2090,7 +2091,7 @@ function setResponderAndExtractTransfer( var blockHostResponder = executeDirectDispatch(grantEvent) === true; if (responderInst) { var terminationRequestEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, + eventTypes$1.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -2107,7 +2108,7 @@ function setResponderAndExtractTransfer( if (shouldSwitch) { var terminateEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, + eventTypes$1.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -2118,7 +2119,7 @@ function setResponderAndExtractTransfer( changeResponder(wantsResponderInst, blockHostResponder); } else { var rejectEvent = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, + eventTypes$1.responderReject, wantsResponderInst, nativeEvent, nativeEventTarget @@ -2187,7 +2188,7 @@ var ResponderEventPlugin = { return responderInst; }, - eventTypes: eventTypes, + eventTypes: eventTypes$1, /** * We must be resilient to `targetInst` being `null` on `touchMove` or @@ -2237,10 +2238,10 @@ var ResponderEventPlugin = { var isResponderTouchMove = responderInst && isMoveish(topLevelType); var isResponderTouchEnd = responderInst && isEndish(topLevelType); var incrementalTouch = isResponderTouchStart - ? eventTypes.responderStart + ? eventTypes$1.responderStart : isResponderTouchMove - ? eventTypes.responderMove - : isResponderTouchEnd ? eventTypes.responderEnd : null; + ? eventTypes$1.responderMove + : isResponderTouchEnd ? eventTypes$1.responderEnd : null; if (incrementalTouch) { var gesture = ResponderSyntheticEvent.getPooled( @@ -2262,8 +2263,8 @@ var ResponderEventPlugin = { isEndish(topLevelType) && noResponderTouches(nativeEvent); var finalTouch = isResponderTerminate - ? eventTypes.responderTerminate - : isResponderRelease ? eventTypes.responderRelease : null; + ? eventTypes$1.responderTerminate + : isResponderRelease ? eventTypes$1.responderRelease : null; if (finalTouch) { var finalEvent = ResponderSyntheticEvent.getPooled( finalTouch, @@ -2315,11 +2316,14 @@ var ResponderEventPlugin = { } }; -var customBubblingEventTypes = {}; -var customDirectEventTypes = {}; +var customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes; +var customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes; +var eventTypes$2 = ReactNativeViewConfigRegistry.eventTypes; var ReactNativeBridgeEventPlugin = { - eventTypes: {}, + eventTypes: eventTypes$2, /** * @see {EventPluginHub.extractEvents} @@ -2334,8 +2338,8 @@ var ReactNativeBridgeEventPlugin = { // Probably a node belonging to another renderer's tree. return null; } - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType]; - var directDispatchConfig = customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType]; + var directDispatchConfig = customDirectEventTypes$1[topLevelType]; invariant( bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', @@ -2355,45 +2359,6 @@ var ReactNativeBridgeEventPlugin = { return null; } return event; - }, - - processEventTypes: function(viewConfig) { - var bubblingEventTypes = viewConfig.bubblingEventTypes, - directEventTypes = viewConfig.directEventTypes; - - { - if (bubblingEventTypes != null && directEventTypes != null) { - for (var topLevelType in directEventTypes) { - invariant( - bubblingEventTypes[topLevelType] == null, - "Event cannot be both direct and bubbling: %s", - topLevelType - ); - } - } - } - - if (bubblingEventTypes != null) { - for (var _topLevelType in bubblingEventTypes) { - if (customBubblingEventTypes[_topLevelType] == null) { - ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType - ] = customBubblingEventTypes[_topLevelType] = - bubblingEventTypes[_topLevelType]; - } - } - } - - if (directEventTypes != null) { - for (var _topLevelType2 in directEventTypes) { - if (customDirectEventTypes[_topLevelType2] == null) { - ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType2 - ] = customDirectEventTypes[_topLevelType2] = - directEventTypes[_topLevelType2]; - } - } - } } }; @@ -2588,48 +2553,6 @@ var injection$2 = { } }; -/** - * Keeps track of allocating and associating native "tags" which are numeric, - * unique view IDs. All the native tags are negative numbers, to avoid - * collisions, but in the JS we keep track of them as positive integers to store - * them effectively in Arrays. So we must refer to them as "inverses" of the - * native tags (that are * normally negative). - * - * It *must* be the case that every `rootNodeID` always maps to the exact same - * `tag` forever. The easiest way to accomplish this is to never delete - * anything from this table. - * Why: Because `dangerouslyReplaceNodeWithMarkupByID` relies on being able to - * unmount a component with a `rootNodeID`, then mount a new one in its place, - */ -var INITIAL_TAG_COUNT = 1; -var ReactNativeTagHandles = { - tagsStartAt: INITIAL_TAG_COUNT, - tagCount: INITIAL_TAG_COUNT, - - allocateTag: function() { - // Skip over root IDs as those are reserved for native - while (this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount)) { - ReactNativeTagHandles.tagCount++; - } - var tag = ReactNativeTagHandles.tagCount; - ReactNativeTagHandles.tagCount++; - return tag; - }, - - assertRootTag: function(tag) { - invariant( - this.reactTagIsNativeTopRootID(tag), - "Expect a native root tag, instead got %s", - tag - ); - }, - - reactTagIsNativeTopRootID: function(reactTag) { - // We reserve all tags that are 1 mod 10 for native root views - return reactTag % 10 === 1; - } -}; - /** * Version of `ReactBrowserEventEmitter` that works on the receiving side of a * serialized worker boundary. @@ -2762,7 +2685,7 @@ function receiveTouches(eventTopLevelType, touches, changedIndices) { var rootNodeID = null; var target = nativeEvent.target; if (target !== null && target !== undefined) { - if (target < ReactNativeTagHandles.tagsStartAt) { + if (target < 1) { { warning( false, @@ -2848,149 +2771,6 @@ function createPortal( }; } -var TouchHistoryMath = { - /** - * This code is optimized and not intended to look beautiful. This allows - * computing of touch centroids that have moved after `touchesChangedAfter` - * timeStamp. You can compute the current centroid involving all touches - * moves after `touchesChangedAfter`, or you can compute the previous - * centroid of all touches that were moved after `touchesChangedAfter`. - * - * @param {TouchHistoryMath} touchHistory Standard Responder touch track - * data. - * @param {number} touchesChangedAfter timeStamp after which moved touches - * are considered "actively moving" - not just "active". - * @param {boolean} isXAxis Consider `x` dimension vs. `y` dimension. - * @param {boolean} ofCurrent Compute current centroid for actively moving - * touches vs. previous centroid of now actively moving touches. - * @return {number} value of centroid in specified dimension. - */ - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank; - var total = 0; - var count = 0; - - var oneTouchData = - touchHistory.numberActiveTouches === 1 - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - - if (oneTouchData !== null) { - if ( - oneTouchData.touchActive && - oneTouchData.currentTimeStamp > touchesChangedAfter - ) { - total += - ofCurrent && isXAxis - ? oneTouchData.currentPageX - : ofCurrent && !isXAxis - ? oneTouchData.currentPageY - : !ofCurrent && isXAxis - ? oneTouchData.previousPageX - : oneTouchData.previousPageY; - count = 1; - } - } else { - for (var i = 0; i < touchBank.length; i++) { - var touchTrack = touchBank[i]; - if ( - touchTrack !== null && - touchTrack !== undefined && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter - ) { - var toAdd = void 0; // Yuck, program temporarily in invalid state. - if (ofCurrent && isXAxis) { - toAdd = touchTrack.currentPageX; - } else if (ofCurrent && !isXAxis) { - toAdd = touchTrack.currentPageY; - } else if (!ofCurrent && isXAxis) { - toAdd = touchTrack.previousPageX; - } else { - toAdd = touchTrack.previousPageY; - } - total += toAdd; - count++; - } - } - } - return count > 0 ? total / count : TouchHistoryMath.noCentroid; - }, - - currentCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - true, // isXAxis - true - ); - }, - - currentCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - false, // isXAxis - true - ); - }, - - previousCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - true, // isXAxis - false - ); - }, - - previousCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - false, // isXAxis - false - ); - }, - - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension( - touchHistory, - 0, // touchesChangedAfter - true, // isXAxis - true - ); - }, - - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension( - touchHistory, - 0, // touchesChangedAfter - false, // isXAxis - true - ); - }, - - noCentroid: -1 -}; - // TODO: this is special because it gets imported during build. var ReactVersion = "16.3.1"; @@ -3064,48 +2844,6 @@ function getStackAddendumByWorkInProgressFiber(workInProgress) { return info; } -function _classCallCheck(instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -} - -var objects = {}; -var uniqueID = 1; -var emptyObject$2 = {}; - -var ReactNativePropRegistry = (function() { - function ReactNativePropRegistry() { - _classCallCheck(this, ReactNativePropRegistry); - } - - ReactNativePropRegistry.register = function register(object) { - var id = ++uniqueID; - { - Object.freeze(object); - } - objects[id] = object; - return id; - }; - - ReactNativePropRegistry.getByID = function getByID(id) { - if (!id) { - // Used in the style={[condition && id]} pattern, - // we want it to be a no-op when the value is false or null - return emptyObject$2; - } - - var object = objects[id]; - if (!object) { - console.warn("Invalid style with id `" + id + "`. Skipping ..."); - return emptyObject$2; - } - return object; - }; - - return ReactNativePropRegistry; -})(); - // Modules provided by RN: var emptyObject$1 = {}; @@ -3132,13 +2870,6 @@ function defaultDiffer(prevProp, nextProp) { } } -function resolveObject(idOrObject) { - if (typeof idOrObject === "number") { - return ReactNativePropRegistry.getByID(idOrObject); - } - return idOrObject; -} - function restoreDeletedValuesInNestedArray( updatePayload, node, @@ -3154,7 +2885,7 @@ function restoreDeletedValuesInNestedArray( ); } } else if (node && removedKeyCount > 0) { - var obj = resolveObject(node); + var obj = node; for (var propKey in removedKeys) { if (!removedKeys[propKey]) { continue; @@ -3258,12 +2989,7 @@ function diffNestedProperty( if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) { // Both are leaves, we can diff the leaves. - return diffProperties( - updatePayload, - resolveObject(prevProp), - resolveObject(nextProp), - validAttributes - ); + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); } if (Array.isArray(prevProp) && Array.isArray(nextProp)) { @@ -3282,14 +3008,14 @@ function diffNestedProperty( // $FlowFixMe - We know that this is always an object when the input is. flattenStyle(prevProp), // $FlowFixMe - We know that this isn't an array because of above flow. - resolveObject(nextProp), + nextProp, validAttributes ); } return diffProperties( updatePayload, - resolveObject(prevProp), + prevProp, // $FlowFixMe - We know that this is always an object when the input is. flattenStyle(nextProp), validAttributes @@ -3308,11 +3034,7 @@ function addNestedProperty(updatePayload, nextProp, validAttributes) { if (!Array.isArray(nextProp)) { // Add each property of the leaf. - return addProperties( - updatePayload, - resolveObject(nextProp), - validAttributes - ); + return addProperties(updatePayload, nextProp, validAttributes); } for (var i = 0; i < nextProp.length; i++) { @@ -3338,11 +3060,7 @@ function clearNestedProperty(updatePayload, prevProp, validAttributes) { if (!Array.isArray(prevProp)) { // Add each property of the leaf. - return clearProperties( - updatePayload, - resolveObject(prevProp), - validAttributes - ); + return clearProperties(updatePayload, prevProp, validAttributes); } for (var i = 0; i < prevProp.length; i++) { @@ -3629,339 +3347,195 @@ function warnForStyleProps(props, validAttributes) { } } -/** - * `ReactInstanceMap` maintains a mapping from a public facing stateful - * instance (key) and the internal representation (value). This allows public - * methods to accept the user facing instance as an argument and map them back - * to internal methods. - * - * Note that this module is currently shared and assumed to be stateless. - * If this becomes an actual Map, that will break. - */ - -/** - * This API should be called `delete` but we'd have to make sure to always - * transform these to strings for IE support. When this transform is fully - * supported we can rename it. - */ - -function get(key) { - return key._reactInternalFiber; -} - -function set(key, value) { - key._reactInternalFiber = value; -} - -var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; - -var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; -var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; - -// TODO: Share this module between Fabric and React Native renderers -// so that both can be used in the same tree. - -var findHostInstance = function(fiber) { - return null; -}; - -var findHostInstanceFabric = function(fiber) { - return null; -}; - -function injectFindHostInstance(impl) { - findHostInstance = impl; -} - -/** - * ReactNative vs ReactWeb - * ----------------------- - * React treats some pieces of data opaquely. This means that the information - * is first class (it can be passed around), but cannot be inspected. This - * allows us to build infrastructure that reasons about resources, without - * making assumptions about the nature of those resources, and this allows that - * infra to be shared across multiple platforms, where the resources are very - * different. General infra (such as `ReactMultiChild`) reasons opaquely about - * the data, but platform specific code (such as `ReactNativeBaseComponent`) can - * make assumptions about the data. - * - * - * `rootNodeID`, uniquely identifies a position in the generated native view - * tree. Many layers of composite components (created with `React.createClass`) - * can all share the same `rootNodeID`. - * - * `nodeHandle`: A sufficiently unambiguous way to refer to a lower level - * resource (dom node, native view etc). The `rootNodeID` is sufficient for web - * `nodeHandle`s, because the position in a tree is always enough to uniquely - * identify a DOM node (we never have nodes in some bank outside of the - * document). The same would be true for `ReactNative`, but we must maintain a - * mapping that we can send efficiently serializable - * strings across native boundaries. - * - * Opaque name TodaysWebReact FutureWebWorkerReact ReactNative - * ---------------------------------------------------------------------------- - * nodeHandle N/A rootNodeID tag - */ - -// TODO (bvaughn) Rename the findNodeHandle module to something more descriptive -// eg findInternalHostInstance. This will reduce the likelihood of someone -// accidentally deep-requiring this version. -function findNodeHandle(componentOrHandle) { - { - var owner = ReactCurrentOwner.current; - if (owner !== null && owner.stateNode !== null) { - !owner.stateNode._warnedAboutRefsInRender - ? warning( - false, - "%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(owner) || "A component" - ) - : void 0; - - owner.stateNode._warnedAboutRefsInRender = true; - } - } - if (componentOrHandle == null) { - return null; - } - if (typeof componentOrHandle === "number") { - // Already a node handle - return componentOrHandle; - } - - var component = componentOrHandle; - - // TODO (balpert): Wrap iOS native components in a composite wrapper, then - // ReactInstanceMap.get here will always succeed for mounted components - var internalInstance = get(component); - if (internalInstance) { - return ( - findHostInstance(internalInstance) || - findHostInstanceFabric(internalInstance) - ); - } else { - if (component) { - return component; - } else { - invariant( - // Native - (typeof component === "object" && "_nativeTag" in component) || - // Composite - (component.render != null && typeof component.render === "function"), - "findNodeHandle(...): Argument is not a component " + - "(type: %s, keys: %s)", - typeof component, - Object.keys(component) - ); - invariant( - false, - "findNodeHandle(...): Unable to find node handle for unmounted " + - "component." - ); - } - } -} - -/** - * External users of findNodeHandle() expect the host tag number return type. - * The injected findNodeHandle() strategy returns the instance wrapper though. - * See NativeMethodsMixin#setNativeProps for more info on why this is done. - */ -function findNumericNodeHandleFiber(componentOrHandle) { - var instance = findNodeHandle(componentOrHandle); - if (instance == null || typeof instance === "number") { - return instance; - } - return instance._nativeTag; -} - // Modules provided by RN: -/** - * `NativeMethodsMixin` provides methods to access the underlying native - * component directly. This can be useful in cases when you want to focus - * a view or measure its on-screen dimensions, for example. - * - * The methods described here are available on most of the default components - * provided by React Native. Note, however, that they are *not* available on - * composite components that aren't directly backed by a native view. This will - * generally include most components that you define in your own app. For more - * information, see [Direct - * Manipulation](docs/direct-manipulation.html). - * - * Note the Flow $Exact<> syntax is required to support mixins. - * React createClass mixins can only be used with exact types. - */ -var NativeMethodsMixin = { +var NativeMethodsMixin = function(findNodeHandle, findHostInstance) { /** - * Determines the location on screen, width, and height of the given view and - * returns the values via an async callback. If successful, the callback will - * be called with the following arguments: + * `NativeMethodsMixin` provides methods to access the underlying native + * component directly. This can be useful in cases when you want to focus + * a view or measure its on-screen dimensions, for example. * - * - x - * - y - * - width - * - height - * - pageX - * - pageY + * The methods described here are available on most of the default components + * provided by React Native. Note, however, that they are *not* available on + * composite components that aren't directly backed by a native view. This will + * generally include most components that you define in your own app. For more + * information, see [Direct + * Manipulation](docs/direct-manipulation.html). * - * Note that these measurements are not available until after the rendering - * has been completed in native. If you need the measurements as soon as - * possible, consider using the [`onLayout` - * prop](docs/view.html#onlayout) instead. + * Note the Flow $Exact<> syntax is required to support mixins. + * React createClass mixins can only be used with exact types. */ - measure: function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - - /** - * Determines the location of the given view in the window and returns the - * values via an async callback. If the React root view is embedded in - * another native view, this will give you the absolute coordinates. If - * successful, the callback will be called with the following - * arguments: - * - * - x - * - y - * - width - * - height - * - * Note that these measurements are not available until after the rendering - * has been completed in native. - */ - measureInWindow: function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - - /** - * Like [`measure()`](#measure), but measures the view relative an ancestor, - * specified as `relativeToNativeNode`. This means that the returned x, y - * are relative to the origin x, y of the ancestor view. - * - * As always, to obtain a native node handle for a component, you can use - * `findNumericNodeHandle(component)`. - */ - measureLayout: function( - relativeToNativeNode, - onSuccess, - onFail /* currently unused */ - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, - - /** - * This function sends props straight to native. They will not participate in - * future diff process - this means that if you do not include them in the - * next render, they will remain active (see [Direct - * Manipulation](docs/direct-manipulation.html)). - */ - setNativeProps: function(nativeProps) { - // Class components don't have viewConfig -> validateAttributes. - // Nor does it make sense to set native props on a non-native component. - // Instead, find the nearest host component and set props on it. - // Use findNodeHandle() rather than findNumericNodeHandle() because - // We want the instance/wrapper (not the native tag). - var maybeInstance = void 0; - - // Fiber errors if findNodeHandle is called for an umounted component. - // Tests using ReactTestRenderer will trigger this case indirectly. - // Mimicking stack behavior, we should silently ignore this case. - // TODO Fix ReactTestRenderer so we can remove this try/catch. - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - - // If there is no host component beneath this we should fail silently. - // This is not an error; it could mean a class component rendered null. - if (maybeInstance == null) { - return; - } - - var viewConfig = maybeInstance.viewConfig; - - { - warnForStyleProps(nativeProps, viewConfig.validAttributes); - } - - var updatePayload = create(nativeProps, viewConfig.validAttributes); - - // Avoid the overhead of bridge calls if there's no update. - // This is an expensive no-op for Android, and causes an unnecessary - // view invalidation for certain components (eg RCTTextInput) on iOS. - if (updatePayload != null) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload + var NativeMethodsMixin = { + /** + * Determines the location on screen, width, and height of the given view and + * returns the values via an async callback. If successful, the callback will + * be called with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * Note that these measurements are not available until after the rendering + * has been completed in native. If you need the measurements as soon as + * possible, consider using the [`onLayout` + * prop](docs/view.html#onlayout) instead. + */ + measure: function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) ); + }, + + /** + * Determines the location of the given view in the window and returns the + * values via an async callback. If the React root view is embedded in + * another native view, this will give you the absolute coordinates. If + * successful, the callback will be called with the following + * arguments: + * + * - x + * - y + * - width + * - height + * + * Note that these measurements are not available until after the rendering + * has been completed in native. + */ + measureInWindow: function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + + /** + * Like [`measure()`](#measure), but measures the view relative an ancestor, + * specified as `relativeToNativeNode`. This means that the returned x, y + * are relative to the origin x, y of the ancestor view. + * + * As always, to obtain a native node handle for a component, you can use + * `findNodeHandle(component)`. + */ + measureLayout: function( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }, + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + setNativeProps: function(nativeProps) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + var viewConfig = maybeInstance.viewConfig; + + { + warnForStyleProps(nativeProps, viewConfig.validAttributes); + } + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }, + + /** + * Requests focus for the given input or view. The exact behavior triggered + * will depend on the platform and type of view. + */ + focus: function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + + /** + * Removes focus from an input or view. This is the opposite of `focus()`. + */ + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); } - }, + }; - /** - * Requests focus for the given input or view. The exact behavior triggered - * will depend on the platform and type of view. - */ - focus: function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }, + { + // hide this from Flow since we can't define these properties outside of + // true without actually implementing them (setting them to undefined + // isn't allowed by ReactClass) + var NativeMethodsMixin_DEV = NativeMethodsMixin; + invariant( + !NativeMethodsMixin_DEV.componentWillMount && + !NativeMethodsMixin_DEV.componentWillReceiveProps && + !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && + !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, + "Do not override existing functions." + ); + // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, + // Once these lifecycles have been remove from the reconciler. + NativeMethodsMixin_DEV.componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) { + throwOnStylesProp(this, newProps); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() { + throwOnStylesProp(this, this.props); + }; + NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function( + newProps + ) { + throwOnStylesProp(this, newProps); + }; - /** - * Removes focus from an input or view. This is the opposite of `focus()`. - */ - blur: function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); + // React may warn about cWM/cWRP/cWU methods being deprecated. + // Add a flag to suppress these warnings for this special case. + // TODO (bvaughn) Remove this flag once the above methods have been removed. + NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; + NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; } + + return NativeMethodsMixin; }; -{ - // hide this from Flow since we can't define these properties outside of - // true without actually implementing them (setting them to undefined - // isn't allowed by ReactClass) - var NativeMethodsMixin_DEV = NativeMethodsMixin; - invariant( - !NativeMethodsMixin_DEV.componentWillMount && - !NativeMethodsMixin_DEV.componentWillReceiveProps && - !NativeMethodsMixin_DEV.UNSAFE_componentWillMount && - !NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps, - "Do not override existing functions." - ); - // TODO (bvaughn) Remove cWM and cWRP in a future version of React Native, - // Once these lifecycles have been remove from the reconciler. - NativeMethodsMixin_DEV.componentWillMount = function() { - throwOnStylesProp(this, this.props); - }; - NativeMethodsMixin_DEV.componentWillReceiveProps = function(newProps) { - throwOnStylesProp(this, newProps); - }; - NativeMethodsMixin_DEV.UNSAFE_componentWillMount = function() { - throwOnStylesProp(this, this.props); - }; - NativeMethodsMixin_DEV.UNSAFE_componentWillReceiveProps = function(newProps) { - throwOnStylesProp(this, newProps); - }; - - // React may warn about cWM/cWRP/cWU methods being deprecated. - // Add a flag to suppress these warnings for this special case. - // TODO (bvaughn) Remove this flag once the above methods have been removed. - NativeMethodsMixin_DEV.componentWillMount.__suppressDeprecationWarning = true; - NativeMethodsMixin_DEV.componentWillReceiveProps.__suppressDeprecationWarning = true; -} - -function _classCallCheck$1(instance, Constructor) { +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } @@ -4000,166 +3574,200 @@ function _inherits(subClass, superClass) { } // Modules provided by RN: -/** - * Superclass that provides methods to access the underlying native component. - * This can be useful when you want to focus a view or measure its dimensions. - * - * Methods implemented by this class are available on most default components - * provided by React Native. However, they are *not* available on composite - * components that are not directly backed by a native view. For more - * information, see [Direct Manipulation](docs/direct-manipulation.html). - * - * @abstract - */ - -var ReactNativeComponent = (function(_React$Component) { - _inherits(ReactNativeComponent, _React$Component); - - function ReactNativeComponent() { - _classCallCheck$1(this, ReactNativeComponent); - - return _possibleConstructorReturn( - this, - _React$Component.apply(this, arguments) - ); - } - +var ReactNativeComponent = function(findNodeHandle, findHostInstance) { /** - * Removes focus. This is the opposite of `focus()`. - */ - - /** - * Due to bugs in Flow's handling of React.createClass, some fields already - * declared in the base class need to be redeclared below. - */ - ReactNativeComponent.prototype.blur = function blur() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - }; - - /** - * Requests focus. The exact behavior depends on the platform and view. - */ - - ReactNativeComponent.prototype.focus = function focus() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }; - - /** - * Measures the on-screen location and dimensions. If successful, the callback - * will be called asynchronously with the following arguments: + * Superclass that provides methods to access the underlying native component. + * This can be useful when you want to focus a view or measure its dimensions. * - * - x - * - y - * - width - * - height - * - pageX - * - pageY + * Methods implemented by this class are available on most default components + * provided by React Native. However, they are *not* available on composite + * components that are not directly backed by a native view. For more + * information, see [Direct Manipulation](docs/direct-manipulation.html). * - * These values are not available until after natives rendering completes. If - * you need the measurements as soon as possible, consider using the - * [`onLayout` prop](docs/view.html#onlayout) instead. + * @abstract */ + var ReactNativeComponent = (function(_React$Component) { + _inherits(ReactNativeComponent, _React$Component); - ReactNativeComponent.prototype.measure = function measure(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; + function ReactNativeComponent() { + _classCallCheck(this, ReactNativeComponent); - /** - * Measures the on-screen location and dimensions. Even if the React Native - * root view is embedded within another native view, this method will give you - * the absolute coordinates measured from the window. If successful, the - * callback will be called asynchronously with the following arguments: - * - * - x - * - y - * - width - * - height - * - * These values are not available until after natives rendering completes. - */ - - ReactNativeComponent.prototype.measureInWindow = function measureInWindow( - callback - ) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - - /** - * Similar to [`measure()`](#measure), but the resulting location will be - * relative to the supplied ancestor's location. - * - * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. - */ - - ReactNativeComponent.prototype.measureLayout = function measureLayout( - relativeToNativeNode, - onSuccess, - onFail /* currently unused */ - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - - /** - * This function sends props straight to native. They will not participate in - * future diff process - this means that if you do not include them in the - * next render, they will remain active (see [Direct - * Manipulation](docs/direct-manipulation.html)). - */ - - ReactNativeComponent.prototype.setNativeProps = function setNativeProps( - nativeProps - ) { - // Class components don't have viewConfig -> validateAttributes. - // Nor does it make sense to set native props on a non-native component. - // Instead, find the nearest host component and set props on it. - // Use findNodeHandle() rather than ReactNative.findNodeHandle() because - // We want the instance/wrapper (not the native tag). - var maybeInstance = void 0; - - // Fiber errors if findNodeHandle is called for an umounted component. - // Tests using ReactTestRenderer will trigger this case indirectly. - // Mimicking stack behavior, we should silently ignore this case. - // TODO Fix ReactTestRenderer so we can remove this try/catch. - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - - // If there is no host component beneath this we should fail silently. - // This is not an error; it could mean a class component rendered null. - if (maybeInstance == null) { - return; - } - - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - - var updatePayload = create(nativeProps, viewConfig.validAttributes); - - // Avoid the overhead of bridge calls if there's no update. - // This is an expensive no-op for Android, and causes an unnecessary - // view invalidation for certain components (eg RCTTextInput) on iOS. - if (updatePayload != null) { - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - updatePayload + return _possibleConstructorReturn( + this, + _React$Component.apply(this, arguments) ); } - }; + + /** + * Removes focus. This is the opposite of `focus()`. + */ + + /** + * Due to bugs in Flow's handling of React.createClass, some fields already + * declared in the base class need to be redeclared below. + */ + ReactNativeComponent.prototype.blur = function blur() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + + /** + * Requests focus. The exact behavior depends on the platform and view. + */ + + ReactNativeComponent.prototype.focus = function focus() { + TextInputState.focusTextInput(findNodeHandle(this)); + }; + + /** + * Measures the on-screen location and dimensions. If successful, the callback + * will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * - pageX + * - pageY + * + * These values are not available until after natives rendering completes. If + * you need the measurements as soon as possible, consider using the + * [`onLayout` prop](docs/view.html#onlayout) instead. + */ + + ReactNativeComponent.prototype.measure = function measure(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + + /** + * Measures the on-screen location and dimensions. Even if the React Native + * root view is embedded within another native view, this method will give you + * the absolute coordinates measured from the window. If successful, the + * callback will be called asynchronously with the following arguments: + * + * - x + * - y + * - width + * - height + * + * These values are not available until after natives rendering completes. + */ + + ReactNativeComponent.prototype.measureInWindow = function measureInWindow( + callback + ) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + + /** + * Similar to [`measure()`](#measure), but the resulting location will be + * relative to the supplied ancestor's location. + * + * Obtain a native node handle with `ReactNative.findNodeHandle(component)`. + */ + + ReactNativeComponent.prototype.measureLayout = function measureLayout( + relativeToNativeNode, + onSuccess, + onFail /* currently unused */ + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + + /** + * This function sends props straight to native. They will not participate in + * future diff process - this means that if you do not include them in the + * next render, they will remain active (see [Direct + * Manipulation](docs/direct-manipulation.html)). + */ + + ReactNativeComponent.prototype.setNativeProps = function setNativeProps( + nativeProps + ) { + // Class components don't have viewConfig -> validateAttributes. + // Nor does it make sense to set native props on a non-native component. + // Instead, find the nearest host component and set props on it. + // Use findNodeHandle() rather than ReactNative.findNodeHandle() because + // We want the instance/wrapper (not the native tag). + var maybeInstance = void 0; + + // Fiber errors if findNodeHandle is called for an umounted component. + // Tests using ReactTestRenderer will trigger this case indirectly. + // Mimicking stack behavior, we should silently ignore this case. + // TODO Fix ReactTestRenderer so we can remove this try/catch. + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + + // If there is no host component beneath this we should fail silently. + // This is not an error; it could mean a class component rendered null. + if (maybeInstance == null) { + return; + } + + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + + var updatePayload = create(nativeProps, viewConfig.validAttributes); + + // Avoid the overhead of bridge calls if there's no update. + // This is an expensive no-op for Android, and causes an unnecessary + // view invalidation for certain components (eg RCTTextInput) on iOS. + if (updatePayload != null) { + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + updatePayload + ); + } + }; + + return ReactNativeComponent; + })(React.Component); + + // eslint-disable-next-line no-unused-expressions return ReactNativeComponent; -})(React.Component); +}; + +/** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + * + * Note that this module is currently shared and assumed to be stateless. + * If this becomes an actual Map, that will break. + */ + +/** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ + +function get$1(key) { + return key._reactInternalFiber; +} + +function set(key, value) { + key._reactInternalFiber = value; +} + +var ReactInternals = React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; + +var ReactCurrentOwner = ReactInternals.ReactCurrentOwner; +var ReactDebugCurrentFrame = ReactInternals.ReactDebugCurrentFrame; // Don't change these two values. They're used by React Dev Tools. var NoEffect = /* */ 0; @@ -4241,7 +3849,7 @@ function isMounted(component) { } } - var fiber = get(component); + var fiber = get$1(component); if (!fiber) { return false; } @@ -6205,7 +5813,7 @@ var ReactFiberClassComponent = function( var updater = { isMounted: isMounted, enqueueSetState: function(instance, partialState, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "setState"); @@ -6224,7 +5832,7 @@ var ReactFiberClassComponent = function( scheduleWork(fiber, expirationTime); }, enqueueReplaceState: function(instance, state, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "replaceState"); @@ -6243,7 +5851,7 @@ var ReactFiberClassComponent = function( scheduleWork(fiber, expirationTime); }, enqueueForceUpdate: function(instance, callback) { - var fiber = get(instance); + var fiber = get$1(instance); callback = callback === undefined ? null : callback; { warnOnInvalidCallback(callback, "forceUpdate"); @@ -9676,7 +9284,7 @@ var ReactFiberCompleteWork = function( function markUpdate(workInProgress) { // Tag the fiber with an update effect. This turns a Placement into - // an UpdateAndPlacement. + // a PlacementAndUpdate. workInProgress.effectTag |= Update; } @@ -13876,7 +13484,7 @@ var ReactFiberReconciler$1 = function(config) { return emptyObject; } - var fiber = get(parentComponent); + var fiber = get$1(parentComponent); var parentContext = findCurrentUnmaskedContext(fiber); return isContextProvider(fiber) ? processChildContext(fiber, parentContext) @@ -13974,7 +13582,19 @@ var ReactFiberReconciler$1 = function(config) { ); } - function findHostInstance(fiber) { + function findHostInstance(component) { + var fiber = get$1(component); + if (fiber === undefined) { + if (typeof component.render === "function") { + invariant(false, "Unable to find node on an unmounted component."); + } else { + invariant( + false, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + ); + } + } var hostFiber = findCurrentHostFiber(fiber); if (hostFiber === null) { return null; @@ -14067,7 +13687,11 @@ var ReactFiberReconciler$1 = function(config) { return injectInternals( Object.assign({}, devToolsConfig, { findHostInstanceByFiber: function(fiber) { - return findHostInstance(fiber); + var hostFiber = findCurrentHostFiber(fiber); + if (hostFiber === null) { + return null; + } + return hostFiber.stateNode; }, findFiberByHostInstance: function(instance) { if (!findFiberByHostInstance) { @@ -14097,50 +13721,7 @@ var reactReconciler = ReactFiberReconciler$3["default"] ? ReactFiberReconciler$3["default"] : ReactFiberReconciler$3; -var viewConfigCallbacks = new Map(); -var viewConfigs = new Map(); - -/** - * Registers a native view/component by name. - * A callback is provided to load the view config from UIManager. - * The callback is deferred until the view is actually rendered. - * This is done to avoid causing Prepack deopts. - */ -function register(name, callback) { - invariant( - !viewConfigCallbacks.has(name), - "Tried to register two views with the same name %s", - name - ); - viewConfigCallbacks.set(name, callback); - return name; -} - -/** - * Retrieves a config for the specified view. - * If this is the first time the view has been used, - * This configuration will be lazy-loaded from UIManager. - */ -function get$1(name) { - var viewConfig = void 0; - if (!viewConfigs.has(name)) { - var callback = viewConfigCallbacks.get(name); - invariant( - typeof callback === "function", - "View config not found for name %s", - name - ); - viewConfigCallbacks.set(name, null); - viewConfig = callback(); - viewConfigs.set(name, viewConfig); - } else { - viewConfig = viewConfigs.get(name); - } - invariant(viewConfig, "View config not found for name %s", name); - return viewConfig; -} - -function _classCallCheck$2(instance, Constructor) { +function _classCallCheck$1(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } @@ -14157,7 +13738,7 @@ function _classCallCheck$2(instance, Constructor) { var ReactNativeFiberHostComponent = (function() { function ReactNativeFiberHostComponent(tag, viewConfig) { - _classCallCheck$2(this, ReactNativeFiberHostComponent); + _classCallCheck$1(this, ReactNativeFiberHostComponent); this._nativeTag = tag; this._children = []; @@ -14272,6 +13853,19 @@ function cancelDeferredCallback(callbackID) { } // Modules provided by RN: +// Counter for uniquely identifying views. +// % 10 === 1 means it is a rootTag. +// % 2 === 0 means it is a Fabric tag. +var nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + if (tag % 10 === 1) { + tag += 2; + } + nextReactTag = tag + 2; + return tag; +} + function recursivelyUncacheFiberNode(node) { if (typeof node === "number") { // Leaf node (eg text) @@ -14294,8 +13888,8 @@ var NativeRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - var tag = ReactNativeTagHandles.allocateTag(); - var viewConfig = get$1(type); + var tag = allocateTag(); + var viewConfig = ReactNativeViewConfigRegistry.get(type); { for (var key in viewConfig.validAttributes) { @@ -14329,7 +13923,7 @@ var NativeRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - var tag = ReactNativeTagHandles.allocateTag(); + var tag = allocateTag(); UIManager.createView( tag, // reactTag @@ -14665,49 +14259,52 @@ var getInspectorDataForViewTag = void 0; }; } -/** - * Creates a renderable ReactNative host component. - * Use this method for view configs that are loaded from UIManager. - * Use createReactNativeComponentClass() for view configs defined within JavaScript. - * - * @param {string} config iOS View configuration. - * @private - */ -var createReactNativeComponentClass = function(name, callback) { - return register(name, callback); -}; - // Module provided by RN: -/** - * Capture an image of the screen, window or an individual view. The image - * will be stored in a temporary file that will only exist for as long as the - * app is running. - * - * The `view` argument can be the literal string `window` if you want to - * capture the entire window, or it can be a reference to a specific - * React Native component. - * - * The `options` argument may include: - * - width/height (number) - the width and height of the image to capture. - * - format (string) - either 'png' or 'jpeg'. Defaults to 'png'. - * - quality (number) - the quality when using jpeg. 0.0 - 1.0 (default). - * - * Returns a Promise. - * @platform ios - */ -function takeSnapshot(view, options) { - if (typeof view !== "number" && view !== "window") { - view = findNumericNodeHandleFiber(view) || "window"; +var findHostInstance = NativeRenderer.findHostInstance; + +function findNodeHandle(componentOrHandle) { + { + var owner = ReactCurrentOwner.current; + if (owner !== null && owner.stateNode !== null) { + !owner.stateNode._warnedAboutRefsInRender + ? warning( + false, + "%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(owner) || "A component" + ) + : void 0; + + owner.stateNode._warnedAboutRefsInRender = true; + } } - - // Call the hidden '__takeSnapshot' method; the main one throws an error to - // prevent accidental backwards-incompatible usage. - return UIManager.__takeSnapshot(view, options); + if (componentOrHandle == null) { + return null; + } + if (typeof componentOrHandle === "number") { + // Already a node handle + return componentOrHandle; + } + if (componentOrHandle._nativeTag) { + return componentOrHandle._nativeTag; + } + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) { + return componentOrHandle.canonical._nativeTag; + } + var hostInstance = findHostInstance(componentOrHandle); + if (hostInstance == null) { + return hostInstance; + } + if (hostInstance.canonical) { + // Fabric + return hostInstance.canonical._nativeTag; + } + return hostInstance._nativeTag; } -// Module provided by RN: -injectFindHostInstance(NativeRenderer.findHostInstance); - injection$2.injectRenderer(NativeRenderer); function computeComponentStackForErrorReporting(reactTag) { @@ -14721,9 +14318,9 @@ function computeComponentStackForErrorReporting(reactTag) { var roots = new Map(); var ReactNativeRenderer = { - NativeComponent: ReactNativeComponent, + NativeComponent: ReactNativeComponent(findNodeHandle, findHostInstance), - findNodeHandle: findNumericNodeHandleFiber, + findNodeHandle: findNodeHandle, render: function(element, containerTag, callback) { var root = roots.get(containerTag); @@ -14762,18 +14359,11 @@ var ReactNativeRenderer = { unstable_batchedUpdates: batchedUpdates, - flushSync: NativeRenderer.flushSync, - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { // Used as a mixin in many createClass-based components - NativeMethodsMixin: NativeMethodsMixin, + NativeMethodsMixin: NativeMethodsMixin(findNodeHandle, findHostInstance), // Used by react-native-github/Libraries/ components - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, // requireNativeComponent ReactNativeComponentTree: ReactNativeComponentTree, // ScrollResponder - ReactNativePropRegistry: ReactNativePropRegistry, // flattenStyle, Stylesheet - TouchHistoryMath: TouchHistoryMath, // PanResponder - createReactNativeComponentClass: createReactNativeComponentClass, // RCTText, RCTView, ReactNativeART - takeSnapshot: takeSnapshot, // react-native-implementation computeComponentStackForErrorReporting: computeComponentStackForErrorReporting } }; diff --git a/Libraries/Renderer/ReactNativeRenderer-prod.js b/Libraries/Renderer/ReactNativeRenderer-prod.js index bf2480f1c03..10e7f6b5fc9 100644 --- a/Libraries/Renderer/ReactNativeRenderer-prod.js +++ b/Libraries/Renderer/ReactNativeRenderer-prod.js @@ -13,6 +13,7 @@ require("InitializeCore"); var invariant = require("fbjs/lib/invariant"), emptyFunction = require("fbjs/lib/emptyFunction"), + ReactNativeViewConfigRegistry = require("ReactNativeViewConfigRegistry"), UIManager = require("UIManager"), RCTEventEmitter = require("RCTEventEmitter"), TextInputState = require("TextInputState"), @@ -624,7 +625,7 @@ function changeResponder(nextResponderInst, blockHostResponder) { blockHostResponder ); } -var eventTypes = { +var eventTypes$1 = { startShouldSetResponder: { phasedRegistrationNames: { bubbled: "onStartShouldSetResponder", @@ -664,7 +665,7 @@ var eventTypes = { _getResponder: function() { return responderInst; }, - eventTypes: eventTypes, + eventTypes: eventTypes$1, extractEvents: function( topLevelType, targetInst, @@ -690,12 +691,12 @@ var eventTypes = { isMoveish(topLevelType)) ) { var JSCompiler_temp = isStartish(topLevelType) - ? eventTypes.startShouldSetResponder + ? eventTypes$1.startShouldSetResponder : isMoveish(topLevelType) - ? eventTypes.moveShouldSetResponder + ? eventTypes$1.moveShouldSetResponder : "topSelectionChange" === topLevelType - ? eventTypes.selectionChangeShouldSetResponder - : eventTypes.scrollShouldSetResponder; + ? eventTypes$1.selectionChangeShouldSetResponder + : eventTypes$1.scrollShouldSetResponder; if (responderInst) b: { var JSCompiler_temp$jscomp$0 = responderInst; @@ -781,7 +782,7 @@ var eventTypes = { JSCompiler_temp && JSCompiler_temp !== responderInst ? ((JSCompiler_temp$jscomp$0 = void 0), (targetInst = ResponderSyntheticEvent.getPooled( - eventTypes.responderGrant, + eventTypes$1.responderGrant, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -791,7 +792,7 @@ var eventTypes = { (depthA = !0 === executeDirectDispatch(targetInst)), responderInst ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminationRequest, + eventTypes$1.responderTerminationRequest, responderInst, nativeEvent, nativeEventTarget @@ -803,7 +804,7 @@ var eventTypes = { tempA.isPersistent() || tempA.constructor.release(tempA), tempB ? ((tempA = ResponderSyntheticEvent.getPooled( - eventTypes.responderTerminate, + eventTypes$1.responderTerminate, responderInst, nativeEvent, nativeEventTarget @@ -817,7 +818,7 @@ var eventTypes = { )), changeResponder(JSCompiler_temp, depthA)) : ((JSCompiler_temp = ResponderSyntheticEvent.getPooled( - eventTypes.responderReject, + eventTypes$1.responderReject, JSCompiler_temp, nativeEvent, nativeEventTarget @@ -845,10 +846,10 @@ var eventTypes = { depthA = responderInst && isEndish(topLevelType); if ( (JSCompiler_temp$jscomp$0 = JSCompiler_temp$jscomp$0 - ? eventTypes.responderStart + ? eventTypes$1.responderStart : targetInst - ? eventTypes.responderMove - : depthA ? eventTypes.responderEnd : null) + ? eventTypes$1.responderMove + : depthA ? eventTypes$1.responderEnd : null) ) (JSCompiler_temp$jscomp$0 = ResponderSyntheticEvent.getPooled( JSCompiler_temp$jscomp$0, @@ -899,8 +900,8 @@ var eventTypes = { } if ( (topLevelType = JSCompiler_temp$jscomp$0 - ? eventTypes.responderTerminate - : topLevelType ? eventTypes.responderRelease : null) + ? eventTypes$1.responderTerminate + : topLevelType ? eventTypes$1.responderRelease : null) ) (nativeEvent = ResponderSyntheticEvent.getPooled( topLevelType, @@ -932,10 +933,12 @@ var eventTypes = { } } }, - customBubblingEventTypes = {}, - customDirectEventTypes = {}, + customBubblingEventTypes$1 = + ReactNativeViewConfigRegistry.customBubblingEventTypes, + customDirectEventTypes$1 = + ReactNativeViewConfigRegistry.customDirectEventTypes, ReactNativeBridgeEventPlugin = { - eventTypes: {}, + eventTypes: ReactNativeViewConfigRegistry.eventTypes, extractEvents: function( topLevelType, targetInst, @@ -943,8 +946,8 @@ var eventTypes = { nativeEventTarget ) { if (null == targetInst) return null; - var bubbleDispatchConfig = customBubblingEventTypes[topLevelType], - directDispatchConfig = customDirectEventTypes[topLevelType]; + var bubbleDispatchConfig = customBubblingEventTypes$1[topLevelType], + directDispatchConfig = customDirectEventTypes$1[topLevelType]; invariant( bubbleDispatchConfig || directDispatchConfig, 'Unsupported top level event type "%s" dispatched', @@ -962,24 +965,6 @@ var eventTypes = { forEachAccumulated(topLevelType, accumulateDirectDispatchesSingle); else return null; return topLevelType; - }, - processEventTypes: function(viewConfig) { - var bubblingEventTypes = viewConfig.bubblingEventTypes; - viewConfig = viewConfig.directEventTypes; - if (null != bubblingEventTypes) - for (var _topLevelType in bubblingEventTypes) - null == customBubblingEventTypes[_topLevelType] && - (ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType - ] = customBubblingEventTypes[_topLevelType] = - bubblingEventTypes[_topLevelType]); - if (null != viewConfig) - for (var _topLevelType2 in viewConfig) - null == customDirectEventTypes[_topLevelType2] && - (ReactNativeBridgeEventPlugin.eventTypes[ - _topLevelType2 - ] = customDirectEventTypes[_topLevelType2] = - viewConfig[_topLevelType2]); } }, instanceCache = {}, @@ -1067,28 +1052,7 @@ function batchedUpdates(fn, bookkeeping) { restoreStateOfTarget(fn[bookkeeping]); } } -var ReactNativeTagHandles = { - tagsStartAt: 1, - tagCount: 1, - allocateTag: function() { - for (; this.reactTagIsNativeTopRootID(ReactNativeTagHandles.tagCount); ) - ReactNativeTagHandles.tagCount++; - var tag = ReactNativeTagHandles.tagCount; - ReactNativeTagHandles.tagCount++; - return tag; - }, - assertRootTag: function(tag) { - invariant( - this.reactTagIsNativeTopRootID(tag), - "Expect a native root tag, instead got %s", - tag - ); - }, - reactTagIsNativeTopRootID: function(reactTag) { - return 1 === reactTag % 10; - } - }, - EMPTY_NATIVE_EVENT = {}; +var EMPTY_NATIVE_EVENT = {}; function _receiveRootNodeIDEvent(rootNodeID, topLevelType, nativeEventParam) { var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT, inst = getInstanceFromTag(rootNodeID); @@ -1153,10 +1117,7 @@ var ReactNativeEventEmitter = Object.freeze({ i.touches = touches; index = null; var target = i.target; - null === target || - void 0 === target || - target < ReactNativeTagHandles.tagsStartAt || - (index = target); + null === target || void 0 === target || 1 > target || (index = target); _receiveRootNodeIDEvent(index, eventTopLevelType, i); } } @@ -1197,103 +1158,6 @@ function createPortal(children, containerInfo, implementation) { implementation: implementation }; } -var TouchHistoryMath = { - centroidDimension: function( - touchHistory, - touchesChangedAfter, - isXAxis, - ofCurrent - ) { - var touchBank = touchHistory.touchBank, - total = 0, - count = 0; - touchHistory = - 1 === touchHistory.numberActiveTouches - ? touchHistory.touchBank[touchHistory.indexOfSingleActiveTouch] - : null; - if (null !== touchHistory) - touchHistory.touchActive && - touchHistory.currentTimeStamp > touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchHistory.currentPageX - : ofCurrent && !isXAxis - ? touchHistory.currentPageY - : !ofCurrent && isXAxis - ? touchHistory.previousPageX - : touchHistory.previousPageY), - (count = 1)); - else - for (touchHistory = 0; touchHistory < touchBank.length; touchHistory++) { - var touchTrack = touchBank[touchHistory]; - null !== touchTrack && - void 0 !== touchTrack && - touchTrack.touchActive && - touchTrack.currentTimeStamp >= touchesChangedAfter && - ((total += - ofCurrent && isXAxis - ? touchTrack.currentPageX - : ofCurrent && !isXAxis - ? touchTrack.currentPageY - : !ofCurrent && isXAxis - ? touchTrack.previousPageX - : touchTrack.previousPageY), - count++); - } - return 0 < count ? total / count : TouchHistoryMath.noCentroid; - }, - currentCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !0 - ); - }, - currentCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !0 - ); - }, - previousCentroidXOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !0, - !1 - ); - }, - previousCentroidYOfTouchesChangedAfter: function( - touchHistory, - touchesChangedAfter - ) { - return TouchHistoryMath.centroidDimension( - touchHistory, - touchesChangedAfter, - !1, - !1 - ); - }, - currentCentroidX: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !0, !0); - }, - currentCentroidY: function(touchHistory) { - return TouchHistoryMath.centroidDimension(touchHistory, 0, !1, !0); - }, - noCentroid: -1 -}; function getComponentName(fiber) { fiber = fiber.type; if ("function" === typeof fiber) return fiber.displayName || fiber.name; @@ -1343,37 +1207,9 @@ function getStackAddendumByWorkInProgressFiber(workInProgress) { } while (workInProgress); return info; } -var objects = {}, - uniqueID = 1, - emptyObject$2 = {}, - ReactNativePropRegistry = (function() { - function ReactNativePropRegistry() { - if (!(this instanceof ReactNativePropRegistry)) - throw new TypeError("Cannot call a class as a function"); - } - ReactNativePropRegistry.register = function(object) { - var id = ++uniqueID; - objects[id] = object; - return id; - }; - ReactNativePropRegistry.getByID = function(id) { - if (!id) return emptyObject$2; - var object = objects[id]; - return object - ? object - : (console.warn("Invalid style with id `" + id + "`. Skipping ..."), - emptyObject$2); - }; - return ReactNativePropRegistry; - })(), - emptyObject$1 = {}, +var emptyObject$1 = {}, removedKeys = null, removedKeyCount = 0; -function resolveObject(idOrObject) { - return "number" === typeof idOrObject - ? ReactNativePropRegistry.getByID(idOrObject) - : idOrObject; -} function restoreDeletedValuesInNestedArray( updatePayload, node, @@ -1387,7 +1223,7 @@ function restoreDeletedValuesInNestedArray( validAttributes ); else if (node && 0 < removedKeyCount) - for (i in ((node = resolveObject(node)), removedKeys)) + for (i in removedKeys) if (removedKeys[i]) { var _nextProp = node[i]; if (void 0 !== _nextProp) { @@ -1426,12 +1262,7 @@ function diffNestedProperty( ? clearNestedProperty(updatePayload, prevProp, validAttributes) : updatePayload; if (!Array.isArray(prevProp) && !Array.isArray(nextProp)) - return diffProperties( - updatePayload, - resolveObject(prevProp), - resolveObject(nextProp), - validAttributes - ); + return diffProperties(updatePayload, prevProp, nextProp, validAttributes); if (Array.isArray(prevProp) && Array.isArray(nextProp)) { var minLength = prevProp.length < nextProp.length ? prevProp.length : nextProp.length, @@ -1461,12 +1292,12 @@ function diffNestedProperty( ? diffProperties( updatePayload, flattenStyle(prevProp), - resolveObject(nextProp), + nextProp, validAttributes ) : diffProperties( updatePayload, - resolveObject(prevProp), + prevProp, flattenStyle(nextProp), validAttributes ); @@ -1474,9 +1305,11 @@ function diffNestedProperty( function addNestedProperty(updatePayload, nextProp, validAttributes) { if (!nextProp) return updatePayload; if (!Array.isArray(nextProp)) - return ( - (nextProp = resolveObject(nextProp)), - diffProperties(updatePayload, emptyObject$1, nextProp, validAttributes) + return diffProperties( + updatePayload, + emptyObject$1, + nextProp, + validAttributes ); for (var i = 0; i < nextProp.length; i++) updatePayload = addNestedProperty( @@ -1489,9 +1322,11 @@ function addNestedProperty(updatePayload, nextProp, validAttributes) { function clearNestedProperty(updatePayload, prevProp, validAttributes) { if (!prevProp) return updatePayload; if (!Array.isArray(prevProp)) - return ( - (prevProp = resolveObject(prevProp)), - diffProperties(updatePayload, prevProp, emptyObject$1, validAttributes) + return diffProperties( + updatePayload, + prevProp, + emptyObject$1, + validAttributes ); for (var i = 0; i < prevProp.length; i++) updatePayload = clearNestedProperty( @@ -1604,37 +1439,6 @@ function mountSafeCallback(context, callback) { } }; } -var ReactCurrentOwner = - React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; -function findHostInstance() { - return null; -} -function findNodeHandle(componentOrHandle) { - if (null == componentOrHandle) return null; - if ("number" === typeof componentOrHandle) return componentOrHandle; - var internalInstance = componentOrHandle._reactInternalFiber; - if (internalInstance) return findHostInstance(internalInstance) || null; - if (componentOrHandle) return componentOrHandle; - invariant( - ("object" === typeof componentOrHandle && - "_nativeTag" in componentOrHandle) || - (null != componentOrHandle.render && - "function" === typeof componentOrHandle.render), - "findNodeHandle(...): Argument is not a component (type: %s, keys: %s)", - typeof componentOrHandle, - Object.keys(componentOrHandle) - ); - invariant( - !1, - "findNodeHandle(...): Unable to find node handle for unmounted component." - ); -} -function findNumericNodeHandleFiber(componentOrHandle) { - componentOrHandle = findNodeHandle(componentOrHandle); - return null == componentOrHandle || "number" === typeof componentOrHandle - ? componentOrHandle - : componentOrHandle._nativeTag; -} function _inherits(subClass, superClass) { if ("function" !== typeof superClass && null !== superClass) throw new TypeError( @@ -1654,74 +1458,8 @@ function _inherits(subClass, superClass) { ? Object.setPrototypeOf(subClass, superClass) : (subClass.__proto__ = superClass)); } -var ReactNativeComponent = (function(_React$Component) { - function ReactNativeComponent() { - if (!(this instanceof ReactNativeComponent)) - throw new TypeError("Cannot call a class as a function"); - var call = _React$Component.apply(this, arguments); - if (!this) - throw new ReferenceError( - "this hasn't been initialised - super() hasn't been called" - ); - return !call || ("object" !== typeof call && "function" !== typeof call) - ? this - : call; - } - _inherits(ReactNativeComponent, _React$Component); - ReactNativeComponent.prototype.blur = function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - }; - ReactNativeComponent.prototype.focus = function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }; - ReactNativeComponent.prototype.measure = function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureInWindow = function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }; - ReactNativeComponent.prototype.measureLayout = function( - relativeToNativeNode, - onSuccess, - onFail - ) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }; - ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = - maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes - ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps - ); - } - }; - return ReactNativeComponent; -})(React.Component); +var ReactCurrentOwner = + React.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner; function isFiberMountedImpl(fiber) { var node = fiber; if (fiber.alternate) for (; node["return"]; ) node = node["return"]; @@ -6048,10 +5786,6 @@ function ReactFiberReconciler$1(config) { scheduleWork(currentTime, expirationTime); return expirationTime; } - function findHostInstance(fiber) { - fiber = findCurrentHostFiber(fiber); - return null === fiber ? null : fiber.stateNode; - } var getPublicInstance = config.getPublicInstance; config = ReactFiberScheduler(config); var recalculateCurrentTime = config.recalculateCurrentTime, @@ -6130,7 +5864,19 @@ function ReactFiberReconciler$1(config) { return container.child.stateNode; } }, - findHostInstance: findHostInstance, + findHostInstance: function(component) { + var fiber = component._reactInternalFiber; + void 0 === fiber && + ("function" === typeof component.render + ? invariant(!1, "Unable to find node on an unmounted component.") + : invariant( + !1, + "Argument appears to not be a ReactComponent. Keys: %s", + Object.keys(component) + )); + component = findCurrentHostFiber(fiber); + return null === component ? null : component.stateNode; + }, findHostInstanceWithNoPortals: function(fiber) { fiber = findCurrentHostFiberWithNoPortals(fiber); return null === fiber ? null : fiber.stateNode; @@ -6140,7 +5886,8 @@ function ReactFiberReconciler$1(config) { return injectInternals( Object.assign({}, devToolsConfig, { findHostInstanceByFiber: function(fiber) { - return findHostInstance(fiber); + fiber = findCurrentHostFiber(fiber); + return null === fiber ? null : fiber.stateNode; }, findFiberByHostInstance: function(instance) { return findFiberByHostInstance @@ -6159,8 +5906,6 @@ var ReactFiberReconciler$2 = Object.freeze({ default: ReactFiberReconciler$1 }), reactReconciler = ReactFiberReconciler$3["default"] ? ReactFiberReconciler$3["default"] : ReactFiberReconciler$3, - viewConfigCallbacks = new Map(), - viewConfigs = new Map(), ReactNativeFiberHostComponent = (function() { function ReactNativeFiberHostComponent(tag, viewConfig) { if (!(this instanceof ReactNativeFiberHostComponent)) @@ -6238,6 +5983,13 @@ function setTimeoutCallback() { scheduledCallback = null; null !== callback && callback(frameDeadlineObject); } +var nextReactTag = 3; +function allocateTag() { + var tag = nextReactTag; + 1 === tag % 10 && (tag += 2); + nextReactTag = tag + 2; + return tag; +} function recursivelyUncacheFiberNode(node) { "number" === typeof node ? uncacheFiberNode(node) @@ -6255,21 +6007,9 @@ var NativeRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - hostContext = ReactNativeTagHandles.allocateTag(); - if (viewConfigs.has(type)) var viewConfig = viewConfigs.get(type); - else - (viewConfig = viewConfigCallbacks.get(type)), - invariant( - "function" === typeof viewConfig, - "View config not found for name %s", - type - ), - viewConfigCallbacks.set(type, null), - (viewConfig = viewConfig()), - viewConfigs.set(type, viewConfig); - invariant(viewConfig, "View config not found for name %s", type); - type = viewConfig; - viewConfig = diffProperties( + hostContext = allocateTag(); + type = ReactNativeViewConfigRegistry.get(type); + var updatePayload = diffProperties( null, emptyObject$1, props, @@ -6279,7 +6019,7 @@ var NativeRenderer = reactReconciler({ hostContext, type.uiViewClassName, rootContainerInstance, - viewConfig + updatePayload ); rootContainerInstance = new ReactNativeFiberHostComponent( hostContext, @@ -6295,7 +6035,7 @@ var NativeRenderer = reactReconciler({ hostContext, internalInstanceHandle ) { - hostContext = ReactNativeTagHandles.allocateTag(); + hostContext = allocateTag(); UIManager.createView(hostContext, "RCTRawText", rootContainerInstance, { text: text }); @@ -6453,13 +6193,96 @@ var NativeRenderer = reactReconciler({ getInspectorDataForViewTag = function() { invariant(!1, "getInspectorDataForViewTag() is not available in production"); }; -findHostInstance = NativeRenderer.findHostInstance; +var findHostInstance = NativeRenderer.findHostInstance; +function findNodeHandle(componentOrHandle) { + if (null == componentOrHandle) return null; + if ("number" === typeof componentOrHandle) return componentOrHandle; + if (componentOrHandle._nativeTag) return componentOrHandle._nativeTag; + if (componentOrHandle.canonical && componentOrHandle.canonical._nativeTag) + return componentOrHandle.canonical._nativeTag; + componentOrHandle = findHostInstance(componentOrHandle); + return null == componentOrHandle + ? componentOrHandle + : componentOrHandle.canonical + ? componentOrHandle.canonical._nativeTag + : componentOrHandle._nativeTag; +} _batchedUpdates = NativeRenderer.batchedUpdates; _flushInteractiveUpdates = NativeRenderer.flushInteractiveUpdates; var roots = new Map(), ReactNativeRenderer = { - NativeComponent: ReactNativeComponent, - findNodeHandle: findNumericNodeHandleFiber, + NativeComponent: (function(findNodeHandle, findHostInstance) { + return (function(_React$Component) { + function ReactNativeComponent() { + if (!(this instanceof ReactNativeComponent)) + throw new TypeError("Cannot call a class as a function"); + var call = _React$Component.apply(this, arguments); + if (!this) + throw new ReferenceError( + "this hasn't been initialised - super() hasn't been called" + ); + return !call || + ("object" !== typeof call && "function" !== typeof call) + ? this + : call; + } + _inherits(ReactNativeComponent, _React$Component); + ReactNativeComponent.prototype.blur = function() { + TextInputState.blurTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.focus = function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }; + ReactNativeComponent.prototype.measure = function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureInWindow = function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }; + ReactNativeComponent.prototype.measureLayout = function( + relativeToNativeNode, + onSuccess, + onFail + ) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }; + ReactNativeComponent.prototype.setNativeProps = function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = + maybeInstance.viewConfig || maybeInstance.canonical.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes + ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }; + return ReactNativeComponent; + })(React.Component); + })(findNodeHandle, findHostInstance), + findNodeHandle: findNodeHandle, render: function(element, containerTag, callback) { var root = roots.get(containerTag); root || @@ -6488,76 +6311,59 @@ var roots = new Map(), ); }, unstable_batchedUpdates: batchedUpdates, - flushSync: NativeRenderer.flushSync, __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: { - NativeMethodsMixin: { - measure: function(callback) { - UIManager.measure( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - measureInWindow: function(callback) { - UIManager.measureInWindow( - findNumericNodeHandleFiber(this), - mountSafeCallback(this, callback) - ); - }, - measureLayout: function(relativeToNativeNode, onSuccess, onFail) { - UIManager.measureLayout( - findNumericNodeHandleFiber(this), - relativeToNativeNode, - mountSafeCallback(this, onFail), - mountSafeCallback(this, onSuccess) - ); - }, - setNativeProps: function(nativeProps) { - var maybeInstance = void 0; - try { - maybeInstance = findNodeHandle(this); - } catch (error) {} - if (null != maybeInstance) { - var viewConfig = maybeInstance.viewConfig; - nativeProps = diffProperties( - null, - emptyObject$1, - nativeProps, - viewConfig.validAttributes + NativeMethodsMixin: (function(findNodeHandle, findHostInstance) { + return { + measure: function(callback) { + UIManager.measure( + findNodeHandle(this), + mountSafeCallback(this, callback) ); - null != nativeProps && - UIManager.updateView( - maybeInstance._nativeTag, - viewConfig.uiViewClassName, - nativeProps + }, + measureInWindow: function(callback) { + UIManager.measureInWindow( + findNodeHandle(this), + mountSafeCallback(this, callback) + ); + }, + measureLayout: function(relativeToNativeNode, onSuccess, onFail) { + UIManager.measureLayout( + findNodeHandle(this), + relativeToNativeNode, + mountSafeCallback(this, onFail), + mountSafeCallback(this, onSuccess) + ); + }, + setNativeProps: function(nativeProps) { + var maybeInstance = void 0; + try { + maybeInstance = findHostInstance(this); + } catch (error) {} + if (null != maybeInstance) { + var viewConfig = maybeInstance.viewConfig; + nativeProps = diffProperties( + null, + emptyObject$1, + nativeProps, + viewConfig.validAttributes ); + null != nativeProps && + UIManager.updateView( + maybeInstance._nativeTag, + viewConfig.uiViewClassName, + nativeProps + ); + } + }, + focus: function() { + TextInputState.focusTextInput(findNodeHandle(this)); + }, + blur: function() { + TextInputState.blurTextInput(findNodeHandle(this)); } - }, - focus: function() { - TextInputState.focusTextInput(findNumericNodeHandleFiber(this)); - }, - blur: function() { - TextInputState.blurTextInput(findNumericNodeHandleFiber(this)); - } - }, - ReactNativeBridgeEventPlugin: ReactNativeBridgeEventPlugin, + }; + })(findNodeHandle, findHostInstance), ReactNativeComponentTree: ReactNativeComponentTree, - ReactNativePropRegistry: ReactNativePropRegistry, - TouchHistoryMath: TouchHistoryMath, - createReactNativeComponentClass: function(name, callback) { - invariant( - !viewConfigCallbacks.has(name), - "Tried to register two views with the same name %s", - name - ); - viewConfigCallbacks.set(name, callback); - return name; - }, - takeSnapshot: function(view, options) { - "number" !== typeof view && - "window" !== view && - (view = findNumericNodeHandleFiber(view) || "window"); - return UIManager.__takeSnapshot(view, options); - }, computeComponentStackForErrorReporting: function(reactTag) { return (reactTag = getInstanceFromTag(reactTag)) ? getStackAddendumByWorkInProgressFiber(reactTag) diff --git a/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js b/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js deleted file mode 100644 index 3170faedbad..00000000000 --- a/Libraries/Renderer/shims/ReactNativeBridgeEventPlugin.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @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 f20bb30faa7..fdee974ae88 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -69,19 +69,9 @@ 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? // And how much information to fill in for the above types. }; @@ -104,3 +94,16 @@ export type ReactNativeType = { __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType, }; + +export type ReactFabricType = { + NativeComponent: any, + findNodeHandle(componentOrHandle: any): ?number, + render( + element: React$Element, + containerTag: any, + callback: ?Function, + ): any, + unmountComponentAtNode(containerTag: number): any, + + __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType, +}; diff --git a/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js new file mode 100644 index 00000000000..ffb0fa213f3 --- /dev/null +++ b/Libraries/Renderer/shims/ReactNativeViewConfigRegistry.js @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule ReactNativeViewConfigRegistry + * @flow + */ +'use strict'; + +import type { + ReactNativeBaseComponentViewConfig, + ViewConfigGetter, +} from './ReactNativeTypes'; + +const invariant = require('fbjs/lib/invariant'); + +// Event configs +const customBubblingEventTypes = {}; +const customDirectEventTypes = {}; +const eventTypes = {}; + +exports.customBubblingEventTypes = customBubblingEventTypes; +exports.customDirectEventTypes = customDirectEventTypes; +exports.eventTypes = eventTypes; + +const viewConfigCallbacks = new Map(); +const viewConfigs = new Map(); + +function processEventTypes( + viewConfig: ReactNativeBaseComponentViewConfig, +): void { + const {bubblingEventTypes, directEventTypes} = viewConfig; + + if (__DEV__) { + if (bubblingEventTypes != null && directEventTypes != null) { + for (const topLevelType in directEventTypes) { + invariant( + bubblingEventTypes[topLevelType] == null, + 'Event cannot be both direct and bubbling: %s', + topLevelType, + ); + } + } + } + + if (bubblingEventTypes != null) { + for (const topLevelType in bubblingEventTypes) { + if (customBubblingEventTypes[topLevelType] == null) { + eventTypes[topLevelType] = customBubblingEventTypes[topLevelType] = + bubblingEventTypes[topLevelType]; + } + } + } + + if (directEventTypes != null) { + for (const topLevelType in directEventTypes) { + if (customDirectEventTypes[topLevelType] == null) { + eventTypes[topLevelType] = customDirectEventTypes[topLevelType] = + directEventTypes[topLevelType]; + } + } + } +} + +/** + * Registers a native view/component by name. + * A callback is provided to load the view config from UIManager. + * The callback is deferred until the view is actually rendered. + * This is done to avoid causing Prepack deopts. + */ +exports.register = function(name: string, callback: ViewConfigGetter): string { + invariant( + !viewConfigCallbacks.has(name), + 'Tried to register two views with the same name %s', + name, + ); + viewConfigCallbacks.set(name, callback); + return name; +}; + +/** + * Retrieves a config for the specified view. + * If this is the first time the view has been used, + * This configuration will be lazy-loaded from UIManager. + */ +exports.get = function(name: string): ReactNativeBaseComponentViewConfig { + let viewConfig; + if (!viewConfigs.has(name)) { + const callback = viewConfigCallbacks.get(name); + invariant( + typeof callback === 'function', + 'View config not found for name %s', + name, + ); + viewConfigCallbacks.set(name, null); + viewConfig = callback(); + processEventTypes(viewConfig); + viewConfigs.set(name, viewConfig); + } else { + viewConfig = viewConfigs.get(name); + } + invariant(viewConfig, 'View config not found for name %s', name); + return viewConfig; +}; diff --git a/Libraries/Renderer/shims/createReactNativeComponentClass.js b/Libraries/Renderer/shims/createReactNativeComponentClass.js index d5d2b8c5900..1a050e8b3cf 100644 --- a/Libraries/Renderer/shims/createReactNativeComponentClass.js +++ b/Libraries/Renderer/shims/createReactNativeComponentClass.js @@ -10,9 +10,23 @@ 'use strict'; -const { - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED, -} = require('ReactNative'); +import type {ViewConfigGetter} from './ReactNativeTypes'; -module.exports = - __SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.createReactNativeComponentClass; +const {register} = require('ReactNativeViewConfigRegistry'); + +/** + * Creates a renderable ReactNative host component. + * Use this method for view configs that are loaded from UIManager. + * Use createReactNativeComponentClass() for view configs defined within JavaScript. + * + * @param {string} config iOS View configuration. + * @private + */ +const createReactNativeComponentClass = function( + name: string, + callback: ViewConfigGetter, +): string { + return register(name, callback); +}; + +module.exports = createReactNativeComponentClass; diff --git a/Libraries/Text/FabricText.js b/Libraries/Text/FabricText.js index 1eedd8b181c..2b6748749b7 100644 --- a/Libraries/Text/FabricText.js +++ b/Libraries/Text/FabricText.js @@ -10,233 +10,4 @@ */ 'use strict'; -const React = require('React'); -const ReactNative = require('ReactNative'); -const ReactNativeViewAttributes = require('ReactNativeViewAttributes'); -const TextPropTypes = require('TextPropTypes'); -const Touchable = require('Touchable'); -const UIManager = require('UIManager'); - -const {createReactNativeComponentClass} = require('ReactFabricInternals'); -const mergeFast = require('mergeFast'); -const processColor = require('processColor'); -const {ViewContextTypes} = require('ViewContext'); - -import type {PressEvent} from 'CoreEventTypes'; -import type {TextProps} from 'TextProps'; -import type {ViewChildContext} from 'ViewContext'; - -type State = { - isHighlighted: boolean, -}; - -type RectOffset = { - top: number, - left: number, - right: number, - bottom: number, -}; - -const PRESS_RECT_OFFSET = {top: 20, left: 20, right: 20, bottom: 30}; - -const viewConfig = { - validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { - isHighlighted: true, - numberOfLines: true, - ellipsizeMode: true, - allowFontScaling: true, - disabled: true, - selectable: true, - selectionColor: true, - adjustsFontSizeToFit: true, - minimumFontScale: true, - textBreakStrategy: true, - }), - uiViewClassName: 'RCTText', -}; - -/** - * A React component for displaying text. - * - * See https://facebook.github.io/react-native/docs/text.html - */ -class Text extends ReactNative.NativeComponent { - static propTypes = TextPropTypes; - static childContextTypes = ViewContextTypes; - static contextTypes = ViewContextTypes; - - static defaultProps = { - accessible: true, - allowFontScaling: true, - ellipsizeMode: 'tail', - }; - - state = mergeFast(Touchable.Mixin.touchableGetInitialState(), { - isHighlighted: false, - }); - - viewConfig = viewConfig; - - getChildContext(): ViewChildContext { - return { - isInAParentText: true, - }; - } - - _handlers: ?Object; - - _hasPressHandler(): boolean { - return !!this.props.onPress || !!this.props.onLongPress; - } - /** - * These are assigned lazily the first time the responder is set to make plain - * text nodes as cheap as possible. - */ - touchableHandleActivePressIn: ?Function; - touchableHandleActivePressOut: ?Function; - touchableHandlePress: ?Function; - touchableHandleLongPress: ?Function; - touchableHandleResponderGrant: ?Function; - touchableHandleResponderMove: ?Function; - touchableHandleResponderRelease: ?Function; - touchableHandleResponderTerminate: ?Function; - touchableHandleResponderTerminationRequest: ?Function; - touchableGetPressRectOffset: ?Function; - - render(): React.Element { - let newProps = this.props; - if (this.props.onStartShouldSetResponder || this._hasPressHandler()) { - if (!this._handlers) { - this._handlers = { - onStartShouldSetResponder: (): boolean => { - const shouldSetFromProps = - this.props.onStartShouldSetResponder && - this.props.onStartShouldSetResponder(); - const setResponder = shouldSetFromProps || this._hasPressHandler(); - if (setResponder && !this.touchableHandleActivePressIn) { - // Attach and bind all the other handlers only the first time a touch - // actually happens. - for (const key in Touchable.Mixin) { - if (typeof Touchable.Mixin[key] === 'function') { - (this: any)[key] = Touchable.Mixin[key].bind(this); - } - } - this.touchableHandleActivePressIn = () => { - if ( - this.props.suppressHighlighting || - !this._hasPressHandler() - ) { - return; - } - this.setState({ - isHighlighted: true, - }); - }; - - this.touchableHandleActivePressOut = () => { - if ( - this.props.suppressHighlighting || - !this._hasPressHandler() - ) { - return; - } - this.setState({ - isHighlighted: false, - }); - }; - - this.touchableHandlePress = (e: PressEvent) => { - this.props.onPress && this.props.onPress(e); - }; - - this.touchableHandleLongPress = (e: PressEvent) => { - this.props.onLongPress && this.props.onLongPress(e); - }; - - this.touchableGetPressRectOffset = function(): RectOffset { - return this.props.pressRetentionOffset || PRESS_RECT_OFFSET; - }; - } - return setResponder; - }, - onResponderGrant: function(e: SyntheticEvent<>, dispatchID: string) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderGrant(e, dispatchID); - this.props.onResponderGrant && - this.props.onResponderGrant.apply(this, arguments); - }.bind(this), - onResponderMove: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderMove(e); - this.props.onResponderMove && - this.props.onResponderMove.apply(this, arguments); - }.bind(this), - onResponderRelease: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderRelease(e); - this.props.onResponderRelease && - this.props.onResponderRelease.apply(this, arguments); - }.bind(this), - onResponderTerminate: function(e: SyntheticEvent<>) { - // $FlowFixMe TouchableMixin handlers couldn't actually be null - this.touchableHandleResponderTerminate(e); - this.props.onResponderTerminate && - this.props.onResponderTerminate.apply(this, arguments); - }.bind(this), - onResponderTerminationRequest: function(): boolean { - // Allow touchable or props.onResponderTerminationRequest to deny - // the request - // $FlowFixMe TouchableMixin handlers couldn't actually be null - var allowTermination = this.touchableHandleResponderTerminationRequest(); - if (allowTermination && this.props.onResponderTerminationRequest) { - allowTermination = this.props.onResponderTerminationRequest.apply( - this, - arguments, - ); - } - return allowTermination; - }.bind(this), - }; - } - newProps = { - ...this.props, - ...this._handlers, - isHighlighted: this.state.isHighlighted, - }; - } - if (newProps.selectionColor != null) { - newProps = { - ...newProps, - selectionColor: processColor(newProps.selectionColor), - }; - } - if (Touchable.TOUCH_TARGET_DEBUG && newProps.onPress) { - newProps = { - ...newProps, - style: [this.props.style, {color: 'magenta'}], - }; - } - if (this.context.isInAParentText) { - return ; - } else { - return ; - } - } -} - -var RCTText = createReactNativeComponentClass( - viewConfig.uiViewClassName, - () => viewConfig, -); -var RCTVirtualText = RCTText; - -if (UIManager.RCTVirtualText) { - RCTVirtualText = createReactNativeComponentClass('RCTVirtualText', () => ({ - validAttributes: mergeFast(ReactNativeViewAttributes.UIView, { - isHighlighted: true, - }), - uiViewClassName: 'RCTVirtualText', - })); -} - -module.exports = Text; +module.exports = require('Text');