[react-packager][streamline oss] Move open sourced JS source to react-native-github

This commit is contained in:
Spencer Ahrens
2015-02-19 20:10:52 -08:00
commit efae175a8e
434 changed files with 44658 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule IOSDefaultEventPluginOrder
*/
'use strict';
var IOSDefaultEventPluginOrder = [
'ResponderEventPlugin',
'IOSNativeBridgeEventPlugin'
];
module.exports = IOSDefaultEventPluginOrder;

View File

@@ -0,0 +1,72 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule IOSNativeBridgeEventPlugin
*/
"use strict";
var EventPropagators = require('EventPropagators');
var NativeModulesDeprecated = require('NativeModulesDeprecated');
var SyntheticEvent = require('SyntheticEvent');
var merge = require('merge');
var warning = require('warning');
var RKUIManager = NativeModulesDeprecated.RKUIManager;
var customBubblingEventTypes = RKUIManager.customBubblingEventTypes;
var customDirectEventTypes = RKUIManager.customDirectEventTypes;
var allTypesByEventName = {};
for (var bubblingTypeName in customBubblingEventTypes) {
allTypesByEventName[bubblingTypeName] = customBubblingEventTypes[bubblingTypeName];
}
for (var directTypeName in customDirectEventTypes) {
warning(
!customBubblingEventTypes[directTypeName],
"Event cannot be both direct and bubbling: %s",
directTypeName
);
allTypesByEventName[directTypeName] = customDirectEventTypes[directTypeName];
}
var IOSNativeBridgeEventPlugin = {
eventTypes: merge(customBubblingEventTypes, customDirectEventTypes),
/**
* @param {string} topLevelType Record from `EventConstants`.
* @param {DOMEventTarget} topLevelTarget The listening component root node.
* @param {string} topLevelTargetID ID of `topLevelTarget`.
* @param {object} nativeEvent Native browser event.
* @return {*} An accumulation of synthetic events.
* @see {EventPluginHub.extractEvents}
*/
extractEvents: function(
topLevelType,
topLevelTarget,
topLevelTargetID,
nativeEvent) {
var bubbleDispatchConfig = customBubblingEventTypes[topLevelType];
var directDispatchConfig = customDirectEventTypes[topLevelType];
var event = SyntheticEvent.getPooled(
bubbleDispatchConfig || directDispatchConfig,
topLevelTargetID,
nativeEvent
);
if (bubbleDispatchConfig) {
EventPropagators.accumulateTwoPhaseDispatches(event);
} else if (directDispatchConfig) {
EventPropagators.accumulateDirectDispatches(event);
} else {
return null;
}
return event;
}
};
module.exports = IOSNativeBridgeEventPlugin;

View File

