Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Thomas Mchugh 2015-04-07 15:18:07 -05:00
commit 2efce394f5
40 changed files with 981 additions and 475 deletions

View File

@ -37,7 +37,7 @@
"rules": { "rules": {
"no-cond-assign": 1, // disallow assignment in conditional expressions "no-cond-assign": 1, // disallow assignment in conditional expressions
"no-console": 0, // disallow use of console (off by default in the node environment) "no-console": 0, // disallow use of console (off by default in the node environment)
"no-constant-condition": 1, // disallow use of constant expressions in conditions "no-constant-condition": 0, // disallow use of constant expressions in conditions
"no-comma-dangle": 0, // disallow trailing commas in object literals "no-comma-dangle": 0, // disallow trailing commas in object literals
"no-control-regex": 1, // disallow control characters in regular expressions "no-control-regex": 1, // disallow control characters in regular expressions
"no-debugger": 1, // disallow use of debugger "no-debugger": 1, // disallow use of debugger

View File

@ -7,23 +7,16 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
13ACB6741AC2117000FF4204 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13ACB6711AC2113600FF4204 /* libRCTAnimation.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; }; 13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
1461632D1AC3E23900C2F5AD /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1461632C1AC3E22900C2F5AD /* libReact.a */; }; 1461632D1AC3E23900C2F5AD /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1461632C1AC3E22900C2F5AD /* libReact.a */; };
58C1E40E1ACF54E9006D1A47 /* libRCTAnimationExperimental.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58C1E40B1ACF54B4006D1A47 /* libRCTAnimationExperimental.a */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; }; 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
13ACB6701AC2113600FF4204 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13ACB66C1AC2113500FF4204 /* RCTAnimation.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTAnimation;
};
1461632B1AC3E22900C2F5AD /* PBXContainerItemProxy */ = { 1461632B1AC3E22900C2F5AD /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */; containerPortal = 146163271AC3E22900C2F5AD /* React.xcodeproj */;
@ -31,6 +24,13 @@
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192; remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
remoteInfo = React; remoteInfo = React;
}; };
58C1E40A1ACF54B4006D1A47 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 13ACB66C1AC2113500FF4204 /* RCTAnimationExperimental.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTAnimationExperimental;
};
832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = { 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */; containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
@ -41,7 +41,7 @@
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
13ACB66C1AC2113500FF4204 /* RCTAnimation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimation.xcodeproj; path = ../../Libraries/Animation/RCTAnimation.xcodeproj; sourceTree = "<group>"; }; 13ACB66C1AC2113500FF4204 /* RCTAnimationExperimental.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAnimationExperimental.xcodeproj; path = ../../Libraries/Animation/RCTAnimationExperimental.xcodeproj; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* 2048.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 2048.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07F961A680F5B00A75B9A /* 2048.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 2048.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = 2048/AppDelegate.h; sourceTree = "<group>"; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = 2048/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = 2048/AppDelegate.m; sourceTree = "<group>"; }; 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = 2048/AppDelegate.m; sourceTree = "<group>"; };
@ -59,7 +59,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
1461632D1AC3E23900C2F5AD /* libReact.a in Frameworks */, 1461632D1AC3E23900C2F5AD /* libReact.a in Frameworks */,
13ACB6741AC2117000FF4204 /* libRCTAnimation.a in Frameworks */, 58C1E40E1ACF54E9006D1A47 /* libRCTAnimationExperimental.a in Frameworks */,
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */, 832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -67,14 +67,6 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
13ACB66D1AC2113500FF4204 /* Products */ = {
isa = PBXGroup;
children = (
13ACB6711AC2113600FF4204 /* libRCTAnimation.a */,
);
name = Products;
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* 2048 */ = { 13B07FAE1A68108700A75B9A /* 2048 */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -96,12 +88,20 @@
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
58C1E4071ACF54B4006D1A47 /* Products */ = {
isa = PBXGroup;
children = (
58C1E40B1ACF54B4006D1A47 /* libRCTAnimationExperimental.a */,
);
name = Products;
sourceTree = "<group>";
};
832341AE1AAA6A7D00B99B32 /* Libraries */ = { 832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
146163271AC3E22900C2F5AD /* React.xcodeproj */, 146163271AC3E22900C2F5AD /* React.xcodeproj */,
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */, 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
13ACB66C1AC2113500FF4204 /* RCTAnimation.xcodeproj */, 13ACB66C1AC2113500FF4204 /* RCTAnimationExperimental.xcodeproj */,
); );
name = Libraries; name = Libraries;
sourceTree = "<group>"; sourceTree = "<group>";
@ -175,8 +175,8 @@
projectDirPath = ""; projectDirPath = "";
projectReferences = ( projectReferences = (
{ {
ProductGroup = 13ACB66D1AC2113500FF4204 /* Products */; ProductGroup = 58C1E4071ACF54B4006D1A47 /* Products */;
ProjectRef = 13ACB66C1AC2113500FF4204 /* RCTAnimation.xcodeproj */; ProjectRef = 13ACB66C1AC2113500FF4204 /* RCTAnimationExperimental.xcodeproj */;
}, },
{ {
ProductGroup = 832341B11AAA6A8300B99B32 /* Products */; ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
@ -195,13 +195,6 @@
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXReferenceProxy section */ /* Begin PBXReferenceProxy section */
13ACB6711AC2113600FF4204 /* libRCTAnimation.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTAnimation.a;
remoteRef = 13ACB6701AC2113600FF4204 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
1461632C1AC3E22900C2F5AD /* libReact.a */ = { 1461632C1AC3E22900C2F5AD /* libReact.a */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = archive.ar; fileType = archive.ar;
@ -209,6 +202,13 @@
remoteRef = 1461632B1AC3E22900C2F5AD /* PBXContainerItemProxy */; remoteRef = 1461632B1AC3E22900C2F5AD /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR; sourceTree = BUILT_PRODUCTS_DIR;
}; };
58C1E40B1ACF54B4006D1A47 /* libRCTAnimationExperimental.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTAnimationExperimental.a;
remoteRef = 58C1E40A1ACF54B4006D1A47 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
832341B51AAA6A8300B99B32 /* libRCTText.a */ = { 832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
isa = PBXReferenceProxy; isa = PBXReferenceProxy;
fileType = archive.ar; fileType = archive.ar;
@ -266,6 +266,10 @@
); );
INFOPLIST_FILE = "$(SRCROOT)/2048/Info.plist"; INFOPLIST_FILE = "$(SRCROOT)/2048/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"/Users/sahrens/src/fbobjc-hg/Libraries/FBReactKit/js/react-native-github/Libraries/Animation/build/Debug-iphoneos",
);
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = 2048; PRODUCT_NAME = 2048;
}; };
@ -282,6 +286,10 @@
); );
INFOPLIST_FILE = "$(SRCROOT)/2048/Info.plist"; INFOPLIST_FILE = "$(SRCROOT)/2048/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"/Users/sahrens/src/fbobjc-hg/Libraries/FBReactKit/js/react-native-github/Libraries/Animation/build/Debug-iphoneos",
);
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = 2048; PRODUCT_NAME = 2048;
}; };

View File

