mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-24 04:16:00 +08:00
[ReactNative] Rename ReactIOS JS module (and relatives) to ReactNative.
This commit is contained in:
committed by
Christopher Chedeau
parent
1db2f07192
commit
ff00e1496c
15
Libraries/ReactNative/React.js
Normal file
15
Libraries/ReactNative/React.js
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule React
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
module.exports = require('ReactNative');
|
||||
135
Libraries/ReactNative/ReactNative.js
Normal file
135
Libraries/ReactNative/ReactNative.js
Normal file
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNative
|
||||
* @flow
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var ReactChildren = require('ReactChildren');
|
||||
var ReactClass = require('ReactClass');
|
||||
var ReactComponent = require('ReactComponent');
|
||||
var ReactContext = require('ReactContext');
|
||||
var ReactCurrentOwner = require('ReactCurrentOwner');
|
||||
var ReactElement = require('ReactElement');
|
||||
var ReactElementValidator = require('ReactElementValidator');
|
||||
var ReactInstanceHandles = require('ReactInstanceHandles');
|
||||
var ReactNativeDefaultInjection = require('ReactNativeDefaultInjection');
|
||||
var ReactNativeMount = require('ReactNativeMount');
|
||||
var ReactPropTypes = require('ReactPropTypes');
|
||||
|
||||
var deprecated = require('deprecated');
|
||||
var invariant = require('invariant');
|
||||
var onlyChild = require('onlyChild');
|
||||
|
||||
ReactNativeDefaultInjection.inject();
|
||||
|
||||
var createElement = ReactElement.createElement;
|
||||
var createFactory = ReactElement.createFactory;
|
||||
var cloneElement = ReactElement.cloneElement;
|
||||
|
||||
if (__DEV__) {
|
||||
createElement = ReactElementValidator.createElement;
|
||||
createFactory = ReactElementValidator.createFactory;
|
||||
cloneElement = ReactElementValidator.cloneElement;
|
||||
}
|
||||
|
||||
var resolveDefaultProps = function(element) {
|
||||
// Could be optimized, but not currently in heavy use.
|
||||
var defaultProps = element.type.defaultProps;
|
||||
var props = element.props;
|
||||
for (var propName in defaultProps) {
|
||||
if (props[propName] === undefined) {
|
||||
props[propName] = defaultProps[propName];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Experimental optimized element creation
|
||||
var augmentElement = function(element: ReactElement) {
|
||||
if (__DEV__) {
|
||||
invariant(
|
||||
false,
|
||||
'This optimized path should never be used in DEV mode because ' +
|
||||
'it does not provide validation. Check your JSX transform.'
|
||||
);
|
||||
}
|
||||
element._owner = ReactCurrentOwner.current;
|
||||
element._context = ReactContext.current;
|
||||
if (element.type.defaultProps) {
|
||||
resolveDefaultProps(element);
|
||||
}
|
||||
return element;
|
||||
};
|
||||
|
||||
var render = function(
|
||||
element: ReactElement,
|
||||
mountInto: number,
|
||||
callback?: ?(() => void)
|
||||
): ?ReactComponent {
|
||||
return ReactNativeMount.renderComponent(element, mountInto, callback);
|
||||
};
|
||||
|
||||
var ReactNative = {
|
||||
hasReactNativeInitialized: false,
|
||||
Children: {
|
||||
map: ReactChildren.map,
|
||||
forEach: ReactChildren.forEach,
|
||||
count: ReactChildren.count,
|
||||
only: onlyChild
|
||||
},
|
||||
Component: ReactComponent,
|
||||
PropTypes: ReactPropTypes,
|
||||
createClass: ReactClass.createClass,
|
||||
createElement: createElement,
|
||||
createFactory: createFactory,
|
||||
cloneElement: cloneElement,
|
||||
_augmentElement: augmentElement,
|
||||
render: render,
|
||||
unmountComponentAtNode: ReactNativeMount.unmountComponentAtNode,
|
||||
|
||||
// Hook for JSX spread, don't use this for anything else.
|
||||
__spread: Object.assign,
|
||||
|
||||
unmountComponentAtNodeAndRemoveContainer: ReactNativeMount.unmountComponentAtNodeAndRemoveContainer,
|
||||
isValidClass: ReactElement.isValidFactory,
|
||||
isValidElement: ReactElement.isValidElement,
|
||||
|
||||
// Deprecations (remove for 0.13)
|
||||
renderComponent: deprecated(
|
||||
'React',
|
||||
'renderComponent',
|
||||
'render',
|
||||
this,
|
||||
render
|
||||
),
|
||||
isValidComponent: deprecated(
|
||||
'React',
|
||||
'isValidComponent',
|
||||
'isValidElement',
|
||||
this,
|
||||
ReactElement.isValidElement
|
||||
)
|
||||
};
|
||||
|
||||
// Inject the runtime into a devtools global hook regardless of browser.
|
||||
// Allows for debugging when the hook is injected on the page.
|
||||
/* globals __REACT_DEVTOOLS_GLOBAL_HOOK__ */
|
||||
if (
|
||||
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' &&
|
||||
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') {
|
||||
__REACT_DEVTOOLS_GLOBAL_HOOK__.inject({
|
||||
CurrentOwner: ReactCurrentOwner,
|
||||
InstanceHandles: ReactInstanceHandles,
|
||||
Mount: ReactNativeMount,
|
||||
Reconciler: require('ReactReconciler'),
|
||||
TextComponent: require('ReactNativeTextComponent'),
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = ReactNative;
|
||||
42
Libraries/ReactNative/ReactNativeBaseComponentEnvironment.js
Normal file
42
Libraries/ReactNative/ReactNativeBaseComponentEnvironment.js
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeComponentEnvironment
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactNativeDOMIDOperations = require('ReactNativeDOMIDOperations');
|
||||
var ReactNativeReconcileTransaction = require('ReactNativeReconcileTransaction');
|
||||
|
||||
var ReactNativeComponentEnvironment = {
|
||||
|
||||
processChildrenUpdates: ReactNativeDOMIDOperations.dangerouslyProcessChildrenUpdates,
|
||||
|
||||
replaceNodeWithMarkupByID: ReactNativeDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID,
|
||||
|
||||
/**
|
||||
* Nothing to do for UIKit bridge.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
unmountIDFromEnvironment: function(/*rootNodeID*/) {
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {DOMElement} Element to clear.
|
||||
*/
|
||||
clearNode: function(/*containerView*/) {
|
||||
|
||||
},
|
||||
|
||||
ReactReconcileTransaction: ReactNativeReconcileTransaction,
|
||||
};
|
||||
|
||||
module.exports = ReactNativeComponentEnvironment;
|
||||
79
Libraries/ReactNative/ReactNativeBaseComponentMixin.js
Normal file
79
Libraries/ReactNative/ReactNativeBaseComponentMixin.js
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeComponentMixin
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var ReactInstanceMap = require('ReactInstanceMap');
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*
|
||||
* `mountImage`: A way to represent the potential to create lower level
|
||||
* resources whos `nodeHandle` can be discovered immediately by knowing the
|
||||
* `rootNodeID`. Today's web React represents this with `innerHTML` annotated
|
||||
* with DOM ids that match the `rootNodeID`.
|
||||
*
|
||||
* Opaque name TodaysWebReact FutureWebWorkerReact ReactNative
|
||||
* ----------------------------------------------------------------------------
|
||||
* mountImage innerHTML innerHTML {rootNodeID, tag}
|
||||
*
|
||||
*/
|
||||
var ReactNativeComponentMixin = {
|
||||
/**
|
||||
* This has no particular meaning in ReactNative. If this were in the DOM, this
|
||||
* would return the DOM node. There should be nothing that invokes this
|
||||
* method. Any current callers of this are mistaken - they should be invoking
|
||||
* `getNodeHandle`.
|
||||
*/
|
||||
getNativeNode: function() {
|
||||
// TODO (balpert): Wrap iOS native components in a composite wrapper, then
|
||||
// ReactInstanceMap.get here will always succeed
|
||||
return ReactNativeTagHandles.rootNodeIDToTag[
|
||||
(ReactInstanceMap.get(this) || this)._rootNodeID
|
||||
];
|
||||
},
|
||||
|
||||
getNodeHandle: function() {
|
||||
return ReactNativeTagHandles.rootNodeIDToTag[
|
||||
(ReactInstanceMap.get(this) || this)._rootNodeID
|
||||
];
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ReactNativeComponentMixin;
|
||||
103
Libraries/ReactNative/ReactNativeDOMIDOperations.js
Normal file
103
Libraries/ReactNative/ReactNativeDOMIDOperations.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeDOMIDOperations
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
|
||||
var RCTUIManager = require('NativeModules').UIManager;
|
||||
var ReactPerf = require('ReactPerf');
|
||||
|
||||
/**
|
||||
* Updates a component's children by processing a series of updates.
|
||||
* For each of the update/create commands, the `fromIndex` refers to the index
|
||||
* that the item existed at *before* any of the updates are applied, and the
|
||||
* `toIndex` refers to the index after *all* of the updates are applied
|
||||
* (including deletes/moves). TODO: refactor so this can be shared with
|
||||
* DOMChildrenOperations.
|
||||
*
|
||||
* @param {array<object>} updates List of update configurations.
|
||||
* @param {array<string>} markup List of markup strings - in the case of React
|
||||
* IOS, the ids of new components assumed to be already created.
|
||||
*/
|
||||
var dangerouslyProcessChildrenUpdates = function(childrenUpdates, markupList) {
|
||||
if (!childrenUpdates.length) {
|
||||
return;
|
||||
}
|
||||
var byContainerTag = {};
|
||||
// Group by parent ID - send them across the bridge in separate commands per
|
||||
// containerID.
|
||||
for (var i = 0; i < childrenUpdates.length; i++) {
|
||||
var update = childrenUpdates[i];
|
||||
var containerTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(update.parentID);
|
||||
var updates = byContainerTag[containerTag] || (byContainerTag[containerTag] = {});
|
||||
if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING) {
|
||||
(updates.moveFromIndices || (updates.moveFromIndices = [])).push(update.fromIndex);
|
||||
(updates.moveToIndices || (updates.moveToIndices = [])).push(update.toIndex);
|
||||
} else if (update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) {
|
||||
(updates.removeAtIndices || (updates.removeAtIndices = [])).push(update.fromIndex);
|
||||
} else if (update.type === ReactMultiChildUpdateTypes.INSERT_MARKUP) {
|
||||
var mountImage = markupList[update.markupIndex];
|
||||
var tag = mountImage.tag;
|
||||
var rootNodeID = mountImage.rootNodeID;
|
||||
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(rootNodeID, tag);
|
||||
(updates.addAtIndices || (updates.addAtIndices = [])).push(update.toIndex);
|
||||
(updates.addChildTags || (updates.addChildTags = [])).push(tag);
|
||||
}
|
||||
}
|
||||
// Note this enumeration order will be different on V8! Move `byContainerTag`
|
||||
// to a sparse array as soon as we confirm there are not horrible perf
|
||||
// penalties.
|
||||
for (var updateParentTagString in byContainerTag) {
|
||||
var updateParentTagNumber = +updateParentTagString;
|
||||
var childUpdatesToSend = byContainerTag[updateParentTagNumber];
|
||||
RCTUIManager.manageChildren(
|
||||
updateParentTagNumber,
|
||||
childUpdatesToSend.moveFromIndices,
|
||||
childUpdatesToSend.moveToIndices,
|
||||
childUpdatesToSend.addChildTags,
|
||||
childUpdatesToSend.addAtIndices,
|
||||
childUpdatesToSend.removeAtIndices
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Operations used to process updates to DOM nodes. This is made injectable via
|
||||
* `ReactComponent.DOMIDOperations`.
|
||||
*/
|
||||
var ReactNativeDOMIDOperations = {
|
||||
dangerouslyProcessChildrenUpdates: ReactPerf.measure(
|
||||
// FIXME(frantic): #4441289 Hack to avoid modifying react-tools
|
||||
'ReactDOMIDOperations',
|
||||
'dangerouslyProcessChildrenUpdates',
|
||||
dangerouslyProcessChildrenUpdates
|
||||
),
|
||||
|
||||
/**
|
||||
* Replaces a view that exists in the document with markup.
|
||||
*
|
||||
* @param {string} id ID of child to be replaced.
|
||||
* @param {string} markup Mount image to replace child with id.
|
||||
*/
|
||||
dangerouslyReplaceNodeWithMarkupByID: ReactPerf.measure(
|
||||
'ReactDOMIDOperations',
|
||||
'dangerouslyReplaceNodeWithMarkupByID',
|
||||
function(id, mountImage) {
|
||||
var oldTag = ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(id);
|
||||
RCTUIManager.replaceExistingNonRootView(oldTag, mountImage.tag);
|
||||
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(id, mountImage.tag);
|
||||
}
|
||||
),
|
||||
};
|
||||
|
||||
module.exports = ReactNativeDOMIDOperations;
|
||||
112
Libraries/ReactNative/ReactNativeDefaultInjection.js
Normal file
112
Libraries/ReactNative/ReactNativeDefaultInjection.js
Normal file
@@ -0,0 +1,112 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeDefaultInjection
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Make sure `setTimeout`/`setInterval` are patched correctly.
|
||||
*/
|
||||
require('InitializeJavaScriptAppEngine');
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var EventPluginUtils = require('EventPluginUtils');
|
||||
var IOSDefaultEventPluginOrder = require('IOSDefaultEventPluginOrder');
|
||||
var IOSNativeBridgeEventPlugin = require('IOSNativeBridgeEventPlugin');
|
||||
var NodeHandle = require('NodeHandle');
|
||||
var ReactClass = require('ReactClass');
|
||||
var ReactComponentEnvironment = require('ReactComponentEnvironment');
|
||||
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
|
||||
var ReactEmptyComponent = require('ReactEmptyComponent');
|
||||
var ReactInstanceHandles = require('ReactInstanceHandles');
|
||||
var ReactNativeComponentEnvironment = require('ReactNativeComponentEnvironment');
|
||||
var ReactNativeComponentMixin = require('ReactNativeComponentMixin');
|
||||
var ReactNativeGlobalInteractionHandler = require('ReactNativeGlobalInteractionHandler');
|
||||
var ReactNativeGlobalResponderHandler = require('ReactNativeGlobalResponderHandler');
|
||||
var ReactNativeMount = require('ReactNativeMount');
|
||||
var ReactNativeTextComponent = require('ReactNativeTextComponent');
|
||||
var ReactNativeComponent = require('ReactNativeComponent');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
var ResponderEventPlugin = require('ResponderEventPlugin');
|
||||
var UniversalWorkerNodeHandle = require('UniversalWorkerNodeHandle');
|
||||
|
||||
var createReactNativeComponentClass = require('createReactNativeComponentClass');
|
||||
var invariant = require('invariant');
|
||||
|
||||
// Just to ensure this gets packaged, since its only caller is from Native.
|
||||
require('RCTEventEmitter');
|
||||
require('RCTLog');
|
||||
require('RCTJSTimers');
|
||||
|
||||
function inject() {
|
||||
/**
|
||||
* Inject module for resolving DOM hierarchy and plugin ordering.
|
||||
*/
|
||||
EventPluginHub.injection.injectEventPluginOrder(IOSDefaultEventPluginOrder);
|
||||
EventPluginHub.injection.injectInstanceHandle(ReactInstanceHandles);
|
||||
|
||||
ResponderEventPlugin.injection.injectGlobalResponderHandler(
|
||||
ReactNativeGlobalResponderHandler
|
||||
);
|
||||
|
||||
ResponderEventPlugin.injection.injectGlobalInteractionHandler(
|
||||
ReactNativeGlobalInteractionHandler
|
||||
);
|
||||
|
||||
/**
|
||||
* Some important event plugins included by default (without having to require
|
||||
* them).
|
||||
*/
|
||||
EventPluginHub.injection.injectEventPluginsByName({
|
||||
'ResponderEventPlugin': ResponderEventPlugin,
|
||||
'IOSNativeBridgeEventPlugin': IOSNativeBridgeEventPlugin
|
||||
});
|
||||
|
||||
ReactUpdates.injection.injectReconcileTransaction(
|
||||
ReactNativeComponentEnvironment.ReactReconcileTransaction
|
||||
);
|
||||
|
||||
ReactUpdates.injection.injectBatchingStrategy(
|
||||
ReactDefaultBatchingStrategy
|
||||
);
|
||||
|
||||
ReactComponentEnvironment.injection.injectEnvironment(
|
||||
ReactNativeComponentEnvironment
|
||||
);
|
||||
|
||||
// Can't import View here because it depends on React to make its composite
|
||||
var RCTView = createReactNativeComponentClass({
|
||||
validAttributes: {},
|
||||
uiViewClassName: 'RCTView',
|
||||
});
|
||||
ReactEmptyComponent.injection.injectEmptyComponent(RCTView);
|
||||
|
||||
EventPluginUtils.injection.injectMount(ReactNativeMount);
|
||||
|
||||
ReactClass.injection.injectMixin(ReactNativeComponentMixin);
|
||||
|
||||
ReactNativeComponent.injection.injectTextComponentClass(
|
||||
ReactNativeTextComponent
|
||||
);
|
||||
ReactNativeComponent.injection.injectAutoWrapper(function(tag) {
|
||||
// Show a nicer error message for non-function tags
|
||||
var info = '';
|
||||
if (typeof tag === 'string' && /^[a-z]/.test(tag)) {
|
||||
info += ' Each component name should start with an uppercase letter.';
|
||||
}
|
||||
invariant(false, 'Expected a component class, got %s.%s', tag, info);
|
||||
});
|
||||
|
||||
NodeHandle.injection.injectImplementation(UniversalWorkerNodeHandle);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
inject: inject,
|
||||
};
|
||||
214
Libraries/ReactNative/ReactNativeEventEmitter.js
Normal file
214
Libraries/ReactNative/ReactNativeEventEmitter.js
Normal file
@@ -0,0 +1,214 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeEventEmitter
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var EventPluginHub = require('EventPluginHub');
|
||||
var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var NodeHandle = require('NodeHandle');
|
||||
var EventConstants = require('EventConstants');
|
||||
|
||||
var merge = require('merge');
|
||||
var warning = require('warning');
|
||||
|
||||
var topLevelTypes = EventConstants.topLevelTypes;
|
||||
|
||||
/**
|
||||
* Version of `ReactBrowserEventEmitter` that works on the receiving side of a
|
||||
* serialized worker boundary.
|
||||
*/
|
||||
|
||||
// Shared default empty native event - conserve memory.
|
||||
var EMPTY_NATIVE_EVENT = {};
|
||||
|
||||
/**
|
||||
* Selects a subsequence of `Touch`es, without destroying `touches`.
|
||||
*
|
||||
* @param {Array<Touch>} touches Deserialized touch objects.
|
||||
* @param {Array<number>} indices Indices by which to pull subsequence.
|
||||
* @return {Array<Touch>} Subsequence of touch objects.
|
||||
*/
|
||||
var touchSubsequence = function(touches, indices) {
|
||||
var ret = [];
|
||||
for (var i = 0; i < indices.length; i++) {
|
||||
ret.push(touches[indices[i]]);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO: Pool all of this.
|
||||
*
|
||||
* Destroys `touches` by removing touch objects at indices `indices`. This is
|
||||
* to maintain compatibility with W3C touch "end" events, where the active
|
||||
* touches don't include the set that has just been "ended".
|
||||
*
|
||||
* @param {Array<Touch>} touches Deserialized touch objects.
|
||||
* @param {Array<number>} indices Indices to remove from `touches`.
|
||||
* @return {Array<Touch>} Subsequence of removed touch objects.
|
||||
*/
|
||||
var removeTouchesAtIndices = function(
|
||||
touches: Array<Object>,
|
||||
indices: Array<number>
|
||||
): Array<Object> {
|
||||
var rippedOut = [];
|
||||
// use an unsafe downcast to alias to nullable elements,
|
||||
// so we can delete and then compact.
|
||||
var temp: Array<?Object> = (touches: Array<any>);
|
||||
for (var i = 0; i < indices.length; i++) {
|
||||
var index = indices[i];
|
||||
rippedOut.push(touches[index]);
|
||||
temp[index] = null;
|
||||
}
|
||||
var fillAt = 0;
|
||||
for (var j = 0; j < temp.length; j++) {
|
||||
var cur = temp[j];
|
||||
if (cur !== null) {
|
||||
temp[fillAt++] = cur;
|
||||
}
|
||||
}
|
||||
temp.length = fillAt;
|
||||
return rippedOut;
|
||||
};
|
||||
|
||||
/**
|
||||
* `ReactNativeEventEmitter` is used to attach top-level event listeners. For example:
|
||||
*
|
||||
* ReactNativeEventEmitter.putListener('myID', 'onClick', myFunction);
|
||||
*
|
||||
* This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
var ReactNativeEventEmitter = merge(ReactEventEmitterMixin, {
|
||||
|
||||
registrationNames: EventPluginHub.registrationNameModules,
|
||||
|
||||
putListener: EventPluginHub.putListener,
|
||||
|
||||
getListener: EventPluginHub.getListener,
|
||||
|
||||
deleteListener: EventPluginHub.deleteListener,
|
||||
|
||||
deleteAllListeners: EventPluginHub.deleteAllListeners,
|
||||
|
||||
/**
|
||||
* Internal version of `receiveEvent` in terms of normalized (non-tag)
|
||||
* `rootNodeID`.
|
||||
*
|
||||
* @see receiveEvent.
|
||||
*
|
||||
* @param {rootNodeID} rootNodeID React root node ID that event occured on.
|
||||
* @param {TopLevelType} topLevelType Top level type of event.
|
||||
* @param {object} nativeEventParam Object passed from native.
|
||||
*/
|
||||
_receiveRootNodeIDEvent: function(
|
||||
rootNodeID: ?string,
|
||||
topLevelType: string,
|
||||
nativeEventParam: Object
|
||||
) {
|
||||
var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
|
||||
ReactNativeEventEmitter.handleTopLevel(
|
||||
topLevelType,
|
||||
rootNodeID,
|
||||
rootNodeID,
|
||||
nativeEvent
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Publically exposed method on module for native objc to invoke when a top
|
||||
* level event is extracted.
|
||||
* @param {rootNodeID} rootNodeID React root node ID that event occured on.
|
||||
* @param {TopLevelType} topLevelType Top level type of event.
|
||||
* @param {object} nativeEventParam Object passed from native.
|
||||
*/
|
||||
receiveEvent: function(
|
||||
tag: number,
|
||||
topLevelType: string,
|
||||
nativeEventParam: Object
|
||||
) {
|
||||
var rootNodeID = ReactNativeTagHandles.tagToRootNodeID[tag];
|
||||
ReactNativeEventEmitter._receiveRootNodeIDEvent(
|
||||
rootNodeID,
|
||||
topLevelType,
|
||||
nativeEventParam
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Simple multi-wrapper around `receiveEvent` that is intended to receive an
|
||||
* efficient representation of `Touch` objects, and other information that
|
||||
* can be used to construct W3C compliant `Event` and `Touch` lists.
|
||||
*
|
||||
* This may create dispatch behavior that differs than web touch handling. We
|
||||
* loop through each of the changed touches and receive it as a single event.
|
||||
* So two `touchStart`/`touchMove`s that occur simultaneously are received as
|
||||
* two separate touch event dispatches - when they arguably should be one.
|
||||
*
|
||||
* This implementation reuses the `Touch` objects themselves as the `Event`s
|
||||
* since we dispatch an event for each touch (though that might not be spec
|
||||
* compliant). The main purpose of reusing them is to save allocations.
|
||||
*
|
||||
* TODO: Dispatch multiple changed touches in one event. The bubble path
|
||||
* could be the first common ancestor of all the `changedTouches`.
|
||||
*
|
||||
* One difference between this behavior and W3C spec: cancelled touches will
|
||||
* not appear in `.touches`, or in any future `.touches`, though they may
|
||||
* still be "actively touching the surface".
|
||||
*
|
||||
* Web desktop polyfills only need to construct a fake touch event with
|
||||
* identifier 0, also abandoning traditional click handlers.
|
||||
*/
|
||||
receiveTouches: function(
|
||||
eventTopLevelType: string,
|
||||
touches: Array<Object>,
|
||||
changedIndices: Array<number>
|
||||
) {
|
||||
var changedTouches =
|
||||
eventTopLevelType === topLevelTypes.topTouchEnd ||
|
||||
eventTopLevelType === topLevelTypes.topTouchCancel ?
|
||||
removeTouchesAtIndices(touches, changedIndices) :
|
||||
touchSubsequence(touches, changedIndices);
|
||||
|
||||
for (var jj = 0; jj < changedTouches.length; jj++) {
|
||||
var touch = changedTouches[jj];
|
||||
// Touch objects can fullfill the role of `DOM` `Event` objects if we set
|
||||
// the `changedTouches`/`touches`. This saves allocations.
|
||||
touch.changedTouches = changedTouches;
|
||||
touch.touches = touches;
|
||||
var nativeEvent = touch;
|
||||
var rootNodeID = null;
|
||||
var target = nativeEvent.target;
|
||||
if (target !== null && target !== undefined) {
|
||||
if (target < ReactNativeTagHandles.tagsStartAt) {
|
||||
if (__DEV__) {
|
||||
warning(
|
||||
false,
|
||||
'A view is reporting that a touch occured on tag zero.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
rootNodeID = NodeHandle.getRootNodeID(target);
|
||||
}
|
||||
}
|
||||
ReactNativeEventEmitter._receiveRootNodeIDEvent(
|
||||
rootNodeID,
|
||||
eventTopLevelType,
|
||||
nativeEvent
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = ReactNativeEventEmitter;
|
||||
33
Libraries/ReactNative/ReactNativeGlobalInteractionHandler.js
Normal file
33
Libraries/ReactNative/ReactNativeGlobalInteractionHandler.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeGlobalInteractionHandler
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var InteractionManager = require('InteractionManager');
|
||||
|
||||
// Interaction handle is created/cleared when responder is granted or
|
||||
// released/terminated.
|
||||
var interactionHandle = null;
|
||||
|
||||
var ReactNativeGlobalInteractionHandler = {
|
||||
onChange: function(numberActiveTouches: number) {
|
||||
if (numberActiveTouches === 0) {
|
||||
if (interactionHandle) {
|
||||
InteractionManager.clearInteractionHandle(interactionHandle);
|
||||
interactionHandle = null;
|
||||
}
|
||||
} else if (!interactionHandle) {
|
||||
interactionHandle = InteractionManager.createInteractionHandle();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ReactNativeGlobalInteractionHandler;
|
||||
29
Libraries/ReactNative/ReactNativeGlobalResponderHandler.js
Normal file
29
Libraries/ReactNative/ReactNativeGlobalResponderHandler.js
Normal file
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeGlobalResponderHandler
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var RCTUIManager = require('NativeModules').UIManager;
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
|
||||
var ReactNativeGlobalResponderHandler = {
|
||||
onChange: function(from: string, to: string) {
|
||||
if (to !== null) {
|
||||
RCTUIManager.setJSResponder(
|
||||
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(to)
|
||||
);
|
||||
} else {
|
||||
RCTUIManager.clearJSResponder();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = ReactNativeGlobalResponderHandler;
|
||||
241
Libraries/ReactNative/ReactNativeMount.js
Normal file
241
Libraries/ReactNative/ReactNativeMount.js
Normal file
@@ -0,0 +1,241 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeMount
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var RCTUIManager = require('NativeModules').UIManager;
|
||||
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var ReactPerf = require('ReactPerf');
|
||||
var ReactReconciler = require('ReactReconciler');
|
||||
var ReactUpdateQueue = require('ReactUpdateQueue');
|
||||
var ReactUpdates = require('ReactUpdates');
|
||||
|
||||
var emptyObject = require('emptyObject');
|
||||
var instantiateReactComponent = require('instantiateReactComponent');
|
||||
var invariant = require('invariant');
|
||||
var shouldUpdateReactComponent = require('shouldUpdateReactComponent');
|
||||
|
||||
function instanceNumberToChildRootID(rootNodeID, instanceNumber) {
|
||||
return rootNodeID + '[' + instanceNumber + ']';
|
||||
}
|
||||
|
||||
/**
|
||||
* Mounts this component and inserts it into the DOM.
|
||||
*
|
||||
* @param {ReactComponent} componentInstance The instance to mount.
|
||||
* @param {number} rootID ID of the root node.
|
||||
* @param {number} container container element to mount into.
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
*/
|
||||
function mountComponentIntoNode(
|
||||
componentInstance,
|
||||
rootID,
|
||||
container,
|
||||
transaction) {
|
||||
var markup = ReactReconciler.mountComponent(
|
||||
componentInstance, rootID, transaction, emptyObject
|
||||
);
|
||||
componentInstance._isTopLevel = true;
|
||||
ReactNativeMount._mountImageIntoNode(markup, container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Batched mount.
|
||||
*
|
||||
* @param {ReactComponent} componentInstance The instance to mount.
|
||||
* @param {number} rootID ID of the root node.
|
||||
* @param {number} container container element to mount into.
|
||||
*/
|
||||
function batchedMountComponentIntoNode(
|
||||
componentInstance,
|
||||
rootID,
|
||||
container) {
|
||||
var transaction = ReactUpdates.ReactReconcileTransaction.getPooled();
|
||||
transaction.perform(
|
||||
mountComponentIntoNode,
|
||||
null,
|
||||
componentInstance,
|
||||
rootID,
|
||||
container,
|
||||
transaction
|
||||
);
|
||||
ReactUpdates.ReactReconcileTransaction.release(transaction);
|
||||
}
|
||||
|
||||
/**
|
||||
* As soon as `ReactMount` is refactored to not rely on the DOM, we can share
|
||||
* code between the two. For now, we'll hard code the ID logic.
|
||||
*/
|
||||
var ReactNativeMount = {
|
||||
instanceCount: 0,
|
||||
|
||||
_instancesByContainerID: {},
|
||||
|
||||
/**
|
||||
* @param {ReactComponent} instance Instance to render.
|
||||
* @param {containerTag} containerView Handle to native view tag
|
||||
*/
|
||||
renderComponent: function(
|
||||
nextElement: ReactElement,
|
||||
containerTag: number,
|
||||
callback?: ?(() => void)
|
||||
): ?ReactComponent {
|
||||
var topRootNodeID = ReactNativeTagHandles.tagToRootNodeID[containerTag];
|
||||
if (topRootNodeID) {
|
||||
var prevComponent = ReactNativeMount._instancesByContainerID[topRootNodeID];
|
||||
if (prevComponent) {
|
||||
var prevElement = prevComponent._currentElement;
|
||||
if (shouldUpdateReactComponent(prevElement, nextElement)) {
|
||||
ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement);
|
||||
if (callback) {
|
||||
ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback);
|
||||
}
|
||||
return prevComponent;
|
||||
} else {
|
||||
ReactNativeMount.unmountComponentAtNode(containerTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
|
||||
console.error('You cannot render into anything but a top root');
|
||||
return;
|
||||
}
|
||||
|
||||
var topRootNodeID = ReactNativeTagHandles.allocateRootNodeIDForTag(containerTag);
|
||||
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
|
||||
topRootNodeID,
|
||||
containerTag
|
||||
);
|
||||
|
||||
var instance = instantiateReactComponent(nextElement);
|
||||
ReactNativeMount._instancesByContainerID[topRootNodeID] = instance;
|
||||
|
||||
var childRootNodeID = instanceNumberToChildRootID(
|
||||
topRootNodeID,
|
||||
ReactNativeMount.instanceCount++
|
||||
);
|
||||
|
||||
// The initial render is synchronous but any updates that happen during
|
||||
// rendering, in componentWillMount or componentDidMount, will be batched
|
||||
// according to the current batching strategy.
|
||||
|
||||
ReactUpdates.batchedUpdates(
|
||||
batchedMountComponentIntoNode,
|
||||
instance,
|
||||
childRootNodeID,
|
||||
topRootNodeID
|
||||
);
|
||||
var component = instance.getPublicInstance();
|
||||
if (callback) {
|
||||
callback.call(component);
|
||||
}
|
||||
return component;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {View} view View tree image.
|
||||
* @param {number} containerViewID View to insert sub-view into.
|
||||
*/
|
||||
_mountImageIntoNode: ReactPerf.measure(
|
||||
// FIXME(frantic): #4441289 Hack to avoid modifying react-tools
|
||||
'ReactComponentBrowserEnvironment',
|
||||
'mountImageIntoNode',
|
||||
function(mountImage, containerID) {
|
||||
// Since we now know that the `mountImage` has been mounted, we can
|
||||
// mark it as such.
|
||||
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
|
||||
mountImage.rootNodeID,
|
||||
mountImage.tag
|
||||
);
|
||||
var addChildTags = [mountImage.tag];
|
||||
var addAtIndices = [0];
|
||||
RCTUIManager.manageChildren(
|
||||
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
|
||||
null, // moveFromIndices
|
||||
null, // moveToIndices
|
||||
addChildTags,
|
||||
addAtIndices,
|
||||
null // removeAtIndices
|
||||
);
|
||||
}
|
||||
),
|
||||
|
||||
/**
|
||||
* Standard unmounting of the component that is rendered into `containerID`,
|
||||
* but will also execute a command to remove the actual container view
|
||||
* itself. This is useful when a client is cleaning up a React tree, and also
|
||||
* knows that the container will no longer be needed. When executing
|
||||
* asynchronously, it's easier to just have this method be the one that calls
|
||||
* for removal of the view.
|
||||
*/
|
||||
unmountComponentAtNodeAndRemoveContainer: function(
|
||||
containerTag: number
|
||||
) {
|
||||
ReactNativeMount.unmountComponentAtNode(containerTag);
|
||||
// call back into native to remove all of the subviews from this container
|
||||
RCTUIManager.removeRootView(containerTag);
|
||||
},
|
||||
|
||||
/**
|
||||
* Unmount component at container ID by iterating through each child component
|
||||
* that has been rendered and unmounting it. There should just be one child
|
||||
* component at this time.
|
||||
*/
|
||||
unmountComponentAtNode: function(containerTag: number): boolean {
|
||||
if (!ReactNativeTagHandles.reactTagIsNativeTopRootID(containerTag)) {
|
||||
console.error('You cannot render into anything but a top root');
|
||||
return false;
|
||||
}
|
||||
|
||||
var containerID = ReactNativeTagHandles.tagToRootNodeID[containerTag];
|
||||
var instance = ReactNativeMount._instancesByContainerID[containerID];
|
||||
if (!instance) {
|
||||
return false;
|
||||
}
|
||||
ReactNativeMount.unmountComponentFromNode(instance, containerID);
|
||||
delete ReactNativeMount._instancesByContainerID[containerID];
|
||||
return true;
|
||||
},
|
||||
|
||||
/**
|
||||
* Unmounts a component and sends messages back to iOS to remove its subviews.
|
||||
*
|
||||
* @param {ReactComponent} instance React component instance.
|
||||
* @param {string} containerID ID of container we're removing from.
|
||||
* @final
|
||||
* @internal
|
||||
* @see {ReactNativeMount.unmountComponentAtNode}
|
||||
*/
|
||||
unmountComponentFromNode: function(
|
||||
instance: ReactComponent,
|
||||
containerID: string
|
||||
) {
|
||||
// Call back into native to remove all of the subviews from this container
|
||||
ReactReconciler.unmountComponent(instance);
|
||||
var containerTag =
|
||||
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID);
|
||||
RCTUIManager.removeSubviewsFromContainerWithID(containerTag);
|
||||
},
|
||||
|
||||
getNode: function<T>(id: T): T {
|
||||
return id;
|
||||
}
|
||||
};
|
||||
|
||||
ReactNativeMount.renderComponent = ReactPerf.measure(
|
||||
'ReactMount',
|
||||
'_renderNewRootComponent',
|
||||
ReactNativeMount.renderComponent
|
||||
);
|
||||
|
||||
module.exports = ReactNativeMount;
|
||||
282
Libraries/ReactNative/ReactNativeNativeComponent.js
Normal file
282
Libraries/ReactNative/ReactNativeNativeComponent.js
Normal file
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeBaseComponent
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var NativeMethodsMixin = require('NativeMethodsMixin');
|
||||
var ReactNativeComponentMixin = require('ReactNativeComponentMixin');
|
||||
var ReactNativeEventEmitter = require('ReactNativeEventEmitter');
|
||||
var ReactNativeStyleAttributes = require('ReactNativeStyleAttributes');
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var ReactMultiChild = require('ReactMultiChild');
|
||||
var RCTUIManager = require('NativeModules').UIManager;
|
||||
|
||||
var styleDiffer = require('styleDiffer');
|
||||
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
|
||||
var diffRawProperties = require('diffRawProperties');
|
||||
var flattenStyle = require('flattenStyle');
|
||||
var precomputeStyle = require('precomputeStyle');
|
||||
var warning = require('warning');
|
||||
|
||||
var registrationNames = ReactNativeEventEmitter.registrationNames;
|
||||
var putListener = ReactNativeEventEmitter.putListener;
|
||||
var deleteAllListeners = ReactNativeEventEmitter.deleteAllListeners;
|
||||
|
||||
type ReactNativeBaseComponentViewConfig = {
|
||||
validAttributes: Object;
|
||||
uiViewClassName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @constructor ReactNativeBaseComponent
|
||||
* @extends ReactComponent
|
||||
* @extends ReactMultiChild
|
||||
* @param {!object} UIKit View Configuration.
|
||||
*/
|
||||
var ReactNativeBaseComponent = function(
|
||||
viewConfig: ReactNativeBaseComponentViewConfig
|
||||
) {
|
||||
this.viewConfig = viewConfig;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates and caches arrays of the form:
|
||||
*
|
||||
* [0, 1, 2, 3]
|
||||
* [0, 1, 2, 3, 4]
|
||||
* [0, 1]
|
||||
*
|
||||
* @param {number} size Size of array to generate.
|
||||
* @return {Array<number>} Array with values that mirror the index.
|
||||
*/
|
||||
var cachedIndexArray = function(size) {
|
||||
var cachedResult = cachedIndexArray._cache[size];
|
||||
if (!cachedResult) {
|
||||
var arr = [];
|
||||
for (var i = 0; i < size; i++) {
|
||||
arr[i] = i;
|
||||
}
|
||||
return cachedIndexArray._cache[size] = arr;
|
||||
} else {
|
||||
return cachedResult;
|
||||
}
|
||||
};
|
||||
cachedIndexArray._cache = {};
|
||||
|
||||
/**
|
||||
* Mixin for containers that contain UIViews. NOTE: markup is rendered markup
|
||||
* which is a `viewID` ... see the return value for `mountComponent` !
|
||||
*/
|
||||
ReactNativeBaseComponent.Mixin = {
|
||||
getPublicInstance: function() {
|
||||
// TODO: This should probably use a composite wrapper
|
||||
return this;
|
||||
},
|
||||
|
||||
construct: function(element) {
|
||||
this._currentElement = element;
|
||||
},
|
||||
|
||||
unmountComponent: function() {
|
||||
deleteAllListeners(this._rootNodeID);
|
||||
this.unmountChildren();
|
||||
this._rootNodeID = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Every native component is responsible for allocating its own `tag`, and
|
||||
* issuing the native `createView` command. But it is not responsible for
|
||||
* recording the fact that its own `rootNodeID` is associated with a
|
||||
* `nodeHandle`. Only the code that actually adds its `nodeHandle` (`tag`) as
|
||||
* a child of a container can confidently record that in
|
||||
* `ReactNativeTagHandles`.
|
||||
*/
|
||||
initializeChildren: function(children, containerTag, transaction, context) {
|
||||
var mountImages = this.mountChildren(children, transaction, context);
|
||||
// In a well balanced tree, half of the nodes are in the bottom row and have
|
||||
// no children - let's avoid calling out to the native bridge for a large
|
||||
// portion of the children.
|
||||
if (mountImages.length) {
|
||||
var indexes = cachedIndexArray(mountImages.length);
|
||||
// TODO: Pool these per platform view class. Reusing the `mountImages`
|
||||
// array would likely be a jit deopt.
|
||||
var createdTags = [];
|
||||
for (var i = 0; i < mountImages.length; i++) {
|
||||
var mountImage = mountImages[i];
|
||||
var childTag = mountImage.tag;
|
||||
var childID = mountImage.rootNodeID;
|
||||
warning(
|
||||
mountImage && mountImage.rootNodeID && mountImage.tag,
|
||||
'Mount image returned does not have required data'
|
||||
);
|
||||
ReactNativeTagHandles.associateRootNodeIDWithMountedNodeHandle(
|
||||
childID,
|
||||
childTag
|
||||
);
|
||||
createdTags[i] = mountImage.tag;
|
||||
}
|
||||
RCTUIManager
|
||||
.manageChildren(containerTag, null, null, createdTags, indexes, null);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Beware, this function has side effect to store this.previousFlattenedStyle!
|
||||
*
|
||||
* @param {!object} prevProps Previous properties
|
||||
* @param {!object} nextProps Next properties
|
||||
* @param {!object} validAttributes Set of valid attributes and how they
|
||||
* should be diffed
|
||||
*/
|
||||
computeUpdatedProperties: function(prevProps, nextProps, validAttributes) {
|
||||
if (__DEV__) {
|
||||
for (var key in nextProps) {
|
||||
if (nextProps.hasOwnProperty(key) &&
|
||||
nextProps[key] &&
|
||||
validAttributes[key]) {
|
||||
deepFreezeAndThrowOnMutationInDev(nextProps[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var updatePayload = diffRawProperties(
|
||||
null, // updatePayload
|
||||
prevProps,
|
||||
nextProps,
|
||||
validAttributes
|
||||
);
|
||||
|
||||
// The style property is a deeply nested element which includes numbers
|
||||
// to represent static objects. Most of the time, it doesn't change across
|
||||
// renders, so it's faster to spend the time checking if it is different
|
||||
// before actually doing the expensive flattening operation in order to
|
||||
// compute the diff.
|
||||
if (styleDiffer(nextProps.style, prevProps.style)) {
|
||||
var nextFlattenedStyle = precomputeStyle(flattenStyle(nextProps.style));
|
||||
updatePayload = diffRawProperties(
|
||||
updatePayload,
|
||||
this.previousFlattenedStyle,
|
||||
nextFlattenedStyle,
|
||||
ReactNativeStyleAttributes
|
||||
);
|
||||
this.previousFlattenedStyle = nextFlattenedStyle;
|
||||
}
|
||||
|
||||
return updatePayload;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Updates the component's currently mounted representation.
|
||||
*
|
||||
* @param {object} nextElement
|
||||
* @param {ReactReconcileTransaction} transaction
|
||||
* @param {object} context
|
||||
* @internal
|
||||
*/
|
||||
receiveComponent: function(nextElement, transaction, context) {
|
||||
var prevElement = this._currentElement;
|
||||
this._currentElement = nextElement;
|
||||
|
||||
var updatePayload = this.computeUpdatedProperties(
|
||||
prevElement.props,
|
||||
nextElement.props,
|
||||
this.viewConfig.validAttributes
|
||||
);
|
||||
|
||||
if (updatePayload) {
|
||||
RCTUIManager.updateView(
|
||||
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(this._rootNodeID),
|
||||
this.viewConfig.uiViewClassName,
|
||||
updatePayload
|
||||
);
|
||||
}
|
||||
|
||||
this._reconcileListenersUponUpdate(
|
||||
prevElement.props,
|
||||
nextElement.props
|
||||
);
|
||||
this.updateChildren(nextElement.props.children, transaction, context);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {object} initialProps Native component props.
|
||||
*/
|
||||
_registerListenersUponCreation: function(initialProps) {
|
||||
for (var key in initialProps) {
|
||||
// NOTE: The check for `!props[key]`, is only possible because this method
|
||||
// registers listeners the *first* time a component is created.
|
||||
if (registrationNames[key] && initialProps[key]) {
|
||||
var listener = initialProps[key];
|
||||
putListener(this._rootNodeID, key, listener);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Reconciles event listeners, adding or removing if necessary.
|
||||
* @param {object} prevProps Native component props including events.
|
||||
* @param {object} nextProps Next native component props including events.
|
||||
*/
|
||||
_reconcileListenersUponUpdate: function(prevProps, nextProps) {
|
||||
for (var key in nextProps) {
|
||||
if (registrationNames[key] && (nextProps[key] != prevProps[key])) {
|
||||
putListener(this._rootNodeID, key, nextProps[key]);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} rootID Root ID of this subtree.
|
||||
* @param {Transaction} transaction For creating/updating.
|
||||
* @return {string} Unique iOS view tag.
|
||||
*/
|
||||
mountComponent: function(rootID, transaction, context) {
|
||||
this._rootNodeID = rootID;
|
||||
|
||||
var tag = ReactNativeTagHandles.allocateTag();
|
||||
|
||||
this.previousFlattenedStyle = {};
|
||||
var updatePayload = this.computeUpdatedProperties(
|
||||
{}, // previous props
|
||||
this._currentElement.props, // next props
|
||||
this.viewConfig.validAttributes
|
||||
);
|
||||
RCTUIManager.createView(tag, this.viewConfig.uiViewClassName, updatePayload);
|
||||
|
||||
this._registerListenersUponCreation(this._currentElement.props);
|
||||
this.initializeChildren(
|
||||
this._currentElement.props.children,
|
||||
tag,
|
||||
transaction,
|
||||
context
|
||||
);
|
||||
return {
|
||||
rootNodeID: rootID,
|
||||
tag: tag
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Order of mixins is important. ReactNativeBaseComponent overrides methods in
|
||||
* ReactMultiChild.
|
||||
*/
|
||||
Object.assign(
|
||||
ReactNativeBaseComponent.prototype,
|
||||
ReactMultiChild.Mixin,
|
||||
ReactNativeBaseComponent.Mixin,
|
||||
NativeMethodsMixin,
|
||||
ReactNativeComponentMixin
|
||||
);
|
||||
|
||||
module.exports = ReactNativeBaseComponent;
|
||||
104
Libraries/ReactNative/ReactNativeReconcileTransaction.js
Normal file
104
Libraries/ReactNative/ReactNativeReconcileTransaction.js
Normal file
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeReconcileTransaction
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var CallbackQueue = require('CallbackQueue');
|
||||
var PooledClass = require('PooledClass');
|
||||
var Transaction = require('Transaction');
|
||||
|
||||
/**
|
||||
* Provides a `CallbackQueue` queue for collecting `onDOMReady` callbacks during
|
||||
* the performing of the transaction.
|
||||
*/
|
||||
var ON_DOM_READY_QUEUEING = {
|
||||
/**
|
||||
* Initializes the internal `onDOMReady` queue.
|
||||
*/
|
||||
initialize: function() {
|
||||
this.reactMountReady.reset();
|
||||
},
|
||||
|
||||
/**
|
||||
* After DOM is flushed, invoke all registered `onDOMReady` callbacks.
|
||||
*/
|
||||
close: function() {
|
||||
this.reactMountReady.notifyAll();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Executed within the scope of the `Transaction` instance. Consider these as
|
||||
* being member methods, but with an implied ordering while being isolated from
|
||||
* each other.
|
||||
*/
|
||||
var TRANSACTION_WRAPPERS = [ON_DOM_READY_QUEUEING];
|
||||
|
||||
/**
|
||||
* Currently:
|
||||
* - The order that these are listed in the transaction is critical:
|
||||
* - Suppresses events.
|
||||
* - Restores selection range.
|
||||
*
|
||||
* Future:
|
||||
* - Restore document/overflow scroll positions that were unintentionally
|
||||
* modified via DOM insertions above the top viewport boundary.
|
||||
* - Implement/integrate with customized constraint based layout system and keep
|
||||
* track of which dimensions must be remeasured.
|
||||
*
|
||||
* @class ReactNativeReconcileTransaction
|
||||
*/
|
||||
function ReactNativeReconcileTransaction() {
|
||||
this.reinitializeTransaction();
|
||||
this.reactMountReady = CallbackQueue.getPooled(null);
|
||||
}
|
||||
|
||||
var Mixin = {
|
||||
/**
|
||||
* @see Transaction
|
||||
* @abstract
|
||||
* @final
|
||||
* @return {array<object>} List of operation wrap proceedures.
|
||||
* TODO: convert to array<TransactionWrapper>
|
||||
*/
|
||||
getTransactionWrappers: function() {
|
||||
return TRANSACTION_WRAPPERS;
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {object} The queue to collect `onDOMReady` callbacks with.
|
||||
* TODO: convert to ReactMountReady
|
||||
*/
|
||||
getReactMountReady: function() {
|
||||
return this.reactMountReady;
|
||||
},
|
||||
|
||||
/**
|
||||
* `PooledClass` looks for this, and will invoke this before allowing this
|
||||
* instance to be resused.
|
||||
*/
|
||||
destructor: function() {
|
||||
CallbackQueue.release(this.reactMountReady);
|
||||
this.reactMountReady = null;
|
||||
}
|
||||
};
|
||||
|
||||
Object.assign(
|
||||
ReactNativeReconcileTransaction.prototype,
|
||||
Transaction.Mixin,
|
||||
ReactNativeReconcileTransaction,
|
||||
Mixin
|
||||
);
|
||||
|
||||
PooledClass.addPoolingTo(ReactNativeReconcileTransaction);
|
||||
|
||||
module.exports = ReactNativeReconcileTransaction;
|
||||
32
Libraries/ReactNative/ReactNativeStyleAttributes.js
Normal file
32
Libraries/ReactNative/ReactNativeStyleAttributes.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeStyleAttributes
|
||||
* @flow
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ImageStylePropTypes = require('ImageStylePropTypes');
|
||||
var TextStylePropTypes = require('TextStylePropTypes');
|
||||
var ViewStylePropTypes = require('ViewStylePropTypes');
|
||||
|
||||
var keyMirror = require('keyMirror');
|
||||
var matricesDiffer = require('matricesDiffer');
|
||||
var sizesDiffer = require('sizesDiffer');
|
||||
|
||||
var ReactNativeStyleAttributes = {
|
||||
...keyMirror(ViewStylePropTypes),
|
||||
...keyMirror(TextStylePropTypes),
|
||||
...keyMirror(ImageStylePropTypes),
|
||||
};
|
||||
|
||||
ReactNativeStyleAttributes.transformMatrix = { diff: matricesDiffer };
|
||||
ReactNativeStyleAttributes.shadowOffset = { diff: sizesDiffer };
|
||||
|
||||
module.exports = ReactNativeStyleAttributes;
|
||||
101
Libraries/ReactNative/ReactNativeTagHandles.js
Normal file
101
Libraries/ReactNative/ReactNativeTagHandles.js
Normal file
@@ -0,0 +1,101 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeTagHandles
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var invariant = require('invariant');
|
||||
var warning = require('warning');
|
||||
|
||||
/**
|
||||
* 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(): number {
|
||||
// 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;
|
||||
},
|
||||
|
||||
/**
|
||||
* This associates the *last* observed *native* mounting between `rootNodeID`
|
||||
* and some `tag`. This association doesn't imply that `rootNodeID` is still
|
||||
* natively mounted as `tag`. The only reason why we don't clear the
|
||||
* association when the `rootNodeID` is unmounted, is that we don't have a
|
||||
* convenient time to disassociate them (otherwise we would).
|
||||
* `unmountComponent` isn't the correct time because that doesn't imply that
|
||||
* the native node has been natively unmounted.
|
||||
*/
|
||||
associateRootNodeIDWithMountedNodeHandle: function(
|
||||
rootNodeID: ?string,
|
||||
tag: ?number
|
||||
) {
|
||||
warning(rootNodeID && tag, 'Root node or tag is null when associating');
|
||||
if (rootNodeID && tag) {
|
||||
ReactNativeTagHandles.tagToRootNodeID[tag] = rootNodeID;
|
||||
ReactNativeTagHandles.rootNodeIDToTag[rootNodeID] = tag;
|
||||
}
|
||||
},
|
||||
|
||||
allocateRootNodeIDForTag: function(tag: number): string {
|
||||
invariant(
|
||||
this.reactTagIsNativeTopRootID(tag),
|
||||
'Expect a native root tag, instead got ', tag
|
||||
);
|
||||
return '.r[' + tag + ']{TOP_LEVEL}';
|
||||
},
|
||||
|
||||
reactTagIsNativeTopRootID: function(reactTag: number): bool {
|
||||
// We reserve all tags that are 1 mod 10 for native root views
|
||||
return reactTag % 10 === 1;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the native `nodeHandle` (`tag`) that was most recently *natively*
|
||||
* mounted at the `rootNodeID`. Just because a React component has been
|
||||
* mounted, that doesn't mean that its native node has been mounted. The
|
||||
* native node is mounted when we actually make the call to insert the
|
||||
* `nodeHandle` (`tag`) into the native hierarchy.
|
||||
*
|
||||
* @param {string} rootNodeID Root node ID to find most recently mounted tag
|
||||
* for. Again, this doesn't imply that it is still currently mounted.
|
||||
* @return {number} Tag ID of native view for most recent mounting of
|
||||
* `rootNodeID`.
|
||||
*/
|
||||
mostRecentMountedNodeHandleForRootNodeID: function(
|
||||
rootNodeID: string
|
||||
): number {
|
||||
return ReactNativeTagHandles.rootNodeIDToTag[rootNodeID];
|
||||
},
|
||||
|
||||
tagToRootNodeID: ([] : Array<string>),
|
||||
|
||||
rootNodeIDToTag: ({} : {[key: string]: number})
|
||||
};
|
||||
|
||||
module.exports = ReactNativeTagHandles;
|
||||
67
Libraries/ReactNative/ReactNativeTextComponent.js
Normal file
67
Libraries/ReactNative/ReactNativeTextComponent.js
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeTextComponent
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
var ReactNativeTagHandles = require('ReactNativeTagHandles');
|
||||
var RCTUIManager = require('NativeModules').UIManager;
|
||||
|
||||
var assign = require('Object.assign');
|
||||
|
||||
var ReactNativeTextComponent = function(props) {
|
||||
// This constructor and its argument is currently used by mocks.
|
||||
};
|
||||
|
||||
assign(ReactNativeTextComponent.prototype, {
|
||||
|
||||
construct: function(text) {
|
||||
// This is really a ReactText (ReactNode), not a ReactElement
|
||||
this._currentElement = text;
|
||||
this._stringText = '' + text;
|
||||
this._rootNodeID = null;
|
||||
},
|
||||
|
||||
mountComponent: function(rootID, transaction, context) {
|
||||
this._rootNodeID = rootID;
|
||||
var tag = ReactNativeTagHandles.allocateTag();
|
||||
RCTUIManager.createView(tag, 'RCTRawText', {text: this._stringText});
|
||||
return {
|
||||
rootNodeID: rootID,
|
||||
tag: tag,
|
||||
};
|
||||
},
|
||||
|
||||
receiveComponent: function(nextText, transaction, context) {
|
||||
if (nextText !== this._currentElement) {
|
||||
this._currentElement = nextText;
|
||||
var nextStringText = '' + nextText;
|
||||
if (nextStringText !== this._stringText) {
|
||||
this._stringText = nextStringText;
|
||||
RCTUIManager.updateView(
|
||||
ReactNativeTagHandles.mostRecentMountedNodeHandleForRootNodeID(
|
||||
this._rootNodeID
|
||||
),
|
||||
'RCTRawText',
|
||||
{text: this._stringText}
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
unmountComponent: function() {
|
||||
this._currentElement = null;
|
||||
this._stringText = null;
|
||||
this._rootNodeID = null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = ReactNativeTextComponent;
|
||||
37
Libraries/ReactNative/ReactNativeViewAttributes.js
Normal file
37
Libraries/ReactNative/ReactNativeViewAttributes.js
Normal file
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule ReactNativeViewAttributes
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var merge = require('merge');
|
||||
|
||||
var ReactNativeViewAttributes = {};
|
||||
|
||||
ReactNativeViewAttributes.UIView = {
|
||||
pointerEvents: true,
|
||||
accessible: true,
|
||||
accessibilityLabel: true,
|
||||
testID: true,
|
||||
onLayout: true,
|
||||
};
|
||||
|
||||
ReactNativeViewAttributes.RCTView = merge(
|
||||
ReactNativeViewAttributes.UIView, {
|
||||
|
||||
// This is a special performance property exposed by RCTView and useful for
|
||||
// scrolling content when there are many subviews, most of which are offscreen.
|
||||
// For this property to be effective, it must be applied to a view that contains
|
||||
// many subviews that extend outside its bound. The subviews must also have
|
||||
// overflow: hidden, as should the containing view (or one of its superviews).
|
||||
removeClippedSubviews: true,
|
||||
});
|
||||
|
||||
module.exports = ReactNativeViewAttributes;
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*
|
||||
* @providesModule createReactNativeComponentClass
|
||||
* @flow
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var ReactElement = require('ReactElement');
|
||||
var ReactNativeBaseComponent = require('ReactNativeBaseComponent');
|
||||
|
||||
// See also ReactNativeBaseComponent
|
||||
type ReactNativeBaseComponentViewConfig = {
|
||||
validAttributes: Object;
|
||||
uiViewClassName: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} config iOS View configuration.
|
||||
* @private
|
||||
*/
|
||||
var createReactNativeComponentClass = function(
|
||||
viewConfig: ReactNativeBaseComponentViewConfig
|
||||
): Function { // returning Function is lossy :/
|
||||
var Constructor = function(element) {
|
||||
this._currentElement = element;
|
||||
|
||||
this._rootNodeID = null;
|
||||
this._renderedChildren = null;
|
||||
this.previousFlattenedStyle = null;
|
||||
};
|
||||
Constructor.displayName = viewConfig.uiViewClassName;
|
||||
Constructor.prototype = new ReactNativeBaseComponent(viewConfig);
|
||||
|
||||
return Constructor;
|
||||
};
|
||||
|
||||
module.exports = createReactNativeComponentClass;
|
||||
Reference in New Issue
Block a user