@@ -0,0 +1,123 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule NativeMethodsMixin
*/
'use strict';
var NativeModules = require('NativeModules');
var NativeModulesDeprecated = require('NativeModulesDeprecated');
var RKUIManager = NativeModules.RKUIManager;
var RKUIManagerDeprecated = NativeModulesDeprecated.RKUIManager;
var RKPOPAnimationManagerDeprecated = NativeModulesDeprecated.RKPOPAnimationManager;
var TextInputState = require('TextInputState');
var flattenStyle = require('flattenStyle');
var invariant = require('invariant');
var mergeFast = require('mergeFast');
var animationIDInvariant = function(funcName, anim) {
invariant(
anim,
funcName + ' must be called with a valid animation ID returned from' +
' POPAnimation.createAnimation, received: "' + anim + '"'
);
};
var NativeMethodsMixin = {
addAnimation: function(anim, callback) {
animationIDInvariant('addAnimation', anim);
RKPOPAnimationManagerDeprecated.addAnimation(this.getNodeHandle(), anim, callback);
},
removeAnimation: function(anim) {
animationIDInvariant('removeAnimation', anim);
RKPOPAnimationManagerDeprecated.removeAnimation(this.getNodeHandle(), anim);
},
measure: function(callback) {
RKUIManagerDeprecated.measure(this.getNodeHandle(), callback);
},
measureLayout: function(relativeToNativeNode, onSuccess, onFail) {
RKUIManager.measureLayout(
this.getNodeHandle(),
relativeToNativeNode,
onFail,
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.
*/
setNativeProps: function(nativeProps) {
// nativeProps contains a style attribute that's going to be flattened
// and all the attributes expanded in place. In order to make this
// process do as few allocations and copies as possible, we return
// one if the other is empty. Only if both have values then we create
// a new object and merge.
var hasOnlyStyle = true;
for (var key in nativeProps) {
if (key !== 'style') {
hasOnlyStyle = false;
break;
}
}
var style = flattenStyle(nativeProps.style);
var props = null;
if (hasOnlyStyle) {
props = style;
} else if (!style) {
props = nativeProps;
} else {
props = mergeFast(nativeProps, style);
}
RKUIManagerDeprecated.updateView(
this.getNodeHandle(),
this.viewConfig.uiViewClassName,
props
);
},
focus: function() {
TextInputState.focusTextInput(this.getNodeHandle());
},
blur: function() {
TextInputState.blurTextInput(this.getNodeHandle());
}
};
function throwOnStylesProp(component, props) {
if (props.styles !== undefined) {
var owner = component._owner || null;
var name = component.constructor.displayName;
var msg = '`styles` is not a supported property of `' + name + '`, did ' +
'you mean `style` (singular)?';
if (owner && owner.constructor && owner.constructor.displayName) {
msg += '\n\nCheck the `' + owner.constructor.displayName + '` parent ' +
' component.';
}
throw new Error(msg);
}
}
if (__DEV__) {
invariant(
!NativeMethodsMixin.componentWillMount &&
!NativeMethodsMixin.componentWillReceiveProps,
'Do not override existing functions.'
);
NativeMethodsMixin.componentWillMount = function () {
throwOnStylesProp(this, this.props);
};
NativeMethodsMixin.componentWillReceiveProps = function (newProps) {
throwOnStylesProp(this, newProps);
};
}
module.exports = NativeMethodsMixin;

View File

@@ -0,0 +1,21 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule RKRawText
* @typechecks static-only
*/
"use strict";
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
var createReactIOSNativeComponentClass = require('createReactIOSNativeComponentClass');
var RKRawText = createReactIOSNativeComponentClass({
validAttributes: {
text: true,
},
uiViewClassName: 'RCTRawText',
});
module.exports = RKRawText;

View File

@@ -0,0 +1,21 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @providesModule React
*/
"use strict";
module.exports = require('ReactIOS');

View File

@@ -0,0 +1,117 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOS
*/
"use strict";
var ReactComponent = require('ReactComponent');
var ReactCompositeComponent = require('ReactCompositeComponent');
var ReactContext = require('ReactContext');
var ReactCurrentOwner = require('ReactCurrentOwner');
var ReactElement = require('ReactElement');
var ReactElementValidator = require('ReactElementValidator');
var ReactInstanceHandles = require('ReactInstanceHandles');
var ReactIOSDefaultInjection = require('ReactIOSDefaultInjection');
var ReactIOSMount = require('ReactIOSMount');
var ReactLegacyElement = require('ReactLegacyElement');
var ReactPropTypes = require('ReactPropTypes');
var deprecated = require('deprecated');
var invariant = require('invariant');
ReactIOSDefaultInjection.inject();
var createElement = ReactElement.createElement;
var createFactory = ReactElement.createFactory;
if (__DEV__) {
createElement = ReactElementValidator.createElement;
createFactory = ReactElementValidator.createFactory;
}
// TODO: Drop legacy elements once classes no longer export these factories
createElement = ReactLegacyElement.wrapCreateElement(
createElement
);
createFactory = ReactLegacyElement.wrapCreateFactory(
createFactory
);
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) {
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(component, mountInto) {
ReactIOSMount.renderComponent(component, mountInto);
};
var ReactIOS = {
hasReactIOSInitialized: false,
PropTypes: ReactPropTypes,
createClass: ReactCompositeComponent.createClass,
createElement: createElement,
createFactory: createFactory,
_augmentElement: augmentElement,
render: render,
unmountComponentAtNode: ReactIOSMount.unmountComponentAtNode,
/**
* Used by the debugger.
*/
__internals: {
Component: ReactComponent,
CurrentOwner: ReactCurrentOwner,
InstanceHandles: ReactInstanceHandles,
Mount: ReactIOSMount,
},
// Hook for JSX spread, don't use this for anything else.
__spread: Object.assign,
unmountComponentAtNodeAndRemoveContainer: ReactIOSMount.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
)
};
module.exports = ReactIOS;

View File

@@ -0,0 +1,68 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSComponentEnvironment
*/
'use strict';
var RKUIManager = require('NativeModulesDeprecated').RKUIManager;
var ReactIOSDOMIDOperations = require('ReactIOSDOMIDOperations');
var ReactIOSReconcileTransaction = require('ReactIOSReconcileTransaction');
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactPerf = require('ReactPerf');
var ReactIOSComponentEnvironment = {
/**
* Will need to supply something that implements this.
*/
BackendIDOperations: ReactIOSDOMIDOperations,
/**
* Nothing to do for UIKit bridge.
*
* @private
*/
unmountIDFromEnvironment: function(/*rootNodeID*/) {
},
/**
* @param {DOMElement} Element to clear.
*/
clearNode: function(/*containerView*/) {
},
/**
* @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.
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(
mountImage.rootNodeID,
mountImage.tag
);
var addChildTags = [mountImage.tag];
var addAtIndices = [0];
RKUIManager.manageChildren(
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID),
null, // moveFromIndices
null, // moveToIndices
addChildTags,
addAtIndices,
null // removeAtIndices
);
}
),
ReactReconcileTransaction: ReactIOSReconcileTransaction,
};
module.exports = ReactIOSComponentEnvironment;

View File

@@ -0,0 +1,66 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSComponentMixin
*/
'use strict';
var ReactIOSTagHandles = require('ReactIOSTagHandles');
/**
* 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 `ReactIOSNativeComponent`) 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 ReactIOSComponentMixin = {
/**
* This has no particular meaning in ReactIOS. 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() {
return ReactIOSTagHandles.rootNodeIDToTag[this._rootNodeID];
},
getNodeHandle: function() {
return ReactIOSTagHandles.rootNodeIDToTag[this._rootNodeID];
}
};
module.exports = ReactIOSComponentMixin;

View File

@@ -0,0 +1,98 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSDOMIDOperations
* @typechecks static-only
*/
"use strict";
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactMultiChildUpdateTypes = require('ReactMultiChildUpdateTypes');
var RKUIManager = require('NativeModulesDeprecated').RKUIManager;
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 = ReactIOSTagHandles.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;
ReactIOSTagHandles.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];
RKUIManager.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 ReactIOSDOMIDOperations = {
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 = ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(id);
RKUIManager.replaceExistingNonRootView(oldTag, mountImage.tag);
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(id, mountImage.tag);
}
),
};
module.exports = ReactIOSDOMIDOperations;