@ -18,13 +18,13 @@
var React = require('react-native'); var React = require('react-native');
var { var {
Animation,
AppRegistry, AppRegistry,
StyleSheet, StyleSheet,
Text, Text,
View, View,
} = React; } = React;
var AnimationExperimental = require('AnimationExperimental');
var GameBoard = require('GameBoard'); var GameBoard = require('GameBoard');
var TouchableBounce = require('TouchableBounce'); var TouchableBounce = require('TouchableBounce');
@ -77,17 +77,15 @@ class Tile extends React.Component {
animationPosition(tile.toColumn()), animationPosition(tile.toColumn()),
animationPosition(tile.toRow()), animationPosition(tile.toRow()),
]; ];
Animation.startAnimation(this.refs['this'], 100, 0, 'easeInOutQuad', {position: point}); AnimationExperimental.startAnimation(this.refs['this'], 100, 0, 'easeInOutQuad', {position: point});
} }
return offset; return offset;
} }
componentDidMount() { componentDidMount() {
setTimeout(() => { AnimationExperimental.startAnimation(this.refs['this'], 100, 0, 'easeInOutQuad', {opacity: 1});
Animation.startAnimation(this.refs['this'], 300, 0, 'easeInOutQuad', {scaleXY: [1, 1]});
Animation.startAnimation(this.refs['this'], 100, 0, 'easeInOutQuad', {opacity: 1});
}, 0);
} }
render() { render() {

View File

@ -52,26 +52,45 @@ var ROUTE_STACK = [
var INIT_ROUTE_INDEX = 1; var INIT_ROUTE_INDEX = 1;
class JumpingNavBar extends React.Component { class JumpingNavBar extends React.Component {
constructor(props) {
super(props);
this.state = {
tabIndex: props.initTabIndex,
};
}
handleWillFocus(route) {
var tabIndex = ROUTE_STACK.indexOf(route);
this.setState({ tabIndex, });
}
render() { render() {
return ( return (
<View style={styles.tabs}> <View style={styles.tabs}>
<TabBarIOS> <TabBarIOS>
<TabBarIOS.Item <TabBarIOS.Item
icon={require('image!tabnav_notification')} icon={require('image!tabnav_notification')}
selected={this.props.tabIndex === 0} selected={this.state.tabIndex === 0}
onPress={() => { this.props.onTabIndex(0); }}> onPress={() => {
this.props.onTabIndex(0);
this.setState({ tabIndex: 0, });
}}>
<View /> <View />
</TabBarIOS.Item> </TabBarIOS.Item>
<TabBarIOS.Item <TabBarIOS.Item
icon={require('image!tabnav_list')} icon={require('image!tabnav_list')}
selected={this.props.tabIndex === 1} selected={this.state.tabIndex === 1}
onPress={() => { this.props.onTabIndex(1); }}> onPress={() => {
this.props.onTabIndex(1);
this.setState({ tabIndex: 1, });
}}>
<View /> <View />
</TabBarIOS.Item> </TabBarIOS.Item>
<TabBarIOS.Item <TabBarIOS.Item
icon={require('image!tabnav_settings')} icon={require('image!tabnav_settings')}
selected={this.props.tabIndex === 2} selected={this.state.tabIndex === 2}
onPress={() => { this.props.onTabIndex(2); }}> onPress={() => {
this.props.onTabIndex(2);
this.setState({ tabIndex: 2, });
}}>
<View /> <View />
</TabBarIOS.Item> </TabBarIOS.Item>
</TabBarIOS> </TabBarIOS>
@ -81,12 +100,6 @@ class JumpingNavBar extends React.Component {
} }
var JumpingNavSample = React.createClass({ var JumpingNavSample = React.createClass({
getInitialState: function() {
return {
tabIndex: INIT_ROUTE_INDEX,
};
},
render: function() { render: function() {
return ( return (
<Navigator <Navigator
@ -98,23 +111,19 @@ var JumpingNavSample = React.createClass({
initialRoute={ROUTE_STACK[INIT_ROUTE_INDEX]} initialRoute={ROUTE_STACK[INIT_ROUTE_INDEX]}
initialRouteStack={ROUTE_STACK} initialRouteStack={ROUTE_STACK}
renderScene={this.renderScene} renderScene={this.renderScene}
configureScene={() => ({
...Navigator.SceneConfigs.HorizontalSwipeJump,
})}
navigationBar={ navigationBar={
<JumpingNavBar <JumpingNavBar
ref={(navBar) => { this.navBar = navBar; }}
initTabIndex={INIT_ROUTE_INDEX}
routeStack={ROUTE_STACK} routeStack={ROUTE_STACK}
tabIndex={this.state.tabIndex}
onTabIndex={(index) => { onTabIndex={(index) => {
this.setState({ tabIndex: index }, () => {
this._navigator.jumpTo(ROUTE_STACK[index]); this._navigator.jumpTo(ROUTE_STACK[index]);
});
}} }}
/> />
} }
onWillFocus={(route) => {
this.setState({
tabIndex: ROUTE_STACK.indexOf(route),
});
}}
shouldJumpOnBackstackPop={true}
/> />
); );
}, },

View File

@ -17,6 +17,7 @@
var React = require('react-native'); var React = require('react-native');
var ViewExample = require('./ViewExample'); var ViewExample = require('./ViewExample');
var createExamplePage = require('./createExamplePage');
var { var {
PixelRatio, PixelRatio,
ScrollView, ScrollView,
@ -77,7 +78,7 @@ var NavigatorIOSExample = React.createClass({
{this._renderRow('Push View Example', () => { {this._renderRow('Push View Example', () => {
this.props.navigator.push({ this.props.navigator.push({
title: 'Very Long Custom View Example Title', title: 'Very Long Custom View Example Title',
component: ViewExample, component: createExamplePage(null, ViewExample),
}); });
})} })}
{this._renderRow('Custom Right Button', () => { {this._renderRow('Custom Right Button', () => {

View File

@ -38,7 +38,7 @@ var NavigatorIOSExample = React.createClass({
_previousLeft: 0, _previousLeft: 0,
_previousTop: 0, _previousTop: 0,
_circleStyles: {}, _circleStyles: {},
circle: (null : ?React.Element), circle: (null : ?{ setNativeProps(props: Object): void }),
componentWillMount: function() { componentWillMount: function() {
this._panResponder = PanResponder.create({ this._panResponder = PanResponder.create({

View File

@ -6,18 +6,25 @@
* LICENSE file in the root directory of this source tree. An additional grant * 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. * of patent rights can be found in the PATENTS file in the same directory.
* *
* @providesModule Animation * @providesModule AnimationExperimental
* @flow * @flow
*/ */
'use strict'; 'use strict';
var RCTAnimationManager = require('NativeModules').AnimationManager; var RCTAnimationManager = require('NativeModules').AnimationExperimentalManager;
var AnimationUtils = require('AnimationUtils'); var AnimationUtils = require('AnimationUtils');
type EasingFunction = (t: number) => number; type EasingFunction = (t: number) => number;
var Animation = { /**
Mixin: require('AnimationMixin'), * This is an experimental module that is under development, incomplete,
* potentially buggy, not used in any production apps, and will probably change
* in non-backward compatible ways.
*
* Use at your own risk.
*/
var AnimationExperimental = {
Mixin: require('AnimationExperimentalMixin'),
startAnimation: function( startAnimation: function(
node: any, node: any,
@ -28,7 +35,14 @@ var Animation = {
): number { ): number {
var nodeHandle = +node.getNodeHandle(); var nodeHandle = +node.getNodeHandle();
var easingSample = AnimationUtils.evaluateEasingFunction(duration, easing); var easingSample = AnimationUtils.evaluateEasingFunction(duration, easing);
var tag: number = RCTAnimationManager.startAnimation(nodeHandle, AnimationUtils.allocateTag(), duration, delay, easingSample, properties); var tag: number = RCTAnimationManager.startAnimation(
nodeHandle,
AnimationUtils.allocateTag(),
duration,
delay,
easingSample,
properties
);
return tag; return tag;
}, },
@ -37,4 +51,4 @@ var Animation = {
}, },
}; };
module.exports = Animation; module.exports = AnimationExperimental;

View File

@ -6,19 +6,26 @@
* LICENSE file in the root directory of this source tree. An additional grant * 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. * of patent rights can be found in the PATENTS file in the same directory.
* *
* @providesModule AnimationMixin * @providesModule AnimationExperimentalMixin
* @flow * @flow
*/ */
'use strict'; 'use strict';
var AnimationUtils = require('AnimationUtils'); var AnimationUtils = require('AnimationUtils');
var RCTAnimationManager = require('NativeModules').AnimationManager; var RCTAnimationManager = require('NativeModules').AnimationExperimentalManager;
var invariant = require('invariant'); var invariant = require('invariant');
type EasingFunction = (t: number) => number; type EasingFunction = (t: number) => number;
var AnimationMixin = { /**
* This is an experimental module that is under development, incomplete,
* potentially buggy, not used in any production apps, and will probably change
* in non-backward compatible ways.
*
* Use at your own risk.
*/
var AnimationExperimentalMixin = {
getInitialState: function(): Object { getInitialState: function(): Object {
return {}; return {};
}, },
@ -48,4 +55,4 @@ var AnimationMixin = {
}, },
}; };
module.exports = AnimationMixin; module.exports = AnimationExperimentalMixin;

View File

@ -7,7 +7,7 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
13BE3DEE1AC21097009241FE /* RCTAnimationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* RCTAnimationManager.m */; }; 13BE3DEE1AC21097009241FE /* RCTAnimationExperimentalManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 13BE3DED1AC21097009241FE /* RCTAnimationExperimentalManager.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@ -23,9 +23,9 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRCTAnimation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAnimation.a; sourceTree = BUILT_PRODUCTS_DIR; }; 134814201AA4EA6300B7C361 /* libRCTAnimationExperimental.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTAnimationExperimental.a; sourceTree = BUILT_PRODUCTS_DIR; };
13BE3DEC1AC21097009241FE /* RCTAnimationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationManager.h; sourceTree = "<group>"; }; 13BE3DEC1AC21097009241FE /* RCTAnimationExperimentalManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAnimationExperimentalManager.h; sourceTree = "<group>"; };
13BE3DED1AC21097009241FE /* RCTAnimationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationManager.m; sourceTree = "<group>"; }; 13BE3DED1AC21097009241FE /* RCTAnimationExperimentalManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationExperimentalManager.m; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -42,7 +42,7 @@
134814211AA4EA7D00B7C361 /* Products */ = { 134814211AA4EA7D00B7C361 /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
134814201AA4EA6300B7C361 /* libRCTAnimation.a */, 134814201AA4EA6300B7C361 /* libRCTAnimationExperimental.a */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -50,8 +50,8 @@
58B511D21A9E6C8500147676 = { 58B511D21A9E6C8500147676 = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
13BE3DEC1AC21097009241FE /* RCTAnimationManager.h */, 13BE3DEC1AC21097009241FE /* RCTAnimationExperimentalManager.h */,
13BE3DED1AC21097009241FE /* RCTAnimationManager.m */, 13BE3DED1AC21097009241FE /* RCTAnimationExperimentalManager.m */,
134814211AA4EA7D00B7C361 /* Products */, 134814211AA4EA7D00B7C361 /* Products */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
@ -59,9 +59,9 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
58B511DA1A9E6C8500147676 /* RCTAnimation */ = { 58B511DA1A9E6C8500147676 /* RCTAnimationExperimental */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimation" */; buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimationExperimental" */;
buildPhases = ( buildPhases = (
58B511D71A9E6C8500147676 /* Sources */, 58B511D71A9E6C8500147676 /* Sources */,
58B511D81A9E6C8500147676 /* Frameworks */, 58B511D81A9E6C8500147676 /* Frameworks */,
@ -71,9 +71,9 @@
); );
dependencies = ( dependencies = (
); );
name = RCTAnimation; name = RCTAnimationExperimental;
productName = RCTDataManager; productName = RCTDataManager;
productReference = 134814201AA4EA6300B7C361 /* libRCTAnimation.a */; productReference = 134814201AA4EA6300B7C361 /* libRCTAnimationExperimental.a */;
productType = "com.apple.product-type.library.static"; productType = "com.apple.product-type.library.static";
}; };
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
@ -90,7 +90,7 @@
}; };
}; };
}; };
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimation" */; buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimationExperimental" */;
compatibilityVersion = "Xcode 3.2"; compatibilityVersion = "Xcode 3.2";
developmentRegion = English; developmentRegion = English;
hasScannedForEncodings = 0; hasScannedForEncodings = 0;
@ -102,7 +102,7 @@
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
targets = ( targets = (
58B511DA1A9E6C8500147676 /* RCTAnimation */, 58B511DA1A9E6C8500147676 /* RCTAnimationExperimental */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
@ -112,7 +112,7 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
13BE3DEE1AC21097009241FE /* RCTAnimationManager.m in Sources */, 13BE3DEE1AC21097009241FE /* RCTAnimationExperimentalManager.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -203,7 +203,7 @@
); );
LIBRARY_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RCTAnimation; PRODUCT_NAME = RCTAnimationExperimental;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
}; };
name = Debug; name = Debug;
@ -218,7 +218,7 @@
); );
LIBRARY_SEARCH_PATHS = "$(inherited)"; LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RCTAnimation; PRODUCT_NAME = RCTAnimationExperimental;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
}; };
name = Release; name = Release;
@ -226,7 +226,7 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimation" */ = { 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTAnimationExperimental" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
58B511ED1A9E6C8500147676 /* Debug */, 58B511ED1A9E6C8500147676 /* Debug */,
@ -235,7 +235,7 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimation" */ = { 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTAnimationExperimental" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
58B511F01A9E6C8500147676 /* Debug */, 58B511F01A9E6C8500147676 /* Debug */,

View File

@ -12,6 +12,6 @@
#import "RCTBridgeModule.h" #import "RCTBridgeModule.h"
@interface RCTAnimationManager : NSObject <RCTBridgeModule> @interface RCTAnimationExperimentalManager : NSObject <RCTBridgeModule>
@end @end

View File

@ -7,7 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#import "RCTAnimationManager.h" #import "RCTAnimationExperimentalManager.h"
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
@ -20,7 +20,7 @@
#define CG_APPEND(PREFIX, SUFFIX_F, SUFFIX_D) PREFIX##SUFFIX_F #define CG_APPEND(PREFIX, SUFFIX_F, SUFFIX_D) PREFIX##SUFFIX_F
#endif #endif
@implementation RCTAnimationManager @implementation RCTAnimationExperimentalManager
{ {
RCTSparseArray *_animationRegistry; // Main thread only; animation tag -> view tag RCTSparseArray *_animationRegistry; // Main thread only; animation tag -> view tag
} }
@ -65,9 +65,9 @@
{ {
RCT_EXPORT(startAnimation); RCT_EXPORT(startAnimation);
__weak RCTAnimationManager *weakSelf = self; __weak RCTAnimationExperimentalManager *weakSelf = self;
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
RCTAnimationManager *strongSelf = weakSelf; RCTAnimationExperimentalManager *strongSelf = weakSelf;
UIView *view = viewRegistry[reactTag]; UIView *view = viewRegistry[reactTag];
if (!view) { if (!view) {
@ -182,9 +182,9 @@
{ {
RCT_EXPORT(stopAnimation); RCT_EXPORT(stopAnimation);
__weak RCTAnimationManager *weakSelf = self; __weak RCTAnimationExperimentalManager *weakSelf = self;
[_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) { [_bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, RCTSparseArray *viewRegistry) {
RCTAnimationManager *strongSelf = weakSelf; RCTAnimationExperimentalManager *strongSelf = weakSelf;
NSNumber *reactTag = strongSelf->_animationRegistry[animationTag]; NSNumber *reactTag = strongSelf->_animationRegistry[animationTag];
if (!reactTag) return; if (!reactTag) return;

View File

@ -364,10 +364,16 @@ var ScrollResponderMixin = {
/** /**
* This method should be used as the callback to onFocus in a TextInputs' * This method should be used as the callback to onFocus in a TextInputs'
* parent view. Note that any module using this mixin needs to return * parent view. Note that any module using this mixin needs to return
* the parent view's ref in getScrollViewRef() in order to use this method * the parent view's ref in getScrollViewRef() in order to use this method.
* @param {any} nodeHandle The TextInput node handle
* @param {number} additionalOffset The scroll view's top "contentInset".
* Default is 0.
* @param {bool} preventNegativeScrolling Whether to allow pulling the content
* down to make it meet the keyboard's top. Default is false.
*/ */
scrollResponderScrollNativeHandleToKeyboard: function(nodeHandle: any, additionalOffset?: number) { scrollResponderScrollNativeHandleToKeyboard: function(nodeHandle: any, additionalOffset?: number, preventNegativeScrollOffset?: bool) {
this.additionalScrollOffset = additionalOffset || 0; this.additionalScrollOffset = additionalOffset || 0;
this.preventNegativeScrollOffset = !!preventNegativeScrollOffset;
RCTUIManager.measureLayout( RCTUIManager.measureLayout(
nodeHandle, nodeHandle,
this.getNodeHandle(), this.getNodeHandle(),
@ -391,9 +397,18 @@ var ScrollResponderMixin = {
var scrollOffsetY = var scrollOffsetY =
top - this.keyboardWillOpenTo.endCoordinates.screenY + height + top - this.keyboardWillOpenTo.endCoordinates.screenY + height +
this.additionalScrollOffset; this.additionalScrollOffset;
// By default, this can scroll with negative offset, pulling the content
// down so that the target component's bottom meets the keyboard's top.
// If requested otherwise, cap the offset at 0 minimum to avoid content
// shifting down.
if (this.preventNegativeScrollOffset) {
scrollOffsetY = Math.max(0, scrollOffsetY);
}
this.scrollResponderScrollTo(0, scrollOffsetY); this.scrollResponderScrollTo(0, scrollOffsetY);
} }
this.additionalOffset = 0; this.additionalOffset = 0;
this.preventNegativeScrollOffset = false;
}, },
scrollResponderTextInputFocusError: function(e: Event) { scrollResponderTextInputFocusError: function(e: Event) {

View File

@ -40,7 +40,7 @@ var SliderIOS = React.createClass({
* Default value is 0. * Default value is 0.
* *
* *This is not a controlled component*, e.g. if you don't update * *This is not a controlled component*, e.g. if you don't update
* the value, the component won't be reset to it's inital value. * the value, the component won't be reset to its inital value.
*/ */
value: PropTypes.number, value: PropTypes.number,
@ -82,6 +82,8 @@ var SliderIOS = React.createClass({
<RCTSlider <RCTSlider
style={[styles.slider, this.props.style]} style={[styles.slider, this.props.style]}
value={this.props.value} value={this.props.value}
maximumValue={this.props.maximumValue}
minimumValue={this.props.minimumValue}
onChange={this._onValueChange} onChange={this._onValueChange}
/> />
); );
@ -94,8 +96,15 @@ var styles = StyleSheet.create({
}, },
}); });
var validAttributes = {
...ReactIOSViewAttributes.UIView,
value: true,
minimumValue: true,
maximumValue: true,
};
var RCTSlider = createReactIOSNativeComponentClass({ var RCTSlider = createReactIOSNativeComponentClass({
validAttributes: merge(ReactIOSViewAttributes.UIView, {value: true}), validAttributes: validAttributes,
uiViewClassName: 'RCTSlider', uiViewClassName: 'RCTSlider',
}); });

View File

@ -217,8 +217,6 @@ var TextInput = React.createClass({
*/ */
onFocus: PropTypes.func, onFocus: PropTypes.func,
/** /**
* (text: string) => void
*
* Callback that is called when the text input's text changes. * Callback that is called when the text input's text changes.
*/ */
onChange: PropTypes.func, onChange: PropTypes.func,

View File

@ -14,7 +14,7 @@
var NativeMethodsMixin = require('NativeMethodsMixin'); var NativeMethodsMixin = require('NativeMethodsMixin');
var React = require('React'); var React = require('React');
var POPAnimation = require('POPAnimation'); var POPAnimation = require('POPAnimation');
var Animation = require('Animation'); var AnimationExperimental = require('AnimationExperimental');
var Touchable = require('Touchable'); var Touchable = require('Touchable');
var merge = require('merge'); var merge = require('merge');
@ -79,7 +79,7 @@ var TouchableBounce = React.createClass({
this.state.animationID = POPAnimation.createSpringAnimation(anim); this.state.animationID = POPAnimation.createSpringAnimation(anim);
this.addAnimation(this.state.animationID, callback); this.addAnimation(this.state.animationID, callback);
} else { } else {
Animation.startAnimation(this, 300, 0, 'easeOutBack', {scaleXY: [value, value]}); AnimationExperimental.startAnimation(this, 300, 0, 'easeOutBack', {scaleXY: [value, value]});
if (fromValue && typeof fromValue === 'function') { if (fromValue && typeof fromValue === 'function') {
callback = fromValue; callback = fromValue;
} }

View File

@ -13,7 +13,6 @@
var React = require('React'); var React = require('React');
var Touchable = require('Touchable'); var Touchable = require('Touchable');
var onlyChild = require('onlyChild'); var onlyChild = require('onlyChild');
/** /**
@ -78,10 +77,8 @@ var TouchableWithoutFeedback = React.createClass({
}, },
render: function(): ReactElement { render: function(): ReactElement {
// Note(vjeux): use cloneWithProps once React has been upgraded
var child = onlyChild(this.props.children);
// Note(avik): remove dynamic typecast once Flow has been upgraded // Note(avik): remove dynamic typecast once Flow has been upgraded
return (React: any).cloneElement(child, { return (React: any).cloneElement(onlyChild(this.props.children), {
accessible: true, accessible: true,
testID: this.props.testID, testID: this.props.testID,
onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder, onStartShouldSetResponder: this.touchableHandleStartShouldSetResponder,

View File

@ -7,6 +7,7 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
* *
* @providesModule View * @providesModule View
* @flow
*/ */
'use strict'; 'use strict';

View File

@ -32,38 +32,6 @@ var invariant = require('invariant');
var isEmpty = require('isEmpty'); var isEmpty = require('isEmpty');
var warning = require('warning'); var warning = require('warning');
/**
* ListViewDataSource - Provides efficient data processing and access to the
* ListView component. A ListViewDataSource is created with functions for
* extracting data from the input blob, and comparing elements (with default
* implementations for convenience). The input blob can be as simple as an
* array of strings, or an object with rows nested inside section objects.
*
* To update the data in the datasource, use `cloneWithRows` (or
* `cloneWithRowsAndSections` if you care about sections). The data in the
* data source is immutable, so you can't modify it directly. The clone methods
* suck in the new data and compute a diff for each row so ListView knows
* whether to re-render it or not.
*
* In this example, a component receives data in chunks, handled by
* `_onDataArrived`, which concats the new data onto the old data and updates the
* data source. We use `concat` to create a new array - mutating `this._data`,
* e.g. with `this._data.push(newRowData)`, would be an error. `_rowHasChanged`
* understands the shape of the row data and knows how to efficiently compare
* it.
*
* getInitialState: function() {
* var ds = new ListViewDataSource({rowHasChanged: this._rowHasChanged});
* return {ds};
* },
* _onDataArrived(newData) {
* this._data = this._data.concat(newData);
* this.setState({
* ds: this.state.ds.cloneWithRows(this._data)
* });
* }
*/
function defaultGetRowData( function defaultGetRowData(
dataBlob: any, dataBlob: any,
sectionID: number | string, sectionID: number | string,
@ -88,15 +56,58 @@ type ParamType = {
getSectionHeaderData: ?typeof defaultGetSectionHeaderData; getSectionHeaderData: ?typeof defaultGetSectionHeaderData;
} }
/**
* Provides efficient data processing and access to the
* `ListView` component. A `ListViewDataSource` is created with functions for
* extracting data from the input blob, and comparing elements (with default
* implementations for convenience). The input blob can be as simple as an
* array of strings, or an object with rows nested inside section objects.
*
* To update the data in the datasource, use `cloneWithRows` (or
* `cloneWithRowsAndSections` if you care about sections). The data in the
* data source is immutable, so you can't modify it directly. The clone methods
* suck in the new data and compute a diff for each row so ListView knows
* whether to re-render it or not.
*
* In this example, a component receives data in chunks, handled by
* `_onDataArrived`, which concats the new data onto the old data and updates the
* data source. We use `concat` to create a new array - mutating `this._data`,
* e.g. with `this._data.push(newRowData)`, would be an error. `_rowHasChanged`
* understands the shape of the row data and knows how to efficiently compare
* it.
*
* ```
* getInitialState: function() {
* var ds = new ListViewDataSource({rowHasChanged: this._rowHasChanged});
* return {ds};
* },
* _onDataArrived(newData) {
* this._data = this._data.concat(newData);
* this.setState({
* ds: this.state.ds.cloneWithRows(this._data)
* });
* }
* ```
*/
class ListViewDataSource { class ListViewDataSource {
/** /**
* @param {ParamType} params * You can provide custom extraction and `hasChanged` functions for section
*
* You can provide custom extraction and 'hasChanged' functions for section
* headers and rows. If absent, data will be extracted with the * headers and rows. If absent, data will be extracted with the
* `defaultGetRowData` and `defaultGetSectionHeaderData` functions. * `defaultGetRowData` and `defaultGetSectionHeaderData` functions.
* *
* The default extractor expects data of one of the following forms:
*
* { sectionID_1: { rowID_1: <rowData1>, ... }, ... }
*
* or
*
* [ [ <rowData1>, <rowData2>, ... ], ... ]
*
* The constructor takes in a params argument that can contain any of the
* following:
*
* - getRowData(dataBlob, sectionID, rowID); * - getRowData(dataBlob, sectionID, rowID);
* - getSectionHeaderData(dataBlob, sectionID); * - getSectionHeaderData(dataBlob, sectionID);
* - rowHasChanged(prevRowData, nextRowData); * - rowHasChanged(prevRowData, nextRowData);
@ -125,9 +136,20 @@ class ListViewDataSource {
} }
/** /**
* @param {object} dataBlob -- This is an arbitrary blob of data. An extractor * Clones this `ListViewDataSource` with the specified `dataBlob` and
* function was defined at construction time. The default extractor assumes * `rowIdentities`. The `dataBlob` is just an aribitrary blob of data. At
* the data is a plain array or keyed object. * construction an extractor to get the interesting informatoin was defined
* (or the default was used).
*
* The `rowIdentities` is is a 2D array of identifiers for rows.
* ie. [['a1', 'a2'], ['b1', 'b2', 'b3'], ...]. If not provided, it's
* assumed that the keys of the section data are the row identities.
*
* Note: This function does NOT clone the data in this data source. It simply
* passes the functions defined at construction to a new data source with
* the data specified. If you wish to maintain the existing data you must
* handle merging of old and new data separately and then pass that into
* this function as the `dataBlob`.
*/ */
cloneWithRows( cloneWithRows(
dataBlob: Array<any> | {[key: string]: any}, dataBlob: Array<any> | {[key: string]: any},
@ -141,22 +163,13 @@ class ListViewDataSource {
} }
/** /**
* @param {object} dataBlob -- This is an arbitrary blob of data. An extractor * This performs the same function as the `cloneWithRows` function but here
* function was defined at construction time. The default extractor assumes * you also specify what your `sectionIdentities` are. If you don't care
* the data is a nested array or keyed object of the form: * about sections you should safely be able to use `cloneWithRows`.
* *
* { sectionID_1: { rowID_1: <rowData1>, ... }, ... } * `sectionIdentities` is an array of identifiers for sections.
* * ie. ['s1', 's2', ...]. If not provided, it's assumed that the
* or
*
* [ [ <rowData1>, <rowData2>, ... ], ... ]
*
* @param {array} sectionIdentities -- This is an array of identifiers for
* sections. ie. ['s1', 's2', ...]. If not provided, it's assumed that the
* keys of dataBlob are the section identities. * keys of dataBlob are the section identities.
* @param {array} rowIdentities -- This is a 2D array of identifiers for rows.
* ie. [['a1', 'a2'], ['b1', 'b2', 'b3'], ...]. If not provided, it's
* assumed that the keys of the section data are the row identities.
* *
* Note: this returns a new object! * Note: this returns a new object!
*/ */
@ -205,9 +218,6 @@ class ListViewDataSource {
} }
/** /**
* @param {number} sectionIndex
* @param {number} rowIndex
*
* Returns if the row is dirtied and needs to be rerendered * Returns if the row is dirtied and needs to be rerendered
*/ */
rowShouldUpdate(sectionIndex: number, rowIndex: number): bool { rowShouldUpdate(sectionIndex: number, rowIndex: number): bool {
@ -218,9 +228,6 @@ class ListViewDataSource {
} }
/** /**
* @param {number} sectionIndex
* @param {number} rowIndex
*
* Gets the data required to render the row. * Gets the data required to render the row.
*/ */
getRowData(sectionIndex: number, rowIndex: number): any { getRowData(sectionIndex: number, rowIndex: number): any {
@ -234,8 +241,6 @@ class ListViewDataSource {
} }
/** /**
* @param {number} index
*
* Gets the rowID at index provided if the dataSource arrays were flattened, * Gets the rowID at index provided if the dataSource arrays were flattened,
* or null of out of range indexes. * or null of out of range indexes.
*/ */
@ -252,8 +257,6 @@ class ListViewDataSource {
} }
/** /**
* @param {number} index
*
* Gets the sectionID at index provided if the dataSource arrays were flattened, * Gets the sectionID at index provided if the dataSource arrays were flattened,
* or null for out of range indexes. * or null for out of range indexes.
*/ */
@ -281,8 +284,6 @@ class ListViewDataSource {
} }
/** /**
* @param {number} sectionIndex
*
* Returns if the section header is dirtied and needs to be rerendered * Returns if the section header is dirtied and needs to be rerendered
*/ */
sectionHeaderShouldUpdate(sectionIndex: number): bool { sectionHeaderShouldUpdate(sectionIndex: number): bool {
@ -293,8 +294,6 @@ class ListViewDataSource {
} }
/** /**
* @param {number} sectionIndex
*
* Gets the data required to render the section header * Gets the data required to render the section header
*/ */
getSectionHeaderData(sectionIndex: number): any { getSectionHeaderData(sectionIndex: number): any {

View File

@ -54,8 +54,6 @@ var SCREEN_HEIGHT = Dimensions.get('window').height;
var OFF_SCREEN = {style: {opacity: 0}}; var OFF_SCREEN = {style: {opacity: 0}};
var NAVIGATION_BAR_REF = 'navigationBar_ref';
var __uid = 0; var __uid = 0;
function getuid() { function getuid() {
return __uid++; return __uid++;
@ -94,6 +92,12 @@ var styles = StyleSheet.create({
} }
}); });
var GESTURE_ACTIONS = [
'pop',
'jumpBack',
'jumpForward',
];
/** /**
* Use `Navigator` to transition between different scenes in your app. To * Use `Navigator` to transition between different scenes in your app. To
* accomplish this, provide route objects to the navigator to identify each * accomplish this, provide route objects to the navigator to identify each
@ -314,6 +318,7 @@ var Navigator = React.createClass({
popToRoute: this.popToRoute, popToRoute: this.popToRoute,
popToTop: this.popToTop, popToTop: this.popToTop,
parentNavigator: this.props.navigator, parentNavigator: this.props.navigator,
getCurrentRoutes: this.getCurrentRoutes,
// We want to bubble focused routes to the top navigation stack. If we // We want to bubble focused routes to the top navigation stack. If we
// are a child navigator, this allows us to call props.navigator.on*Focus // are a child navigator, this allows us to call props.navigator.on*Focus
// of the topmost Navigator // of the topmost Navigator
@ -457,15 +462,18 @@ var Navigator = React.createClass({
_completeTransition: function() { _completeTransition: function() {
if (this.spring.getCurrentValue() === 1) { if (this.spring.getCurrentValue() === 1) {
var presentedIndex = this.state.toIndex; var presentedIndex = this.state.toIndex;
this.state.fromIndex = presentedIndex;
this.state.presentedIndex = presentedIndex; this.state.presentedIndex = presentedIndex;
this.state.fromIndex = presentedIndex;
this._emitDidFocus(presentedIndex); this._emitDidFocus(presentedIndex);
this._removePoppedRoutes(); this._removePoppedRoutes();
if (AnimationsDebugModule) { if (AnimationsDebugModule) {
AnimationsDebugModule.stopRecordingFps(Date.now()); AnimationsDebugModule.stopRecordingFps(Date.now());
} }
this._hideOtherScenes(presentedIndex); } else {
this.state.fromIndex = this.state.presentedIndex;
this.state.toIndex = this.state.presentedIndex;
} }
this._hideOtherScenes(presentedIndex);
}, },
_transitionToToIndexWithVelocity: function(v) { _transitionToToIndexWithVelocity: function(v) {
@ -499,6 +507,10 @@ var Navigator = React.createClass({
_emitWillFocus: function(index) { _emitWillFocus: function(index) {
var route = this.state.routeStack[index]; var route = this.state.routeStack[index];
var navBar = this._navBar;
if (navBar && navBar.handleWillFocus) {
navBar.handleWillFocus(route);
}
if (this.props.onWillFocus) { if (this.props.onWillFocus) {
this.props.onWillFocus(route); this.props.onWillFocus(route);
} else if (this.props.navigator && this.props.navigator.onWillFocus) { } else if (this.props.navigator && this.props.navigator.onWillFocus) {
@ -532,95 +544,170 @@ var Navigator = React.createClass({
_handleMoveShouldSetPanResponder: function(e, gestureState) { _handleMoveShouldSetPanResponder: function(e, gestureState) {
var currentRoute = this.state.routeStack[this.state.presentedIndex]; var currentRoute = this.state.routeStack[this.state.presentedIndex];
var animationConfig = this.state.sceneConfigStack[this.state.presentedIndex]; var sceneConfig = this.state.sceneConfigStack[this.state.presentedIndex];
if (!animationConfig.enableGestures) { this._expectingGestureGrant = this._matchGestureAction(sceneConfig.gestures, gestureState);
return false; return !! this._expectingGestureGrant;
} },
var currentLoc = animationConfig.isVertical ? gestureState.moveY : gestureState.moveX;
var travelDist = animationConfig.isVertical ? gestureState.dy : gestureState.dx; _doesGestureOverswipe: function(gestureName) {
var oppositeAxisTravelDist = var wouldOverswipeBack = this.state.presentedIndex <= 0 &&
animationConfig.isVertical ? gestureState.dx : gestureState.dy; (gestureName === 'pop' || gestureName === 'jumpBack');
var moveStartedInRegion = currentLoc < animationConfig.edgeHitWidth; var wouldOverswipeForward = this.state.presentedIndex >= this.state.routeStack.length - 1 &&
var moveTravelledFarEnough = gestureName === 'jumpForward';
travelDist >= animationConfig.gestureDetectMovement && return wouldOverswipeForward || wouldOverswipeBack;
travelDist > oppositeAxisTravelDist * animationConfig.directionRatio;
return (
!this.state.isResponderOnlyToBlockTouches &&
moveStartedInRegion &&
!this.state.isAnimating &&
this.state.presentedIndex > 0 &&
moveTravelledFarEnough
);
}, },
_handlePanResponderGrant: function(e, gestureState) { _handlePanResponderGrant: function(e, gestureState) {
invariant(
this._expectingGestureGrant,
'Responder granted unexpectedly.'
);
this._activeGestureAction = this._expectingGestureGrant;
this._expectingGestureGrant = null;
this.state.isResponderOnlyToBlockTouches = this.state.isAnimating; this.state.isResponderOnlyToBlockTouches = this.state.isAnimating;
if (!this.state.isAnimating) { if (!this.state.isAnimating) {
this.state.fromIndex = this.state.presentedIndex; this.state.fromIndex = this.state.presentedIndex;
this.state.toIndex = this.state.presentedIndex - 1; var gestureSceneDelta = this._deltaForGestureAction(this._activeGestureAction);
this.state.toIndex = this.state.presentedIndex + gestureSceneDelta;
}
},
_deltaForGestureAction: function(gestureAction) {
switch (gestureAction) {
case 'pop':
case 'jumpBack':
return -1;
case 'jumpForward':
return 1;
default:
invariant(false, 'Unsupported gesture action ' + gestureAction);
return;
} }
}, },
_handlePanResponderRelease: function(e, gestureState) { _handlePanResponderRelease: function(e, gestureState) {
var sceneConfig = this.state.sceneConfigStack[this.state.presentedIndex];
var releaseGestureAction = this._activeGestureAction;
this._activeGestureAction = null;
if (this.state.isResponderOnlyToBlockTouches) { if (this.state.isResponderOnlyToBlockTouches) {
this.state.isResponderOnlyToBlockTouches = false; this.state.isResponderOnlyToBlockTouches = false;
return; return;
} }
var animationConfig = this.state.sceneConfigStack[this.state.presentedIndex]; var releaseGesture = sceneConfig.gestures[releaseGestureAction];
var velocity = animationConfig.isVertical ? gestureState.vy : gestureState.vx;
// It's not the real location. There is no *real* location - that's the
// point of the pan gesture.
var pseudoLocation = animationConfig.isVertical ?
gestureState.y0 + gestureState.dy :
gestureState.x0 + gestureState.dx;
var still = Math.abs(velocity) < animationConfig.notMoving;
if (this.spring.getCurrentValue() === 0) { if (this.spring.getCurrentValue() === 0) {
// The spring is at zero, so the gesture is already complete
this.spring.setCurrentValue(0).setAtRest(); this.spring.setCurrentValue(0).setAtRest();
this._completeTransition(); this._completeTransition();
return; return;
} }
var transitionVelocity = var isTravelVertical = releaseGesture.direction === 'top-to-bottom' || releaseGesture.direction === 'bottom-to-top';
still && animationConfig.pastPointOfNoReturn(pseudoLocation) ? animationConfig.snapVelocity : var isTravelInverted = releaseGesture.direction === 'right-to-left' || releaseGesture.direction === 'bottom-to-top';
still && !animationConfig.pastPointOfNoReturn(pseudoLocation) ? -animationConfig.snapVelocity : var velocity, gestureDistance;
clamp(-10, velocity, 10); // What are Rebound UoM? if (isTravelVertical) {
velocity = isTravelInverted ? -gestureState.vy : gestureState.vy;
gestureDistance = isTravelInverted ? -gestureState.dy : gestureState.dy;
} else {
velocity = isTravelInverted ? -gestureState.vx : gestureState.vx;
gestureDistance = isTravelInverted ? -gestureState.dx : gestureState.dx;
}
var transitionVelocity = clamp(-10, velocity, 10);
if (Math.abs(velocity) < releaseGesture.notMoving) {
// The gesture velocity is so slow, is "not moving"
var hasGesturedEnoughToComplete = gestureDistance > releaseGesture.fullDistance * releaseGesture.stillCompletionRatio;
transitionVelocity = hasGesturedEnoughToComplete ? releaseGesture.snapVelocity : -releaseGesture.snapVelocity;
}
this.spring.setOvershootClampingEnabled(true); this.spring.setOvershootClampingEnabled(true);
if (transitionVelocity < 0) { if (transitionVelocity < 0 || this._doesGestureOverswipe(releaseGestureAction)) {
this._transitionToFromIndexWithVelocity(transitionVelocity); this._transitionToFromIndexWithVelocity(transitionVelocity);
} else { } else {
this._manuallyPopBackstack(1);
this._transitionToToIndexWithVelocity(transitionVelocity); this._transitionToToIndexWithVelocity(transitionVelocity);
} }
}, },
_handlePanResponderTerminate: function(e, gestureState) { _handlePanResponderTerminate: function(e, gestureState) {
this._activeGestureAction = null;
this.state.isResponderOnlyToBlockTouches = false; this.state.isResponderOnlyToBlockTouches = false;
this._transitionToFromIndexWithVelocity(0); this._transitionToFromIndexWithVelocity(0);
}, },
_handlePanResponderMove: function(e, gestureState) { _handlePanResponderMove: function(e, gestureState) {
if (!this.state.isResponderOnlyToBlockTouches) { if (!this.state.isResponderOnlyToBlockTouches) {
var animationConfig = this.state.sceneConfigStack[this.state.presentedIndex]; var sceneConfig = this.state.sceneConfigStack[this.state.presentedIndex];
var distance = animationConfig.isVertical ? gestureState.dy : gestureState.dx; var gesture = sceneConfig.gestures[this._activeGestureAction];
var gestureDetectMovement = animationConfig.gestureDetectMovement; var isTravelVertical = gesture.direction === 'top-to-bottom' || gesture.direction === 'bottom-to-top';
var isTravelInverted = gesture.direction === 'right-to-left' || gesture.direction === 'bottom-to-top';
var distance = isTravelVertical ? gestureState.dy : gestureState.dx;
distance = isTravelInverted ? - distance : distance;
var gestureDetectMovement = gesture.gestureDetectMovement;
var nextProgress = (distance - gestureDetectMovement) / var nextProgress = (distance - gestureDetectMovement) /
(animationConfig.screenDimension - gestureDetectMovement); (gesture.fullDistance - gestureDetectMovement);
if (this._doesGestureOverswipe(this._activeGestureAction)) {
var frictionConstant = gesture.overswipe.frictionConstant;
var frictionByDistance = gesture.overswipe.frictionByDistance;
var frictionRatio = 1 / ((frictionConstant) + (Math.abs(nextProgress) * frictionByDistance));
nextProgress *= frictionRatio;
}
this.spring.setCurrentValue(clamp(0, nextProgress, 1)); this.spring.setCurrentValue(clamp(0, nextProgress, 1));
} }
}, },
_matchGestureAction: function(gestures, gestureState) {
if (!gestures) {
return null;
}
if (this.state.isResponderOnlyToBlockTouches || this.state.isAnimating) {
return null;
}
var matchedGesture = null;
GESTURE_ACTIONS.some((gestureName) => {
var gesture = gestures[gestureName];
if (!gesture) {
return;
}
if (gesture.overswipe == null && this._doesGestureOverswipe(gestureName)) {
// cannot swipe past first or last scene without overswiping
return false;
}
var isTravelVertical = gesture.direction === 'top-to-bottom' || gesture.direction === 'bottom-to-top';
var isTravelInverted = gesture.direction === 'right-to-left' || gesture.direction === 'bottom-to-top';
var currentLoc = isTravelVertical ? gestureState.moveY : gestureState.moveX;
var travelDist = isTravelVertical ? gestureState.dy : gestureState.dx;
var oppositeAxisTravelDist =
isTravelVertical ? gestureState.dx : gestureState.dy;
if (isTravelInverted) {
currentLoc = -currentLoc;
travelDist = -travelDist;
oppositeAxisTravelDist = -oppositeAxisTravelDist;
}
var moveStartedInRegion = gesture.edgeHitWidth == null ||
currentLoc < gesture.edgeHitWidth;
var moveTravelledFarEnough =
travelDist >= gesture.gestureDetectMovement &&
travelDist > oppositeAxisTravelDist * gesture.directionRatio;
if (moveStartedInRegion && moveTravelledFarEnough) {
matchedGesture = gestureName;
return true;
}
});
return matchedGesture;
},
_transitionSceneStyle: function(fromIndex, toIndex, progress, index) { _transitionSceneStyle: function(fromIndex, toIndex, progress, index) {
var viewAtIndex = this.refs['scene_' + index]; var viewAtIndex = this.refs['scene_' + index];
if (viewAtIndex === null || viewAtIndex === undefined) { if (viewAtIndex === null || viewAtIndex === undefined) {
return; return;
} }
// Use toIndex animation when we move forwards. Use fromIndex when we move back // Use toIndex animation when we move forwards. Use fromIndex when we move back
var animationIndex = this.state.presentedIndex < toIndex ? toIndex : fromIndex; var sceneConfigIndex = this.state.presentedIndex < toIndex ? toIndex : fromIndex;
var animationConfig = this.state.sceneConfigStack[animationIndex]; var sceneConfig = this.state.sceneConfigStack[sceneConfigIndex];
// this happens for overswiping when there is no scene at toIndex
if (!sceneConfig) {
sceneConfig = this.state.sceneConfigStack[sceneConfigIndex - 1];
}
var styleToUse = {}; var styleToUse = {};
var useFn = index < fromIndex || index < toIndex ? var useFn = index < fromIndex || index < toIndex ?
animationConfig.interpolators.out : sceneConfig.animationInterpolators.out :
animationConfig.interpolators.into; sceneConfig.animationInterpolators.into;
var directionAdjustedProgress = fromIndex < toIndex ? progress : 1 - progress; var directionAdjustedProgress = fromIndex < toIndex ? progress : 1 - progress;
var didChange = useFn(styleToUse, directionAdjustedProgress); var didChange = useFn(styleToUse, directionAdjustedProgress);
if (didChange) { if (didChange) {
@ -631,7 +718,7 @@ var Navigator = React.createClass({
_transitionBetween: function(fromIndex, toIndex, progress) { _transitionBetween: function(fromIndex, toIndex, progress) {
this._transitionSceneStyle(fromIndex, toIndex, progress, fromIndex); this._transitionSceneStyle(fromIndex, toIndex, progress, fromIndex);
this._transitionSceneStyle(fromIndex, toIndex, progress, toIndex); this._transitionSceneStyle(fromIndex, toIndex, progress, toIndex);
var navBar = this.refs[NAVIGATION_BAR_REF]; var navBar = this._navBar;
if (navBar && navBar.updateProgress) { if (navBar && navBar.updateProgress) {
navBar.updateProgress(progress, fromIndex, toIndex); navBar.updateProgress(progress, fromIndex, toIndex);
} }
@ -912,6 +999,10 @@ var Navigator = React.createClass({
} }
}, },
getCurrentRoutes: function() {
return this.state.routeStack;
},
_onItemRef: function(itemId, ref) { _onItemRef: function(itemId, ref) {
this._itemRefs[itemId] = ref; this._itemRefs[itemId] = ref;
var itemIndex = this.state.idStack.indexOf(itemId); var itemIndex = this.state.idStack.indexOf(itemId);
@ -989,7 +1080,7 @@ var Navigator = React.createClass({
return null; return null;
} }
return React.cloneElement(this.props.navigationBar, { return React.cloneElement(this.props.navigationBar, {
ref: NAVIGATION_BAR_REF, ref: (navBar) => { this._navBar = navBar; },
navigator: this.navigatorActions, navigator: this.navigatorActions,
navState: this.state, navState: this.state,
}); });

View File

@ -30,7 +30,6 @@ var Dimensions = require('Dimensions');
var PixelRatio = require('PixelRatio'); var PixelRatio = require('PixelRatio');
var buildStyleInterpolator = require('buildStyleInterpolator'); var buildStyleInterpolator = require('buildStyleInterpolator');
var merge = require('merge');
var SCREEN_WIDTH = Dimensions.get('window').width; var SCREEN_WIDTH = Dimensions.get('window').width;
var SCREEN_HEIGHT = Dimensions.get('window').height; var SCREEN_HEIGHT = Dimensions.get('window').height;
@ -220,32 +219,12 @@ var FromTheFront = {
}, },
}; };
var BaseOverswipeConfig = {
var Interpolators = { frictionConstant: 1,
Vertical: { frictionByDistance: 1.5,
into: buildStyleInterpolator(FromTheFront),
out: buildStyleInterpolator(ToTheBack),
},
Horizontal: {
into: buildStyleInterpolator(FromTheRight),
out: buildStyleInterpolator(ToTheLeft),
},
}; };
var BaseLeftToRightGesture = {
// These are meant to mimic iOS default behavior
var PastPointOfNoReturn = {
horizontal: function(location) {
return location > SCREEN_WIDTH * 3 / 5;
},
vertical: function(location) {
return location > SCREEN_HEIGHT * 3 / 5;
},
};
var BaseConfig = {
// When false, all gestures are ignored for this scene
enableGestures: true,
// How far the swipe must drag to start transitioning // How far the swipe must drag to start transitioning
gestureDetectMovement: 2, gestureDetectMovement: 2,
@ -253,48 +232,88 @@ var BaseConfig = {
// Amplitude of release velocity that is considered still // Amplitude of release velocity that is considered still
notMoving: 0.3, notMoving: 0.3,
// Velocity to start at when transitioning without gesture
defaultTransitionVelocity: 1.5,
// Fraction of directional move required. // Fraction of directional move required.
directionRatio: 0.66, directionRatio: 0.66,
// Velocity to transition with when the gesture release was "not moving" // Velocity to transition with when the gesture release was "not moving"
snapVelocity: 2, snapVelocity: 2,
// Region that can trigger swipe. iOS default is 30px from the left edge
edgeHitWidth: 30,
// Ratio of gesture completion when non-velocity release will cause action
stillCompletionRatio: 3 / 5,
fullDistance: SCREEN_WIDTH,
direction: 'left-to-right',
};
var BaseRightToLeftGesture = {
...BaseLeftToRightGesture,
direction: 'right-to-left',
};
var BaseConfig = {
// A list of all gestures that are enabled on this scene
gestures: {
pop: BaseLeftToRightGesture,
},
// Rebound spring parameters when transitioning FROM this scene // Rebound spring parameters when transitioning FROM this scene
springFriction: 26, springFriction: 26,
springTension: 200, springTension: 200,
// Defaults for horizontal transitioning: // Velocity to start at when transitioning without gesture
defaultTransitionVelocity: 1.5,
isVertical: false, // Animation interpolators for horizontal transitioning:
screenDimension: SCREEN_WIDTH, animationInterpolators: {
into: buildStyleInterpolator(FromTheRight),
// Region that can trigger swipe. iOS default is 30px from the left edge out: buildStyleInterpolator(ToTheLeft),
edgeHitWidth: 30, },
// Point at which a non-velocity release will cause nav pop
pastPointOfNoReturn: PastPointOfNoReturn.horizontal,
// Animation interpolators for this transition
interpolators: Interpolators.Horizontal,
}; };
var NavigatorSceneConfigs = { var NavigatorSceneConfigs = {
PushFromRight: merge(BaseConfig, { PushFromRight: {
...BaseConfig,
// We will want to customize this soon // We will want to customize this soon
}), },
FloatFromRight: merge(BaseConfig, { FloatFromRight: {
...BaseConfig,
// We will want to customize this soon // We will want to customize this soon
}), },
FloatFromBottom: merge(BaseConfig, { FloatFromBottom: {
...BaseConfig,
gestures: {
pop: {
...BaseLeftToRightGesture,
edgeHitWidth: 150, edgeHitWidth: 150,
interpolators: Interpolators.Vertical, direction: 'top-to-bottom',
isVertical: true, fullDistance: SCREEN_HEIGHT,
pastPointOfNoReturn: PastPointOfNoReturn.vertical, }
screenDimension: SCREEN_HEIGHT, },
}), animationInterpolators: {
into: buildStyleInterpolator(FromTheFront),
out: buildStyleInterpolator(ToTheBack),
},
},
HorizontalSwipeJump: {
...BaseConfig,
gestures: {
jumpBack: {
...BaseLeftToRightGesture,
overswipe: BaseOverswipeConfig,
edgeHitWidth: null,
},
jumpForward: {
...BaseRightToLeftGesture,
overswipe: BaseOverswipeConfig,
edgeHitWidth: null,
},
}
}
}; };
module.exports = NavigatorSceneConfigs; module.exports = NavigatorSceneConfigs;

View File

@ -1,70 +0,0 @@
/**
* Copyright 2004-present Facebook. All Rights Reserved.
*
* @providesModule Portal
* @flow
*/
'use strict';
var React = require('React');
var StyleSheet = require('StyleSheet');
var View = require('View');
var _portalRef: any;
/*
* A container that renders all the modals on top of everything else in the application.
*
* Portal makes it possible for application code to pass modal views all the way up to
* the root element created in `renderApplication`.
*
* Never use `<Portal>` in your code. There is only one Portal instance rendered
* by the top-level `renderApplication`.
*/
var Portal = React.createClass({
statics: {
showModal: function(component) {
if (!_portalRef) {
console.error('Calling showModal but no Portal has been rendered');
return;
}
_portalRef.setState({modal: component});
},
closeModal: function() {
if (!_portalRef) {
console.error('Calling closeModal but no Portal has been rendered');
return;
}
_portalRef.setState({modal: null});
},
},
getInitialState: function() {
return {modal: (null: any)};
},
render: function() {
_portalRef = this;
if (!this.state.modal) {
return <View />;
}
return (
<View style={styles.modalsContainer}>
{this.state.modal}
</View>
);
}
});
var styles = StyleSheet.create({
modalsContainer: {
position: 'absolute',
left: 0,
top: 0,
right: 0,
bottom: 0,
},
});
module.exports = Portal;

View File

@ -11,10 +11,7 @@
*/ */
'use strict'; 'use strict';
var Portal = require('Portal');
var React = require('React'); var React = require('React');
var StyleSheet = require('StyleSheet');
var View = require('View');
var invariant = require('invariant'); var invariant = require('invariant');
@ -28,26 +25,11 @@ function renderApplication<D, P, S>(
'Expect to have a valid rootTag, instead got ', rootTag 'Expect to have a valid rootTag, instead got ', rootTag
); );
React.render( React.render(
<View style={styles.appContainer}>
<RootComponent <RootComponent
{...initialProps} {...initialProps}
/> />,
<Portal />
</View>,
rootTag rootTag
); );
} }
var styles = StyleSheet.create({
// This is needed so the application covers the whole screen
// and therefore the contents of the Portal are not clipped.
appContainer: {
position: 'absolute',
left: 0,
top: 0,
right: 0,
bottom: 0,
},
});
module.exports = renderApplication; module.exports = renderApplication;

View File

@ -20,12 +20,6 @@ var DEFAULT_BUTTON = {
}; };
/** /**
* AlertIOS manages native iOS alerts, option sheets, and share dialogs
*/
class AlertIOS {
/**
* Launches an alert dialog with the specified title and message. * Launches an alert dialog with the specified title and message.
* *
* Optionally provide a list of buttons. Tapping any button will fire the * Optionally provide a list of buttons. Tapping any button will fire the
@ -46,6 +40,8 @@ class AlertIOS {
* )} * )}
* ``` * ```
*/ */
class AlertIOS {
static alert( static alert(
title: ?string, title: ?string,
message?: ?string, message?: ?string,

View File

@ -41,7 +41,6 @@ var ReactNative = Object.assign(Object.create(require('React')), {
// APIs // APIs
AlertIOS: require('AlertIOS'), AlertIOS: require('AlertIOS'),
Animation: require('Animation'),
AppRegistry: require('AppRegistry'), AppRegistry: require('AppRegistry'),
AppStateIOS: require('AppStateIOS'), AppStateIOS: require('AppStateIOS'),
AsyncStorage: require('AsyncStorage'), AsyncStorage: require('AsyncStorage'),

View File

@ -44,9 +44,9 @@ Pod::Spec.new do |s|
ss.preserve_paths = "Libraries/AdSupport/*.js" ss.preserve_paths = "Libraries/AdSupport/*.js"
end end
s.subspec 'RCTAnimation' do |ss| s.subspec 'RCTAnimationExperimental' do |ss|
ss.dependency 'React/Core' ss.dependency 'React/Core'
ss.source_files = "Libraries/Animation/*.{h,m}" ss.source_files = "Libraries/Animation/RCTAnimationExperimental*.{h,m}"
ss.preserve_paths = "Libraries/Animation/*.js" ss.preserve_paths = "Libraries/Animation/*.js"
end end

1
cli.js
View File

@ -1,4 +1,3 @@
/** /**
* Copyright 2004-present Facebook. All Rights Reserved. * Copyright 2004-present Facebook. All Rights Reserved.
*/ */

View File

@ -1,4 +1,4 @@
Displaying images is a fascinating subject, React Native uses some cool tricks to make it a better experience. Displaying images is a fascinating subject; React Native uses some cool tricks to make it a better experience.
## No Automatic Sizing ## No Automatic Sizing

View File

@ -15,7 +15,7 @@ This is a more advanced guide that shows how to build a native module. It assume
## iOS Calendar module example ## iOS Calendar module example
This guide will use [iOS Calendar API](https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html) example. Let's say we would like to be able to access iOS calendar from JavaScript. This guide will use [iOS Calendar API](https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html) example. Let's say we would like to be able to access the iOS calendar from JavaScript.
Native module is just an Objectve-C class that implements `RCTBridgeModule` protocol. If you are wondering, RCT is a shorthand for ReaCT. Native module is just an Objectve-C class that implements `RCTBridgeModule` protocol. If you are wondering, RCT is a shorthand for ReaCT.
@ -52,7 +52,7 @@ CalendarManager.addEventWithName('Birthday Party', '4 Privet Drive, Surrey');
Notice that the exported method name was generated from first part of Objective-C selector. Sometimes it results in a non-idiomatic JavaScript name (like the one in our example). You can change the name by supplying an optional argument to `RCT_EXPORT`, e.g. `RCT_EXPORT(addEvent)`. Notice that the exported method name was generated from first part of Objective-C selector. Sometimes it results in a non-idiomatic JavaScript name (like the one in our example). You can change the name by supplying an optional argument to `RCT_EXPORT`, e.g. `RCT_EXPORT(addEvent)`.
The return type of the method should always be `void`. React Native bridge is asynchronous, so the only way to pass result to JavaScript is by using callbacks or emitting events (see below). The return type of the method should always be `void`. React Native bridge is asynchronous, so the only way to pass a result to JavaScript is by using callbacks or emitting events (see below).
## Argument types ## Argument types
@ -109,7 +109,7 @@ CalendarManager.addEvent('Birthday Party', {
> >
> This section is even more experimental than others, we don't have a set of best practices around callbacks yet. > This section is even more experimental than others, we don't have a set of best practices around callbacks yet.
Native module also supports a special kind of argument - callback. In most cases it is used to provide function call result to JavaScript. Native module also supports a special kind of argument- a callback. In most cases it is used to provide the function call result to JavaScript.
```objective-c ```objective-c
- (void)findEvents:(RCTResponseSenderBlock)callback - (void)findEvents:(RCTResponseSenderBlock)callback
@ -120,7 +120,7 @@ Native module also supports a special kind of argument - callback. In most cases
} }
``` ```
`RCTResponseSenderBlock` accepts only one argument - array of arguments to pass to JavaScript callback. In this case we use node's convention to set first argument to error and the rest - to the result of the function. `RCTResponseSenderBlock` accepts only one argument - an array of arguments to pass to the JavaScript callback. In this case we use node's convention to set first argument to error and the rest - to the result of the function.
```javascript ```javascript
CalendarManager.findEvents((error, events) => { CalendarManager.findEvents((error, events) => {
@ -132,7 +132,7 @@ CalendarManager.findEvents((error, events) => {
}) })
``` ```
Native module is supposed to invoke callback only once. It can, however, store the callback as an ivar and invoke it later. This pattern is often used to wrap iOS APIs that require delegate. See [`RCTAlertManager`](https://github.com/facebook/react-native/blob/master/React/Modules/RCTAlertManager.m). Native module is supposed to invoke its callback only once. It can, however, store the callback as an ivar and invoke it later. This pattern is often used to wrap iOS APIs that require delegate. See [`RCTAlertManager`](https://github.com/facebook/react-native/blob/master/React/Modules/RCTAlertManager.m).
If you want to pass error-like object to JavaScript, use `RCTMakeError` from [`RCTUtils.h`](https://github.com/facebook/react-native/blob/master/React/Base/RCTUtils.h). If you want to pass error-like object to JavaScript, use `RCTMakeError` from [`RCTUtils.h`](https://github.com/facebook/react-native/blob/master/React/Base/RCTUtils.h).

View File

@ -7,7 +7,7 @@ permalink: docs/network.html
next: timers next: timers
--- ---
One of React Native's goals is to be a playground where we can experiment with different architectures and crazy ideas. Since browsers are not flexible enough, we had no choice but to reimplement the entire stack. In the places that we did not intend to change, we tried to be as faithful as possible to the browser APIs. The networking stack is a great example. One of React Native's goals is to be a playground where we can experiment with different architectures and crazy ideas. Since browsers are not flexible enough, we had no choice but to reimplement the entire stack. In the places that we did not intend to change anything, we tried to be as faithful as possible to the browser APIs. The networking stack is a great example.
## XMLHttpRequest ## XMLHttpRequest

View File

@ -15,7 +15,7 @@ The React Native repo has several tests you can run to verify you haven't caused
[Jest](http://facebook.github.io/jest/) tests are JS-only tests run on the command line with node. The tests themselves live in the `__tests__` directories of the files they test, and there is a large emphasis on aggressively mocking out functionality that is not under test for failure isolation and maximum speed. You can run the existing React Native jest tests with `npm test` from the react-native root, and we encourage you to add your own tests for any components you want to contribute to. See [`getImageSource-test.js`](https://github.com/facebook/react-native/blob/master/Examples/Movies/__tests__/getImageSource-test.js) for a basic example. [Jest](http://facebook.github.io/jest/) tests are JS-only tests run on the command line with node. The tests themselves live in the `__tests__` directories of the files they test, and there is a large emphasis on aggressively mocking out functionality that is not under test for failure isolation and maximum speed. You can run the existing React Native jest tests with `npm test` from the react-native root, and we encourage you to add your own tests for any components you want to contribute to. See [`getImageSource-test.js`](https://github.com/facebook/react-native/blob/master/Examples/Movies/__tests__/getImageSource-test.js) for a basic example.
## Integration Tests. ## Integration Tests
React Native provides facilities to make it easier to test integrated components that require both native and JS components to communicate across the bridge. The two main components are `RCTTestRunner` and `RCTTestModule`. `RCTTestRunner` sets up the ReactNative environment and provides facilities to run the tests as `XCTestCase`s in Xcode (`runTest:module` is the simplest method). `RCTTestModule` is exported to JS via `NativeModules` as `TestModule`. The tests themselves are written in JS, and must call `TestModule.markTestCompleted()` when they are done, otherwise the test will timeout and fail. Test failures are primarily indicated by throwing an exception. It is also possible to test error conditions with `runTest:module:initialProps:expectErrorRegex:` or `runTest:module:initialProps:expectErrorBlock:` which will expect an error to be thrown and verify the error matches the provided criteria. See [`IntegrationTestHarnessTest.js`](https://github.com/facebook/react-native/blob/master/IntegrationTests/IntegrationTestHarnessTest.js) and [`IntegrationTestsTests.m`](https://github.com/facebook/react-native/blob/master/IntegrationTests/IntegrationTestsTests/IntegrationTestsTests.m) for example usage. React Native provides facilities to make it easier to test integrated components that require both native and JS components to communicate across the bridge. The two main components are `RCTTestRunner` and `RCTTestModule`. `RCTTestRunner` sets up the ReactNative environment and provides facilities to run the tests as `XCTestCase`s in Xcode (`runTest:module` is the simplest method). `RCTTestModule` is exported to JS via `NativeModules` as `TestModule`. The tests themselves are written in JS, and must call `TestModule.markTestCompleted()` when they are done, otherwise the test will timeout and fail. Test failures are primarily indicated by throwing an exception. It is also possible to test error conditions with `runTest:module:initialProps:expectErrorRegex:` or `runTest:module:initialProps:expectErrorBlock:` which will expect an error to be thrown and verify the error matches the provided criteria. See [`IntegrationTestHarnessTest.js`](https://github.com/facebook/react-native/blob/master/IntegrationTests/IntegrationTestHarnessTest.js) and [`IntegrationTestsTests.m`](https://github.com/facebook/react-native/blob/master/IntegrationTests/IntegrationTestsTests/IntegrationTestsTests.m) for example usage.

View File

@ -44,7 +44,7 @@ Edit `AppDelegate.m` to use a different port.
## Watchman took too long to load ## Watchman took too long to load
Permission settings prevent Watchman from loading. A recent update solves this, get a HEAD install of Watchman if you are experiening this error. Permission settings prevent Watchman from loading. A recent update solves this, get a HEAD install of Watchman if you are experiencing this error.
``` ```
brew uninstall watchman brew uninstall watchman

View File

@ -47,6 +47,10 @@ function init(root, projectName) {
spawn(path.resolve(__dirname, 'init.sh'), [projectName], {stdio:'inherit'}); spawn(path.resolve(__dirname, 'init.sh'), [projectName], {stdio:'inherit'});
} }
if (require.main === module) {
run();
}
module.exports = { module.exports = {
run: run, run: run,
init: init, init: init,

View File

@ -13,7 +13,7 @@ jest
.dontMock('path') .dontMock('path')
.dontMock('absolute-path') .dontMock('absolute-path')
.dontMock('../docblock') .dontMock('../docblock')
.dontMock('../../requirePattern') .dontMock('../../replacePatterns')
.setMock('../../../ModuleDescriptor', function(data) {return data;}); .setMock('../../../ModuleDescriptor', function(data) {return data;});
describe('DependencyGraph', function() { describe('DependencyGraph', function() {
@ -64,7 +64,7 @@ describe('DependencyGraph', function() {
}); });
}); });
pit('should get dependencies', function() { pit('should get dependencies with deprecated assets', function() {
var root = '/root'; var root = '/root';
fs.__setMockFilesystem({ fs.__setMockFilesystem({
'root': { 'root': {
@ -83,7 +83,7 @@ describe('DependencyGraph', function() {
var dgraph = new DependencyGraph({ var dgraph = new DependencyGraph({
roots: [root], roots: [root],
fileWatcher: fileWatcher, fileWatcher: fileWatcher,
assetRoots: ['/root/imgs'] assetRoots_DEPRECATED: ['/root/imgs'],
}); });
return dgraph.load().then(function() { return dgraph.load().then(function() {
expect(dgraph.getOrderedDependencies('/root/index.js')) expect(dgraph.getOrderedDependencies('/root/index.js'))
@ -98,6 +98,97 @@ describe('DependencyGraph', function() {
}); });
}); });
pit('should get dependencies with relative assets', function() {
var root = '/root';
fs.__setMockFilesystem({
'root': {
'index.js': [
'/**',
' * @providesModule index',
' */',
'require("./imgs/a.png")'
].join('\n'),
'imgs': {
'a.png': ''
},
'package.json': JSON.stringify({
name: 'rootPackage'
}),
}
});
var dgraph = new DependencyGraph({
roots: [root],
fileWatcher: fileWatcher,
});
return dgraph.load().then(function() {
expect(dgraph.getOrderedDependencies('/root/index.js'))
.toEqual([
{
id: 'index',
altId: 'rootPackage/index',
path: '/root/index.js',
dependencies: ['./imgs/a.png']
},
{ id: 'rootPackage/imgs/a.png',
path: '/root/imgs/a.png',
dependencies: [],
isAsset: true
},
]);
});
});
pit('Deprecated and relative assets can live together', function() {
var root = '/root';
fs.__setMockFilesystem({
'root': {
'index.js': [
'/**',
' * @providesModule index',
' */',
'require("./imgs/a.png")',
'require("image!a")',
].join('\n'),
'imgs': {
'a.png': ''
},
'package.json': JSON.stringify({
name: 'rootPackage'
}),
}
});
var dgraph = new DependencyGraph({
roots: [root],
fileWatcher: fileWatcher,
assetRoots_DEPRECATED: ['/root/imgs'],
});
return dgraph.load().then(function() {
expect(dgraph.getOrderedDependencies('/root/index.js'))
.toEqual([
{
id: 'index',
altId: 'rootPackage/index',
path: '/root/index.js',
dependencies: ['./imgs/a.png', 'image!a']
},
{
id: 'rootPackage/imgs/a.png',
path: '/root/imgs/a.png',
dependencies: [],
isAsset: true
},
{
id: 'image!a',
path: '/root/imgs/a.png',
dependencies: [],
isAsset: true
},
]);
});
});
pit('should get recursive dependencies', function() { pit('should get recursive dependencies', function() {
var root = '/root'; var root = '/root';
fs.__setMockFilesystem({ fs.__setMockFilesystem({
@ -821,7 +912,7 @@ describe('DependencyGraph', function() {
}); });
}); });
pit('updates module dependencies on asset add', function() { pit('updates module dependencies on deprecated asset add', function() {
var root = '/root'; var root = '/root';
var filesystem = fs.__setMockFilesystem({ var filesystem = fs.__setMockFilesystem({
'root': { 'root': {
@ -836,7 +927,7 @@ describe('DependencyGraph', function() {
var dgraph = new DependencyGraph({ var dgraph = new DependencyGraph({
roots: [root], roots: [root],
assetRoots: [root], assetRoots_DEPRECATED: [root],
assetExts: ['png'], assetExts: ['png'],
fileWatcher: fileWatcher fileWatcher: fileWatcher
}); });
@ -870,6 +961,57 @@ describe('DependencyGraph', function() {
}); });
}); });
pit('updates module dependencies on relative asset add', function() {
var root = '/root';
var filesystem = fs.__setMockFilesystem({
'root': {
'index.js': [
'/**',
' * @providesModule index',
' */',
'require("./foo.png")'
].join('\n'),
'package.json': JSON.stringify({
name: 'aPackage'
}),
},
});
var dgraph = new DependencyGraph({
roots: [root],
assetExts: ['png'],
fileWatcher: fileWatcher
});
return dgraph.load().then(function() {
expect(dgraph.getOrderedDependencies('/root/index.js'))
.toEqual([
{ id: 'index', altId: 'aPackage/index',
path: '/root/index.js',
dependencies: ['./foo.png']
}
]);
filesystem.root['foo.png'] = '';
triggerFileChange('add', 'foo.png', root);
return dgraph.load().then(function() {
expect(dgraph.getOrderedDependencies('/root/index.js'))
.toEqual([
{ id: 'index', altId: 'aPackage/index',
path: '/root/index.js',
dependencies: ['./foo.png']
},
{ id: 'aPackage/foo.png',
path: '/root/foo.png',
dependencies: [],
isAsset: true,
},
]);
});
});
});
pit('runs changes through ignore filter', function() { pit('runs changes through ignore filter', function() {
var root = '/root'; var root = '/root';
var filesystem = fs.__setMockFilesystem({ var filesystem = fs.__setMockFilesystem({

View File

@ -12,7 +12,7 @@ var ModuleDescriptor = require('../../ModuleDescriptor');
var Promise = require('bluebird'); var Promise = require('bluebird');
var fs = require('fs'); var fs = require('fs');
var docblock = require('./docblock'); var docblock = require('./docblock');
var requirePattern = require('../requirePattern'); var replacePatterns = require('../replacePatterns');
var path = require('path'); var path = require('path');
var isAbsolutePath = require('absolute-path'); var isAbsolutePath = require('absolute-path');
var debug = require('debug')('DependecyGraph'); var debug = require('debug')('DependecyGraph');
@ -37,7 +37,7 @@ var validateOpts = declareOpts({
type: 'object', type: 'object',
required: true, required: true,
}, },
assetRoots: { assetRoots_DEPRECATED: {
type: 'array', type: 'array',
default: [], default: [],
}, },
@ -51,7 +51,7 @@ function DependecyGraph(options) {
var opts = validateOpts(options); var opts = validateOpts(options);
this._roots = opts.roots; this._roots = opts.roots;
this._assetRoots = opts.assetRoots; this._assetRoots_DEPRECATED = opts.assetRoots_DEPRECATED;
this._assetExts = opts.assetExts; this._assetExts = opts.assetExts;
this._ignoreFilePath = opts.ignoreFilePath; this._ignoreFilePath = opts.ignoreFilePath;
this._fileWatcher = options.fileWatcher; this._fileWatcher = options.fileWatcher;
@ -64,6 +64,10 @@ function DependecyGraph(options) {
this._moduleById = Object.create(null); this._moduleById = Object.create(null);
this._debugUpdateEvents = []; this._debugUpdateEvents = [];
this._moduleExtPattern = new RegExp(
'.' + ['js'].concat(this._assetExts).join('|') + '$'
);
// Kick off the search process to precompute the dependency graph. // Kick off the search process to precompute the dependency graph.
this._init(); this._init();
} }
@ -75,7 +79,7 @@ DependecyGraph.prototype.load = function() {
this._loading = Promise.all([ this._loading = Promise.all([
this._search(), this._search(),
this._buildAssetMap(), this._buildAssetMap_DEPRECATED(),
]); ]);
return this._loading; return this._loading;
@ -147,15 +151,15 @@ DependecyGraph.prototype.resolveDependency = function(
fromModule, fromModule,
depModuleId depModuleId
) { ) {
if (this._assetMap != null) { if (this._assetMap_DEPRECATED != null) {
// Process asset requires.
var assetMatch = depModuleId.match(/^image!(.+)/); var assetMatch = depModuleId.match(/^image!(.+)/);
// Process DEPRECATED global asset requires.
if (assetMatch && assetMatch[1]) { if (assetMatch && assetMatch[1]) {
if (!this._assetMap[assetMatch[1]]) { if (!this._assetMap_DEPRECATED[assetMatch[1]]) {
debug('WARINING: Cannot find asset:', assetMatch[1]); debug('WARINING: Cannot find asset:', assetMatch[1]);
return null; return null;
} }
return this._assetMap[assetMatch[1]]; return this._assetMap_DEPRECATED[assetMatch[1]];
} }
} }
@ -218,7 +222,11 @@ DependecyGraph.prototype.resolveDependency = function(
// fromModule.path: /x/y/z // fromModule.path: /x/y/z
// modulePath: /x/y/a/b // modulePath: /x/y/a/b
var dir = path.dirname(fromModule.path); var dir = path.dirname(fromModule.path);
modulePath = withExtJs(path.join(dir, depModuleId)); modulePath = path.join(dir, depModuleId);
if (this._assetExts.indexOf(extname(modulePath)) === -1) {
modulePath = withExtJs(modulePath);
}
dep = this._graph[modulePath]; dep = this._graph[modulePath];
@ -287,7 +295,7 @@ DependecyGraph.prototype._search = function() {
return false; return false;
} }
return filePath.match(/\.js$/); return filePath.match(self._moduleExtPattern);
}); });
var processing = self._findAndProcessPackage(files, dir) var processing = self._findAndProcessPackage(files, dir)
@ -370,11 +378,21 @@ DependecyGraph.prototype._removePackageFromIndices = function(packageJson) {
* Parse a module and update indices. * Parse a module and update indices.
*/ */
DependecyGraph.prototype._processModule = function(modulePath) { DependecyGraph.prototype._processModule = function(modulePath) {
var moduleData = { path: path.resolve(modulePath) };
var module;
if (this._assetExts.indexOf(extname(modulePath)) > -1) {
moduleData.id = this._lookupName(modulePath);
moduleData.isAsset = true;
moduleData.dependencies = [];
module = Promise.resolve(new ModuleDescriptor(moduleData));
this._updateGraphWithModule(module);
}
var self = this; var self = this;
return readFile(modulePath, 'utf8') return readFile(modulePath, 'utf8')
.then(function(content) { .then(function(content) {
var moduleDocBlock = docblock.parseAsObject(content); var moduleDocBlock = docblock.parseAsObject(content);
var moduleData = { path: path.resolve(modulePath) };
if (moduleDocBlock.providesModule || moduleDocBlock.provides) { if (moduleDocBlock.providesModule || moduleDocBlock.provides) {
moduleData.id = moduleData.id =
moduleDocBlock.providesModule || moduleDocBlock.provides; moduleDocBlock.providesModule || moduleDocBlock.provides;
@ -387,7 +405,7 @@ DependecyGraph.prototype._processModule = function(modulePath) {
} }
moduleData.dependencies = extractRequires(content); moduleData.dependencies = extractRequires(content);
var module = new ModuleDescriptor(moduleData); module = new ModuleDescriptor(moduleData);
self._updateGraphWithModule(module); self._updateGraphWithModule(module);
return module; return module;
}); });
@ -497,8 +515,8 @@ DependecyGraph.prototype._processFileChange = function(
this._debugUpdateEvents.push({event: eventType, path: filePath}); this._debugUpdateEvents.push({event: eventType, path: filePath});
if (this._assetExts.indexOf(extname(filePath)) > -1) { if (this._assetExts.indexOf(extname(filePath)) > -1) {
this._processAssetChange(eventType, absPath); this._processAssetChange_DEPRECATED(eventType, absPath);
return; // Fall through because new-style assets are actually modules.
} }
var isPackage = path.basename(filePath) === 'package.json'; var isPackage = path.basename(filePath) === 'package.json';
@ -554,27 +572,28 @@ DependecyGraph.prototype._getAbsolutePath = function(filePath) {
return null; return null;
}; };
DependecyGraph.prototype._buildAssetMap = function() { DependecyGraph.prototype._buildAssetMap_DEPRECATED = function() {
if (this._assetRoots == null || this._assetRoots.length === 0) { if (this._assetRoots_DEPRECATED == null ||
this._assetRoots_DEPRECATED.length === 0) {
return Promise.resolve(); return Promise.resolve();
} }
this._assetMap = Object.create(null); this._assetMap_DEPRECATED = Object.create(null);
return buildAssetMap( return buildAssetMap_DEPRECATED(
this._assetRoots, this._assetRoots_DEPRECATED,
this._processAsset.bind(this) this._processAsset_DEPRECATED.bind(this)
); );
}; };
DependecyGraph.prototype._processAsset = function(file) { DependecyGraph.prototype._processAsset_DEPRECATED = function(file) {
var ext = extname(file); var ext = extname(file);
if (this._assetExts.indexOf(ext) !== -1) { if (this._assetExts.indexOf(ext) !== -1) {
var name = assetName(file, ext); var name = assetName(file, ext);
if (this._assetMap[name] != null) { if (this._assetMap_DEPRECATED[name] != null) {
debug('Conflcting assets', name); debug('Conflcting assets', name);
} }
this._assetMap[name] = new ModuleDescriptor({ this._assetMap_DEPRECATED[name] = new ModuleDescriptor({
id: 'image!' + name, id: 'image!' + name,
path: path.resolve(file), path: path.resolve(file),
isAsset: true, isAsset: true,
@ -583,18 +602,18 @@ DependecyGraph.prototype._processAsset = function(file) {
} }
}; };
DependecyGraph.prototype._processAssetChange = function(eventType, file) { DependecyGraph.prototype._processAssetChange_DEPRECATED = function(eventType, file) {
if (this._assetMap == null) { if (this._assetMap_DEPRECATED == null) {
return; return;
} }
var name = assetName(file, extname(file)); var name = assetName(file, extname(file));
if (eventType === 'change' || eventType === 'delete') { if (eventType === 'change' || eventType === 'delete') {
delete this._assetMap[name]; delete this._assetMap_DEPRECATED[name];
} }
if (eventType === 'change' || eventType === 'add') { if (eventType === 'change' || eventType === 'add') {
this._processAsset(file); this._processAsset_DEPRECATED(file);
} }
}; };
@ -609,7 +628,11 @@ function extractRequires(code) {
code code
.replace(blockCommentRe, '') .replace(blockCommentRe, '')
.replace(lineCommentRe, '') .replace(lineCommentRe, '')
.replace(requirePattern, function(match, _, dep) { .replace(replacePatterns.IMPORT_RE, function(match, pre, quot, dep, post) {
deps.push(dep);
return match;
})
.replace(replacePatterns.REQUIRE_RE, function(match, pre, quot, dep, post) {
deps.push(dep); deps.push(dep);
}); });
@ -669,7 +692,7 @@ function readAndStatDir(dir) {
* Given a list of roots and list of extensions find all the files in * Given a list of roots and list of extensions find all the files in
* the directory with that extension and build a map of those assets. * the directory with that extension and build a map of those assets.
*/ */
function buildAssetMap(roots, processAsset) { function buildAssetMap_DEPRECATED(roots, processAsset) {
var queue = roots.slice(0); var queue = roots.slice(0);
function search() { function search() {

View File

@ -10,7 +10,7 @@
jest.dontMock('../') jest.dontMock('../')
.dontMock('q') .dontMock('q')
.dontMock('../requirePattern') .dontMock('../replacePatterns')
.setMock('../../ModuleDescriptor', function(data) {return data;}); .setMock('../../ModuleDescriptor', function(data) {return data;});
var Promise = require('bluebird'); var Promise = require('bluebird');
@ -228,13 +228,148 @@ describe('HasteDependencyResolver', function() {
var depGraph = depResolver._depGraph; var depGraph = depResolver._depGraph;
var dependencies = ['x', 'y', 'z', 'a', 'b']; var dependencies = ['x', 'y', 'z', 'a', 'b'];
/*eslint-disable */
var code = [ var code = [
"import'x';",
"import 'x';",
"import 'x' ;",
"import Default from 'x';",
"import * as All from 'x';",
"import {} from 'x';",
"import { } from 'x';",
"import {Foo} from 'x';",
"import { Foo } from 'x';",
"import { Foo, } from 'x';",
"import {Foo as Bar} from 'x';",
"import { Foo as Bar } from 'x';",
"import { Foo as Bar, } from 'x';",
"import { Foo, Bar } from 'x';",
"import { Foo, Bar, } from 'x';",
"import { Foo as Bar, Baz } from 'x';",
"import { Foo as Bar, Baz, } from 'x';",
"import { Foo, Bar as Baz } from 'x';",
"import { Foo, Bar as Baz, } from 'x';",
"import { Foo as Bar, Baz as Qux } from 'x';",
"import { Foo as Bar, Baz as Qux, } from 'x';",
"import { Foo, Bar, Baz } from 'x';",
"import { Foo, Bar, Baz, } from 'x';",
"import { Foo as Bar, Baz, Qux } from 'x';",
"import { Foo as Bar, Baz, Qux, } from 'x';",
"import { Foo, Bar as Baz, Qux } from 'x';",
"import { Foo, Bar as Baz, Qux, } from 'x';",
"import { Foo, Bar, Baz as Qux } from 'x';",
"import { Foo, Bar, Baz as Qux, } from 'x';",
"import { Foo as Bar, Baz as Qux, Norf } from 'x';",
"import { Foo as Bar, Baz as Qux, Norf, } from 'x';",
"import { Foo as Bar, Baz, Qux as Norf } from 'x';",
"import { Foo as Bar, Baz, Qux as Norf, } from 'x';",
"import { Foo, Bar as Baz, Qux as Norf } from 'x';",
"import { Foo, Bar as Baz, Qux as Norf, } from 'x';",
"import { Foo as Bar, Baz as Qux, Norf as Enuf } from 'x';",
"import { Foo as Bar, Baz as Qux, Norf as Enuf, } from 'x';",
"import Default, * as All from 'x';",
"import Default, { } from 'x';",
"import Default, { Foo } from 'x';",
"import Default, { Foo, } from 'x';",
"import Default, { Foo as Bar } from 'x';",
"import Default, { Foo as Bar, } from 'x';",
"import Default, { Foo, Bar } from 'x';",
"import Default, { Foo, Bar, } from 'x';",
"import Default, { Foo as Bar, Baz } from 'x';",
"import Default, { Foo as Bar, Baz, } from 'x';",
"import Default, { Foo, Bar as Baz } from 'x';",
"import Default, { Foo, Bar as Baz, } from 'x';",
"import Default, { Foo as Bar, Baz as Qux } from 'x';",
"import Default, { Foo as Bar, Baz as Qux, } from 'x';",
"import Default, { Foo, Bar, Baz } from 'x';",
"import Default, { Foo, Bar, Baz, } from 'x';",
"import Default, { Foo as Bar, Baz, Qux } from 'x';",
"import Default, { Foo as Bar, Baz, Qux, } from 'x';",
"import Default, { Foo, Bar as Baz, Qux } from 'x';",
"import Default, { Foo, Bar as Baz, Qux, } from 'x';",
"import Default, { Foo, Bar, Baz as Qux } from 'x';",
"import Default, { Foo, Bar, Baz as Qux, } from 'x';",
"import Default, { Foo as Bar, Baz as Qux, Norf } from 'x';",
"import Default, { Foo as Bar, Baz as Qux, Norf, } from 'x';",
"import Default, { Foo as Bar, Baz, Qux as Norf } from 'x';",
"import Default, { Foo as Bar, Baz, Qux as Norf, } from 'x';",
"import Default, { Foo, Bar as Baz, Qux as Norf } from 'x';",
"import Default, { Foo, Bar as Baz, Qux as Norf, } from 'x';",
"import Default, { Foo as Bar, Baz as Qux, Norf as NoMore } from 'x';",
"import Default, { Foo as Bar, Baz as Qux, Norf as NoMore, } from 'x';",
"import Default , { } from 'x';",
'import "x";',
'import Default from "x";',
'import * as All from "x";',
'import { } from "x";',
'import { Foo } from "x";',
'import { Foo, } from "x";',
'import { Foo as Bar } from "x";',
'import { Foo as Bar, } from "x";',
'import { Foo, Bar } from "x";',
'import { Foo, Bar, } from "x";',
'import { Foo as Bar, Baz } from "x";',
'import { Foo as Bar, Baz, } from "x";',
'import { Foo, Bar as Baz } from "x";',
'import { Foo, Bar as Baz, } from "x";',
'import { Foo as Bar, Baz as Qux } from "x";',
'import { Foo as Bar, Baz as Qux, } from "x";',
'import { Foo, Bar, Baz } from "x";',
'import { Foo, Bar, Baz, } from "x";',
'import { Foo as Bar, Baz, Qux } from "x";',
'import { Foo as Bar, Baz, Qux, } from "x";',
'import { Foo, Bar as Baz, Qux } from "x";',
'import { Foo, Bar as Baz, Qux, } from "x";',
'import { Foo, Bar, Baz as Qux } from "x";',
'import { Foo, Bar, Baz as Qux, } from "x";',
'import { Foo as Bar, Baz as Qux, Norf } from "x";',
'import { Foo as Bar, Baz as Qux, Norf, } from "x";',
'import { Foo as Bar, Baz, Qux as Norf } from "x";',
'import { Foo as Bar, Baz, Qux as Norf, } from "x";',
'import { Foo, Bar as Baz, Qux as Norf } from "x";',
'import { Foo, Bar as Baz, Qux as Norf, } from "x";',
'import { Foo as Bar, Baz as Qux, Norf as NoMore } from "x";',
'import { Foo as Bar, Baz as Qux, Norf as NoMore, } from "x";',
'import Default, * as All from "x";',
'import Default, { } from "x";',
'import Default, { Foo } from "x";',
'import Default, { Foo, } from "x";',
'import Default, { Foo as Bar } from "x";',
'import Default, { Foo as Bar, } from "x";',
'import Default, { Foo, Bar } from "x";',
'import Default, { Foo, Bar, } from "x";',
'import Default, { Foo as Bar, Baz } from "x";',
'import Default, { Foo as Bar, Baz, } from "x";',
'import Default, { Foo, Bar as Baz } from "x";',
'import Default, { Foo, Bar as Baz, } from "x";',
'import Default, { Foo as Bar, Baz as Qux } from "x";',
'import Default, { Foo as Bar, Baz as Qux, } from "x";',
'import Default, { Foo, Bar, Baz } from "x";',
'import Default, { Foo, Bar, Baz, } from "x";',
'import Default, { Foo as Bar, Baz, Qux } from "x";',
'import Default, { Foo as Bar, Baz, Qux, } from "x";',
'import Default, { Foo, Bar as Baz, Qux } from "x";',
'import Default, { Foo, Bar as Baz, Qux, } from "x";',
'import Default, { Foo, Bar, Baz as Qux } from "x";',
'import Default, { Foo, Bar, Baz as Qux, } from "x";',
'import Default, { Foo as Bar, Baz as Qux, Norf } from "x";',
'import Default, { Foo as Bar, Baz as Qux, Norf, } from "x";',
'import Default, { Foo as Bar, Baz, Qux as Norf } from "x";',
'import Default, { Foo as Bar, Baz, Qux as Norf, } from "x";',
'import Default, { Foo, Bar as Baz, Qux as Norf } from "x";',
'import Default, { Foo, Bar as Baz, Qux as Norf, } from "x";',
'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf } from "x";',
'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf, } from "x";',
'import Default from "y";',
'import * as All from \'z\';',
'require("x")', 'require("x")',
'require("y")', 'require("y")',
'require( "z" )', 'require( \'z\' )',
'require( "a")', 'require( "a")',
'require("b" )', 'require("b" )',
].join('\n'); ].join('\n');
/*eslint-disable */
depGraph.resolveDependency.mockImpl(function(fromModule, toModuleName) { depGraph.resolveDependency.mockImpl(function(fromModule, toModuleName) {
if (toModuleName === 'x') { if (toModuleName === 'x') {
@ -242,7 +377,7 @@ describe('HasteDependencyResolver', function() {
id: 'changed' id: 'changed'
}; };
} else if (toModuleName === 'y') { } else if (toModuleName === 'y') {
return { id: 'y' }; return { id: 'Y' };
} }
return null; return null;
}); });
@ -254,13 +389,145 @@ describe('HasteDependencyResolver', function() {
}, code); }, code);
expect(processedCode).toEqual([ expect(processedCode).toEqual([
'__d(\'test module\',["changed","y"],function(global,' + '__d(\'test module\',["changed","Y"],function(global,' +
' require, requireDynamic, requireLazy, module, exports) {' + ' require, requireDynamic, requireLazy, module, exports) { ' +
' require(\'changed\')', "import'x';",
'require(\'y\')', "import 'changed';",
'require("z")', "import 'changed' ;",
'require("a")', "import Default from 'changed';",
'require("b")});', "import * as All from 'changed';",
"import {} from 'changed';",
"import { } from 'changed';",
"import {Foo} from 'changed';",
"import { Foo } from 'changed';",
"import { Foo, } from 'changed';",
"import {Foo as Bar} from 'changed';",
"import { Foo as Bar } from 'changed';",
"import { Foo as Bar, } from 'changed';",
"import { Foo, Bar } from 'changed';",
"import { Foo, Bar, } from 'changed';",
"import { Foo as Bar, Baz } from 'changed';",
"import { Foo as Bar, Baz, } from 'changed';",
"import { Foo, Bar as Baz } from 'changed';",
"import { Foo, Bar as Baz, } from 'changed';",
"import { Foo as Bar, Baz as Qux } from 'changed';",
"import { Foo as Bar, Baz as Qux, } from 'changed';",
"import { Foo, Bar, Baz } from 'changed';",
"import { Foo, Bar, Baz, } from 'changed';",
"import { Foo as Bar, Baz, Qux } from 'changed';",
"import { Foo as Bar, Baz, Qux, } from 'changed';",
"import { Foo, Bar as Baz, Qux } from 'changed';",
"import { Foo, Bar as Baz, Qux, } from 'changed';",
"import { Foo, Bar, Baz as Qux } from 'changed';",
"import { Foo, Bar, Baz as Qux, } from 'changed';",
"import { Foo as Bar, Baz as Qux, Norf } from 'changed';",
"import { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
"import { Foo as Bar, Baz, Qux as Norf } from 'changed';",
"import { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
"import { Foo, Bar as Baz, Qux as Norf } from 'changed';",
"import { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
"import { Foo as Bar, Baz as Qux, Norf as Enuf } from 'changed';",
"import { Foo as Bar, Baz as Qux, Norf as Enuf, } from 'changed';",
"import Default, * as All from 'changed';",
"import Default, { } from 'changed';",
"import Default, { Foo } from 'changed';",
"import Default, { Foo, } from 'changed';",
"import Default, { Foo as Bar } from 'changed';",
"import Default, { Foo as Bar, } from 'changed';",
"import Default, { Foo, Bar } from 'changed';",
"import Default, { Foo, Bar, } from 'changed';",
"import Default, { Foo as Bar, Baz } from 'changed';",
"import Default, { Foo as Bar, Baz, } from 'changed';",
"import Default, { Foo, Bar as Baz } from 'changed';",
"import Default, { Foo, Bar as Baz, } from 'changed';",
"import Default, { Foo as Bar, Baz as Qux } from 'changed';",
"import Default, { Foo as Bar, Baz as Qux, } from 'changed';",
"import Default, { Foo, Bar, Baz } from 'changed';",
"import Default, { Foo, Bar, Baz, } from 'changed';",
"import Default, { Foo as Bar, Baz, Qux } from 'changed';",
"import Default, { Foo as Bar, Baz, Qux, } from 'changed';",
"import Default, { Foo, Bar as Baz, Qux } from 'changed';",
"import Default, { Foo, Bar as Baz, Qux, } from 'changed';",
"import Default, { Foo, Bar, Baz as Qux } from 'changed';",
"import Default, { Foo, Bar, Baz as Qux, } from 'changed';",
"import Default, { Foo as Bar, Baz as Qux, Norf } from 'changed';",
"import Default, { Foo as Bar, Baz as Qux, Norf, } from 'changed';",
"import Default, { Foo as Bar, Baz, Qux as Norf } from 'changed';",
"import Default, { Foo as Bar, Baz, Qux as Norf, } from 'changed';",
"import Default, { Foo, Bar as Baz, Qux as Norf } from 'changed';",
"import Default, { Foo, Bar as Baz, Qux as Norf, } from 'changed';",
"import Default, { Foo as Bar, Baz as Qux, Norf as NoMore } from 'changed';",
"import Default, { Foo as Bar, Baz as Qux, Norf as NoMore, } from 'changed';",
"import Default , { } from 'changed';",
'import "changed";',
'import Default from "changed";',
'import * as All from "changed";',
'import { } from "changed";',
'import { Foo } from "changed";',
'import { Foo, } from "changed";',
'import { Foo as Bar } from "changed";',
'import { Foo as Bar, } from "changed";',
'import { Foo, Bar } from "changed";',
'import { Foo, Bar, } from "changed";',
'import { Foo as Bar, Baz } from "changed";',
'import { Foo as Bar, Baz, } from "changed";',
'import { Foo, Bar as Baz } from "changed";',
'import { Foo, Bar as Baz, } from "changed";',
'import { Foo as Bar, Baz as Qux } from "changed";',
'import { Foo as Bar, Baz as Qux, } from "changed";',
'import { Foo, Bar, Baz } from "changed";',
'import { Foo, Bar, Baz, } from "changed";',
'import { Foo as Bar, Baz, Qux } from "changed";',
'import { Foo as Bar, Baz, Qux, } from "changed";',
'import { Foo, Bar as Baz, Qux } from "changed";',
'import { Foo, Bar as Baz, Qux, } from "changed";',
'import { Foo, Bar, Baz as Qux } from "changed";',
'import { Foo, Bar, Baz as Qux, } from "changed";',
'import { Foo as Bar, Baz as Qux, Norf } from "changed";',
'import { Foo as Bar, Baz as Qux, Norf, } from "changed";',
'import { Foo as Bar, Baz, Qux as Norf } from "changed";',
'import { Foo as Bar, Baz, Qux as Norf, } from "changed";',
'import { Foo, Bar as Baz, Qux as Norf } from "changed";',
'import { Foo, Bar as Baz, Qux as Norf, } from "changed";',
'import { Foo as Bar, Baz as Qux, Norf as NoMore } from "changed";',
'import { Foo as Bar, Baz as Qux, Norf as NoMore, } from "changed";',
'import Default, * as All from "changed";',
'import Default, { } from "changed";',
'import Default, { Foo } from "changed";',
'import Default, { Foo, } from "changed";',
'import Default, { Foo as Bar } from "changed";',
'import Default, { Foo as Bar, } from "changed";',
'import Default, { Foo, Bar } from "changed";',
'import Default, { Foo, Bar, } from "changed";',
'import Default, { Foo as Bar, Baz } from "changed";',
'import Default, { Foo as Bar, Baz, } from "changed";',
'import Default, { Foo, Bar as Baz } from "changed";',
'import Default, { Foo, Bar as Baz, } from "changed";',
'import Default, { Foo as Bar, Baz as Qux } from "changed";',
'import Default, { Foo as Bar, Baz as Qux, } from "changed";',
'import Default, { Foo, Bar, Baz } from "changed";',
'import Default, { Foo, Bar, Baz, } from "changed";',
'import Default, { Foo as Bar, Baz, Qux } from "changed";',
'import Default, { Foo as Bar, Baz, Qux, } from "changed";',
'import Default, { Foo, Bar as Baz, Qux } from "changed";',
'import Default, { Foo, Bar as Baz, Qux, } from "changed";',
'import Default, { Foo, Bar, Baz as Qux } from "changed";',
'import Default, { Foo, Bar, Baz as Qux, } from "changed";',
'import Default, { Foo as Bar, Baz as Qux, Norf } from "changed";',
'import Default, { Foo as Bar, Baz as Qux, Norf, } from "changed";',
'import Default, { Foo as Bar, Baz, Qux as Norf } from "changed";',
'import Default, { Foo as Bar, Baz, Qux as Norf, } from "changed";',
'import Default, { Foo, Bar as Baz, Qux as Norf } from "changed";',
'import Default, { Foo, Bar as Baz, Qux as Norf, } from "changed";',
'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf } from "changed";',
'import Default, { Foo as Bar, Baz as Qux, Norf as Enuf, } from "changed";',
'import Default from "Y";',
'import * as All from \'z\';',
'require("changed")',
'require("Y")',
'require( \'z\' )',
'require( "a")',
'require("b" )});',
].join('\n')); ].join('\n'));
}); });
}); });

View File

@ -10,7 +10,7 @@
var path = require('path'); var path = require('path');
var DependencyGraph = require('./DependencyGraph'); var DependencyGraph = require('./DependencyGraph');
var requirePattern = require('./requirePattern'); var replacePatterns = require('./replacePatterns');
var ModuleDescriptor = require('../ModuleDescriptor'); var ModuleDescriptor = require('../ModuleDescriptor');
var declareOpts = require('../../lib/declareOpts'); var declareOpts = require('../../lib/declareOpts');
@ -61,7 +61,7 @@ function HasteDependencyResolver(options) {
this._depGraph = new DependencyGraph({ this._depGraph = new DependencyGraph({
roots: opts.projectRoots, roots: opts.projectRoots,
assetRoots: opts.assetRoots, assetRoots_DEPRECATED: opts.assetRoots,
ignoreFilePath: function(filepath) { ignoreFilePath: function(filepath) {
return filepath.indexOf('__tests__') !== -1 || return filepath.indexOf('__tests__') !== -1 ||
(opts.blacklistRE && opts.blacklistRE.test(filepath)); (opts.blacklistRE && opts.blacklistRE.test(filepath));
@ -144,20 +144,20 @@ HasteDependencyResolver.prototype.wrapModule = function(module, code) {
} }
} }
var relativizedCode = var relativizeCode = function(codeMatch, pre, quot, depName, post) {
code.replace(requirePattern, function(codeMatch, _, depName) {
var depId = resolvedDeps[depName]; var depId = resolvedDeps[depName];
if (depId != null) { if (depId) {
return 'require(\'' + depId + '\')'; return pre + quot + depId + post;
} else { } else {
return codeMatch.replace(/\s+/g, ''); return codeMatch;
} }
}); };
return DEFINE_MODULE_CODE.replace(DEFINE_MODULE_REPLACE_RE, function(key) { return DEFINE_MODULE_CODE.replace(DEFINE_MODULE_REPLACE_RE, function(key) {
return { return {
'_moduleName_': module.id, '_moduleName_': module.id,
'_code_': relativizedCode, '_code_': code.replace(replacePatterns.IMPORT_RE, relativizeCode)
.replace(replacePatterns.REQUIRE_RE, relativizeCode),
'_deps_': JSON.stringify(resolvedDepsArr), '_deps_': JSON.stringify(resolvedDepsArr),
}[key]; }[key];
}); });

View File

@ -9,6 +9,5 @@
'use strict'; 'use strict';
var REQUIRE_RE = /\brequire\s*?\(\s*?([\'"])([^"\']+)\1\s*?\)/g; exports.IMPORT_RE = /(\bimport\s+?(?:.+\s+?from\s+?)?)(['"])([^'"]+)(\2)/g;
exports.REQUIRE_RE = /(\brequire\s*?\(\s*?)(['"])([^'"]+)(\2\s*?\))/g;
module.exports = REQUIRE_RE;

View File

@ -61,9 +61,7 @@ function Transformer(options) {
projectRoots: options.projectRoots, projectRoots: options.projectRoots,
}); });
if (options.transformModulePath == null) { if (options.transformModulePath != null) {
this._failedToStart = Promise.reject(new Error('No transfrom module'));
} else {
this._workers = workerFarm( this._workers = workerFarm(
{autoStart: true, maxConcurrentCallsPerWorker: 1}, {autoStart: true, maxConcurrentCallsPerWorker: 1},
options.transformModulePath options.transformModulePath
@ -83,8 +81,8 @@ Transformer.prototype.invalidateFile = function(filePath) {
}; };
Transformer.prototype.loadFileAndTransform = function(filePath) { Transformer.prototype.loadFileAndTransform = function(filePath) {
if (this._failedToStart) { if (this._transform == null) {
return this._failedToStart; return Promise.reject(new Error('No transfrom module'));
} }
var transform = this._transform; var transform = this._transform;

View File

@ -240,7 +240,9 @@ var APIDoc = React.createClass({
render: function() { render: function() {
var content = this.props.content; var content = this.props.content;
if (!content.methods) { if (!content.methods) {
return <div>Error</div>; throw new Error(
'No component methods found for ' + content.componentName
);
} }
return ( return (
<div> <div>

View File

@ -127,7 +127,6 @@ var components = [
var apis = [ var apis = [
'../Libraries/Utilities/AlertIOS.js', '../Libraries/Utilities/AlertIOS.js',
'../Libraries/Animation/Animation.js',
'../Libraries/AppRegistry/AppRegistry.js', '../Libraries/AppRegistry/AppRegistry.js',
'../Libraries/AppStateIOS/AppStateIOS.ios.js', '../Libraries/AppStateIOS/AppStateIOS.ios.js',
'../Libraries/Storage/AsyncStorage.ios.js', '../Libraries/Storage/AsyncStorage.ios.js',