mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-29 12:45:37 +08:00
Merge pull request #357 from facebook/updates-mar-27
Update from Friday March 27
This commit is contained in:
@@ -92,7 +92,7 @@
|
|||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
00481BDB1AC0C7FA00671115 /* RCTWebSocketDebugger.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocketDebugger.xcodeproj; path = ../../Libraries/RCTWebSocketDebugger/RCTWebSocketDebugger.xcodeproj; sourceTree = "<group>"; };
|
00481BDB1AC0C7FA00671115 /* RCTWebSocketDebugger.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocketDebugger.xcodeproj; path = ../../Libraries/RCTWebSocketDebugger/RCTWebSocketDebugger.xcodeproj; sourceTree = "<group>"; };
|
||||||
00481BE91AC0C89D00671115 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
|
00481BE91AC0C89D00671115 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; };
|
||||||
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../../Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<absolute>"; };
|
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../../Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
|
||||||
00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
|
00C302AF1ABCB8E700DB3ED1 /* RCTAdSupport.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTAdSupport.xcodeproj; path = ../../Libraries/AdSupport/RCTAdSupport.xcodeproj; sourceTree = "<group>"; };
|
||||||
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
|
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../../Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
|
||||||
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
|
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../../Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
|
||||||
|
|||||||
@@ -15,245 +15,133 @@
|
|||||||
|
|
||||||
var React = require('react-native');
|
var React = require('react-native');
|
||||||
var {
|
var {
|
||||||
|
PixelRatio,
|
||||||
Navigator,
|
Navigator,
|
||||||
ScrollView,
|
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
TabBarIOS,
|
ScrollView,
|
||||||
Text,
|
Text,
|
||||||
View,
|
|
||||||
TouchableHighlight,
|
TouchableHighlight,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
} = React;
|
} = React;
|
||||||
|
|
||||||
var SAMPLE_TEXT = 'Top Pushes. Middle Replaces. Bottom Pops.';
|
|
||||||
|
|
||||||
var _getRandomRoute = function() {
|
var _getRandomRoute = function() {
|
||||||
return {
|
return {
|
||||||
backButtonTitle: 'Back' + ('' + 10 * Math.random()).substr(0, 1),
|
title: '#' + Math.ceil(Math.random() * 1000),
|
||||||
content:
|
|
||||||
SAMPLE_TEXT + '\nHere\'s a random number ' + Math.random(),
|
|
||||||
title: Math.random() > 0.5 ? 'Hello' : 'There',
|
|
||||||
rightButtonTitle: Math.random() > 0.5 ? 'Right' : 'Button',
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class NavButton extends React.Component {
|
||||||
var SampleNavigationBarRouteMapper = {
|
render() {
|
||||||
rightContentForRoute: function(route, navigator) {
|
|
||||||
if (route.rightButtonTitle) {
|
|
||||||
return (
|
|
||||||
<Text style={[styles.titleText, styles.filterText]}>
|
|
||||||
{route.rightButtonTitle}
|
|
||||||
</Text>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
titleContentForRoute: function(route, navigator) {
|
|
||||||
return (
|
return (
|
||||||
<TouchableHighlight
|
<TouchableHighlight
|
||||||
onPress={() => navigator.push(_getRandomRoute())}>
|
style={styles.button}
|
||||||
<View>
|
underlayColor="#B5B5B5"
|
||||||
<Text style={styles.titleText}>{route.title}</Text>
|
onPress={this.props.onPress}>
|
||||||
</View>
|
<Text style={styles.buttonText}>{this.props.text}</Text>
|
||||||
</TouchableHighlight>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
iconForRoute: function(route, navigator) {
|
|
||||||
var onPress =
|
|
||||||
navigator.popToRoute.bind(navigator, route);
|
|
||||||
return (
|
|
||||||
<TouchableHighlight onPress={onPress}>
|
|
||||||
<View style={styles.crumbIconPlaceholder} />
|
|
||||||
</TouchableHighlight>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorForRoute: function(route, navigator) {
|
|
||||||
return (
|
|
||||||
<TouchableHighlight onPress={navigator.pop}>
|
|
||||||
<View style={styles.crumbSeparatorPlaceholder} />
|
|
||||||
</TouchableHighlight>
|
</TouchableHighlight>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
var _delay = 400; // Just to test for race conditions with native nav.
|
|
||||||
|
|
||||||
var renderScene = function(route, navigator) {
|
|
||||||
var content = route.content;
|
|
||||||
return (
|
|
||||||
<ScrollView>
|
|
||||||
<View style={styles.scene}>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={_pushRouteLater(navigator.push)}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>request push soon</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={_pushRouteLater(navigator.replace)}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text>{content}</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={_pushRouteLater(navigator.replace)}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text>{content}</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={_pushRouteLater(navigator.replace)}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text>{content}</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={_pushRouteLater(navigator.replace)}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text>{content}</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={_pushRouteLater(navigator.replace)}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text>{content}</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={_popRouteLater(navigator.pop)}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>request pop soon</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={
|
|
||||||
_immediatelySetTwoItemsLater(
|
|
||||||
navigator.immediatelyResetRouteStack
|
|
||||||
)
|
|
||||||
}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>Immediate set two routes</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={_popToTopLater(navigator.popToTop)}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>pop to top soon</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
var _popToTopLater = function(popToTop) {
|
|
||||||
return () => setTimeout(popToTop, _delay);
|
|
||||||
};
|
|
||||||
|
|
||||||
var _pushRouteLater = function(push) {
|
|
||||||
return () => setTimeout(
|
|
||||||
() => push(_getRandomRoute()),
|
|
||||||
_delay
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
var _immediatelySetTwoItemsLater = function(immediatelyResetRouteStack) {
|
|
||||||
return () => setTimeout(
|
|
||||||
() => immediatelyResetRouteStack([
|
|
||||||
_getRandomRoute(),
|
|
||||||
_getRandomRoute(),
|
|
||||||
])
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
var _popRouteLater = function(pop) {
|
|
||||||
return () => setTimeout(pop, _delay);
|
|
||||||
};
|
|
||||||
|
|
||||||
var BreadcrumbNavSample = React.createClass({
|
var BreadcrumbNavSample = React.createClass({
|
||||||
|
|
||||||
getInitialState: function() {
|
componentWillMount: function() {
|
||||||
return {
|
this._navBarRouteMapper = {
|
||||||
selectedTab: 0,
|
rightContentForRoute: function(route, navigator) {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
titleContentForRoute: function(route, navigator) {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => navigator.push(_getRandomRoute())}>
|
||||||
|
<View>
|
||||||
|
<Text style={styles.titleText}>{route.title}</Text>
|
||||||
|
</View>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
iconForRoute: function(route, navigator) {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity onPress={() => {
|
||||||
|
navigator.popToRoute(route);
|
||||||
|
}}>
|
||||||
|
<View style={styles.crumbIconPlaceholder} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorForRoute: function(route, navigator) {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity onPress={navigator.pop}>
|
||||||
|
<View style={styles.crumbSeparatorPlaceholder} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
render: function() {
|
_renderScene: function(route, navigator) {
|
||||||
var initialRoute = {
|
|
||||||
backButtonTitle: 'Start', // no back button for initial scene
|
|
||||||
content: SAMPLE_TEXT,
|
|
||||||
title: 'Campaigns',
|
|
||||||
rightButtonTitle: 'Filter',
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<TabBarIOS>
|
<ScrollView style={styles.scene}>
|
||||||
<TabBarIOS.Item
|
<NavButton
|
||||||
selected={this.state.selectedTab === 0}
|
onPress={() => { navigator.push(_getRandomRoute()) }}
|
||||||
onPress={this.onTabSelect.bind(this, 0)}
|
text="Push"
|
||||||
icon={require('image!tabnav_list')}
|
/>
|
||||||
title="One">
|
<NavButton
|
||||||
<Navigator
|
onPress={() => { navigator.immediatelyResetRouteStack([_getRandomRoute(), _getRandomRoute()]) }}
|
||||||
debugOverlay={false}
|
text="Reset w/ 2 scenes"
|
||||||
style={[styles.appContainer]}
|
/>
|
||||||
initialRoute={initialRoute}
|
<NavButton
|
||||||
renderScene={renderScene}
|
onPress={() => { navigator.popToTop() }}
|
||||||
navigationBar={
|
text="Pop to top"
|
||||||
<Navigator.BreadcrumbNavigationBar
|
/>
|
||||||
navigationBarRouteMapper={SampleNavigationBarRouteMapper}
|
<NavButton
|
||||||
/>
|
onPress={() => { navigator.replace(_getRandomRoute()) }}
|
||||||
}
|
text="Replace"
|
||||||
/>
|
/>
|
||||||
</TabBarIOS.Item>
|
<NavButton
|
||||||
<TabBarIOS.Item
|
onPress={() => { this.props.navigator.pop(); }}
|
||||||
selected={this.state.selectedTab === 1}
|
text="Close breadcrumb example"
|
||||||
onPress={this.onTabSelect.bind(this, 1)}
|
/>
|
||||||
icon={require('image!tabnav_notification')}
|
</ScrollView>
|
||||||
title="Two">
|
|
||||||
<Navigator
|
|
||||||
configureScene={() => Navigator.SceneConfigs.FloatFromBottom}
|
|
||||||
debugOverlay={false}
|
|
||||||
style={[styles.appContainer]}
|
|
||||||
initialRoute={initialRoute}
|
|
||||||
renderScene={renderScene}
|
|
||||||
navigationBar={
|
|
||||||
<Navigator.BreadcrumbNavigationBar
|
|
||||||
navigationBarRouteMapper={SampleNavigationBarRouteMapper}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</TabBarIOS.Item>
|
|
||||||
</TabBarIOS>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
onTabSelect: function(tab, event) {
|
render: function() {
|
||||||
if (this.state.selectedTab !== tab) {
|
return (
|
||||||
this.setState({selectedTab: tab});
|
<Navigator
|
||||||
}
|
style={styles.container}
|
||||||
|
initialRoute={_getRandomRoute()}
|
||||||
|
renderScene={this._renderScene}
|
||||||
|
navigationBar={
|
||||||
|
<Navigator.BreadcrumbNavigationBar
|
||||||
|
navigationBarRouteMapper={this._navBarRouteMapper}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
navigationItem: {
|
|
||||||
backgroundColor: '#eeeeee',
|
|
||||||
},
|
|
||||||
scene: {
|
scene: {
|
||||||
paddingTop: 50,
|
paddingTop: 50,
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: '#cccccc',
|
backgroundColor: 'white',
|
||||||
margin: 50,
|
padding: 15,
|
||||||
marginTop: 26,
|
borderBottomWidth: 1 / PixelRatio.get(),
|
||||||
padding: 10,
|
borderBottomColor: '#CDCDCD',
|
||||||
},
|
},
|
||||||
buttonText: {
|
buttonText: {
|
||||||
fontSize: 12,
|
fontSize: 17,
|
||||||
textAlign: 'center',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
appContainer: {
|
container: {
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
backgroundColor: '#dddddd',
|
backgroundColor: '#dddddd',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
@@ -262,13 +150,9 @@ var styles = StyleSheet.create({
|
|||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: '#666666',
|
color: '#666666',
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontWeight: '500',
|
fontWeight: 'bold',
|
||||||
lineHeight: 32,
|
lineHeight: 32,
|
||||||
},
|
},
|
||||||
filterText: {
|
|
||||||
color: '#5577ff',
|
|
||||||
},
|
|
||||||
// TODO: Accept icons from route.
|
|
||||||
crumbIconPlaceholder: {
|
crumbIconPlaceholder: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: '#666666',
|
backgroundColor: '#666666',
|
||||||
|
|||||||
@@ -16,8 +16,10 @@
|
|||||||
var React = require('react-native');
|
var React = require('react-native');
|
||||||
var {
|
var {
|
||||||
Navigator,
|
Navigator,
|
||||||
|
PixelRatio,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
|
TabBarIOS,
|
||||||
Text,
|
Text,
|
||||||
TouchableHighlight,
|
TouchableHighlight,
|
||||||
View,
|
View,
|
||||||
@@ -25,178 +27,186 @@ var {
|
|||||||
|
|
||||||
var _getRandomRoute = function() {
|
var _getRandomRoute = function() {
|
||||||
return {
|
return {
|
||||||
randNumber: Math.random(),
|
randNumber: Math.ceil(Math.random() * 1000),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
var INIT_ROUTE = _getRandomRoute();
|
class NavButton extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.button}
|
||||||
|
underlayColor="#B5B5B5"
|
||||||
|
onPress={this.props.onPress}>
|
||||||
|
<Text style={styles.buttonText}>{this.props.text}</Text>
|
||||||
|
</TouchableHighlight>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var ROUTE_STACK = [
|
var ROUTE_STACK = [
|
||||||
_getRandomRoute(),
|
_getRandomRoute(),
|
||||||
_getRandomRoute(),
|
_getRandomRoute(),
|
||||||
INIT_ROUTE,
|
|
||||||
_getRandomRoute(),
|
|
||||||
_getRandomRoute(),
|
_getRandomRoute(),
|
||||||
];
|
];
|
||||||
var renderScene = function(route, navigator) {
|
var INIT_ROUTE_INDEX = 1;
|
||||||
return (
|
|
||||||
<ScrollView style={styles.scene}>
|
|
||||||
<View style={styles.scroll}>
|
|
||||||
<Text>{route.randNumber}</Text>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={() => {
|
|
||||||
navigator.jumpBack();
|
|
||||||
}}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>jumpBack</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={() => {
|
|
||||||
navigator.jumpForward();
|
|
||||||
}}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>jumpForward</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={() => {
|
|
||||||
navigator.jumpTo(INIT_ROUTE);
|
|
||||||
}}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>jumpTo initial route</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={() => {
|
|
||||||
navigator.push(_getRandomRoute());
|
|
||||||
}}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>destructive: push</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={() => {
|
|
||||||
navigator.replace(_getRandomRoute());
|
|
||||||
}}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>destructive: replace</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={() => {
|
|
||||||
navigator.pop();
|
|
||||||
}}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>destructive: pop</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={() => {
|
|
||||||
navigator.immediatelyResetRouteStack([
|
|
||||||
_getRandomRoute(),
|
|
||||||
_getRandomRoute(),
|
|
||||||
]);
|
|
||||||
}}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>destructive: Immediate set two routes</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
<TouchableHighlight
|
|
||||||
onPress={() => {
|
|
||||||
navigator.popToTop();
|
|
||||||
}}>
|
|
||||||
<View style={styles.button}>
|
|
||||||
<Text style={styles.buttonText}>destructive: pop to top</Text>
|
|
||||||
</View>
|
|
||||||
</TouchableHighlight>
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
class JumpingNavBar extends React.Component {
|
class JumpingNavBar extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.navBar}>
|
<View style={styles.tabs}>
|
||||||
{this.props.routeStack.map((route, index) => (
|
<TabBarIOS
|
||||||
<TouchableHighlight onPress={() => {
|
selectedTab={'tab_' + this.props.tabIndex}>
|
||||||
this.props.navigator.jumpTo(route);
|
<TabBarIOS.Item
|
||||||
}}>
|
name="tab_0"
|
||||||
<View style={styles.navButton}>
|
icon={require('image!tabnav_notification')}
|
||||||
<Text
|
selected={this.props.tabIndex === 0}
|
||||||
style={[
|
onPress={() => { this.props.onTabIndex(0); }}
|
||||||
styles.navButtonText,
|
children={<View />}
|
||||||
this.props.navState.toIndex === index && styles.navButtonActive
|
/>
|
||||||
]}>
|
<TabBarIOS.Item
|
||||||
{index}
|
name="tab_1"
|
||||||
</Text>
|
icon={require('image!tabnav_list')}
|
||||||
</View>
|
selected={this.props.tabIndex === 1}
|
||||||
</TouchableHighlight>
|
onPress={() => { this.props.onTabIndex(1); }}
|
||||||
))}
|
children={<View />}
|
||||||
|
/>
|
||||||
|
<TabBarIOS.Item
|
||||||
|
name="tab_2"
|
||||||
|
icon={require('image!tabnav_settings')}
|
||||||
|
selected={this.props.tabIndex === 2}
|
||||||
|
onPress={() => { this.props.onTabIndex(2); }}
|
||||||
|
children={<View />}
|
||||||
|
/>
|
||||||
|
</TabBarIOS>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var JumpingNavSample = React.createClass({
|
var JumpingNavSample = React.createClass({
|
||||||
|
getInitialState: function() {
|
||||||
|
return {
|
||||||
|
tabIndex: INIT_ROUTE_INDEX,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<Navigator
|
<Navigator
|
||||||
debugOverlay={false}
|
debugOverlay={false}
|
||||||
style={[styles.appContainer]}
|
style={styles.appContainer}
|
||||||
initialRoute={INIT_ROUTE}
|
ref={(navigator) => {
|
||||||
|
this._navigator = navigator;
|
||||||
|
}}
|
||||||
|
initialRoute={ROUTE_STACK[INIT_ROUTE_INDEX]}
|
||||||
initialRouteStack={ROUTE_STACK}
|
initialRouteStack={ROUTE_STACK}
|
||||||
renderScene={renderScene}
|
renderScene={this.renderScene}
|
||||||
navigationBar={<JumpingNavBar routeStack={ROUTE_STACK} />}
|
navigationBar={
|
||||||
|
<JumpingNavBar
|
||||||
|
routeStack={ROUTE_STACK}
|
||||||
|
tabIndex={this.state.tabIndex}
|
||||||
|
onTabIndex={(index) => {
|
||||||
|
this.setState({ tabIndex: index }, () => {
|
||||||
|
this._navigator.jumpTo(ROUTE_STACK[index]);
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onWillFocus={(route) => {
|
||||||
|
this.setState({
|
||||||
|
tabIndex: ROUTE_STACK.indexOf(route),
|
||||||
|
});
|
||||||
|
}}
|
||||||
shouldJumpOnBackstackPop={true}
|
shouldJumpOnBackstackPop={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
renderScene: function(route, navigator) {
|
||||||
|
var backBtn;
|
||||||
|
var forwardBtn;
|
||||||
|
if (ROUTE_STACK.indexOf(route) !== 0) {
|
||||||
|
backBtn = (
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
navigator.jumpBack();
|
||||||
|
}}
|
||||||
|
text="jumpBack"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (ROUTE_STACK.indexOf(route) !== ROUTE_STACK.length - 1) {
|
||||||
|
forwardBtn = (
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
navigator.jumpForward();
|
||||||
|
}}
|
||||||
|
text="jumpForward"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<ScrollView style={styles.scene}>
|
||||||
|
<Text style={styles.messageText}>#{route.randNumber}</Text>
|
||||||
|
{backBtn}
|
||||||
|
{forwardBtn}
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
navigator.jumpTo(ROUTE_STACK[1]);
|
||||||
|
}}
|
||||||
|
text="jumpTo middle route"
|
||||||
|
/>
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
this.props.navigator.pop();
|
||||||
|
}}
|
||||||
|
text="Exit Navigation Example"
|
||||||
|
/>
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
this.props.navigator.push({
|
||||||
|
message: 'Came from jumping example',
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
text="Nav Menu"
|
||||||
|
/>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
scene: {
|
|
||||||
backgroundColor: '#eeeeee',
|
|
||||||
},
|
|
||||||
scroll: {
|
|
||||||
flex: 1,
|
|
||||||
},
|
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: '#cccccc',
|
backgroundColor: 'white',
|
||||||
margin: 50,
|
padding: 15,
|
||||||
marginTop: 26,
|
borderBottomWidth: 1 / PixelRatio.get(),
|
||||||
padding: 10,
|
borderBottomColor: '#CDCDCD',
|
||||||
},
|
},
|
||||||
buttonText: {
|
buttonText: {
|
||||||
fontSize: 12,
|
fontSize: 17,
|
||||||
textAlign: 'center',
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
appContainer: {
|
appContainer: {
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
backgroundColor: '#dddddd',
|
backgroundColor: '#dddddd',
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
navBar: {
|
messageText: {
|
||||||
position: 'absolute',
|
fontSize: 17,
|
||||||
bottom: 0,
|
fontWeight: '500',
|
||||||
left: 0,
|
padding: 15,
|
||||||
right: 0,
|
marginTop: 50,
|
||||||
height: 90,
|
marginLeft: 15,
|
||||||
flexDirection: 'row',
|
|
||||||
},
|
},
|
||||||
navButton: {
|
scene: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
paddingTop: 20,
|
||||||
|
backgroundColor: '#EAEAEA',
|
||||||
},
|
},
|
||||||
navButtonText: {
|
tabs: {
|
||||||
textAlign: 'center',
|
height: 50,
|
||||||
fontSize: 32,
|
}
|
||||||
marginTop: 25,
|
|
||||||
},
|
|
||||||
navButtonActive: {
|
|
||||||
color: 'green',
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = JumpingNavSample;
|
module.exports = JumpingNavSample;
|
||||||
|
|||||||
@@ -16,15 +16,30 @@
|
|||||||
|
|
||||||
var React = require('react-native');
|
var React = require('react-native');
|
||||||
var {
|
var {
|
||||||
|
PixelRatio,
|
||||||
Navigator,
|
Navigator,
|
||||||
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
TouchableHighlight,
|
TouchableHighlight,
|
||||||
|
TouchableOpacity,
|
||||||
View,
|
View,
|
||||||
} = React;
|
} = React;
|
||||||
|
|
||||||
var cssVar = require('cssVar');
|
var cssVar = require('cssVar');
|
||||||
|
|
||||||
|
class NavButton extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.button}
|
||||||
|
underlayColor="#B5B5B5"
|
||||||
|
onPress={this.props.onPress}>
|
||||||
|
<Text style={styles.buttonText}>{this.props.text}</Text>
|
||||||
|
</TouchableHighlight>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var NavigationBarRouteMapper = {
|
var NavigationBarRouteMapper = {
|
||||||
|
|
||||||
@@ -35,26 +50,27 @@ var NavigationBarRouteMapper = {
|
|||||||
|
|
||||||
var previousRoute = navState.routeStack[index - 1];
|
var previousRoute = navState.routeStack[index - 1];
|
||||||
return (
|
return (
|
||||||
<TouchableHighlight onPress={() => navigator.pop()}>
|
<TouchableOpacity
|
||||||
<View>
|
onPress={() => navigator.pop()}>
|
||||||
|
<View style={styles.navBarLeftButton}>
|
||||||
<Text style={[styles.navBarText, styles.navBarButtonText]}>
|
<Text style={[styles.navBarText, styles.navBarButtonText]}>
|
||||||
{previousRoute.title}
|
{previousRoute.title}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableHighlight>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
RightButton: function(route, navigator, index, navState) {
|
RightButton: function(route, navigator, index, navState) {
|
||||||
return (
|
return (
|
||||||
<TouchableHighlight
|
<TouchableOpacity
|
||||||
onPress={() => navigator.push(newRandomRoute())}>
|
onPress={() => navigator.push(newRandomRoute())}>
|
||||||
<View>
|
<View style={styles.navBarRightButton}>
|
||||||
<Text style={[styles.navBarText, styles.navBarButtonText]}>
|
<Text style={[styles.navBarText, styles.navBarButtonText]}>
|
||||||
Next
|
Next
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
</TouchableHighlight>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -70,8 +86,7 @@ var NavigationBarRouteMapper = {
|
|||||||
|
|
||||||
function newRandomRoute() {
|
function newRandomRoute() {
|
||||||
return {
|
return {
|
||||||
content: 'Hello World!',
|
title: '#' + Math.ceil(Math.random() * 1000),
|
||||||
title: 'Random ' + Math.round(Math.random() * 100),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,37 +94,63 @@ var NavigationBarSample = React.createClass({
|
|||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.appContainer}>
|
<Navigator
|
||||||
<Navigator
|
debugOverlay={false}
|
||||||
debugOverlay={false}
|
style={styles.appContainer}
|
||||||
style={styles.appContainer}
|
initialRoute={newRandomRoute()}
|
||||||
initialRoute={newRandomRoute()}
|
renderScene={(route, navigator) => (
|
||||||
renderScene={(route, navigator) => (
|
<ScrollView style={styles.scene}>
|
||||||
<View style={styles.scene}>
|
<Text style={styles.messageText}>{route.content}</Text>
|
||||||
<Text>{route.content}</Text>
|
<NavButton
|
||||||
</View>
|
onPress={() => {
|
||||||
)}
|
navigator.immediatelyResetRouteStack([
|
||||||
navigationBar={
|
newRandomRoute(),
|
||||||
<Navigator.NavigationBar
|
newRandomRoute(),
|
||||||
navigationBarRouteMapper={NavigationBarRouteMapper}
|
newRandomRoute(),
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
text="Reset w/ 3 scenes"
|
||||||
/>
|
/>
|
||||||
}
|
<NavButton
|
||||||
/>
|
onPress={() => {
|
||||||
</View>
|
this.props.navigator.pop();
|
||||||
|
}}
|
||||||
|
text="Exit NavigationBar Example"
|
||||||
|
/>
|
||||||
|
</ScrollView>
|
||||||
|
)}
|
||||||
|
navigationBar={
|
||||||
|
<Navigator.NavigationBar
|
||||||
|
navigationBarRouteMapper={NavigationBarRouteMapper}
|
||||||
|
navigationBarStyles={styles.navBar}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
appContainer: {
|
messageText: {
|
||||||
overflow: 'hidden',
|
fontSize: 17,
|
||||||
backgroundColor: '#ffffff',
|
fontWeight: '500',
|
||||||
flex: 1,
|
padding: 15,
|
||||||
|
marginTop: 50,
|
||||||
|
marginLeft: 15,
|
||||||
},
|
},
|
||||||
scene: {
|
button: {
|
||||||
paddingTop: 50,
|
backgroundColor: 'white',
|
||||||
flex: 1,
|
padding: 15,
|
||||||
|
borderBottomWidth: 1 / PixelRatio.get(),
|
||||||
|
borderBottomColor: '#CDCDCD',
|
||||||
|
},
|
||||||
|
buttonText: {
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
navBar: {
|
||||||
|
backgroundColor: 'white',
|
||||||
},
|
},
|
||||||
navBarText: {
|
navBarText: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
@@ -120,9 +161,20 @@ var styles = StyleSheet.create({
|
|||||||
fontWeight: '500',
|
fontWeight: '500',
|
||||||
marginVertical: 9,
|
marginVertical: 9,
|
||||||
},
|
},
|
||||||
|
navBarLeftButton: {
|
||||||
|
paddingLeft: 10,
|
||||||
|
},
|
||||||
|
navBarRightButton: {
|
||||||
|
paddingRight: 10,
|
||||||
|
},
|
||||||
navBarButtonText: {
|
navBarButtonText: {
|
||||||
color: cssVar('fbui-accent-blue'),
|
color: cssVar('fbui-accent-blue'),
|
||||||
},
|
},
|
||||||
|
scene: {
|
||||||
|
flex: 1,
|
||||||
|
paddingTop: 20,
|
||||||
|
backgroundColor: '#EAEAEA',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = NavigationBarSample;
|
module.exports = NavigationBarSample;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
var React = require('react-native');
|
var React = require('react-native');
|
||||||
var {
|
var {
|
||||||
Navigator,
|
Navigator,
|
||||||
|
PixelRatio,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
@@ -25,30 +26,78 @@ var BreadcrumbNavSample = require('./BreadcrumbNavSample');
|
|||||||
var NavigationBarSample = require('./NavigationBarSample');
|
var NavigationBarSample = require('./NavigationBarSample');
|
||||||
var JumpingNavSample = require('./JumpingNavSample');
|
var JumpingNavSample = require('./JumpingNavSample');
|
||||||
|
|
||||||
|
class NavButton extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<TouchableHighlight
|
||||||
|
style={styles.button}
|
||||||
|
underlayColor="#B5B5B5"
|
||||||
|
onPress={this.props.onPress}>
|
||||||
|
<Text style={styles.buttonText}>{this.props.text}</Text>
|
||||||
|
</TouchableHighlight>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class NavMenu extends React.Component {
|
class NavMenu extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<ScrollView style={styles.scene}>
|
<ScrollView style={styles.scene}>
|
||||||
<TouchableHighlight style={styles.button} onPress={() => {
|
<Text style={styles.messageText}>{this.props.message}</Text>
|
||||||
this.props.navigator.push({ id: 'breadcrumbs' });
|
<NavButton
|
||||||
}}>
|
onPress={() => {
|
||||||
<Text style={styles.buttonText}>Breadcrumbs Example</Text>
|
this.props.navigator.push({
|
||||||
</TouchableHighlight>
|
message: 'Swipe right to dismiss',
|
||||||
<TouchableHighlight style={styles.button} onPress={() => {
|
sceneConfig: Navigator.SceneConfigs.FloatFromRight,
|
||||||
this.props.navigator.push({ id: 'navbar' });
|
});
|
||||||
}}>
|
}}
|
||||||
<Text style={styles.buttonText}>Navbar Example</Text>
|
text="Float in from right"
|
||||||
</TouchableHighlight>
|
/>
|
||||||
<TouchableHighlight style={styles.button} onPress={() => {
|
<NavButton
|
||||||
this.props.navigator.push({ id: 'jumping' });
|
onPress={() => {
|
||||||
}}>
|
this.props.navigator.push({
|
||||||
<Text style={styles.buttonText}>Jumping Example</Text>
|
message: 'Swipe down to dismiss',
|
||||||
</TouchableHighlight>
|
sceneConfig: Navigator.SceneConfigs.FloatFromBottom,
|
||||||
<TouchableHighlight style={styles.button} onPress={() => {
|
});
|
||||||
this.props.onExampleExit();
|
}}
|
||||||
}}>
|
text="Float in from bottom"
|
||||||
<Text style={styles.buttonText}>Exit Navigator Example</Text>
|
/>
|
||||||
</TouchableHighlight>
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
this.props.navigator.pop();
|
||||||
|
}}
|
||||||
|
text="Pop"
|
||||||
|
/>
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
this.props.navigator.popToTop();
|
||||||
|
}}
|
||||||
|
text="Pop to top"
|
||||||
|
/>
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
this.props.navigator.push({ id: 'navbar' });
|
||||||
|
}}
|
||||||
|
text="Navbar Example"
|
||||||
|
/>
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
this.props.navigator.push({ id: 'jumping' });
|
||||||
|
}}
|
||||||
|
text="Jumping Example"
|
||||||
|
/>
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
this.props.navigator.push({ id: 'breadcrumbs' });
|
||||||
|
}}
|
||||||
|
text="Breadcrumbs Example"
|
||||||
|
/>
|
||||||
|
<NavButton
|
||||||
|
onPress={() => {
|
||||||
|
this.props.onExampleExit();
|
||||||
|
}}
|
||||||
|
text="Exit <Navigator> Example"
|
||||||
|
/>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -63,19 +112,20 @@ var TabBarExample = React.createClass({
|
|||||||
|
|
||||||
renderScene: function(route, nav) {
|
renderScene: function(route, nav) {
|
||||||
switch (route.id) {
|
switch (route.id) {
|
||||||
case 'menu':
|
case 'navbar':
|
||||||
|
return <NavigationBarSample navigator={nav} />;
|
||||||
|
case 'breadcrumbs':
|
||||||
|
return <BreadcrumbNavSample navigator={nav} />;
|
||||||
|
case 'jumping':
|
||||||
|
return <JumpingNavSample navigator={nav} />;
|
||||||
|
default:
|
||||||
return (
|
return (
|
||||||
<NavMenu
|
<NavMenu
|
||||||
|
message={route.message}
|
||||||
navigator={nav}
|
navigator={nav}
|
||||||
onExampleExit={this.props.onExampleExit}
|
onExampleExit={this.props.onExampleExit}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case 'navbar':
|
|
||||||
return <NavigationBarSample />;
|
|
||||||
case 'breadcrumbs':
|
|
||||||
return <BreadcrumbNavSample />;
|
|
||||||
case 'jumping':
|
|
||||||
return <JumpingNavSample />;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -83,9 +133,14 @@ var TabBarExample = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<Navigator
|
<Navigator
|
||||||
style={styles.container}
|
style={styles.container}
|
||||||
initialRoute={{ id: 'menu', }}
|
initialRoute={{ message: "First Scene", }}
|
||||||
renderScene={this.renderScene}
|
renderScene={this.renderScene}
|
||||||
configureScene={(route) => Navigator.SceneConfigs.FloatFromBottom}
|
configureScene={(route) => {
|
||||||
|
if (route.sceneConfig) {
|
||||||
|
return route.sceneConfig;
|
||||||
|
}
|
||||||
|
return Navigator.SceneConfigs.FloatFromBottom;
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -93,18 +148,30 @@ var TabBarExample = React.createClass({
|
|||||||
});
|
});
|
||||||
|
|
||||||
var styles = StyleSheet.create({
|
var styles = StyleSheet.create({
|
||||||
|
messageText: {
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: '500',
|
||||||
|
padding: 15,
|
||||||
|
marginTop: 50,
|
||||||
|
marginLeft: 15,
|
||||||
|
},
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
button: {
|
button: {
|
||||||
backgroundColor: 'white',
|
backgroundColor: 'white',
|
||||||
padding: 15,
|
padding: 15,
|
||||||
|
borderBottomWidth: 1 / PixelRatio.get(),
|
||||||
|
borderBottomColor: '#CDCDCD',
|
||||||
},
|
},
|
||||||
buttonText: {
|
buttonText: {
|
||||||
|
fontSize: 17,
|
||||||
|
fontWeight: '500',
|
||||||
},
|
},
|
||||||
scene: {
|
scene: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
paddingTop: 64,
|
paddingTop: 20,
|
||||||
|
backgroundColor: '#EAEAEA',
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<Workspace
|
|
||||||
version = "1.0">
|
|
||||||
<FileRef
|
|
||||||
location = "self:UIExplorer.xcodeproj">
|
|
||||||
</FileRef>
|
|
||||||
</Workspace>
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 262 KiB After Width: | Height: | Size: 253 KiB |
@@ -11,14 +11,18 @@
|
|||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var POPAnimation = require('POPAnimation');
|
var POPAnimationOrNull = require('POPAnimation');
|
||||||
|
|
||||||
if (!POPAnimation) {
|
if (!POPAnimationOrNull) {
|
||||||
// POP animation isn't available in the OSS fork - this is a temporary
|
// POP animation isn't available in the OSS fork - this is a temporary
|
||||||
// workaround to enable its availability to be determined at runtime.
|
// workaround to enable its availability to be determined at runtime.
|
||||||
module.exports = (null : ?{});
|
module.exports = (null : ?{});
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
// At this point, POPAnimationOrNull is guaranteed to be
|
||||||
|
// non-null. Bring it local to preserve type refinement.
|
||||||
|
var POPAnimation = POPAnimationOrNull;
|
||||||
|
|
||||||
var invariant = require('invariant');
|
var invariant = require('invariant');
|
||||||
var warning = require('warning');
|
var warning = require('warning');
|
||||||
|
|
||||||
|
|||||||
@@ -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 POPAnimation
|
* @providesModule POPAnimation
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ var RCTPOPAnimationManager = require('NativeModules').POPAnimationManager;
|
|||||||
if (!RCTPOPAnimationManager) {
|
if (!RCTPOPAnimationManager) {
|
||||||
// POP animation isn't available in the OSS fork - this is a temporary
|
// POP animation isn't available in the OSS fork - this is a temporary
|
||||||
// workaround to enable its availability to be determined at runtime.
|
// workaround to enable its availability to be determined at runtime.
|
||||||
module.exports = null;
|
module.exports = (null: ?Object);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
var ReactPropTypes = require('ReactPropTypes');
|
var ReactPropTypes = require('ReactPropTypes');
|
||||||
@@ -64,6 +65,20 @@ var Types = {
|
|||||||
spring: RCTTypes.spring,
|
spring: RCTTypes.spring,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Attrs = {
|
||||||
|
type?: $Enum<typeof Types>;
|
||||||
|
property?: $Enum<typeof Properties>;
|
||||||
|
fromValue?: any;
|
||||||
|
toValue?: any;
|
||||||
|
duration?: any;
|
||||||
|
velocity?: any;
|
||||||
|
deceleration?: any;
|
||||||
|
springBounciness?: any;
|
||||||
|
dynamicsFriction?: any;
|
||||||
|
dynamicsMass?: any;
|
||||||
|
dynamicsTension?: any;
|
||||||
|
}
|
||||||
|
|
||||||
var POPAnimation = {
|
var POPAnimation = {
|
||||||
Types: Types,
|
Types: Types,
|
||||||
Properties: Properties,
|
Properties: Properties,
|
||||||
@@ -83,11 +98,11 @@ var POPAnimation = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
lastUsedTag: 0,
|
lastUsedTag: 0,
|
||||||
allocateTagForAnimation: function() {
|
allocateTagForAnimation: function(): number {
|
||||||
return ++this.lastUsedTag;
|
return ++this.lastUsedTag;
|
||||||
},
|
},
|
||||||
|
|
||||||
createAnimation: function(typeName, attrs) {
|
createAnimation: function(typeName: number, attrs: Attrs): number {
|
||||||
var tag = this.allocateTagForAnimation();
|
var tag = this.allocateTagForAnimation();
|
||||||
|
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
@@ -107,35 +122,35 @@ var POPAnimation = {
|
|||||||
return tag;
|
return tag;
|
||||||
},
|
},
|
||||||
|
|
||||||
createSpringAnimation: function(attrs) {
|
createSpringAnimation: function(attrs: Attrs): number {
|
||||||
return this.createAnimation(this.Types.spring, attrs);
|
return this.createAnimation(this.Types.spring, attrs);
|
||||||
},
|
},
|
||||||
|
|
||||||
createDecayAnimation: function(attrs) {
|
createDecayAnimation: function(attrs: Attrs): number {
|
||||||
return this.createAnimation(this.Types.decay, attrs);
|
return this.createAnimation(this.Types.decay, attrs);
|
||||||
},
|
},
|
||||||
|
|
||||||
createLinearAnimation: function(attrs) {
|
createLinearAnimation: function(attrs: Attrs): number {
|
||||||
return this.createAnimation(this.Types.linear, attrs);
|
return this.createAnimation(this.Types.linear, attrs);
|
||||||
},
|
},
|
||||||
|
|
||||||
createEaseInAnimation: function(attrs) {
|
createEaseInAnimation: function(attrs: Attrs): number {
|
||||||
return this.createAnimation(this.Types.easeIn, attrs);
|
return this.createAnimation(this.Types.easeIn, attrs);
|
||||||
},
|
},
|
||||||
|
|
||||||
createEaseOutAnimation: function(attrs) {
|
createEaseOutAnimation: function(attrs: Attrs): number {
|
||||||
return this.createAnimation(this.Types.easeOut, attrs);
|
return this.createAnimation(this.Types.easeOut, attrs);
|
||||||
},
|
},
|
||||||
|
|
||||||
createEaseInEaseOutAnimation: function(attrs) {
|
createEaseInEaseOutAnimation: function(attrs: Attrs): number {
|
||||||
return this.createAnimation(this.Types.easeInEaseOut, attrs);
|
return this.createAnimation(this.Types.easeInEaseOut, attrs);
|
||||||
},
|
},
|
||||||
|
|
||||||
addAnimation: function(nodeHandle, anim, callback) {
|
addAnimation: function(nodeHandle: any, anim: number, callback: Function) {
|
||||||
RCTPOPAnimationManager.addAnimation(nodeHandle, anim, callback);
|
RCTPOPAnimationManager.addAnimation(nodeHandle, anim, callback);
|
||||||
},
|
},
|
||||||
|
|
||||||
removeAnimation: function(nodeHandle, anim) {
|
removeAnimation: function(nodeHandle: any, anim: number) {
|
||||||
RCTPOPAnimationManager.removeAnimation(nodeHandle, anim);
|
RCTPOPAnimationManager.removeAnimation(nodeHandle, anim);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -95,20 +95,20 @@ var styles = StyleSheet.create({
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Use `ReactNavigator` 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
|
||||||
* scene, and also a `renderScene` function that the navigator can use to
|
* scene, and also a `renderScene` function that the navigator can use to
|
||||||
* render the scene for a given route.
|
* render the scene for a given route.
|
||||||
*
|
*
|
||||||
* To change the animation or gesture properties of the scene, provide a
|
* To change the animation or gesture properties of the scene, provide a
|
||||||
* `configureScene` prop to get the config object for a given route. See
|
* `configureScene` prop to get the config object for a given route. See
|
||||||
* `ReactNavigator.SceneConfigs` for default animations and more info on
|
* `Navigator.SceneConfigs` for default animations and more info on
|
||||||
* scene config options.
|
* scene config options.
|
||||||
*
|
*
|
||||||
* ### Basic Usage
|
* ### Basic Usage
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* <ReactNavigator
|
* <Navigator
|
||||||
* initialRoute={{name: 'My First Scene', index: 0}}
|
* initialRoute={{name: 'My First Scene', index: 0}}
|
||||||
* renderScene={(route, navigator) =>
|
* renderScene={(route, navigator) =>
|
||||||
* <MySceneComponent
|
* <MySceneComponent
|
||||||
@@ -132,7 +132,7 @@ var styles = StyleSheet.create({
|
|||||||
*
|
*
|
||||||
* ### Navigation Methods
|
* ### Navigation Methods
|
||||||
*
|
*
|
||||||
* `ReactNavigator` can be told to navigate in two ways. If you have a ref to
|
* `Navigator` can be told to navigate in two ways. If you have a ref to
|
||||||
* the element, you can invoke several methods on it to trigger navigation:
|
* the element, you can invoke several methods on it to trigger navigation:
|
||||||
*
|
*
|
||||||
* - `jumpBack()` - Jump backward without unmounting the current scene
|
* - `jumpBack()` - Jump backward without unmounting the current scene
|
||||||
@@ -174,7 +174,7 @@ var Navigator = React.createClass({
|
|||||||
* configuration object
|
* configuration object
|
||||||
*
|
*
|
||||||
* ```
|
* ```
|
||||||
* (route) => ReactNavigator.SceneConfigs.FloatFromRight
|
* (route) => Navigator.SceneConfigs.FloatFromRight
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
configureScene: PropTypes.func,
|
configureScene: PropTypes.func,
|
||||||
@@ -230,7 +230,7 @@ var Navigator = React.createClass({
|
|||||||
navigationBar: PropTypes.node,
|
navigationBar: PropTypes.node,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optionally provide the navigator object from a parent ReactNavigator
|
* Optionally provide the navigator object from a parent Navigator
|
||||||
*/
|
*/
|
||||||
navigator: PropTypes.object,
|
navigator: PropTypes.object,
|
||||||
|
|
||||||
@@ -316,7 +316,7 @@ var Navigator = React.createClass({
|
|||||||
parentNavigator: this.props.navigator,
|
parentNavigator: this.props.navigator,
|
||||||
// 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 ReactNavigator
|
// of the topmost Navigator
|
||||||
onWillFocus: this.props.onWillFocus,
|
onWillFocus: this.props.onWillFocus,
|
||||||
onDidFocus: this.props.onDidFocus,
|
onDidFocus: this.props.onDidFocus,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ var Geolocation = {
|
|||||||
getCurrentPosition: function(
|
getCurrentPosition: function(
|
||||||
geo_success: Function,
|
geo_success: Function,
|
||||||
geo_error?: Function,
|
geo_error?: Function,
|
||||||
geo_options?: Object) {
|
geo_options?: Object
|
||||||
|
) {
|
||||||
invariant(
|
invariant(
|
||||||
typeof geo_success === 'function',
|
typeof geo_success === 'function',
|
||||||
'Must provide a valid geo_success callback.'
|
'Must provide a valid geo_success callback.'
|
||||||
|
|||||||
@@ -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 Image
|
* @providesModule Image
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -106,7 +107,9 @@ var Image = React.createClass({
|
|||||||
|
|
||||||
render: function() {
|
render: function() {
|
||||||
var style = flattenStyle([styles.base, this.props.style]);
|
var style = flattenStyle([styles.base, this.props.style]);
|
||||||
|
invariant(style, "style must be initialized");
|
||||||
var source = this.props.source;
|
var source = this.props.source;
|
||||||
|
invariant(source, "source must be initialized");
|
||||||
var isNetwork = source.uri && source.uri.match(/^https?:/);
|
var isNetwork = source.uri && source.uri.match(/^https?:/);
|
||||||
invariant(
|
invariant(
|
||||||
!(isNetwork && source.isStatic),
|
!(isNetwork && source.isStatic),
|
||||||
|
|||||||
@@ -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 ImageResizeMode
|
* @providesModule ImageResizeMode
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
|||||||
@@ -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 ImageStylePropTypes
|
* @providesModule ImageStylePropTypes
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -39,8 +40,8 @@ var unsupportedProps = Object.keys({
|
|||||||
paddingHorizontal: null,
|
paddingHorizontal: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
for (var key in unsupportedProps) {
|
for (var i = 0; i < unsupportedProps.length; i++) {
|
||||||
delete ImageStylePropTypes[key];
|
delete ImageStylePropTypes[unsupportedProps[i]];
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ImageStylePropTypes;
|
module.exports = ImageStylePropTypes;
|
||||||
|
|||||||
@@ -75,6 +75,7 @@
|
|||||||
} else {
|
} else {
|
||||||
_downloadToken = [_imageDownloader downloadImageForURL:imageURL size:self.bounds.size scale:RCTScreenScale() block:^(UIImage *image, NSError *error) {
|
_downloadToken = [_imageDownloader downloadImageForURL:imageURL size:self.bounds.size scale:RCTScreenScale() block:^(UIImage *image, NSError *error) {
|
||||||
if (image) {
|
if (image) {
|
||||||
|
[self.layer removeAnimationForKey:@"contents"];
|
||||||
self.layer.contentsScale = image.scale;
|
self.layer.contentsScale = image.scale;
|
||||||
self.layer.contents = (__bridge id)image.CGImage;
|
self.layer.contents = (__bridge id)image.CGImage;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 InteractionManager
|
* @providesModule InteractionManager
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -70,7 +71,7 @@ var InteractionManager = {
|
|||||||
/**
|
/**
|
||||||
* Schedule a function to run after all interactions have completed.
|
* Schedule a function to run after all interactions have completed.
|
||||||
*/
|
*/
|
||||||
runAfterInteractions(callback) {
|
runAfterInteractions(callback: Function) {
|
||||||
invariant(
|
invariant(
|
||||||
typeof callback === 'function',
|
typeof callback === 'function',
|
||||||
'Must specify a function to schedule.'
|
'Must specify a function to schedule.'
|
||||||
@@ -82,7 +83,7 @@ var InteractionManager = {
|
|||||||
/**
|
/**
|
||||||
* Notify manager that an interaction has started.
|
* Notify manager that an interaction has started.
|
||||||
*/
|
*/
|
||||||
createInteractionHandle() {
|
createInteractionHandle(): number {
|
||||||
scheduleUpdate();
|
scheduleUpdate();
|
||||||
var handle = ++_inc;
|
var handle = ++_inc;
|
||||||
_addInteractionSet.add(handle);
|
_addInteractionSet.add(handle);
|
||||||
@@ -92,7 +93,7 @@ var InteractionManager = {
|
|||||||
/**
|
/**
|
||||||
* Notify manager that an interaction has completed.
|
* Notify manager that an interaction has completed.
|
||||||
*/
|
*/
|
||||||
clearInteractionHandle(handle) {
|
clearInteractionHandle(handle: number) {
|
||||||
invariant(
|
invariant(
|
||||||
!!handle,
|
!!handle,
|
||||||
'Must provide a handle to clear.'
|
'Must provide a handle to clear.'
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
* Copyright 2004-present Facebook. All Rights Reserved.
|
* Copyright 2004-present Facebook. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* @providesModule InteractionMixin
|
* @providesModule InteractionMixin
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ var InteractionMixin = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_interactionMixinHandles: [],
|
_interactionMixinHandles: ([]: Array<number>),
|
||||||
|
|
||||||
createInteractionHandle: function() {
|
createInteractionHandle: function() {
|
||||||
var handle = InteractionManager.createInteractionHandle();
|
var handle = InteractionManager.createInteractionHandle();
|
||||||
@@ -29,7 +30,7 @@ var InteractionMixin = {
|
|||||||
return handle;
|
return handle;
|
||||||
},
|
},
|
||||||
|
|
||||||
clearInteractionHandle: function(clearHandle) {
|
clearInteractionHandle: function(clearHandle: number) {
|
||||||
InteractionManager.clearInteractionHandle(clearHandle);
|
InteractionManager.clearInteractionHandle(clearHandle);
|
||||||
this._interactionMixinHandles = this._interactionMixinHandles.filter(
|
this._interactionMixinHandles = this._interactionMixinHandles.filter(
|
||||||
handle => handle !== clearHandle
|
handle => handle !== clearHandle
|
||||||
@@ -41,7 +42,7 @@ var InteractionMixin = {
|
|||||||
*
|
*
|
||||||
* @param {function} callback
|
* @param {function} callback
|
||||||
*/
|
*/
|
||||||
runAfterInteractions: function(callback) {
|
runAfterInteractions: function(callback: Function) {
|
||||||
InteractionManager.runAfterInteractions(callback);
|
InteractionManager.runAfterInteractions(callback);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 ExceptionsManager
|
* @providesModule ExceptionsManager
|
||||||
|
* @flow
|
||||||
*/
|
*/
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
@@ -18,7 +19,13 @@ var parseErrorStack = require('parseErrorStack');
|
|||||||
|
|
||||||
var sourceMapPromise;
|
var sourceMapPromise;
|
||||||
|
|
||||||
function handleException(e) {
|
type Exception = {
|
||||||
|
sourceURL: string;
|
||||||
|
line: number;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleException(e: Exception) {
|
||||||
var stack = parseErrorStack(e);
|
var stack = parseErrorStack(e);
|
||||||
console.error(
|
console.error(
|
||||||
'Error: ' +
|
'Error: ' +
|
||||||
|
|||||||
@@ -21,74 +21,8 @@ var _initialURL = RCTLinkingManager &&
|
|||||||
|
|
||||||
var DEVICE_NOTIF_EVENT = 'openURL';
|
var DEVICE_NOTIF_EVENT = 'openURL';
|
||||||
|
|
||||||
/**
|
|
||||||
* `LinkingIOS` gives you an interface to interact with both incoming and
|
|
||||||
* outgoing app links.
|
|
||||||
*
|
|
||||||
* ### Basic Usage
|
|
||||||
*
|
|
||||||
* #### Handling deep links
|
|
||||||
*
|
|
||||||
* If your app was launched from an external URL registered with your app, you can
|
|
||||||
* access and handle it from any component you want with the following:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* componentDidMount() {
|
|
||||||
* var url = LinkingIOS.popInitialURL();
|
|
||||||
* if (url) { ... }
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* If you also want to listen to incoming app links during your app's
|
|
||||||
* execution you'll need to add the following lines to you `*AppDelegate.m`:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
|
|
||||||
* return [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* And in your React component, you'll then be able to listen to the events from
|
|
||||||
* `LinkingIOS` as follows
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* componentDidMount() {
|
|
||||||
* LinkingIOS.addEventListener('url', this._handleOpenURL);
|
|
||||||
* },
|
|
||||||
* componentWillUnmount() {
|
|
||||||
* LinkingIOS.removeEventListener('url', this._handleOpenURL);
|
|
||||||
* },
|
|
||||||
* _handleOpenURL(event) {
|
|
||||||
* console.log(event.url);
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* #### Triggering App links
|
|
||||||
*
|
|
||||||
* To trigger an app link (browser, email, or custom schemes) you can call:
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* LinkingIOS.openURL(url)
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* If you want to check if a URL can be opened by an installed app on the system you can call
|
|
||||||
*
|
|
||||||
* ```
|
|
||||||
* LinkingIOS.canOpenURL(url, (supported) => {
|
|
||||||
* if (!supported) {
|
|
||||||
* AlertIOS.alert('Can\'t handle url: ' + url);
|
|
||||||
* } else {
|
|
||||||
* LinkingIOS.openURL(url);
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
class LinkingIOS {
|
class LinkingIOS {
|
||||||
/**
|
static addEventListener(type, handler) {
|
||||||
* Add a handler to LinkingIOS changes by listening to the `url` event type
|
|
||||||
* and providing the handler
|
|
||||||
*/
|
|
||||||
static addEventListener(type: string, handler: Function) {
|
|
||||||
invariant(
|
invariant(
|
||||||
type === 'url',
|
type === 'url',
|
||||||
'LinkingIOS only supports `url` events'
|
'LinkingIOS only supports `url` events'
|
||||||
@@ -101,10 +35,7 @@ class LinkingIOS {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static removeEventListener(type, handler) {
|
||||||
* Remove a handler by passing the `url` event type and the handler
|
|
||||||
*/
|
|
||||||
static removeEventListener(type: string, handler: Function ) {
|
|
||||||
invariant(
|
invariant(
|
||||||
type === 'url',
|
type === 'url',
|
||||||
'LinkingIOS only supports `url` events'
|
'LinkingIOS only supports `url` events'
|
||||||
@@ -116,12 +47,7 @@ class LinkingIOS {
|
|||||||
_notifHandlers[handler] = null;
|
_notifHandlers[handler] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static openURL(url) {
|
||||||
* Try to open the given `url` with any of the installed apps.
|
|
||||||
* If multiple applications can open `url`, the one that opens
|
|
||||||
* is undefined.
|
|
||||||
*/
|
|
||||||
static openURL(url: string) {
|
|
||||||
invariant(
|
invariant(
|
||||||
typeof url === 'string',
|
typeof url === 'string',
|
||||||
'Invalid url: should be a string'
|
'Invalid url: should be a string'
|
||||||
@@ -129,11 +55,7 @@ class LinkingIOS {
|
|||||||
RCTLinkingManager.openURL(url);
|
RCTLinkingManager.openURL(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static canOpenURL(url, callback) {
|
||||||
* Determine whether an installed app can handle a given `url`.
|
|
||||||
* The callback function will be called with `bool supported` as the only argument
|
|
||||||
*/
|
|
||||||
static canOpenURL(url: string, callback: Function) {
|
|
||||||
invariant(
|
invariant(
|
||||||
typeof url === 'string',
|
typeof url === 'string',
|
||||||
'Invalid url: should be a string'
|
'Invalid url: should be a string'
|
||||||
@@ -145,11 +67,7 @@ class LinkingIOS {
|
|||||||
RCTLinkingManager.canOpenURL(url, callback);
|
RCTLinkingManager.canOpenURL(url, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static popInitialURL() {
|
||||||
* If the app launch was triggered by an app link, it will pop the link URL,
|
|
||||||
* otherwise it will return `null`
|
|
||||||
*/
|
|
||||||
static popInitialURL(): ?string {
|
|
||||||
var initialURL = _initialURL;
|
var initialURL = _initialURL;
|
||||||
_initialURL = null;
|
_initialURL = null;
|
||||||
return initialURL;
|
return initialURL;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "RCTBridgeModule.h"
|
#import "../../React/Base/RCTBridgeModule.h"
|
||||||
|
|
||||||
@interface RCTLinkingManager : NSObject <RCTBridgeModule>
|
@interface RCTLinkingManager : NSObject <RCTBridgeModule>
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "RCTBridgeModule.h"
|
#import "../../React/Base/RCTBridgeModule.h"
|
||||||
|
|
||||||
@interface RCTPushNotificationManager : NSObject <RCTBridgeModule>
|
@interface RCTPushNotificationManager : NSObject <RCTBridgeModule>
|
||||||
|
|
||||||
|
|||||||
105
React.podspec
105
React.podspec
@@ -1,93 +1,78 @@
|
|||||||
Pod::Spec.new do |s|
|
Pod::Spec.new do |s|
|
||||||
s.name = "React"
|
s.name = "React"
|
||||||
s.version = "0.1.0"
|
s.version = "0.1.0"
|
||||||
s.summary = "Build high quality mobile apps using React."
|
s.summary = "Build high quality mobile apps using React."
|
||||||
s.description = <<-DESC
|
s.description= <<-DESC
|
||||||
React Native apps are built using the React JS
|
React Native apps are built using the React JS framework,
|
||||||
framework, and render directly to native UIKit
|
and render directly to native UIKit elements using a fully
|
||||||
elements using a fully asynchronous architecture.
|
asynchronous architecture. There is no browser and no HTML.
|
||||||
There is no browser and no HTML. We have picked what
|
We have picked what we think is the best set of features from
|
||||||
we think is the best set of features from these and
|
these and other technologies to build what we hope to become
|
||||||
other technologies to build what we hope to become
|
the best product development framework available, with an
|
||||||
the best product development framework available,
|
emphasis on iteration speed, developer delight, continuity
|
||||||
with an emphasis on iteration speed, developer
|
of technology, and absolutely beautiful and fast products
|
||||||
delight, continuity of technology, and absolutely
|
with no compromises in quality or capability.
|
||||||
beautiful and fast products with no compromises in
|
DESC
|
||||||
quality or capability.
|
s.homepage = "http://facebook.github.io/react-native/"
|
||||||
DESC
|
s.license = "BSD"
|
||||||
s.homepage = "http://facebook.github.io/react-native/"
|
s.author = "Facebook"
|
||||||
s.license = "BSD"
|
s.platform = :ios, "7.0"
|
||||||
s.author = "Facebook"
|
s.source = { :git => "https://github.com/facebook/react-native.git", :tag => "v#{s.version}" }
|
||||||
s.source = { :git => "https://github.com/facebook/react-native.git", :tag => "v#{s.version}" }
|
s.source_files = "React/**/*.{c,h,m}"
|
||||||
s.default_subspec = 'Core'
|
s.resources = "Resources/*.png"
|
||||||
s.requires_arc = true
|
s.preserve_paths = "cli.js", "Libraries/**/*.js", "lint", "linter.js", "node_modules", "package.json", "packager", "PATENTS", "react-native-cli"
|
||||||
s.platform = :ios, "7.0"
|
s.exclude_files = "**/__tests__/*", "IntegrationTests/*"
|
||||||
s.prepare_command = 'npm install'
|
s.frameworks = "JavaScriptCore"
|
||||||
s.preserve_paths = "cli.js", "Libraries/**/*.js", "lint", "linter.js", "node_modules", "package.json", "packager", "PATENTS", "react-native-cli"
|
s.requires_arc = true
|
||||||
|
s.prepare_command = 'npm install'
|
||||||
s.subspec 'Core' do |ss|
|
s.libraries = 'icucore'
|
||||||
ss.libraries = 'icucore'
|
|
||||||
ss.source_files = "React/**/*.{c,h,m}"
|
|
||||||
ss.exclude_files = "**/__tests__/*", "IntegrationTests/*"
|
|
||||||
ss.frameworks = "JavaScriptCore"
|
|
||||||
end
|
|
||||||
|
|
||||||
s.subspec 'RCTActionSheet' do |ss|
|
s.subspec 'RCTActionSheet' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/ActionSheetIOS/*.{h,m}"
|
||||||
ss.source_files = "Libraries/ActionSheetIOS/*.{h,m}"
|
|
||||||
ss.preserve_paths = "Libraries/ActionSheetIOS/*.js"
|
ss.preserve_paths = "Libraries/ActionSheetIOS/*.js"
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTAdSupport' do |ss|
|
s.subspec 'RCTAdSupport' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/RCTAdSupport/*.{h,m}"
|
||||||
ss.source_files = "Libraries/AdSupport/*.{h,m}"
|
ss.preserve_paths = "Libraries/RCTAdSupport/*.js"
|
||||||
ss.preserve_paths = "Libraries/AdSupport/*.js"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTAnimation' do |ss|
|
s.subspec 'RCTAnimation' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/Animation/*.{h,m}"
|
||||||
ss.source_files = "Libraries/Animation/*.{h,m}"
|
ss.preserve_paths = "Libraries/Animation/*.js"
|
||||||
ss.preserve_paths = "Libraries/Animation/*.js"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTGeolocation' do |ss|
|
s.subspec 'RCTGeolocation' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/Geolocation/*.{h,m}"
|
||||||
ss.source_files = "Libraries/Geolocation/*.{h,m}"
|
ss.preserve_paths = "Libraries/Geolocation/*.js"
|
||||||
ss.preserve_paths = "Libraries/Geolocation/*.js"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTImage' do |ss|
|
s.subspec 'RCTImage' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/Image/*.{h,m}"
|
||||||
ss.source_files = "Libraries/Image/*.{h,m}"
|
ss.preserve_paths = "Libraries/Image/*.js"
|
||||||
ss.preserve_paths = "Libraries/Image/*.js"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTNetwork' do |ss|
|
s.subspec 'RCTNetwork' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/Network/*.{h,m}"
|
||||||
ss.source_files = "Libraries/Network/*.{h,m}"
|
ss.preserve_paths = "Libraries/Network/*.js"
|
||||||
ss.preserve_paths = "Libraries/Network/*.js"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTPushNotification' do |ss|
|
s.subspec 'RCTPushNotification' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/PushNotificationIOS/*.{h,m}"
|
||||||
ss.source_files = "Libraries/PushNotificationIOS/*.{h,m}"
|
ss.preserve_paths = "Libraries/PushNotificationIOS/*.js"
|
||||||
ss.preserve_paths = "Libraries/PushNotificationIOS/*.js"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTWebSocketDebugger' do |ss|
|
s.subspec 'RCTWebSocketDebugger' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/RCTWebSocketDebugger/*.{h,m}"
|
||||||
ss.source_files = "Libraries/RCTWebSocketDebugger/*.{h,m}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTText' do |ss|
|
s.subspec 'RCTText' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/Text/*.{h,m}"
|
||||||
ss.source_files = "Libraries/Text/*.{h,m}"
|
ss.preserve_paths = "Libraries/Text/*.js"
|
||||||
ss.preserve_paths = "Libraries/Text/*.js"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
s.subspec 'RCTVibration' do |ss|
|
s.subspec 'RCTVibration' do |ss|
|
||||||
ss.dependency 'React/Core'
|
ss.source_files = "Libraries/Vibration/*.{h,m}"
|
||||||
ss.source_files = "Libraries/Vibration/*.{h,m}"
|
ss.preserve_paths = "Libraries/Vibration/*.js"
|
||||||
ss.preserve_paths = "Libraries/Vibration/*.js"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,10 +10,11 @@
|
|||||||
#import <QuartzCore/QuartzCore.h>
|
#import <QuartzCore/QuartzCore.h>
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "Layout.h"
|
#import "../Layout/Layout.h"
|
||||||
#import "RCTAnimationType.h"
|
#import "../Views/RCTAnimationType.h"
|
||||||
|
#import "../Views/RCTPointerEvents.h"
|
||||||
|
|
||||||
#import "RCTLog.h"
|
#import "RCTLog.h"
|
||||||
#import "RCTPointerEvents.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides a collection of conversion functions for mapping
|
* This class provides a collection of conversion functions for mapping
|
||||||
|
|||||||
@@ -453,22 +453,21 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[
|
|||||||
return [self UIImage:json].CGImage;
|
return [self UIImage:json].CGImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef __IPHONE_8_2
|
#if !defined(__IPHONE_8_2) || __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_8_2
|
||||||
|
|
||||||
// These constants are defined in iPhone SDK 8.2
|
// These constants are defined in iPhone SDK 8.2, but the app cannot run on
|
||||||
// They'll work fine in earlier iOS versions, but the app cannot be built with
|
// iOS < 8.2 unless we redefine them here. If you target iOS 8.2 or above
|
||||||
// an SDK version < 8.2 unless we redefine them here. This will be removed
|
// as a base target, the standard constants will be used instead.
|
||||||
// in a future version of React, once 8.2 is more widely adopted.
|
|
||||||
|
|
||||||
static const CGFloat UIFontWeightUltraLight = -0.8;
|
#define UIFontWeightUltraLight -0.8
|
||||||
static const CGFloat UIFontWeightThin = -0.6;
|
#define UIFontWeightThin -0.6
|
||||||
static const CGFloat UIFontWeightLight = -0.4;
|
#define UIFontWeightLight -0.4
|
||||||
static const CGFloat UIFontWeightRegular = 0;
|
#define UIFontWeightRegular 0
|
||||||
static const CGFloat UIFontWeightMedium = 0.23;
|
#define UIFontWeightMedium 0.23
|
||||||
static const CGFloat UIFontWeightSemibold = 0.3;
|
#define UIFontWeightSemibold 0.3
|
||||||
static const CGFloat UIFontWeightBold = 0.4;
|
#define UIFontWeightBold 0.4
|
||||||
static const CGFloat UIFontWeightHeavy = 0.56;
|
#define UIFontWeightHeavy 0.56
|
||||||
static const CGFloat UIFontWeightBlack = 0.62;
|
#define UIFontWeightBlack 0.62
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -9,10 +9,10 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "RCTBridge.h"
|
#import "../Base/RCTBridge.h"
|
||||||
#import "RCTBridgeModule.h"
|
#import "../Base/RCTBridgeModule.h"
|
||||||
#import "RCTInvalidating.h"
|
#import "../Base/RCTInvalidating.h"
|
||||||
#import "RCTViewManager.h"
|
#import "../Views/RCTViewManager.h"
|
||||||
|
|
||||||
@protocol RCTScrollableProtocol;
|
@protocol RCTScrollableProtocol;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "Layout.h"
|
#import "../Layout/Layout.h"
|
||||||
|
|
||||||
#import "RCTViewNodeProtocol.h"
|
#import "RCTViewNodeProtocol.h"
|
||||||
|
|
||||||
@class RCTSparseArray;
|
@class RCTSparseArray;
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
#import "RCTBridgeModule.h"
|
#import "../Base/RCTBridgeModule.h"
|
||||||
#import "RCTConvert.h"
|
#import "../Base/RCTConvert.h"
|
||||||
#import "RCTLog.h"
|
#import "../Base/RCTLog.h"
|
||||||
|
|
||||||
@class RCTBridge;
|
@class RCTBridge;
|
||||||
@class RCTEventDispatcher;
|
@class RCTEventDispatcher;
|
||||||
|
|||||||
@@ -69,11 +69,7 @@ if (options.assetRoots) {
|
|||||||
options.assetRoots = options.assetRoots.split(',');
|
options.assetRoots = options.assetRoots.split(',');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (__dirname.match(/node_modules\/react-native\/packager$/)) {
|
options.assetRoots = [path.resolve(__dirname, '..')];
|
||||||
options.assetRoots = [path.resolve(__dirname, '../../..')];
|
|
||||||
} else {
|
|
||||||
options.assetRoots = [path.resolve(__dirname, '..')];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('\n' +
|
console.log('\n' +
|
||||||
|
|||||||
@@ -10,4 +10,4 @@
|
|||||||
ulimit -n 4096
|
ulimit -n 4096
|
||||||
|
|
||||||
THIS_DIR=$(dirname "$0")
|
THIS_DIR=$(dirname "$0")
|
||||||
node $THIS_DIR/packager.js "$@"
|
node "$THIS_DIR/packager.js" "$@"
|
||||||
|
|||||||
@@ -821,6 +821,55 @@ describe('DependencyGraph', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pit('updates module dependencies on asset add', function() {
|
||||||
|
var root = '/root';
|
||||||
|
var filesystem = fs.__setMockFilesystem({
|
||||||
|
'root': {
|
||||||
|
'index.js': [
|
||||||
|
'/**',
|
||||||
|
' * @providesModule index',
|
||||||
|
' */',
|
||||||
|
'require("image!foo")'
|
||||||
|
].join('\n'),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var dgraph = new DependencyGraph({
|
||||||
|
roots: [root],
|
||||||
|
assetRoots: [root],
|
||||||
|
assetExts: ['png'],
|
||||||
|
fileWatcher: fileWatcher
|
||||||
|
});
|
||||||
|
|
||||||
|
return dgraph.load().then(function() {
|
||||||
|
expect(dgraph.getOrderedDependencies('/root/index.js'))
|
||||||
|
.toEqual([
|
||||||
|
{ id: 'index', altId: '/root/index.js',
|
||||||
|
path: '/root/index.js',
|
||||||
|
dependencies: ['image!foo']
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
filesystem.root['foo.png'] = '';
|
||||||
|
triggerFileChange('add', 'foo.png', root);
|
||||||
|
|
||||||
|
return dgraph.load().then(function() {
|
||||||
|
expect(dgraph.getOrderedDependencies('/root/index.js'))
|
||||||
|
.toEqual([
|
||||||
|
{ id: 'index', altId: '/root/index.js',
|
||||||
|
path: '/root/index.js',
|
||||||
|
dependencies: ['image!foo']
|
||||||
|
},
|
||||||
|
{ id: 'image!foo',
|
||||||
|
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({
|
||||||
|
|||||||
@@ -86,7 +86,11 @@ DependecyGraph.prototype.load = function() {
|
|||||||
DependecyGraph.prototype.getOrderedDependencies = function(entryPath) {
|
DependecyGraph.prototype.getOrderedDependencies = function(entryPath) {
|
||||||
var absolutePath = this._getAbsolutePath(entryPath);
|
var absolutePath = this._getAbsolutePath(entryPath);
|
||||||
if (absolutePath == null) {
|
if (absolutePath == null) {
|
||||||
throw new Error('Cannot find entry file in any of the roots: ' + entryPath);
|
throw new NotFoundError(
|
||||||
|
'Cannot find entry file %s in any of the roots: %j',
|
||||||
|
entryPath,
|
||||||
|
this._roots
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
var module = this._graph[absolutePath];
|
var module = this._graph[absolutePath];
|
||||||
@@ -478,7 +482,12 @@ DependecyGraph.prototype._lookupPackage = function(modulePath) {
|
|||||||
/**
|
/**
|
||||||
* Process a filewatcher change event.
|
* Process a filewatcher change event.
|
||||||
*/
|
*/
|
||||||
DependecyGraph.prototype._processFileChange = function(eventType, filePath, root, stat) {
|
DependecyGraph.prototype._processFileChange = function(
|
||||||
|
eventType,
|
||||||
|
filePath,
|
||||||
|
root,
|
||||||
|
stat
|
||||||
|
) {
|
||||||
var absPath = path.join(root, filePath);
|
var absPath = path.join(root, filePath);
|
||||||
if (this._ignoreFilePath(absPath)) {
|
if (this._ignoreFilePath(absPath)) {
|
||||||
return;
|
return;
|
||||||
@@ -486,6 +495,11 @@ DependecyGraph.prototype._processFileChange = function(eventType, filePath, root
|
|||||||
|
|
||||||
this._debugUpdateEvents.push({event: eventType, path: filePath});
|
this._debugUpdateEvents.push({event: eventType, path: filePath});
|
||||||
|
|
||||||
|
if (this._assetExts.indexOf(extname(filePath)) > -1) {
|
||||||
|
this._processAssetChange(eventType, absPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var isPackage = path.basename(filePath) === 'package.json';
|
var isPackage = path.basename(filePath) === 'package.json';
|
||||||
if (eventType === 'delete') {
|
if (eventType === 'delete') {
|
||||||
if (isPackage) {
|
if (isPackage) {
|
||||||
@@ -520,7 +534,8 @@ DependecyGraph.prototype.getDebugInfo = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Searches all roots for the file and returns the first one that has file of the same path.
|
* Searches all roots for the file and returns the first one that has file of
|
||||||
|
* the same path.
|
||||||
*/
|
*/
|
||||||
DependecyGraph.prototype._getAbsolutePath = function(filePath) {
|
DependecyGraph.prototype._getAbsolutePath = function(filePath) {
|
||||||
if (isAbsolutePath(filePath)) {
|
if (isAbsolutePath(filePath)) {
|
||||||
@@ -543,12 +558,43 @@ DependecyGraph.prototype._buildAssetMap = function() {
|
|||||||
return q();
|
return q();
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
this._assetMap = Object.create(null);
|
||||||
return buildAssetMap(this._assetRoots, this._assetExts)
|
return buildAssetMap(
|
||||||
.then(function(map) {
|
this._assetRoots,
|
||||||
self._assetMap = map;
|
this._processAsset.bind(this)
|
||||||
return map;
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
DependecyGraph.prototype._processAsset = function(file) {
|
||||||
|
var ext = extname(file);
|
||||||
|
if (this._assetExts.indexOf(ext) !== -1) {
|
||||||
|
var name = assetName(file, ext);
|
||||||
|
if (this._assetMap[name] != null) {
|
||||||
|
debug('Conflcting assets', name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._assetMap[name] = new ModuleDescriptor({
|
||||||
|
id: 'image!' + name,
|
||||||
|
path: path.resolve(file),
|
||||||
|
isAsset: true,
|
||||||
|
dependencies: [],
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DependecyGraph.prototype._processAssetChange = function(eventType, file) {
|
||||||
|
if (this._assetMap == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = assetName(file, extname(file));
|
||||||
|
if (eventType === 'change' || eventType === 'delete') {
|
||||||
|
delete this._assetMap[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (eventType === 'change' || eventType === 'add') {
|
||||||
|
this._processAsset(file);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -623,15 +669,14 @@ 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, exts) {
|
function buildAssetMap(roots, processAsset) {
|
||||||
var queue = roots.slice(0);
|
var queue = roots.slice(0);
|
||||||
var map = Object.create(null);
|
|
||||||
|
|
||||||
function search() {
|
function search() {
|
||||||
var root = queue.shift();
|
var root = queue.shift();
|
||||||
|
|
||||||
if (root == null) {
|
if (root == null) {
|
||||||
return q(map);
|
return q();
|
||||||
}
|
}
|
||||||
|
|
||||||
return readAndStatDir(root).spread(function(files, stats) {
|
return readAndStatDir(root).spread(function(files, stats) {
|
||||||
@@ -639,21 +684,7 @@ function buildAssetMap(roots, exts) {
|
|||||||
if (stats[i].isDirectory()) {
|
if (stats[i].isDirectory()) {
|
||||||
queue.push(file);
|
queue.push(file);
|
||||||
} else {
|
} else {
|
||||||
var ext = path.extname(file).replace(/^\./, '');
|
processAsset(file);
|
||||||
if (exts.indexOf(ext) !== -1) {
|
|
||||||
var assetName = path.basename(file, '.' + ext)
|
|
||||||
.replace(/@[\d\.]+x/, '');
|
|
||||||
if (map[assetName] != null) {
|
|
||||||
debug('Conflcting assets', assetName);
|
|
||||||
}
|
|
||||||
|
|
||||||
map[assetName] = new ModuleDescriptor({
|
|
||||||
id: 'image!' + assetName,
|
|
||||||
path: path.resolve(file),
|
|
||||||
isAsset: true,
|
|
||||||
dependencies: [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -664,4 +695,24 @@ function buildAssetMap(roots, exts) {
|
|||||||
return search();
|
return search();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function assetName(file, ext) {
|
||||||
|
return path.basename(file, '.' + ext).replace(/@[\d\.]+x/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function extname(name) {
|
||||||
|
return path.extname(name).replace(/^\./, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function NotFoundError() {
|
||||||
|
Error.call(this);
|
||||||
|
Error.captureStackTrace(this, this.constructor);
|
||||||
|
var msg = util.format.apply(util, arguments);
|
||||||
|
this.message = msg;
|
||||||
|
this.type = this.name = 'NotFoundError';
|
||||||
|
this.status = 404;
|
||||||
|
}
|
||||||
|
|
||||||
|
NotFoundError.__proto__ = Error.prototype;
|
||||||
|
|
||||||
module.exports = DependecyGraph;
|
module.exports = DependecyGraph;
|
||||||
|
|||||||
@@ -51,15 +51,15 @@ var validateOpts = declareOpts({
|
|||||||
type: 'array',
|
type: 'array',
|
||||||
default: [],
|
default: [],
|
||||||
},
|
},
|
||||||
|
fileWatcher: {
|
||||||
|
type: 'object',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function HasteDependencyResolver(options) {
|
function HasteDependencyResolver(options) {
|
||||||
var opts = validateOpts(options);
|
var opts = validateOpts(options);
|
||||||
|
|
||||||
this._fileWatcher = opts.nonPersistent
|
|
||||||
? FileWatcher.createDummyWatcher()
|
|
||||||
: new FileWatcher(opts.projectRoots);
|
|
||||||
|
|
||||||
this._depGraph = new DependencyGraph({
|
this._depGraph = new DependencyGraph({
|
||||||
roots: opts.projectRoots,
|
roots: opts.projectRoots,
|
||||||
assetRoots: opts.assetRoots,
|
assetRoots: opts.assetRoots,
|
||||||
@@ -67,7 +67,7 @@ function HasteDependencyResolver(options) {
|
|||||||
return filepath.indexOf('__tests__') !== -1 ||
|
return filepath.indexOf('__tests__') !== -1 ||
|
||||||
(opts.blacklistRE && opts.blacklistRE.test(filepath));
|
(opts.blacklistRE && opts.blacklistRE.test(filepath));
|
||||||
},
|
},
|
||||||
fileWatcher: this._fileWatcher,
|
fileWatcher: opts.fileWatcher,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -164,10 +164,6 @@ HasteDependencyResolver.prototype.wrapModule = function(module, code) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
HasteDependencyResolver.prototype.end = function() {
|
|
||||||
return this._fileWatcher.end();
|
|
||||||
};
|
|
||||||
|
|
||||||
HasteDependencyResolver.prototype.getDebugInfo = function() {
|
HasteDependencyResolver.prototype.getDebugInfo = function() {
|
||||||
return this._depGraph.getDebugInfo();
|
return this._depGraph.getDebugInfo();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ describe('FileWatcher', function() {
|
|||||||
var Watcher;
|
var Watcher;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
require('mock-modules').dumpCache();
|
||||||
FileWatcher = require('../');
|
FileWatcher = require('../');
|
||||||
Watcher = require('sane').WatchmanWatcher;
|
Watcher = require('sane').WatchmanWatcher;
|
||||||
Watcher.prototype.once.mockImplementation(function(type, callback) {
|
Watcher.prototype.once.mockImplementation(function(type, callback) {
|
||||||
|
|||||||
32
packager/react-packager/src/FileWatcher/index.js
vendored
32
packager/react-packager/src/FileWatcher/index.js
vendored
@@ -16,7 +16,7 @@ var exec = require('child_process').exec;
|
|||||||
|
|
||||||
var Promise = q.Promise;
|
var Promise = q.Promise;
|
||||||
|
|
||||||
var detectingWatcherClass = new Promise(function(resolve, reject) {
|
var detectingWatcherClass = new Promise(function(resolve) {
|
||||||
exec('which watchman', function(err, out) {
|
exec('which watchman', function(err, out) {
|
||||||
if (err || out.length === 0) {
|
if (err || out.length === 0) {
|
||||||
resolve(sane.NodeWatcher);
|
resolve(sane.NodeWatcher);
|
||||||
@@ -30,14 +30,23 @@ module.exports = FileWatcher;
|
|||||||
|
|
||||||
var MAX_WAIT_TIME = 3000;
|
var MAX_WAIT_TIME = 3000;
|
||||||
|
|
||||||
function FileWatcher(projectRoots) {
|
// Singleton
|
||||||
var self = this;
|
var fileWatcher = null;
|
||||||
|
|
||||||
|
function FileWatcher(rootConfigs) {
|
||||||
|
if (fileWatcher) {
|
||||||
|
// This allows us to optimize watching in the future by merging roots etc.
|
||||||
|
throw new Error('FileWatcher can only be instantiated once');
|
||||||
|
}
|
||||||
|
|
||||||
|
fileWatcher = this;
|
||||||
|
|
||||||
this._loading = q.all(
|
this._loading = q.all(
|
||||||
projectRoots.map(createWatcher)
|
rootConfigs.map(createWatcher)
|
||||||
).then(function(watchers) {
|
).then(function(watchers) {
|
||||||
watchers.forEach(function(watcher) {
|
watchers.forEach(function(watcher) {
|
||||||
watcher.on('all', function(type, filepath, root) {
|
watcher.on('all', function(type, filepath, root) {
|
||||||
self.emit('all', type, filepath, root);
|
fileWatcher.emit('all', type, filepath, root);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return watchers;
|
return watchers;
|
||||||
@@ -50,21 +59,14 @@ util.inherits(FileWatcher, EventEmitter);
|
|||||||
FileWatcher.prototype.end = function() {
|
FileWatcher.prototype.end = function() {
|
||||||
return this._loading.then(function(watchers) {
|
return this._loading.then(function(watchers) {
|
||||||
watchers.forEach(function(watcher) {
|
watchers.forEach(function(watcher) {
|
||||||
delete watchersByRoot[watcher._root];
|
|
||||||
return q.ninvoke(watcher, 'close');
|
return q.ninvoke(watcher, 'close');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var watchersByRoot = Object.create(null);
|
function createWatcher(rootConfig) {
|
||||||
|
|
||||||
function createWatcher(root) {
|
|
||||||
if (watchersByRoot[root] != null) {
|
|
||||||
return Promise.resolve(watchersByRoot[root]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return detectingWatcherClass.then(function(Watcher) {
|
return detectingWatcherClass.then(function(Watcher) {
|
||||||
var watcher = new Watcher(root, {glob: ['**/*.js', '**/package.json']});
|
var watcher = new Watcher(rootConfig.dir, rootConfig.globs);
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
var rejectTimeout = setTimeout(function() {
|
var rejectTimeout = setTimeout(function() {
|
||||||
@@ -77,8 +79,6 @@ function createWatcher(root) {
|
|||||||
|
|
||||||
watcher.once('ready', function() {
|
watcher.once('ready', function() {
|
||||||
clearTimeout(rejectTimeout);
|
clearTimeout(rejectTimeout);
|
||||||
watchersByRoot[root] = watcher;
|
|
||||||
watcher._root = root;
|
|
||||||
resolve(watcher);
|
resolve(watcher);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
14
packager/react-packager/src/Packager/index.js
vendored
14
packager/react-packager/src/Packager/index.js
vendored
@@ -56,6 +56,14 @@ var validateOpts = declareOpts({
|
|||||||
type: 'array',
|
type: 'array',
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
assetExts: {
|
||||||
|
type: 'array',
|
||||||
|
default: ['png'],
|
||||||
|
},
|
||||||
|
fileWatcher: {
|
||||||
|
type: 'object',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function Packager(options) {
|
function Packager(options) {
|
||||||
@@ -70,6 +78,7 @@ function Packager(options) {
|
|||||||
nonPersistent: opts.nonPersistent,
|
nonPersistent: opts.nonPersistent,
|
||||||
moduleFormat: opts.moduleFormat,
|
moduleFormat: opts.moduleFormat,
|
||||||
assetRoots: opts.assetRoots,
|
assetRoots: opts.assetRoots,
|
||||||
|
fileWatcher: opts.fileWatcher,
|
||||||
});
|
});
|
||||||
|
|
||||||
this._transformer = new Transformer({
|
this._transformer = new Transformer({
|
||||||
@@ -83,10 +92,7 @@ function Packager(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Packager.prototype.kill = function() {
|
Packager.prototype.kill = function() {
|
||||||
return q.all([
|
return this._transformer.kill();
|
||||||
this._transformer.kill(),
|
|
||||||
this._resolver.end(),
|
|
||||||
]);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Packager.prototype.package = function(main, runModule, sourceMapUrl, isDev) {
|
Packager.prototype.package = function(main, runModule, sourceMapUrl, isDev) {
|
||||||
|
|||||||
42
packager/react-packager/src/Server/index.js
vendored
42
packager/react-packager/src/Server/index.js
vendored
@@ -55,18 +55,49 @@ var validateOpts = declareOpts({
|
|||||||
type: 'array',
|
type: 'array',
|
||||||
required: false,
|
required: false,
|
||||||
},
|
},
|
||||||
|
assetExts: {
|
||||||
|
type: 'array',
|
||||||
|
default: ['png'],
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
function Server(options) {
|
function Server(options) {
|
||||||
var opts = validateOpts(options);
|
var opts = validateOpts(options);
|
||||||
|
|
||||||
this._projectRoots = opts.projectRoots;
|
this._projectRoots = opts.projectRoots;
|
||||||
this._packages = Object.create(null);
|
this._packages = Object.create(null);
|
||||||
this._packager = new Packager(opts);
|
|
||||||
this._changeWatchers = [];
|
this._changeWatchers = [];
|
||||||
|
|
||||||
|
var watchRootConfigs = opts.projectRoots.map(function(dir) {
|
||||||
|
return {
|
||||||
|
dir: dir,
|
||||||
|
globs: [
|
||||||
|
'**/*.js',
|
||||||
|
'**/package.json',
|
||||||
|
]
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if (opts.assetRoots != null) {
|
||||||
|
watchRootConfigs = watchRootConfigs.concat(
|
||||||
|
opts.assetRoots.map(function(dir) {
|
||||||
|
return {
|
||||||
|
dir: dir,
|
||||||
|
globs: opts.assetExts.map(function(ext) {
|
||||||
|
return '**/*.' + ext;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this._fileWatcher = options.nonPersistent
|
this._fileWatcher = options.nonPersistent
|
||||||
? FileWatcher.createDummyWatcher()
|
? FileWatcher.createDummyWatcher()
|
||||||
: new FileWatcher(options.projectRoots);
|
: new FileWatcher(watchRootConfigs);
|
||||||
|
|
||||||
|
var packagerOpts = Object.create(opts);
|
||||||
|
packagerOpts.fileWatcher = this._fileWatcher;
|
||||||
|
this._packager = new Packager(packagerOpts);
|
||||||
|
|
||||||
var onFileChange = this._onFileChange.bind(this);
|
var onFileChange = this._onFileChange.bind(this);
|
||||||
this._fileWatcher.on('all', onFileChange);
|
this._fileWatcher.on('all', onFileChange);
|
||||||
@@ -246,6 +277,9 @@ Server.prototype.processRequest = function(req, res, next) {
|
|||||||
function getOptionsFromUrl(reqUrl) {
|
function getOptionsFromUrl(reqUrl) {
|
||||||
// `true` to parse the query param as an object.
|
// `true` to parse the query param as an object.
|
||||||
var urlObj = url.parse(reqUrl, true);
|
var urlObj = url.parse(reqUrl, true);
|
||||||
|
// node v0.11.14 bug see https://github.com/facebook/react-native/issues/218
|
||||||
|
urlObj.query = urlObj.query || {};
|
||||||
|
|
||||||
var pathname = urlObj.pathname;
|
var pathname = urlObj.pathname;
|
||||||
|
|
||||||
// Backwards compatibility. Options used to be as added as '.' to the
|
// Backwards compatibility. Options used to be as added as '.' to the
|
||||||
@@ -281,11 +315,11 @@ function getBoolOptionFromQuery(query, opt, defaultVal) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleError(res, error) {
|
function handleError(res, error) {
|
||||||
res.writeHead(500, {
|
res.writeHead(error.status || 500, {
|
||||||
'Content-Type': 'application/json; charset=UTF-8',
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
});
|
});
|
||||||
|
|
||||||
if (error.type === 'TransformError') {
|
if (error.type === 'TransformError' || error.type === 'NotFoundError') {
|
||||||
res.end(JSON.stringify(error));
|
res.end(JSON.stringify(error));
|
||||||
} else {
|
} else {
|
||||||
console.error(error.stack || error);
|
console.error(error.stack || error);
|
||||||
|
|||||||
Reference in New Issue
Block a user