View File

@@ -0,0 +1,94 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSDefaultInjection
*/
"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 ReactComponent = require('ReactComponent');
var ReactCompositeComponent = require('ReactCompositeComponent');
var ReactDefaultBatchingStrategy = require('ReactDefaultBatchingStrategy');
var ReactElement = require('ReactElement');
var ReactInstanceHandles = require('ReactInstanceHandles');
var ReactIOSComponentEnvironment = require('ReactIOSComponentEnvironment');
var ReactIOSComponentMixin = require('ReactIOSComponentMixin');
var ReactIOSGlobalInteractionHandler = require('ReactIOSGlobalInteractionHandler');
var ReactIOSGlobalResponderHandler = require('ReactIOSGlobalResponderHandler');
var ReactIOSMount = require('ReactIOSMount');
var ReactTextComponent = require('ReactTextComponent');
var ReactUpdates = require('ReactUpdates');
var ResponderEventPlugin = require('ResponderEventPlugin');
var RKRawText = require('RKRawText');
var UniversalWorkerNodeHandle = require('UniversalWorkerNodeHandle');
// 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(
ReactIOSGlobalResponderHandler
);
ResponderEventPlugin.injection.injectGlobalInteractionHandler(
ReactIOSGlobalInteractionHandler
);
/**
* Some important event plugins included by default (without having to require
* them).
*/
EventPluginHub.injection.injectEventPluginsByName({
'ResponderEventPlugin': ResponderEventPlugin,
'IOSNativeBridgeEventPlugin': IOSNativeBridgeEventPlugin
});
ReactUpdates.injection.injectReconcileTransaction(
ReactIOSComponentEnvironment.ReactReconcileTransaction
);
ReactUpdates.injection.injectBatchingStrategy(
ReactDefaultBatchingStrategy
);
ReactComponent.injection.injectEnvironment(
ReactIOSComponentEnvironment
);
EventPluginUtils.injection.injectMount(ReactIOSMount);
ReactCompositeComponent.injection.injectMixin(ReactIOSComponentMixin);
ReactTextComponent.inject(function(initialText) {
// RKRawText is a class so we can't invoke it directly. Instead of using
// a factory, we use the internal fast path to create a descriptor.
// RKRawText is not quite a class yet, so we access the real class from
// the type property. TODO: Change this once factory wrappers are gone.
return new ReactElement(RKRawText.type, null, null, null, null, {
text: initialText
});
});
NodeHandle.injection.injectImplementation(UniversalWorkerNodeHandle);
}
module.exports = {
inject: inject,
};

View File

@@ -0,0 +1,191 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSEventEmitter
* @typechecks static-only
*/
"use strict";
var EventPluginHub = require('EventPluginHub');
var ReactEventEmitterMixin = require('ReactEventEmitterMixin');
var ReactIOSTagHandles = require('ReactIOSTagHandles');
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, indices) {
var rippedOut = [];
for (var i = 0; i < indices.length; i++) {
var index = indices[i];
rippedOut.push(touches[index]);
touches[index] = null;
}
var fillAt = 0;
for (var j = 0; j < touches.length; j++) {
var cur = touches[j];
if (cur !== null) {
touches[fillAt++] = cur;
}
}
touches.length = fillAt;
return rippedOut;
};
/**
* `ReactIOSEventEmitter` is used to attach top-level event listeners. For example:
*
* ReactIOSEventEmitter.putListener('myID', 'onClick', myFunction);
*
* This would allocate a "registration" of `('onClick', myFunction)` on 'myID'.
*
* @internal
*/
var ReactIOSEventEmitter = 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, topLevelType, nativeEventParam) {
var nativeEvent = nativeEventParam || EMPTY_NATIVE_EVENT;
ReactIOSEventEmitter.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, topLevelType, nativeEventParam) {
var rootNodeID = ReactIOSTagHandles.tagToRootNodeID[tag];
ReactIOSEventEmitter._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, touches, changedIndices) {
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 < ReactIOSTagHandles.tagsStartAt) {
if (__DEV__) {
warning(
false,
'A view is reporting that a touch occured on tag zero.'
);
}
} else {
rootNodeID = NodeHandle.getRootNodeID(target);
}
}
ReactIOSEventEmitter._receiveRootNodeIDEvent(
rootNodeID,
eventTopLevelType,
nativeEvent
);
}
}
});
module.exports = ReactIOSEventEmitter;

View File

@@ -0,0 +1,25 @@
/**
* @providesModule ReactIOSGlobalInteractionHandler
*/
'use strict';
var InteractionManager = require('InteractionManager');
// Interaction handle is created/cleared when responder is granted or
// released/terminated.
var interactionHandle = null;
var ReactIOSGlobalInteractionHandler = {
onChange: function(numberActiveTouches) {
if (numberActiveTouches === 0) {
if (interactionHandle) {
InteractionManager.clearInteractionHandle(interactionHandle);
interactionHandle = null;
}
} else if (!interactionHandle) {
interactionHandle = InteractionManager.createInteractionHandle();
}
}
};
module.exports = ReactIOSGlobalInteractionHandler;

View File

@@ -0,0 +1,21 @@
/**
* @providesModule ReactIOSGlobalResponderHandler
*/
'use strict';
var RKUIManager = require('NativeModules').RKUIManager;
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactIOSGlobalResponderHandler = {
onChange: function(from, to) {
if (to !== null) {
RKUIManager.setJSResponder(
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(to)
);
} else {
RKUIManager.clearJSResponder();
}
}
};
module.exports = ReactIOSGlobalResponderHandler;

View File

@@ -0,0 +1,123 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSMount
*/
'use strict';
var RKUIManager = require('NativeModulesDeprecated').RKUIManager;
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactPerf = require('ReactPerf');
var instantiateReactComponent = require('instantiateReactComponent');
var invariant = require('invariant');
var TOP_ROOT_NODE_IDS = {};
function instanceNumberToChildRootID(rootNodeID, instanceNumber) {
return rootNodeID + '[' + instanceNumber + ']';
}
/**
* 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 ReactIOSMount = {
instanceCount: 0,
_instancesByContainerID: {},
/**
* @param {ReactComponent} instance Instance to render.
* @param {containerTag} containerView Handle to native view tag
*/
renderComponent: function(descriptor, containerTag) {
var instance = instantiateReactComponent(descriptor);
if (!ReactIOSTagHandles.reactTagIsNativeTopRootID(containerTag)) {
console.error('You cannot render into anything but a top root');
return;
}
var topRootNodeID = ReactIOSTagHandles.allocateRootNodeIDForTag(containerTag);
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(
topRootNodeID,
containerTag
);
TOP_ROOT_NODE_IDS[topRootNodeID] = true;
var childRootNodeID = instanceNumberToChildRootID(
topRootNodeID,
ReactIOSMount.instanceCount++
);
ReactIOSMount._instancesByContainerID[topRootNodeID] = instance;
instance.mountComponentIntoNode(childRootNodeID, topRootNodeID);
},
/**
* 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) {
ReactIOSMount.unmountComponentAtNode(containerTag);
// call back into native to remove all of the subviews from this container
RKUIManager.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) {
var containerID = ReactIOSTagHandles.tagToRootNodeID[containerTag];
invariant(
TOP_ROOT_NODE_IDS[containerID],
'We only currently support removing components from the root node'
);
var instance = ReactIOSMount._instancesByContainerID[containerID];
if (!instance) {
console.error('Tried to unmount a component that does not exist');
return false;
}
ReactIOSMount.unmountComponentFromNode(instance, containerID);
delete ReactIOSMount._instancesByContainerID[containerID];
delete TOP_ROOT_NODE_IDS[containerID];
return true;
},
/**
* Unmounts a component and sends messages back to iOS to remove its subviews.
*
* @param {ReactComponent} instance React component instance.
* @param {int} containerID ID of container we're removing from.
* @final
* @internal
* @see {ReactIOSMount.unmountComponentAtNode}
*/
unmountComponentFromNode: function(instance, containerID) {
// call back into native to remove all of the subviews from this container
instance.unmountComponent();
var containerTag =
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(containerID);
RKUIManager.removeSubviewsFromContainerWithID(containerTag);
},
getNode: function(id) {
return id;
}
};
ReactIOSMount.renderComponent = ReactPerf.measure(
'ReactMount',
'_renderNewRootComponent',
ReactIOSMount.renderComponent
);
module.exports = ReactIOSMount;

View File

@@ -0,0 +1,265 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSNativeComponent
*/
'use strict';
var NativeMethodsMixin = require('NativeMethodsMixin');
var ReactComponent = require('ReactComponent');
var ReactIOSComponentMixin = require('ReactIOSComponentMixin');
var ReactIOSEventEmitter = require('ReactIOSEventEmitter');
var ReactIOSStyleAttributes = require('ReactIOSStyleAttributes');
var ReactIOSTagHandles = require('ReactIOSTagHandles');
var ReactMultiChild = require('ReactMultiChild');
var RKUIManager = require('NativeModulesDeprecated').RKUIManager;
var styleDiffer = require('styleDiffer');
var deepFreezeAndThrowOnMutationInDev = require('deepFreezeAndThrowOnMutationInDev');
var diffRawProperties = require('diffRawProperties');
var flattenStyle = require('flattenStyle');
var warning = require('warning');
var registrationNames = ReactIOSEventEmitter.registrationNames;
var putListener = ReactIOSEventEmitter.putListener;
var deleteAllListeners = ReactIOSEventEmitter.deleteAllListeners;
/**
* @constructor ReactIOSNativeComponent
* @extends ReactComponent
* @extends ReactMultiChild
* @param {!object} UIKit View Configuration.
*/
var ReactIOSNativeComponent = function(viewConfig) {
this.viewConfig = viewConfig;
this.props = null;
this.previousFlattenedStyle = null;
};
/**
* 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` !
*/
ReactIOSNativeComponent.Mixin = {
unmountComponent: function() {
deleteAllListeners(this._rootNodeID);
ReactComponent.Mixin.unmountComponent.call(this);
this.unmountChildren();
},
/**
* 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
* `ReactIOSTagHandles`.
*/
initializeChildren: function(children, containerTag, transaction) {
var mountImages = this.mountChildren(children, transaction);
// 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'
);
ReactIOSTagHandles.associateRootNodeIDWithMountedNodeHandle(
childID,
childTag
);
createdTags[i] = mountImage.tag;
}
RKUIManager
.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 = flattenStyle(nextProps.style);
updatePayload = diffRawProperties(
updatePayload,
this.previousFlattenedStyle,
nextFlattenedStyle,
ReactIOSStyleAttributes
);
this.previousFlattenedStyle = nextFlattenedStyle;
}
return updatePayload;
},
/**
* Updates the component's currently mounted representation.
*
* @param {ReactReconcileTransaction} transaction
* @param {object} prevDescriptor
* @internal
*/
updateComponent: function(transaction, prevDescriptor) {
ReactComponent.Mixin.updateComponent.call(
this,
transaction,
prevDescriptor
);
var nextDescriptor = this._currentElement;
var updatePayload = this.computeUpdatedProperties(
prevDescriptor.props,
nextDescriptor.props,
this.viewConfig.validAttributes
);
if (updatePayload) {
RKUIManager.updateView(
ReactIOSTagHandles.mostRecentMountedNodeHandleForRootNodeID(this._rootNodeID),
this.viewConfig.uiViewClassName,
updatePayload
);
}
this._reconcileListenersUponUpdate(
prevDescriptor.props,
nextDescriptor.props
);
this.updateChildren(this.props.children, transaction);
},
/**
* @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, mountDepth) {
ReactComponent.Mixin.mountComponent.call(
this,
rootID,
transaction,
mountDepth
);
var tag = ReactIOSTagHandles.allocateTag();
this.previousFlattenedStyle = {};
var updatePayload = this.computeUpdatedProperties(
{}, // previous props
this.props, // next props
this.viewConfig.validAttributes
);
RKUIManager.createView(tag, this.viewConfig.uiViewClassName, updatePayload);
this._registerListenersUponCreation(this.props);
this.initializeChildren(this.props.children, tag, transaction);
return {
rootNodeID: rootID,
tag: tag
};
}
};
/**
* Order of mixins is important. ReactIOSNativeComponent overrides methods in
* ReactMultiChild.
*/
Object.assign(
ReactIOSNativeComponent.prototype,
ReactComponent.Mixin,
ReactMultiChild.Mixin,
ReactIOSNativeComponent.Mixin,
NativeMethodsMixin,
ReactIOSComponentMixin
);
module.exports = ReactIOSNativeComponent;

View File

@@ -0,0 +1,99 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSReconcileTransaction
* @typechecks static-only
*/
"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 ReactIOSReconcileTransaction
*/
function ReactIOSReconcileTransaction() {
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(
ReactIOSReconcileTransaction.prototype,
Transaction.Mixin,
ReactIOSReconcileTransaction,
Mixin
);
PooledClass.addPoolingTo(ReactIOSReconcileTransaction);
module.exports = ReactIOSReconcileTransaction;

View File

@@ -0,0 +1,25 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSStyleAttributes
*/
"use strict";
var TextStylePropTypes = require('TextStylePropTypes');
var ViewStylePropTypes = require('ViewStylePropTypes');
var deepDiffer = require('deepDiffer');
var keyMirror = require('keyMirror');
var matricesDiffer = require('matricesDiffer');
var merge = require('merge');
var ReactIOSStyleAttributes = merge(
keyMirror(ViewStylePropTypes),
keyMirror(TextStylePropTypes)
);
ReactIOSStyleAttributes.transformMatrix = { diff: matricesDiffer };
ReactIOSStyleAttributes.shadowOffset = { diff: deepDiffer };
module.exports = ReactIOSStyleAttributes;

View File

@@ -0,0 +1,88 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSTagHandles
*/
'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 ReactIOSTagHandles = {
tagsStartAt: INITIAL_TAG_COUNT,
tagCount: INITIAL_TAG_COUNT,
allocateTag: function() {
// Skip over root IDs as those are reserved for native
while (this.reactTagIsNativeTopRootID(ReactIOSTagHandles.tagCount)) {
ReactIOSTagHandles.tagCount++;
}
var tag = ReactIOSTagHandles.tagCount;
ReactIOSTagHandles.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, tag) {
warning(rootNodeID && tag, 'Root node or tag is null when associating');
ReactIOSTagHandles.tagToRootNodeID[tag] = rootNodeID;
ReactIOSTagHandles.rootNodeIDToTag[rootNodeID] = tag;
},
allocateRootNodeIDForTag: function(tag) {
invariant(
this.reactTagIsNativeTopRootID(tag),
'Expect a native root tag, instead got ', tag
);
return '.r[' + tag + ']{TOP_LEVEL}';
},
reactTagIsNativeTopRootID: function(reactTag) {
// 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) {
return ReactIOSTagHandles.rootNodeIDToTag[rootNodeID];
},
tagToRootNodeID: [],
rootNodeIDToTag: {}
};
module.exports = ReactIOSTagHandles;

View File

@@ -0,0 +1,31 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule ReactIOSViewAttributes
*/
"use strict";
var merge = require('merge');
var ReactIOSViewAttributes = {};
ReactIOSViewAttributes.UIView = {
pointerEvents: true,
accessible: true,
accessibilityLabel: true,
testID: true,
};
ReactIOSViewAttributes.RKView = merge(
ReactIOSViewAttributes.UIView, {
// This is a special performance property exposed by RKView 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 = ReactIOSViewAttributes;

View File

@@ -0,0 +1,30 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @providesModule ReactTextComponent
* @typechecks static-only
*/
"use strict";
var InjectedTextComponent = null;
var ReactTextComponent = function() {
return InjectedTextComponent.apply(this, arguments);
};
ReactTextComponent.inject = function(textComponent) {
InjectedTextComponent = textComponent;
};
module.exports = ReactTextComponent;

View File

@@ -0,0 +1,29 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule createReactIOSNativeComponentClass
*/
"use strict";
var ReactElement = require('ReactElement');
var ReactLegacyElement = require('ReactLegacyElement');
var ReactIOSNativeComponent = require('ReactIOSNativeComponent');
/**
* @param {string} config iOS View configuration.
* @private
*/
var createReactIOSNativeComponentClass = function(viewConfig) {
var Constructor = function(props) {
};
Constructor.displayName = viewConfig.uiViewClassName;
Constructor.prototype = new ReactIOSNativeComponent(viewConfig);
Constructor.prototype.constructor = Constructor;
return ReactLegacyElement.wrapFactory(
ReactElement.createFactory(Constructor)
);
};
module.exports = createReactIOSNativeComponentClass;

View File

@@ -0,0 +1,85 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule diffRawProperties
*/
'use strict';
/**
* diffRawProperties takes two sets of props and a set of valid attributes
* and write to updatePayload the values that changed or were deleted
*
* @param {?object} updatePayload Overriden with the props that changed.
* @param {!object} prevProps Previous properties to diff against current
* properties. These properties are as supplied to component construction.
* @param {!object} prevProps Next "current" properties to diff against
* previous. These properties are as supplied to component construction.
* @return {?object}
*/
function diffRawProperties(updatePayload, prevProps, nextProps, validAttributes) {
var validAttributeConfig;
var nextProp;
var prevProp;
var isScalar;
var shouldUpdate;
for (var propKey in nextProps) {
validAttributeConfig = validAttributes[propKey];
if (!validAttributeConfig) {
continue; // not a valid native prop
}
prevProp = prevProps && prevProps[propKey];
nextProp = nextProps[propKey];
if (prevProp !== nextProp) {
// If you want a property's diff to be detected, you must configure it
// to be so - *or* it must be a scalar property. For now, we'll allow
// creation with any attribute that is not scalar, but we should
// eventually even reject those unless they are properly configured.
isScalar = typeof nextProp !== 'object' || nextProp === null;
shouldUpdate = isScalar ||
!prevProp ||
validAttributeConfig.diff &&
validAttributeConfig.diff(prevProp, nextProp);
if (shouldUpdate) {
updatePayload = updatePayload || {};
updatePayload[propKey] = nextProp;
}
}
}
// Also iterate through all the previous props to catch any that have been
// removed and make sure native gets the signal so it can reset them to the
// default.
for (var propKey in prevProps) {
validAttributeConfig = validAttributes[propKey];
if (!validAttributeConfig) {
continue; // not a valid native prop
}
if (updatePayload && updatePayload[propKey] !== undefined) {
continue; // Prop already specified
}
prevProp = prevProps[propKey];
nextProp = nextProps && nextProps[propKey];
if (prevProp !== nextProp) {
if (nextProp === undefined) {
nextProp = null; // null is a sentinel we explicitly send to native
}
// If you want a property's diff to be detected, you must configure it
// to be so - *or* it must be a scalar property. For now, we'll allow
// creation with any attribute that is not scalar, but we should
// eventually even reject those unless they are properly configured.
isScalar = typeof nextProp !== 'object' || nextProp === null;
shouldUpdate = isScalar && prevProp !== nextProp ||
validAttributeConfig.diff &&
validAttributeConfig.diff(prevProp, nextProp);
if (shouldUpdate) {
updatePayload = updatePayload || {};
updatePayload[propKey] = nextProp;
}
}
}
return updatePayload;
}
module.exports = diffRawProperties;

View File

@@ -0,0 +1,18 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule nativePropType
*/
'use strict'
/**
* A simple wrapper for prop types to mark them as native, which will allow them
* to be passed over the bridge to be applied to the native component if
* processed by `validAttributesFromPropTypes`.
*/
function nativePropType(propType) {
propType.isNative = true;
return propType;
}
module.exports = nativePropType;

View File

@@ -0,0 +1,20 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule renderApplication
*/
'use strict';
var React = require('React');
var invariant = require('invariant');
function renderApplication(RootComponent, initialProps, rootTag) {
invariant(
rootTag,
'Expect to have a valid rootTag, instead got ', rootTag
);
React.render(<RootComponent {...initialProps} />, rootTag);
}
module.exports = renderApplication;